有了上一篇圖片放大鏡的鋪墊,今天的這個例子是縮小鏡,因為裁剪的原圖往往很大,不能在工作區域看到全部圖片,所以,要有縮小鏡來顯示,當前裁剪的區域是原圖的個部分.按照慣例首先看下效果圖:
功能一:載入默認圖片
功能二:選擇本地圖片
功能三:拖拽(鼠標直接拖動工作區視窗)
功能四:放大,縮小(點擊按鈕放大/縮小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,所以可以直接發送給服務器,或者用於本地圖直接展示
有問題,希望指正,本人剛接觸前端不久,謝謝!