Как создать перетаскиваемую линию в холсте HTML5?
Так что, если вы рисуете линию на холсте HTML5, как лучше всего сделать его перетаскиваемым на MouseDrag? Я знаю, что вы можете сделать это очень легко в SVG, но поскольку работать с холстом не так просто, я хотел бы узнать хорошее решение для этого.
2 ответа
Вот один из способов создания перетаскиваемых линий на холсте html5.
Примечание о холсте html5: Вы не можете переместить что-либо, что уже было нарисовано на холсте html5. Вместо этого вы моделируете движение, очищая холст и перерисовывая все в новой позиции.
Вот как позволить пользователю "перетащить" строку на холст:
Создайте массив объектов, которые определяют несколько строк:
{x0:,y0:,x1:,y1:}
,На
mousedown
, рассчитать, какая линия ближе всего к позиции мыши.Установите флаг, указывающий, что линия перетаскивается.
На
mousemove
, измените X,Y перетаскиваемой линии на расстояние, на которое мышь переместилась с момента последнегоmousemove
, Затем очистите холст и перерисовайте все строки в их текущем положении.На
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>
На
mousedown
, запишите положение мыши и положение линии и зарегистрируйтеmousemove
обработчик закрыл эти стартовые позиции и зарегистрировалmouseup
обработчик для удаленияmousemove
обработчик.В течение
mousemove
обработчик, найдите смещение между текущей позицией мыши и начальной позицией мыши, добавьте это смещение к позиции начальной линии, а затем перерисовайте холст, используя эту новую позицию.
Возможно, вы захотите отслеживать преобразования каждого объекта независимо, поэтому, по сути, вы будете сами воссоздавать графическую систему с сохраненным режимом рисования, такую как SVG или HTML.