Как проверить начальную и конечную точки линии, которая щелкает в полилинии или многоугольнике SVG? - PullRequest
0 голосов
/ 31 января 2020

Я делаю редактор карт для своей игры. У меня есть SVG, который будет содержать много <polyline>. Всякий раз, когда пользователь нажимает на любую строку <polyline>. Я две вещи, как информация. Координаты, где была нажата мышь, и все точки этой полилинии в порядке.

Я хочу проверить, что это за две точки, между которыми была нажата линия.

Для этого я использовал формулу расстояния. Если AB - это линия, и мы хотим проверить, лежит ли точка C на этой линии или нет. Мы проверим, равно ли расстояние AB BC + AC.

Ниже мой код.

const poly = document.getElementById("poly");

poly.onclick = function(e){
  const mousePos = [e.clientX,e.clientY];
  //console.log(mousePos)
  const points = poly.getAttribute('points').split(' ').map(x => x.split(',').map(Number));
  const res= points.find((p, i) => {
    let prevPoint = points[i-1];
    if(i === 0){
      prevPoint = points[points.length - 1];
    }
    return arePointsCollinear(prevPoint, p, mousePos)
  });
  if(res){
    console.log(res);
  }
}

const getDistance = (pointA, pointB) => {
   const dx = Math.pow(pointA[0] - pointB[0], 2);
   const dy = Math.pow(pointA[1] - pointB[1], 2);
   return Math.sqrt(dx + dy);
};

const arePointsCollinear = (
   pointA,
   pointB,
   pointC
) => {
   const totalDistance = getDistance(pointA, pointB);
   const deltaAC = getDistance(pointA, pointC);
   const deltaBC = getDistance(pointB, pointC);
   return totalDistance === deltaAC + deltaBC;
};
svg polyline{
  fill:none;
  stroke:black;
  stroke-width: 10
}
svg{
height:500px;
width:500px;
}
body{
padding: 0;
margin: 0;
}
<svg xmlns="http://www.w3.org/2000/svg">
  <polyline id="poly" points="100,100 150,200 250,150 100,100"/>
</svg>

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

1 Ответ

1 голос
/ 01 февраля 2020

у меня что-то работает,

https://codepen.io/Alexander9111/pen/rNaERKa

enter image description here

HTML:

<svg id="svg" height="500" width="500" xmlns="http://www.w3.org/2000/svg"> 
    <polyline id="poly" points="100,100 150,200 250,150 100,100"/>
</svg>

JS:

const svg = document.getElementById("svg");
const poly = document.getElementById("poly");
const poly_width = getComputedStyle(poly)['stroke-width'];
console.log(parseInt(poly_width));
const half_width = parseInt(poly_width) / 2;

poly.onclick = function(e){
  const mousePos = [e.clientX,e.clientY];
  console.log(mousePos)
  const points = poly.getAttribute('points').split(' ').map(x => x.split(',').map(Number));
  const res= points.find((p, i) => {
    let prevPoint = points[i-1];
    if(i === 0){
      prevPoint = points[points.length - 1];
    }
    return arePointsCollinear(prevPoint, p, mousePos)
  });
  if(res){
    console.log(res);
    const NS = 'http://www.w3.org/2000/svg';
    const circle = document.createElementNS(NS,'circle');
    circle.setAttribute('r', '5');
    circle.setAttribute('cx', res[0]);
    circle.setAttribute('cy', res[1]);
    svg.appendChild(circle);
    console.log('circle');
  }
}

const getDistance = (pointA, pointB) => {
   const dx = Math.pow(pointA[0] - pointB[0], 2);
   const dy = Math.pow(pointA[1] - pointB[1], 2);
   return Math.sqrt(dx + dy);
};

const arePointsCollinear = (
   pointA,
   pointB,
   pointC
) => {
   const totalDistance = getDistance(pointA, pointB);
   const deltaAC = getDistance(pointA, pointC);
   const deltaBC = getDistance(pointB, pointC);
   return deltaAC + deltaBC <= Math.sqrt(totalDistance**2 + half_width**2);
};

Самая важная строка - return deltaAC + deltaBC <= Math.sqrt(totalDistance**2 + half_width**2); - и я нарисовал диаграмму, чтобы объяснить, откуда это происходит:

enter image description here

По сути, вам необходимо учесть самый длинный путь, который все еще находится внутри ширины хода. Я считаю, что это квадрат root из (длина AB ^ 2 плюс half_stroke-width ^ 2)

ОБНОВЛЕНИЕ

Если вы хотите добавить строки вместо этого, вам нужно измените points.find() на points.findIndex(), затем вы можете использовать индекс и prevIndex, чтобы нарисовать линию между точками:

enter image description here

JS:

const svg = document.getElementById("svg");
const poly = document.getElementById("poly");
const poly_width = getComputedStyle(poly)['stroke-width'];
console.log(parseInt(poly_width));
const half_width = parseInt(poly_width) / 2;

poly.onclick = function(e){
  const mousePos = [e.clientX,e.clientY];
  console.log(mousePos)
  const points = poly.getAttribute('points').split(' ').map(x => x.split(',').map(Number));
  const res= points.findIndex((p, i) => {
    let prevPoint = points[i-1];
    if(i === 0){
      prevPoint = points[points.length - 1];
    }
    return arePointsCollinear(prevPoint, p, mousePos)
  });
  if(res != -1){
    console.log(res);
    const NS = 'http://www.w3.org/2000/svg';
    const line = document.createElementNS(NS,'line')
    // const circle = document.createElementNS(NS,'circle');
    // circle.setAttribute('r', '5');
    // circle.setAttribute('cx', points[res][0]);
    // circle.setAttribute('cy', points[res][1]);
    // svg.appendChild(circle);
    // console.log('circle');

    line.setAttribute('x1', points[res][0]);
    line.setAttribute('y1', points[res][1]);
    let prevIndex = (res === 0) ? (points.length - 1) : res - 1;
    line.setAttribute('x2', points[prevIndex][0]);
    line.setAttribute('y2', points[prevIndex][1]);
    svg.appendChild(line);
    console.log('line');
  }
}

const getDistance = (pointA, pointB) => {
   const dx = Math.pow(pointA[0] - pointB[0], 2);
   const dy = Math.pow(pointA[1] - pointB[1], 2);
   return Math.sqrt(dx + dy);
};

const arePointsCollinear = (
   pointA,
   pointB,
   pointC
) => {
   const totalDistance = getDistance(pointA, pointB);
   const deltaAC = getDistance(pointA, pointC);
   const deltaBC = getDistance(pointB, pointC);
   return deltaAC + deltaBC <= Math.sqrt(totalDistance**2 + (2*half_width)**2);
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...