diff --git a/index.html b/index.html index 21227c32..32e46b1b 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ -一个简单的web思维导图实现
\ No newline at end of file +一个简单的web思维导图实现
\ No newline at end of file diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 7ebbc2e4..d3cdbe74 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -92,7 +92,16 @@ const defaultOpt = { // 如果开启节点动画过渡,可以通过该属性设置过渡的时间,单位ms nodeTransitionMoveDuration: 300, // 初始根节点的位置 - initRootNodePosition: null + initRootNodePosition: null, + // 导出png、svg、pdf时的图形内边距 + exportPaddingX: 10, + exportPaddingY: 10, + // 节点文本编辑框的z-index + nodeTextEditZIndex: 3000, + // 节点备注浮层的z-index + nodeNoteTooltipZIndex: 3000, + // 是否在点击了画布外的区域时结束节点文本的编辑状态 + isEndNodeTextEditOnClickOuter: true } // 思维导图 @@ -359,7 +368,7 @@ class MindMap { } // 获取svg数据 - getSvgData() { + getSvgData({ paddingX = 0, paddingY = 0 }) { const svg = this.svg const draw = this.draw // 保存原始信息 @@ -371,6 +380,10 @@ class MindMap { draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY) // 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法 const rect = draw.rbox() + // 内边距 + rect.width += paddingX + rect.height += paddingY + draw.translate(paddingX / 2, paddingY / 2) // 将svg设置为实际内容的宽高 svg.size(rect.width, rect.height) // 把实际内容变换 diff --git a/simple-mind-map/package.json b/simple-mind-map/package.json index 6403a28d..783d8696 100644 --- a/simple-mind-map/package.json +++ b/simple-mind-map/package.json @@ -1,6 +1,6 @@ { "name": "simple-mind-map", - "version": "0.5.4-fix.1", + "version": "0.5.5", "description": "一个简单的web在线思维导图", "authors": [ { diff --git a/simple-mind-map/src/Event.js b/simple-mind-map/src/Event.js index 917f51b8..daac439f 100644 --- a/simple-mind-map/src/Event.js +++ b/simple-mind-map/src/Event.js @@ -27,6 +27,7 @@ class Event extends EventEmitter { // 绑定函数上下文 bindFn() { + this.onBodyClick = this.onBodyClick.bind(this) this.onDrawClick = this.onDrawClick.bind(this) this.onMousedown = this.onMousedown.bind(this) this.onMousemove = this.onMousemove.bind(this) @@ -41,6 +42,7 @@ class Event extends EventEmitter { // 绑定事件 bind() { + document.body.addEventListener('click', this.onBodyClick) this.mindMap.svg.on('click', this.onDrawClick) this.mindMap.el.addEventListener('mousedown', this.onMousedown) this.mindMap.svg.on('mousedown', this.onSvgMousedown) @@ -55,6 +57,7 @@ class Event extends EventEmitter { // 解绑事件 unbind() { + document.body.removeEventListener('click', this.onBodyClick) this.mindMap.svg.off('click', this.onDrawClick) this.mindMap.el.removeEventListener('mousedown', this.onMousedown) window.removeEventListener('mousemove', this.onMousemove) @@ -71,6 +74,11 @@ class Event extends EventEmitter { this.emit('draw_click', e) } + // 页面的单击事件 + onBodyClick(e) { + this.emit('body_click', e) + } + // svg画布的鼠标按下事件 onSvgMousedown(e) { this.emit('svg_mousedown', e) diff --git a/simple-mind-map/src/Export.js b/simple-mind-map/src/Export.js index 27fd84b7..aab5b1dc 100644 --- a/simple-mind-map/src/Export.js +++ b/simple-mind-map/src/Export.js @@ -28,7 +28,11 @@ class Export { // 获取svg数据 async getSvgData(domToImage) { - let { svg, svgHTML } = this.mindMap.getSvgData() + let { exportPaddingX, exportPaddingY } = this.mindMap.opt + let { svg, svgHTML } = this.mindMap.getSvgData({ + paddingX: exportPaddingX, + paddingY: exportPaddingY + }) // 把图片的url转换成data:url类型,否则导出会丢失图片 let imageList = svg.find('image') let task = imageList.map(async item => { diff --git a/simple-mind-map/src/RichText.js b/simple-mind-map/src/RichText.js index 2f2af9f7..39a24920 100644 --- a/simple-mind-map/src/RichText.js +++ b/simple-mind-map/src/RichText.js @@ -99,6 +99,9 @@ class RichText { if (!this.textEditNode) { this.textEditNode = document.createElement('div') this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;box-shadow: 0 0 20px rgba(0,0,0,.5);outline: none; word-break: break-all;padding: 3px 5px;margin-left: -5px;margin-top: -3px;` + this.textEditNode.addEventListener('click', e => { + e.stopPropagation() + }) document.body.appendChild(this.textEditNode) } // 原始宽高 @@ -107,6 +110,7 @@ class RichText { let originHeight = g.attr('data-height') // 使用节点的填充色,否则如果节点颜色是白色的话编辑时看不见 let bgColor = node.style.merge('fillColor') + this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex this.textEditNode.style.backgroundColor = bgColor === 'transparent' ? '#fff' : bgColor this.textEditNode.style.minWidth = originWidth + 'px' this.textEditNode.style.minHeight = originHeight + 'px' diff --git a/simple-mind-map/src/TextEdit.js b/simple-mind-map/src/TextEdit.js index 388e8090..f2f9330b 100644 --- a/simple-mind-map/src/TextEdit.js +++ b/simple-mind-map/src/TextEdit.js @@ -23,6 +23,12 @@ export default class TextEdit { // 隐藏文本编辑框 this.hideEditTextBox() }) + this.mindMap.on('body_click', () => { + // 隐藏文本编辑框 + if (this.mindMap.opt.isEndNodeTextEditOnClickOuter) { + this.hideEditTextBox() + } + }) this.mindMap.on('svg_mousedown', () => { // 隐藏文本编辑框 this.hideEditTextBox() @@ -73,6 +79,9 @@ export default class TextEdit { this.textEditNode.addEventListener('keyup', e => { e.stopPropagation() }) + this.textEditNode.addEventListener('click', e => { + e.stopPropagation() + }) document.body.appendChild(this.textEditNode) } let scale = this.mindMap.view.scale @@ -80,6 +89,7 @@ export default class TextEdit { let fontSize = node.style.merge('fontSize') let textLines = node.nodeData.data.text.split(/\n/gim) node.style.domText(this.textEditNode, scale, textLines.length) + this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex this.textEditNode.innerHTML = textLines.join('
') this.textEditNode.style.minWidth = rect.width + 10 + 'px' this.textEditNode.style.minHeight = rect.height + 6 + 'px' diff --git a/simple-mind-map/src/utils/nodeCreateContents.js b/simple-mind-map/src/utils/nodeCreateContents.js index e2ec64c5..eafa8a6b 100644 --- a/simple-mind-map/src/utils/nodeCreateContents.js +++ b/simple-mind-map/src/utils/nodeCreateContents.js @@ -205,13 +205,14 @@ function createNoteNode() { if (!this.noteEl) { this.noteEl = document.createElement('div') this.noteEl.style.cssText = ` - position: absolute; - padding: 10px; - border-radius: 5px; - box-shadow: 0 2px 5px rgb(0 0 0 / 10%); - display: none; - background-color: #fff; - ` + position: absolute; + padding: 10px; + border-radius: 5px; + box-shadow: 0 2px 5px rgb(0 0 0 / 10%); + display: none; + background-color: #fff; + z-index: ${ this.mindMap.opt.nodeNoteTooltipZIndex } + ` document.body.appendChild(this.noteEl) } this.noteEl.innerText = this.nodeData.data.note diff --git a/web/package-lock.json b/web/package-lock.json index edcc11d0..d89d26ed 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -18450,7 +18450,6 @@ "integrity": "sha512-VCNRiAt2P/bLo09rYt3DLe6xXUMlhJwrvU18Ddd/lYJgC7s8+wvhgYs+MTx4OiAXdu58drGwSBO9SPx7C6J82Q==", "dev": true, "requires": { - "@babel/core": "^7.11.0", "@babel/helper-compilation-targets": "^7.9.6", "@babel/helper-module-imports": "^7.8.3", "@babel/plugin-proposal-class-properties": "^7.8.3", @@ -18463,7 +18462,6 @@ "@vue/babel-plugin-jsx": "^1.0.3", "@vue/babel-preset-jsx": "^1.2.4", "babel-plugin-dynamic-import-node": "^2.3.3", - "core-js": "^3.6.5", "core-js-compat": "^3.6.5", "semver": "^6.1.0" } diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js index 9df10eae..0d1d1c6d 100644 --- a/web/src/lang/en_us.js +++ b/web/src/lang/en_us.js @@ -95,7 +95,9 @@ export default { svgTips: 'tips: Exporting pictures in rich text mode is time-consuming', transformingDomToImages: 'Converting nodes: ', notifyTitle: 'Info', - notifyMessage: 'If the download is not triggered, check whether it is blocked by the browser' + notifyMessage: 'If the download is not triggered, check whether it is blocked by the browser', + paddingX: 'Padding x', + paddingY: 'Padding y' }, fullscreen: { fullscreenShow: 'Full screen show', diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js index 09f00b2f..74477611 100644 --- a/web/src/lang/zh_cn.js +++ b/web/src/lang/zh_cn.js @@ -95,7 +95,9 @@ export default { svgTips: 'tips:富文本模式导出图片非常耗时', transformingDomToImages: '正在转换节点:', notifyTitle: '消息', - notifyMessage: '如果没有触发下载,请检查是否被浏览器拦截了' + notifyMessage: '如果没有触发下载,请检查是否被浏览器拦截了', + paddingX: '水平内边距', + paddingY: '垂直内边距' }, fullscreen: { fullscreenShow: '全屏查看', diff --git a/web/src/pages/Doc/en/changelog/index.md b/web/src/pages/Doc/en/changelog/index.md index 651e9fb7..50b58823 100644 --- a/web/src/pages/Doc/en/changelog/index.md +++ b/web/src/pages/Doc/en/changelog/index.md @@ -1,5 +1,9 @@ # Changelog +## 0.5.5 + +New: 1.Supports configuring the padding when exporting to PNG, SVG, or PDF. 2.Support the configuration of z-index for node text editing boxes and node comment floating layer elements. 3.Support clicking on areas outside the canvas to end node editing status. + ## 0.5.4 New: 1.Add new themes. 2.Added timeline and fishbone structure. @@ -8,6 +12,10 @@ Fix: 1.Fix the conflict issue between node right-click and canvas right-click. 2 optimization: 1.Optimize the layout of organizational chart. 2.Optimize the layout of the directory organization chart. +## 0.5.4-fix.1 + +optimization: 1.Optimize fishbone layout. + ## 0.5.3 Fix: 1.Fixed the issue of setting the text style when multiple nodes were selected in rich text mode, which would change the text of all selected nodes to the text of the last selected node. diff --git a/web/src/pages/Doc/en/changelog/index.vue b/web/src/pages/Doc/en/changelog/index.vue index 83b64dad..0ee79ab6 100644 --- a/web/src/pages/Doc/en/changelog/index.vue +++ b/web/src/pages/Doc/en/changelog/index.vue @@ -1,10 +1,14 @@