UNPKG

@jsplumb/core

Version:

Visual connectivity for webapps. This is the core package, which is imported by specific renderers. You probably want to import @jsplumb/browser-ui, as it is currently the only renderer available.

1,492 lines (1,432 loc) 274 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@jsplumb/util'), require('@jsplumb/common')) : typeof define === 'function' && define.amd ? define(['exports', '@jsplumb/util', '@jsplumb/common'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.jsPlumb = {}, global.jsPlumbUtil, global.jsPlumbCommon)); }(this, (function (exports, util, common) { 'use strict'; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var endpointMap = {}; var endpointComputers = {}; var handlers = {}; var EndpointFactory = { get: function get(ep, name, params) { var e = endpointMap[name]; if (!e) { throw { message: "jsPlumb: unknown endpoint type '" + name + "'" }; } else { return new e(ep, params); } }, clone: function clone(epr) { var handler = handlers[epr.type]; return EndpointFactory.get(epr.endpoint, epr.type, handler.getParams(epr)); }, compute: function compute(endpoint, anchorPoint, orientation, endpointStyle) { var c = endpointComputers[endpoint.type]; if (c != null) { return c(endpoint, anchorPoint, orientation, endpointStyle); } else { util.log("jsPlumb: cannot find endpoint calculator for endpoint of type ", endpoint.type); } }, registerHandler: function registerHandler(eph) { handlers[eph.type] = eph; endpointMap[eph.type] = eph.cls; endpointComputers[eph.type] = eph.compute; } }; var EndpointRepresentation = function () { function EndpointRepresentation(endpoint, params) { _classCallCheck(this, EndpointRepresentation); this.endpoint = endpoint; _defineProperty(this, "typeId", void 0); _defineProperty(this, "x", void 0); _defineProperty(this, "y", void 0); _defineProperty(this, "w", void 0); _defineProperty(this, "h", void 0); _defineProperty(this, "computedValue", void 0); _defineProperty(this, "bounds", common.EMPTY_BOUNDS()); _defineProperty(this, "classes", []); _defineProperty(this, "instance", void 0); _defineProperty(this, "type", void 0); params = params || {}; this.instance = endpoint.instance; if (endpoint.cssClass) { this.classes.push(endpoint.cssClass); } if (params.cssClass) { this.classes.push(params.cssClass); } } _createClass(EndpointRepresentation, [{ key: "addClass", value: function addClass(c) { this.classes.push(c); this.instance.addEndpointClass(this.endpoint, c); } }, { key: "removeClass", value: function removeClass(c) { this.classes = this.classes.filter(function (_c) { return _c !== c; }); this.instance.removeEndpointClass(this.endpoint, c); } }, { key: "compute", value: function compute(anchorPoint, orientation, endpointStyle) { this.computedValue = EndpointFactory.compute(this, anchorPoint, orientation, endpointStyle); this.bounds.xmin = this.x; this.bounds.ymin = this.y; this.bounds.xmax = this.x + this.w; this.bounds.ymax = this.y + this.h; } }, { key: "setVisible", value: function setVisible(v) { this.instance.setEndpointVisible(this.endpoint, v); } }]); return EndpointRepresentation; }(); var DotEndpoint = function (_EndpointRepresentati) { _inherits(DotEndpoint, _EndpointRepresentati); var _super = _createSuper(DotEndpoint); function DotEndpoint(endpoint, params) { var _this; _classCallCheck(this, DotEndpoint); _this = _super.call(this, endpoint, params); _defineProperty(_assertThisInitialized(_this), "radius", void 0); _defineProperty(_assertThisInitialized(_this), "defaultOffset", void 0); _defineProperty(_assertThisInitialized(_this), "defaultInnerRadius", void 0); _defineProperty(_assertThisInitialized(_this), "type", DotEndpoint.type); params = params || {}; _this.radius = params.radius || 5; _this.defaultOffset = 0.5 * _this.radius; _this.defaultInnerRadius = _this.radius / 3; return _this; } return DotEndpoint; }(EndpointRepresentation); _defineProperty(DotEndpoint, "type", "Dot"); var DotEndpointHandler = { type: DotEndpoint.type, cls: DotEndpoint, compute: function compute(ep, anchorPoint, orientation, endpointStyle) { var x = anchorPoint.curX - ep.radius, y = anchorPoint.curY - ep.radius, w = ep.radius * 2, h = ep.radius * 2; if (endpointStyle && endpointStyle.stroke) { var lw = endpointStyle.strokeWidth || 1; x -= lw; y -= lw; w += lw * 2; h += lw * 2; } ep.x = x; ep.y = y; ep.w = w; ep.h = h; return [x, y, w, h, ep.radius]; }, getParams: function getParams(ep) { return { radius: ep.radius }; } }; var BlankEndpoint = function (_EndpointRepresentati) { _inherits(BlankEndpoint, _EndpointRepresentati); var _super = _createSuper(BlankEndpoint); function BlankEndpoint(endpoint, params) { var _this; _classCallCheck(this, BlankEndpoint); _this = _super.call(this, endpoint, params); _defineProperty(_assertThisInitialized(_this), "type", BlankEndpoint.type); return _this; } return BlankEndpoint; }(EndpointRepresentation); _defineProperty(BlankEndpoint, "type", "Blank"); var BlankEndpointHandler = { type: BlankEndpoint.type, cls: BlankEndpoint, compute: function compute(ep, anchorPoint, orientation, endpointStyle) { ep.x = anchorPoint.curX; ep.y = anchorPoint.curY; ep.w = 10; ep.h = 0; return [anchorPoint.curX, anchorPoint.curY, 10, 0]; }, getParams: function getParams(ep) { return {}; } }; var RectangleEndpoint = function (_EndpointRepresentati) { _inherits(RectangleEndpoint, _EndpointRepresentati); var _super = _createSuper(RectangleEndpoint); function RectangleEndpoint(endpoint, params) { var _this; _classCallCheck(this, RectangleEndpoint); _this = _super.call(this, endpoint, params); _defineProperty(_assertThisInitialized(_this), "width", void 0); _defineProperty(_assertThisInitialized(_this), "height", void 0); _defineProperty(_assertThisInitialized(_this), "type", RectangleEndpoint.type); params = params || {}; _this.width = params.width || 10; _this.height = params.height || 10; return _this; } _createClass(RectangleEndpoint, null, [{ key: "_getParams", value: function _getParams(ep) { return { width: ep.width, height: ep.height }; } }]); return RectangleEndpoint; }(EndpointRepresentation); _defineProperty(RectangleEndpoint, "type", "Rectangle"); var RectangleEndpointHandler = { type: RectangleEndpoint.type, cls: RectangleEndpoint, compute: function compute(ep, anchorPoint, orientation, endpointStyle) { var width = endpointStyle.width || ep.width, height = endpointStyle.height || ep.height, x = anchorPoint.curX - width / 2, y = anchorPoint.curY - height / 2; ep.x = x; ep.y = y; ep.w = width; ep.h = height; return [x, y, width, height]; }, getParams: function getParams(ep) { return { width: ep.width, height: ep.height }; } }; var AbstractConnector = function () { function AbstractConnector(connection, params) { _classCallCheck(this, AbstractConnector); this.connection = connection; _defineProperty(this, "type", void 0); _defineProperty(this, "edited", false); _defineProperty(this, "stub", void 0); _defineProperty(this, "sourceStub", void 0); _defineProperty(this, "targetStub", void 0); _defineProperty(this, "maxStub", void 0); _defineProperty(this, "typeId", void 0); _defineProperty(this, "gap", void 0); _defineProperty(this, "sourceGap", void 0); _defineProperty(this, "targetGap", void 0); _defineProperty(this, "segments", []); _defineProperty(this, "totalLength", 0); _defineProperty(this, "segmentProportions", []); _defineProperty(this, "segmentProportionalLengths", []); _defineProperty(this, "paintInfo", null); _defineProperty(this, "strokeWidth", void 0); _defineProperty(this, "x", void 0); _defineProperty(this, "y", void 0); _defineProperty(this, "w", void 0); _defineProperty(this, "h", void 0); _defineProperty(this, "segment", void 0); _defineProperty(this, "bounds", common.EMPTY_BOUNDS()); _defineProperty(this, "cssClass", void 0); _defineProperty(this, "hoverClass", void 0); _defineProperty(this, "geometry", void 0); this.stub = params.stub || this.getDefaultStubs(); this.sourceStub = Array.isArray(this.stub) ? this.stub[0] : this.stub; this.targetStub = Array.isArray(this.stub) ? this.stub[1] : this.stub; this.gap = params.gap || 0; this.sourceGap = Array.isArray(this.gap) ? this.gap[0] : this.gap; this.targetGap = Array.isArray(this.gap) ? this.gap[1] : this.gap; this.maxStub = Math.max(this.sourceStub, this.targetStub); this.cssClass = params.cssClass || ""; this.hoverClass = params.hoverClass || ""; } _createClass(AbstractConnector, [{ key: "getTypeDescriptor", value: function getTypeDescriptor() { return "connector"; } }, { key: "getIdPrefix", value: function getIdPrefix() { return "_jsplumb_connector"; } }, { key: "setGeometry", value: function setGeometry(g, internal) { this.geometry = g; this.edited = g != null && !internal; } }, { key: "exportGeometry", value: function exportGeometry() { return this.geometry; } }, { key: "importGeometry", value: function importGeometry(g) { this.geometry = g; return true; } }, { key: "resetGeometry", value: function resetGeometry() { this.geometry = null; this.edited = false; } }, { key: "transformAnchorPlacement", value: function transformAnchorPlacement(a, dx, dy) { return { x: a.x, y: a.y, ox: a.ox, oy: a.oy, curX: a.curX + dx, curY: a.curY + dy }; } }, { key: "resetBounds", value: function resetBounds() { this.bounds = common.EMPTY_BOUNDS(); } }, { key: "findSegmentForPoint", value: function findSegmentForPoint(x, y) { var out = { d: Infinity, s: null, x: null, y: null, l: null, x1: null, y1: null, x2: null, y2: null, index: null, connectorLocation: null }; for (var i = 0; i < this.segments.length; i++) { var _s = this.segments[i].findClosestPointOnPath(x, y); if (_s.d < out.d) { out.d = _s.d; out.l = _s.l; out.x = _s.x; out.y = _s.y; out.s = this.segments[i]; out.x1 = _s.x1; out.x2 = _s.x2; out.y1 = _s.y1; out.y2 = _s.y2; out.index = i; out.connectorLocation = this.segmentProportions[i][0] + _s.l * (this.segmentProportions[i][1] - this.segmentProportions[i][0]); } } return out; } }, { key: "lineIntersection", value: function lineIntersection(x1, y1, x2, y2) { var out = []; for (var i = 0; i < this.segments.length; i++) { out.push.apply(out, this.segments[i].lineIntersection(x1, y1, x2, y2)); } return out; } }, { key: "boxIntersection", value: function boxIntersection(x, y, w, h) { var out = []; for (var i = 0; i < this.segments.length; i++) { out.push.apply(out, this.segments[i].boxIntersection(x, y, w, h)); } return out; } }, { key: "boundingBoxIntersection", value: function boundingBoxIntersection(box) { var out = []; for (var i = 0; i < this.segments.length; i++) { out.push.apply(out, this.segments[i].boundingBoxIntersection(box)); } return out; } }, { key: "_updateSegmentProportions", value: function _updateSegmentProportions() { var curLoc = 0; for (var i = 0; i < this.segments.length; i++) { var sl = this.segments[i].getLength(); this.segmentProportionalLengths[i] = sl / this.totalLength; this.segmentProportions[i] = [curLoc, curLoc += sl / this.totalLength]; } } }, { key: "_findSegmentForLocation", value: function _findSegmentForLocation(location, absolute) { var idx, i, inSegmentProportion; if (absolute) { location = location > 0 ? location / this.totalLength : (this.totalLength + location) / this.totalLength; } if (location === 1) { idx = this.segments.length - 1; inSegmentProportion = 1; } else if (location === 0) { inSegmentProportion = 0; idx = 0; } else { if (location >= 0.5) { idx = 0; inSegmentProportion = 0; for (i = this.segmentProportions.length - 1; i > -1; i--) { if (this.segmentProportions[i][1] >= location && this.segmentProportions[i][0] <= location) { idx = i; inSegmentProportion = (location - this.segmentProportions[i][0]) / this.segmentProportionalLengths[i]; break; } } } else { idx = this.segmentProportions.length - 1; inSegmentProportion = 1; for (i = 0; i < this.segmentProportions.length; i++) { if (this.segmentProportions[i][1] >= location) { idx = i; inSegmentProportion = (location - this.segmentProportions[i][0]) / this.segmentProportionalLengths[i]; break; } } } } return { segment: this.segments[idx], proportion: inSegmentProportion, index: idx }; } }, { key: "_addSegment", value: function _addSegment(clazz, params) { if (params.x1 === params.x2 && params.y1 === params.y2) { return; } var s = new clazz(params); this.segments.push(s); this.totalLength += s.getLength(); this.updateBounds(s); } }, { key: "_clearSegments", value: function _clearSegments() { this.totalLength = 0; this.segments.length = 0; this.segmentProportions.length = 0; this.segmentProportionalLengths.length = 0; } }, { key: "getLength", value: function getLength() { return this.totalLength; } }, { key: "_prepareCompute", value: function _prepareCompute(params) { this.strokeWidth = params.strokeWidth; var x1 = params.sourcePos.curX, x2 = params.targetPos.curX, y1 = params.sourcePos.curY, y2 = params.targetPos.curY, segment = util.quadrant({ x: x1, y: y1 }, { x: x2, y: y2 }), swapX = x2 < x1, swapY = y2 < y1, so = [params.sourcePos.ox, params.sourcePos.oy], to = [params.targetPos.ox, params.targetPos.oy], x = swapX ? x2 : x1, y = swapY ? y2 : y1, w = Math.abs(x2 - x1), h = Math.abs(y2 - y1); var noSourceOrientation = so[0] === 0 && so[1] === 0; var noTargetOrientation = to[0] === 0 && to[1] === 0; if (noSourceOrientation || noTargetOrientation) { var index = w > h ? 0 : 1, oIndex = [1, 0][index], v1 = index === 0 ? x1 : y1, v2 = index === 0 ? x2 : y2; if (noSourceOrientation) { so[index] = v1 > v2 ? -1 : 1; so[oIndex] = 0; } if (noTargetOrientation) { to[index] = v1 > v2 ? 1 : -1; to[oIndex] = 0; } } var sx = swapX ? w + this.sourceGap * so[0] : this.sourceGap * so[0], sy = swapY ? h + this.sourceGap * so[1] : this.sourceGap * so[1], tx = swapX ? this.targetGap * to[0] : w + this.targetGap * to[0], ty = swapY ? this.targetGap * to[1] : h + this.targetGap * to[1], oProduct = so[0] * to[0] + so[1] * to[1]; var result = { sx: sx, sy: sy, tx: tx, ty: ty, xSpan: Math.abs(tx - sx), ySpan: Math.abs(ty - sy), mx: (sx + tx) / 2, my: (sy + ty) / 2, so: so, to: to, x: x, y: y, w: w, h: h, segment: segment, startStubX: sx + so[0] * this.sourceStub, startStubY: sy + so[1] * this.sourceStub, endStubX: tx + to[0] * this.targetStub, endStubY: ty + to[1] * this.targetStub, isXGreaterThanStubTimes2: Math.abs(sx - tx) > this.sourceStub + this.targetStub, isYGreaterThanStubTimes2: Math.abs(sy - ty) > this.sourceStub + this.targetStub, opposite: oProduct === -1, perpendicular: oProduct === 0, orthogonal: oProduct === 1, sourceAxis: so[0] === 0 ? "y" : "x", points: [x, y, w, h, sx, sy, tx, ty], stubs: [this.sourceStub, this.targetStub] }; result.anchorOrientation = result.opposite ? "opposite" : result.orthogonal ? "orthogonal" : "perpendicular"; return result; } }, { key: "updateBounds", value: function updateBounds(segment) { var segBounds = segment.extents; this.bounds.xmin = Math.min(this.bounds.xmin, segBounds.xmin); this.bounds.xmax = Math.max(this.bounds.xmax, segBounds.xmax); this.bounds.ymin = Math.min(this.bounds.ymin, segBounds.ymin); this.bounds.ymax = Math.max(this.bounds.ymax, segBounds.ymax); } }, { key: "dumpSegmentsToConsole", value: function dumpSegmentsToConsole() { util.log("SEGMENTS:"); for (var i = 0; i < this.segments.length; i++) { util.log(this.segments[i].type, "" + this.segments[i].getLength(), "" + this.segmentProportions[i]); } } }, { key: "pointOnPath", value: function pointOnPath(location, absolute) { var seg = this._findSegmentForLocation(location, absolute); return seg.segment && seg.segment.pointOnPath(seg.proportion, false) || { x: 0, y: 0 }; } }, { key: "gradientAtPoint", value: function gradientAtPoint(location, absolute) { var seg = this._findSegmentForLocation(location, absolute); return seg.segment && seg.segment.gradientAtPoint(seg.proportion, false) || 0; } }, { key: "pointAlongPathFrom", value: function pointAlongPathFrom(location, distance, absolute) { var seg = this._findSegmentForLocation(location, absolute); return seg.segment && seg.segment.pointAlongPathFrom(seg.proportion, distance, false) || { x: 0, y: 0 }; } }, { key: "compute", value: function compute(params) { this.paintInfo = this._prepareCompute(params); this._clearSegments(); this._compute(this.paintInfo, params); this.x = this.paintInfo.points[0]; this.y = this.paintInfo.points[1]; this.w = this.paintInfo.points[2]; this.h = this.paintInfo.points[3]; this.segment = this.paintInfo.segment; this._updateSegmentProportions(); } }, { key: "setAnchorOrientation", value: function setAnchorOrientation(idx, orientation) {} }]); return AbstractConnector; }(); var StraightSegment = function (_AbstractSegment) { _inherits(StraightSegment, _AbstractSegment); var _super = _createSuper(StraightSegment); function StraightSegment(params) { var _this; _classCallCheck(this, StraightSegment); _this = _super.call(this, params); _defineProperty(_assertThisInitialized(_this), "length", void 0); _defineProperty(_assertThisInitialized(_this), "m", void 0); _defineProperty(_assertThisInitialized(_this), "m2", void 0); _defineProperty(_assertThisInitialized(_this), "type", StraightSegment.segmentType); _this._setCoordinates({ x1: params.x1, y1: params.y1, x2: params.x2, y2: params.y2 }); return _this; } _createClass(StraightSegment, [{ key: "getPath", value: function getPath(isFirstSegment) { return (isFirstSegment ? "M " + this.x1 + " " + this.y1 + " " : "") + "L " + this.x2 + " " + this.y2; } }, { key: "_recalc", value: function _recalc() { this.length = Math.sqrt(Math.pow(this.x2 - this.x1, 2) + Math.pow(this.y2 - this.y1, 2)); this.m = util.gradient({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }); this.m2 = -1 / this.m; this.extents = { xmin: Math.min(this.x1, this.x2), ymin: Math.min(this.y1, this.y2), xmax: Math.max(this.x1, this.x2), ymax: Math.max(this.y1, this.y2) }; } }, { key: "getLength", value: function getLength() { return this.length; } }, { key: "getGradient", value: function getGradient() { return this.m; } }, { key: "_setCoordinates", value: function _setCoordinates(coords) { this.x1 = coords.x1; this.y1 = coords.y1; this.x2 = coords.x2; this.y2 = coords.y2; this._recalc(); } }, { key: "pointOnPath", value: function pointOnPath(location, absolute) { if (location === 0 && !absolute) { return { x: this.x1, y: this.y1 }; } else if (location === 1 && !absolute) { return { x: this.x2, y: this.y2 }; } else { var l = absolute ? location > 0 ? location : this.length + location : location * this.length; return util.pointOnLine({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }, l); } } }, { key: "gradientAtPoint", value: function gradientAtPoint(location, absolute) { return this.m; } }, { key: "pointAlongPathFrom", value: function pointAlongPathFrom(location, distance, absolute) { var p = this.pointOnPath(location, absolute), farAwayPoint = distance <= 0 ? { x: this.x1, y: this.y1 } : { x: this.x2, y: this.y2 }; if (distance <= 0 && Math.abs(distance) > 1) { distance *= -1; } return util.pointOnLine(p, farAwayPoint, distance); } }, { key: "within", value: function within(a, b, c) { return c >= Math.min(a, b) && c <= Math.max(a, b); } }, { key: "closest", value: function closest(a, b, c) { return Math.abs(c - a) < Math.abs(c - b) ? a : b; } }, { key: "findClosestPointOnPath", value: function findClosestPointOnPath(x, y) { var out = { d: Infinity, x: null, y: null, l: null, x1: this.x1, x2: this.x2, y1: this.y1, y2: this.y2 }; if (this.m === 0) { out.y = this.y1; out.x = this.within(this.x1, this.x2, x) ? x : this.closest(this.x1, this.x2, x); } else if (this.m === Infinity || this.m === -Infinity) { out.x = this.x1; out.y = this.within(this.y1, this.y2, y) ? y : this.closest(this.y1, this.y2, y); } else { var b = this.y1 - this.m * this.x1, b2 = y - this.m2 * x, _x1 = (b2 - b) / (this.m - this.m2), _y1 = this.m * _x1 + b; out.x = this.within(this.x1, this.x2, _x1) ? _x1 : this.closest(this.x1, this.x2, _x1); out.y = this.within(this.y1, this.y2, _y1) ? _y1 : this.closest(this.y1, this.y2, _y1); } var fractionInSegment = util.lineLength({ x: out.x, y: out.y }, { x: this.x1, y: this.y1 }); out.d = util.lineLength({ x: x, y: y }, out); out.l = fractionInSegment / length; return out; } }, { key: "_pointLiesBetween", value: function _pointLiesBetween(q, p1, p2) { return p2 > p1 ? p1 <= q && q <= p2 : p1 >= q && q >= p2; } }, { key: "lineIntersection", value: function lineIntersection(_x1, _y1, _x2, _y2) { var m2 = Math.abs(util.gradient({ x: _x1, y: _y1 }, { x: _x2, y: _y2 })), m1 = Math.abs(this.m), b = m1 === Infinity ? this.x1 : this.y1 - m1 * this.x1, out = [], b2 = m2 === Infinity ? _x1 : _y1 - m2 * _x1; if (m2 !== m1) { if (m2 === Infinity && m1 === 0) { if (this._pointLiesBetween(_x1, this.x1, this.x2) && this._pointLiesBetween(this.y1, _y1, _y2)) { out.push({ x: _x1, y: this.y1 }); } } else if (m2 === 0 && m1 === Infinity) { if (this._pointLiesBetween(_y1, this.y1, this.y2) && this._pointLiesBetween(this.x1, _x1, _x2)) { out.push({ x: this.x1, y: _y1 }); } } else { var X, Y; if (m2 === Infinity) { X = _x1; if (this._pointLiesBetween(X, this.x1, this.x2)) { Y = m1 * _x1 + b; if (this._pointLiesBetween(Y, _y1, _y2)) { out.push({ x: X, y: Y }); } } } else if (m2 === 0) { Y = _y1; if (this._pointLiesBetween(Y, this.y1, this.y2)) { X = (_y1 - b) / m1; if (this._pointLiesBetween(X, _x1, _x2)) { out.push({ x: X, y: Y }); } } } else { X = (b2 - b) / (m1 - m2); Y = m1 * X + b; if (this._pointLiesBetween(X, this.x1, this.x2) && this._pointLiesBetween(Y, this.y1, this.y2)) { out.push({ x: X, y: Y }); } } } } return out; } }, { key: "boxIntersection", value: function boxIntersection(x, y, w, h) { var a = []; a.push.apply(a, this.lineIntersection(x, y, x + w, y)); a.push.apply(a, this.lineIntersection(x + w, y, x + w, y + h)); a.push.apply(a, this.lineIntersection(x + w, y + h, x, y + h)); a.push.apply(a, this.lineIntersection(x, y + h, x, y)); return a; } }]); return StraightSegment; }(common.AbstractSegment); _defineProperty(StraightSegment, "segmentType", "Straight"); var StraightConnector = function (_AbstractConnector) { _inherits(StraightConnector, _AbstractConnector); var _super = _createSuper(StraightConnector); function StraightConnector() { var _this; _classCallCheck(this, StraightConnector); for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _super.call.apply(_super, [this].concat(args)); _defineProperty(_assertThisInitialized(_this), "type", StraightConnector.type); return _this; } _createClass(StraightConnector, [{ key: "getDefaultStubs", value: function getDefaultStubs() { return [0, 0]; } }, { key: "_compute", value: function _compute(paintInfo, p) { this._addSegment(StraightSegment, { x1: paintInfo.sx, y1: paintInfo.sy, x2: paintInfo.startStubX, y2: paintInfo.startStubY }); this._addSegment(StraightSegment, { x1: paintInfo.startStubX, y1: paintInfo.startStubY, x2: paintInfo.endStubX, y2: paintInfo.endStubY }); this._addSegment(StraightSegment, { x1: paintInfo.endStubX, y1: paintInfo.endStubY, x2: paintInfo.tx, y2: paintInfo.ty }); this.geometry = { source: p.sourcePos, target: p.targetPos }; } }, { key: "transformGeometry", value: function transformGeometry(g, dx, dy) { return { source: this.transformAnchorPlacement(g.source, dx, dy), target: this.transformAnchorPlacement(g.target, dx, dy) }; } }]); return StraightConnector; }(AbstractConnector); _defineProperty(StraightConnector, "type", "Straight"); var connectorMap = {}; var Connectors = { get: function get(connection, name, params) { var c = connectorMap[name]; if (!c) { throw { message: "jsPlumb: unknown connector type '" + name + "'" }; } else { return new c(connection, params); } }, register: function register(name, conn) { connectorMap[name] = conn; } }; function cls() { for (var _len = arguments.length, className = new Array(_len), _key = 0; _key < _len; _key++) { className[_key] = arguments[_key]; } return className.map(function (cn) { return "." + cn; }).join(","); } function classList() { for (var _len2 = arguments.length, className = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { className[_key2] = arguments[_key2]; } return className.join(" "); } function att() { for (var _len3 = arguments.length, attName = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { attName[_key3] = arguments[_key3]; } return attName.map(function (an) { return "[" + an + "]"; }).join(","); } var SOURCE = "source"; var TARGET = "target"; var BLOCK = "block"; var NONE = "none"; var SOURCE_INDEX = 0; var TARGET_INDEX = 1; var ABSOLUTE = "absolute"; var FIXED = "fixed"; var STATIC = "static"; var ATTRIBUTE_GROUP = "data-jtk-group"; var ATTRIBUTE_MANAGED = "data-jtk-managed"; var ATTRIBUTE_NOT_DRAGGABLE = "data-jtk-not-draggable"; var ATTRIBUTE_TABINDEX = "tabindex"; var ATTRIBUTE_SCOPE = "data-jtk-scope"; var ATTRIBUTE_SCOPE_PREFIX = ATTRIBUTE_SCOPE + "-"; var CHECK_CONDITION = "checkCondition"; var CHECK_DROP_ALLOWED = "checkDropAllowed"; var CLASS_CONNECTOR = "jtk-connector"; var CLASS_CONNECTOR_OUTLINE = "jtk-connector-outline"; var CLASS_CONNECTED = "jtk-connected"; var CLASS_ENDPOINT = "jtk-endpoint"; var CLASS_ENDPOINT_CONNECTED = "jtk-endpoint-connected"; var CLASS_ENDPOINT_FULL = "jtk-endpoint-full"; var CLASS_ENDPOINT_FLOATING = "jtk-floating-endpoint"; var CLASS_ENDPOINT_DROP_ALLOWED = "jtk-endpoint-drop-allowed"; var CLASS_ENDPOINT_DROP_FORBIDDEN = "jtk-endpoint-drop-forbidden"; var CLASS_ENDPOINT_ANCHOR_PREFIX = "jtk-endpoint-anchor"; var CLASS_GROUP_COLLAPSED = "jtk-group-collapsed"; var CLASS_GROUP_EXPANDED = "jtk-group-expanded"; var CLASS_OVERLAY = "jtk-overlay"; var EVENT_ANCHOR_CHANGED = "anchor:changed"; var EVENT_CONNECTION = "connection"; var EVENT_INTERNAL_CONNECTION = "internal.connection"; var EVENT_CONNECTION_DETACHED = "connection:detach"; var EVENT_CONNECTION_MOVED = "connection:move"; var EVENT_CONTAINER_CHANGE = "container:change"; var EVENT_ENDPOINT_REPLACED = "endpoint:replaced"; var EVENT_INTERNAL_ENDPOINT_UNREGISTERED = "internal.endpoint:unregistered"; var EVENT_INTERNAL_CONNECTION_DETACHED = "internal.connection:detached"; var EVENT_MANAGE_ELEMENT = "element:manage"; var EVENT_GROUP_ADDED = "group:added"; var EVENT_GROUP_COLLAPSE = "group:collapse"; var EVENT_GROUP_EXPAND = "group:expand"; var EVENT_GROUP_MEMBER_ADDED = "group:member:added"; var EVENT_GROUP_MEMBER_REMOVED = "group:member:removed"; var EVENT_GROUP_REMOVED = "group:removed"; var EVENT_MAX_CONNECTIONS = "maxConnections"; var EVENT_NESTED_GROUP_ADDED = "group:nested:added"; var EVENT_NESTED_GROUP_REMOVED = "group:nested:removed"; var EVENT_UNMANAGE_ELEMENT = "element:unmanage"; var EVENT_ZOOM = "zoom"; var IS_DETACH_ALLOWED = "isDetachAllowed"; var INTERCEPT_BEFORE_DRAG = "beforeDrag"; var INTERCEPT_BEFORE_DROP = "beforeDrop"; var INTERCEPT_BEFORE_DETACH = "beforeDetach"; var INTERCEPT_BEFORE_START_DETACH = "beforeStartDetach"; var SELECTOR_MANAGED_ELEMENT = att(ATTRIBUTE_MANAGED); var ERROR_SOURCE_ENDPOINT_FULL = "Cannot establish connection: source endpoint is full"; var ERROR_TARGET_ENDPOINT_FULL = "Cannot establish connection: target endpoint is full"; var ERROR_SOURCE_DOES_NOT_EXIST = "Cannot establish connection: source does not exist"; var ERROR_TARGET_DOES_NOT_EXIST = "Cannot establish connection: target does not exist"; var KEY_CONNECTION_OVERLAYS = "connectionOverlays"; var DEFAULT_KEY_ALLOW_NESTED_GROUPS = "allowNestedGroups"; var DEFAULT_KEY_ANCHOR = "anchor"; var DEFAULT_KEY_ANCHORS = "anchors"; var DEFAULT_KEY_CONNECTION_OVERLAYS = "connectionOverlays"; var DEFAULT_KEY_CONNECTIONS_DETACHABLE = "connectionsDetachable"; var DEFAULT_KEY_CONNECTOR = "connector"; var DEFAULT_KEY_CONTAINER = "container"; var DEFAULT_KEY_ENDPOINT = "endpoint"; var DEFAULT_KEY_ENDPOINT_OVERLAYS = "endpointOverlays"; var DEFAULT_KEY_ENDPOINTS = "endpoints"; var DEFAULT_KEY_ENDPOINT_STYLE = "endpointStyle"; var DEFAULT_KEY_ENDPOINT_STYLES = "endpointStyles"; var DEFAULT_KEY_ENDPOINT_HOVER_STYLE = "endpointHoverStyle"; var DEFAULT_KEY_ENDPOINT_HOVER_STYLES = "endpointHoverStyles"; var DEFAULT_KEY_HOVER_CLASS = "hoverClass"; var DEFAULT_KEY_HOVER_PAINT_STYLE = "hoverPaintStyle"; var DEFAULT_KEY_LIST_STYLE = "listStyle"; var DEFAULT_KEY_MAX_CONNECTIONS = "maxConnections"; var DEFAULT_KEY_PAINT_STYLE = "paintStyle"; var DEFAULT_KEY_REATTACH_CONNECTIONS = "reattachConnections"; var DEFAULT_KEY_SCOPE = "scope"; function isFullOverlaySpec(o) { return o.type != null && o.options != null; } function convertToFullOverlaySpec(spec) { var o = null; if (util.isString(spec)) { o = { type: spec, options: {} }; } else { o = spec; } o.options.id = o.options.id || util.uuid(); return o; } var Overlay = function (_EventGenerator) { _inherits(Overlay, _EventGenerator); var _super = _createSuper(Overlay); function Overlay(instance, component, p) { var _this; _classCallCheck(this, Overlay); _this = _super.call(this); _this.instance = instance; _this.component = component; _defineProperty(_assertThisInitialized(_this), "id", void 0); _defineProperty(_assertThisInitialized(_this), "type", void 0); _defineProperty(_assertThisInitialized(_this), "cssClass", void 0); _defineProperty(_assertThisInitialized(_this), "visible", true); _defineProperty(_assertThisInitialized(_this), "location", void 0); _defineProperty(_assertThisInitialized(_this), "events", void 0); _defineProperty(_assertThisInitialized(_this), "attributes", void 0); p = p || {}; _this.id = p.id || util.uuid(); _this.cssClass = p.cssClass || ""; _this.setLocation(p.location); _this.events = p.events || {}; _this.attributes = p.attributes || {}; for (var _event in _this.events) { _this.bind(_event, _this.events[_event]); } return _this; } _createClass(Overlay, [{ key: "setLocation", value: function setLocation(l) { var newLocation = this.location == null ? 0.5 : this.location; if (l != null) { try { var _l = typeof l === "string" ? parseFloat(l) : l; if (!isNaN(_l)) { newLocation = _l; } } catch (e) { } } this.location = newLocation; } }, { key: "shouldFireEvent", value: function shouldFireEvent(event, value, originalEvent) { return true; } }, { key: "setVisible", value: function setVisible(v) { this.visible = v; this.instance.setOverlayVisible(this, v); } }, { key: "isVisible", value: function isVisible() { return this.visible; } }]); return Overlay; }(util.EventGenerator); var overlayMap = {}; var OverlayFactory = { get: function get(instance, name, component, params) { var c = overlayMap[name]; if (!c) { throw { message: "jsPlumb: unknown overlay type '" + name + "'" }; } else { return new c(instance, component, params); } }, register: function register(name, overlay) { overlayMap[name] = overlay; } }; var LabelOverlay = function (_Overlay) { _inherits(LabelOverlay, _Overlay); var _super = _createSuper(LabelOverlay); function LabelOverlay(instance, component, p) { var _this; _classCallCheck(this, LabelOverlay); _this = _super.call(this, instance, component, p); _this.instance = instance; _this.component = component; _defineProperty(_assertThisInitialized(_this), "label", void 0); _defineProperty(_assertThisInitialized(_this), "labelText", void 0); _defineProperty(_assertThisInitialized(_this), "type", LabelOverlay.type); _defineProperty(_assertThisInitialized(_this), "cachedDimensions", void 0); p = p || { label: "" }; _this.setLabel(p.label); return _this; } _createClass(LabelOverlay, [{ key: "getLabel", value: function getLabel() { if (util.isFunction(this.label)) { return this.label(this); } else { return this.labelText; } } }, { key: "setLabel", value: function setLabel(l) { this.label = l; this.labelText = null; this.instance.updateLabel(this); } }, { key: "getDimensions", value: function getDimensions() { return { w: 1, h: 1 }; } }, { key: "updateFrom", value: function updateFrom(d) { if (d.label != null) { this.setLabel(d.label); } if (d.location != null) { this.setLocation(d.location); this.instance.updateLabel(this); } } }]); return LabelOverlay; }(Overlay); _defineProperty(LabelOverlay, "type", "Label"); function isLabelOverlay(o) { return o.type === LabelOverlay.type; } OverlayFactory.register(LabelOverlay.type, LabelOverlay); function _splitType(t) { return t == null ? null : t.split(" ").filter(function (t) { return t != null && t.length > 0; }); } function _mapType(map, obj, typeId) { for (var i in obj) { map[i] = typeId; } } var CONNECTOR = "connector"; var MERGE_STRATEGY_OVERRIDE = "override"; var CSS_CLASS = "cssClass"; var DEFAULT_TYPE_KEY = "__default"; var ANCHOR = "anchor"; var ANCHORS = "anchors"; var _internalLabelOverlayId = "__label"; var _internalLabelOverlayClass = "jtk-default-label"; var TYPE_ITEM_OVERLAY = "overlay"; var LOCATION_ATTRIBUTE = "labelLocation"; var ACTION_ADD = "add"; var ACTION_REMOVE = "remove"; function _applyTypes(component, params) { if (component.getDefaultType) { var td = component.getTypeDescriptor(), map = {}; var defType = component.getDefaultType(); var o = util.extend({}, defType); _mapType(map, defType, DEFAULT_TYPE_KEY); component._types.forEach(function (tid) { if (tid !== DEFAULT_TYPE_KEY) { var _t = component.instance.getType(tid, td); if (_t != null) { var overrides = new Set([CONNECTOR, ANCHOR, ANCHORS]); if (_t.mergeStrategy === MERGE_STRATEGY_OVERRIDE) { for (var k in _t) { overrides.add(k); } } o = util.merge(o, _t, [CSS_CLASS], util.setToArray(overrides)); _mapType(map, _t, tid); } } }); if (params) { o = util.populate(o, params, "_"); } component.applyType(o, map); } } function _removeTypeCssHelper(component, typeId) { var type = component.instance.getType(typeId, component.getTypeDescriptor()); if (type != null && type.cssClass) { component.removeClass(type.cssClass); } } function _updateHoverStyle(component) { if (component.paintStyle && component.hoverPaintStyle) { var mergedHoverStyle = {}; util.extend(mergedHoverStyle, component.paintStyle); util.extend(mergedHoverStyle, component.hoverPaintStyle); component.hoverPaintStyle = mergedHoverStyle; } } var ADD_CLASS_ACTION = "add"; var REMOVE_CLASS_ACTION = "remove"; function _makeLabelOverlay(component, params) { var _params = { cssClass: params.cssClass, id: _internalLabelOverlayId, component: component }, mergedParams = util.extend(_params, params); return new LabelOverlay(component.instance, component, mergedParams); } function _processOverlay(component, o) { var _newOverlay = null; if (util.isString(o)) { _newOverlay = OverlayFactory.get(component.instance, o, component, {}); } else if (o.type != null && o.options != null) { var oa = o; var p = util.extend({}, oa.options); _newOverlay = OverlayFactory.get(component.instance, oa.type, component, p); } else { _newOverlay = o; } _newOverlay.id = _newOverlay.id || util.uuid(); component.cacheTypeItem(TYPE_ITEM_OVERLAY, _newOverlay, _newOverlay.id); component.overlays[_newOverlay.id] = _newOverlay; return _newOverlay; } var Component = function (_EventGenerator) { _inherits(Component, _EventGenerator); var _super = _createSuper(Component); function Component(instance, params) { var _this; _classCallCheck(this, Component); _this = _super.call(this); _this.instance = instance; _defineProperty(_assertThisInitialized(_this), "defaultLabelLocation", 0.5); _defineProperty(_assertThisInitialized(_this), "overlays", {}); _defineProperty(_assertThisInitialized(_this), "overlayPositions", {}); _defineProperty(_assertThisInitialized(_this), "overlayPlacements", {}); _definePro