绘制一个总是指向远离对象的箭头

时间:2018-08-21 06:26:09

标签: javascript graphics fabricjs

我有一个带圆圈的画布和一个带连线的三角形。我正在尝试使用三角形作为箭头。如果两个对象中的任何一个被移动,我都希望箭头始终指向圆心。我以为可以用线的角度旋转三角形,但结果不尽人意,我敢肯定我的方法是错误的。

是否有解决此问题的建议或技巧?在我链接的JSFiddle中,您可以移动任意一个对象,并且三角形的角度也可以旋转,但这从来都不是正确的:

https://jsfiddle.net/zh1bkfs5/

const c = new fabric.Canvas('c');
c.preserveObjectStacking = true;

function radiansToDegrees (radians) {
  return radians * 180 / Math.PI;
}

function calcAngle (opposite, adjacent) {
  return radiansToDegrees(Math.atan(opposite / adjacent));
}

function syncObjects (e) {

  const x1 = triangle.left;
  const y1 = triangle.top;
  const x2 = circle.left + circle.radius;
  const y2 = circle.top + circle.radius;

  line.set('x1', x1);
  line.set('y1', y1);
  line.set('x2', x2);
  line.set('y2', y2);

  const angle = calcAngle(y2 - y1, x1 - x2);

  triangle.set('angle', -angle);
  triangle.setCoords();

  c.renderAll();
}

const circle = new fabric.Circle({
  fill: 'black',
  radius: 20,
  top: 100,
  left: 100,
  hasBorders: false,
  hasControls: false
});

const triangle = new fabric.Triangle({
  fill: 'orange',
  height: 20,
  width: 20,
  top: 50,
  left: 120,
  hasBorders: false,
  hasControls: false,
  originX: 'center',
  originY: 'center'
});

const coords = [
  triangle.left,
  triangle.top,
  circle.left + circle.radius,
  circle.top + circle.radius
];

const line = new fabric.Line(coords, {
  stroke: 'orange',
  strokeWidth: 1,
  selectable: false
});

c.add(circle, line, triangle);

c.on('object:moving', syncObjects);

2 个答案:

答案 0 :(得分:1)

将您的syncObject函数的一部分更改为此:

const x = x1 - x2;
const y = y2 - y1;
const angle = calcAngle(x, y);
if(x < 0 && y > 0 || x > 0 && y > 0) {
   triangle.set('angle', angle);
} else if(x < 0 && y < 0) {
   triangle.set('angle', 180 + angle);
} if(x > 0 && y < 0) {
   triangle.set('angle', -180 + angle);
}

这应该有效。您更新的小提琴https://jsfiddle.net/zh1bkfs5/30/

答案 1 :(得分:0)

更新后,我不再需要反转角度,因此将“相邻”和“相反”的值翻转了。我现在有99%的人,只是在某些情况下,三角形有时会以错误的方式翻转,但应该很容易修复,至少我最初的方法可行。

更新:https://jsfiddle.net/zh1bkfs5/1/

const c = new fabric.Canvas('c');
c.preserveObjectStacking = true;

function radiansToDegrees (radians) {
  return radians * 180 / Math.PI;
}

function calcAngle (opposite, adjacent) {
  return radiansToDegrees(Math.atan(opposite / adjacent));
}

function syncObjects (e) {

  const x1 = triangle.left;
  const y1 = triangle.top;
  const x2 = circle.left + circle.radius;
  const y2 = circle.top + circle.radius;

  line.set('x1', x1);
  line.set('y1', y1);
  line.set('x2', x2);
  line.set('y2', y2);

  const angle = calcAngle(x1 - x2, y2 - y1);

  triangle.set('angle', angle);
  triangle.setCoords();

  c.renderAll();
}

const circle = new fabric.Circle({
  fill: 'black',
  radius: 20,
  top: 100,
  left: 100,
  hasBorders: false,
  hasControls: false
});

const triangle = new fabric.Triangle({
  fill: 'orange',
  height: 20,
  width: 20,
  top: 50,
  left: 120,
  hasBorders: false,
  hasControls: false,
  originX: 'center',
  originY: 'center'
});

const coords = [
  triangle.left,
  triangle.top,
  circle.left + circle.radius,
  circle.top + circle.radius
];

const line = new fabric.Line(coords, {
  stroke: 'orange',
  strokeWidth: 1,
  selectable: false
});

c.add(circle, line, triangle);

c.on('object:moving', syncObjects);