2013-10-07 50 views
5

在我的代碼中,我將圖像加載到畫布中。然後我需要調整大小,旋轉並拖動它。我設法實現拖拽和調整大小。使用鼠標在畫布中旋轉圖像

如何在此代碼上使用鼠標實現旋轉(沿圖像中心)。

我的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> 

回答

15

這裏是如何使用一拖柄,如果旋轉圖像

enter image description hereenter image description here

MouseDown事件處理程序命中測試用戶正在開始拖動旋轉手柄。

這個命中測試用context.isPointInPath(x,y)來測試一個指定的[x,y]座標是否位於最近繪製的路徑之內(方便地,旋轉手柄實際上是一個路徑)。

所以鼠標按下啓動拖動手柄這樣的:

  • 計算當前mouseX和mouseY的。
  • 重繪旋轉手柄(因爲isPointInPath命中 - 只測試最近的路徑)
  • 設置isDown標誌,如果用戶沒有點擊旋轉手柄。

鼠標按下代碼如下所示:

function handleMouseDown(e){ 
    mouseX=parseInt(e.clientX-offsetX); 
    mouseY=parseInt(e.clientY-offsetY); 
    drawRotationHandle(false); 
    isDown=ctx.isPointInPath(mouseX,mouseY); 
} 

是的......我們可以簡單地按下測試的旋轉手柄的末端處的圓圈,但使用isPointInPath將可以繪製不管你想要什麼花哨的旋轉。

而isPointInPath有另一個好處。當包含路徑的上下文被旋轉時,isPointInPath會爲您測試循環路徑。這意味着您不必編寫數學代碼來旋轉鼠標座標來進行命中測試 - 這是爲您完成的!

的鼠標移動處理程序在由旋轉句柄指定的角度重繪旋轉的圖像:

  • 如果未設置isDown標誌,只返回(用戶沒有拖動旋轉手柄) 。
  • 計算當前的mouseX和mouseY。
  • 計算旋轉手柄的當前角度。
  • 以當前角度重繪可旋轉圖像。

鼠標移動的代碼如下所示:

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(); 
} 

圖像以指定的旋轉通過繪製背景的變換方法

function drawRect(){ 
    ctx.save(); 
    ctx.translate(cx,cy); 
    ctx.rotate(r); 
    ctx.drawImage(img,0,0); 
    ctx.restore(); 
} 

最後,mouseup和鼠標移開處理程序停止通過清除isDown標誌進行拖動操作。

function handleMouseUp(e){ 
    isDown=false; 
} 

function handleMouseOut(e){ 
    isDown=false; 
} 

這裏是代碼和一個小提琴: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> 
+0

感謝真棒答案,@markE!但我有一個小問題。我的畫布有背景(在其上畫一個圖像),當我通過draw()函數添加「facesSmall.png」時,ctx.clearRect()使畫布變成白色空白。如何保持我之前繪製的圖像? – Davuz

+2

不客氣。如果您有背景圖片,只需在每個clearRect後面繪製圖片即可。乾杯! – markE

+0

哦,我明白了!這是簡單的解決方案! – Davuz