jointjs
Version:
JavaScript diagramming library
149 lines (122 loc) • 4.93 kB
JavaScript
import * as g from '../g/index.mjs';
import V from '../V/index.mjs';
import * as util from '../util/index.mjs';
function offset(p1, p2, offset) {
if (!isFinite(offset)) return p1;
var length = p1.distance(p2);
if (offset === 0 && length > 0) return p1;
return p1.move(p2, -Math.min(offset, length - 1));
}
function stroke(magnet) {
var stroke = magnet.getAttribute('stroke-width');
if (stroke === null) return 0;
return parseFloat(stroke) || 0;
}
// Connection Points
function anchorIntersection(line, view, magnet, opt) {
return offset(line.end, line.start, opt.offset);
}
function bboxIntersection(line, view, magnet, opt) {
var bbox = view.getNodeBBox(magnet);
if (opt.stroke) bbox.inflate(stroke(magnet) / 2);
var intersections = line.intersect(bbox);
var cp = (intersections)
? line.start.chooseClosest(intersections)
: line.end;
return offset(cp, line.start, opt.offset);
}
function rectangleIntersection(line, view, magnet, opt) {
var angle = view.model.angle();
if (angle === 0) {
return bboxIntersection(line, view, magnet, opt);
}
var bboxWORotation = view.getNodeUnrotatedBBox(magnet);
if (opt.stroke) bboxWORotation.inflate(stroke(magnet) / 2);
var center = bboxWORotation.center();
var lineWORotation = line.clone().rotate(center, angle);
var intersections = lineWORotation.setLength(1e6).intersect(bboxWORotation);
var cp = (intersections)
? lineWORotation.start.chooseClosest(intersections).rotate(center, -angle)
: line.end;
return offset(cp, line.start, opt.offset);
}
function findShapeNode(magnet) {
if (!magnet) return null;
var node = magnet;
do {
var tagName = node.tagName;
if (typeof tagName !== 'string') return null;
tagName = tagName.toUpperCase();
if (tagName === 'G') {
node = node.firstElementChild;
} else if (tagName === 'TITLE') {
node = node.nextElementSibling;
} else break;
} while (node);
return node;
}
var BNDR_SUBDIVISIONS = 'segmentSubdivisons';
var BNDR_SHAPE_BBOX = 'shapeBBox';
function boundaryIntersection(line, view, magnet, opt) {
var node, intersection;
var selector = opt.selector;
var anchor = line.end;
if (typeof selector === 'string') {
node = view.findBySelector(selector)[0];
} else if (Array.isArray(selector)) {
node = util.getByPath(magnet, selector);
} else {
node = findShapeNode(magnet);
}
if (!V.isSVGGraphicsElement(node)) {
if (node === magnet || !V.isSVGGraphicsElement(magnet)) return anchor;
node = magnet;
}
var localShape = view.getNodeShape(node);
var magnetMatrix = view.getNodeMatrix(node);
var translateMatrix = view.getRootTranslateMatrix();
var rotateMatrix = view.getRootRotateMatrix();
var targetMatrix = translateMatrix.multiply(rotateMatrix).multiply(magnetMatrix);
var localMatrix = targetMatrix.inverse();
var localLine = V.transformLine(line, localMatrix);
var localRef = localLine.start.clone();
var data = view.getNodeData(node);
if (opt.insideout === false) {
if (!data[BNDR_SHAPE_BBOX]) data[BNDR_SHAPE_BBOX] = localShape.bbox();
var localBBox = data[BNDR_SHAPE_BBOX];
if (localBBox.containsPoint(localRef)) return anchor;
}
// Caching segment subdivisions for paths
var pathOpt;
if (localShape instanceof g.Path) {
var precision = opt.precision || 2;
if (!data[BNDR_SUBDIVISIONS]) data[BNDR_SUBDIVISIONS] = localShape.getSegmentSubdivisions({ precision: precision });
pathOpt = {
precision: precision,
segmentSubdivisions: data[BNDR_SUBDIVISIONS]
};
}
if (opt.extrapolate === true) localLine.setLength(1e6);
intersection = localLine.intersect(localShape, pathOpt);
if (intersection) {
// More than one intersection
if (V.isArray(intersection)) intersection = localRef.chooseClosest(intersection);
} else if (opt.sticky === true) {
// No intersection, find the closest point instead
if (localShape instanceof g.Rect) {
intersection = localShape.pointNearestToPoint(localRef);
} else if (localShape instanceof g.Ellipse) {
intersection = localShape.intersectionWithLineFromCenterToPoint(localRef);
} else {
intersection = localShape.closestPoint(localRef, pathOpt);
}
}
var cp = (intersection) ? V.transformPoint(intersection, targetMatrix) : anchor;
var cpOffset = opt.offset || 0;
if (opt.stroke) cpOffset += stroke(node) / 2;
return offset(cp, line.start, cpOffset);
}
export const anchor = anchorIntersection;
export const bbox = bboxIntersection;
export const rectangle = rectangleIntersection;
export const boundary = boundaryIntersection;