最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - HTML5 Canvas drag image along path with coordinates - Stack Overflow

programmeradmin1浏览0评论

Is it possible to have an array of coordinates and drag and drop an image only along those coordinates? I would like to use only javascript and not use a javascript library. I keep scratching my head and googling this forever and can't find how to do this or if it is possible.

Is it possible to have an array of coordinates and drag and drop an image only along those coordinates? I would like to use only javascript and not use a javascript library. I keep scratching my head and googling this forever and can't find how to do this or if it is possible.

Share Improve this question asked Feb 4, 2014 at 21:30 gikygikgikygik 4219 silver badges27 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 3

Demo: http://jsfiddle/m1erickson/7vmML/

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./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 $canvas=$("#canvas");
    var canvasOffset=$canvas.offset();
    var offsetX=canvasOffset.left;
    var offsetY=canvasOffset.top;
    var scrollX=$canvas.scrollLeft();
    var scrollY=$canvas.scrollTop();

    var isDown=false;
    var startX;
    var startY;

    var points=[];
    points.push({x:10,y:10});
    points.push({x:75,y:100});
    points.push({x:150,y:125});
    points.push({x:125,y:200});

    var imageX=-200;
    var imageY=-200;

    var img=new Image();
    img.onload=start;
    img.crossOrigin="anonymous";
    img.src="https://dl.dropboxusercontent./u/139992952/stackoverflow/house32x32transparent.png";
    function start(){
        drawAll();
    }

    function drawAll(){

        ctx.clearRect(0,0,canvas.width,canvas.height);

        ctx.beginPath();
        ctx.moveTo(points[0].x+4,points[0].y+4)
        for(var i=1;i<points.length;i++){
            var pt=points[i];
            ctx.lineTo(pt.x+4,pt.y+4);
        }
        ctx.stroke();
        //
        for(var i=0;i<points.length;i++){
            var pt=points[i];
            ctx.fillRect(pt.x,pt.y,8,8);
        }
        //
        ctx.drawImage(img,imageX,imageY);

    }

    function handleMouseDown(e){
      e.preventDefault();
      isDown=true;
    }

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

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

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

      var minDistance=1000;
      var minPoint=-1;
      for(var i=0;i<points.length;i++){
          var pt=points[i];
          var dx=mouseX-pt.x;
          var dy=mouseY-pt.y;
          var distance=Math.sqrt(dx*dx+dy*dy);
          if(distance<minDistance){
              minDistance=distance;
              imageX=pt.x-img.width/2;
              imageY=pt.y-img.height/2;
          }
      }
      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 mouse.  Image will snap to nearest point.</h4>
    <canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Note that this example code uses jQuery to listen for mouse events. If you prefer pure javascript you can use these event bindings instead:

canvas.onmousedown=handleMouseDown;
canvas.onmouseup=handleMouseUp;
canvas.onmouseout=handleMouseOut;
canvas.onmousemove=handleMouseMove;

And you can calculate mouse position like this:

  function getMousePos(canvas,e) {
      var rect=canvas.getBoundingClientRect();
      return{ x:e.clientX-rect.left, y:e.clientY-rect.top };
  }

Yes, calculate the shortest distance to each of the points and override the mouse position with the point that is closest.

Lets use a simple point array as an example:

var points = [10,200, 50,250, 100,100, 150,120, 200,240,
              250,200, 300,120, 350,180, 400,150];

Now, when you move you item over you get the closest point this way:

Lets first get the mouse x and y position (for demo - in you code you would use the position of the item):

var rect = canvas.getBoundingClientRect(),
    x = e.clientX - rect.left,
    y = e.clientY - rect.top,

Now you can iterate the point array and get the point with shortest distance to mouse x and y:

var i = 0,
    pIndex = -1,
    minDist = 999999999,
    dist;

/// get shortest distance
for(; i < points.length; i+=2) {

    /// get distance from current point to mouse x,y
    dist = getDistance(x, y, points[i], points[i+1]);

    /// if less than previous distance, update
    if (dist < minDist) {
        minDist = dist;  /// current low
        pIndex = i;      /// point index
    }
}

pointX = points[pIndex];
pointY = points[pIndex+1];

The function for calculating distance is simple trigonometry calculating the hypotenuse:

function getDistance(x1, y1, x2, y2) {
    var dx = x2 - x1,
        dy = y2 - y1;
    return Math.abs(Math.sqrt(dx * dx + dy * dy));
}

Now you can draw your item at (pointX, pointY).

Live demo

The example here uses a very rough point array. If you need finer resolution you can use a line smoother such as this one or interpolate the point on the line. Here is a version where line smoothing is applied to increase its resolution and smoothness (you can drop the smoothness by setting tension to 0, and you can adjust resolution by changing number of segments, see following demo):

Here is a demo where line smoothing is used

Also have in mind that you may need to optimize the check range by for example doing a rough iteration first then use the 3-4 closest points and do a finer iteration between the range those represents.

Update

To allow snapping only when is held down and moved add these lines to code:

var allowMove = false;

canvas.onmousedown = function() {
    allowMove = true;
}
canvas.onmouseup = function() {
    allowMove = false;
}
canvas.onmousemove = function(e) {
    
    if (!allowMove) return;

    ... as before ...
发布评论

评论列表(0)

  1. 暂无评论