mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-21 18:37:43 +08:00
Feat:全新升级节点拖拽时的交互效果
This commit is contained in:
parent
c4777fb17a
commit
a75eb5f195
@ -198,10 +198,15 @@ export const defaultOpt = {
|
||||
dragMultiNodeRectConfig: {
|
||||
width: 40,
|
||||
height: 20,
|
||||
fill: '' // 填充颜色,如果不传默认使用连线的颜色
|
||||
fill: 'rgb(94, 200, 248)' // 填充颜色
|
||||
},
|
||||
// 节点拖拽时新位置的示意矩形的填充颜色
|
||||
dragPlaceholderRectFill: 'rgb(94, 200, 248)',
|
||||
// 节点拖拽时新位置的示意连线的样式配置
|
||||
dragPlaceholderLineConfig: {
|
||||
color: 'rgb(94, 200, 248)',
|
||||
width: 2
|
||||
},
|
||||
// 节点拖拽时新位置的示意矩形的填充颜色,如果不传默认使用连线的颜色
|
||||
dragPlaceholderRectFill: '',
|
||||
// 节点拖拽时的透明度配置
|
||||
dragOpacityConfig: {
|
||||
cloneNodeOpacity: 0.5, // 跟随鼠标移动的克隆节点或矩形的透明度
|
||||
@ -327,5 +332,5 @@ export const defaultOpt = {
|
||||
// 添加附加的节点前置内容,前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分
|
||||
createNodePrefixContent: null,
|
||||
// 添加附加的节点后置内容,后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分
|
||||
createNodePostfixContent: null,
|
||||
createNodePostfixContent: null
|
||||
}
|
||||
|
||||
@ -8,12 +8,17 @@ import nodeCreateContentsMethods from './nodeCreateContents'
|
||||
import nodeExpandBtnPlaceholderRectMethods from './nodeExpandBtnPlaceholderRect'
|
||||
import nodeCooperateMethods from './nodeCooperate'
|
||||
import { CONSTANTS } from '../../../constants/constant'
|
||||
import { copyNodeTree, createForeignObjectNode } from '../../../utils/index'
|
||||
import {
|
||||
copyNodeTree,
|
||||
createForeignObjectNode,
|
||||
createUid
|
||||
} from '../../../utils/index'
|
||||
|
||||
// 节点类
|
||||
class Node {
|
||||
// 构造函数
|
||||
constructor(opt = {}) {
|
||||
this.opt = opt
|
||||
// 节点数据
|
||||
this.nodeData = this.handleData(opt.data || {})
|
||||
// uid
|
||||
@ -111,31 +116,35 @@ class Node {
|
||||
this.needLayout = false
|
||||
// 当前是否是隐藏状态
|
||||
this.isHide = false
|
||||
// 概要相关方法
|
||||
Object.keys(nodeGeneralizationMethods).forEach(item => {
|
||||
this[item] = nodeGeneralizationMethods[item].bind(this)
|
||||
})
|
||||
// 展开收起按钮相关方法
|
||||
Object.keys(nodeExpandBtnMethods).forEach(item => {
|
||||
this[item] = nodeExpandBtnMethods[item].bind(this)
|
||||
})
|
||||
// 展开收起按钮占位元素相关方法
|
||||
Object.keys(nodeExpandBtnPlaceholderRectMethods).forEach(item => {
|
||||
this[item] = nodeExpandBtnPlaceholderRectMethods[item].bind(this)
|
||||
})
|
||||
// 命令的相关方法
|
||||
Object.keys(nodeCommandWrapsMethods).forEach(item => {
|
||||
this[item] = nodeCommandWrapsMethods[item].bind(this)
|
||||
})
|
||||
// 创建节点内容的相关方法
|
||||
Object.keys(nodeCreateContentsMethods).forEach(item => {
|
||||
this[item] = nodeCreateContentsMethods[item].bind(this)
|
||||
})
|
||||
// 协同相关
|
||||
if (this.mindMap.cooperate) {
|
||||
Object.keys(nodeCooperateMethods).forEach(item => {
|
||||
this[item] = nodeCooperateMethods[item].bind(this)
|
||||
const proto = Object.getPrototypeOf(this)
|
||||
if (!proto.bindEvent) {
|
||||
// 概要相关方法
|
||||
Object.keys(nodeGeneralizationMethods).forEach(item => {
|
||||
proto[item] = nodeGeneralizationMethods[item]
|
||||
})
|
||||
// 展开收起按钮相关方法
|
||||
Object.keys(nodeExpandBtnMethods).forEach(item => {
|
||||
proto[item] = nodeExpandBtnMethods[item]
|
||||
})
|
||||
// 展开收起按钮占位元素相关方法
|
||||
Object.keys(nodeExpandBtnPlaceholderRectMethods).forEach(item => {
|
||||
proto[item] = nodeExpandBtnPlaceholderRectMethods[item]
|
||||
})
|
||||
// 命令的相关方法
|
||||
Object.keys(nodeCommandWrapsMethods).forEach(item => {
|
||||
proto[item] = nodeCommandWrapsMethods[item]
|
||||
})
|
||||
// 创建节点内容的相关方法
|
||||
Object.keys(nodeCreateContentsMethods).forEach(item => {
|
||||
proto[item] = nodeCreateContentsMethods[item]
|
||||
})
|
||||
// 协同相关
|
||||
if (this.mindMap.cooperate) {
|
||||
Object.keys(nodeCooperateMethods).forEach(item => {
|
||||
proto[item] = nodeCooperateMethods[item]
|
||||
})
|
||||
}
|
||||
proto.bindEvent = true
|
||||
}
|
||||
// 初始化
|
||||
this.getSize()
|
||||
@ -1175,6 +1184,19 @@ class Node {
|
||||
closeHighlight() {
|
||||
if (this.group) this.group.removeClass('smm-node-highlight')
|
||||
}
|
||||
|
||||
// 伪克隆节点
|
||||
// 克隆出的节点并不能真正当做一个节点使用
|
||||
fakeClone() {
|
||||
const newNode = new Node({
|
||||
...this.opt,
|
||||
uid: createUid()
|
||||
})
|
||||
Object.keys(this).forEach((item) => {
|
||||
newNode[item] = this[item]
|
||||
})
|
||||
return newNode
|
||||
}
|
||||
}
|
||||
|
||||
export default Node
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
getNodeIndexInNodeList
|
||||
} from '../utils'
|
||||
import Base from '../layouts/Base'
|
||||
import { CONSTANTS } from '../constants/constant'
|
||||
|
||||
// 节点拖动插件
|
||||
class Drag extends Base {
|
||||
@ -38,6 +39,10 @@ class Drag extends Base {
|
||||
this.clone = null
|
||||
// 同级位置占位符
|
||||
this.placeholder = null
|
||||
this.placeholderWidth = 50
|
||||
this.placeholderHeight = 10
|
||||
this.placeHolderLine = null
|
||||
this.placeHolderExtraLines = []
|
||||
// 鼠标按下位置和节点左上角的偏移量
|
||||
this.offsetX = 0
|
||||
this.offsetY = 0
|
||||
@ -276,6 +281,7 @@ class Drag extends Base {
|
||||
const {
|
||||
dragMultiNodeRectConfig,
|
||||
dragPlaceholderRectFill,
|
||||
dragPlaceholderLineConfig,
|
||||
dragOpacityConfig
|
||||
} = this.mindMap.opt
|
||||
const {
|
||||
@ -309,9 +315,19 @@ class Drag extends Base {
|
||||
this.clone.opacity(dragOpacityConfig.cloneNodeOpacity)
|
||||
this.clone.css('z-index', 99999)
|
||||
// 同级位置提示元素
|
||||
this.placeholder = this.mindMap.otherDraw.rect().fill({
|
||||
color: dragPlaceholderRectFill || lineColor
|
||||
})
|
||||
this.placeholder = this.mindMap.otherDraw
|
||||
.rect()
|
||||
.fill({
|
||||
color: dragPlaceholderRectFill || lineColor
|
||||
})
|
||||
.radius(5)
|
||||
this.placeHolderLine = this.mindMap.otherDraw
|
||||
.path()
|
||||
.stroke({
|
||||
color: dragPlaceholderLineConfig.color || lineColor,
|
||||
width: dragPlaceholderLineConfig.width
|
||||
})
|
||||
.fill({ color: 'none' })
|
||||
// 当前被拖拽的节点的临时设置
|
||||
this.beingDragNodeList.forEach(node => {
|
||||
// 降低透明度
|
||||
@ -331,6 +347,16 @@ class Drag extends Base {
|
||||
}
|
||||
this.clone.remove()
|
||||
this.placeholder.remove()
|
||||
this.placeHolderLine.remove()
|
||||
this.removeExtraLines()
|
||||
}
|
||||
|
||||
// 移除额外创建的连线
|
||||
removeExtraLines() {
|
||||
this.placeHolderExtraLines.forEach(item => {
|
||||
item.remove()
|
||||
})
|
||||
this.placeHolderExtraLines = []
|
||||
}
|
||||
|
||||
// 检测重叠节点
|
||||
@ -338,10 +364,22 @@ class Drag extends Base {
|
||||
if (!this.drawTransform || !this.placeholder) {
|
||||
return
|
||||
}
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
MIND_MAP,
|
||||
ORGANIZATION_STRUCTURE,
|
||||
CATALOG_ORGANIZATION,
|
||||
TIMELINE,
|
||||
TIMELINE2,
|
||||
VERTICAL_TIMELINE,
|
||||
FISHBONE
|
||||
} = CONSTANTS.LAYOUT
|
||||
this.overlapNode = null
|
||||
this.prevNode = null
|
||||
this.nextNode = null
|
||||
this.placeholder.size(0, 0)
|
||||
this.placeHolderLine.hide()
|
||||
this.removeExtraLines()
|
||||
this.nodeList.forEach(node => {
|
||||
if (node.getData('isActive')) {
|
||||
this.mindMap.execCommand('SET_NODE_ACTIVE', node, false)
|
||||
@ -350,52 +388,310 @@ class Drag extends Base {
|
||||
return
|
||||
}
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case 'logicalStructure':
|
||||
case LOGICAL_STRUCTURE:
|
||||
this.handleLogicalStructure(node)
|
||||
break
|
||||
case 'mindMap':
|
||||
case MIND_MAP:
|
||||
this.handleMindMap(node)
|
||||
break
|
||||
case 'organizationStructure':
|
||||
case ORGANIZATION_STRUCTURE:
|
||||
this.handleOrganizationStructure(node)
|
||||
break
|
||||
case 'catalogOrganization':
|
||||
case CATALOG_ORGANIZATION:
|
||||
this.handleCatalogOrganization(node)
|
||||
break
|
||||
case 'timeline':
|
||||
case TIMELINE:
|
||||
this.handleTimeLine(node)
|
||||
break
|
||||
case 'timeline2':
|
||||
case TIMELINE2:
|
||||
this.handleTimeLine2(node)
|
||||
break
|
||||
case 'verticalTimeline':
|
||||
case VERTICAL_TIMELINE:
|
||||
this.handleLogicalStructure(node)
|
||||
break
|
||||
case 'fishbone':
|
||||
case FISHBONE:
|
||||
this.handleFishbone(node)
|
||||
break
|
||||
default:
|
||||
this.handleLogicalStructure(node)
|
||||
}
|
||||
})
|
||||
// 重叠节点,也就是添加为子节点
|
||||
if (this.overlapNode) {
|
||||
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
|
||||
this.handleOverlapNode()
|
||||
}
|
||||
}
|
||||
|
||||
// 处理作为子节点的情况
|
||||
handleOverlapNode() {
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
MIND_MAP,
|
||||
ORGANIZATION_STRUCTURE,
|
||||
CATALOG_ORGANIZATION,
|
||||
TIMELINE,
|
||||
TIMELINE2,
|
||||
VERTICAL_TIMELINE,
|
||||
FISHBONE
|
||||
} = CONSTANTS.LAYOUT
|
||||
const { LEFT, TOP, RIGHT, BOTTOM } = CONSTANTS.LAYOUT_GROW_DIR
|
||||
const layerIndex = this.overlapNode.layerIndex
|
||||
const children = this.overlapNode.children
|
||||
const marginX = this.mindMap.renderer.layout.getMarginX(layerIndex + 1)
|
||||
const marginY = this.mindMap.renderer.layout.getMarginY(layerIndex + 1)
|
||||
const halfPlaceholderWidth = this.placeholderWidth / 2
|
||||
const halfPlaceholderHeight = this.placeholderHeight / 2
|
||||
let dir = ''
|
||||
let x = ''
|
||||
let y = ''
|
||||
let rotate = false
|
||||
let notRenderPlaceholder = false
|
||||
// 目标节点存在子节点,那么基于最后一个子节点定位
|
||||
if (children.length > 0) {
|
||||
const lastChild = children[children.length - 1]
|
||||
const lastNodeRect = this.getNodeRect(lastChild)
|
||||
dir = this.getNewChildNodeDir(lastChild)
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case LOGICAL_STRUCTURE:
|
||||
case MIND_MAP:
|
||||
x =
|
||||
dir === LEFT
|
||||
? lastNodeRect.originRight - this.placeholderWidth
|
||||
: lastNodeRect.originLeft
|
||||
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
break
|
||||
case ORGANIZATION_STRUCTURE:
|
||||
rotate = true
|
||||
x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
|
||||
y = lastNodeRect.originTop
|
||||
break
|
||||
case CATALOG_ORGANIZATION:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
x =
|
||||
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
|
||||
y = lastNodeRect.originTop
|
||||
} else {
|
||||
x = lastNodeRect.originLeft
|
||||
y =
|
||||
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
}
|
||||
break
|
||||
case TIMELINE:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
x =
|
||||
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
|
||||
y =
|
||||
lastNodeRect.originTop +
|
||||
lastNodeRect.originHeight / 2 -
|
||||
halfPlaceholderWidth
|
||||
} else {
|
||||
x = lastNodeRect.originLeft
|
||||
y =
|
||||
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
}
|
||||
break
|
||||
case TIMELINE2:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
x =
|
||||
lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
|
||||
y =
|
||||
lastNodeRect.originTop +
|
||||
lastNodeRect.originHeight / 2 -
|
||||
halfPlaceholderWidth
|
||||
} else {
|
||||
x = lastNodeRect.originLeft
|
||||
if (layerIndex === 1) {
|
||||
y =
|
||||
dir === TOP
|
||||
? lastNodeRect.originTop -
|
||||
this.placeholderHeight -
|
||||
this.minOffset +
|
||||
halfPlaceholderHeight
|
||||
: lastNodeRect.originBottom +
|
||||
this.minOffset -
|
||||
halfPlaceholderHeight
|
||||
} else {
|
||||
y =
|
||||
lastNodeRect.originBottom +
|
||||
this.minOffset -
|
||||
halfPlaceholderHeight
|
||||
}
|
||||
}
|
||||
break
|
||||
case VERTICAL_TIMELINE:
|
||||
if (layerIndex === 0) {
|
||||
x =
|
||||
lastNodeRect.originLeft +
|
||||
lastNodeRect.originWidth / 2 -
|
||||
halfPlaceholderWidth
|
||||
y =
|
||||
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
} else {
|
||||
x =
|
||||
dir === RIGHT
|
||||
? lastNodeRect.originLeft
|
||||
: lastNodeRect.originRight - this.placeholderWidth
|
||||
y =
|
||||
lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
}
|
||||
break
|
||||
case FISHBONE:
|
||||
if (layerIndex <= 1) {
|
||||
notRenderPlaceholder = true
|
||||
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
|
||||
} else {
|
||||
x = lastNodeRect.originLeft
|
||||
y =
|
||||
dir === TOP
|
||||
? lastNodeRect.originBottom +
|
||||
this.minOffset -
|
||||
halfPlaceholderHeight
|
||||
: lastNodeRect.originTop -
|
||||
this.placeholderHeight -
|
||||
this.minOffset +
|
||||
halfPlaceholderHeight
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
// 目标节点不存在子节点,那么基于目标节点定位
|
||||
const nodeRect = this.getNodeRect(this.overlapNode)
|
||||
dir = this.getNewChildNodeDir(this.overlapNode)
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case LOGICAL_STRUCTURE:
|
||||
case MIND_MAP:
|
||||
x =
|
||||
dir === RIGHT
|
||||
? nodeRect.originRight + marginX
|
||||
: nodeRect.originLeft - this.placeholderWidth - marginX
|
||||
y =
|
||||
nodeRect.originTop +
|
||||
(nodeRect.originHeight - this.placeholderHeight) / 2
|
||||
break
|
||||
case ORGANIZATION_STRUCTURE:
|
||||
rotate = true
|
||||
x =
|
||||
nodeRect.originLeft +
|
||||
(nodeRect.originWidth - this.placeholderHeight) / 2
|
||||
y = nodeRect.originBottom + marginX
|
||||
break
|
||||
case CATALOG_ORGANIZATION:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
}
|
||||
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
|
||||
y = nodeRect.originBottom + marginX
|
||||
break
|
||||
case TIMELINE:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
}
|
||||
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
|
||||
y = nodeRect.originBottom + marginY
|
||||
break
|
||||
case TIMELINE2:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
}
|
||||
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
|
||||
if (layerIndex === 1) {
|
||||
y =
|
||||
dir === TOP
|
||||
? nodeRect.originTop - this.placeholderHeight - marginX
|
||||
: nodeRect.originBottom + marginX
|
||||
} else {
|
||||
y = nodeRect.originBottom + marginX
|
||||
}
|
||||
break
|
||||
case VERTICAL_TIMELINE:
|
||||
if (layerIndex === 0) {
|
||||
rotate = true
|
||||
}
|
||||
x =
|
||||
dir === RIGHT
|
||||
? nodeRect.originRight + marginX
|
||||
: nodeRect.originLeft - this.placeholderWidth - marginX
|
||||
y =
|
||||
nodeRect.originTop +
|
||||
nodeRect.originHeight / 2 -
|
||||
halfPlaceholderHeight
|
||||
break
|
||||
case FISHBONE:
|
||||
if (layerIndex <= 1) {
|
||||
notRenderPlaceholder = true
|
||||
this.mindMap.execCommand('SET_NODE_ACTIVE', this.overlapNode, true)
|
||||
} else {
|
||||
x = nodeRect.originLeft + nodeRect.originWidth * 0.5
|
||||
y =
|
||||
dir === BOTTOM
|
||||
? nodeRect.originTop -
|
||||
this.placeholderHeight -
|
||||
this.minOffset +
|
||||
halfPlaceholderHeight
|
||||
: nodeRect.originBottom + this.minOffset - halfPlaceholderHeight
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
if (!notRenderPlaceholder) {
|
||||
this.setPlaceholderRect({
|
||||
x,
|
||||
y,
|
||||
dir,
|
||||
rotate
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取节点的生长方向
|
||||
getNewChildNodeDir(node) {
|
||||
const {
|
||||
LOGICAL_STRUCTURE,
|
||||
MIND_MAP,
|
||||
TIMELINE2,
|
||||
VERTICAL_TIMELINE,
|
||||
FISHBONE
|
||||
} = CONSTANTS.LAYOUT
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case LOGICAL_STRUCTURE:
|
||||
return CONSTANTS.LAYOUT_GROW_DIR.RIGHT
|
||||
case MIND_MAP:
|
||||
case TIMELINE2:
|
||||
case VERTICAL_TIMELINE:
|
||||
case FISHBONE:
|
||||
return node.dir
|
||||
default:
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
// 垂直方向比较
|
||||
// isReverse:是否反向
|
||||
handleVerticalCheck(node, checkList, isReverse = false) {
|
||||
let x = this.mouseMoveX
|
||||
let y = this.mouseMoveY
|
||||
let nodeRect = this.getNodeRect(node)
|
||||
if (isReverse) {
|
||||
const { layout } = this.mindMap.opt
|
||||
const { LAYOUT, LAYOUT_GROW_DIR } = CONSTANTS
|
||||
const { VERTICAL_TIMELINE, FISHBONE } = LAYOUT
|
||||
const { BOTTOM, LEFT } = LAYOUT_GROW_DIR
|
||||
const mouseMoveX = this.mouseMoveX
|
||||
const mouseMoveY = this.mouseMoveY
|
||||
const nodeRect = this.getNodeRect(node)
|
||||
const dir = this.getNewChildNodeDir(node)
|
||||
const layerIndex = node.layerIndex
|
||||
if (
|
||||
isReverse ||
|
||||
(layout === FISHBONE && dir === BOTTOM && layerIndex >= 3)
|
||||
) {
|
||||
checkList = checkList.reverse()
|
||||
}
|
||||
let oneFourthHeight = nodeRect.height / 4
|
||||
let oneFourthHeight = nodeRect.originHeight / 4
|
||||
let { prevBrotherOffset, nextBrotherOffset } =
|
||||
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'v')
|
||||
if (nodeRect.left <= x && nodeRect.right >= x) {
|
||||
if (nodeRect.left <= mouseMoveX && nodeRect.right >= mouseMoveX) {
|
||||
// 检测兄弟节点位置
|
||||
if (
|
||||
!this.overlapNode &&
|
||||
@ -405,38 +701,92 @@ class Drag extends Base {
|
||||
) {
|
||||
let checkIsPrevNode =
|
||||
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
|
||||
? y > nodeRect.bottom && y <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点外底部判断
|
||||
: y >= nodeRect.bottom - oneFourthHeight && y <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
|
||||
? mouseMoveY > nodeRect.bottom &&
|
||||
mouseMoveY <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点外底部判断
|
||||
: mouseMoveY >= nodeRect.bottom - oneFourthHeight &&
|
||||
mouseMoveY <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
|
||||
let checkIsNextNode =
|
||||
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
|
||||
? y < nodeRect.top && y >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
|
||||
: y >= nodeRect.top && y <= nodeRect.top + oneFourthHeight
|
||||
? mouseMoveY < nodeRect.top &&
|
||||
mouseMoveY >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
|
||||
: mouseMoveY >= nodeRect.top &&
|
||||
mouseMoveY <= nodeRect.top + oneFourthHeight
|
||||
|
||||
const { scaleY } = this.drawTransform
|
||||
let x =
|
||||
dir === LEFT
|
||||
? nodeRect.originRight - this.placeholderWidth
|
||||
: nodeRect.originLeft
|
||||
let notRenderLine = false
|
||||
switch (layout) {
|
||||
case VERTICAL_TIMELINE:
|
||||
if (layerIndex === 1) {
|
||||
x =
|
||||
nodeRect.originLeft +
|
||||
nodeRect.originWidth / 2 -
|
||||
this.placeholderWidth / 2
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
if (checkIsPrevNode) {
|
||||
if (isReverse) {
|
||||
this.nextNode = node
|
||||
} else {
|
||||
this.prevNode = node
|
||||
}
|
||||
let size = this.formatPlaceholderSize(nextBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
node.width,
|
||||
size,
|
||||
nodeRect.originLeft,
|
||||
nodeRect.originBottom
|
||||
)
|
||||
let y =
|
||||
nodeRect.originBottom +
|
||||
nextBrotherOffset / scaleY - //nextBrotherOffset已经是实际间距的一半了
|
||||
this.placeholderHeight / 2
|
||||
switch (layout) {
|
||||
case FISHBONE:
|
||||
if (layerIndex === 2) {
|
||||
notRenderLine = true
|
||||
y =
|
||||
nodeRect.originBottom +
|
||||
this.minOffset -
|
||||
this.placeholderHeight / 2
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
this.setPlaceholderRect({
|
||||
x,
|
||||
y,
|
||||
dir,
|
||||
notRenderLine
|
||||
})
|
||||
} else if (checkIsNextNode) {
|
||||
if (isReverse) {
|
||||
this.prevNode = node
|
||||
} else {
|
||||
this.nextNode = node
|
||||
}
|
||||
let size = this.formatPlaceholderSize(prevBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
node.width,
|
||||
size,
|
||||
nodeRect.originLeft,
|
||||
nodeRect.originTop - size
|
||||
)
|
||||
let y =
|
||||
nodeRect.originTop -
|
||||
this.placeholderHeight -
|
||||
prevBrotherOffset / scaleY +
|
||||
this.placeholderHeight / 2
|
||||
switch (layout) {
|
||||
case FISHBONE:
|
||||
if (layerIndex === 2) {
|
||||
notRenderLine = true
|
||||
y =
|
||||
nodeRect.originTop -
|
||||
this.placeholderHeight -
|
||||
this.minOffset +
|
||||
this.placeholderHeight / 2
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
this.setPlaceholderRect({
|
||||
x,
|
||||
y,
|
||||
dir,
|
||||
notRenderLine
|
||||
})
|
||||
}
|
||||
}
|
||||
// 检测是否重叠
|
||||
@ -446,7 +796,7 @@ class Drag extends Base {
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset,
|
||||
size: oneFourthHeight,
|
||||
pos: y,
|
||||
pos: mouseMoveY,
|
||||
nodeRect
|
||||
})
|
||||
}
|
||||
@ -454,13 +804,16 @@ class Drag extends Base {
|
||||
|
||||
// 水平方向比较
|
||||
handleHorizontalCheck(node, checkList) {
|
||||
let x = this.mouseMoveX
|
||||
let y = this.mouseMoveY
|
||||
const { layout } = this.mindMap.opt
|
||||
const { LAYOUT } = CONSTANTS
|
||||
const { FISHBONE, TIMELINE, TIMELINE2 } = LAYOUT
|
||||
let mouseMoveX = this.mouseMoveX
|
||||
let mouseMoveY = this.mouseMoveY
|
||||
let nodeRect = this.getNodeRect(node)
|
||||
let oneFourthWidth = nodeRect.width / 4
|
||||
let oneFourthWidth = nodeRect.originWidth / 4
|
||||
let { prevBrotherOffset, nextBrotherOffset } =
|
||||
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'h')
|
||||
if (nodeRect.top <= y && nodeRect.bottom >= y) {
|
||||
if (nodeRect.top <= mouseMoveY && nodeRect.bottom >= mouseMoveY) {
|
||||
// 检测兄弟节点位置
|
||||
if (
|
||||
!this.overlapNode &&
|
||||
@ -470,30 +823,62 @@ class Drag extends Base {
|
||||
) {
|
||||
let checkIsPrevNode =
|
||||
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
|
||||
? x < nodeRect.right + nextBrotherOffset && x >= nodeRect.right // 那么在当前节点外底部判断
|
||||
: x <= nodeRect.right && x >= nodeRect.right - oneFourthWidth // 否则在当前节点内底部1/4区间判断
|
||||
? mouseMoveX < nodeRect.right + nextBrotherOffset &&
|
||||
mouseMoveX >= nodeRect.right // 那么在当前节点外底部判断
|
||||
: mouseMoveX <= nodeRect.right &&
|
||||
mouseMoveX >= nodeRect.right - oneFourthWidth // 否则在当前节点内底部1/4区间判断
|
||||
let checkIsNextNode =
|
||||
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
|
||||
? x > nodeRect.left - prevBrotherOffset && x <= nodeRect.left // 那么在当前节点外底部判断
|
||||
: x <= nodeRect.left + oneFourthWidth && x >= nodeRect.left
|
||||
? mouseMoveX > nodeRect.left - prevBrotherOffset &&
|
||||
mouseMoveX <= nodeRect.left // 那么在当前节点外底部判断
|
||||
: mouseMoveX <= nodeRect.left + oneFourthWidth &&
|
||||
mouseMoveX >= nodeRect.left
|
||||
const { scaleX } = this.drawTransform
|
||||
const layerIndex = node.layerIndex
|
||||
let y = nodeRect.originTop
|
||||
let notRenderLine = false
|
||||
switch (layout) {
|
||||
case TIMELINE:
|
||||
case TIMELINE2:
|
||||
y =
|
||||
nodeRect.originTop +
|
||||
nodeRect.originHeight / 2 -
|
||||
this.placeholderWidth / 2
|
||||
break
|
||||
case FISHBONE:
|
||||
if (layerIndex === 1) {
|
||||
notRenderLine = true
|
||||
y =
|
||||
nodeRect.originTop +
|
||||
nodeRect.originHeight / 2 -
|
||||
this.placeholderWidth / 2
|
||||
}
|
||||
break
|
||||
default:
|
||||
}
|
||||
if (checkIsPrevNode) {
|
||||
this.prevNode = node
|
||||
let size = this.formatPlaceholderSize(nextBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
size,
|
||||
node.height,
|
||||
nodeRect.originRight,
|
||||
nodeRect.originTop
|
||||
)
|
||||
this.setPlaceholderRect({
|
||||
x:
|
||||
nodeRect.originRight +
|
||||
nextBrotherOffset / scaleX - //nextBrotherOffset已经是实际间距的一半了
|
||||
this.placeholderHeight / 2,
|
||||
y,
|
||||
rotate: true,
|
||||
notRenderLine
|
||||
})
|
||||
} else if (checkIsNextNode) {
|
||||
this.nextNode = node
|
||||
let size = this.formatPlaceholderSize(prevBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
size,
|
||||
node.height,
|
||||
nodeRect.originLeft - size,
|
||||
nodeRect.originTop
|
||||
)
|
||||
this.setPlaceholderRect({
|
||||
x:
|
||||
nodeRect.originLeft -
|
||||
this.placeholderHeight -
|
||||
prevBrotherOffset / scaleX +
|
||||
this.placeholderHeight / 2,
|
||||
y,
|
||||
rotate: true,
|
||||
notRenderLine
|
||||
})
|
||||
}
|
||||
}
|
||||
// 检测是否重叠
|
||||
@ -503,7 +888,7 @@ class Drag extends Base {
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset,
|
||||
size: oneFourthWidth,
|
||||
pos: x,
|
||||
pos: mouseMoveX,
|
||||
nodeRect
|
||||
})
|
||||
}
|
||||
@ -511,8 +896,12 @@ class Drag extends Base {
|
||||
|
||||
// 获取节点距前一个和后一个节点的距离
|
||||
getNodeDistanceToSiblingNode(checkList, node, nodeRect, dir) {
|
||||
let dir1 = dir === 'v' ? 'top' : 'left'
|
||||
let dir2 = dir === 'v' ? 'bottom' : 'right'
|
||||
const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
|
||||
let { scaleX, scaleY } = this.drawTransform
|
||||
let dir1 = dir === 'v' ? TOP : LEFT
|
||||
let dir2 = dir === 'v' ? BOTTOM : RIGHT
|
||||
let scale = dir === 'v' ? scaleY : scaleX
|
||||
let minOffset = this.minOffset * scale
|
||||
let index = getNodeIndexInNodeList(node, checkList)
|
||||
let prevBrother = null
|
||||
let nextBrother = null
|
||||
@ -531,10 +920,10 @@ class Drag extends Base {
|
||||
prevBrotherOffset = nodeRect[dir1] - prevNodeRect[dir2]
|
||||
// 间距小于10就当它不存在
|
||||
prevBrotherOffset =
|
||||
prevBrotherOffset >= this.minOffset ? prevBrotherOffset / 2 : 0
|
||||
prevBrotherOffset >= minOffset ? prevBrotherOffset / 2 : 0
|
||||
} else {
|
||||
// 没有前一个兄弟节点,那么假设和前一个节点的距离为20
|
||||
prevBrotherOffset = this.minOffset
|
||||
prevBrotherOffset = minOffset
|
||||
}
|
||||
// 和后一个兄弟节点的距离
|
||||
let nextBrotherOffset = 0
|
||||
@ -542,25 +931,70 @@ class Drag extends Base {
|
||||
let nextNodeRect = this.getNodeRect(nextBrother)
|
||||
nextBrotherOffset = nextNodeRect[dir1] - nodeRect[dir2]
|
||||
nextBrotherOffset =
|
||||
nextBrotherOffset >= this.minOffset ? nextBrotherOffset / 2 : 0
|
||||
nextBrotherOffset >= minOffset ? nextBrotherOffset / 2 : 0
|
||||
} else {
|
||||
nextBrotherOffset = this.minOffset
|
||||
nextBrotherOffset = minOffset
|
||||
}
|
||||
return {
|
||||
prevBrother,
|
||||
prevBrotherOffset,
|
||||
nextBrother,
|
||||
nextBrotherOffset
|
||||
}
|
||||
}
|
||||
|
||||
// 处理提示元素的大小
|
||||
formatPlaceholderSize(size) {
|
||||
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
|
||||
return size > 0 ? Math.min(size, nodeDragPlaceholderMaxSize) : 5
|
||||
}
|
||||
|
||||
// 设置提示元素的大小和位置
|
||||
setPlaceholderRect(w, h, x, y) {
|
||||
setPlaceholderRect({ x, y, dir, rotate, notRenderLine }) {
|
||||
let w = this.placeholderWidth
|
||||
let h = this.placeholderHeight
|
||||
if (rotate) {
|
||||
const tmp = w
|
||||
w = h
|
||||
h = tmp
|
||||
}
|
||||
this.placeholder.size(w, h).move(x, y)
|
||||
if (notRenderLine) {
|
||||
return
|
||||
}
|
||||
const { dragPlaceholderLineConfig } = this.mindMap.opt
|
||||
let node = null
|
||||
let parent = null
|
||||
if (this.overlapNode) {
|
||||
node = this.overlapNode
|
||||
parent = this.overlapNode
|
||||
} else {
|
||||
node = this.prevNode || this.nextNode
|
||||
parent = node.parent
|
||||
}
|
||||
parent = parent.fakeClone()
|
||||
node = node.fakeClone()
|
||||
const tmpNode = this.beingDragNodeList[0].fakeClone()
|
||||
tmpNode.dir = dir
|
||||
tmpNode.left = x
|
||||
tmpNode.top = y
|
||||
tmpNode.width = w
|
||||
tmpNode.height = h
|
||||
parent.children = [tmpNode]
|
||||
parent._lines = []
|
||||
this.placeHolderLine.show()
|
||||
this.mindMap.renderer.layout.renderLine(
|
||||
parent,
|
||||
[this.placeHolderLine],
|
||||
(...args) => {
|
||||
// node.styleLine(...args)
|
||||
},
|
||||
node.style.getStyle('lineStyle', true)
|
||||
)
|
||||
this.placeHolderExtraLines = [...parent._lines]
|
||||
this.placeHolderExtraLines.forEach(line => {
|
||||
this.mindMap.otherDraw.add(line)
|
||||
line
|
||||
.stroke({
|
||||
color: dragPlaceholderLineConfig.color,
|
||||
width: dragPlaceholderLineConfig.width
|
||||
})
|
||||
.fill({ color: 'none' })
|
||||
})
|
||||
}
|
||||
|
||||
// 检测是否重叠
|
||||
@ -573,8 +1007,9 @@ class Drag extends Base {
|
||||
pos,
|
||||
nodeRect
|
||||
}) {
|
||||
let dir1 = dir === 'v' ? 'top' : 'left'
|
||||
let dir2 = dir === 'v' ? 'bottom' : 'right'
|
||||
const { TOP, LEFT, BOTTOM, RIGHT } = CONSTANTS.LAYOUT_GROW_DIR
|
||||
let dir1 = dir === 'v' ? TOP : LEFT
|
||||
let dir2 = dir === 'v' ? BOTTOM : RIGHT
|
||||
if (!this.overlapNode && !this.prevNode && !this.nextNode) {
|
||||
if (
|
||||
nodeRect[dir1] + (prevBrotherOffset > 0 ? 0 : size) <= pos &&
|
||||
@ -638,7 +1073,7 @@ class Drag extends Base {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
|
||||
if (node.dir === 'top' && node.layerIndex === 2) {
|
||||
if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
|
||||
this.handleVerticalCheck(node, checkList, true)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
@ -657,7 +1092,7 @@ class Drag extends Base {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
|
||||
if (node.dir === 'top' && node.layerIndex === 2) {
|
||||
if (node.dir === CONSTANTS.LAYOUT_GROW_DIR.TOP && node.layerIndex === 2) {
|
||||
this.handleVerticalCheck(node, checkList, true)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
@ -678,6 +1113,8 @@ class Drag extends Base {
|
||||
getNodeRect(node) {
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
let { left, top, width, height } = node
|
||||
let originWidth = width
|
||||
let originHeight = height
|
||||
let originLeft = left
|
||||
let originTop = top
|
||||
let originBottom = top + height
|
||||
@ -687,12 +1124,12 @@ class Drag extends Base {
|
||||
left = left * scaleX + translateX
|
||||
top = top * scaleY + translateY
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom,
|
||||
originWidth,
|
||||
originHeight,
|
||||
originLeft,
|
||||
originTop,
|
||||
originBottom,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user