240 lines
6.1 KiB
JavaScript
240 lines
6.1 KiB
JavaScript
import { bfsWalk, throttle, checkTwoRectIsOverlap } from '../utils'
|
|
import AutoMove from '../utils/AutoMove'
|
|
|
|
// 节点选择插件
|
|
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.autoMove = new AutoMove(mindMap)
|
|
this.bindEvent()
|
|
}
|
|
|
|
// 绑定事件
|
|
bindEvent() {
|
|
this.onMousedown = this.onMousedown.bind(this)
|
|
this.onMousemove = this.onMousemove.bind(this)
|
|
this.onMouseup = this.onMouseup.bind(this)
|
|
this.checkInNodes = throttle(this.checkInNodes, 300, this)
|
|
|
|
this.mindMap.on('mousedown', this.onMousedown)
|
|
this.mindMap.on('mousemove', this.onMousemove)
|
|
this.mindMap.on('mouseup', this.onMouseup)
|
|
this.mindMap.on('node_mouseup', this.onMouseup)
|
|
}
|
|
|
|
// 解绑事件
|
|
unBindEvent() {
|
|
this.mindMap.off('mousedown', this.onMousedown)
|
|
this.mindMap.off('mousemove', this.onMousemove)
|
|
this.mindMap.off('mouseup', this.onMouseup)
|
|
this.mindMap.off('node_mouseup', this.onMouseup)
|
|
}
|
|
|
|
// 鼠标按下
|
|
onMousedown(e) {
|
|
const { readonly, mousedownEventPreventDefault } = this.mindMap.opt
|
|
if (readonly) {
|
|
return
|
|
}
|
|
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
|
|
if (
|
|
!(e.ctrlKey || e.metaKey) &&
|
|
(useLeftKeySelectionRightKeyDrag ? e.which !== 1 : e.which !== 3)
|
|
) {
|
|
return
|
|
}
|
|
if (mousedownEventPreventDefault) {
|
|
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)
|
|
}
|
|
|
|
// 鼠标移动
|
|
onMousemove(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.autoMove.clearAutoMoveTimer()
|
|
this.autoMove.onMove(
|
|
e.clientX,
|
|
e.clientY,
|
|
() => {
|
|
this.isSelecting = true
|
|
// 绘制矩形
|
|
if (this.rect) {
|
|
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
|
|
}
|
|
}
|
|
)
|
|
}
|
|
|
|
// 结束框选
|
|
onMouseup() {
|
|
if (this.mindMap.opt.readonly) {
|
|
return
|
|
}
|
|
if (!this.isMousedown) {
|
|
return
|
|
}
|
|
this.checkTriggerNodeActiveEvent()
|
|
this.autoMove.clearAutoMoveTimer()
|
|
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()
|
|
}
|
|
}
|
|
|
|
// 创建矩形
|
|
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)
|
|
|
|
const check = 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)
|
|
this.mindMap.renderer.emitNodeActiveEvent()
|
|
} else if (node.getData('isActive')) {
|
|
if (!node.getData('isActive')) {
|
|
return
|
|
}
|
|
this.mindMap.renderer.removeNodeFromActiveList(node)
|
|
this.mindMap.renderer.emitNodeActiveEvent()
|
|
}
|
|
}
|
|
|
|
bfsWalk(this.mindMap.renderer.root, node => {
|
|
check(node)
|
|
// 概要节点
|
|
if (node._generalizationList && node._generalizationList.length > 0) {
|
|
node._generalizationList.forEach(item => {
|
|
check(item.generalizationNode)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
// 是否存在选区
|
|
hasSelectRange() {
|
|
return this.isSelecting
|
|
}
|
|
|
|
// 插件被移除前做的事情
|
|
beforePluginRemove() {
|
|
this.unBindEvent()
|
|
}
|
|
|
|
// 插件被卸载前做的事情
|
|
beforePluginDestroy() {
|
|
this.unBindEvent()
|
|
}
|
|
}
|
|
|
|
Select.instanceName = 'select'
|
|
|
|
export default Select
|