javascript 使用鼠标在画布中旋转图像
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19229319/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
To rotation an image in canvas using mouse
提问by Deepu S A
In my code I am loading an image in to a canvas. Then I need to resize, rotate and drag it. I managed to implement both dragging and resizing.
在我的代码中,我将图像加载到画布中。然后我需要调整大小、旋转和拖动它。我设法实现了拖动和调整大小。
How can I implement rotation(along the center of the image) using mouse on this code.
如何在此代码上使用鼠标实现旋转(沿图像中心)。
My HTML page:
我的 HTML 页面:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:10px;}
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX;
var startY;
var isDown=false;
var pi2=Math.PI*2;
var resizerRadius=8;
var rr=resizerRadius*resizerRadius;
var draggingResizer={x:0,y:0};
var imageX=50;
var imageY=50;
var imageWidth,imageHeight,imageRight,imageBottom;
var draggingImage=false;
var startX;
var startY;
var img=new Image();
img.onload=function(){
imageWidth=img.width;
imageHeight=img.height;
imageRight=imageX+imageWidth;
imageBottom=imageY+imageHeight
draw(true,false);
}
img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/facesSmall.png";
function draw(withAnchors,withBorders){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// draw the image
ctx.drawImage(img,0,0,img.width,img.height,imageX,imageY,imageWidth,imageHeight);
// optionally draw the draggable anchors
if(withAnchors){
drawDragAnchor(imageX,imageY);
drawDragAnchor(imageRight,imageY);
drawDragAnchor(imageRight,imageBottom);
drawDragAnchor(imageX,imageBottom);
}
// optionally draw the connecting anchor lines
if(withBorders){
ctx.beginPath();
ctx.moveTo(imageX,imageY);
ctx.lineTo(imageRight,imageY);
ctx.lineTo(imageRight,imageBottom);
ctx.lineTo(imageX,imageBottom);
ctx.closePath();
ctx.stroke();
}
}
function drawDragAnchor(x,y){
ctx.beginPath();
ctx.arc(x,y,resizerRadius,0,pi2,false);
ctx.closePath();
ctx.fill();
}
function anchorHitTest(x,y){
var dx,dy;
// top-left
dx=x-imageX;
dy=y-imageY;
if(dx*dx+dy*dy<=rr){ return(0); }
// top-right
dx=x-imageRight;
dy=y-imageY;
if(dx*dx+dy*dy<=rr){ return(1); }
// bottom-right
dx=x-imageRight;
dy=y-imageBottom;
if(dx*dx+dy*dy<=rr){ return(2); }
// bottom-left
dx=x-imageX;
dy=y-imageBottom;
if(dx*dx+dy*dy<=rr){ return(3); }
return(-1);
}
function hitImage(x,y){
return(x>imageX && x<imageX+imageWidth && y>imageY && y<imageY+imageHeight);
}
function handleMouseDown(e){
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
draggingResizer=anchorHitTest(startX,startY);
draggingImage= draggingResizer<0 && hitImage(startX,startY);
}
function handleMouseUp(e){
draggingResizer=-1;
draggingImage=false;
draw(true,false);
}
function handleMouseOut(e){
handleMouseUp(e);
}
function handleMouseMove(e){
if(draggingResizer>-1){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// resize the image
switch(draggingResizer){
case 0: //top-left
imageX=mouseX;
imageWidth=imageRight-mouseX;
imageY=mouseY;
imageHeight=imageBottom-mouseY;
break;
case 1: //top-right
imageY=mouseY;
imageWidth=mouseX-imageX;
imageHeight=imageBottom-mouseY;
break;
case 2: //bottom-right
imageWidth=mouseX-imageX;
imageHeight=mouseY-imageY;
break;
case 3: //bottom-left
imageX=mouseX;
imageWidth=imageRight-mouseX;
imageHeight=mouseY-imageY;
break;
}
// enforce minimum dimensions of 25x25
if(imageWidth<25){imageWidth=25;}
if(imageHeight<25){imageHeight=25;}
// set the image right and bottom
imageRight=imageX+imageWidth;
imageBottom=imageY+imageHeight;
// redraw the image with resizing anchors
draw(true,true);
}else if(draggingImage){
imageClick=false;
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// move the image by the amount of the latest drag
var dx=mouseX-startX;
var dy=mouseY-startY;
imageX+=dx;
imageY+=dy;
imageRight+=dx;
imageBottom+=dy;
// reset the startXY for next time
startX=mouseX;
startY=mouseY;
// redraw the image with border
draw(false,true);
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Resize the image using the 4 draggable corner anchors</p>
<p>You can also drag the image</p>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
回答by markE
Here's how to use a drag-handle to rotate an image
以下是如何使用拖动手柄旋转图像
The mousedown event handler hit-tests if the user is starting to drag the rotation-handle.
mousedown 事件处理程序命中测试用户是否开始拖动旋转手柄。
This hit-testing is made easier with context.isPointInPath(x,y) which tests whether a specified [x,y] coordinate is inside the most recently drawn path (Conveniently, the rotation-handle is actually a path).
使用 context.isPointInPath(x,y) 可以更轻松地进行命中测试,它测试指定的 [x,y] 坐标是否在最近绘制的路径内(方便地,旋转手柄实际上是一条路径)。
So mousedown activates the drag-handle like this:
所以 mousedown 像这样激活拖动手柄:
- Calculate the current mouseX and mouseY.
- Redraw the rotation handle (required because isPointInPath hit-tests just the most recent path)
- Set the isDown flag if the user did click in the rotation handle.
- 计算当前的 mouseX 和 mouseY。
- 重绘旋转手柄(需要,因为 isPointInPath 命中测试只是最近的路径)
- 如果用户确实单击了旋转手柄,则设置 isDown 标志。
The mousedown code looks like this:
mousedown 代码如下所示:
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
drawRotationHandle(false);
isDown=ctx.isPointInPath(mouseX,mouseY);
}
Yes...we could have simply hit-tested a circle on the end of the rotation-handle, but using isPointInPath will allow you to draw whatever fancy rotation handle you desire.
是的...我们可以简单地在旋转手柄的末端测试一个圆,但是使用 isPointInPath 将允许您绘制您想要的任何花哨的旋转手柄。
And isPointInPath has another nice benefit. When the context containing the path is rotated, isPointInPath will hit-test the rotated pathfor you. This means you don't have to code the math to unrotate the mouse coordinates to do the hit testing--it's done for you!
isPointInPath 还有另一个好处。当包含路径的上下文旋转时,isPointInPath 将为您点击测试旋转的路径。这意味着您不必编写数学代码来旋转鼠标坐标来进行命中测试——它已经为您完成了!
The mousemove handler redraws the rotatable image at the angle specified by the rotation-handle:
mousemove 处理程序以旋转手柄指定的角度重绘可旋转图像:
- If the isDown flag is not set, just return (the user is not dragging the rotation-handle).
- Calculate the current mouseX and mouseY.
- Calculate the current angle of the rotation-handle.
- Redraw the rotatable image at the current angle.
- 如果未设置 isDown 标志,则返回(用户未拖动旋转手柄)。
- 计算当前的 mouseX 和 mouseY。
- 计算旋转手柄的当前角度。
- 以当前角度重绘可旋转图像。
The mousemove code looks like this:
mousemove 代码如下所示:
function handleMouseMove(e){
if(!isDown){return;}
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
var dx=mouseX-cx;
var dy=mouseY-cy;
r=Math.atan2(dy,dx);
draw();
}
The image is drawn at the specified rotation using context's transform methods
使用上下文的变换方法在指定的旋转处绘制图像
function drawRect(){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(r);
ctx.drawImage(img,0,0);
ctx.restore();
}
Finally, the mouseup and mouseout handlers stop the drag operation by clearing the isDown flag.
最后,mouseup 和mouseout 处理程序通过清除isDown 标志来停止拖动操作。
function handleMouseUp(e){
isDown=false;
}
function handleMouseOut(e){
isDown=false;
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/QqwKR/
这是代码和小提琴:http: //jsfiddle.net/m1erickson/QqwKR/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isDown=false;
var cx=canvas.width/2;
var cy=canvas.height/2;
var w;
var h;
var r=0;
var img=new Image();
img.onload=function(){
w=img.width/2;
h=img.height/2;
draw();
}
img.src="facesSmall.png";
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawRotationHandle(true);
drawRect();
}
function drawRect(){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(r);
ctx.drawImage(img,0,0,img.width,img.height,-w/2,-h/2,w,h);
ctx.restore();
}
function drawRotationHandle(withFill){
ctx.save();
ctx.translate(cx,cy);
ctx.rotate(r);
ctx.beginPath();
ctx.moveTo(0,-1);
ctx.lineTo(w/2+20,-1);
ctx.lineTo(w/2+20,-7);
ctx.lineTo(w/2+30,-7);
ctx.lineTo(w/2+30,7);
ctx.lineTo(w/2+20,7);
ctx.lineTo(w/2+20,1);
ctx.lineTo(0,1);
ctx.closePath();
if(withFill){
ctx.fillStyle="blue";
ctx.fill();
}
ctx.restore();
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
drawRotationHandle(false);
isDown=ctx.isPointInPath(mouseX,mouseY);
console.log(isDown);
}
function handleMouseUp(e){
isDown=false;
}
function handleMouseOut(e){
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
var dx=mouseX-cx;
var dy=mouseY-cy;
r=Math.atan2(dy,dx);
draw();
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<p>Rotate by dragging blue rotation handle</p>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>