拖动在画布上绘制的形状与绘制相同

时间:2014-03-10 12:26:18

标签: javascript html5-canvas

我有类似于paint的工具,我允许用户使用鼠标事件在画布上绘制不同的形状。我希望允许用户在画布上绘制后拖动形状(与绘画相同)。以前有人这样做过吗?我已经尝试过使用OOPDragging,但这在我的情况下不起作用。我的工具还包括各种形状,如Line,elbow connector,oval,text,image,而不仅仅是圆形和矩形。任何人都可以建议一些容易实现的解决方案,因为我需要尽快。 提前谢谢。

2 个答案:

答案 0 :(得分:3)

演示:http://jsfiddle.net/m1erickson/JrzM2/

假设您已在绘图程序中创建了此三角形

enter image description here

该三角形的点数如下:

[{x:0,y:20},{x:30,y:0},{x:70,y:45}]

要将该三角形移动到[20,35],您需要先将三角形偏移x:20& Y:35

var myTriangle={
    x:20,
    y:35,
    points:[{x:0,y:20},{x:30,y:0},{x:70,y:45}]
}

然后你可以像这样在[20,35]绘制三角形:

请注意,偏移量(20,35)会添加到三角形位置的每个点

function draw(myTriangle){

    var x=myTriangle.x;
    var y=myTriangle.y;
    var points=myTriangle.points;

    ctx.beginPath();
    ctx.moveTo( x+points[0].x, y+points[0].y );
    for(var i=1;i<points.length;i++){
        ctx.lineTo( x+points[i].x, y+points[i].y );
    }
    ctx.closePath();
    ctx.fill();

}

要拖动三角形,您可以监听鼠标事件

  • 在mousedown中,检查鼠标是否在三角形上方。如果是,请开始拖动。
  • 在mousemove中,添加用户从上次mousemove拖动到三角形位置的距离。
  • 在mouseup中,停止拖动

在mousedown中

Canvas有一个很好的内置函数来测试任何指定的点是否在像三角形这样的路径中。

此函数是context.isPointInPath(mouseX,mouseY),它测试mouseX / mouseY是否在最后绘制的路径中。

如果在三角形上按下鼠标,我们设置isSelected标志以指示每次鼠标移动时应拖动三角形。

所以mousedown函数如下所示:

function handleMouseDown(e){

  // tell the browser we're using mousedown, 
  // so don't bother doing any browser stuff with this event
  e.preventDefault();

  // get the current mouseX,mouseY position
  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // test if mouseX,mouseY is inside the triangle
  if(ctx.isPointInPath(startX,startY)){

      // if yes, set the "isSelected" flag
      // which indicates that the triangle should 
      // move with the mouse
      isSelected=true;
  }
}

在mousemove中

当用户移动鼠标时,mousemove事件每秒触发约20-30次。

在mousemove中,如果三角形被选中,我们想要计算自上次mousemove事件以来鼠标移动了多远。

然后我们想要将三角形的x,y位置改变鼠标移动的距离。

所以mousemove函数如下所示:

function handleMouseMove(e){

  // if the triangle wasn't selected during mousedown
  // there's nothing to do, so just return
  if(!isSelected){return;}
  e.preventDefault();

  // get the current mouse position
  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // calculate how far the mouse has moved since the last mousemove
  var dx=mouseX-startX;
  var dy=mouseY-startY;

  // for next mousemove, reset the starting XY to the current XY
  startX=mouseX;
  startY=mouseY;

  // move the triangle by the change in mouse position 
  myTriangle.x+=dx;
  myTriangle.y+=dy;

  // clear the canvas and 
  // redraw the triangle at its new position
  context.clearRect(0,0,canvas.width,canvas.height);
  draw(myTriangle);

}

在mouseup中

在mouseup中,由于拖动结束,isSelected标志被清除:

function handleMouseUp(e){
  e.preventDefault();
  isSelected=false;
}

以下是具有多种形状的更复杂示例的代码:

<!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(){

    // vars related to canvas
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();
    var cw=canvas.width;
    var ch=canvas.height;

    // vars related to dragging
    var isDown=false;
    var startX;
    var startY;

    // save your shape-points in
    var shapes=[];
    var selectedShape=null;

    // test shapes
    addShape(50,50,[{x:0,y:20},{x:30,y:0},{x:70,y:45}],"blue","red");
    addShape(100,100,
        [{x:0,y:10},{x:30,y:10},{x:30,y:0},
        {x:45,y:15},{x:30,y:30},{x:30,y:20},{x:0,y:20}],
        "green","red");

    // begin...
    drawAll();


    function addShape(x,y,points,fill,stroke){
        shapes.push({x:x,y:y,points:points,fill:fill,stroke:stroke});
    }

    function define(shape){
        var x=shape.x;
        var y=shape.y;
        var points=shape.points;
        ctx.beginPath();
        ctx.moveTo(x+points[0].x,y+points[0].y);
        for(var i=1;i<points.length;i++){
            ctx.lineTo(x+points[i].x,y+points[i].y);
        }
        ctx.closePath();
    }

    function draw(shape){
        define(shape);
        ctx.fillStyle=shape.fill;
        ctx.fill();
        ctx.strokeStyle=shape.stroke;
        ctx.stroke();
    }

    function drawAll(){
        ctx.clearRect(0,0,cw,ch);
        for(var i=0;i<shapes.length;i++){
            draw(shapes[i]);
        }
    }

    function handleMouseDown(e){
      e.preventDefault();
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);
      for(var i=0;i<shapes.length;i++){
          define(shapes[i]);
          if(ctx.isPointInPath(startX,startY)){
              selectedShape=shapes[i];
              isDown=true;
          }
      }
    }

    function handleMouseUp(e){
      e.preventDefault();
      isDown=false;
      selectedShape=null;
    }

    function handleMouseOut(e){
      e.preventDefault();
      isDown=false;
      selectedShape=null;
    }

    function handleMouseMove(e){
      if(!isDown){return;}
      e.preventDefault();
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
      var dx=mouseX-startX;
      var dy=mouseY-startY;
      startX=mouseX;
      startY=mouseY;

      selectedShape.x+=dx;
      selectedShape.y+=dy;
      drawAll();

    }

    $("#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>
    <h4>Drag the shapes around the canvas</h4>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

答案 1 :(得分:0)

前段时间我遇到了同样的问题,但我只需要线路,但我认为你可以使用我的解决方案来处理所有不同的形状。

基本上你需要重叠画布,一个监听鼠标事件并绘制临时形状的画布,一旦用户释放鼠标按钮,你就会获得值并在原始画布上绘制形状。这是我所做的链接:http://www.zhereicome.com/experiments/statics/drawtogether/

和主要的js文件: http://www.zhereicome.com/experiments/statics/drawtogether/js/main.js

重要的是:     temp_canvas.onmousemove = function(e){             //console.log(e);             if(self.mouseDown){                 self.drawTempLine(e.clientX,e.clientY);             }         }

    temp_canvas.onmousedown = function(e) {
        start = {
            x: e.clientX,
            y: e.clientY
        }
        self.mouseDown = true;
    }

    temp_canvas.onmouseup = function(e) {
        end = {
            x: e.clientX,
            y: e.clientY
        }
        self.mouseDown = false;
        self.sendToServer(); //When the user has finished drawing the line, send it to the server
    }

我有一个函数sendToServer(),因为我的项目是一个实时多人绘图应用程序。在你的情况下,你将不得不用drawOnFinalCanvas();

替换它