UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering.

1,225 lines (1,224 loc) 85.8 kB
"use strict"; var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.EdgeView = void 0; var geometry_1 = require("../geometry"); var util_1 = require("../util"); var registry_1 = require("../registry"); var edge_1 = require("../model/edge"); var markup_1 = require("./markup"); var cell_1 = require("./cell"); var EdgeView = /** @class */ (function (_super) { __extends(EdgeView, _super); function EdgeView() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.POINT_ROUNDING = 2; _this.markerCache = {}; return _this; // #endregion // #endregion } Object.defineProperty(EdgeView.prototype, Symbol.toStringTag, { get: function () { return EdgeView.toStringTag; }, enumerable: false, configurable: true }); EdgeView.prototype.getContainerClassName = function () { return [_super.prototype.getContainerClassName.call(this), this.prefixClassName('edge')].join(' '); }; Object.defineProperty(EdgeView.prototype, "sourceBBox", { get: function () { var sourceView = this.sourceView; if (!sourceView) { var sourceDef = this.cell.getSource(); return new geometry_1.Rectangle(sourceDef.x, sourceDef.y); } var sourceMagnet = this.sourceMagnet; if (sourceView.isEdgeElement(sourceMagnet)) { return new geometry_1.Rectangle(this.sourceAnchor.x, this.sourceAnchor.y); } return sourceView.getBBoxOfElement(sourceMagnet || sourceView.container); }, enumerable: false, configurable: true }); Object.defineProperty(EdgeView.prototype, "targetBBox", { get: function () { var targetView = this.targetView; if (!targetView) { var targetDef = this.cell.getTarget(); return new geometry_1.Rectangle(targetDef.x, targetDef.y); } var targetMagnet = this.targetMagnet; if (targetView.isEdgeElement(targetMagnet)) { return new geometry_1.Rectangle(this.targetAnchor.x, this.targetAnchor.y); } return targetView.getBBoxOfElement(targetMagnet || targetView.container); }, enumerable: false, configurable: true }); EdgeView.prototype.isEdgeView = function () { return true; }; EdgeView.prototype.confirmUpdate = function (flag, options) { var _this = this; if (options === void 0) { options = {}; } var ref = flag; if (this.hasAction(ref, 'source')) { if (!this.updateTerminalProperties('source')) { return ref; } ref = this.removeAction(ref, 'source'); } if (this.hasAction(ref, 'target')) { if (!this.updateTerminalProperties('target')) { return ref; } ref = this.removeAction(ref, 'target'); } var graph = this.graph; var sourceView = this.sourceView; var targetView = this.targetView; if (graph && ((sourceView && !graph.renderer.isViewMounted(sourceView)) || (targetView && !graph.renderer.isViewMounted(targetView)))) { // Wait for the sourceView and targetView to be rendered. return ref; } if (this.hasAction(ref, 'render')) { this.render(); ref = this.removeAction(ref, [ 'render', 'update', 'vertices', 'labels', 'tools', 'widget', ]); return ref; } ref = this.handleAction(ref, 'vertices', function () { return _this.renderVertexMarkers(); }); ref = this.handleAction(ref, 'update', function () { return _this.update(null, options); }); ref = this.handleAction(ref, 'labels', function () { return _this.onLabelsChange(options); }); ref = this.handleAction(ref, 'tools', function () { _this.renderTools(); _this.updateToolsPosition(); }); ref = this.handleAction(ref, 'widget', function () { return _this.renderExternalTools(); }); return ref; }; EdgeView.prototype.onLabelsChange = function (options) { if (options === void 0) { options = {}; } // Note: this optimization works in async=false mode only if (this.shouldRerenderLabels(options)) { this.renderLabels(); } else { this.updateLabels(); } this.updateLabelPositions(); }; EdgeView.prototype.shouldRerenderLabels = function (options) { if (options === void 0) { options = {}; } var previousLabels = this.cell.previous('labels'); if (previousLabels == null) { return true; } // Here is an optimization for cases when we know, that change does // not require re-rendering of all labels. if ('propertyPathArray' in options && 'propertyValue' in options) { // The label is setting by `prop()` method var pathArray = options.propertyPathArray || []; var pathLength = pathArray.length; if (pathLength > 1) { // We are changing a single label here e.g. 'labels/0/position' var index = pathArray[1]; if (previousLabels[index]) { if (pathLength === 2) { // We are changing the entire label. Need to check if the // markup is also being changed. return (typeof options.propertyValue === 'object' && util_1.ObjectExt.has(options.propertyValue, 'markup')); } // We are changing a label property but not the markup if (pathArray[2] !== 'markup') { return false; } } } } return true; }; EdgeView.prototype.render = function () { this.empty(); this.containers = {}; this.renderMarkup(); this.renderLabels(); this.update(); return this; }; EdgeView.prototype.renderMarkup = function () { var markup = this.cell.markup; if (markup) { if (typeof markup === 'string') { return this.renderStringMarkup(markup); } return this.renderJSONMarkup(markup); } throw new TypeError('Invalid edge markup.'); }; EdgeView.prototype.renderJSONMarkup = function (markup) { var ret = this.parseJSONMarkup(markup, this.container); this.selectors = ret.selectors; this.container.append(ret.fragment); }; EdgeView.prototype.renderStringMarkup = function (markup) { var cache = this.containers; var children = util_1.Vector.createVectors(markup); // Cache children elements for quicker access. children.forEach(function (child) { var className = child.attr('class'); if (className) { cache[util_1.StringExt.camelCase(className)] = child.node; } }); this.renderTools(); this.renderVertexMarkers(); this.renderArrowheadMarkers(); util_1.Dom.append(this.container, children.map(function (child) { return child.node; })); }; EdgeView.prototype.renderLabels = function () { var edge = this.cell; var labels = edge.getLabels(); var count = labels.length; var container = this.containers.labels; this.labelCache = {}; this.labelSelectors = {}; if (count <= 0) { if (container && container.parentNode) { container.parentNode.removeChild(container); } return this; } if (container) { this.empty(container); } else { container = util_1.Dom.createSvgElement('g'); this.addClass(this.prefixClassName('edge-labels'), container); this.containers.labels = container; } for (var i = 0, ii = labels.length; i < ii; i += 1) { var label = labels[i]; var normalized = this.normalizeLabelMarkup(this.parseLabelMarkup(label.markup)); var labelNode = void 0; var selectors = void 0; if (normalized) { labelNode = normalized.node; selectors = normalized.selectors; } else { var defaultLabel = edge.getDefaultLabel(); var normalized_1 = this.normalizeLabelMarkup(this.parseLabelMarkup(defaultLabel.markup)); labelNode = normalized_1.node; selectors = normalized_1.selectors; } labelNode.setAttribute('data-index', "" + i); container.appendChild(labelNode); var rootSelector = this.rootSelector; if (selectors[rootSelector]) { throw new Error('Ambiguous label root selector.'); } selectors[rootSelector] = labelNode; this.labelCache[i] = labelNode; this.labelSelectors[i] = selectors; } if (container.parentNode == null) { this.container.appendChild(container); } this.updateLabels(); this.customizeLabels(); return this; }; EdgeView.prototype.parseLabelMarkup = function (markup) { if (markup) { if (typeof markup === 'string') { return this.parseLabelStringMarkup(markup); } return this.parseJSONMarkup(markup); } return null; }; EdgeView.prototype.parseLabelStringMarkup = function (labelMarkup) { var children = util_1.Vector.createVectors(labelMarkup); var fragment = document.createDocumentFragment(); for (var i = 0, n = children.length; i < n; i += 1) { var currentChild = children[i].node; fragment.appendChild(currentChild); } return { fragment: fragment, selectors: {} }; }; EdgeView.prototype.normalizeLabelMarkup = function (markup) { if (markup == null) { return; } var fragment = markup.fragment; if (!(fragment instanceof DocumentFragment) || !fragment.hasChildNodes()) { throw new Error('Invalid label markup.'); } var vel; var childNodes = fragment.childNodes; if (childNodes.length > 1 || childNodes[0].nodeName.toUpperCase() !== 'G') { // default markup fragment is not wrapped in `<g/>` // add a `<g/>` container vel = util_1.Vector.create('g').append(fragment); } else { vel = util_1.Vector.create(childNodes[0]); } vel.addClass(this.prefixClassName('edge-label')); return { node: vel.node, selectors: markup.selectors, }; }; EdgeView.prototype.updateLabels = function () { if (this.containers.labels) { var edge = this.cell; var labels = edge.labels; var canLabelMove = this.can('edgeLabelMovable'); var defaultLabel = edge.getDefaultLabel(); for (var i = 0, n = labels.length; i < n; i += 1) { var elem = this.labelCache[i]; var selectors = this.labelSelectors[i]; elem.setAttribute('cursor', canLabelMove ? 'move' : 'default'); var label = labels[i]; var attrs = util_1.ObjectExt.merge({}, defaultLabel.attrs, label.attrs); this.updateAttrs(elem, attrs, { selectors: selectors, rootBBox: label.size ? geometry_1.Rectangle.fromSize(label.size) : undefined, }); } } }; EdgeView.prototype.mergeLabelAttrs = function (hasCustomMarkup, labelAttrs, defaultLabelAttrs) { if (labelAttrs === null) { return null; } if (labelAttrs === undefined) { if (defaultLabelAttrs === null) { return null; } if (defaultLabelAttrs === undefined) { return undefined; } if (hasCustomMarkup) { return defaultLabelAttrs; } return util_1.ObjectExt.merge({}, defaultLabelAttrs); } if (hasCustomMarkup) { return util_1.ObjectExt.merge({}, defaultLabelAttrs, labelAttrs); } }; EdgeView.prototype.customizeLabels = function () { if (this.containers.labels) { var edge = this.cell; var labels = edge.labels; for (var i = 0, n = labels.length; i < n; i += 1) { var label = labels[i]; var container = this.labelCache[i]; var selectors = this.labelSelectors[i]; this.graph.hook.onEdgeLabelRendered({ edge: edge, label: label, container: container, selectors: selectors, }); } } }; EdgeView.prototype.renderTools = function () { var container = this.containers.tools; if (container == null) { return this; } var markup = this.cell.toolMarkup; var $container = this.$(container).empty(); if (markup_1.Markup.isStringMarkup(markup)) { var template = util_1.StringExt.template(markup); var tool = util_1.Vector.create(template()); $container.append(tool.node); this.toolCache = tool.node; // If `doubleTools` is enabled, we render copy of the tools on the // other side of the edge as well but only if the edge is longer // than `longLength`. if (this.options.doubleTools) { var tool2 = void 0; var doubleToolMarkup = this.cell.doubleToolMarkup; if (markup_1.Markup.isStringMarkup(doubleToolMarkup)) { template = util_1.StringExt.template(doubleToolMarkup); tool2 = util_1.Vector.create(template()); } else { tool2 = tool.clone(); } $container.append(tool2.node); this.tool2Cache = tool2.node; } } return this; }; EdgeView.prototype.renderExternalTools = function () { var tools = this.cell.getTools(); this.addTools(tools); return this; }; EdgeView.prototype.renderVertexMarkers = function () { var container = this.containers.vertices; if (container == null) { return this; } var markup = this.cell.vertexMarkup; var $container = this.$(container).empty(); if (markup_1.Markup.isStringMarkup(markup)) { var template_1 = util_1.StringExt.template(markup); this.cell.getVertices().forEach(function (vertex, index) { $container.append(util_1.Vector.create(template_1(__assign({ index: index }, vertex))).node); }); } return this; }; EdgeView.prototype.renderArrowheadMarkers = function () { var container = this.containers.arrowheads; if (container == null) { return this; } var markup = this.cell.arrowheadMarkup; var $container = this.$(container).empty(); if (markup_1.Markup.isStringMarkup(markup)) { var template = util_1.StringExt.template(markup); var sourceArrowhead = util_1.Vector.create(template({ end: 'source' })).node; var targetArrowhead = util_1.Vector.create(template({ end: 'target' })).node; this.containers.sourceArrowhead = sourceArrowhead; this.containers.targetArrowhead = targetArrowhead; $container.append(sourceArrowhead, targetArrowhead); } return this; }; // #endregion // #region updating EdgeView.prototype.update = function (partialAttrs, options) { if (options === void 0) { options = {}; } this.cleanCache(); this.updateConnection(options); var attrs = this.cell.getAttrs(); if (attrs != null) { this.updateAttrs(this.container, attrs, { attrs: partialAttrs === attrs ? null : partialAttrs, selectors: this.selectors, }); } this.updateConnectionPath(); this.updateLabelPositions(); this.updateToolsPosition(); this.updateArrowheadMarkers(); if (options.toolId == null) { this.renderExternalTools(); } else { this.updateTools(options); } return this; }; EdgeView.prototype.removeRedundantLinearVertices = function (options) { if (options === void 0) { options = {}; } var edge = this.cell; var vertices = edge.getVertices(); var routePoints = __spreadArray(__spreadArray([this.sourceAnchor], vertices, true), [this.targetAnchor], false); var rawCount = routePoints.length; // Puts the route points into a polyline and try to simplify. var polyline = new geometry_1.Polyline(routePoints); polyline.simplify({ threshold: 0.01 }); var simplifiedPoints = polyline.points.map(function (point) { return point.toJSON(); }); var simplifiedCount = simplifiedPoints.length; // If simplification did not remove any redundant vertices. if (rawCount === simplifiedCount) { return 0; } // Sets simplified polyline points as edge vertices. // Removes first and last polyline points again (source/target anchors). edge.setVertices(simplifiedPoints.slice(1, simplifiedCount - 1), options); return rawCount - simplifiedCount; }; EdgeView.prototype.updateConnectionPath = function () { var containers = this.containers; if (containers.connection) { var pathData = this.getConnectionPathData(); containers.connection.setAttribute('d', pathData); } if (containers.connectionWrap) { var pathData = this.getConnectionPathData(); containers.connectionWrap.setAttribute('d', pathData); } if (containers.sourceMarker && containers.targetMarker) { this.translateAndAutoOrientArrows(containers.sourceMarker, containers.targetMarker); } }; EdgeView.prototype.getTerminalView = function (type) { switch (type) { case 'source': return this.sourceView || null; case 'target': return this.targetView || null; default: throw new Error("Unknown terminal type '" + type + "'"); } }; EdgeView.prototype.getTerminalAnchor = function (type) { switch (type) { case 'source': return geometry_1.Point.create(this.sourceAnchor); case 'target': return geometry_1.Point.create(this.targetAnchor); default: throw new Error("Unknown terminal type '" + type + "'"); } }; EdgeView.prototype.getTerminalConnectionPoint = function (type) { switch (type) { case 'source': return geometry_1.Point.create(this.sourcePoint); case 'target': return geometry_1.Point.create(this.targetPoint); default: throw new Error("Unknown terminal type '" + type + "'"); } }; EdgeView.prototype.getTerminalMagnet = function (type, options) { if (options === void 0) { options = {}; } switch (type) { case 'source': { if (options.raw) { return this.sourceMagnet; } var sourceView = this.sourceView; if (!sourceView) { return null; } return this.sourceMagnet || sourceView.container; } case 'target': { if (options.raw) { return this.targetMagnet; } var targetView = this.targetView; if (!targetView) { return null; } return this.targetMagnet || targetView.container; } default: { throw new Error("Unknown terminal type '" + type + "'"); } } }; EdgeView.prototype.updateConnection = function (options) { if (options === void 0) { options = {}; } var edge = this.cell; // The edge is being translated by an ancestor that will shift // source, target and vertices by an equal distance. if (options.translateBy && edge.isFragmentDescendantOf(options.translateBy)) { var tx = options.tx || 0; var ty = options.ty || 0; this.routePoints = new geometry_1.Polyline(this.routePoints).translate(tx, ty).points; this.translateConnectionPoints(tx, ty); this.path.translate(tx, ty); } else { var vertices = edge.getVertices(); // 1. Find anchor points var anchors = this.findAnchors(vertices); this.sourceAnchor = anchors.source; this.targetAnchor = anchors.target; // 2. Find route points this.routePoints = this.findRoutePoints(vertices); // 3. Find connection points var connectionPoints = this.findConnectionPoints(this.routePoints, this.sourceAnchor, this.targetAnchor); this.sourcePoint = connectionPoints.source; this.targetPoint = connectionPoints.target; // 4. Find Marker Connection Point var markerPoints = this.findMarkerPoints(this.routePoints, this.sourcePoint, this.targetPoint); // 5. Make path this.path = this.findPath(this.routePoints, markerPoints.source || this.sourcePoint, markerPoints.target || this.targetPoint); } this.cleanCache(); }; EdgeView.prototype.findAnchors = function (vertices) { var edge = this.cell; var source = edge.source; var target = edge.target; var firstVertex = vertices[0]; var lastVertex = vertices[vertices.length - 1]; if (target.priority && !source.priority) { // Reversed order return this.findAnchorsOrdered('target', lastVertex, 'source', firstVertex); } // Usual order return this.findAnchorsOrdered('source', firstVertex, 'target', lastVertex); }; EdgeView.prototype.findAnchorsOrdered = function (firstType, firstPoint, secondType, secondPoint) { var _a; var firstAnchor; var secondAnchor; var edge = this.cell; var firstTerminal = edge[firstType]; var secondTerminal = edge[secondType]; var firstView = this.getTerminalView(firstType); var secondView = this.getTerminalView(secondType); var firstMagnet = this.getTerminalMagnet(firstType); var secondMagnet = this.getTerminalMagnet(secondType); if (firstView) { var firstRef = void 0; if (firstPoint) { firstRef = geometry_1.Point.create(firstPoint); } else if (secondView) { firstRef = secondMagnet; } else { firstRef = geometry_1.Point.create(secondTerminal); } firstAnchor = this.getAnchor(firstTerminal.anchor, firstView, firstMagnet, firstRef, firstType); } else { firstAnchor = geometry_1.Point.create(firstTerminal); } if (secondView) { var secondRef = geometry_1.Point.create(secondPoint || firstAnchor); secondAnchor = this.getAnchor(secondTerminal.anchor, secondView, secondMagnet, secondRef, secondType); } else { secondAnchor = geometry_1.Point.isPointLike(secondTerminal) ? geometry_1.Point.create(secondTerminal) : new geometry_1.Point(); } return _a = {}, _a[firstType] = firstAnchor, _a[secondType] = secondAnchor, _a; }; EdgeView.prototype.getAnchor = function (def, cellView, magnet, ref, terminalType) { var isEdge = cellView.isEdgeElement(magnet); var connecting = this.graph.options.connecting; var config = typeof def === 'string' ? { name: def } : def; if (!config) { var defaults = isEdge ? (terminalType === 'source' ? connecting.sourceEdgeAnchor : connecting.targetEdgeAnchor) || connecting.edgeAnchor : (terminalType === 'source' ? connecting.sourceAnchor : connecting.targetAnchor) || connecting.anchor; config = typeof defaults === 'string' ? { name: defaults } : defaults; } if (!config) { throw new Error("Anchor should be specified."); } var anchor; var name = config.name; if (isEdge) { var fn = registry_1.EdgeAnchor.registry.get(name); if (typeof fn !== 'function') { return registry_1.EdgeAnchor.registry.onNotFound(name); } anchor = util_1.FunctionExt.call(fn, this, cellView, magnet, ref, config.args || {}, terminalType); } else { var fn = registry_1.NodeAnchor.registry.get(name); if (typeof fn !== 'function') { return registry_1.NodeAnchor.registry.onNotFound(name); } anchor = util_1.FunctionExt.call(fn, this, cellView, magnet, ref, config.args || {}, terminalType); } return anchor ? anchor.round(this.POINT_ROUNDING) : new geometry_1.Point(); }; EdgeView.prototype.findRoutePoints = function (vertices) { if (vertices === void 0) { vertices = []; } var defaultRouter = this.graph.options.connecting.router || registry_1.Router.presets.normal; var router = this.cell.getRouter() || defaultRouter; var routePoints; if (typeof router === 'function') { routePoints = util_1.FunctionExt.call(router, this, vertices, {}, this); } else { var name_1 = typeof router === 'string' ? router : router.name; var args = typeof router === 'string' ? {} : router.args || {}; var fn = name_1 ? registry_1.Router.registry.get(name_1) : registry_1.Router.presets.normal; if (typeof fn !== 'function') { return registry_1.Router.registry.onNotFound(name_1); } routePoints = util_1.FunctionExt.call(fn, this, vertices, args, this); } return routePoints == null ? vertices.map(function (p) { return geometry_1.Point.create(p); }) : routePoints.map(function (p) { return geometry_1.Point.create(p); }); }; EdgeView.prototype.findConnectionPoints = function (routePoints, sourceAnchor, targetAnchor) { var edge = this.cell; var connecting = this.graph.options.connecting; var sourceTerminal = edge.getSource(); var targetTerminal = edge.getTarget(); var sourceView = this.sourceView; var targetView = this.targetView; var firstRoutePoint = routePoints[0]; var lastRoutePoint = routePoints[routePoints.length - 1]; // source var sourcePoint; if (sourceView && !sourceView.isEdgeElement(this.sourceMagnet)) { var sourceMagnet = this.sourceMagnet || sourceView.container; var sourcePointRef = firstRoutePoint || targetAnchor; var sourceLine = new geometry_1.Line(sourcePointRef, sourceAnchor); var connectionPointDef = sourceTerminal.connectionPoint || connecting.sourceConnectionPoint || connecting.connectionPoint; sourcePoint = this.getConnectionPoint(connectionPointDef, sourceView, sourceMagnet, sourceLine, 'source'); } else { sourcePoint = sourceAnchor; } // target var targetPoint; if (targetView && !targetView.isEdgeElement(this.targetMagnet)) { var targetMagnet = this.targetMagnet || targetView.container; var targetConnectionPointDef = targetTerminal.connectionPoint || connecting.targetConnectionPoint || connecting.connectionPoint; var targetPointRef = lastRoutePoint || sourceAnchor; var targetLine = new geometry_1.Line(targetPointRef, targetAnchor); targetPoint = this.getConnectionPoint(targetConnectionPointDef, targetView, targetMagnet, targetLine, 'target'); } else { targetPoint = targetAnchor; } return { source: sourcePoint, target: targetPoint, }; }; EdgeView.prototype.getConnectionPoint = function (def, view, magnet, line, endType) { var anchor = line.end; if (def == null) { return anchor; } var name = typeof def === 'string' ? def : def.name; var args = typeof def === 'string' ? {} : def.args; var fn = registry_1.ConnectionPoint.registry.get(name); if (typeof fn !== 'function') { return registry_1.ConnectionPoint.registry.onNotFound(name); } var connectionPoint = util_1.FunctionExt.call(fn, this, line, view, magnet, args || {}, endType); return connectionPoint ? connectionPoint.round(this.POINT_ROUNDING) : anchor; }; EdgeView.prototype.updateMarkerAttr = function (type) { var _a; var attrs = this.cell.getAttrs(); var key = "." + type + "-marker"; var partial = attrs && attrs[key]; if (partial) { this.updateAttrs(this.container, {}, { attrs: (_a = {}, _a[key] = partial, _a), selectors: this.selectors, }); } }; EdgeView.prototype.findMarkerPoints = function (routePoints, sourcePoint, targetPoint) { var _this = this; var getLineWidth = function (type) { var attrs = _this.cell.getAttrs(); var keys = Object.keys(attrs); for (var i = 0, l = keys.length; i < l; i += 1) { var attr = attrs[keys[i]]; if (attr[type + "Marker"] || attr[type + "-marker"]) { var strokeWidth = attr.strokeWidth || attr['stroke-width']; if (strokeWidth) { return parseFloat(strokeWidth); } break; } } return null; }; var firstRoutePoint = routePoints[0]; var lastRoutePoint = routePoints[routePoints.length - 1]; var sourceMarkerElem = this.containers.sourceMarker; var targetMarkerElem = this.containers.targetMarker; var cache = this.markerCache; var sourceMarkerPoint; var targetMarkerPoint; // Move the source point by the width of the marker taking into // account its scale around x-axis. Note that scale is the only // transform that makes sense to be set in `.marker-source` // attributes object as all other transforms (translate/rotate) // will be replaced by the `translateAndAutoOrient()` function. if (sourceMarkerElem) { this.updateMarkerAttr('source'); // support marker connection point registry??? cache.sourceBBox = cache.sourceBBox || util_1.Dom.getBBox(sourceMarkerElem); if (cache.sourceBBox.width > 0) { var scale = util_1.Dom.scale(sourceMarkerElem); sourceMarkerPoint = sourcePoint .clone() .move(firstRoutePoint || targetPoint, cache.sourceBBox.width * scale.sx * -1); } } else { var strokeWidth = getLineWidth('source'); if (strokeWidth) { sourceMarkerPoint = sourcePoint .clone() .move(firstRoutePoint || targetPoint, -strokeWidth); } } if (targetMarkerElem) { this.updateMarkerAttr('target'); cache.targetBBox = cache.targetBBox || util_1.Dom.getBBox(targetMarkerElem); if (cache.targetBBox.width > 0) { var scale = util_1.Dom.scale(targetMarkerElem); targetMarkerPoint = targetPoint .clone() .move(lastRoutePoint || sourcePoint, cache.targetBBox.width * scale.sx * -1); } } else { var strokeWidth = getLineWidth('target'); if (strokeWidth) { targetMarkerPoint = targetPoint .clone() .move(lastRoutePoint || sourcePoint, -strokeWidth); } } // If there was no markup for the marker, use the connection point. cache.sourcePoint = sourceMarkerPoint || sourcePoint.clone(); cache.targetPoint = targetMarkerPoint || targetPoint.clone(); return { source: sourceMarkerPoint, target: targetMarkerPoint, }; }; EdgeView.prototype.findPath = function (routePoints, sourcePoint, targetPoint) { var def = this.cell.getConnector() || this.graph.options.connecting.connector; var name; var args; var fn; if (typeof def === 'string') { name = def; } else { name = def.name; args = def.args; } if (name) { var method = registry_1.Connector.registry.get(name); if (typeof method !== 'function') { return registry_1.Connector.registry.onNotFound(name); } fn = method; } else { fn = registry_1.Connector.presets.normal; } var path = util_1.FunctionExt.call(fn, this, sourcePoint, targetPoint, routePoints, __assign(__assign({}, args), { raw: true }), this); return typeof path === 'string' ? geometry_1.Path.parse(path) : path; }; EdgeView.prototype.translateConnectionPoints = function (tx, ty) { var cache = this.markerCache; if (cache.sourcePoint) { cache.sourcePoint.translate(tx, ty); } if (cache.targetPoint) { cache.targetPoint.translate(tx, ty); } this.sourcePoint.translate(tx, ty); this.targetPoint.translate(tx, ty); this.sourceAnchor.translate(tx, ty); this.targetAnchor.translate(tx, ty); }; EdgeView.prototype.updateLabelPositions = function () { if (this.containers.labels == null) { return this; } var path = this.path; if (!path) { return this; } var edge = this.cell; var labels = edge.getLabels(); if (labels.length === 0) { return this; } var defaultLabel = edge.getDefaultLabel(); var defaultPosition = this.normalizeLabelPosition(defaultLabel.position); for (var i = 0, ii = labels.length; i < ii; i += 1) { var label = labels[i]; var labelPosition = this.normalizeLabelPosition(label.position); var pos = util_1.ObjectExt.merge({}, defaultPosition, labelPosition); var matrix = this.getLabelTransformationMatrix(pos); this.labelCache[i].setAttribute('transform', util_1.Dom.matrixToTransformString(matrix)); } return this; }; EdgeView.prototype.updateToolsPosition = function () { if (this.containers.tools == null) { return this; } // Move the tools a bit to the target position but don't cover the // `sourceArrowhead` marker. Note that the offset is hardcoded here. // The offset should be always more than the // `this.$('.marker-arrowhead[end="source"]')[0].bbox().width` but looking // this up all the time would be slow. var scale = ''; var offset = this.options.toolsOffset; var connectionLength = this.getConnectionLength(); // Firefox returns `connectionLength=NaN` in odd cases (for bezier curves). // In that case we won't update tools position at all. if (connectionLength != null) { // If the edge is too short, make the tools half the // size and the offset twice as low. if (connectionLength < this.options.shortLength) { scale = 'scale(.5)'; offset /= 2; } var pos = this.getPointAtLength(offset); if (pos != null) { util_1.Dom.attr(this.toolCache, 'transform', "translate(" + pos.x + "," + pos.y + ") " + scale); } if (this.options.doubleTools && connectionLength >= this.options.longLength) { var doubleToolsOffset = this.options.doubleToolsOffset || offset; pos = this.getPointAtLength(connectionLength - doubleToolsOffset); if (pos != null) { util_1.Dom.attr(this.tool2Cache, 'transform', "translate(" + pos.x + "," + pos.y + ") " + scale); } util_1.Dom.attr(this.tool2Cache, 'visibility', 'visible'); } else if (this.options.doubleTools) { util_1.Dom.attr(this.tool2Cache, 'visibility', 'hidden'); } } return this; }; EdgeView.prototype.updateArrowheadMarkers = function () { var container = this.containers.arrowheads; if (container == null) { return this; } if (container.style.display === 'none') { return this; } var sourceArrowhead = this.containers.sourceArrowhead; var targetArrowhead = this.containers.targetArrowhead; if (sourceArrowhead && targetArrowhead) { var len = this.getConnectionLength() || 0; var sx = len < this.options.shortLength ? 0.5 : 1; util_1.Dom.scale(sourceArrowhead, sx); util_1.Dom.scale(targetArrowhead, sx); this.translateAndAutoOrientArrows(sourceArrowhead, targetArrowhead); } return this; }; EdgeView.prototype.updateTerminalProperties = function (type) { var edge = this.cell; var graph = this.graph; var terminal = edge[type]; var nodeId = terminal && terminal.cell; var viewKey = type + "View"; // terminal is a point if (!nodeId) { this[viewKey] = null; this.updateTerminalMagnet(type); return true; } var terminalCell = graph.getCellById(nodeId); if (!terminalCell) { throw new Error("Edge's " + type + " node with id \"" + nodeId + "\" not exists"); } var endView = terminalCell.findView(graph); if (!endView) { return false; } this[viewKey] = endView; this.updateTerminalMagnet(type); return true; }; EdgeView.prototype.updateTerminalMagnet = function (type) { var propName = type + "Magnet"; var terminalView = this.getTerminalView(type); if (terminalView) { var magnet = terminalView.getMagnetFromEdgeTerminal(this.cell[type]); if (magnet === terminalView.container) { magnet = null; } this[propName] = magnet; } else { this[propName] = null; } }; EdgeView.prototype.translateAndAutoOrientArrows = function (sourceArrow, targetArrow) { var route = this.routePoints; if (sourceArrow) { util_1.Dom.translateAndAutoOrient(sourceArrow, this.sourcePoint, route[0] || this.targetPoint, this.graph.view.stage); } if (targetArrow) { util_1.Dom.translateAndAutoOrient(targetArrow, this.targetPoint, route[route.length - 1] || this.sourcePoint, this.graph.view.stage); } }; EdgeView.prototype.getLabelPositionAngle = function (idx) { var label = this.cell.getLabelAt(idx); if (label && label.position && typeof label.position === 'object') { return label.position.angle || 0; } return 0; }; EdgeView.prototype.getLabelPositionArgs = function (idx) { var label = this.cell.getLabelAt(idx); if (label && label.position && typeof label.position === 'object') { return label.position.options; } }; EdgeView.prototype.getDefaultLabelPositionArgs = function () { var defaultLabel = this.cell.getDefaultLabel(); if (defaultLabel && defaultLabel.position && typeof defaultLabel.position === 'object') { return defaultLabel.position.options; } }; // merge default label position args into label position args // keep `undefined` or `null` because `{}` means something else EdgeView.prototype.mergeLabelPositionArgs = function (labelPositionArgs, defaultLabelPositionArgs) { if (labelPositionArgs === null) { return null; } if (labelPositionArgs === undefined) { if (defaultLabelPositionArgs === null) { return null; } return defaultLabelPositionArgs; } return util_1.ObjectExt.merge({}, defaultLabelPositionArgs, labelPositionArgs); }; EdgeView.prototype.addLabel = function (p1, p2, p3, options) { var localX; var localY; var localAngle = 0; var localOptions; if (typeof p1 !== 'number') { localX = p1.x; localY = p1.y; if (typeof p2 === 'number') { localAngle = p2; localOptions = p3; } else { localOptions = p2; } } else { localX = p1; localY = p2; if (typeof p3 === 'number') { localAngle = p3; localOptions = options; } else { localOptions = p3; } } // merge label position arguments var defaultLabelPositionArgs = this.getDefaultLabelPositionArgs(); var labelPositionArgs = localOptions; var positionArgs = this.mergeLabelPositionArgs(labelPositionArgs, defaultLabelPositionArgs); // append label to labels array var label = { position: this.getLabelPosition(localX, localY, localAngle, positionArgs), }; var index = -1; this.cell.insertLabel(label, index, localOptions); return index; }; EdgeView.prototype.addVertex = function (x, y, options) { var isPoint = typeof x !== 'number'; var localX = isPoint ? x.x : x; var localY = isPoint ? x.y : y; var localOptions = isPoint ? y : options; var vertex = { x: localX, y: localY }; var index = this.getVertexIndex(localX, localY); this.cell.insertVertex(vertex, index, localOptions); return index; }; EdgeView.prototype.sendToken = function (token, options, callback) { var duration; var reversed; var selector; var rorate; var timing = 'linear'; if (typeof options === 'object') { duration = options.duration; reversed = options.reversed === true; selector = options.selector; if (options.rotate === false) { rorate = ''; } else if (options.rotate === true) { rorate = 'auto'; } else if (options.rotate != null) { rorate = "" + options.rotate; } if (options.timing) { timing = options.timing; } } else { duration = options; reversed = false; selector = null; } duration = duration || 1000; var attrs = { dur: duration + "ms", repeatCount: '1', calcMode: timing, fill: 'freeze', }; if (rorate) { attrs.rotate = rorate; } if (reversed) { attrs.keyPoints = '1;0'; attrs.keyTimes = '0;1'; } if (typeof options === 'object') { var duration_1 = options.duration, reversed_1 = options.reversed, selector_1 = options.selector, rotate = options.rotate, timing_1 = options.timing, others_1 = __rest(options, ["duration", "reversed", "selector", "rotate", "timing"]); Object.keys(others_1).forEach(function (key) { attrs[key] = others_1[key]; }); } var path; if (typeof selector === 'string') { path = this.findOne(selector, this.container, this.selectors); } else { // Select connection path automatically. path = this.containers.connection ? this.containers.connection : this.container.querySelector('path'); } if (!(path instanceof SVGPathElement)) { throw new Error('Token animation requires a valid connection path.'); } var target = typeof token === 'string' ? this.findOne(token) : token; if (target == null) { throw new Error('Token animation requires a valid token element.'); } var parent = target.parentNode; var revert = function () { if (!parent) { util_1.Dom.remove(target); } }; var vToken = util_1.Vector.create(target); if (!parent) { vToken.appendTo(this.graph.view.stage); } var onComplete = attrs.complete; attrs.complete = function (e) { revert(); if (callback) { callback(); } if (onComplete) { onComplete(e); } }; var stop = vToken.animateAlongPath(attrs, path); return function () { revert(); stop(); }; }; // #endregion EdgeView.prototype.getConnection = function () { return this.path != null ? this.path.clone() : null; }; EdgeView.prototype.getConnectionPathData = function () { if (this.path == null) { return ''; } var cache = this.cache.pathCache; if (!util_1.ObjectExt.has(cache, 'data')) { cache.data = this.path.serialize(); } return cache.data || ''; }; EdgeView.prototype.getConnectionSubdivisions = function () { if (this.path == null) { return null; } var cache = this.cache.pathCache; if (!util_1.ObjectExt.has(cache, 'segmentSubdivisions')) { cache.segmentSubdivisions = this.path.getSegmentSubdivisions(); } return cache.segmentSubdivisions;