I'm having issue with the update of Polyline points.
I want to be able to move my arrow, and also to change two points of it.
When I move my arrow (left, top), the points doesn't update. So I update them manually, and the issue comes here.
For me, maybe I'm wrong, my point calculation is good, but fabric displays me the opposite.
I've made a jsfiddle which reproduces the issue: https://jsfiddle.net/7k6oyuL4/1/
const calcNewAngle = ({ x1, y1, x2, y2 }) => {
const width = Math.abs(Math.max(x1, x2) - Math.min(x1, x2));
const height = Math.abs(Math.max(y1, y2) - Math.min(y1, y2));
let theta;
if (x1 < x2 && y1 < y2) {
theta = Math.atan(height / width);
} else if (x1 < x2 && y1 >= y2) {
theta = Math.atan(-height / width);
} else if (x1 >= x2 && y1 < y2) {
theta = Math.abs(Math.atan(height / width) - Math.PI);
} else {
theta = Math.abs(Math.atan(-height / width) - Math.PI);
}
return theta;
};
const setArrowPoints = ({x1, y1, x2, y2}) => {
const angle = calcNewAngle({x1, y1, x2, y2});
const headlen = 8;
return [
{
x: x1,
y: y1
},
{
x: x2,
y: y2
},
{
x: x2 - headlen * Math.cos(angle - Math.PI / 2),
y: y2 - headlen * Math.sin(angle - Math.PI / 2)
},
{
x: x2 + headlen * Math.cos(angle),
y: y2 + headlen * Math.sin(angle)
},
{
x: x2 - headlen * Math.cos(angle + Math.PI / 2),
y: y2 - headlen * Math.sin(angle + Math.PI / 2)
},
{
x: x2,
y: y2
}
];
}
const getX1Y1X2Y2 = points => {
return {
x1: points[0].x,
y1: points[0].y,
x2: points[1].x,
y2: points[1].y
}
}
const updateArrow = (e, canvas, arrow, index) => {
const mousePos = canvas.getPointer(e);
const {points} = arrow;
points[index].x = mousePos.x;
points[index].y = mousePos.y;
arrow.set('points', setArrowPoints(getX1Y1X2Y2(points)))
}
const createControl = ({canvas, index, arrow}) => {
const left = arrow.points[index].x;
const top = arrow.points[index].y;
const control = new fabric.Circle({
index,
left,
top,
radius: 5,
strokeWidth: 1,
hasBorders: false,
stroke: 'rgba(0,0,255,1)',
fill: 'rgba(255,255,255,1)',
originX: 'center',
originY: 'center'
});
control.setControlsVisibility({
bl: false,
br: false,
mb: false,
ml: false,
mr: false,
mt: false,
tl: false,
tr: false,
mtr: false
});
control.on('moving', e => updateArrow(e, canvas, arrow, index));
return control;
}
const handleMoving = (e, canvas, controls) => {
const {target} = e.transform;
if (!target.alreadyLogged) {
target.alreadyLogged = true;
console.log('handleMoving', target.points);
controls.forEach(control => control.set('visible', false))
}
}
const handleMoved = (e, canvas, controls) => {
console.log('###### handleMoved ######')
const {target, transform} = e;
const {left: originLeft, top: originTop} = transform.original;
const {left: newLeft, top: newTop, points} = target;
const leftDiff = newLeft - originLeft;
const topDiff = newTop - originTop;
console.log({originLeft, newLeft, leftDiff, originTop, newTop, topDiff});
console.log('pointsBeforeManualUpdate', getX1Y1X2Y2(points))
const x1 = points[0].x + leftDiff;
const y1 = points[0].y + topDiff;
const x2 = points[1].x + leftDiff;
const y2 = points[1].y + topDiff;
target.set('points', setArrowPoints({x1, y1, x2, y2}))
console.log('pointsAfterManualUpdate', getX1Y1X2Y2(target.points))
controls.forEach(control => {
const {index} = control;
const leftControl = target.points[index].x;
const topControl = target.points[index].y;
control.set({
visible: true,
left: leftControl,
top: topControl
})
})
target.alreadyLogged = false;
}
const createArrow = ({canvas, points}) => {
const arrowPoints = setArrowPoints(points);
const arrow = new fabric.Polyline(arrowPoints, {
strokeWidth: 2,
stroke: 'rgba(0,0,0,1)',
fill: 'rgba(0,0,0,1)',
perPixelTargetFind: true
});
arrow.setControlsVisibility({
bl: false,
br: false,
mb: false,
ml: false,
mr: false,
mt: false,
tl: false,
tr: false,
mtr: false
});
const control1 = createControl({canvas, index: 0, arrow})
const control2 = createControl({canvas, index: 1, arrow})
arrow.on('moving', e => handleMoving(e, canvas, [control1, control2]))
arrow.on('moved', e => handleMoved(e, canvas, [control1, control2]))
canvas.add(arrow)
canvas.add(control1)
canvas.add(control2)
return arrow;
}
(function() {
const canvas = this.__canvas = new fabric.Canvas('c', { width: 1500, height: 1000 });
const arrowObj = createArrow({canvas, points: {x1: 50, y1: 50, x2: 200, y2: 200}})
})();
Thanks in advance for your help!