I have been using Konva for drawing, I would like the arrow to "snap" to the other groups or shapes when the tip of the arrow intersects them and the user lets up on the mouse. If the arrow does not interset one then it should automatically delete its self.
Then when the groups or shapes are moved I would like the tips of the arrow to move with it.
I found an example of something similar but I'm not sure how I can combine them to get what I want.
I will post my current code below.
Example link
Click here
Code
var width = height = 170;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var isDrawArrow;
var Startpos;
var Endpos;
var arrow = new Konva.Arrow({
points: [],
pointerLength: 10,
pointerWidth: 10,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
var circle = new Konva.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 20,
fill: 'green'
});
var circleA = new Konva.Circle({
x: stage.getWidth() / 5,
y: stage.getHeight() / 5,
radius: 30,
fill: 'red',
draggable: true
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
layer.draw()
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
layer.draw()
});
circle.on('mousedown touchstart', function() {
isDrawArrow = true;
circleA.on('dragmove', adjustPoint);
Startpos = stage.getPointerPosition();
});
stage.addEventListener('mouseup touchend', function() {
isDrawArrow = false;
});
stage.addEventListener('mousemove touchmove', function() {
if (!isDrawArrow) return;
Endpos = stage.getPointerPosition()
var p = [Startpos.x, Startpos.y, Endpos.x, Endpos.y];
arrow.setPoints(p);
layer.add(arrow);
layer.batchDraw();
});
circle.on('mouseup', function() {
this.setFill('green');
layer.batchDraw();
});
function adjustPoint(e) {
var p = [circle.getX(), circle.getY(), circleA.getX(), circleA.getY()];
arrow.setPoints(p);
layer.draw();
stage.draw();
}
function haveIntersection(r1, r2) {
return !(
r2.x > r1.x + r1.width ||
r2.x + r2.width < r1.x ||
r2.y > r1.y + r1.height ||
r2.y + r2.height < r1.y
);
}
layer.add(circle);
layer.add(circleA);
stage.add(layer);
adjustPoint();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.3.0/konva.js"></script>
<div id="container"></div>
To do the snap you needed a function to determine distance between 2 points.
Easily done with a pythagorean calculation, (if you need help with that read about it here).
On the mouse move when you detect that the distance between the end of the arrow and your point (on this case the center or the red cirle) is less than what you want you can "snap it" that is what you do on your function adjustPoint that was all good.
On the mouse up you also need to check the distance and if is too far just hide the arrow
Working Code below:
var width = height = 170;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var isDrawArrow, Startpos, Endpos;
var snapDistance = 20;
function distance(p, c) {
var dx = p.x - c.getX();
var dy = p.y - c.getY();
return Math.sqrt(dx * dx + dy * dy);
}
var arrow = new Konva.Arrow({
points: [],
pointerLength: 10,
pointerWidth: 10,
fill: 'black',
stroke: 'black',
strokeWidth: 4
});
var circle = new Konva.Circle({
x: stage.getWidth() - 25,
y: stage.getHeight() - 25,
radius: 20,
fill: 'green'
});
var circleA = new Konva.Circle({
x: stage.getWidth() / 5,
y: stage.getHeight() / 5,
radius: 25,
fill: 'red',
draggable: true
});
circle.on('mousedown touchstart', function() {
isDrawArrow = true;
circleA.on('dragmove', adjustPoint);
Startpos = stage.getPointerPosition();
});
stage.addEventListener('mouseup touchend', function() {
isDrawArrow = false;
if (distance(Endpos, circleA) > snapDistance) {
arrow.hide();
layer.batchDraw();
}
});
stage.addEventListener('mousemove touchmove', function() {
if (!isDrawArrow) return;
Endpos = stage.getPointerPosition()
var p = [Startpos.x, Startpos.y, Endpos.x, Endpos.y];
arrow.setPoints(p);
arrow.show();
layer.add(arrow);
layer.batchDraw();
if (distance(Endpos, circleA) <= snapDistance) {
adjustPoint();
isDrawArrow = false
}
});
function adjustPoint(e) {
var p = [circle.getX(), circle.getY(), circleA.getX(), circleA.getY()];
arrow.setPoints(p);
layer.draw();
stage.draw();
}
layer.add(circle);
layer.add(circleA);
stage.add(layer);
canvas {
border: 1px solid #eaeaea !IMPORTANT;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.3.0/konva.js"></script>
<div id="container"></div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With