pinchzoom 官网 http://manuelstofer.github.io/pinchzoom/


PortraitClip.css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
.pinch-page{
     position : fixed ;
     top : 0 ;
     bottom : 0 ;
     left : 0 ;
     right : 0 ;
     display : none ;
     width : 100% ;
     height : 100% ;
     background-color : #333 ;
     z-index : 9 ;
 
}
.pinch-page .top-mask,
.pinch-page .bottom-mask{
     position : absolute ;
     left : 0 ;
     top : 0 ;
     right : 0 ;
     display : block ;
     background-color :rgba( 0 , 0 , 0 , 0.6 );
     z-index 99 ;
}
 
.pinch-page .bottom-mask{
     top : auto ;
     bottom : 0 ;
}
 
.pinch-page .pinch-zoom-container{
     position : absolute !important ;
     left : 0 ;
     top : 0 ;
     bottom : 0 ;
     right : 0 ;
     margin : auto ;
     overflow visible !important ;
     z-index 9 ;
     box-sizing: border-box;
}
 
.pinch-page .pinch-zoom-container:before{
     content : "" ;
     position : absolute ;
     top : 0 ;
     bottom : 0 ;
     left : 0 ;
     right : 0 ;
     display : block ;
     width : 100% ;
     height : 100% ;
     z-index : 999 ;
     border : 1px  solid  #fff ;
     box-sizing: border-box;
}
 
.pinch-page .pinch-zoom{
}
 
.pinch-page .pinch-zoom-image{
     display : block ;
     width : 100% ;
     height : 320px ;
     background no-repeat  center  center ;
     background- size :contain;
}
 
.pinch-page .operation-bar{
     position : absolute ;
     left : 0 ;
     right : 0 ;
     bottom : 0 ;
     display : block ;
     height : 60px ;
     z-index 999 ;
     background-color :rgba( 51 , 51 , 51 , 0.6 );
}
.pinch-page .operation-bar .cancel-btn{
     position : absolute ;
     top : 0 ;
     bottom : 0 ;
     left : 0 ;
     display : block ;
     height : 60px ;
     line-height 60px ;
     font-size : 16px ;
     color : #fff ;
     padding : 0  20px ;
}
.pinch-page .operation-bar .save-btn{
     position : absolute ;
     top : 0 ;
     bottom : 0 ;
     right : 0 ;
     display : block ;
     height : 60px ;
     line-height 60px ;
     font-size : 16px ;
     color : #fff ;
     padding : 0  20px ;
}

PortraitClip.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
( function ($){
     /* ======================================== 页面渲染 ======================================== */
     /* ======================================== 不可变字段 ======================================== */
     var  initialized =  false // 是否初始化
     var  container =  null ;
     var  clientWidth = $(window).width();
     var  clientHeight = $(window).height();
     var  pinchZoomImageWidth = clientWidth;
     var  pinchZoomImageHeight = clientWidth;
     var  maskHeight = (clientHeight-clientWidth)/2;
     var  pinchZoom =  null // pinchZoom 对象
 
     /* ======================================== 可变字段 ======================================== */
     var  imageWidth = 0;
     var  imageHeight = 0;
     var  xOffset = 0;
     var  yOffset = 0;
     var  originScale = 0;
     var  image =  null ;
     var  callback =  null // 加载完之后的回调
 
 
 
     // 构建DOM
     function  render(){
         var  html =   "<div class='pinch-page'>                                                           " +
                     "  <em class='top-mask'></em>                                                      " +
                     "  <div class='pinch-zoom'>                                                        " +
                     "     <div class='pinch-zoom-image'></div>                                        " +
                     "  </div>                                                                          " +
                     "  <em class='bottom-mask'></em>                                                   " +
                     "  <div class='operation-bar'>                                                     " +
                     "     <a class='cancel-btn'>取消</a>                                              " +
                     "     <a class='save-btn'>选取</a>                                                " +
                     "  </div>                                                                          " +
                     "</div>                                                                             " ;
         $(html).appendTo( "body" );
 
         // 初始化 pinchZoom
         pinchZoom =  new  RTP.PinchZoom($( ".pinch-zoom" ));
 
         // 添加遮罩
         $( ".pinch-page .top-mask" ).css( "height" ,maskHeight+ "px" );
         $( ".pinch-page .bottom-mask" ).css( "height" ,maskHeight+ "px" );
         $( ".pinch-zoom-container,.pinch-zoom-image" ).css({
             "width" :pinchZoomImageWidth+ "px" ,
             "height" :pinchZoomImageHeight+ "px"
         });
 
         container = $( ".pinch-page" );
     }
 
     // 绑定事件
     function  bindPageEvents(){
         container.on( "touchend" , ".save-btn" , function (e){
             e.stopPropagation();
             e.preventDefault();
 
             var  transformCss = $( ".pinch-zoom" ).css( "-webkit-transform" );
             var  positionInfo = retrievePositionInfo(transformCss);
             clipImage(positionInfo.scale,positionInfo.x,positionInfo.y,callback);
 
             $(container).hide();
         });
 
 
         container.on( "touchend" , ".cancel-btn" , function (e){
             e.stopPropagation();
             e.preventDefault();
             $(container).hide();
         });
 
         container.on( "touchstart touchmove touchend" , function (e){
             e.stopPropagation();
             e.preventDefault();
         });
     }
 
     // 初始化方法
     function  init(){
         if (initialized){
             return ;
         }
         initialized =  true ;
         render();
         bindPageEvents();
     }
 
     /* ======================================== common-method ======================================== */
     // 刷新 头像剪裁容器
     function  loadImage(originImage,loadCallback){
         if (!initialized){init();}  // 如果未初始化则初始化
 
         callback = loadCallback;
         $(container).find( ".pinch-zoom-image" ).css( "background-image" , "url(" +originImage+ ")" );
 
         image =  new  Image();
         image.onload =  function (){
             imageWidth = image.width;
             imageHeight = image.height;
             loadImageCallback();
 
             $(container).show();
         };
         image.src=originImage;
     }
 
 
 
     // 图像加载回调
     function  loadImageCallback(){
 
         if (imageWidth>imageHeight){
             yOffset = (imageWidth-imageHeight)*pinchZoomImageWidth/imageWidth/2;
             originScale = pinchZoomImageWidth/imageWidth;
         } else {
             xOffset = (imageHeight-imageWidth)*pinchZoomImageWidth/imageHeight/2;
             originScale = pinchZoomImageHeight/imageHeight;
         }
 
         var  minZoom = 1;
         if (xOffset!=0){
             minZoom = clientWidth/(clientWidth-2*xOffset);
         }
         if (yOffset!=0){
             minZoom = clientWidth/(clientWidth-2*yOffset);
         }
 
         // 初始化 pinchZoom 对戏那个
         pinchZoom.options.minZoom = minZoom;
         pinchZoom.options.tapZoomFactor = minZoom;
         pinchZoom.options.xOffset = xOffset;
         pinchZoom.options.yOffset = yOffset;
 
 
 
         var  event = {touches:[{pageX:pinchZoomImageWidth/2,pageY:clientHeight/2}]};
         setTimeout( function (){pinchZoom.handleDoubleTap(event);},300);
 
     }
 
     // 剪裁图像
     function  clipImage(scale,x,y,callback){
         // 创建 canvas
         var  canvasId = "canvas_" + new  Date().getTime()+ "" +parseInt(Math.random()*10000);
         $( "<canvas></canvas>" ).hide().attr( "id" ,canvasId).appendTo( "body" );
 
         var  canvas=$( "#" +canvasId)[0];
         var  ctx=canvas.getContext( "2d" );
 
         // 释放canvas
         function  releaseCanvas(){
             $( "#" +canvasId).remove();
         }
         // canvas 宽度 高度
         canvas.width = pinchZoomImageWidth;
         canvas.height= pinchZoomImageHeight;
 
         if (image.width>image.height){
             y=y-yOffset;
         } else {
             x=x-xOffset;
         }
         ctx.drawImage(image,x/originScale,y/originScale,pinchZoomImageWidth/scale/originScale,pinchZoomImageHeight/scale/originScale,0,0,pinchZoomImageWidth,pinchZoomImageHeight);
 
         var  dataURL = canvas.toDataURL();
         if (callback!= null ){
             callback(dataURL);
         }
 
         releaseCanvas();
     }
 
     // 获取 pinch-zoom 缩放 偏移信息
     function  retrievePositionInfo(transformCss){
         var  infoStr = transformCss.replace( "matrix(" , "" );
         infoStr = infoStr.replace( ")" , "" );
         var  arr = infoStr.split( "," );
         var  scale = arr[0];
         var  x = arr[4];
         var  y = arr[5];
         if (x<0){
             x = -1*x;
         }
         if (y<0){
             y=-1*y;
         }
 
         var  result = {scale:scale,x:x/scale,y:y/scale};
         return  result;
     }
 
 
 
     var  PortraitClipUtil = {};
 
     PortraitClipUtil.loadImage=loadImage;
 
     window.PortraitClipUtil = PortraitClipUtil;
})(jQuery);


测试页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
         "http://www.w3.org/TR/html4/loose.dtd">
< html >
< head >
     < title >Pinchzoom.js Demo</ title >
 
     < meta  charset = "UTF-8"  />
     < meta  name = "viewport"  content = "width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" >
     < meta  name = "apple-mobile-web-app-capable"  content = "yes"  />
 
 
     < link  rel = "stylesheet"  href = "css/common/PortraitClip.css"  />
     < style >
         body{margin:0;}
     </ style >
</ head >
< body  style = "height:900px;" >
 
     < button  id = "upload-image" >上传图片</ button >
 
     < image  id = "image"  style = "position: absolute;display:block;top:0;z-index:9999;" />
 
 
     < script  type = "text/javascript"  src = "dist/js/jquery-1.11.3.min.js" ></ script >
     < script  type = "text/javascript"  src = "dist/js/pinchzoom-xiaomin.min.js" ></ script >
     < script  type = "text/javascript"  src = "js/common/PortraitClip.js" ></ script >
     < script >
         $("#upload-image").click(function(e){
             PortraitClipUtil.loadImage("frog.jpg",function(dataURL){
                 $("#image").attr("src",dataURL);
             });
         });
     </ script >
</ body >
</ html >


wKioL1fD-lnTKyqzAAhseDbauOw019.jpg


注:这边引入的是pinchzoom-xiaomin.min.js。对pinchzoom.min.js源代码有所变更。pinchzoom.js,pinchzoom.min.js,pinchzoom-xiaomin.js,pinchzoom-xiaomin.min.js在相应的附件中。