From f20748744a10d1b53443a72d3a01ee5c0fae2259 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Mon, 14 Aug 2023 09:27:59 +0800 Subject: [PATCH 01/83] =?UTF-8?q?Demo=EF=BC=9A=E5=8F=B3=E4=B8=8B=E8=A7=92?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=B7=B3=E8=BD=AC=E7=9B=B8=E5=85=B3=E9=93=BE?= =?UTF-8?q?=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Edit/components/NavigatorToolbar.vue | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/web/src/pages/Edit/components/NavigatorToolbar.vue b/web/src/pages/Edit/components/NavigatorToolbar.vue index 52e4ae4f..5916e7f4 100644 --- a/web/src/pages/Edit/components/NavigatorToolbar.vue +++ b/web/src/pages/Edit/components/NavigatorToolbar.vue @@ -72,9 +72,16 @@ >
- - - + +
+ + Github + 使用文档 + 开发文档 + 官方网站 + 意见反馈 + +
@@ -116,7 +123,7 @@ export default { computed: { ...mapState(['isDark']) }, - created () { + created() { this.lang = getLang() }, methods: { @@ -143,6 +150,33 @@ export default { toggleDark() { this.setIsDark(!this.isDark) + }, + + handleCommand(command) { + let url = '' + switch (command) { + case 'github': + url = 'https://github.com/wanglin2/mind-map' + break + case 'helpDoc': + url = 'https://wanglin2.github.io/mind-map/#/help/zh/' + break + case 'devDoc': + url = 'https://wanglin2.github.io/mind-map/#/doc/zh/introduction/' + break + case 'site': + url = 'https://wanglin2.github.io/mind-map/#/index' + break + case 'issue': + url = 'https://github.com/wanglin2/mind-map/issues/new' + break + default: + break + } + const a = document.createElement('a') + a.href = url + a.target = '_blank' + a.click() } } } From 393410757ba400c1456e67630acd6b62a2648238 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Mon, 14 Aug 2023 09:29:11 +0800 Subject: [PATCH 02/83] =?UTF-8?q?Demo=EF=BC=9A=E8=B0=83=E6=95=B4=E5=B0=8F?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E4=BD=8D=E7=BD=AE=EF=BC=8C=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E8=A2=AB=E4=BE=A7=E8=BE=B9=E6=8C=89=E9=92=AE=E9=81=AE=E6=8C=A1?= =?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 --- web/src/pages/Edit/components/Navigator.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/pages/Edit/components/Navigator.vue b/web/src/pages/Edit/components/Navigator.vue index a8252bc8..b6118776 100644 --- a/web/src/pages/Edit/components/Navigator.vue +++ b/web/src/pages/Edit/components/Navigator.vue @@ -127,7 +127,7 @@ export default { height: 220px; background-color: #fff; bottom: 80px; - right: 20px; + right: 70px; box-shadow: 0 0 16px #989898; border-radius: 4px; border: 1px solid #eee; From ec83976818bad3833e53d802c61bf6b132744111 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Mon, 14 Aug 2023 09:36:10 +0800 Subject: [PATCH 03/83] =?UTF-8?q?Doc=EF=BC=9A=E8=B0=83=E6=95=B4=E9=A6=96?= =?UTF-8?q?=E9=A1=B5=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/pages/Index/components/Block2.vue | 6 +-- web/src/pages/Index/components/Block5.vue | 47 +++++++++++++++-------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/web/src/pages/Index/components/Block2.vue b/web/src/pages/Index/components/Block2.vue index 25f19690..d5bd2c8d 100644 --- a/web/src/pages/Index/components/Block2.vue +++ b/web/src/pages/Index/components/Block2.vue @@ -42,11 +42,11 @@ export default { dataList: [ { icon: 'iconstar', - value: 'Github star数量450+' + value: 'Github star数量600+' }, { icon: 'iconfork', - value: 'Github fork数量100+' + value: 'Github fork数量150+' }, { icon: 'iconxiazai', @@ -54,7 +54,7 @@ export default { }, { icon: 'iconteamwork', - value: '代码贡献者6+' + value: '代码贡献者8+' } ], functionList: [ diff --git a/web/src/pages/Index/components/Block5.vue b/web/src/pages/Index/components/Block5.vue index 90120d62..b97a34f1 100644 --- a/web/src/pages/Index/components/Block5.vue +++ b/web/src/pages/Index/components/Block5.vue @@ -2,9 +2,9 @@
-
街角小林出品
+
理想青年实验室
- 男,90后,六年+前端开发工程师,热爱前端、写作、开源。 + 专注前端、写作、开源。
@@ -52,7 +52,12 @@
更多作品
@@ -67,51 +72,63 @@ export default { linkList: [ { name: 'CodeRun', - url: 'https://github.com/wanglin2/code-run' + url: 'https://github.com/wanglin2/code-run', + desc: '一个代码在线编辑预览工具,类似codepen、jsbin、jsfiddle等' }, { name: 'TinyWhiteboard', - url: 'https://github.com/wanglin2/tiny_whiteboard' + url: 'https://github.com/wanglin2/tiny_whiteboard', + desc: '一个在线小白板,类似excalidraw' }, { name: 'Mark.js', - url: 'https://github.com/wanglin2/markjs' + url: 'https://github.com/wanglin2/markjs', + desc: '一个插件化的多边形标注库' }, { name: 'WebMapEngine', - url: 'https://github.com/wanglin2/web_map_demo' + url: 'https://github.com/wanglin2/web_map_demo', + desc: '一个简单的2D地图加载器' }, { name: 'SimpleNoviceGuide', - url: 'https://github.com/wanglin2/simple-novice-guide' + url: 'https://github.com/wanglin2/simple-novice-guide', + desc: ' 一个简洁的新手引导库' }, { name: 'CanvasEditor', - url: 'https://github.com/wanglin2/canvas-editor-demo' + url: 'https://github.com/wanglin2/canvas-editor-demo', + desc: '一个用Canvas做的富文本编辑器Demo' }, { name: 'JsonTreeView', - url: 'https://github.com/wanglin2/json-tree-view' + url: 'https://github.com/wanglin2/json-tree-view', + desc: '一个简洁的json格式化插件' }, { name: 'SimpleFlowChart', - url: 'https://github.com/wanglin2/simple-flow-chart' + url: 'https://github.com/wanglin2/simple-flow-chart', + desc: '一个用flex布局做的流程设计器' }, { name: 'VideoTimeLine', - url: 'https://github.com/wanglin2/VideoTimeLine' + url: 'https://github.com/wanglin2/VideoTimeLine', + desc: '一个基于Vue2的视频时间轴组件' }, { name: 'MarkdownEditor', - url: 'https://github.com/wanglin2/markdown_editor_sync_scroll_demo' + url: 'https://github.com/wanglin2/markdown_editor_sync_scroll_demo', + desc: '一个能精确同步滚动的Markdown编辑器' }, { name: 'AssociationLine', - url: 'https://github.com/wanglin2/AssociationLineDemo' + url: 'https://github.com/wanglin2/AssociationLineDemo', + desc: '关联线探究,如何连接流程图的两个节点' }, { name: 'HandPaintedStyle', - url: 'https://github.com/wanglin2/handPaintedStyle' + url: 'https://github.com/wanglin2/handPaintedStyle', + desc: '手绘风格图形的简单实现' } ] } From edc63b12933d97ee68c9787d77a870ea4d466a14 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Mon, 14 Aug 2023 09:38:49 +0800 Subject: [PATCH 04/83] =?UTF-8?q?=E6=89=93=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index e0178be7..8d73c924 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ 思绪思维导图
\ No newline at end of file + } \ No newline at end of file From f0e9b76bb57227fa0c3262ce5676f7ca9b34ffd6 Mon Sep 17 00:00:00 2001 From: suka233 <43712875+suka233@users.noreply.github.com> Date: Mon, 14 Aug 2023 15:13:42 +0800 Subject: [PATCH 05/83] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=B0=9D?= =?UTF-8?q?=E8=AF=95=E8=B5=8B=E5=80=BC=E7=BB=99const=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E7=9A=84vite=E5=90=AF=E5=8A=A8dev=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/TouchEvent.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simple-mind-map/src/plugins/TouchEvent.js b/simple-mind-map/src/plugins/TouchEvent.js index 1c91f100..e2a3a741 100644 --- a/simple-mind-map/src/plugins/TouchEvent.js +++ b/simple-mind-map/src/plugins/TouchEvent.js @@ -78,7 +78,7 @@ class TouchEvent { return } const viewBefore = this.touchStartScaleView - const scale = viewBefore.scale * (distance / viewBefore.distance) + let scale = viewBefore.scale * (distance / viewBefore.distance) if (Math.abs(distance - viewBefore.distance) <= 10) { scale = viewBefore.scale } From ffff257f5799b105c4881b139e974c6b22433619 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Tue, 15 Aug 2023 09:03:26 +0800 Subject: [PATCH 06/83] =?UTF-8?q?Demo=EF=BC=9A=E4=BF=AE=E5=A4=8D=E6=89=93?= =?UTF-8?q?=E5=BC=80=E6=9C=AC=E5=9C=B0=E6=96=87=E4=BB=B6=E5=8F=B3=E4=B8=8A?= =?UTF-8?q?=E8=A7=92=E7=9A=84=E6=8F=90=E7=A4=BA=E6=97=A0=E6=B3=95=E5=85=B3?= =?UTF-8?q?=E9=97=AD=E7=9A=84=E9=97=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 4 ++-- web/src/pages/Edit/components/Toolbar.vue | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 8d73c924..86ebbd1a 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ 思绪思维导图
\ No newline at end of file + } \ No newline at end of file diff --git a/web/src/pages/Edit/components/Toolbar.vue b/web/src/pages/Edit/components/Toolbar.vue index 26ff1e71..68a2062d 100644 --- a/web/src/pages/Edit/components/Toolbar.vue +++ b/web/src/pages/Edit/components/Toolbar.vue @@ -354,7 +354,7 @@ export default { title: '提示', message: `当前正在编辑你本机的【${file.name}】文件`, duration: 0, - showClose: false + showClose: true }) } fileReader.readAsText(file) From 002ec41ba88261605c19f4ea0b3ef9bd327a93ea Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Tue, 15 Aug 2023 09:30:00 +0800 Subject: [PATCH 07/83] =?UTF-8?q?Fix=EF=BC=9A=E4=BF=AE=E5=A4=8D=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E6=96=87=E6=9C=AC=E4=B8=BA=E7=A9=BA=E6=97=B6=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E5=BC=82=E5=B8=B8=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/constants/constant.js | 3 +- .../core/render/node/nodeCreateContents.js | 59 ++++++++++++------- 2 files changed, 41 insertions(+), 21 deletions(-) diff --git a/simple-mind-map/src/constants/constant.js b/simple-mind-map/src/constants/constant.js index 3b991fe4..269c2c12 100644 --- a/simple-mind-map/src/constants/constant.js +++ b/simple-mind-map/src/constants/constant.js @@ -330,5 +330,6 @@ export const nodeDataNoStylePropList = [ // 数据缓存 export const commonCaches = { - measureCustomNodeContentSizeEl: null + measureCustomNodeContentSizeEl: null, + measureRichtextNodeTextSizeEl: null } \ No newline at end of file diff --git a/simple-mind-map/src/core/render/node/nodeCreateContents.js b/simple-mind-map/src/core/render/node/nodeCreateContents.js index 2d5268bf..ba19d884 100644 --- a/simple-mind-map/src/core/render/node/nodeCreateContents.js +++ b/simple-mind-map/src/core/render/node/nodeCreateContents.js @@ -1,4 +1,10 @@ -import { measureText, resizeImgSize, removeHtmlStyle, addHtmlStyle, checkIsRichText } from '../../../utils' +import { + measureText, + resizeImgSize, + removeHtmlStyle, + addHtmlStyle, + checkIsRichText +} from '../../../utils' import { Image, SVG, A, G, Rect, Text, ForeignObject } from '@svgdotjs/svg.js' import iconsSvg from '../../../svg/icons' import { CONSTANTS, commonCaches } from '../../../constants/constant' @@ -54,7 +60,10 @@ function createIconNode() { } let iconSize = this.mindMap.themeConfig.iconSize return _data.icon.map(item => { - let src = iconsSvg.getNodeIconListIcon(item, this.mindMap.opt.iconList || []) + let src = iconsSvg.getNodeIconListIcon( + item, + this.mindMap.opt.iconList || [] + ) let node = null // svg图标 if (/^${this.nodeData.data.text}
` - let div = document.createElement('div') + if (!commonCaches.measureRichtextNodeTextSizeEl) { + commonCaches.measureRichtextNodeTextSizeEl = document.createElement('div') + } + let div = commonCaches.measureRichtextNodeTextSizeEl div.innerHTML = html div.style.cssText = `position: fixed; left: -999999px;` let el = div.children[0] @@ -117,12 +129,18 @@ function createRichTextNode() { el.style.maxWidth = this.mindMap.opt.textAutoWrapWidth + 'px' this.mindMap.el.appendChild(div) let { width, height } = el.getBoundingClientRect() - width = Math.ceil(width) + 1// 修复getBoundingClientRect方法对实际宽度是小数的元素获取到的值是整数,导致宽度不够文本发生换行的问题 + // 如果文本为空,那么需要计算一个默认高度 + if (height <= 0) { + div.innerHTML = '

abc123我和你

' + let elTmp = div.children[0] + elTmp.classList.add('smm-richtext-node-wrap') + height = elTmp.getBoundingClientRect().height + } + width = Math.ceil(width) + 1 // 修复getBoundingClientRect方法对实际宽度是小数的元素获取到的值是整数,导致宽度不够文本发生换行的问题 height = Math.ceil(height) g.attr('data-width', width) g.attr('data-height', height) html = div.innerHTML - this.mindMap.el.removeChild(div) let foreignObject = new ForeignObject() foreignObject.width(width) foreignObject.height(height) @@ -274,9 +292,10 @@ function createNoteNode() { box-shadow: 0 2px 5px rgb(0 0 0 / 10%); display: none; background-color: #fff; - z-index: ${ this.mindMap.opt.nodeNoteTooltipZIndex } + z-index: ${this.mindMap.opt.nodeNoteTooltipZIndex} ` - const targetNode = this.mindMap.opt.customInnerElsAppendTo || document.body + const targetNode = + this.mindMap.opt.customInnerElsAppendTo || document.body targetNode.appendChild(this.noteEl) } this.noteEl.innerText = this.nodeData.data.note @@ -310,7 +329,7 @@ function createNoteNode() { } // 测量自定义节点内容元素的宽高 -function measureCustomNodeContentSize (content) { +function measureCustomNodeContentSize(content) { if (!commonCaches.measureCustomNodeContentSizeEl) { commonCaches.measureCustomNodeContentSizeEl = document.createElement('div') commonCaches.measureCustomNodeContentSizeEl.style.cssText = ` @@ -330,19 +349,19 @@ function measureCustomNodeContentSize (content) { } // 是否使用的是自定义节点内容 -function isUseCustomNodeContent() { +function isUseCustomNodeContent() { return !!this._customNodeContent } export default { - createImgNode, - getImgShowSize, - createIconNode, - createRichTextNode, - createTextNode, - createHyperlinkNode, - createTagNode, - createNoteNode, - measureCustomNodeContentSize, - isUseCustomNodeContent -} \ No newline at end of file + createImgNode, + getImgShowSize, + createIconNode, + createRichTextNode, + createTextNode, + createHyperlinkNode, + createTagNode, + createNoteNode, + measureCustomNodeContentSize, + isUseCustomNodeContent +} From 9af8afca220c63ae389819673fbf9d65216db735 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 16 Aug 2023 09:25:33 +0800 Subject: [PATCH 08/83] =?UTF-8?q?Demo=EF=BC=9A=E5=8D=95=E7=8B=AC=E7=BC=96?= =?UTF-8?q?=E8=BE=91=E5=A4=A7=E7=BA=B2=E4=B8=8D=E5=86=8D=E5=92=8C=E7=94=BB?= =?UTF-8?q?=E5=B8=83=E8=81=94=E5=8A=A8=EF=BC=8C=E4=BC=98=E5=8C=96=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E9=87=8F=E4=B8=8B=E7=9A=84=E7=BC=96=E8=BE=91?= =?UTF-8?q?=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/lang/en_us.js | 3 +- web/src/lang/zh_cn.js | 3 +- web/src/pages/Edit/components/Outline.vue | 2 +- web/src/pages/Edit/components/OutlineEdit.vue | 295 +++++++++++++++++- 4 files changed, 292 insertions(+), 11 deletions(-) diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index ca580137..b7a8eb85 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -145,7 +145,8 @@ export default { addTip: 'Press Enter to add' }, outline: { - title: 'Outline' + title: 'Outline', + nodeDefaultText: 'Branch node' }, scale: { zoomIn: 'Zoom in', diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index a3bbb59e..f09ec097 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -145,7 +145,8 @@ export default { addTip: '请按回车键添加' }, outline: { - title: '大纲' + title: '大纲', + nodeDefaultText: '分支节点' }, scale: { zoomIn: '放大', diff --git a/web/src/pages/Edit/components/Outline.vue b/web/src/pages/Edit/components/Outline.vue index 615ae042..11b58824 100644 --- a/web/src/pages/Edit/components/Outline.vue +++ b/web/src/pages/Edit/components/Outline.vue @@ -69,7 +69,7 @@ export default { } }, computed: { - ...mapState(['isDark', 'isOutlineEdit']) + ...mapState(['isDark']) }, created() { window.addEventListener('keydown', this.onKeyDown) diff --git a/web/src/pages/Edit/components/OutlineEdit.vue b/web/src/pages/Edit/components/OutlineEdit.vue index eb125758..7adbf8dd 100644 --- a/web/src/pages/Edit/components/OutlineEdit.vue +++ b/web/src/pages/Edit/components/OutlineEdit.vue @@ -10,7 +10,38 @@
- + + + + +
@@ -18,39 +49,190 @@
\ No newline at end of file + } \ No newline at end of file From 8d1e5dd2e966897ab520db14f7dc98d877b0e199 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 16 Aug 2023 17:17:18 +0800 Subject: [PATCH 10/83] =?UTF-8?q?Feat=EF=BC=9A=E5=AF=BC=E5=87=BAsvg?= =?UTF-8?q?=E7=9A=84=E5=9B=BE=E5=BD=A2=E7=9A=84paddingX=E5=92=8CpaddingY?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=8D=95=E4=BE=A7padding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index c5b6edc6..ec7cb0d9 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -317,9 +317,9 @@ class MindMap { // 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法 const rect = draw.rbox() // 内边距 - rect.width += paddingX - rect.height += paddingY - draw.translate(paddingX / 2, paddingY / 2) + rect.width += paddingX * 2 + rect.height += paddingY * 2 + draw.translate(paddingX, paddingY) // 将svg设置为实际内容的宽高 svg.size(rect.width, rect.height) // 把实际内容变换 From 64209a63929773dcfbbbdb6364fb0262db86025a Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 16 Aug 2023 17:19:35 +0800 Subject: [PATCH 11/83] =?UTF-8?q?Featc=EF=BC=9A=E5=88=A0=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84exportPadding=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8exportPaddingX=E5=92=8Cexpo?= =?UTF-8?q?rtPaddingY=E9=85=8D=E7=BD=AE=EF=BC=9B=E5=8E=BB=E9=99=A4?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=9B=BE=E7=89=87=E6=97=B6=E7=9A=84=E5=8F=8C?= =?UTF-8?q?=E9=87=8Dpadding=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/constants/defaultOptions.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index 7453122d..ff057c76 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -18,8 +18,6 @@ export const defaultOpt = { mouseScaleCenterUseMousePosition: true, // 最多显示几个标签 maxTag: 5, - // 导出图片时的内边距 - exportPadding: 20, // 展开收缩按钮尺寸 expandBtnSize: 20, // 节点里图片和文字的间距 @@ -81,7 +79,7 @@ export const defaultOpt = { enableShortcutOnlyWhenMouseInSvg: true, // 初始根节点的位置 initRootNodePosition: null, - // 导出png、svg、pdf时的图形内边距 + // 导出png、svg、pdf时的图形内边距,注意是单侧内边距 exportPaddingX: 10, exportPaddingY: 10, // 节点文本编辑框的z-index From 3f659af1e1747fc2bcb17abb79a08e33adbf9553 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 16 Aug 2023 17:20:05 +0800 Subject: [PATCH 12/83] =?UTF-8?q?Featc=EF=BC=9A=E5=88=A0=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E7=9A=84exportPadding=E9=85=8D=E7=BD=AE=EF=BC=8C?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8exportPaddingX=E5=92=8Cexpo?= =?UTF-8?q?rtPaddingY=E9=85=8D=E7=BD=AE=EF=BC=9B=E5=8E=BB=E9=99=A4?= =?UTF-8?q?=E5=AF=BC=E5=87=BA=E5=9B=BE=E7=89=87=E6=97=B6=E7=9A=84=E5=8F=8C?= =?UTF-8?q?=E9=87=8Dpadding=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Export.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/simple-mind-map/src/plugins/Export.js b/simple-mind-map/src/plugins/Export.js index a5747595..7820ac72 100644 --- a/simple-mind-map/src/plugins/Export.js +++ b/simple-mind-map/src/plugins/Export.js @@ -8,7 +8,6 @@ class Export { // 构造函数 constructor(opt) { this.mindMap = opt.mindMap - this.exportPadding = this.mindMap.opt.exportPadding } // 导出 @@ -51,14 +50,17 @@ class Export { // svg转png svgToPng(svgSrc, transparent) { return new Promise((resolve, reject) => { + // const { exportPaddingX, exportPaddingY } = this.mindMap.opt + let exportPaddingX = 0 + let exportPaddingY = 0 const img = new Image() // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片 img.setAttribute('crossOrigin', 'anonymous') img.onload = async () => { try { let canvas = document.createElement('canvas') - canvas.width = img.width + this.exportPadding * 2 - canvas.height = img.height + this.exportPadding * 2 + canvas.width = img.width + exportPaddingX * 2 + canvas.height = img.height + exportPaddingY * 2 let ctx = canvas.getContext('2d') // 绘制背景 if (!transparent) { @@ -71,8 +73,8 @@ class Export { 0, img.width, img.height, - this.exportPadding, - this.exportPadding, + exportPaddingX, + exportPaddingY, img.width, img.height ) From efe4aa0ec2294c54a98730c1d18a71ac51f2d2ee Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Wed, 16 Aug 2023 17:45:34 +0800 Subject: [PATCH 13/83] =?UTF-8?q?Feat=EF=BC=9A=E5=AF=BC=E5=87=BApdf?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE=E5=9B=BE=E7=89=87=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=88=86=E9=A1=B5=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Export.js | 4 +- simple-mind-map/src/plugins/ExportPDF.js | 57 +++++++++++++++++++++++- web/src/lang/en_us.js | 3 +- web/src/lang/zh_cn.js | 3 +- web/src/pages/Edit/components/Export.vue | 11 ++++- 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/simple-mind-map/src/plugins/Export.js b/simple-mind-map/src/plugins/Export.js index 7820ac72..13bc95be 100644 --- a/simple-mind-map/src/plugins/Export.js +++ b/simple-mind-map/src/plugins/Export.js @@ -175,12 +175,12 @@ class Export { } // 导出为pdf - async pdf(name) { + async pdf(name, useMultiPageExport) { if (!this.mindMap.doExportPDF) { throw new Error('请注册ExportPDF插件') } let img = await this.png() - this.mindMap.doExportPDF.pdf(name, img) + this.mindMap.doExportPDF.pdf(name, img, useMultiPageExport) } // 导出为xmind diff --git a/simple-mind-map/src/plugins/ExportPDF.js b/simple-mind-map/src/plugins/ExportPDF.js index e46b3a3c..27a81374 100644 --- a/simple-mind-map/src/plugins/ExportPDF.js +++ b/simple-mind-map/src/plugins/ExportPDF.js @@ -8,7 +8,16 @@ class ExportPDF { } // 导出为pdf - pdf(name, img) { + pdf(name, img, useMultiPageExport = false) { + if (useMultiPageExport) { + this.multiPageExport(name, img) + } else { + this.onePageExport(name, img) + } + } + + // 单页导出 + onePageExport(name, img) { let pdf = new JsPDF('', 'pt', 'a4') let a4Width = 595 let a4Height = 841 @@ -37,6 +46,52 @@ class ExportPDF { } image.src = img } + + // 多页导出 + multiPageExport(name, img) { + let image = new Image() + const a4Width = 592.28 + const a4Height = 841.89 + image.onload = () => { + let imageWidth = image.width + let imageHeight = image.height + // 一页pdf显示高度 + let pageHeight = (imageWidth / a4Width) * a4Height + // 未生成pdf的高度 + let leftHeight = imageHeight + // 偏移 + let position = 0 + // a4纸的尺寸[595.28,841.89],图片在pdf中图片的宽高 + let imgWidth = a4Width + let imgHeight = (a4Width / imageWidth) * imageHeight + let pdf = new JsPDF('', 'pt', 'a4') + // 有两个高度需要区分,一个是图片的实际高度,和生成pdf的页面高度(841.89) + // 当内容未超过pdf一页显示的范围,无需分页 + if (leftHeight < pageHeight) { + pdf.addImage( + img, + 'PNG', + (a4Width - imgWidth) / 2, + (a4Height - imgHeight) / 2, + imgWidth, + imgHeight + ) + } else { + // 分页 + while (leftHeight > 0) { + pdf.addImage(img, 'PNG', 0, position, imgWidth, imgHeight) + leftHeight -= pageHeight + position -= a4Height + // 避免添加空白页 + if (leftHeight > 0) { + pdf.addPage() + } + } + } + pdf.save(name) + } + image.src = img + } } ExportPDF.instanceName = 'doExportPDF' diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index b7a8eb85..5302cea9 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -108,7 +108,8 @@ export default { notifyTitle: 'Info', notifyMessage: 'If the download is not triggered, check whether it is blocked by the browser', paddingX: 'Padding x', - paddingY: 'Padding y' + paddingY: 'Padding y', + useMultiPageExport: 'Export multi page' }, fullscreen: { fullscreenShow: 'Full screen show', diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index f09ec097..dca9eb6e 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -108,7 +108,8 @@ export default { notifyTitle: '消息', notifyMessage: '如果没有触发下载,请检查是否被浏览器拦截了', paddingX: '水平内边距', - paddingY: '垂直内边距' + paddingY: '垂直内边距', + useMultiPageExport: '是否多页导出' }, fullscreen: { fullscreenShow: '全屏查看', diff --git a/web/src/pages/Edit/components/Export.vue b/web/src/pages/Edit/components/Export.vue index 35f45957..06552be4 100644 --- a/web/src/pages/Edit/components/Export.vue +++ b/web/src/pages/Edit/components/Export.vue @@ -53,6 +53,12 @@ style="margin-left: 12px" >{{ $t('export.isTransparent') }} + {{ $t('export.useMultiPageExport') }}
Date: Thu, 17 Aug 2023 08:49:40 +0800 Subject: [PATCH 14/83] =?UTF-8?q?Feat=EF=BC=9A=E5=AF=BC=E5=87=BApdf?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE=E9=95=BF=E5=AE=BD=E6=AF=94?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=B0=83=E6=95=B4=E6=96=B9=E5=90=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/plugins/Export.js | 83 ++++++++++++++++++--------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/simple-mind-map/src/plugins/Export.js b/simple-mind-map/src/plugins/Export.js index 13bc95be..779a5829 100644 --- a/simple-mind-map/src/plugins/Export.js +++ b/simple-mind-map/src/plugins/Export.js @@ -1,4 +1,9 @@ -import { imgToDataUrl, downloadFile, readBlob, removeHTMLEntities } from '../utils' +import { + imgToDataUrl, + downloadFile, + readBlob, + removeHTMLEntities +} from '../utils' import { SVG } from '@svgdotjs/svg.js' import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas' import { transformToMarkdown } from '../parse/toMarkdown' @@ -48,23 +53,32 @@ class Export { } // svg转png - svgToPng(svgSrc, transparent) { + svgToPng(svgSrc, transparent, rotateWhenWidthLongerThenHeight = false) { return new Promise((resolve, reject) => { - // const { exportPaddingX, exportPaddingY } = this.mindMap.opt - let exportPaddingX = 0 - let exportPaddingY = 0 const img = new Image() // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片 img.setAttribute('crossOrigin', 'anonymous') img.onload = async () => { try { let canvas = document.createElement('canvas') - canvas.width = img.width + exportPaddingX * 2 - canvas.height = img.height + exportPaddingY * 2 + // 如果宽比高长,那么旋转90度 + let needRotate = + rotateWhenWidthLongerThenHeight && img.width / img.height > 1 + if (needRotate) { + canvas.width = img.height + canvas.height = img.width + } else { + canvas.width = img.width + canvas.height = img.height + } let ctx = canvas.getContext('2d') + if (needRotate) { + ctx.rotate(0.5 * Math.PI) + ctx.translate(0, -img.height) + } // 绘制背景 if (!transparent) { - await this.drawBackgroundToCanvas(ctx, canvas.width, canvas.height) + await this.drawBackgroundToCanvas(ctx, img.width, img.height) } // 图片绘制到canvas里 ctx.drawImage( @@ -73,8 +87,8 @@ class Export { 0, img.width, img.height, - exportPaddingX, - exportPaddingY, + 0, + 0, img.width, img.height ) @@ -98,7 +112,7 @@ class Export { backgroundImage, backgroundRepeat = 'no-repeat', backgroundPosition = 'center center', - backgroundSize = 'cover', + backgroundSize = 'cover' } = this.mindMap.themeConfig // 背景颜色 ctx.save() @@ -109,18 +123,25 @@ class Export { // 背景图片 if (backgroundImage && backgroundImage !== 'none') { ctx.save() - drawBackgroundImageToCanvas(ctx, width, height, backgroundImage, { - backgroundRepeat, - backgroundPosition, - backgroundSize - }, (err) => { - if (err) { - reject(err) - } else { - resolve() + drawBackgroundImageToCanvas( + ctx, + width, + height, + backgroundImage, + { + backgroundRepeat, + backgroundPosition, + backgroundSize + }, + err => { + if (err) { + reject(err) + } else { + resolve() + } + ctx.restore() } - ctx.restore() - }) + ) } else { resolve() } @@ -154,13 +175,17 @@ class Export { * 方法1.把svg的图片都转化成data:url格式,再转换 * 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换 */ - async png(name, transparent = false) { + async png(name, transparent = false, rotateWhenWidthLongerThenHeight) { let { node, str } = await this.getSvgData() str = removeHTMLEntities(str) // 如果开启了富文本,则使用htmltocanvas转换为图片 if (this.mindMap.richText) { - let res = await this.mindMap.richText.handleExportPng(node.node) - let imgDataUrl = await this.svgToPng(res, transparent) + let res = await this.mindMap.richText.handleExportPng(node.node) + let imgDataUrl = await this.svgToPng( + res, + transparent, + rotateWhenWidthLongerThenHeight + ) return imgDataUrl } // 转换成blob数据 @@ -170,7 +195,11 @@ class Export { // 转换成data:url数据 let svgUrl = await readBlob(blob) // 绘制到canvas上 - let res = await this.svgToPng(svgUrl, transparent) + let res = await this.svgToPng( + svgUrl, + transparent, + rotateWhenWidthLongerThenHeight + ) return res } @@ -179,7 +208,7 @@ class Export { if (!this.mindMap.doExportPDF) { throw new Error('请注册ExportPDF插件') } - let img = await this.png() + let img = await this.png('', false, true) this.mindMap.doExportPDF.pdf(name, img, useMultiPageExport) } From 8d1e9fa8e9199def7c39e8320fa32b7e931a3c08 Mon Sep 17 00:00:00 2001 From: wanglin2 <1013335014@qq.com> Date: Thu, 17 Aug 2023 10:00:33 +0800 Subject: [PATCH 15/83] =?UTF-8?q?Demo=EF=BC=9A=E4=BE=A7=E8=BE=B9=E6=A0=8F?= =?UTF-8?q?=E6=B6=89=E5=8F=8A=E5=9B=BE=E5=BD=A2=E7=9A=84=E9=80=89=E9=A1=B9?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8F=AF=E8=A7=86=E5=8C=96=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/config/index.js | 16 ++++- web/src/config/zh.js | 24 ++++++- web/src/pages/Edit/components/BaseStyle.vue | 79 ++++++++++++++++++++- web/src/pages/Edit/components/Style.vue | 77 ++++++++++++++++++-- 4 files changed, 187 insertions(+), 9 deletions(-) diff --git a/web/src/config/index.js b/web/src/config/index.js index 385fc236..9b8e115d 100644 --- a/web/src/config/index.js +++ b/web/src/config/index.js @@ -17,7 +17,9 @@ import { shapeList as shapeListZh, sidebarTriggerList as sidebarTriggerListZh, backgroundSizeList as backgroundSizeListZh, - downTypeList as downTypeListZh + downTypeList as downTypeListZh, + shapeListMap as shapeListMapZh, + lineStyleMap as lineStyleMapZh } from './zh' import { fontFamilyList as fontFamilyListEn, @@ -48,6 +50,11 @@ const lineStyleList = { en: lineStyleListEn } +const lineStyleMap = { + zh: lineStyleMapZh, + en: lineStyleMapZh +} + const rootLineKeepSameInCurveList = { zh: rootLineKeepSameInCurveListZh, en: rootLineKeepSameInCurveListEn @@ -78,6 +85,11 @@ const shapeList = { en: shapeListEn } +const shapeListMap = { + zh: shapeListMapZh, + en: shapeListMapZh +} + const sidebarTriggerList = { zh: sidebarTriggerListZh, en: sidebarTriggerListEn @@ -100,12 +112,14 @@ export { fontFamilyList, borderDasharrayList, lineStyleList, + lineStyleMap, rootLineKeepSameInCurveList, backgroundRepeatList, backgroundPositionList, backgroundSizeList, shortcutKeyList, shapeList, + shapeListMap, sidebarTriggerList, downTypeList } diff --git a/web/src/config/zh.js b/web/src/config/zh.js index c33c1cdf..08798137 100644 --- a/web/src/config/zh.js +++ b/web/src/config/zh.js @@ -142,6 +142,12 @@ export const borderRadiusList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 线宽 export const lineWidthList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +export const lineStyleMap = { + straight: ``, + curve: ``, + direct: `` +} + // 连线风格 export const lineStyleList = [ { @@ -379,6 +385,22 @@ export const shortcutKeyList = [ } ] +export const shapeListMap = { + rectangle: 'M 4 12 L 4 3 L 56 3 L 56 21 L 4 21 L 4 12 Z', + diamond: 'M 4 12 L 30 3 L 56 12 L 30 21 L 4 12 Z', + parallelogram: 'M 10 3 L 56 3 L 50 21 L 4 21 L 10 3 Z', + roundedRectangle: + 'M 13 3 L 47 3 A 9 9 0, 0 1 47 21 L 13 21 A 9 9 0, 0 1 13 3 Z', + octagonalRectangle: + 'M 4 12 L 4 9 L 10 3 L 50 3 L 56 9 L 56 15 L 50 21 L 10 21 L 4 15 L 4 12 Z', + outerTriangularRectangle: + 'M 4 12 L 10 3 L 50 3 L 56 12 L 50 21 L 10 21 L 4 12 Z', + innerTriangularRectangle: + 'M 10 12 L 4 3 L 56 3 L 50 12 L 56 21 L 4 21 L 10 12 Z', + ellipse: 'M 4 12 A 26 9 0, 1, 0 30 3 A 26 9 0, 0, 0 4 12 Z', + circle: 'M 21 12 A 9 9 0, 1, 0 30 3 A 9 9 0, 0, 0 21 12 Z' +} + // 形状列表 export const shapeList = [ { @@ -509,4 +531,4 @@ export const downTypeList = [ icon: 'iconxmind', desc: 'XMind格式' } -] \ No newline at end of file +] diff --git a/web/src/pages/Edit/components/BaseStyle.vue b/web/src/pages/Edit/components/BaseStyle.vue index ef1e89dc..d9705bf6 100644 --- a/web/src/pages/Edit/components/BaseStyle.vue +++ b/web/src/pages/Edit/components/BaseStyle.vue @@ -137,6 +137,12 @@ :label="item" :value="item" > +
@@ -160,6 +166,12 @@ :key="item.value" :label="item.name" :value="item.value" + class="lineStyleOption" + :class="{ + isDark: isDark, + isSelected: style.lineStyle === item.value + }" + v-html="lineStyleMap[item.value]" > @@ -227,6 +239,12 @@ :label="item" :value="item" > +
@@ -271,6 +289,12 @@ :label="item" :value="item" > + @@ -317,6 +341,12 @@ :label="item" :value="item" > + @@ -738,7 +768,8 @@ import { backgroundSizeList, fontFamilyList, fontSizeList, - rootLineKeepSameInCurveList + rootLineKeepSameInCurveList, + lineStyleMap } from '@/config' import ImgUpload from '@/components/ImgUpload' import { storeConfig } from '@/api' @@ -845,6 +876,9 @@ export default { }, fontFamilyList() { return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh + }, + lineStyleMap() { + return lineStyleMap[this.$i18n.locale] || lineStyleMap.zh } }, watch: { @@ -1158,4 +1192,47 @@ export default { } } } + +.borderLine { + display: inline-block; + width: 100%; + background-color: #000; + + &.isDark { + background-color: #fff; + } +} + + diff --git a/web/src/pages/Edit/components/Style.vue b/web/src/pages/Edit/components/Style.vue index 8aba9892..6bce2364 100644 --- a/web/src/pages/Edit/components/Style.vue +++ b/web/src/pages/Edit/components/Style.vue @@ -1,6 +1,10 @@