有了上一篇图片放大镜的铺垫,今天的这个例子是缩小镜,因为裁剪的原图往往很大,不能在工作区域看到全部图片,所以,要有缩小镜来显示,当前裁剪的区域是原图的个部分.按照惯例首先看下效果图:
功能一:载入默认图片
功能二:选择本地图片
功能三:拖拽(鼠标直接拖动工作区视窗)
功能四:放大,缩小(点击按钮放大/缩小0.5倍,鼠标滚轮图片缩放)
功能五:利用canvas绘图裁剪图片
以下是源码,分享下,防止忘记:
html:
1 <script src="./javascript/jquery.min.js"></script>
2 <div id="workplace">
3 <div id="workplacewrap">
4 <div id="operateplace">
5 <div class="showinfo">
6 <span class="mouseposition">
7 坐标(px):
8 x:<span class="mouseposition-x">0</span>
9 y:<span class="mouseposition-y">0</span>
10 </span>
11 </div>
12 <div id="sourceImage">
13 <img src="./images/show-window/1-1.jpg" alt="" draggable="false">
14 </div>
15 <div id="clipregion"></div>
16 <div class="operation">
17 <input id="fileselector" type="file" hidden style="">
18 <label class="btn" for="fileselector">选择文件</label>
19 <span id="btn-ResizeUp" class="btn">放大</span>
20 <span id="btn-ResizeDown" class="btn">缩小</span>
21 <span id="btn-Clip" class="btn">裁剪</span>
22 </div>
23 </div>
24 <div id="showwindow">
25 <div class="showinfo">
26 <span class="mouseposition">
27 缩放比例:
28 <span class="enlargeratio"></span>%
29 </span>
30 </div>
31 <div style="position: absolute;">
32 <div id="pologen"></div>
33 </div>
34 <div id="previewwindow">
35 <img src="" alt="" draggable="false">
36 </div>
37 <div class="operation">
38 <span class="btn">保存</span>
39 </div>
40
41 </div>
42 </div>
css:
1 * {
2 font-size: 14px;
3 letter-spacing: 1px;
4 color: #000;
5 -ms-text-justify: auto;
6 text-justify: auto;
7 font-size: 12px;
8 }
9
10 #workplace {
11 width: 100%;
12 height: auto;
13 background: #f4f4f4;
14
15 }
16
17 #workplacewrap {
18 margin: 0px auto;
19 width: 1200px;
20 display: flex;
21 flex-direction: row;
22 align-items: flex-start;
23 justify-content: flex-start;
24 border-right: 1px solid #f0f0f0;
25 border-left: 1px solid #f0f0f0;
26 background: #f4f4f4;
27 font-family: "微软雅黑 Light";
28 padding: 5px;
29 }
30
31 #operateplace {
32 padding: 4px;
33 border: 1px solid #bababa;
34
35 }
36
37 #sourceImage {
38 width: 500px;
39 height: 300px;
40 border: 1px solid #bababa;
41 background: none;
42 margin-bottom: -1px;
43 overflow: hidden;
44 }
45
46 #sourceImage img {
47 position: relative;
48 top: 0;
49 left: 0;
50 }
51
52 .btn {
53 background: #aa0000;
54 border: #F8F8F8;
55 color: white;
56 padding: 5px;
57 }
58
59 .btn:hover {
60 cursor: pointer;
61 background: #cc1234;
62 }
63
64 .operation {
65 display: flex;
66 flex-direction: row;
67 align-items: center;
68 justify-content: space-around;
69 height: 50px;
70 }
71
72 .showinfo {
73
74 margin-bottom: -1px;
75 font-size: 12px;
76 }
77
78 #showwindow {
79 justify-self: flex-end;
80 align-items: flex-end;
81 width: 500px;
82 height: auto;
83 border: #baabba 1px solid;
84 margin-left: 5px;
85 padding: 5px;
86 overflow: hidden;
87 position:relative;
88 }
89
90 #previewwindow {
91 border: 1px solid #bababa;
92 width: 500px;
93 height: 300px;
94 }
95 #pologen
96 {
97 border:1px solid red;
98 position:relative;
99 display:none;
100 }
javascript:
1 //代码重新修订
2 class ClipTools {
3 constructor() {
4 this.workview = $('#sourceImage');
5 this.showview = $('#previewwindow');
6
7 this.workviewimg=$('#sourceImage>img');
8 this.showviewimg = $('#previewwindow>img');
9 //工作区实际尺寸,由于图片有缩放,工作区尺寸实际是有workvimg尺寸决定的,而工作区视窗的是尺寸是固定的,本例中是500*300,这个尺寸默认就是最终截图的尺寸
10 //后面扩展,可以对工作视图的尺寸进行调整,截出不同尺寸的图片
11 this.workvwidth = 0;
12 this.workvheight = 0;
13 //同样展示框的尺寸,实际是右侧展示框图片缩放后的尺寸,本例中图片一定要全部放入展示视窗,所以,这个尺寸是小于等于展示视窗的尺寸的
14 this.showvwidth = $('#sourceImage').width();
15 this.showvheight = $('#sourceImage').height();
16
17 //右侧显示区图片缩放后的高度
18 this.showvimgheight=0;
19 //右侧显示区图片缩放后的宽度
20 this.showvimgwidth=0;
21 this.resizeRate = 0.5;
22 this.isScrollMouseResize = false;
23 //后面扩展,比如绘制裁剪区域时用,本例中没有实际意义
24 this.isClip=false;
25
26 this.isMouseDown=false;
27 //标识鼠标在工作区的坐标,offsetX 和offsetY(相对于视窗)
28 this.workpos_x = 0;
29 this.workpos_y = 0;
30
31 //图片顶点位置
32 this.sourceimg_l=0;
33 this.sourceimg_t=0;
34 //图片在计算拖动距离的时候,需要记录鼠标的起始位置,在鼠标的down->move中,起始位置以鼠标的down点为基准
35 this.lastMouse_x=0;
36 this.lastMouse_y=0;
37 //记录图片的原始尺寸
38 this.sourceimg_w = 0;
39 this.sourceimg_h = 0;
40 //记录图片缩放的比例
41 this.enlargeratio = 1.0;
42
43 //显示区图片和显示区域的比例
44 this.showToSourceWidthRatio=0.1;
45 this.showToSouceHeightRatio=0.1;
46
47
48 this.Init = this.Init.bind(this);
49 this.ImgInputFileChanged = this.ImgInputFileChanged.bind(this);
50 this.ResizeUp = this.ResizeUp.bind(this);
51 this.ResizeDown = this.ResizeDown.bind(this);
52 this.ShowWorkPos = this.ShowWorkPos.bind(this);
53 this.DrawClipRegionTosShow=this.DrawClipRegionTosShow.bind(this);
54 }
55 ShowWorkPos(x, y) {
56 $('.mouseposition-x').text(this.workpos_x);
57 $('.mouseposition-y').text(this.workpos_y);
58 $(".enlargeratio").text(($("#pologen").height()/this.showvimgwidth)*100);
59
60 this.DrawClipRegionTosShow();
61 }
62
63 Init() {
64 //如果工作区域有默认图片
65 this.sourceimg_h = this.workviewimg.height();
66 this.sourceimg_w = this.workviewimg.width();
67
68 this.workvwidth = this.sourceimg_w;
69 this.workvheight = this.sourceimg_h;
70
71 this.showToSouceHeightRatio=this.showvheight/this.sourceimg_h;
72 this.showToSourceWidthRatio=this.showvwidth/this.sourceimg_w;
73
74 //右侧展示区域,展示当前工作区处于图片的区域
75 //按照最小比例对图片进行缩放
76
77 if (this.showToSouceHeightRatio<this.showToSourceWidthRatio)
78 {
79 this.showvimgheight=this.showvheight;
80 this.showvimgwidth=this.showToSouceHeightRatio*this.sourceimg_w;
81 }
82 else
83 {
84 this.showvimgheight=this.sourceimg_h*this.showToSourceWidthRatio;
85 this.showvimgwidth=this.showvwidth;
86 }
87 this.showviewimg.attr('src',this.workviewimg.attr('src')).width(this.showvimgwidth).height(this.showvimgheight);
88
89 $('#btn-Clip').click(()=>{
90 let _cropCanvas = document.createElement('canvas');
91 // 计算截取时从原图片的原始长度的坐标
92 //图片有缩放等,所以要利用原始数据进行计算
93 let _sy =-this.sourceimg_t/ (this.workvheight/this.sourceimg_h);
94 let _sx=-this.sourceimg_l/(this.workvwidth/this.sourceimg_w);
95 let _swidth=this.workview.width()/(this.workvwidth/this.sourceimg_w);
96 let _sheight=this.workview.height()/(this.workvheight/this.sourceimg_h);
97 let width=this.workview.width();
98 let height=this.workview.height();
99 //工作区域视窗就是图片的大小
100 _cropCanvas.width = width;
101 _cropCanvas.height = height;
102 // 绘制图片
103 _cropCanvas.getContext('2d').drawImage(this.workviewimg[0], _sx, _sy, _swidth, _sheight, 0, 0, width, height);
104 // 保存图片信息
105 let _lastImageData = _cropCanvas.toDataURL('image/png');
106 // 将裁剪出来的信息展示
107 this.showviewimg.attr({"src": _lastImageData}).css({"width":width+"px","height":height+"px"});
108 $('#pologen').css('display',"none");
109 alert("裁剪成功");
110 });
111 $('#fileselector').on("change", this.ImgInputFileChanged);
112 $("#btn-ResizeUp").click(this.ResizeUp);
113 $("#btn-ResizeDown").click(this.ResizeDown);
114 //this.DrawClipRegionTosShow();
115 this.workviewimg.mousemove((e) => {
116
117 if(this.isMouseDown)
118 {
119 if (this.workviewimg)
120 var left_s= e.offsetX- this.lastMouse_x;
121 var top_s=e.offsetY-this.lastMouse_y;
122
123 this.sourceimg_l+=left_s;
124 this.sourceimg_t+=top_s;
125 this.workviewimg.css({"left":this.sourceimg_l+"px","top":this.sourceimg_t+"px"});
126 }
127 this.workpos_x = e.offsetX+this.sourceimg_l;
128 this.workpos_y = e.offsetY+this.sourceimg_t;
129 this.ShowWorkPos(e.offsetX,e.offsetY);
130 return false;
131 });
132 //工作区滚轮事件,调整图片缩放,相当于是微调
133 this.workviewimg.on("mousewheel DOMMouseScroll",(e)=> {
134 this.isScrollMouseResize=true;
135 var delta = (e.originalEvent.wheelDelta && (e.originalEvent.wheelDelta > 0 ? 1 : -1)) || // chrome & ie
136 (e.originalEvent.detail && (e.originalEvent.detail > 0 ? -1 : 1)); // firefox
137
138 if(delta>0)//向上滚
139 {
140 if(this.enlargeratio>=1)
141 {
142 return;
143 }
144 this.workvwidth += 1;
145 this.workvheight +=this.sourceimg_h/this.sourceimg_w;
146 }
147 else if(delta<0)
148 {
149 this.workvwidth -= 1;
150 this.workvheight -=this.sourceimg_h/this.sourceimg_w;
151 }
152 this.workviewimg.css({"width":this.workvwidth+"px","height":this.workvheight+"px"});
153 this.workviewimg.height(this.workvheight);
154 //this.DrawClipRegionTosShow();
155 });
156
157 //工作区图片拖拽
158 this.workviewimg.mousedown((e)=>{
159 this.isMouseDown=true;
160 if(!this.isClip)
161 {
162 this.workviewimg.css({"cursor":"move"});
163 }
164 this.lastMouse_x=e.offsetX;
165 this.lastMouse_y=e.offsetY;
166 });
167 //鼠标未松开,移出工作区
168 this.workviewimg.mouseleave((e)=>{
169 this.isMouseDown=false;
170 if(!this.isClip)
171 {
172 this.workviewimg.css({"cursor":"default"});
173 }
174 });
175 //防止鼠标松开的事件,遗漏,所以拖拽的终事件,放在body中监听
176 $('body').mouseup((e)=>{
177 this.isMouseDown=false;
178 if(!this.isClip)
179 {
180 this.workviewimg.css({"cursor":"default"});
181 }
182 });
183 }
184 //在展示区域,标识出被截图的范围
185 DrawClipRegionTosShow()
186 {
187 //1.首先将工作区左上角的位置还原到原图的位置,因为有滚轮的放大和缩小,所以原本定义在放大或者缩小按钮上的缩放比例不能再使用,要重新计算
188 //不管是放大缩小按钮,还是滚轮缩放的比例在工作区都是一样的
189 //计算在右侧展示区,缩放后投影裁剪区域的位置
190 this.showToSouceHeightRatio=this.showvheight/this.workvheight;
191 this.showToSourceWidthRatio=this.showvwidth/this.workvwidth;
192 let showLeft=0;
193 let showTop=0;
194 let showWidth=0;
195 let showHeight=0;
196 if (this.showToSouceHeightRatio<this.showToSourceWidthRatio)
197 {
198 showWidth=this.workview.width()*this.showToSouceHeightRatio;
199 showHeight=this.workview.height()*this.showToSouceHeightRatio;
200 showLeft=-this.sourceimg_l*this.showToSouceHeightRatio;
201 showTop=-this.sourceimg_t*this.showToSouceHeightRatio;
202 }
203 else
204 {
205 showWidth=this.workview.width()*this.showToSourceWidthRatio;
206 showHeight=this.workview.height()*this.showToSourceWidthRatio;
207 showLeft=-this.sourceimg_l*this.showToSourceWidthRatio;
208 showTop=-this.sourceimg_t*this.showToSourceWidthRatio;
209 }
210 $('#pologen').css({"display":"block","top":showTop+"px","left":showLeft+"px","width":showWidth+"px","height":showHeight+"px"});
211
212 }
213 ResizeDown(e) {
214 this.sourceimg_t=0;
215 this.sourceimg_l=0;
216 this.workviewimg.css({"left":this.sourceimg_l+"px","top":this.sourceimg_t+"px"});
217 //鼠标滑轮调整过尺寸,则将图复原
218 if (this.isScrollMouseResize) {
219 this.enlargeratio = 1.0;
220 this.workvwidth=this.sourceimg_w;
221 this.workvheight=this.sourceimg_h;
222 this.workviewimg.css({"width":this.sourceimg_w+"px","height":this.sourceimg_h+"px"});
223 }
224 this.isScrollMouseResize = false;
225 //不允许对完全在工作区展示的图片,再缩小
226 if (this.workvheight < this.showvheight && this.workvwidth < this.showvwidth) {
227 return;
228 }
229 else {
230 this.enlargeratio *= this.resizeRate;
231 this.workvwidth = this.sourceimg_w * this.enlargeratio;
232 this.workvheight = this.sourceimg_h * this.enlargeratio;
233 this.workviewimg.css({"width":this.workvwidth+"px","height":this.workvheight+"px"});
234 this.DrawClipRegionTosShow();
235 }
236 }
237
238 ResizeUp(e) {
239 this.sourceimg_t=0;
240 this.sourceimg_l=0;
241 this.workviewimg.css({"left":this.sourceimg_l+"px","top":this.sourceimg_t+"px"});
242 //鼠标滑轮调整过尺寸,则将图复原
243 if (this.isScrollMouseResize) {
244 this.enlargeratio = 1.0;
245 this.workvwidth=this.sourceimg_w;
246 this.workvheight=this.sourceimg_h;
247 this.workviewimg.css({"width":this.sourceimg_w+"px","height":this.sourceimg_h+"px"});
248
249 }
250 this.isScrollMouseResize = false;
251 //不允许,对原样展示的图片再进行放大
252 if (this.enlargeratio >= 1) {
253 return;
254 }
255 else {
256 this.enlargeratio /= this.resizeRate;
257 this.workvwidth = this.sourceimg_w * this.enlargeratio;
258 this.workvheight = this.sourceimg_h * this.enlargeratio;
259 this.workviewimg.css({"width":this.workvwidth+"px","height":this.workvheight+"px"});
260 }
261 this.DrawClipRegionTosShow();
262 }
263 ImgInputFileChanged(e) {
264 let file = e.target.files[0];
265 let reader = new FileReader();
266 reader.readAsDataURL(file);
267 //读取完成时
268 reader.onloadend = (e) => {
269 this.workviewimg.attr('src', e.target.result);
270
271 this.sourceimg_h = this.workviewimg.height();
272 this.sourceimg_w = this.workviewimg.width();
273
274
275 this.showToSouceHeightRatio=this.showvheight/this.sourceimg_h;
276 this.showToSourceWidthRatio=this.showvwidth/this.sourceimg_w;
277
278 //右侧展示区域,展示当前工作区处于图片的区域
279 //按照短边的比例对图片进行缩放
280 if (this.showToSouceHeightRatio<this.showToSourceWidthRatio)
281 {
282 this.showvimgheight=this.showvheight;
283 this.showvimgwidth=this.showToSouceHeightRatio*this.sourceimg_w;
284 }
285 else
286 {
287 this.showvimgheight=this.sourceimg_h*this.showToSourceWidthRatio;
288 this.showvimgwidth=this.showvwidth;
289 }
290 this.showviewimg.attr('src',this.workviewimg.attr('src')).css({"width":this.showvimgwidth+"px","height":this.showvimgheight+"px"});
291
292 this.DrawClipRegionTosShow();
293 }
294
295
296 }
297 }
298
299 $(function () {
300 let clip = new ClipTools();
301 clip.Init();
302 })
还有个文件保存的功能,由于裁剪之后,展示区域的图片路径是base64,所以可以直接发送给服务器,或者用于本地图直接展示
有问题,希望指正,本人刚接触前端不久,谢谢!