From e53e41dadcba0240528f65459e8de37358b7c455 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: Tue, 18 Mar 2025 09:35:32 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A1.=E6=96=B0=E5=A2=9EbeforeAddHisto?= =?UTF-8?q?ry=E4=BA=8B=E4=BB=B6=EF=BC=9B2.=E6=96=B0=E5=A2=9E=E5=A4=84?= =?UTF-8?q?=E7=90=86base64=E6=A0=BC=E5=BC=8F=E5=AD=98=E5=82=A8=E7=9A=84?= =?UTF-8?q?=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/full.js | 2 + simple-mind-map/src/constants/constant.js | 3 +- simple-mind-map/src/core/command/Command.js | 1 + .../core/render/node/nodeCreateContents.js | 3 +- .../src/plugins/NodeBase64ImageStorage.js | 100 ++++++++++++++++++ web/src/pages/Edit/components/Edit.vue | 2 + web/src/pages/Edit/components/NodeImage.vue | 2 +- 7 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 simple-mind-map/src/plugins/NodeBase64ImageStorage.js diff --git a/simple-mind-map/full.js b/simple-mind-map/full.js index 761bdf54..66e96b66 100644 --- a/simple-mind-map/full.js +++ b/simple-mind-map/full.js @@ -19,6 +19,7 @@ import RainbowLines from './src/plugins/RainbowLines.js' import Demonstrate from './src/plugins/Demonstrate.js' import OuterFrame from './src/plugins/OuterFrame.js' import MindMapLayoutPro from './src/plugins/MindMapLayoutPro.js' +import NodeBase64ImageStorage from './src/plugins/NodeBase64ImageStorage.js' import xmind from './src/parse/xmind.js' import markdown from './src/parse/markdown.js' import icons from './src/svg/icons.js' @@ -52,5 +53,6 @@ MindMap.usePlugin(MiniMap) .usePlugin(Demonstrate) .usePlugin(OuterFrame) .usePlugin(MindMapLayoutPro) + .usePlugin(NodeBase64ImageStorage) export default MindMap diff --git a/simple-mind-map/src/constants/constant.js b/simple-mind-map/src/constants/constant.js index b1f74a36..f6cc7bf2 100644 --- a/simple-mind-map/src/constants/constant.js +++ b/simple-mind-map/src/constants/constant.js @@ -179,7 +179,8 @@ export const nodeDataNoStylePropList = [ 'customTextWidth', 'checkbox', 'dir', - 'needUpdate'// 重新创建节点内容 + 'needUpdate',// 重新创建节点内容 + 'imgMap' ] // 错误类型 diff --git a/simple-mind-map/src/core/command/Command.js b/simple-mind-map/src/core/command/Command.js index 0aab42d5..ca41ef71 100644 --- a/simple-mind-map/src/core/command/Command.js +++ b/simple-mind-map/src/core/command/Command.js @@ -106,6 +106,7 @@ class Command { if (this.mindMap.opt.readonly || this.isPause) { return } + this.mindMap.emit('beforeAddHistory') const lastData = this.history.length > 0 ? this.history[this.activeHistoryIndex] : null const data = this.getCopyData() diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index b28be580..22876b4a 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -34,10 +34,11 @@ const defaultTagStyle = { // 创建图片节点 function createImgNode() { - const img = this.getData('image') + let img = this.getData('image') if (!img) { return } + img = (this.mindMap.renderer.renderTree.data.imgMap || {})[img] || img const imgSize = this.getImgShowSize() const node = new SVGImage().load(img).size(...imgSize) // 如果指定了加载失败显示的图片,那么加载一下图片检测是否失败 diff --git a/simple-mind-map/src/plugins/NodeBase64ImageStorage.js b/simple-mind-map/src/plugins/NodeBase64ImageStorage.js new file mode 100644 index 00000000..b7f6b977 --- /dev/null +++ b/simple-mind-map/src/plugins/NodeBase64ImageStorage.js @@ -0,0 +1,100 @@ +import { walk, createUid } from '../utils/index' + +// 修改base64格式的节点图片在数据中的存储方式 +// 将base64格式的图片以key-map的形式存储在根节点的imgMap字段里,其他节点只保存key,避免不同的节点引用相同的图片重复存储的问题,普通url格式的图片不处理 +class NodeBase64ImageStorage { + constructor(opt) { + this.opt = opt + this.mindMap = opt.mindMap + this.bindEvent() + } + + bindEvent() { + this.onBeforeAddHistory = this.onBeforeAddHistory.bind(this) + this.mindMap.on('beforeAddHistory', this.onBeforeAddHistory) + } + + unBindEvent() { + this.mindMap.off('beforeAddHistory', this.onBeforeAddHistory) + } + + isBase64ImgUrl(url) { + return /^data:/.test(url) + } + + isImageKey(url) { + return /^smm_img_key_/.test(url) + } + + createImageKey() { + return 'smm_img_key_' + createUid() + } + + onBeforeAddHistory() { + const renderTree = this.mindMap.renderer.renderTree + if (!renderTree) return + let imgMap = renderTree.data.imgMap + if (!imgMap) { + imgMap = renderTree.data.imgMap = {} + } + const useIds = [] + + const getImgIds = () => { + return Object.keys(imgMap) + } + + const getImgId = image => { + return getImgIds().find(id => { + return imgMap[id] === image + }) + } + + walk(renderTree, null, node => { + const image = node.data.image + if (image) { + // 如果是base64图片url + if (this.isBase64ImgUrl(image)) { + // 检查该图片是否已存在 + const hasId = getImgId(image) + if (hasId) { + // 已存在则直接使用现有的key + useIds.push(hasId) + node.data.image = hasId + } else { + // 不存在则生成key,并存储 + const newId = this.createImageKey() + node.data.image = newId + imgMap[newId] = image + useIds.push(newId) + } + } else if (this.isImageKey(image)) { + // 如果是key,那么收集一下 + if (getImgIds().includes(image)) { + useIds.push(image) + } + } + } + }) + + // 删除已无节点引用的图片 + getImgIds().forEach(id => { + if (!useIds.includes(id)) { + delete imgMap[id] + } + }) + } + + // 插件被移除前做的事情 + beforePluginRemove() { + this.unBindEvent() + } + + // 插件被卸载前做的事情 + beforePluginDestroy() { + this.unBindEvent() + } +} + +NodeBase64ImageStorage.instanceName = 'nodeBase64ImageStorage' + +export default NodeBase64ImageStorage diff --git a/web/src/pages/Edit/components/Edit.vue b/web/src/pages/Edit/components/Edit.vue index a660b133..c99a51e5 100644 --- a/web/src/pages/Edit/components/Edit.vue +++ b/web/src/pages/Edit/components/Edit.vue @@ -87,6 +87,7 @@ import RainbowLines from 'simple-mind-map/src/plugins/RainbowLines.js' import Demonstrate from 'simple-mind-map/src/plugins/Demonstrate.js' import OuterFrame from 'simple-mind-map/src/plugins/OuterFrame.js' import MindMapLayoutPro from 'simple-mind-map/src/plugins/MindMapLayoutPro.js' +import NodeBase64ImageStorage from 'simple-mind-map/src/plugins/NodeBase64ImageStorage.js' import Themes from 'simple-mind-map-plugin-themes' // 协同编辑插件 // import Cooperate from 'simple-mind-map/src/plugins/Cooperate.js' @@ -161,6 +162,7 @@ MindMap.usePlugin(MiniMap) .usePlugin(Demonstrate) .usePlugin(OuterFrame) .usePlugin(MindMapLayoutPro) + .usePlugin(NodeBase64ImageStorage) // .usePlugin(Cooperate) // 协同插件 // 注册主题 diff --git a/web/src/pages/Edit/components/NodeImage.vue b/web/src/pages/Edit/components/NodeImage.vue index 91a34ee5..51194ac2 100644 --- a/web/src/pages/Edit/components/NodeImage.vue +++ b/web/src/pages/Edit/components/NodeImage.vue @@ -3,7 +3,7 @@ class="nodeImageDialog" :title="$t('nodeImage.title')" :visible.sync="dialogVisible" - :width="isMobile ? '90%' : '50%'" + :width="isMobile ? '90%' : '600px'" :top="isMobile ? '20px' : '15vh'" >