diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 33711154..022d006a 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -238,5 +238,8 @@ export const defaultOpt = { */ createNewNodeBehavior: CONSTANTS.CREATE_NEW_NODE_BEHAVIOR.DEFAULT, // 当节点图片加载失败时显示的默认图片 - defaultNodeImage: '' + defaultNodeImage: '', + // 是否将思维导图限制在画布内 + // 比如向右拖动时,思维导图图形的最左侧到达画布中心时将无法继续向右拖动,其他同理 + isLimitMindMapInCanvas: false } diff --git a/simple-mind-map/src/core/view/View.js b/simple-mind-map/src/core/view/View.js index 27244e5a..5e89cd60 100644 --- a/simple-mind-map/src/core/view/View.js +++ b/simple-mind-map/src/core/view/View.js @@ -194,6 +194,7 @@ class View { // 应用变换 transform() { + this.limitMindMapInCanvas() this.mindMap.draw.transform({ origin: [0, 0], scale: this.scale, @@ -306,6 +307,64 @@ class View { } this.translateXY(newX, newY) } + + // 将思维导图限制在画布内 + limitMindMapInCanvas() { + if (!this.mindMap.opt.isLimitMindMapInCanvas) return + let { scale, left, top, right, bottom } = this.getPositionLimit() + + // 如果缩放值改变了 + const scaleRatio = this.scale / scale + left *= scaleRatio + right *= scaleRatio + top *= scaleRatio + bottom *= scaleRatio + + // 加上画布中心点距离 + const centerX = this.mindMap.width / 2 + const centerY = this.mindMap.height / 2 + const scaleOffset = this.scale - 1 + left -= scaleOffset * centerX + right -= scaleOffset * centerX + top -= scaleOffset * centerY + bottom -= scaleOffset * centerY + + // 判断是否超出边界 + if (this.x > left) { + this.x = left + } + if (this.x < right) { + this.x = right + } + if (this.y > top) { + this.y = top + } + if (this.y < bottom) { + this.y = bottom + } + } + + // 计算图形四个方向的位置边界值 + getPositionLimit() { + const { scaleX, scaleY } = this.mindMap.draw.transform() + const drawRect = this.mindMap.draw.rbox() + const rootRect = this.mindMap.renderer.root.group.rbox() + const rootCenterOffset = this.mindMap.renderer.layout.getRootCenterOffset( + rootRect.width, + rootRect.height + ) + const left = rootRect.x - drawRect.x - rootCenterOffset.x * scaleX + const right = rootRect.x - drawRect.x2 - rootCenterOffset.x * scaleX + const top = rootRect.y - drawRect.y - rootCenterOffset.y * scaleY + const bottom = rootRect.y - drawRect.y2 - rootCenterOffset.y * scaleY + return { + scale: scaleX, + left, + right, + top, + bottom + } + } } export default View diff --git a/simple-mind-map/src/layouts/Base.js b/simple-mind-map/src/layouts/Base.js index 79d02ab6..6df5ae1f 100644 --- a/simple-mind-map/src/layouts/Base.js +++ b/simple-mind-map/src/layouts/Base.js @@ -168,18 +168,21 @@ class Base { } } + // 规范initRootNodePosition配置 + formatInitRootNodePosition(pos) { + const { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION + if (!pos || !Array.isArray(pos) || pos.length < 2) { + pos = [CENTER, CENTER] + } + return pos + } + // 定位节点到画布中间 setNodeCenter(node, position) { let { initRootNodePosition } = this.mindMap.opt - initRootNodePosition = position || initRootNodePosition - let { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION - if ( - !initRootNodePosition || - !Array.isArray(initRootNodePosition) || - initRootNodePosition.length < 2 - ) { - initRootNodePosition = [CENTER, CENTER] - } + initRootNodePosition = this.formatInitRootNodePosition( + position || initRootNodePosition + ) node.left = this.formatPosition( initRootNodePosition[0], this.mindMap.width, @@ -192,6 +195,38 @@ class Base { ) } + // 当initRootNodePosition配置不为默认的['center','center']时,计算当前配置和默认配置情况下,中心点位置的差值 + getRootCenterOffset(width, height) { + // 如果initRootNodePosition是默认的,那么不需要计算 + let { initRootNodePosition } = this.mindMap.opt + const { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION + initRootNodePosition = this.formatInitRootNodePosition(initRootNodePosition) + if ( + initRootNodePosition[0] === CENTER && + initRootNodePosition[1] === CENTER + ) { + return { + x: 0, + y: 0 + } + } + // 否则需要计算当前配置和默认配置的差值 + const tmpNode = { + width: width, + height: height + } + const tmpNode2 = { + width: width, + height: height + } + this.setNodeCenter(tmpNode, ['center', 'center']) + this.setNodeCenter(tmpNode2) + return { + x: tmpNode2.left - tmpNode.left, + y: tmpNode2.top - tmpNode.top + } + } + // 更新子节点属性 updateChildren(children, prop, offset) { children.forEach(item => {