From 508d8fe35735f671f4b959694f55a01c834389bf 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: Wed, 27 Nov 2024 19:06:14 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A1.=E4=BC=98=E5=8C=96=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=A0=B7=E5=BC=8F=E8=AE=BE=E7=BD=AE=EF=BC=8C=E5=A6=82?= =?UTF-8?q?=E6=9E=9C=E8=AE=BE=E7=BD=AE=E7=9A=84=E6=98=AF=E8=BF=9E=E7=BA=BF?= =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E4=B8=8D=E8=A7=A6=E5=8F=91=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=88=9B=E5=BB=BA=EF=BC=9B2.=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AF=8C=E6=96=87=E6=9C=AC=E6=A8=A1=E5=BC=8F=E4=B8=8B?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E5=AF=B9=E5=A4=A7=E9=87=8F=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E8=B0=83=E7=94=A8setStyle=E6=96=B9=E6=B3=95=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E6=96=87=E6=9C=AC=E6=A0=B7=E5=BC=8F=E9=9D=9E=E5=B8=B8=E6=85=A2?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/index.js | 2 +- simple-mind-map/src/core/render/Render.js | 27 ++++++++---- simple-mind-map/src/plugins/RichText.js | 50 +++++++++++------------ simple-mind-map/src/theme/default.js | 39 +++++++++++------- simple-mind-map/src/utils/index.js | 16 +++++++- 5 files changed, 82 insertions(+), 52 deletions(-) diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 946fc500..6b13a4d0 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -336,7 +336,7 @@ class MindMap { this.opt.themeConfig = config if (!notRender) { // 检查改变的是否是节点大小无关的主题属性 - let res = checkIsNodeSizeIndependenceConfig(changedConfig) + const res = checkIsNodeSizeIndependenceConfig(changedConfig) this.render(null, res ? '' : CONSTANTS.CHANGE_THEME) } } diff --git a/simple-mind-map/src/core/render/Render.js b/simple-mind-map/src/core/render/Render.js index f14e67ee..eeacc7b2 100644 --- a/simple-mind-map/src/core/render/Render.js +++ b/simple-mind-map/src/core/render/Render.js @@ -34,7 +34,8 @@ import { formatGetNodeGeneralization, sortNodeList, throttle, - checkClipboardReadEnable + checkClipboardReadEnable, + isNodeNotNeedRenderData } from '../../utils' import { shapeList } from './node/Shape' import { lineStyleProps } from '../../theme/default' @@ -1580,14 +1581,15 @@ class Render { // 设置节点样式 setNodeStyle(node, prop, value) { - let data = { + const data = { [prop]: value } // 如果开启了富文本,则需要应用到富文本上 - if (this.hasRichTextPlugin()) { - this.mindMap.richText.setNotActiveNodeStyle(node, { - [prop]: value - }) + if ( + this.hasRichTextPlugin() && + this.mindMap.richText.isHasRichTextStyle(data) + ) { + data.resetRichText = true } this.setNodeDataRender(node, data) // 更新了连线的样式 @@ -1598,10 +1600,13 @@ class Render { // 设置节点多个样式 setNodeStyles(node, style) { - let data = { ...style } + const data = { ...style } // 如果开启了富文本,则需要应用到富文本上 - if (this.hasRichTextPlugin()) { - this.mindMap.richText.setNotActiveNodeStyle(node, style) + if ( + this.hasRichTextPlugin() && + this.mindMap.richText.isHasRichTextStyle(data) + ) { + data.resetRichText = true } this.setNodeDataRender(node, data) // 更新了连线的样式 @@ -1964,6 +1969,10 @@ class Render { // 设置节点数据,并判断是否渲染 setNodeDataRender(node, data, notRender = false) { this.mindMap.execCommand('SET_NODE_DATA', node, data) + if (isNodeNotNeedRenderData(data)) { + this.mindMap.emit('node_tree_render_end') + return + } this.reRenderNodeCheckChange(node, notRender) } diff --git a/simple-mind-map/src/plugins/RichText.js b/simple-mind-map/src/plugins/RichText.js index e112319e..21ebb457 100644 --- a/simple-mind-map/src/plugins/RichText.js +++ b/simple-mind-map/src/plugins/RichText.js @@ -57,6 +57,14 @@ class RichText { this.isCompositing = false this.textNodePaddingX = 6 this.textNodePaddingY = 4 + this.supportStyleProps = [ + 'fontFamily', + 'fontSize', + 'fontWeight', + 'fontStyle', + 'textDecoration', + 'color' + ] this.initOpt() this.extendQuill() this.appendCss() @@ -675,14 +683,7 @@ class RichText { // 再将样式恢复为当前主题改节点的默认样式 const style = {} if (this.node) { - ;[ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'textDecoration', - 'color' - ].forEach(key => { + this.supportStyleProps.forEach(key => { style[key] = this.node.style.merge(key) }) } @@ -713,14 +714,7 @@ class RichText { if (!this.node) return if (clear) { // 清除文本样式 - ;[ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'textDecoration', - 'color' - ].forEach(prop => { + this.supportStyleProps.forEach(prop => { delete this.node.nodeData.data[prop] }) } else { @@ -795,6 +789,18 @@ class RichText { return data } + // 判断一个对象是否包含了富文本支持的样式字段 + isHasRichTextStyle(obj) { + const keys = Object.keys(obj) + for (let i = 0; i < keys.length; i++) { + const key = keys[i] + if (this.supportStyleProps.includes(key)) { + return true + } + } + return false + } + // 给未激活的节点设置富文本样式 setNotActiveNodeStyle(node, style) { const config = this.normalStyleToRichTextStyle(style) @@ -807,17 +813,9 @@ class RichText { // 检查指定节点是否存在自定义的富文本样式 checkNodeHasCustomRichTextStyle(node) { - const list = [ - 'fontFamily', - 'fontSize', - 'fontWeight', - 'fontStyle', - 'textDecoration', - 'color' - ] const nodeData = node instanceof MindMapNode ? node.getData() : node - for (let i = 0; i < list.length; i++) { - if (nodeData[list[i]] !== undefined) { + for (let i = 0; i < this.supportStyleProps.length; i++) { + if (nodeData[this.supportStyleProps[i]] !== undefined) { return true } } diff --git a/simple-mind-map/src/theme/default.js b/simple-mind-map/src/theme/default.js index 94ddb12d..519ecc95 100644 --- a/simple-mind-map/src/theme/default.js +++ b/simple-mind-map/src/theme/default.js @@ -15,6 +15,12 @@ export default { lineColor: '#549688', // 连线样式 lineDasharray: 'none', + // 连线是否开启流动效果,仅在虚线时有效(需要注册LineFlow插件) + lineFlow: false, + // 流动效果一个周期的时间,单位:s + lineFlowDuration: 1, + // 流动方向是否是从父节点到子节点 + lineFlowForward: true, // 连线风格 lineStyle: 'straight', // 曲线(curve)【仅支持logicalStructure、mindMap、verticalTimeline三种结构】、直线(straight)、直连(direct)【仅支持logicalStructure、mindMap、organizationStructure、verticalTimeline四种结构】 // 曲线连接时,根节点和其他节点的连接线样式保持统一,默认根节点为 ( 型,其他节点为 { 型,设为true后,都为 { 型。仅支持logicalStructure、mindMap两种结构 @@ -88,8 +94,15 @@ export default { hoverRectColor: '', // 点鼠标hover和激活时显示的矩形边框的圆角大小 hoverRectRadius: 5 - // paddingX: 15, - // paddingY: 5 + // 下列样式也支持给节点设置,用于覆盖最外层的设置 + // paddingX, + // paddingY, + // lineWidth, + // lineColor, + // lineDasharray, + // lineFlow, + // lineFlowDuration, + // lineFlowForward }, // 二级节点样式 second: { @@ -115,8 +128,6 @@ export default { lineMarkerDir: 'end', hoverRectColor: '', hoverRectRadius: 5 - // paddingX: 15, - // paddingY: 5 }, // 三级及以下节点样式 node: { @@ -142,8 +153,6 @@ export default { lineMarkerDir: 'end', hoverRectColor: '', hoverRectRadius: 5 - // paddingX: 15, - // paddingY: 5 }, // 概要节点样式 generalization: { @@ -168,8 +177,6 @@ export default { endDir: [1, 0], hoverRectColor: '', hoverRectRadius: 5 - // paddingX: 15, - // paddingY: 5 } } @@ -197,14 +204,12 @@ const nodeSizeIndependenceList = [ 'rootLineKeepSameInCurve', 'rootLineStartPositionKeepSameInCurve', 'showLineMarker', - 'gradientStyle', 'lineRadius', - 'startColor', - 'endColor', - 'startDir', - 'endDir', 'hoverRectColor', - 'hoverRectRadius' + 'hoverRectRadius', + 'lineFlow', + 'lineFlowDuration', + 'lineFlowForward' ] export const checkIsNodeSizeIndependenceConfig = config => { let keys = Object.keys(config) @@ -220,9 +225,13 @@ export const checkIsNodeSizeIndependenceConfig = config => { return true } +// 连线的样式 export const lineStyleProps = [ 'lineColor', 'lineDasharray', 'lineWidth', - 'lineMarkerDir' + 'lineMarkerDir', + 'lineFlow', + 'lineFlowDuration', + 'lineFlowForward' ] diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 9431e641..97a626b7 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -6,6 +6,7 @@ import { import MersenneTwister from './mersenneTwister' import { ForeignObject } from '@svgdotjs/svg.js' import merge from 'deepmerge' +import { lineStyleProps } from '../theme/default' // 深度优先遍历树 export const walk = ( @@ -507,13 +508,14 @@ export const addHtmlStyle = (html, tag, style) => { if (!addHtmlStyleEl) { addHtmlStyleEl = document.createElement('div') } + const tags = Array.isArray(tag) ? tag : [tag] addHtmlStyleEl.innerHTML = html let walk = root => { let childNodes = root.childNodes childNodes.forEach(node => { if (node.nodeType === 1) { // 元素节点 - if (node.tagName.toLowerCase() === tag) { + if (tags.includes(node.tagName.toLowerCase())) { node.style.cssText = style } else { walk(node) @@ -790,6 +792,18 @@ export const checkIsNodeStyleDataKey = key => { return false } +// 判断一个对象是否不需要触发节点重新创建 +export const isNodeNotNeedRenderData = config => { + const list = [...lineStyleProps] // 节点连线样式 + const keys = Object.keys(config) + for (let i = 0; i < keys.length; i++) { + if (!list.includes(keys[i])) { + return false + } + } + return true +} + // 合并图标数组 // const data = [ // { type: 'priority', name: '优先级图标', list: [{ name: '1', icon: 'a' }, { name: 2, icon: 'b' }] },