You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

230 lines
5.8 KiB

import {
getDistancePointPoint,
rotateVector,
getAngle
} from './GeometricUtil';
import {
getAttachment
} from './LineAttachmentUtil';
import {
roundPoint
} from 'diagram-js/lib/layout/LayoutUtil';
export function findNewLineStartIndex(oldWaypoints, newWaypoints, attachment, hints) {
var index = attachment.segmentIndex;
var offset = newWaypoints.length - oldWaypoints.length;
// segmentMove happened
if (hints.segmentMove) {
var oldSegmentStartIndex = hints.segmentMove.segmentStartIndex,
newSegmentStartIndex = hints.segmentMove.newSegmentStartIndex;
// if point was on moved segment return new segment index
if (index === oldSegmentStartIndex) {
return newSegmentStartIndex;
}
// point is after new segment index
if (index >= newSegmentStartIndex) {
return (index + offset < newSegmentStartIndex) ? newSegmentStartIndex : index + offset;
}
// if point is before new segment index
return index;
}
// bendpointMove happened
if (hints.bendpointMove) {
var insert = hints.bendpointMove.insert,
bendpointIndex = hints.bendpointMove.bendpointIndex,
newIndex;
// waypoints length didnt change
if (offset === 0) {
return index;
}
// point behind new/removed bendpoint
if (index >= bendpointIndex) {
newIndex = insert ? index + 1 : index - 1;
}
// point before new/removed bendpoint
if (index < bendpointIndex) {
newIndex = index;
// decide point should take right or left segment
if (insert && attachment.type !== 'bendpoint' && bendpointIndex - 1 === index) {
var rel = relativePositionMidWaypoint(newWaypoints, bendpointIndex);
if (rel < attachment.relativeLocation) {
newIndex++;
}
}
}
return newIndex;
}
// start/end changed
if (offset === 0) {
return index;
}
if (hints.connectionStart && index === 0) {
return 0;
}
if (hints.connectionEnd && index === oldWaypoints.length - 2) {
return newWaypoints.length - 2;
}
// if nothing fits, take the middle segment
return Math.floor((newWaypoints.length - 2) / 2);
}
/**
* Calculate the required adjustment (move delta) for the given point
* after the connection waypoints got updated.
*
* @param {Point} position
* @param {Array<Point>} newWaypoints
* @param {Array<Point>} oldWaypoints
* @param {Object} hints
*
* @return {Object} result
* @return {Point} result.point
* @return {Point} result.delta
*/
export function getAnchorPointAdjustment(position, newWaypoints, oldWaypoints, hints) {
var dx = 0,
dy = 0;
var oldPosition = {
point: position,
delta: { x: 0, y: 0 }
};
// get closest attachment
var attachment = getAttachment(position, oldWaypoints),
oldLabelLineIndex = attachment.segmentIndex,
newLabelLineIndex = findNewLineStartIndex(oldWaypoints, newWaypoints, attachment, hints);
// should never happen
// TODO(@janstuemmel): throw an error here when connectionSegmentMove is refactored
if (newLabelLineIndex < 0 ||
newLabelLineIndex > newWaypoints.length - 2 ||
newLabelLineIndex === null) {
return oldPosition;
}
var oldLabelLine = getLine(oldWaypoints, oldLabelLineIndex),
newLabelLine = getLine(newWaypoints, newLabelLineIndex),
oldFoot = attachment.position;
var relativeFootPosition = getRelativeFootPosition(oldLabelLine, oldFoot),
angleDelta = getAngleDelta(oldLabelLine, newLabelLine);
// special rule if label on bendpoint
if (attachment.type === 'bendpoint') {
var offset = newWaypoints.length - oldWaypoints.length,
oldBendpointIndex = attachment.bendpointIndex,
oldBendpoint = oldWaypoints[oldBendpointIndex];
// bendpoint position hasn't changed, return same position
if (newWaypoints.indexOf(oldBendpoint) !== -1) {
return oldPosition;
}
// new bendpoint and old bendpoint have same index, then just return the offset
if (offset === 0) {
var newBendpoint = newWaypoints[oldBendpointIndex];
dx = newBendpoint.x - attachment.position.x,
dy = newBendpoint.y - attachment.position.y;
return {
delta: {
x: dx,
y: dy
},
point: {
x: position.x + dx,
y: position.y + dy
}
};
}
// if bendpoints get removed
if (offset < 0 && oldBendpointIndex !== 0 && oldBendpointIndex < oldWaypoints.length - 1) {
relativeFootPosition = relativePositionMidWaypoint(oldWaypoints, oldBendpointIndex);
}
}
var newFoot = {
x: (newLabelLine[1].x - newLabelLine[0].x) * relativeFootPosition + newLabelLine[0].x,
y: (newLabelLine[1].y - newLabelLine[0].y) * relativeFootPosition + newLabelLine[0].y
};
// the rotated vector to label
var newLabelVector = rotateVector({
x: position.x - oldFoot.x,
y: position.y - oldFoot.y
}, angleDelta);
// the new relative position
dx = newFoot.x + newLabelVector.x - position.x;
dy = newFoot.y + newLabelVector.y - position.y;
return {
point: roundPoint(newFoot),
delta: roundPoint({
x: dx,
y: dy
})
};
}
// HELPERS //////////////////////
function relativePositionMidWaypoint(waypoints, idx) {
var distanceSegment1 = getDistancePointPoint(waypoints[idx - 1], waypoints[idx]),
distanceSegment2 = getDistancePointPoint(waypoints[idx], waypoints[idx + 1]);
var relativePosition = distanceSegment1 / (distanceSegment1 + distanceSegment2);
return relativePosition;
}
function getAngleDelta(l1, l2) {
var a1 = getAngle(l1),
a2 = getAngle(l2);
return a2 - a1;
}
function getLine(waypoints, idx) {
return [ waypoints[idx], waypoints[idx + 1] ];
}
function getRelativeFootPosition(line, foot) {
var length = getDistancePointPoint(line[0], line[1]),
lengthToFoot = getDistancePointPoint(line[0], foot);
return length === 0 ? 0 : lengthToFoot / length;
}