Как создать перетаскиваемую линию в холсте HTML5? - PullRequest
3 голосов
/ 06 апреля 2011

Итак, если вы рисуете линию на холсте HTML5, как лучше всего сделать его перетаскиваемым наMouseDrag? Я знаю, что вы можете сделать это очень легко в SVG, но поскольку работать с холстом не так просто, я хотел бы узнать хорошее решение для этого.

Ответы [ 2 ]

3 голосов
/ 25 марта 2016

Вот один из способов создания перетаскиваемых линий на холсте html5.

Примечание о холсте html5: Вы не можете переместить то, что уже было нарисованоHTML5 холст.Вместо этого вы имитируете движение , очищая холст и перерисовывая все на своей новой позиции.

Вот как пользователь может "перетащить" линию на холст:

  1. Создать массив объектов, которые определяют несколько линий: {x0:,y0:,x1:,y1:}.

  2. При mousedown, вычислить, какая линия ближе к положению мыши.

  3. Установите флаг, указывающий, что линия перетаскивается.

  4. Вкл. mousemove, измените X, Y перетаскиваемой линии на расстояние, которое имеет мышьпереехал с последнего mousemove.Затем очистите холст и перерисовайте все линии в их текущем положении.

  5. Вкл. mouseup или mouseout, снимите флажок перетаскивания.

Вот аннотированный код и демоверсия:

// 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>
2 голосов
/ 06 апреля 2011
  1. При mousedown запишите положение мыши и положение линии, зарегистрируйте обработчик mousemove, закрытый вокруг этих начальных позиций, и зарегистрируйте обработчик mouseup, чтобы удалить обработчик mousemove.

  2. В обработчике mousemove найдите смещение между текущей позицией мыши и начальной позицией мыши, добавьте это смещение к позиции начальной линии, а затем перерисовайте холст, используя эту новую позицию.

Возможно, вы захотите отслеживать преобразования каждого объекта независимо, поэтому, по сути, вы будете сами воссоздавать графическую систему с сохраненным режимом рисования, такую ​​как SVG или HTML.

...