UNPKG

@logicflow/extension

Version:
349 lines (348 loc) 14.9 kB
var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; 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)); }; import { cloneDeep } from 'lodash-es'; var SelectionSelect = /** @class */ (function () { function SelectionSelect(_a) { var lf = _a.lf, options = _a.options; var _this = this; var _b; this.disabled = true; this.isWholeNode = true; this.isWholeEdge = true; this.exclusiveMode = false; // 框选独占模式:true 表示只能进行框选操作,false 表示可以同时进行其他画布操作 // 用于区分选区和点击事件 this.mouseDownInfo = null; // 记录原始的 stopMoveGraph 设置 this.originalStopMoveGraph = false; /** * 处理画布空白处鼠标按下事件(非独占模式) */ this.handleBlankMouseDown = function (_a) { var e = _a.e; _this.handleMouseDown(e); }; this.draw = function (ev) { var _a = _this.lf.getPointByClient(ev.clientX, ev.clientY).domOverlayPosition, x1 = _a.x, y1 = _a.y; _this.endPoint = { x: x1, y: y1, }; if (_this.startPoint) { var _b = _this.startPoint, x = _b.x, y = _b.y; var left = x; var top_1 = y; var width = x1 - x; var height = y1 - y; if (x1 < x) { left = x1; width = x - x1; } if (y1 < y) { top_1 = y1; height = y - y1; } if (_this.wrapper) { _this.wrapper.style.left = "".concat(left, "px"); _this.wrapper.style.top = "".concat(top_1, "px"); _this.wrapper.style.width = "".concat(width, "px"); _this.wrapper.style.height = "".concat(height, "px"); } } }; this.drawOff = function (e) { // 处理鼠标抬起事件 // 首先判断是否是点击,如果是,则清空框选 if (_this.mouseDownInfo) { var _a = _this.mouseDownInfo, x = _a.x, y = _a.y, time = _a.time; var isClick = Math.abs(e.clientX - x) < 5 && Math.abs(e.clientY - y) < 5 && Date.now() - time < 200; if (isClick) { _this.lf.clearSelectElements(); _this.cleanupSelectionState(); return; } } var curStartPoint = cloneDeep(_this.startPoint); var curEndPoint = cloneDeep(_this.endPoint); document.removeEventListener('mousemove', _this.draw); if (!_this.exclusiveMode) { document.removeEventListener('mouseup', _this.drawOff); } // 恢复原始的 stopMoveGraph 设置 _this.lf.updateEditConfig({ stopMoveGraph: _this.originalStopMoveGraph, }); if (curStartPoint && curEndPoint) { var x = curStartPoint.x, y = curStartPoint.y; var x1 = curEndPoint.x, y1 = curEndPoint.y; // 返回框选范围,左上角和右下角的坐标 var lt = [Math.min(x, x1), Math.min(y, y1)]; var rb = [Math.max(x, x1), Math.max(y, y1)]; _this.lf.emit('selection:selected-area', { topLeft: lt, bottomRight: rb, }); // 选区太小的情况就忽略 if (Math.abs(x1 - x) < 10 && Math.abs(y1 - y) < 10) { if (_this.wrapper) { _this.wrapper.oncontextmenu = null; if (_this.container && _this.wrapper.parentNode === _this.container) { _this.container.removeChild(_this.wrapper); } _this.wrapper = undefined; } return; } var elements_1 = _this.lf.graphModel.getAreaElement(lt, rb, _this.isWholeEdge, _this.isWholeNode, true); var _b = _this.lf.graphModel, dynamicGroup_1 = _b.dynamicGroup, group_1 = _b.group; var nonGroupedElements_1 = []; var selectedElements = _this.lf.getSelectElements(); // 同时记录节点和边的ID var selectedIds_1 = new Set(__spreadArray(__spreadArray([], __read(selectedElements.nodes.map(function (node) { return node.id; })), false), __read(selectedElements.edges.map(function (edge) { return edge.id; })), false)); elements_1.forEach(function (element) { // 如果节点属于分组,则不选中节点,此处兼容旧版 Group 插件 if (group_1) { var elementGroup = group_1.getNodeGroup(element.id); if (elements_1.includes(elementGroup)) { // 当被选中的元素的父分组被选中时,不选中该元素 return; } } if (dynamicGroup_1) { var elementGroup = dynamicGroup_1.getGroupByNodeId(element.id); if (elements_1.includes(elementGroup)) { // 当被选中的元素的父分组被选中时,不选中该元素 return; } } // 在独占模式下,如果元素已经被选中,则取消选中 if (_this.exclusiveMode && selectedIds_1.has(element.id)) { _this.lf.deselectElementById(element.id); return; } // 非独占模式下,或者元素未被选中时,选中元素 _this.lf.selectElementById(element.id, true); nonGroupedElements_1.push(element); }); // 重置起始点和终点 // 注意:这两个值必须在触发closeSelectionSelect方法前充值,否则会导致独占模式下元素无法选中的问题 _this.startPoint = undefined; _this.endPoint = undefined; // 如果有选中的元素,触发 selection:drop 事件 if (nonGroupedElements_1.length > 0) { _this.lf.emit('selection:drop', { e: e }); } // 触发 selection:selected 事件 _this.lf.emit('selection:selected', { elements: nonGroupedElements_1, leftTopPoint: lt, rightBottomPoint: rb, }); } if (_this.wrapper) { _this.wrapper.oncontextmenu = null; if (_this.container && _this.wrapper.parentNode === _this.container) { _this.container.removeChild(_this.wrapper); } _this.wrapper = undefined; } }; this.lf = lf; this.exclusiveMode = (_b = options === null || options === void 0 ? void 0 : options.exclusiveMode) !== null && _b !== void 0 ? _b : false; // TODO: 有没有既能将方法挂载到lf上,又能提供类型提示的方法? lf.openSelectionSelect = function () { _this.openSelectionSelect(); }; lf.closeSelectionSelect = function () { _this.closeSelectionSelect(); }; // 新增切换独占模式的方法 lf.setSelectionSelectMode = function (exclusive) { _this.setExclusiveMode(exclusive); }; // 绑定方法的 this 上下文 this.handleMouseDown = this.handleMouseDown.bind(this); this.draw = this.draw.bind(this); this.drawOff = this.drawOff.bind(this); } SelectionSelect.prototype.render = function (_, domContainer) { this.container = domContainer; }; /** * 清理选区状态 */ SelectionSelect.prototype.cleanupSelectionState = function () { // 清理当前的选区状态 if (this.wrapper) { this.wrapper.oncontextmenu = null; if (this.container && this.wrapper.parentNode === this.container) { this.container.removeChild(this.wrapper); } this.wrapper = undefined; } this.startPoint = undefined; this.endPoint = undefined; this.mouseDownInfo = null; // 移除事件监听 document.removeEventListener('mousemove', this.draw); document.removeEventListener('mouseup', this.drawOff); }; /** * 切换框选模式 * @param exclusive 是否为独占模式。true 表示只能进行框选操作,false 表示可以同时进行其他画布操作 */ SelectionSelect.prototype.setExclusiveMode = function (exclusive) { if (exclusive === void 0) { exclusive = false; } if (this.exclusiveMode === exclusive) return; this.cleanupSelectionState(); this.exclusiveMode = exclusive; if (this.container && !this.disabled) { // 切换事件监听方式 this.removeEventListeners(); this.addEventListeners(); } }; SelectionSelect.prototype.addEventListeners = function () { if (!this.container) return; if (this.exclusiveMode) { // 独占模式:监听 container 的 mousedown 事件 this.container.style.pointerEvents = 'auto'; this.container.addEventListener('mousedown', this.handleMouseDown); } else { // 非独占模式:监听画布的 blank:mousedown 事件 this.container.style.pointerEvents = 'none'; // 使用实例方法而不是箭头函数,这样可以正确移除事件监听 this.lf.on('blank:mousedown', this.handleBlankMouseDown); } }; SelectionSelect.prototype.removeEventListeners = function () { if (this.container) { this.container.style.pointerEvents = 'none'; this.container.removeEventListener('mousedown', this.handleMouseDown); } // 移除 blank:mousedown 事件监听 this.lf.off('blank:mousedown', this.handleBlankMouseDown); }; /** * 处理鼠标按下事件 */ SelectionSelect.prototype.handleMouseDown = function (e) { var _a; if (!this.container || this.disabled) return; // 禁用右键框选 var isRightClick = e.button === 2; if (isRightClick) return; // 清理之前可能存在的选区状态 this.cleanupSelectionState(); // 记录鼠标按下时的位置和时间 this.mouseDownInfo = { x: e.clientX, y: e.clientY, time: Date.now(), }; // 记录原始设置并临时禁止画布移动 this.originalStopMoveGraph = this.lf.getEditConfig().stopMoveGraph; this.lf.updateEditConfig({ stopMoveGraph: true, }); var _b = this.lf.getPointByClient(e.clientX, e.clientY).domOverlayPosition, x = _b.x, y = _b.y; this.startPoint = { x: x, y: y }; this.endPoint = { x: x, y: y }; var wrapper = document.createElement('div'); wrapper.className = 'lf-selection-select'; wrapper.oncontextmenu = function prevent(ev) { ev.preventDefault(); }; wrapper.style.top = "".concat(this.startPoint.y, "px"); wrapper.style.left = "".concat(this.startPoint.x, "px"); (_a = this.container) === null || _a === void 0 ? void 0 : _a.appendChild(wrapper); this.wrapper = wrapper; document.addEventListener('mousemove', this.draw); document.addEventListener('mouseup', this.drawOff); }; /** * 设置选中的灵敏度 * @param isWholeEdge 是否要边的起点终点都在选区范围才算选中。默认true * @param isWholeNode 是否要节点的全部点都在选区范围才算选中。默认true */ SelectionSelect.prototype.setSelectionSense = function (isWholeEdge, isWholeNode) { if (isWholeEdge === void 0) { isWholeEdge = true; } if (isWholeNode === void 0) { isWholeNode = true; } this.isWholeEdge = isWholeEdge; this.isWholeNode = isWholeNode; }; /** * 开启选区 */ SelectionSelect.prototype.openSelectionSelect = function () { if (!this.disabled) { this.closeSelectionSelect(); } if (!this.container) { return; } this.cleanupSelectionState(); this.addEventListeners(); this.open(); }; /** * 关闭选区 */ SelectionSelect.prototype.closeSelectionSelect = function () { if (!this.container) { return; } // 如果还有未完成的框选,先触发 drawOff 完成框选 if (this.wrapper && this.startPoint && this.endPoint) { // 记录上一次的结束点,用于触发 mouseup 事件 var lastEndPoint = cloneDeep(this.endPoint); var lastEvent = new MouseEvent('mouseup', { clientX: lastEndPoint.x, clientY: lastEndPoint.y, }); this.drawOff(lastEvent); } this.cleanupSelectionState(); this.removeEventListeners(); this.close(); }; SelectionSelect.prototype.open = function () { this.disabled = false; }; SelectionSelect.prototype.close = function () { this.disabled = true; }; SelectionSelect.pluginName = 'selectionSelect'; return SelectionSelect; }()); export { SelectionSelect }; export default SelectionSelect;