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
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; |
|
}
|
|
|