From bb2502501e1e1595fc620ba04f0471bffc38fdcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Sat, 11 May 2024 10:05:46 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A1.=E6=BC=94=E7=A4=BA=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E4=B8=AD=E7=A6=81=E6=AD=A2=E7=94=BB=E5=B8=83=E7=9A=84?= =?UTF-8?q?=E6=89=80=E6=9C=89=E5=86=85=E5=AE=B9=E5=93=8D=E5=BA=94=E9=BC=A0?= =?UTF-8?q?=E6=A0=87=E4=BA=8B=E4=BB=B6=EF=BC=9B2.=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E7=9A=84=E8=B6=85=E9=93=BE=E6=8E=A5=E5=92=8C=E5=A4=87=E6=B3=A8?= =?UTF-8?q?=E5=9B=BE=E6=A0=87=E6=94=AF=E6=8C=81=E5=93=8D=E5=BA=94=E9=BC=A0?= =?UTF-8?q?=E6=A0=87=E4=BA=8B=E4=BB=B6=EF=BC=9B3.=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A1=AB=E7=A9=BA=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/index.js | 17 ++- .../core/render/node/nodeCreateContents.js | 5 +- simple-mind-map/src/plugins/Demonstrate.js | 104 +++++++++++++++--- web/src/pages/Edit/components/Demonstrate.vue | 2 + 4 files changed, 108 insertions(+), 20 deletions(-) diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index f7b26e74..705a45d7 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -128,13 +128,18 @@ class MindMap { // 创建容器元素 initContainer() { const { associativeLineIsAlwaysAboveNode } = this.opt + // 给容器元素添加一个类名 + this.el.classList.add('smm-mind-map-container') // 节点关联线容器 const createAssociativeLineDraw = () => { this.associativeLineDraw = this.draw.group() this.associativeLineDraw.addClass('smm-associative-line-container') } // 画布 - this.svg = SVG().addTo(this.el).size(this.width, this.height) + this.svg = SVG() + .addTo(this.el) + .size(this.width, this.height) + // 容器 this.draw = this.svg.group() this.draw.addClass('smm-container') @@ -432,7 +437,13 @@ class MindMap { // 需要裁减的区域 let clipData = null if (node) { - clipData = getNodeTreeBoundingRect(node, rect.x, rect.y, paddingX, paddingY) + clipData = getNodeTreeBoundingRect( + node, + rect.x, + rect.y, + paddingX, + paddingY + ) } // 内边距 const fixHeight = 0 @@ -581,6 +592,8 @@ class MindMap { this.svg.remove() // 去除给容器元素设置的背景样式 Style.removeBackgroundStyle(this.el) + // 移除给容器元素添加的类名 + this.el.classList.remove('smm-mind-map-container') this.el.innerHTML = '' this.el = null this.removeCss() diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index 984b0fbf..4dc4dcf9 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -316,7 +316,10 @@ function createNoteNode() { return null } let iconSize = this.mindMap.themeConfig.iconSize - let node = new SVG().attr('cursor', 'pointer').size(iconSize, iconSize) + let node = new SVG() + .attr('cursor', 'pointer') + .addClass('smm-node-note') + .size(iconSize, iconSize) // 透明的层,用来作为鼠标区域 node.add(new Rect().size(iconSize, iconSize).fill({ color: 'transparent' })) // 备注图标 diff --git a/simple-mind-map/src/plugins/Demonstrate.js b/simple-mind-map/src/plugins/Demonstrate.js index 044678e9..ec2965e2 100644 --- a/simple-mind-map/src/plugins/Demonstrate.js +++ b/simple-mind-map/src/plugins/Demonstrate.js @@ -14,16 +14,25 @@ const defaultConfig = { transition: 'all 0.3s ease-out', // 高亮框动画的过渡 zIndex: 9999, // 高亮框元素的层级 padding: 20, // 高亮框的内边距 - margin: 50 // 高亮框的外边距 + margin: 50, // 高亮框的外边距 + openBlankMode: true // 是否开启填空模式,即带下划线的文本默认不显示,按回车键才依次显示 } // 演示插件 class Demonstrate { constructor(opt) { this.mindMap = opt.mindMap + // 演示的步骤列表 this.stepList = [] + // 当前所在步骤 this.currentStepIndex = 0 - this.maskEl = null + // 当前所在步骤对应的节点实例 + this.currentStepNode = null + // 当前所在步骤节点的下划线文本数据 + this.currentUnderlineTextData = null + // 临时的样式剩余 + this.tmpStyleEl = null + // 高亮样式元素 this.highlightEl = null this.transformState = null this.renderTree = null @@ -47,6 +56,8 @@ class Demonstrate { } _enter() { + // 添加演示用的临时的样式 + this.addTmpStyles() // 记录演示前的画布状态 this.transformState = this.mindMap.view.getTransformData() // 记录演示前的画布数据 @@ -79,27 +90,53 @@ class Demonstrate { this.transformState = null this.stepList = [] this.currentStepIndex = 0 + this.currentStepNode = null + this.currentUnderlineTextData = null this.unBindEvent() + this.removeTmpStyles() this.removeHighlightEl() this.mindMap.command.recovery() this.mindMap.keyCommand.recovery() this.mindMap.emit('exit_demonstrate') } + // 添加临时的样式 + addTmpStyles() { + this.tmpStyleEl = document.createElement('style') + let cssText = ` + /* 画布所有元素禁止响应鼠标事件 */ + .smm-mind-map-container { + pointer-events: none; + } + /* 超链接图标允许响应鼠标事件 */ + .smm-node a { + pointer-events: all; + } + /* 备注图标允许响应鼠标事件 */ + .smm-node .smm-node-note { + pointer-events: all; + } + ` + if (this.config.openBlankMode) { + cssText += ` + /* 带下划线的文本内容全部隐藏 */ + .smm-richtext-node-wrap u { + opacity: 0; + } + ` + } + this.tmpStyleEl.innerText = cssText + document.head.appendChild(this.tmpStyleEl) + } + + // 移除临时的样式 + removeTmpStyles() { + if (this.tmpStyleEl) document.head.removeChild(this.tmpStyleEl) + } + // 创建高亮元素 createHighlightEl() { if (!this.highlightEl) { - // 遮罩元素 - this.maskEl = document.createElement('div') - this.maskEl.style.cssText = ` - position: absolute; - left: 0; - top: 0; - width: 100%; - height: 100%; - z-index: ${this.config.zIndex}; - ` - this.mindMap.el.appendChild(this.maskEl) // 高亮元素 this.highlightEl = document.createElement('div') this.highlightEl.style.cssText = ` @@ -108,6 +145,7 @@ class Demonstrate { border-radius: ${this.config.borderRadius}; transition: ${this.config.transition}; z-index: ${this.config.zIndex + 1}; + pointer-events: none; ` this.mindMap.el.appendChild(this.highlightEl) } @@ -119,10 +157,6 @@ class Demonstrate { this.mindMap.el.removeChild(this.highlightEl) this.highlightEl = null } - if (this.maskEl) { - this.mindMap.el.removeChild(this.maskEl) - this.maskEl = null - } } // 更新高亮元素的位置和大小 @@ -180,6 +214,9 @@ class Demonstrate { } else if (e.keyCode === keyMap.Esc) { // 退出演示 this.exit() + } else if (e.keyCode === keyMap.Enter) { + // 回车键显示隐藏的下划线文本 + this.showNextUnderlineText() } } @@ -198,8 +235,31 @@ class Demonstrate { } } + // 显示隐藏的下划线文本 + showNextUnderlineText() { + if ( + !this.config.openBlankMode || + !this.currentStepNode || + !this.currentUnderlineTextData + ) + return + const { index, list, length } = this.currentUnderlineTextData + if (index >= length) return + const node = list[index] + this.currentUnderlineTextData.index++ + node.node.style.opacity = 1 + } + // 跳转到某一张 jump(index) { + // 移除该当前下划线元素设置的样式 + if (this.currentUnderlineTextData) { + this.currentUnderlineTextData.list.forEach(item => { + item.node.style.opacity = '' + }) + this.currentUnderlineTextData = null + } + this.currentStepNode = null this.currentStepIndex = index this.mindMap.emit( 'demonstrate_jump', @@ -226,6 +286,16 @@ class Demonstrate { } // 1.聚焦到某个节点 if (step.type === 'node') { + this.currentStepNode = node + // 当前节点存在带下划线的文本内容 + const uNodeList = this.config.openBlankMode ? node.group.find('u') : null + if (uNodeList && uNodeList.length > 0) { + this.currentUnderlineTextData = { + index: 0, + list: uNodeList, + length: uNodeList.length + } + } // 适应画布大小 this.mindMap.view.fit( () => { diff --git a/web/src/pages/Edit/components/Demonstrate.vue b/web/src/pages/Edit/components/Demonstrate.vue index 6e7af1e0..c11acd78 100644 --- a/web/src/pages/Edit/components/Demonstrate.vue +++ b/web/src/pages/Edit/components/Demonstrate.vue @@ -139,6 +139,7 @@ export default { top: 20px; cursor: pointer; z-index: 10001; + pointer-events: all; .icon { font-size: 28px; @@ -150,6 +151,7 @@ export default { position: absolute; right: 40px; bottom: 20px; + pointer-events: all; z-index: 10001; display: flex;