I have a function closestPointData
to determine the closest point of a line, highlight that point by showing a red dot and to determine which point needs to be dragged.
I'm having a problem with the tolerance, when I drag too fast, the mouse "drops" the point.
How can I ensure I don't exceed the tolerance of 30px
line = new Path.Line([90, 90], [250, 250]);
line.strokeColor = 'black';
line.strokeWidth = 3;
var redDot = new Path.Circle({
center: view.center,
radius: 3,
fillColor: 'transparent',
position: [90, 90]
});
function onMouseDrag(e) {
var cpd = closestPointData(e);
if (cpd.closestDistance < 30) {
line.segments[cpd.closestPointIndex].point = e.point;
redDot.position = cpd.usePoint;
}
}
function onMouseMove(e) {
var cpd = closestPointData(e);
if (cpd.closestDistance < 30) {
redDot.position = cpd.usePoint;
redDot.fillColor = 'red';
}else{
redDot.fillColor = 'transparent';
}
}
// Determine which of the line segment points is closest to the mouse pointer
function closestPointData(e) {
var closestPointIndex = null;
var closestDistance = Infinity;
var usePoint; // segment point coordinates
// console.log(line.segments);
// get point from each end of segment
for (var i = 0; i < line.segments.length; i++) {
var pointAt = line.getPointAt(line.segments[i]);
var distance = e.point.getDistance(pointAt);
// Qualify shortest distance
if (distance < closestDistance) {
closestDistance = distance;
closestPointIndex = i;
usePoint = pointAt;
}
}
return {
closestPointIndex: closestPointIndex,
closestDistance: closestDistance,
usePoint: usePoint
};
}
In my opinion, the onMouseDrag
handler is usefull only when there is no onMouseMove
, otherwise, it gets a bit confusing.
I would do it this way.
// Set target size.
const MIN_DISTANCE = 30;
// Create items.
const path = new Path.Line({
from: view.center,
to: view.center + 150,
strokeColor: 'black',
strokeWidth: 2,
});
const dot = new Path.Circle({
center: view.center,
radius: 5,
fillColor: 'transparent',
});
// Create state variables.
// This will store the active path point.
let activePoint;
// This will allow us to check if we are currently dragging or not.
let dragging = false;
function onMouseDown() {
dragging = true;
}
function onMouseMove(event) {
// If we are not currently dragging...
if (!dragging) {
// ...look for the closest path point...
const closest = path.segments
.map((it) => ({point: it.point, distance: it.point.getDistance(event.point)}))
.sort((a, b) => a.distance - b.distance)
.shift();
// ...and if it is close enough...
if (closest.distance <= MIN_DISTANCE) {
// ...show the dot...
dot.fillColor = 'red';
dot.position = closest.point;
// ...and store the active point.
activePoint = closest.point;
}
// Otherwise...
else {
// ...hide the dot...
dot.fillColor = 'transparent';
// ...and store no active point.
activePoint = null;
}
}
// If we are dragging and there is an active point...
else if (activePoint) {
// ...move the dot...
dot.position += event.delta;
// ...and move the path point.
activePoint.x = dot.position.x;
activePoint.y = dot.position.y;
}
}
function onMouseUp() {
dragging = false;
}