编辑路径点或线的选择

son*_*ouf 3 javascript html5-canvas

我正在尝试找到一种方法,通过在 html5 画布上通过鼠标单击选择路径点来拖放带有 javascript 的多边形点或线

有点像下图 在此处输入图片说明

通过单击并将选定的点拖动到新位置来移动选定的点

var canvas=document.getElementById("canvas");
var context=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(); }

context.lineWidth=2;
context.strokeStyle='blue';

var coordinates = [];
var isDone=false;

$('#done').click(function(){
  isDone=true;
});

$("#canvas").mousedown(function(e){handleMouseDown(e);});

function handleMouseDown(e){
  if(isDone || coordinates.length>10){return;}

  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);
  coordinates.push({x:mouseX,y:mouseY});
  drawPolygon();
}

function drawPolygon(){
  context.clearRect(0,0,cw,ch);
  context.beginPath();
  context.moveTo(coordinates[0].x, coordinates[0].y);
  for(index=1; index<coordinates.length;index++) {
    context.lineTo(coordinates[index].x, coordinates[index].y);
  }
  context.closePath();
  context.stroke();
}
Run Code Online (Sandbox Code Playgroud)
body{ background-color: ivory; }
#canvas{border:1px solid red;}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Click to assign polygon vertices</h4>
<button id=done>Click when done assigning points</button>
<br><canvas id="canvas" width=300 height=300></canvas>
Run Code Online (Sandbox Code Playgroud)

Bli*_*n67 6

给出的答案是在处理鼠标和呈现内容方面的不良做法示例。

从鼠标事件渲染将消耗功率并在不需要时强制画布渲染。鼠标可以以高达每秒 1000 次的速率发射,而最大显示速率仅为每秒 60 次。

使用鼠标移动事件意味着用户将看不到许多呈现的更新,充其量只是浪费 CPU/GPU 周期,最坏的情况是主要的电池消耗。

始终用于requestAnimationFrame呈现任何经常更改的内容。

下面的示例使用 requestAnimationFrame 将渲染与输入事件分离,仅在需要时渲染内容。它还通过光标和突出显示点为用户添加了一些反馈。

var ctx = canvas.getContext("2d");
requestAnimationFrame(update)

mouse = {x : 0, y : 0, button : 0, lx : 0, ly : 0, update : true};
function mouseEvents(e){
	const bounds = canvas.getBoundingClientRect();
	mouse.x = e.pageX - bounds.left - scrollX;
	mouse.y = e.pageY - bounds.top - scrollY;
	mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
  mouse.update = true;
}
["mousedown","mouseup","mousemove"].forEach(name => document.addEventListener(name,mouseEvents));



ctx.lineWidth = 2;
ctx.strokeStyle = "blue";
const point = (x,y) => ({x,y});
const poly = () => ({
    points : [],
    addPoint(p){ this.points.push(point(p.x,p.y)) },
    draw() {
        ctx.lineWidth = 2;
        ctx.strokeStyle = "blue";
        ctx.beginPath();
        for (const p of this.points) { ctx.lineTo(p.x,p.y) }
        ctx.closePath();
        for (const p of this.points) {
            ctx.moveTo(p.x + 4,p.y);
            ctx.arc(p.x,p.y,4,0,Math.PI *2);
        }
        ctx.stroke();
    },
    closest(pos, dist = 8) {
        var i = 0, index = -1;
        dist *= dist;
        for (const p of this.points) {
            var x = pos.x - p.x;
            var y = pos.y - p.y;
            var d2 =  x * x + y * y;
            if (d2 < dist) {
                dist = d2;
                index = i;
            }
            i++;
        }
        if (index > -1) { return this.points[index] }
    }
});
function drawCircle(pos,color="red",size=8){
    ctx.strokeStyle = color;
    ctx.beginPath();
    ctx.arc(pos.x,pos.y,size,0,Math.PI *2);
    ctx.stroke();
}
const polygon = poly();
var activePoint,cursor;
var dragging= false;
function update(){
    if (mouse.update) {
        cursor = "crosshair";
        ctx.clearRect(0,0,canvas.width,canvas.height);
        if (!dragging) {  activePoint = polygon.closest(mouse) }
        if (activePoint === undefined && mouse.button) {
            polygon.addPoint(mouse);
            mouse.button = false;
        } else if(activePoint) {
            if (mouse.button) {
                if(dragging) {
                    activePoint.x += mouse.x - mouse.lx;
                    activePoint.y += mouse.y - mouse.ly;
                } else {  dragging = true }
            } else { dragging = false }
        }
        polygon.draw();
        if (activePoint) { 
            drawCircle(activePoint);
            cursor = "move";
        }

        mouse.lx = mouse.x;
        mouse.ly = mouse.y;
        canvas.style.cursor = cursor;
        mouse.update = false;
    }
    requestAnimationFrame(update)
}
Run Code Online (Sandbox Code Playgroud)
#canvas{
  border:1px 
  solid black;
}
Run Code Online (Sandbox Code Playgroud)
<canvas id="canvas" width=300 height=300></canvas>
Run Code Online (Sandbox Code Playgroud)