How to make HTML5 draggable objects over canvas?

后端 未结 1 1087
别那么骄傲
别那么骄傲 2021-02-10 09:35

I just started learning html5 and I am trying to create a battleship interface with draggable ships. I need help making my dragging methods work. I am purposely not using a libr

相关标签:
1条回答
  • 2021-02-10 10:04

    This is the procedure for making an html shape draggable

    Note that this has been answered before on SO (many times!)

    But this answer illustrates the new context.isPointInPath method to hit-test whether a point is inside an html canvas path.

    Hopefully, this new hit-testing method will be new & useful to the OP and others :)

    Here's the general procedure for dragging shapes in html canvas:

    On mouseDown:

    • save this mouseX position in a variable (lastX)
    • save this mouseY position in a variable (lastY)
    • set the mouseIsDown flag to true

    On mouseUp

    • set the mouseIsDown flag to false

    On mouseMove

    • Hit-test each ship to see if it should be dragged.
    • If the lastX/lastY was inside a ship, that ship is being dragged
    • Move dragging ships by the distance the mouse has just moved

    MouseDown handler code:

    function handleMouseDown(e){
    
      // get the current mouse position relative to the canvas
    
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
    
      // save this last mouseX/mouseY
    
      lastX=mouseX;
      lastY=mouseY;
    
      // set the mouseIsDown flag
    
      mouseIsDown=true;
    }
    

    MouseUp handler code:

    function handleMouseUp(e){
    
      // clear the mouseIsDown flag
    
      mouseIsDown=false;
    }
    

    MouseMove handler code:

    This code illustrates using context.isPointInPath to hit-test an html canvas path

    The procedure to do that is:

    • define a path (but not draw it -- no fill, no stroke)
    • use context.isPointInPath(x,y) to test if x,y are inside the path defined above.

    Here's the mouseMove handler using context.isPointInPath

    function handleMouseMove(e){
    
      // if the mouseIsDown flag is’nt set, no work to do
    
      if(!mouseIsDown){ return; }
      // get mouseX/mouseY
    
      mouseX=parseInt(e.clientX-offsetX);
      mouseY=parseInt(e.clientY-offsetY);
    
      // for each ship in the ships array
      // use context.isPointInPath to test if it’s being dragged
    
      for(var i=0;i<ships.length;i++){
          var ship=ships[i];
          drawShip(ship);
          if(ctx.isPointInPath(lastX,lastY)){ 
    
              // if this ship’s being dragged, 
              // move it by the change in mouse position from lastXY to currentXY
    
              ship.x+=(mouseX-lastX);
              ship.y+=(mouseY-lastY);
              ship.right=ship.x+ship.width;
              ship.bottom=ship.y+ship.height;
          }
      }
    
      // update the lastXY to the current mouse position
      lastX=mouseX;
      lastY=mouseY;
    
      // draw all ships in their new positions
      drawAllShips();
    }
    

    Note about enhancing performance:

    • In production, you'll want to have the mouseMove just save the mouse positions.
    • Then have another procedure retrieve those saved positions and do hit-testing/redrawing.
    • That other procedure will probably be inside a timed loop like requestAnimationFrame.

    Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/sEBAC/

    <!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");
        ctx.strokeStyle="lightgray";
    
        var canvasOffset=$("#canvas").offset();
        var offsetX=canvasOffset.left;
        var offsetY=canvasOffset.top;
    
        var mouseIsDown=false;
        var lastX=0;
        var lastY=0;
    
        var ships=[];
    
        // make some ship
        makeShip(20,30,50,25,"skyblue");
        makeShip(20,100,30,25,"skyblue");
        makeShip(20,170,50,25,"salmon");
        makeShip(20,240,30,25,"salmon");
    
        function makeShip(x,y,width,height,fill){
            var ship={
              x:x,
              y:y,
              width:width,
              height:height,
              right:x+width,
              bottom:y+height,
              fill:fill
            }
            ships.push(ship);
            return(ship);
        }
    
        drawAllShips();
    
        function drawAllShips(){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            for(var i=0;i<ships.length;i++){
                var ship=ships[i]
                drawShip(ship);
                ctx.fillStyle=ship.fill;
                ctx.fill();
                ctx.stroke();
            }
        }
    
        function drawShip(ship){
            ctx.beginPath();
            ctx.moveTo(ship.x,ship.y);
            ctx.lineTo(ship.right,ship.y);
            ctx.lineTo(ship.right+10,ship.y+ship.height/2);
            ctx.lineTo(ship.right,ship.bottom);
            ctx.lineTo(ship.x,ship.bottom);
            ctx.closePath();
        }
    
        function handleMouseDown(e){
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
    
          // mousedown stuff here
          lastX=mouseX;
          lastY=mouseY;
          mouseIsDown=true;
    
        }
    
        function handleMouseUp(e){
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
    
          // mouseup stuff here
          mouseIsDown=false;
        }
    
        function handleMouseMove(e){
          if(!mouseIsDown){ return; }
    
          mouseX=parseInt(e.clientX-offsetX);
          mouseY=parseInt(e.clientY-offsetY);
    
          // mousemove stuff here
          for(var i=0;i<ships.length;i++){
              var ship=ships[i];
              drawShip(ship);
              if(ctx.isPointInPath(lastX,lastY)){ 
                  ship.x+=(mouseX-lastX);
                  ship.y+=(mouseY-lastY);
                  ship.right=ship.x+ship.width;
                  ship.bottom=ship.y+ship.height;
              }
          }
          lastX=mouseX;
          lastY=mouseY;
          drawAllShips();
        }
    
        $("#canvas").mousedown(function(e){handleMouseDown(e);});
        $("#canvas").mousemove(function(e){handleMouseMove(e);});
        $("#canvas").mouseup(function(e){handleMouseUp(e);});
    
    }); // end $(function(){});
    </script>
    
    </head>
    
    <body>
        <canvas id="canvas" width=300 height=300></canvas>
    </body>
    </html>
    
    0 讨论(0)
提交回复
热议问题