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

Posted

技术标签:

【中文标题】如何在 HTML5 Canvas 中创建可拖动的线条?【英文标题】:How to Create a Draggable Line in HTML5 Canvas? 【发布时间】:2011-07-30 09:02:53 【问题描述】:

那么,如果你在 html5 画布上画一条线,那么让它在鼠标拖动上可拖动的最佳方法是什么?我知道你可以在 SVG 中很容易地做到这一点,但由于画布不是那么容易使用,我想知道一个很好的解决方案。

【问题讨论】:

看看这个 tut langexplr.blogspot.com/2008/11/using-canvas-html-element.html 【参考方案1】:

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

关于 html5 画布的注意事项: 你不能真正移动已经在 html5 画布上绘制的任何东西。相反,您可以通过清除画布并在新位置重新绘制所有内容来模拟运动

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

    创建定义一些行的对象数组:x0:,y0:,x1:,y1:

    mousedown 上,计算哪条线最靠近鼠标位置。

    设置一个标志,表示正在拖动一条线。

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

    mouseupmouseout 上,清除拖动标志。

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

// 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; 
#canvasborder: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>

【讨论】:

如果你有一个可以让你在画布界面上用鼠标绘制的功能,你会如何改变这个,因此有没有办法调整大小。【参考方案2】:

    mousedown 上,记录您的鼠标位置和行位置并注册一个围绕这些起始位置关闭的mousemove 处理程序,并注册一个mouseup 处理程序以删除mousemove 处理程序。

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

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

【讨论】:

以上是关于如何在 HTML5 Canvas 中创建可拖动的线条?的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 Canvas:在画布外拖动

HTML5 Canvas:在画布外拖动

HTML5 Canvas 中可拖动、可缩放的图像

HTML5中Canvas怎么拖动元素

如何在 Serilog 输出模板中创建可选属性?

如何在 Ionic 4/5 中拖动元素