如何在HTML5 Canvas中创建可拖动的线?

时间:2011-04-05 22:18:04

标签: html5 canvas draggable line

因此,如果您在HTML5画布上绘制一条线,那么在onMouseDrag上使其可拖动的最佳方法是什么?我知道你可以很容易地在SVG中做到这一点,但由于画布不太容易使用,我想知道一个很好的解决方案。

2 个答案:

答案 0 :(得分:2)

  1. mousedown上,记录您的鼠标位置和行位置,并在这些起始位置周围注册mousemove处理程序,并注册mouseup处理程序以删除{{1}处理程序。

  2. mousemove处理程序中,找到当前鼠标位置和起始鼠标位置之间的偏移量,将此偏移量添加到起始行位置,然后使用此新位置重绘画布。

  3. 您可能希望独立跟踪每个对象的变换,因此本质上您将自己重建一个保留的绘图模式图形系统,如SVG或HTML。

答案 1 :(得分:2)

这是在html5画布上创建可拖动线条的一种方式。

关于html5画布的注意事项:你无法真正移动任何已在html5画布上绘制的内容。而是通过清除画布并重新绘制其中新内容中的所有内容来模拟移动

这是让用户在画布上“拖动”一行的方法:

  1. 创建一个定义某些行的对象数组:{x0:,y0:,x1:,y1:}

  2. mousedown上,计算哪条线最接近鼠标位置。

  3. 设置一个标志,指示正在拖动一条线。

  4. mousemove上,将拖动线的X,Y更改为鼠标所具有的距离 自上次mousemove以来已移动。然后清除画布并重新绘制当前位置的所有行。

  5. mouseupmouseout上,清除拖动标记。

  6. 这是带注释的代码和演示:

    // canvas vars
    var canvas=document.getElementById("canvas");
    var ctx=canvas.getContext("2d");
    var cw=canvas.width;
    var ch=canvas.height;
    function reOffset(){
        var BB=canvas.getBoundingClientRect();
        offsetX=BB.left;
        offsetY=BB.top;        
    }
    var offsetX,offsetY;
    reOffset();
    window.onscroll=function(e){ reOffset(); }
    window.onresize=function(e){ reOffset(); }
    
    // dragging vars
    var isDown=false;
    var startX,startY;
    
    // line vars
    var nearest;
    var lines=[];
    lines.push({x0:75, y0:25, x1:125,y1:25});
    lines.push({x0:75, y0:100, x1:125, y1:100});
    lines.push({x0:50, y0:35, x1:50,y1:85});
    lines.push({x0:150,y0:35, x1:150,y1:85});
    
    draw();
    
    // listen for mouse events
    $("#canvas").mousedown(function(e){handleMouseDown(e);});
    $("#canvas").mousemove(function(e){handleMouseMove(e);});
    $("#canvas").mouseup(function(e){handleMouseUpOut(e);});
    $("#canvas").mouseout(function(e){handleMouseUpOut(e);});
    
    
    // functions
    //////////////////////////
    
    // select the nearest line to the mouse
    function closestLine(mx,my){
        var dist=100000000;
        var index,pt;
        for(var i=0;i<lines.length;i++){
            //
            var xy=closestXY(lines[i],mx,my);
            //
            var dx=mx-xy.x;
            var dy=my-xy.y;
            var thisDist=dx*dx+dy*dy;
            if(thisDist<dist){
                dist=thisDist;
                pt=xy;
                index=i;
            }
        }
        var line=lines[index];
        return({ pt:pt, line:line, originalLine:{x0:line.x0,y0:line.y0,x1:line.x1,y1:line.y1} });
    }
    
    // linear interpolation -- needed in setClosestLine()
    function lerp(a,b,x){return(a+x*(b-a));}
    
    // find closest XY on line to mouse XY
    function closestXY(line,mx,my){
        var x0=line.x0;
        var y0=line.y0;
        var x1=line.x1;
        var y1=line.y1;
        var dx=x1-x0;
        var dy=y1-y0;
        var t=((mx-x0)*dx+(my-y0)*dy)/(dx*dx+dy*dy);
        t=Math.max(0,Math.min(1,t));
        var x=lerp(x0,x1,t);
        var y=lerp(y0,y1,t);
        return({x:x,y:y});
    }
    
    // draw the scene
    function draw(){
        ctx.clearRect(0,0,cw,ch);
        // draw all lines at their current positions
        for(var i=0;i<lines.length;i++){
            drawLine(lines[i],'black');
        }
        // draw markers if a line is being dragged
        if(nearest){
            // point on line nearest to mouse
            ctx.beginPath();
            ctx.arc(nearest.pt.x,nearest.pt.y,5,0,Math.PI*2);
            ctx.strokeStyle='red';
            ctx.stroke();
            // marker for original line before dragging
            drawLine(nearest.originalLine,'red');
            // hightlight the line as its dragged
            drawLine(nearest.line,'red');
        }
    }
    
    function drawLine(line,color){
        ctx.beginPath();
        ctx.moveTo(line.x0,line.y0);
        ctx.lineTo(line.x1,line.y1);
        ctx.strokeStyle=color;
        ctx.stroke();
    }
    
    function handleMouseDown(e){
      // tell the browser we're handling this event
      e.preventDefault();
      e.stopPropagation();
      // mouse position
      startX=parseInt(e.clientX-offsetX);
      startY=parseInt(e.clientY-offsetY);
      // find nearest line to mouse
      nearest=closestLine(startX,startY);
      draw();
      // set dragging flag
      isDown=true;
    }
    
    function handleMouseUpOut(e){
      // tell the browser we're handling this event
      e.preventDefault();
      e.stopPropagation();
      // clear dragging flag
      isDown=false;
      nearest=null;
      draw();
    }
    
    function handleMouseMove(e){
        if(!isDown){return;}
        // tell the browser we're handling this event
        e.preventDefault();
        e.stopPropagation();
        // mouse position
        mouseX=parseInt(e.clientX-offsetX);
        mouseY=parseInt(e.clientY-offsetY);
        // calc how far mouse has moved since last mousemove event
        var dx=mouseX-startX;
        var dy=mouseY-startY;
        startX=mouseX;
        startY=mouseY;
        // change nearest line vertices by distance moved
        var line=nearest.line;
        line.x0+=dx;
        line.y0+=dy;
        line.x1+=dx;
        line.y1+=dy;
        // redraw
        draw();
    }
    body{ background-color: ivory; }
    #canvas{border:1px solid red; }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
    <h4>Drag the lines...</h4>
    <canvas id="canvas" width=300 height=300></canvas>