Feat:1.优化节点样式设置,如果设置的是连线样式不触发节点重新创建;2.优化富文本模式下同时对大量节点调用setStyle方法修改文本样式非常慢的问题

This commit is contained in:
街角小林 2024-11-27 19:06:14 +08:00
parent 7258ed9ea7
commit 508d8fe357
5 changed files with 82 additions and 52 deletions

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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
}
}

View File

@ -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'
]

View File

@ -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' }] },