实现一个类似于QQ截图的小东西,点击载入按钮,则载入图片,长按图片,弹出截图框,截图框右下角能够调整大小,并在右边的截图预览区域实时显示
需求
实现一个类似于QQ截图的小东西,点击载入按钮,则载入图片,长按图片,弹出截图框,截图框右下角能够调整大小,并在右边的截图预览区域实时显示,其最终效果图如下:

HTML
需要注意canvas的设置,主要结构如下:
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | <section class="clearfix"><div id="origin">
 <canvas id="originImg" width="500" height="500"></canvas>
 <div id="shotRect">
 <div class="resizeBR"></div>
 </div>
 </div>
 <canvas id="showPre" width="500" height="500"></canvas>
 </section>
 
 | 
CSS
截图框初始大小为50px50px,右下角设置了一个不可见的调节区域,此处大小设置为12px12px,并在之后为其注册调整大小的事件。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | #shotRect {position: absolute;
 display: none;
 width: 50px;
 height: 50px;
 opacity: .5;
 border: 2px solid #2d2d2d;
 }
 
 .resizeBR {
 position: absolute;
 right: -5px;
 bottom: -5px;
 width: 12px;
 height: 12px;
 cursor: nw-resize;
 opacity: 0;
 background: #000;
 background: #ff0;
 }
 
 | 
其中原始图片的canvas大小与预览区的大小一致。
JavaScript
载入图片,并绘制canvas
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | function loadImg(event) { cOri = document.getElementById("originImg");
 imgOri = new Image();
 ctxOri = cOri.getContext("2d");
 imgOri.src = "vegetable.jpg";
 imgOri.onload=function(){
 ctxOri.drawImage(imgOri,0,0,500,500);
 };
 }
 
 | 
长按待截图区域,弹出截图框
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | function longClick(event) { event = event || window.event;
 var shotRect = document.getElementById("shotRect");
 timeout = setTimeout(function() {
 shotRect.style.display = "block";
 var disX = event.clientX - shotRect.offsetWidth + 10,
 disY = event.clientY - shotRect.offsetHeight + 10;
 shotRect.style.left = disX + 'px';
 shotRect.style.top = disY + 'px';
 initCanvas();
 updateRect(disX, disY, shotRect.offsetWidth, shotRect.offsetHeight);
 }, 1000);
 }
 
 | 
释放鼠标时,需要清除timeout。
初始化预览canvas
| 12
 3
 4
 5
 
 | function initCanvas() {cPre = document.getElementById("showPre");
 ctxPre = cPre.getContext("2d");
 img = document.getElementById("originImg");
 }
 
 | 
更新预览canvas
根据原始图片,在预览区域上使用drawImage方法画出预览图,其中x,y为截图框左上角相对于原始图片左上角的坐标;而w,h为截图框的长与宽;这四个参数提取出了截图框内的图像数据,而之后(0,0)这个坐标代表在画布上放置该图像数据的坐标位置,(0,0)意味着将该图像数据的左上角与预览区域的左上角重合。
| 12
 3
 4
 
 | function updateRect(x, y, w, h) {ctxPre.clearRect(0, 0, 500, 500);
 ctxPre.drawImage(img, x, y, w, h, 0, 0, 500, 500);
 }
 
 | 
调整截图框大小
计算截图框左上角的坐标,并根据调整大小后鼠标的坐标,并据此重新设置截图框的大小,然后调用更新截图预览的函数updateRect,注意限制截图框的边界不能超过原始图片的大小。
| 12
 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
 
 | function resizeDown(event) {event = event || window.event;
 var shotRect = document.getElementById("shotRect"),
 
 x = shotRect.offsetLeft,
 y = shotRect.offsetTop ;
 
 
 document.addEventListener("mousemove", mouseMove);
 document.addEventListener("mouseup", mouseUp);
 
 function mouseMove(event) {
 event = event || window.event;
 var finalX = event.clientX,
 finalY = event.clientY;
 
 if (event.clientX >= 488) {
 finalX = 488;
 }
 if (event.clientY >= 488) {
 finalY = 488;
 }
 
 xy = (finalX - x + 10) < (finalY - y +10) ? (finalX -x + 10) : (finalY - y + 10);
 
 shotRect.style.width = xy + 'px';
 shotRect.style.height = xy + 'px';
 updateRect(x, x, shotRect.offsetWidth, shotRect.offsetHeight);
 }
 
 function mouseUp() {
 
 document.removeEventListener("mousemove", mouseMove);
 document.removeEventListener("mouseup", mouseUp);
 }
 }
 
 | 
移动截图框
详看注释吧~
| 12
 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
 
 | function dragDown(event) {event = event || window.event;
 if (event.target !== event.currentTarget) return;
 var shotRect = document.getElementById("shotRect"),
 disX = event.clientX - shotRect.offsetLeft,
 disY = event.clientY - shotRect.offsetTop;
 
 document.addEventListener("mousemove", mouseMove);
 document.addEventListener("mouseup", mouseUp);
 
 function mouseMove(event) {
 event = event || window.event;
 var disL = event.clientX - disX,
 disT = event.clientY - disY,
 maxW = document.getElementById("originImg").clientWidth - shotRect.offsetWidth,
 maxH = document.getElementById("originImg").clientHeight - shotRect.offsetHeight;
 
 if (disL < 0) {
 disL = 0;
 } else if (disL > maxW) {
 disL = maxW + 1;
 }
 if (disT < 0) {
 disT = 0;
 } else if (disT > maxH) {
 disT = maxH + 1;
 }
 shotRect.style.left = disL + 'px';
 shotRect.style.top = disT + 'px';
 updateRect(disL, disT, shotRect.offsetWidth, shotRect.offsetHeight);
 }
 
 function mouseUp(event) {
 document.removeEventListener("mousemove", mouseMove);
 document.removeEventListener("mouseup", mouseUp);
 }
 }
 
 | 
保存图片
由于跨域问题,保存在chrome无效,在firefox中有效:
| 12
 3
 4
 5
 
 | function saveImg(event) {var image = cPre.toDataURL("image/png");
 var w = window.open('about:blank', 'image from canvas');
 w.document.write("<img src='" + image + "' alt='from canvas'/>");
 }
 
 | 
完整代码