Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript two objects intersecting

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>
like image 964
laxer Avatar asked Mar 04 '26 05:03

laxer


1 Answers

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>
like image 155
Helder Sepulveda Avatar answered Mar 06 '26 19:03

Helder Sepulveda



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!