drag element on canvas

99封情书 提交于 2020-12-30 03:14:03

问题


I draw an element onto a canvas as a string. I then want to be able to click the element (or tap on a mobile device) and drag it around. What I have now is:

<!DOCTYPE html>
<html>
    <head>
         <link rel="stylesheet" href="bootstrap.min.css" />
        <link type="text/css" rel="stylesheet" href="stylesheet.css"/>
        <script src="jquery-1.11.0.js"></script>
    </head>
    <body>
         <canvas id="canvas1" width="662" height="983">
             <script src="jquery-1.11.0.js"></script>
        </canvas>

        <script>
            var chosenChord=""; //this gets updated at various times by excluded code, but that code works, because the chord does always print correctly below
    `       $("button").click(function() {
                canvas = document.getElementById('canvas1');
                canvas1.addEventListener('click', on_canvas_click, false);

                function on_canvas_click(ev) {
                    x = ev.clientX - canvas1.offsetLeft-40;
                    y = ev.clientY - canvas1.offsetTop;

                   //add to canvas
                    var canvas = document.getElementById("canvas1");
                    var context = canvas.getContext("2d");
                    context.fillStyle = "blue";
                    context.font = "bold 16px Arial";
                    context.fillText([theString], [x], [y]);
                });
            });
        </script>   
    </body>
</html>

What do I need to add in order to enable this drag functionality?


回答1:


Here's an outline of how to drag an element on canvas

A Demo: http://jsfiddle.net/m1erickson/AGd6u/

Listen for mouse events: mousedown, mousemove, mouseup, mouseout

    // listen for mouse events
    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUp(e);});
    $("#canvas").mouseout(function(e){handleMouseOut(e);});

Define your pieces of text as objects in an array

    // some text objects
    var texts=[];

    // some test texts
    texts.push({text:"Hello",x:20,y:20});
    texts.push({text:"World",x:20,y:70});

In mousedown:

  • Test if the mouse is over the text
  • If yes, select that text for dragging

    // handle mousedown events
    // iterate through texts[] and see if the user
    // mousedown'ed on one of them
    // If yes, set the selectedText to the index of that text
    function handleMouseDown(e){
      e.preventDefault();
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);
      // Put your mousedown stuff here
      for(var i=0;i<texts.length;i++){
          if(textHittest(startX,startY,i)){
              selectedText=i;
          }
      }
    }
    

In mousemove:

  • change the position of the selected text by the distance the user has dragged
  • redraw the canvas

    // handle mousemove events
    // calc how far the mouse has been dragged since
    // the last mousemove event and move the selected text
    // by that distance
    function handleMouseMove(e){
      if(selectedText<0){return;}
      e.preventDefault();
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
    
      // Put your mousemove stuff here
      var dx=mouseX-startX;
      var dy=mouseY-startY;
      startX=mouseX;
      startY=mouseY;
    
      var text=texts[selectedText];
      text.x+=dx;
      text.y+=dy;
      draw();
    }
    

In mouseup:

  • the drag is over so deselect the text

    // done dragging
    function handleMouseUp(e){
      e.preventDefault();
      selectedText=-1;
    }
    

Example code:

<!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");

    // variables used to get mouse position on the canvas
    var $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    // variables to save last mouse position
    // used to see how far the user dragged the mouse
    // and then move the text by that distance
    var startX;
    var startY;

    // some text objects
    var texts=[];

    // some test texts
    texts.push({text:"Hello",x:20,y:20});
    texts.push({text:"World",x:20,y:70});

    // calculate width of each text for hit-testing purposes
    ctx.font="16px verdana";
    for(var i=0;i<texts.length;i++){
        var text=texts[i];
        text.width=ctx.measureText(text.text).width;
        text.height=16;
    }

    // this var will hold the index of the selected text
    var selectedText=-1;

    // START: draw all texts to the canvas
    draw();

    // clear the canvas draw all texts
    function draw(){
        ctx.clearRect(0,0,canvas.width,canvas.height);
        for(var i=0;i<texts.length;i++){
            var text=texts[i];
            ctx.fillText(text.text,text.x,text.y);
        }
    }

    // test if x,y is inside the bounding box of texts[textIndex]
    function textHittest(x,y,textIndex){
        var text=texts[textIndex];
        return(x>=text.x && 
            x<=text.x+text.width &&
            y>=text.y-text.height && 
            y<=text.y);
    }

    // handle mousedown events
    // iterate through texts[] and see if the user
    // mousedown'ed on one of them
    // If yes, set the selectedText to the index of that text
    function handleMouseDown(e){
      e.preventDefault();
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);

      // Put your mousedown stuff here
      for(var i=0;i<texts.length;i++){
          if(textHittest(startX,startY,i)){
              selectedText=i;
          }
      }
    }

    // done dragging
    function handleMouseUp(e){
      e.preventDefault();
      selectedText=-1;
    }

    // also done dragging
    function handleMouseOut(e){
      e.preventDefault();
      selectedText=-1;
    }

    // handle mousemove events
    // calc how far the mouse has been dragged since
    // the last mousemove event and move the selected text
    // by that distance
    function handleMouseMove(e){
      if(selectedText<0){return;}
      e.preventDefault();
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);

      // Put your mousemove stuff here
      var dx=mouseX-startX;
      var dy=mouseY-startY;
      startX=mouseX;
      startY=mouseY;

      var text=texts[selectedText];
      text.x+=dx;
      text.y+=dy;
      draw();
    }

    // listen for mouse events
    $("#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>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>



回答2:


I think the answer by @markE is really good. I would just like to add my 2c though.

Working with canvas directly can become daunting very quickly, as you have to do all sorts of state management on your own.

I think it's wise when you want to do something like this to rather utilize one of the many amazing frameworks out there that aims to make vector drawing on canvas easier.

To name but a few:

  • paper.js (I've created a screencast on paperjs -> http://tagtree.tv/canvas-with-paper-js)
  • easeljs
  • kineticjs


来源:https://stackoverflow.com/questions/21605942/drag-element-on-canvas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!