UNPKG

@zxr3680166/simple-mind-map

Version:

一个简单的web在线思维导图

241 lines (228 loc) 6.33 kB
import { bfsWalk, throttle, checkTwoRectIsOverlap } from '../utils' // 节点选择插件 class Select { // 构造函数 constructor({ mindMap }) { this.mindMap = mindMap this.rect = null this.isMousedown = false this.mouseDownX = 0 this.mouseDownY = 0 this.mouseMoveX = 0 this.mouseMoveY = 0 this.isSelecting = false this.cacheActiveList = [] this.bindEvent() } // 绑定事件 bindEvent() { this.checkInNodes = throttle(this.checkInNodes, 300, this) this.mindMap.on('mousedown', e => { if (this.mindMap.opt.readonly) { return } let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt if ( !e.ctrlKey && (useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3) ) { return } e.preventDefault() this.isMousedown = true this.cacheActiveList = [...this.mindMap.renderer.activeNodeList] let { x, y } = this.mindMap.toPos(e.clientX, e.clientY) this.mouseDownX = x this.mouseDownY = y this.createRect(x, y) }) this.mindMap.on('mousemove', e => { if (this.mindMap.opt.readonly) { return } if (!this.isMousedown) { return } let { x, y } = this.mindMap.toPos(e.clientX, e.clientY) this.mouseMoveX = x this.mouseMoveY = y if ( Math.abs(x - this.mouseDownX) <= 10 && Math.abs(y - this.mouseDownY) <= 10 ) { return } this.clearAutoMoveTimer() this.onMove( e.clientX, e.clientY, () => { this.isSelecting = true // 绘制矩形 this.rect.plot([ [this.mouseDownX, this.mouseDownY], [this.mouseMoveX, this.mouseDownY], [this.mouseMoveX, this.mouseMoveY], [this.mouseDownX, this.mouseMoveY] ]) this.checkInNodes() }, (dir, step) => { switch (dir) { case 'left': this.mouseDownX += step break case 'top': this.mouseDownY += step break case 'right': this.mouseDownX -= step break case 'bottom': this.mouseDownY -= step break default: break } } ) }) this.onMouseup = this.onMouseup.bind(this) this.mindMap.on('mouseup', this.onMouseup) this.mindMap.on('node_mouseup', this.onMouseup) } // 结束框选 onMouseup() { if (this.mindMap.opt.readonly) { return } if (!this.isMousedown) { return } this.checkTriggerNodeActiveEvent() clearTimeout(this.autoMoveTimer) this.isMousedown = false this.cacheActiveList = [] if (this.rect) this.rect.remove() this.rect = null setTimeout(() => { this.isSelecting = false }, 0) } // 如果激活节点改变了,那么触发事件 checkTriggerNodeActiveEvent() { let isNumChange = this.cacheActiveList.length !== this.mindMap.renderer.activeNodeList.length let isNodeChange = false if (!isNumChange) { for (let i = 0; i < this.cacheActiveList.length; i++) { let cur = this.cacheActiveList[i] if ( !this.mindMap.renderer.activeNodeList.find(item => { return item.getData('uid') === cur.getData('uid') }) ) { isNodeChange = true break } } } if (isNumChange || isNodeChange) { this.mindMap.renderer.emitNodeActiveEvent() } } // 鼠标移动事件 onMove(x, y, callback = () => {}, handle = () => {}) { callback() // 检测边缘移动 let step = this.mindMap.opt.selectTranslateStep let limit = this.mindMap.opt.selectTranslateLimit let count = 0 // 左边缘 if (x <= this.mindMap.elRect.left + limit) { handle('left', step) this.mindMap.view.translateX(step) count++ } // 右边缘 if (x >= this.mindMap.elRect.right - limit) { handle('right', step) this.mindMap.view.translateX(-step) count++ } // 上边缘 if (y <= this.mindMap.elRect.top + limit) { handle('top', step) this.mindMap.view.translateY(step) count++ } // 下边缘 if (y >= this.mindMap.elRect.bottom - limit) { handle('bottom', step) this.mindMap.view.translateY(-step) count++ } if (count > 0) { this.startAutoMove(x, y, callback, handle) } } // 开启自动移动 startAutoMove(x, y, callback, handle) { this.autoMoveTimer = setTimeout(() => { this.onMove(x, y, callback, handle) }, 20) } // 清除自动移动定时器 clearAutoMoveTimer() { clearTimeout(this.autoMoveTimer) } // 创建矩形 createRect(x, y) { if (this.rect) this.rect.remove() this.rect = this.mindMap.svg .polygon() .stroke({ color: '#0984e3' }) .fill({ color: 'rgba(9,132,227,0.3)' }) .plot([[x, y]]) } // 检测在选区里的节点 checkInNodes() { let { scaleX, scaleY, translateX, translateY } = this.mindMap.draw.transform() let minx = Math.min(this.mouseDownX, this.mouseMoveX) let miny = Math.min(this.mouseDownY, this.mouseMoveY) let maxx = Math.max(this.mouseDownX, this.mouseMoveX) let maxy = Math.max(this.mouseDownY, this.mouseMoveY) bfsWalk(this.mindMap.renderer.root, node => { let { left, top, width, height } = node let right = (left + width) * scaleX + translateX let bottom = (top + height) * scaleY + translateY left = left * scaleX + translateX top = top * scaleY + translateY if ( checkTwoRectIsOverlap(minx, maxx, miny, maxy, left, right, top, bottom) ) { if (node.getData('isActive')) { return } this.mindMap.renderer.addNodeToActiveList(node) } else if (node.getData('isActive')) { if (!node.getData('isActive')) { return } this.mindMap.renderer.removeNodeFromActiveList(node) } }) } // 是否存在选区 hasSelectRange() { return this.isSelecting } } Select.instanceName = 'select' export default Select