UNPKG

butterfly-dag

Version:

一个基于数据驱动的节点式编排组件库,让你有方便快捷定制可视化流程图表

1,939 lines (1,591 loc) 388 kB
import _$d from 'lodash'; import d3Force from 'd3-force'; import dagre from 'dagre'; import { Matrix, SingularValueDecomposition } from 'ml-matrix'; import '@antv/matrix-util'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; } else { _typeof = function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 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 && (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."); } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function () {}; return { s: F, n: function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function (e) { throw e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function () { it = it.call(o); }, n: function () { var step = it.next(); normalCompletion = step.done; return step; }, e: function (e) { didErr = true; err = e; }, f: function () { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; } var EventEmit3$4 = require('eventemitter3'); var Canvas = /*#__PURE__*/function (_EventEmit) { _inherits(Canvas, _EventEmit); var _super = _createSuper(Canvas); function Canvas() { _classCallCheck(this, Canvas); // root 根节点 // layout 布局支持 // zoomable 是否可放大缩小 // moveable 是否可移动 // draggable 是否可拖动节点 // linkable 是否可连接线条 // disLinkable 是否可取消连线 // theme 主题配置 // global 公共配置 return _super.call(this); } // 渲染节点 _createClass(Canvas, [{ key: "draw", value: function draw() {} // 获取节点 }, { key: "getNode", value: function getNode() {} // 获取线条 }, { key: "getEdge", value: function getEdge() {} // 获取节点组 }, { key: "getGroup", value: function getGroup() {} // 添加节点 }, { key: "addNode", value: function addNode() {} // 批量添加节点 }, { key: "addNodes", value: function addNodes() {} // 添加线条 }, { key: "addEdge", value: function addEdge() {} // 批量添加线条 }, { key: "addEdges", value: function addEdges() {} // 批量添加节点组 }, { key: "addGroups", value: function addGroups() {} // 删除节点 }, { key: "removeNode", value: function removeNode() {} // 批量删除节点 }, { key: "removeNodes", value: function removeNodes() {} // 删除线条 }, { key: "removeEdge", value: function removeEdge() {} // 批量删除线条 }, { key: "removeEdges", value: function removeEdges() {} // 删除节点组 }, { key: "removeGroup", value: function removeGroup() {} // 获取相邻的线条 }, { key: "getNeighborEdges", value: function getNeighborEdges() {} // 获取相邻的节点 }, { key: "getNeighborNodes", value: function getNeighborNodes() {} // 获取无环血缘图 }, { key: "getNeighborNodesAndEdgesByLevel", value: function getNeighborNodesAndEdgesByLevel() {} }, { key: "getAdjcentTable", value: function getAdjcentTable() {} // 需要改为内部方法 // 获取缩放值 }, { key: "getZoom", value: function getZoom() {} // 动态设置可缩放 }, { key: "setZoomable", value: function setZoomable() {} // 动态设置缩放值 }, { key: "zoom", value: function zoom() {} // 获取偏移值 }, { key: "getOffset", value: function getOffset() {} // 动态设置可移动 }, { key: "setMoveable", value: function setMoveable() {} // 动态设置移动 }, { key: "move", value: function move() {} // 获取中心点 }, { key: "getOrigin", value: function getOrigin() {} // 动态设置中心点 }, { key: "setOrigin", value: function setOrigin() {} // 获取数据结构 }, { key: "getDataMap", value: function getDataMap() {} // 设置网格模式 }, { key: "setGirdMode", value: function setGirdMode() {} // 设置网格线条 }, { key: "setGuideLine", value: function setGuideLine() {} // 设置辅助线 }, { key: "justifyCoordinate", value: function justifyCoordinate() {} // 设置框选模式 }, { key: "setSelectMode", value: function setSelectMode() {} // 设置某些联合值,即框选的元素 }, { key: "getUnion", value: function getUnion() {} // 设置所有联合值,即框选的元素 }, { key: "getAllUnion", value: function getAllUnion() {} // 添加联合值 }, { key: "add2Union", value: function add2Union() {} // 删除某些联合值 }, { key: "removeUnion", value: function removeUnion() {} // 删除所有联合值 }, { key: "removeAllUnion", value: function removeAllUnion() {} // 聚焦单个节点(看看需要合并不) }, { key: "focusNodeWithAnimate", value: function focusNodeWithAnimate() {} // 聚焦某些节点 }, { key: "focusNodesWithAnimate", value: function focusNodesWithAnimate() {} // 画布坐标转换为终端坐标 }, { key: "canvas2terminal", value: function canvas2terminal() {} // 终端坐标转换为画布坐标 }, { key: "terminal2canvas", value: function terminal2canvas() {} // 保存为图片 }, { key: "save2img", value: function save2img() {} // ********* 需要优化的api ********* // 更新画布的大小 }, { key: "updateRootResize", value: function updateRootResize() {} // ********* 需要新增的api ********* // 单击的回调 }, { key: "click", value: function click() {} // 双击的回调 }, { key: "doubleClick", value: function doubleClick() {} // 右键的回调 }, { key: "onContextmenu", value: function onContextmenu() {} // 集成menu // 生成/关闭缩略图 }]); return Canvas; }(EventEmit3$4); var EventEmit3$3 = require('eventemitter3'); var Node = /*#__PURE__*/function (_EventEmit) { _inherits(Node, _EventEmit); var _super = _createSuper(Node); function Node() { _classCallCheck(this, Node); // id 节点唯一标志 // top 坐标y // left 坐标x // group 存在于哪个节点组上 // dom 节点的dom元素 // draggable 该节点是否能拖动标志,可覆盖全局的 // options 数据的透传 // _on 节点发送事件 // _emit 节点发送事件 // _global 全局的配置 // 需要优化的 // scope scope相同可拉进group里面 // endpoints endpoint对象 // _endpointsData 真实的endpoint数据 // _isMoving 标识是否在移动做,兼容冒泡 return _super.call(this); } // 渲染节点 _createClass(Node, [{ key: "draw", value: function draw() {} // 获取锚点 }, { key: "getEndpoint", value: function getEndpoint() {} // 添加锚点 }, { key: "addEndpoint", value: function addEndpoint() {} // 删除锚点 }, { key: "removeEndpoint", value: function removeEndpoint() {} // 移动节点 }, { key: "moveTo", value: function moveTo() {} // 获取宽度 }, { key: "getWidth", value: function getWidth() {} // 获取高度 }, { key: "getHeight", value: function getHeight() {} // 设置该节点是否能拖动,能覆盖全局 }, { key: "setDraggable", value: function setDraggable() {} // remove的方法 }, { key: "remove", value: function remove() {} // 销毁的方法 }, { key: "destroy", value: function destroy() {} // ********* 需要新增的api ********* // focus回调 }, { key: "focus", value: function focus() {} // unFocus回调 }, { key: "unFocus", value: function unFocus() {} // 单击的回调 }, { key: "click", value: function click() {} // 双击的回调 }, { key: "doubleClick", value: function doubleClick() {} // 右键的回调 }, { key: "onContextmenu", value: function onContextmenu() {} // hover的回调 }, { key: "hover", value: function hover() {} }]); return Node; }(EventEmit3$3); var EventEmit3$2 = require('eventemitter3'); var Endpoint = /*#__PURE__*/function (_EventEmit) { _inherits(Endpoint, _EventEmit); var _super = _createSuper(Endpoint); function Endpoint() { _classCallCheck(this, Endpoint); return _super.call(this); } return Endpoint; }(EventEmit3$2); var $$a = require('jquery'); var _$c = require('lodash'); var BaseEndpoint = /*#__PURE__*/function (_Endpoint) { _inherits(BaseEndpoint, _Endpoint); var _super = _createSuper(BaseEndpoint); function BaseEndpoint(opts) { var _this; _classCallCheck(this, BaseEndpoint); _this = _super.call(this, opts); _this.id = opts.id; _this.options = opts; _this.orientation = opts.orientation; _this.pos = opts.pos; _this.type = opts.type; _this.nodeType = _$c.get(opts, 'nodeType', 'node'); _this.nodeId = _$c.get(opts, '_node.id'); _this.root = opts.root; _this.scope = opts.scope; _this.expandArea = opts.expandArea; _this.limitNum = opts.limitNum; // 已连接数 _this.connectedNum = 0; _this.options = opts; // 鸭子辨识手动判断类型 _this.__type = 'endpoint'; // 假如锚点在节点上则有值 _this._node = opts._node; _this._global = opts._global; _this._on = opts._on; _this._emit = opts._emit; // 相对坐标 _this._top = 0; _this._left = 0; // 相对于画布的绝对坐标 _this._posTop = 0; _this._posLeft = 0; _this._width = 0; _this._height = 0; // 拉线时候可连接的标志 _this._linkable = false; _this._coordinateService = null; _this.dom = null; // 判断自定义锚点 _this._isInitedDom = false; if (opts.dom) { _this.dom = opts.dom; _this._isInitedDom = true; } return _this; } _createClass(BaseEndpoint, [{ key: "_init", value: function _init(obj) { this._coordinateService = obj._coordinateService; if (obj.nodeType) { this.nodeType = obj.nodeType; } // 计算锚点起始值 if (!this._isInitedDom) { this.dom = this.draw({ id: this.id, orientation: this.orientation, pos: this.pos, dom: this.dom, root: this.root, type: this.type, options: this.options }); } else { // 计算width,height,left,top this._width = $$a(this.dom).outerWidth(); this._height = $$a(this.dom).outerHeight(); this._left = this._coordinateService._terminal2canvas('x', $$a(this.dom).offset().left + this._coordinateService.scrollLeft); this._top = this._coordinateService._terminal2canvas('y', $$a(this.dom).offset().top + this._coordinateService.scrollTop); this._posTop = this._top; this._posLeft = this._left; } this.attachEvent(); } }, { key: "draw", value: function draw(obj) { var _dom = obj.dom; if (!_dom) { _dom = $$a('<div class="butterflie-circle-endpoint"></div>').attr('id', this.id); } else { _dom = $$a(_dom); } return _dom[0]; } }, { key: "updatePos", value: function updatePos() { var dom = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.dom; var orientation = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.orientation; var pos = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.pos; if (this._isInitedDom) { // 计算width,height,left,top this._width = $$a(this.dom).outerWidth(); this._height = $$a(this.dom).outerHeight(); // 计算锚点起始值 this._left = this._coordinateService._terminal2canvas('x', $$a(this.dom).offset().left + this._coordinateService.scrollLeft); this._top = this._coordinateService._terminal2canvas('y', $$a(this.dom).offset().top + this._coordinateService.scrollTop); this._posLeft = this._left; this._posTop = this._top; } else { var _currentNode = this._node; var _currentDom = $$a(this._node.dom); this.nodeType; // 分情况弄好方向和位置 var nodeW = _currentDom.outerWidth(); var nodeH = _currentDom.outerHeight(); var targetDom = null; var targetDomW = 0; var targetDomH = 0; if (this.root) { targetDom = _currentDom.find(this.root); targetDomW = targetDom.width(); targetDomH = targetDom.height(); } this._width = $$a(dom).outerWidth(); this._height = $$a(dom).outerHeight(); // 计算节点本身的偏移量 var eOffsetX = this._width / 2; var eOffsetY = this._height / 2; var _offsetTop = 0; var _offsetLeft = 0; var _orientation = orientation || this.orientation || [0, -1]; var _pos = pos || this.pos || [_orientation[0] === 0 ? 0.5 : 0, _orientation[1] === 0 ? 0.5 : 0]; var result = [0, 0]; var _ox = _orientation[0]; var _oy = _orientation[1]; var _px = _pos[0]; var _py = _pos[1]; if (_ox === 0) { result[0] = !this.root ? nodeW * _px - eOffsetX : targetDomW * _px - eOffsetX; } else if (_ox === -1) { result[0] = 0 - eOffsetX; } else if (_ox === 1) { result[0] = !this.root ? nodeW - eOffsetX : targetDomW - eOffsetX; } if (_oy === 0) { result[1] = !this.root ? nodeH * _py - eOffsetY : targetDomH * _py - eOffsetY; } else if (_oy === -1) { result[1] = 0 - eOffsetY; } else if (_oy === 1) { result[1] = !this.root ? nodeH - eOffsetY : targetDomH - eOffsetY; } // 计算绝对定位 if (_currentNode && !this.root) { _offsetTop += _currentNode.top; _offsetLeft += _currentNode.left; } else if (_currentNode && this.root) { // 计算传入的dom距离跟节点 var nodeDomOffsets = _currentDom.offset(); var targetDomOffsets = targetDom.offset(); // 先计算目标节点和父节点得差值再加上父节点的offset _offsetTop += targetDomOffsets.top - nodeDomOffsets.top + _currentNode.top; _offsetLeft += targetDomOffsets.left - nodeDomOffsets.left + _currentNode.left; } this._top = result[1] + _offsetTop; this._left = result[0] + _offsetLeft; this._posTop = this._top; this._posLeft = this._left; if (_currentNode._group) { var _groupPos = this._getGroupPos(_currentNode._group); this._posTop += _groupPos.top; this._posLeft += _groupPos.left; } $$a(dom).css('top', this._top).css('left', this._left); this.updated && this.updated(); } this.emit('InnerEvents', { type: 'endpoint:updatePos', point: this }); } }, { key: "_getGroupPos", value: function _getGroupPos(group) { var targetGroup = group; var top = 0; var left = 0; while (targetGroup) { top += targetGroup.top; left += targetGroup.left; targetGroup = targetGroup._group; } return { top: top, left: left }; } }, { key: "hasConnection", value: function hasConnection() { return this.connectedNum > 0; } }, { key: "moveTo", value: function moveTo(x, y) { this._top = y; this._left = x; this._posTop = this._top; this._posLeft = this._left; if (!this._isInitedDom) { $$a(this.dom).css('top', y).css('left', x); if (_$c.get(this, '_node._group')) { this._posTop += this._node._group.top; this._posLeft += this._node._group.left; } } } }, { key: "linkable", value: function linkable() { $$a(this.dom).addClass('linkable'); } }, { key: "unLinkable", value: function unLinkable() { $$a(this.dom).removeClass('linkable'); } }, { key: "hoverLinkable", value: function hoverLinkable() { $$a(this.dom).addClass('hover'); } }, { key: "unHoverLinkable", value: function unHoverLinkable() { $$a(this.dom).removeClass('hover'); } }, { key: "attachEvent", value: function attachEvent() { var _this2 = this; $$a(this.dom).on('mousedown', function (e) { var LEFT_KEY = 0; if (e.button !== LEFT_KEY) { return; } e.preventDefault(); e.stopPropagation(); _this2.emit('InnerEvents', { type: 'endpoint:drag', data: _this2 }); }); } }, { key: "emit", value: function emit(type, data) { _get(_getPrototypeOf(BaseEndpoint.prototype), "emit", this).call(this, type, data); this._emit(type, data); } }, { key: "destroy", value: function destroy(isNotEvent) { if (!isNotEvent) { $$a(this.dom).off(); $$a(this.dom).remove(); this.removeAllListeners(); } else { $$a(this.dom).detach(); } } }]); return BaseEndpoint; }(Endpoint); var $$9 = require('jquery'); var _$b = require('lodash'); var BaseNode = /*#__PURE__*/function (_Node) { _inherits(BaseNode, _Node); var _super = _createSuper(BaseNode); function BaseNode(opts) { var _this; _classCallCheck(this, BaseNode); _this = _super.call(this, opts); _this.id = opts.id; _this.scope = opts.scope; _this.group = opts.group; _this.top = opts.top || 0; _this.left = opts.left || 0; _this.dom = opts.dom || null; _this.draggable = opts.draggable; _this.options = opts; // 鸭子辨识手动判断类型 _this.__type = 'node'; _this._on = opts._on; _this._emit = opts._emit; _this._global = opts._global; // endpoint 这部分需要考虑 _this.endpoints = []; _this._endpointsData = opts.endpoints; _this._endpointLimitNum = opts._endpointLimitNum; // 标识是否在移动做,兼容冒泡 _this._isMoving = false; // 长宽 _this.width = undefined; _this.height = undefined; _this._isForceUpdateSize = false; return _this; } _createClass(BaseNode, [{ key: "draw", value: function draw(obj) { var _dom = obj.dom; if (!_dom) { _dom = $$9('<div></div>').attr('class', 'node').attr('id', obj.id); } var node = $$9(_dom); if (obj.top !== undefined) { node.css('top', "".concat(obj.top, "px")); } if (obj.left !== undefined) { node.css('left', "".concat(obj.left, "px")); } this.updated && this.updated(); return node[0]; } }, { key: "focus", value: function focus() {} }, { key: "unFocus", value: function unFocus() {} }, { key: "addEndpoint", value: function addEndpoint(obj, isInited) { if (isInited) { this.emit('InnerEvents', { type: 'node:addEndpoint', data: obj, isInited: isInited }); return obj; } // 这部分可能还需要想一下 var EndpointClass = obj.Class || BaseEndpoint; var endpoint = new EndpointClass(_$b.assign({ limitNum: obj.limitNum || this._endpointLimitNum, _on: this._on, _emit: this._emit, _node: this, _global: this.global }, obj)); this.emit('InnerEvents', { type: 'node:addEndpoint', data: endpoint }); this.endpoints.push(endpoint); return endpoint; } }, { key: "removeEndpoint", value: function removeEndpoint(pointId) { var rmEndpointIndex = _$b.findIndex(this.endpoints, function (point) { return point.id === pointId; }); if (rmEndpointIndex !== -1) { var rmEndpoint = this.endpoints.splice(rmEndpointIndex, 1)[0]; this.emit('InnerEvents', { type: 'node:removeEndpoint', data: rmEndpoint }); rmEndpoint.destroy(); return rmEndpoint; } } }, { key: "getEndpoint", value: function getEndpoint(pointId, type) { return _$b.find(this.endpoints, function (point) { if (!point.type || point.type === 'onlyConnect') { return pointId === point.id; } else { return pointId === point.id && (type && type === point.type || !type); } }); } }, { key: "_init", value: function _init() { var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; if (this._isInited) { return; } // 这里可以抽象下,和constructor对比 if (obj.left) { this.left = obj.left; } if (obj.top) { this.top = obj.top; } if (obj._isDeleteGroup) { this.group = undefined; this._group = undefined; } else { obj.group && (this.group = obj.group); } delete obj._isDeleteGroup; this._isInited = true; if (obj.dom) { this.dom = obj.dom; obj.left && $$9(this.dom).css('left', "".concat(obj.left, "px")); obj.top && $$9(this.dom).css('top', "".concat(obj.top, "px")); } else { this.dom = this.draw(_$b.assign({ id: this.id, top: this.top, left: this.left, dom: this.dom, options: this.options }, obj)); } if (!this._hasEventListener) { this._addEventListener(); this._hasEventListener = true; } } // drag的时候移动的api }, { key: "_moveTo", value: function _moveTo(x, y) { var _this2 = this; // 自身移动 $$9(this.dom).css('top', y).css('left', x); // 所在的点移动 this.endpoints.forEach(function (item) { item.moveTo(x - _this2.left + item._left, y - _this2.top + item._top); }); this.top = y; this.left = x; } }, { key: "moveTo", value: function moveTo(x, y, isNotEventEmit) { this.emit('InnerEvents', { type: 'node:move', node: this, x: x, y: y, isNotEventEmit: isNotEventEmit }); } }, { key: "getWidth", value: function getWidth(useCache) { if (!useCache || !this.width || this._isForceUpdateSize) { this.width = $$9(this.dom).outerWidth(); this._isForceUpdateSize = false; } return this.width; } }, { key: "getHeight", value: function getHeight(useCache) { if (!useCache || !this.height || this._isForceUpdateSize) { this.height = $$9(this.dom).outerHeight(); this._isForceUpdateSize = false; } return this.height; } }, { key: "_createEndpoint", value: function _createEndpoint(isInited) { var _this3 = this; if (isInited) { this.endpoints.forEach(function (item) { return _this3.addEndpoint(item, isInited); }); } else if (this._endpointsData) { this._endpointsData.map(function (item) { return _this3.addEndpoint(item); }); } } }, { key: "_addEventListener", value: function _addEventListener() { var _this4 = this; // todo 做事件代理的形式 $$9(this.dom).on('mousedown', function (e) { var LEFT_KEY = 0; if (e.button !== LEFT_KEY) { return; } if (!['SELECT', 'INPUT', 'RADIO', 'CHECKBOX', 'TEXTAREA'].includes(e.target.nodeName)) { e.preventDefault(); } if (_this4.draggable) { _this4._isMoving = true; _this4.emit('InnerEvents', { type: 'node:dragBegin', data: _this4 }); } else { // 单纯为了抛错事件给canvas,为了让canvas的dragtype不为空,不会触发canvas:click事件 _this4.emit('InnerEvents', { type: 'node:mouseDown', data: _this4 }); } }); $$9(this.dom).on('click', function (e) { e.preventDefault(); e.stopPropagation(); _this4.emit('system.node.click', { node: _this4 }); _this4.emit('events', { type: 'node:click', node: _this4 }); }); this.setDraggable(this.draggable); } }, { key: "setDraggable", value: function setDraggable(draggable) { this.draggable = draggable; } }, { key: "remove", value: function remove() { this.emit('InnerEvents', { type: 'node:delete', data: this }); } }, { key: "emit", value: function emit(type, data) { _get(_getPrototypeOf(BaseNode.prototype), "emit", this).call(this, type, data); this._emit(type, data); } }, { key: "on", value: function on(type, callback) { _get(_getPrototypeOf(BaseNode.prototype), "on", this).call(this, type, callback); this._on(type, callback); } }, { key: "destroy", value: function destroy(isNotEvent) { if (!isNotEvent) { this.endpoints.forEach(function (item) { !item._isInitedDom && item.destroy(); }); $$9(this.dom).remove(); this.removeAllListeners(); this._hasEventListener = false; } else { this.endpoints.forEach(function (item) { !item._isInitedDom && item.destroy(isNotEvent); }); $$9(this.dom).detach(); } this._isInited = false; } }]); return BaseNode; }(Node); var ARROW_TYPE = { default1: { type: 'pathString', content: 'M0 0 L-3 3 L2 0 L-3 -3 Z' }, "default": { type: 'pathString', content: 'M5 0 L0 -2 Q 1.0 0 0 2 Z' }, length: 5 //自定义 // arrow1: { // type: 'svg', // content: require('../../static/arrow/arrow1.svg') // }, // arrow2: { // type: 'svg', // content: require('../../static/arrow/arrow2.svg') // }, // arrow3: { // type: 'svg', // content: require('../../static/arrow/arrow3.svg') // }, }; // 计算线条某个位置的斜率 function calcSlope(opts) { var shapeType = _$d.get(opts, 'shapeType'); var dom = _$d.get(opts, 'dom'); var arrowPosition = _$d.get(opts, 'arrowPosition', 0.5); var path = _$d.get(opts, 'path'); var coordinates = path.split(' '); var x = 0; var y = 0; if (shapeType === 'BezierTest' || shapeType === 'AdvancedBezierTest') { var p0 = { x: coordinates[8], y: coordinates[9] }; var p1 = { x: coordinates[1], y: coordinates[2] }; if (arrowPosition !== 1) { p0 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition + 0.001); p1 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition); } else { p0 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition); p1 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition - 0.001); } x = p1.x - p0.x; y = p1.y - p0.y; } else if (shapeType === 'Straight') { var _p = { x: coordinates[1], y: coordinates[2] }; var _p2 = { x: coordinates[4], y: coordinates[5] }; x = _p2.x - _p.x; y = _p2.y - _p.y; } else { var _p3 = 0; var _p4 = 1; if (arrowPosition !== 1) { _p3 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition); _p4 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition + 0.001); } else { _p3 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition - 0.001); _p4 = dom.getPointAtLength(dom.getTotalLength() * arrowPosition); } x = _p4.x - _p3.x; y = _p4.y - _p3.y; } return { x: x, y: y }; } var registerArrow = function registerArrow(arrows) { arrows.forEach(function (item) { ARROW_TYPE[item.key] = { type: item.type, content: item.content, width: item.width, height: item.height }; }); }; var Arrow = { calcSlope: calcSlope, ARROW_TYPE: ARROW_TYPE, registerArrow: registerArrow }; var MINDIST = 20; var TOL = 0.1; var TOLxTOL = 0.01; // this.x = x; // this.y = y; // } var LEFT = 'Left'; var RIGHT = 'Right'; var TOP = 'Top'; var BOTTOM = 'Bottom'; // 曼哈顿折线路由算法 function _route(conn, fromPt, fromDir, toPt, toDir) { // 防止图上节点隐藏NaN的死循环问题 fromPt.x = fromPt.x || 0; fromPt.y = fromPt.y || 0; toPt.x = toPt.x || 0; toPt.y = toPt.y || 0; var xDiff = fromPt.x - toPt.x; var yDiff = fromPt.y - toPt.y; var point; var dir; var pos; conn.push({ x: fromPt.x, y: fromPt.y }); if (xDiff * xDiff < TOLxTOL && yDiff * yDiff < TOLxTOL) { // conn.push({x: toPt.x, y: toPt.y}); return; } if (fromDir === LEFT) { if (xDiff > 0 && yDiff * yDiff < TOL && toDir === RIGHT) { point = toPt; dir = toDir; } else { if (xDiff < 0) { point = { x: fromPt.x - MINDIST, y: fromPt.y }; } else if (yDiff > 0 && toDir === BOTTOM || yDiff < 0 && toDir === TOP) { point = { x: toPt.x, y: fromPt.y }; } else if (fromDir === toDir) { pos = Math.min(fromPt.x, toPt.x) - MINDIST; point = { x: pos, y: fromPt.y }; } else { point = { x: fromPt.x - xDiff / 2, y: fromPt.y }; } if (yDiff > 0) { dir = TOP; } else { dir = BOTTOM; } } } else if (fromDir === RIGHT) { if (xDiff < 0 && yDiff * yDiff < TOL && toDir === LEFT) { point = toPt; dir = toDir; } else { if (xDiff > 0) { point = { x: fromPt.x + MINDIST, y: fromPt.y }; } else if (yDiff > 0 && toDir === BOTTOM || yDiff < 0 && toDir === TOP) { point = { x: toPt.x, y: fromPt.y }; } else if (fromDir === toDir) { pos = Math.max(fromPt.x, toPt.x) + MINDIST; point = { x: pos, y: fromPt.y }; } else { point = { x: fromPt.x - xDiff / 2, y: fromPt.y }; } if (yDiff > 0) { dir = TOP; } else { dir = BOTTOM; } } } else if (fromDir === BOTTOM) { if (xDiff * xDiff < TOL && yDiff < 0 && toDir === TOP) { point = toPt; dir = toDir; } else { if (yDiff > 0) { point = { x: fromPt.x, y: fromPt.y + MINDIST }; } else if (xDiff > 0 && toDir === RIGHT || xDiff < 0 && toDir === LEFT) { point = { x: fromPt.x, y: toPt.y }; } else if (fromDir === toDir) { pos = Math.max(fromPt.y, toPt.y) + MINDIST; point = { x: fromPt.x, y: pos }; } else { point = { x: fromPt.x, y: fromPt.y - yDiff / 2 }; } if (xDiff > 0) { dir = LEFT; } else { dir = RIGHT; } } } else if (fromDir === TOP) { if (xDiff * xDiff < TOL && yDiff > 0 && toDir === BOTTOM) { point = toPt; dir = toDir; } else { if (yDiff < 0) { point = { x: fromPt.x, y: fromPt.y - MINDIST }; } else if (xDiff > 0 && toDir === RIGHT || xDiff < 0 && toDir === LEFT) { point = { x: fromPt.x, y: toPt.y }; } else if (fromDir === toDir) { pos = Math.min(fromPt.y, toPt.y) - MINDIST; point = { x: fromPt.x, y: pos }; } else { point = { x: fromPt.x, y: fromPt.y - yDiff / 2 }; } if (xDiff > 0) { dir = LEFT; } else { dir = RIGHT; } } } _route(conn, point, dir, toPt, toDir); } function _calcOrientation(beginX, beginY, endX, endY, orientationLimit) { var _calcWithLimit = function _calcWithLimit(rank) { if (orientationLimit) { var _loop = function _loop(i) { var isInLimit = _$d.some(orientationLimit, function (limit) { return limit === rank[i]; }); if (isInLimit) { return { v: rank[i] }; } }; for (var i = 0; i < rank.length; i++) { var _ret = _loop(i); if (_typeof(_ret) === "object") return _ret.v; } return rank[0]; } else { return rank[0]; } }; // 计算orientation var posX = endX - beginX; var posY = endY - beginY; var orientation = null; // 斜率 var k = Math.abs(posY / posX); if (posX === 0 || posY === 0) { if (posX === 0) { orientation = posY >= 0 ? _calcWithLimit(['Top', 'Left', 'Right', 'Bottom']) : orientation; orientation = posY < 0 ? _calcWithLimit(['Bottom', 'Left', 'Right', 'Top']) : orientation; } if (posY === 0) { orientation = posX >= 0 ? _calcWithLimit(['Right', 'Top', 'Bottom', 'Left']) : orientation; orientation = posX < 0 ? _calcWithLimit(['Left', 'Top', 'Bottom', 'Right']) : orientation; } } else if (posX > 0 && posY > 0) { if (k > 1) { orientation = _calcWithLimit(['Top', 'Left', 'Right', 'Bottom']); // orientation = [0, -1]; } else { orientation = _calcWithLimit(['Left', 'Top', 'Bottom', 'Right']); // orientation = [-1, 0]; } } else if (posX < 0 && posY > 0) { if (k > 1) { orientation = _calcWithLimit(['Top', 'Right', 'Left', 'Bottom']); // orientation = [0, -1]; } else { orientation = _calcWithLimit(['Right', 'Top', 'Bottom', 'Left']); // orientation = [1, 0]; } } else if (posX < 0 && posY < 0) { if (k > 1) { orientation = _calcWithLimit(['Bottom', 'Right', 'Left', 'Top']); // orientation = [0, 1]; } else { orientation = _calcWithLimit(['Right', 'Bottom', 'Top', 'Left']); // orientation = [1, 0]; } } else { if (k > 1) { orientation = _calcWithLimit(['Bottom', 'Left', 'Right', 'Top']); // orientation = [0, 1]; } else { orientation = _calcWithLimit(['Left', 'Bottom', 'Top', 'Right']); // orientation = [-1, 0]; } } switch (orientation) { case 'Left': return [-1, 0]; case 'Right': return [1, 0]; case 'Top': return [0, -1]; case 'Bottom': return [0, 1]; } } function _findControlPoint(point, sourcePoint, targetPoint, _so, _to) { // 曲率,可配置的 var majorAnchor = 10; // 偏移,定死的 var minorAnchor = 10; var result = []; // 特殊处理完全水平和垂直的情况 if (sourcePoint.pos[0] === targetPoint.pos[0] && _so[1] !== _to[1] && _so[0] === 0 && _to[0] === 0) { result = [point[0], point[1] + majorAnchor * _so[1]]; return result; } if (sourcePoint.pos[1] === targetPoint.pos[1] && _so[0] !== _to[0] && _so[1] === 0 && _to[1] === 0) { result = [point[0] + majorAnchor * _so[0], point[1]]; return result; } // 平常情况 var perpendicular = _so[0] !== _to[0] || _so[1] === _to[1]; if (!perpendicular) { if (_so[0] === 0) { result.push(sourcePoint.pos[0] < targetPoint.pos[0] ? point[0] + minorAnchor : point[0] - minorAnchor); } else { result.push(point[0] - majorAnchor * _so[0]); } if (_so[1] === 0) { result.push(sourcePoint.pos[1] < targetPoint.pos[1] ? point[1] + minorAnchor : point[1] - minorAnchor); } else { result.push(point[1] - majorAnchor * _to[1]); } } else { if (_to[0] === 0) { result.push(targetPoint.pos[0] < sourcePoint.pos[0] ? point[0] + minorAnchor : point[0] - minorAnchor); } else { result.push(point[0] + majorAnchor * _to[0]); } if (_to[1] === 0) { result.push(targetPoint.pos[1] < sourcePoint.pos[1] ? point[1] + minorAnchor : point[1] - minorAnchor); } else { result.push(point[1] + majorAnchor * _so[1]); } } return result; } //二阶贝塞尔曲线 function _findSecondControlPoint(sourcePoint, targetPoint, _so, _to, shapeType) { //中点 var midX = (sourcePoint.pos[0] + targetPoint.pos[0]) / 2; var midY = (sourcePoint.pos[1] + targetPoint.pos[1]) / 2; //四分之一点的位置 var quarterX = midX - (midX - sourcePoint.pos[0]) / 2; var quarterY = midY - (midY - sourcePoint.pos[1]) / 2; //四分之三位置 var threeQuarterX = midX + (midX - sourcePoint.pos[0]) / 2; var threeQuarterY = midY + (midY - sourcePoint.pos[1]) / 2; var basicPointX = midX; var basicPointY = midY; if (shapeType === "Bezier2-1") { basicPointX = midX; basicPointY = midY; } else if (shapeType === "Bezier2-2") { basicPointX = quarterX; basicPointY = quarterY; } else if (shapeType === "Bezier2-3") { basicPointX = threeQuarterX; basicPointY = threeQuarterY; } var ctrlPoint; var offset; var _width = Math.abs(sourcePoint.pos[0] - sourcePoint.pos[0]); var _height = Math.abs(sourcePoint.pos[1] - targetPoint.pos[1]); var dist = Math.sqrt(_width * _width + _height * _height); //正常情况 var midK = (targetPoint.pos[1] - sourcePoint.pos[1]) / (targetPoint.pos[0] - sourcePoint.pos[0]); if (midK === 0) { if (sourcePoint.pos[0] < targetPoint.pos[0] && _so[0] === 1 && _to[0] === -1 || sourcePoint.pos[0] > targetPoint.pos[0] && _so[0] === -1 && _to[0] === 1 || sourcePoint.pos[1] < targetPoint.pos[1] && _so[1] === 1 && _to[1] === -1 || sourcePoint.pos[1] > targetPoint.pos[1] && _so[1] === -1 && _to[1] === 1) { return ctrlPoint = [midX, midY]; } } var k = -1 / midK; var b = basicPointY - k * basicPointX; offset = Math.sqrt(3) * dist / 6; var t; var _sum0 = _so[0] + _to[0]; var _sum1 = _so[1] + _to[1]; if (targetPoint.pos[0] < sourcePoint.pos[0] && targetPoint.pos[1] < sourcePoint.pos[1] && (_sum0 === 0 && _sum1 === 0 || _sum0 === 1 && _sum1 === -1)) { t = 1; } else if (targetPoint.pos[0] > sourcePoint.pos[0] && targetPoint.pos[1] < sourcePoint.pos[1] && _sum0 === 1 && _sum1 === 1) { t = 1; } else if (targetPoint.pos[0] < sourcePoint.pos[0] && targetPoint.pos[1] > sourcePoint.pos[1] && (_sum0 === 0 && _sum1 === 0 || _sum0 === 1 && _sum1 === 1)) { t = 1; } else if (targetPoint.pos[0] > sourcePoint.pos[0] && targetPoint.pos[1] > sourcePoint.pos[1] && _sum0 === 1 && _sum1 === -1) { t = 1; } else { t = -1; } ctrlPoint = [basicPointX + offset * t, k * (basicPointX + offset * t) + b]; //特殊情况: var percent = 0.25; var minorDist = 100; offset = dist * percent + minorDist; var so_offsetX = 0; var so_offsetY = 0; var to_offsetX = 0; var to_offsetY = 0; if (_so[0] === -1 && targetPoint.pos[0] > sourcePoint.pos[0] || _so[0] === 1 && targetPoint.pos[0] < sourcePoint.pos[0] || _so[1] === 1 && targetPoint.pos[1] < sourcePoint.pos[1] || _so[1] === -1 && targetPoint.pos[1] > sourcePoint.pos[1]) { if (_so[0] !== 0) { so_offsetX = offset * _so[0]; } if (_so[1] !== 0) { so_offsetY = offset * _so[1]; } return ctrlPoint = [sourcePoint.pos[0] + so_offsetX, sourcePoint.pos[1] + so_offsetY]; } if (_so[0] === _to[0] && _so[1] === _to[1] || _so[0] !== 0 && targetPoint.pos[1] < sourcePoint.pos[1] && _to[1] === -1 || _so[0] !== 0 && targetPoint.pos[1] > sourcePoint.pos[1] && _to[1] === 1 || _so[1] !== 0 && targetPoint.pos[0] < sourcePoint.pos[0] && _to[0] === -1 || _so[1] !== 0 && targetPoint.pos[0] > sourcePoint.pos[0] && _to[0] === 1) { if (_to[0] !== 0) { to_offsetX = offset * _to[0]; } else if (_to[1] !== 0) { to_offsetY = offset * _to[1]; } ctrlPoint = [targetPoint.pos[0] + to_offsetX, targetPoint.pos[1] + to_offsetY]; } return ctrlPoint; } function _findManhattanPoint(points, pos) { var result = undefined; var gap = Infinity; for (var i = 0; i < points.length - 1; i++) { var _dir = points[i].x === points[i + 1].x ? 'vertical' : 'horizontal'; var _from = points[i]; var _to = points[i + 1]; if (_dir === 'vertical') { if (gap > Math.abs(pos.x - _from.x)) { gap = Math.abs(pos.x - _from.x); result = { from: _from, to: _to, direction: _dir, index: i }; } } else { if (gap > Math.abs(pos.y - _from.y)) { gap = Math.abs(pos.y - _from.y); result = { from: _from, to: _to, direction: _dir, index: i }; } } } return result; } var drawAdvancedBezier = function drawAdvancedBezier(sourcePoint, targetPoint) { if (!sourcePoint.orientation) { sourcePoint.orientation = _calcOrientation(targetPoint.pos[0], targetPoint.pos[1], sourcePoint.pos[0], sourcePoint.pos[1]); } if (!targetPoint.orientation) { targetPoint.orientation = _calcOrientation(sourcePoint.pos[0], sourcePoint.pos[1], targetPoint.pos[0], targetPoint.pos[1]); } // 控制点 var _width = Math.abs(sourcePoint.pos[0] - targetPoint.pos[0]); var _height = Math.abs(sourcePoint.pos[1] - targetPoint.pos[1]); var _so = sourcePoint.orientation; var _to = targetPoint.orientation; var dist = Math.sqrt(_width * _width + _height * _height); // 控制点百分比,可转配置 var percent = 0.25; // 偏差量,可转配置 var minorDist = 30; var so_offsetX = 0; var so_offsetY = 0; if (_so[0] !== 0) { so_offsetX = (dist * percent + minorDist) * _so[0]; } else if (_so[1] !== 0) { so_offsetY = (dist * percent + minorDist) * _so[1]; } var to_offsetX = 0; var to_offsetY = 0; if (_to[0] !== 0) { to_offsetX = (dist * percent + minorDist) * _to[0]; } else if (_to[1] !== 0) { to_offsetY = (dist * percent + minorDist) * _to[1]; } var sourceCtrlPoint = [sourcePoint.pos[0] + so_offsetX, sourcePoint.pos[1] + so_offsetY]; var targetCtrlPoint = [targetPoint.pos[0] + to_offsetX, targetPoint.pos[1] + to_offsetY]; // 起始点 var result = ['M', sourcePoint.pos[0], sourcePoint.pos[1]]; // let result = ['M', targetPoint.pos[0], targetPoint.pos[1]]; // 两个控制点 result = result.concat(['C', sourceCtrlPoint[0], sourceCtrlPoint[1]], targetCtrlPoint[0], targetCtrlPoint[1]); // result = result.concat(['C', targetCtrlPoint[0], targetCtrlPoint[1], sourceCtrlPoint[0], sourceCtrlPoint[1]]); // 结束点 result = result.concat([targetPoint.pos[0], targetPoint.pos[1]]); // result = result.concat([sourcePoint.pos[0], sourcePoint.pos[1]]); return result.join(' '); }; function drawBezier(sourcePoint, targetPoint) { if (!sourcePoint.orientation) { sourcePoint.orientation = _calcOrientation(targetPoint.pos[0], targetPoint.pos[1], sourcePoint.pos[0], sourcePoint.pos[1]); } if (!targetPoint.orientation) { targetPoint.orientation = _calcOrientation(sourcePoint.pos[0], sourcePoint.pos[1], targetPoint.pos[0], targetPoint.pos[1]); } // 控制点 var _width = Math.abs(sourcePoint.pos[0] - targetPoint.pos[0]); var _height = Math.abs(sourcePoint.pos[1] - targetPoint.pos[1]); var _sx = sourcePoint.pos[0] < targetPoint.pos[0] ? _width : 0; var _sy = sourcePoint.pos[1] < targetPoint.pos[1] ? _height : 0; var _tx = sourcePoint.pos[0] < targetPoint.pos[0] ? 0 : _width; var _ty = sourcePoint.pos[1] < targetPoint.pos[1] ? 0 : _height; var _so = sourcePoint.orientation; var _to = targetPoint.orientation; var sourceCtrlPoint = _findControlPoint([_sx, _sy], sourcePoint, targetPoint, _so, _to); var targetCtrlPoint = _findControlPoint([_tx, _ty], targetPoint, sourcePoint, _to, _so); var offsetX = sourcePoint.pos[0] < targetPoint.pos[0] ? sourcePoint.pos[0] : targetPoint.pos[0]; var offsetY = sourcePoint.pos[1] < targetPoint.pos[1] ? sour