通过绕过点来连接点

问题描述 投票:0回答:1

我正在为网络应用程序(html canvas)开发线条绘制功能。它包括一条线和一组点。线的一端连接到锚点,另一端跟随鼠标指针。当鼠标在簇内部移动时,线可能会“卡住”一个或多个点。

如果您在地图上的图钉之间移动一根线,您可以想象这在现实生活中是如何工作的。通过将线绕着别针移动,您可以将其从一个别针拉伸到另一个别针。

线距离某个点很近还不够(它没有捕捉)。需要有一个交叉点,并且线程的连续路径需要偏离先前的路径。如果相交发生在销钉的右侧,则螺纹需要向左移动,反之亦然。

目前我还无法生成任何可以向您展示的有意义的代码。我已经知道如何在满足特定条件时绘制一条线并添加新线段。我没有对这种条件的良好定义以及确定何时满足该条件的实用方法。任何帮助将非常感激。

我无法找到任何处理此特定任务的算法或其他技术。

javascript canvas line path-finding
1个回答
0
投票

不确定我完全理解该任务,但这里是我所理解的示例实现:

const pinUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABdaVRYdFNuaXBNZXRhZGF0YQAAAAAAeyJjbGlwUG9pbnRzIjpbeyJ4IjowLCJ5IjowfSx7IngiOjI4LCJ5IjowfSx7IngiOjI4LCJ5IjoyOH0seyJ4IjowLCJ5IjoyOH1dfeeW5RYAAAQ9SURBVEhLnVY3Sy1hEB1zwoRZUTBhthEFESvtxAQ2WqiVaGshoqXY+RfExkLQSlBsDKCCghERzIiYMGPO8+bMu7te07t334GPe3d3ds43M2fmWxcWkB3e39/p+vqatra2aHl5mRYXF2l7e5vOzs7o6emJYO7p6Uk+Pj4UHh5O8fHxlJaWpis5OZlCQkLIzc3N5u0HgNDA8/MzLy0tcUtLC4sDFqfs6uqqy8XFxVz298Q5+/r6cmJiItfW1vLAwAAfHx/z29ubzetnmIQwmJub49LSUnUAZ9iPsYzrr7/2C5sICwvjuro6npmZ4cfHR5v3D5iER0dHXF9fz5Iu0yEceHl5saSJ4+LiOCkpSZekkaOiojgoKEjtEaU9sbu7O+fl5XF/fz/f3NzYGP5Ca4i6DQ4OUkNDg9ZKbpEQUX5+PpWXl1NKSgr5+/uTOCLZhNZZdk+3t7e0ublJU1NTJBGRpFKfAbBDTdva2qiyslLfV4BQRMKtra26U0SG37KyMhbBaF1/wsPDA5+cnPD+/j6LqHhoaIirq6s5MDDQTDcyhGygrrAHlBBFrqmpMYWAGvb09CByNfoKpEkyws3Nzdze3s7T09PqcG9vjzs7Ozk2NlZ9gRT+CgsLWTKh77prmDbItS4xooCAAP017otDuri4IImIxsfHqa+vjzY2Nsjb25teX19JaktCRE1NTRQcHEwdHR0kutB30Vqrq6uUkJBASigRUXR0tOZd1Kr9Njk5qT318vJC5+fnWquFhQWStqHDw0OSVKszkKHu2Mz9/T1dXl4qoYhMawob+Ds9PVXfuKEt0d3drX2HgLBQC6RGmlvvo65GmuyXiIGrqqq4sbGRS0pKODs7W9/x8PAwbfz8/FSxsrmPtpifn+f09PRPzozi/7bwHC0A5/hviM5YsMHzoqIiXltbUx6TEErt6urSxoWxIaCvJM4svAsi9GlFRQWPjY2Zav80S1GL4eFh7cmdnR29Rh1QJwN25grUXSIjiVIFBLFBD5JaEnVSQUEBxcTEaA8D34Y3GhoiAZmkgUZGRmhlZUVViuIfHByoDQDnMgopNzeXIiMjSepOEpWKJjQ0VK8NIhMg/A1CwKJIFkKds729vSzSNmuEMTc6OvrrcPgJrjbeH4FjSGYmZWZmUk5ODqWmpurIM4DdiwI1nc7in4RfgXrZO0dfaW9ZgCVCRAdhSDpVPKgrBoAVWCaEEACQYgpBSFZgiRAjMCIiQqPDuru7UzUbR5IzsESINsAZh74D0B4YzDgXnYUlQnw4ZWVlmScJBsLExATt7u7aLBzDEiFUmpGRoV9oAEjX19dpdnZW6+kMLBECGFPFxcXaowCUKkOBrq6u9NoRLBNCOJiPGAgGIB5j3DmCZUKkEYMZH0YgxYcwZqn5keQA34a3M8B0wWmCoY7UYgNItaHef+G/CAGQYsogYpBCUI5B9AcI4Zaprk7MAwAAAABJRU5ErkJggg==';

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const pinImage = new Image();
pinImage.onload = drawFrame;
pinImage.src = pinUrl;
const pinPositions = [{x: 40, y: 40}, {x: 100, y: 130}, {x: 400, y: 350}, {x: 300, y: 400}, {x: 270, y: 230}, {x: 50, y: 380}, {x: 460, y: 73}];
const drawedLines = [];
let lastMovePoint = {x: 40, y: 40};
const candidateLine = {x1: 40, y1: 40, x2: 40, y2: 40};

canvas.addEventListener('mousemove', ({offsetX, offsetY}) => {
  const prevPoint = {x: candidateLine.x2, y: candidateLine.y2};
  candidateLine.x2 = offsetX;
  candidateLine.y2 = offsetY;
  checkIntersection();
  lastMovePoint = prevPoint;
});

function drawFrame() {
  ctx.beginPath();
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  for(const pin of pinPositions) {
    ctx.drawImage(pinImage, pin.x - 10, pin.y - 10, 20, 20);
  }
  
  ctx.strokeStyle = 'red';
  ctx.strokeWidth = 2;
  ctx.moveTo(40, 40);
  
  for(const line of drawedLines) {
    ctx.lineTo(line.x2, line.y2);
  }

  ctx.stroke();
  ctx.strokeStyle = 'green';
  ctx.lineTo(candidateLine.x2, candidateLine.y2);
  ctx.stroke();
  ctx.closePath();
  
  requestAnimationFrame(drawFrame);
}

function checkIntersection() {
  
  for(const pin of pinPositions) {
    const {x1, x2, y1, y2} = candidateLine;
    if(isLineExist({x: x1, y: y1}, pin)) continue;
    if(isPointInTriangle({x: x1, y: y1}, {x: x2, y: y2}, lastMovePoint, pin)) {
      candidateLine.x1 = pin.x;
      candidateLine.y1 = pin.y;
      drawedLines.push({x1, y1, x2: pin.x, y2: pin.y});
    }
  }
}

function triangleArea(p1, p2, p3) {
  const area = (p1.x * (p2.y - p3.y) + p2.x * (p3.y - p1.y) + p3.x * (p1.y - p2.y)) / 2;
  return Math.abs(area);
}

function isPointInTriangle(p1, p2, p3, p) {
  return triangleArea(p1, p2, p3) === triangleArea(p1, p2, p) + triangleArea(p1, p, p3) + triangleArea(p, p2, p3);
}

function isLineExist(p1, p2) {
  return drawedLines.some(({x1, x2, y1, y2}) => x1 === p1.x && y1 === p1.y && x2 === p2.x && y2 === p2.y || x2 === p1.x && y2 === p1.y && x1 === p2.x && y1 === p2.y)
}

function restart() {
  drawedLines.splice(0, drawedLines.length);
  candidateLine.x1 = 40;
  candidateLine.y1 = 40;
  candidateLine.x2 = 40;
  candidateLine.y2 = 40;
}
#canvas {
  display: block;
  background: white;
  border: 1px solid darkgray;
}

button {
  margin-top: 10px;
}
<canvas id="canvas" width="500" height="500"></canvas>
<button onClick="restart()">Restart</button>

然后你总是可以检查已经有入口和存在线并且不允许连接到它们的点,检查你是否关闭了一个循环并以某种方式处理它,或者接下来你需要用它做什么。

© www.soinside.com 2019 - 2024. All rights reserved.