From a24f7a73c897af5bf20b64513066b7757f1966f3 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Sun, 27 Aug 2023 22:10:49 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E8=8A=82=E7=82=B9=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E9=BC=A0=E6=A0=87=E6=BB=91=E8=BF=87=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E3=80=81=E8=8A=82=E7=82=B9=E6=BF=80=E6=B4=BB=E6=95=88=E6=9E=9C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E3=80=81=E5=8E=BB=E9=99=A4=E6=BF=80=E6=B4=BB?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E6=94=B9=E5=8F=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/index.js | 21 ++++++++++- simple-mind-map/src/constants/constant.js | 22 +++++++++++- .../src/constants/defaultOptions.js | 4 ++- simple-mind-map/src/core/render/Render.js | 4 +-- simple-mind-map/src/core/render/node/Node.js | 35 ++++++++++--------- simple-mind-map/src/core/render/node/Shape.js | 16 ++++++++- simple-mind-map/src/core/render/node/Style.js | 31 ++++++++-------- 7 files changed, 97 insertions(+), 36 deletions(-) diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 8767e978..44ad317f 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -11,7 +11,8 @@ import { layoutValueList, CONSTANTS, commonCaches, - ERROR_TYPES + ERROR_TYPES, + cssContent } from './src/constants/constant' import { SVG } from '@svgdotjs/svg.js' import { simpleDeepClone, getType } from './src/utils' @@ -37,6 +38,10 @@ class MindMap { this.height = this.elRect.height if (this.width <= 0 || this.height <= 0) throw new Error('容器元素el的宽高不能为0') + // 添加css + this.cssEl = null + this.addCss() + // 画布 this.svg = SVG().addTo(this.el).size(this.width, this.height) this.draw = this.svg.group() @@ -101,6 +106,19 @@ class MindMap { return opt } + // 添加css到页面 + addCss() { + this.cssEl = document.createElement('style') + this.cssEl.type = 'text/css' + this.cssEl.innerHTML = cssContent + document.head.appendChild(this.cssEl) + } + + // 移除css + removeCss() { + document.head.removeChild(this.cssEl) + } + // 渲染,部分渲染 render(callback, source = '') { this.batchExecution.push('render', () => { @@ -419,6 +437,7 @@ class MindMap { Style.removeBackgroundStyle(this.el) this.el.innerHTML = '' this.el = null + this.removeCss() } } diff --git a/simple-mind-map/src/constants/constant.js b/simple-mind-map/src/constants/constant.js index 13202200..3a90c01c 100644 --- a/simple-mind-map/src/constants/constant.js +++ b/simple-mind-map/src/constants/constant.js @@ -348,4 +348,24 @@ export const ERROR_TYPES = { export const a4Size = { width: 592.28, height: 841.89 -} \ No newline at end of file +} + +// css +export const cssContent = ` + /* 鼠标hover和激活时渲染的矩形 */ + .smm-hover-node{ + display: none; + opacity: 0.6; + stroke-width: 1; + } + + .smm-node:hover .smm-hover-node{ + display: block; + } + + .smm-node.active .smm-hover-node{ + display: block; + opacity: 1; + stroke-width: 2; + } +` \ No newline at end of file diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 8aeb847b..9cd26ce9 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -168,5 +168,7 @@ export const defaultOpt = { // 开启鼠标双击复位思维导图位置及缩放 enableDblclickReset: true, // 导出图片时canvas的缩放倍数,该配置会和window.devicePixelRatio值取最大值 - minExportImgCanvasScale: 2 + minExportImgCanvasScale: 2, + // 节点鼠标hover和激活时显示的矩形边框颜色 + hoverRectColor: 'rgb(94, 200, 248)' } diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js index 39506d75..b7bb3ba1 100644 --- a/simple-mind-map/src/core/render/Render.js +++ b/simple-mind-map/src/core/render/Render.js @@ -407,7 +407,7 @@ class Render { // 激活节点需要显示展开收起按钮 node.showExpandBtn() setTimeout(() => { - node.updateNodeShape() + node.updateNodeActive() }, 0) } }, @@ -1000,7 +1000,7 @@ class Render { } else { node.hideExpandBtn() } - node.updateNodeShape() + node.updateNodeActive() } // 设置节点是否展开 diff --git a/simple-mind-map/src/core/render/node/Node.js b/simple-mind-map/src/core/render/node/Node.js index f763b650..11eed5f9 100644 --- a/simple-mind-map/src/core/render/node/Node.js +++ b/simple-mind-map/src/core/render/node/Node.js @@ -1,6 +1,6 @@ import Style from './Style' import Shape from './Shape' -import { G, ForeignObject, SVG } from '@svgdotjs/svg.js' +import { G, ForeignObject, SVG, Rect } from '@svgdotjs/svg.js' import nodeGeneralizationMethods from './nodeGeneralization' import nodeExpandBtnMethods from './nodeExpandBtn' import nodeCommandWrapsMethods from './nodeCommandWraps' @@ -58,6 +58,7 @@ class Node { // 节点内容的容器 this.group = null this.shapeNode = null // 节点形状节点 + this.hoverNode = null // 节点hover和激活的节点 // 节点内容对象 this._customNodeContent = null this._imgData = null @@ -277,8 +278,8 @@ class Node { this.shapeNode = this.shapeInstance.createShape() this.shapeNode.addClass('smm-node-shape') this.shapeNode.translate(halfBorderWidth, halfBorderWidth) + this.style.shape(this.shapeNode) this.group.add(this.shapeNode) - this.updateNodeShape() // 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示 this.renderExpandBtnPlaceholderRect() // 概要节点添加一个带所属节点id的类名 @@ -365,6 +366,11 @@ class Node { : 0) ) this.group.add(textContentNested) + // 激活hover和激活边框 + this.hoverNode = new Rect() + this.hoverNode.addClass('smm-hover-node') + this.style.hoverNode(this.hoverNode, width, height) + this.group.add(this.hoverNode) } // 给节点绑定事件 @@ -467,10 +473,11 @@ class Node { } // 更新节点 - update(isLayout = false) { + update() { if (!this.group) { return } + this.updateNodeActive() let { alwaysShowExpandBtn } = this.mindMap.opt if (alwaysShowExpandBtn) { // 需要移除展开收缩按钮 @@ -543,13 +550,11 @@ class Node { return sizeChange } - // 更新节点形状样式 - updateNodeShape() { - if (!this.shapeNode) return - const shape = this.getShape() - this.style[shape === CONSTANTS.SHAPE.RECTANGLE ? 'rect' : 'shape']( - this.shapeNode - ) + // 更新节点激活状态 + updateNodeActive() { + if (!this.group) return + const isActive = this.nodeData.data.isActive + this.group[isActive ? 'addClass' : 'removeClass']('active') } // 递归渲染 @@ -557,9 +562,7 @@ class Node { // 节点 // 重新渲染连线 this.renderLine() - let isLayout = false if (!this.group) { - isLayout = true // 创建组 this.group = new G() this.group.addClass('smm-node') @@ -569,7 +572,7 @@ class Node { this.bindGroupEvent() this.draw.add(this.group) this.layout() - this.update(isLayout) + this.update() } else { this.draw.add(this.group) if (this.needLayout) { @@ -803,8 +806,8 @@ class Node { } // 获取某个样式 - getStyle(prop, root, isActive) { - let v = this.style.merge(prop, root, isActive) + getStyle(prop, root) { + let v = this.style.merge(prop, root) return v === undefined ? '' : v } @@ -833,7 +836,7 @@ class Node { // 获取节点非节点状态的边框大小 getBorderWidth() { - return this.style.merge('borderWidth', false, false) || 0 + return this.style.merge('borderWidth', false) || 0 } // 获取数据 diff --git a/simple-mind-map/src/core/render/node/Shape.js b/simple-mind-map/src/core/render/node/Shape.js index edefc6b2..f6d0e0df 100644 --- a/simple-mind-map/src/core/render/node/Shape.js +++ b/simple-mind-map/src/core/render/node/Shape.js @@ -69,7 +69,8 @@ export default class Shape { let node = null // 矩形 if (shape === CONSTANTS.SHAPE.RECTANGLE) { - node = new Rect().size(width, height) + // node = new Rect().size(width, height) + node = this.createRect() } else if (shape === CONSTANTS.SHAPE.DIAMOND) { // 菱形 node = this.createDiamond() @@ -98,6 +99,19 @@ export default class Shape { return node } + // 创建矩形TODO + createRect() { + let { width, height } = this.node + let borderRadius = this.node.style.merge('borderRadius') + return new Path().plot(` + M${0},0 + L${width},0 + L${width},${height} + L${0},${height} + L${0},${0} + `) + } + // 创建菱形 createDiamond() { let { width, height } = this.node diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index 9cd452d2..325b8989 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -42,7 +42,7 @@ class Style { } // 合并样式 - merge(prop, root, isActive) { + merge(prop, root) { let themeConfig = this.ctx.mindMap.themeConfig // 三级及以下节点 let defaultConfig = themeConfig.node @@ -59,17 +59,6 @@ class Style { // 二级节点 defaultConfig = themeConfig.second } - // 激活状态 - if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) { - if ( - this.ctx.nodeData.data.activeStyle && - this.ctx.nodeData.data.activeStyle[prop] !== undefined - ) { - return this.ctx.nodeData.data.activeStyle[prop] - } else if (defaultConfig.active && defaultConfig.active[prop]) { - return defaultConfig.active[prop] - } - } // 优先使用节点本身的样式 return this.getSelfStyle(prop) !== undefined ? this.getSelfStyle(prop) @@ -77,8 +66,8 @@ class Style { } // 获取某个样式值 - getStyle(prop, root, isActive) { - return this.merge(prop, root, isActive) + getStyle(prop, root) { + return this.merge(prop, root) } // 获取自身自定义样式 @@ -220,6 +209,20 @@ class Style { }) return res } + + // hover和激活节点 + hoverNode(node, width, height) { + const { hoverRectColor } = this.ctx.mindMap.opt + node + .size(width + 0, height + 0) + .x(-0) + .y(-0) + .radius(5) + .fill('none') + .stroke({ + color: hoverRectColor + }) + } } Style.cacheStyle = null