diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 492c2317..1505df69 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -120,9 +120,7 @@ class MindMap { // 注册插件 MindMap.pluginList.forEach((plugin) => { - this[plugin.instanceName] = new plugin({ - mindMap: this - }) + this.initPlugin(plugin) }) // 初始渲染 @@ -374,14 +372,51 @@ class MindMap { scaleY: origTransform.scaleY // 思维导图图形的垂直缩放值 } } + + // 添加插件 + addPlugin(plugin, opt) { + let index = MindMap.hasPlugin(plugin) + if (index === -1) { + MindMap.usePlugin(plugin, opt) + this.initPlugin(plugin) + } + } + + // 移除插件 + removePlugin(plugin) { + let index = MindMap.hasPlugin(plugin) + if (index !== -1) { + MindMap.pluginList.splice(index, 1) + if (this[plugin.instanceName]) { + if (this[plugin.instanceName].beforePluginRemove) { + this[plugin.instanceName].beforePluginRemove() + } + delete this[plugin.instanceName] + } + } + } + + // 实例化插件 + initPlugin(plugin) { + this[plugin.instanceName] = new plugin({ + mindMap: this, + pluginOpt: plugin.pluginOpt + }) + } } // 插件列表 MindMap.pluginList = [] -MindMap.usePlugin = (plugin) => { +MindMap.usePlugin = (plugin, opt = {}) => { + plugin.pluginOpt = opt MindMap.pluginList.push(plugin) return MindMap } +MindMap.hasPlugin = (plugin) => { + return MindMap.pluginList.findIndex((item) => { + return item === plugin + }) +} // 定义新主题 MindMap.defineTheme = (name, config = {}) => { diff --git a/simple-mind-map/package-lock.json b/simple-mind-map/package-lock.json index e1937183..bbd2adeb 100644 --- a/simple-mind-map/package-lock.json +++ b/simple-mind-map/package-lock.json @@ -1,19 +1,21 @@ { "name": "simple-mind-map", - "version": "0.2.21", + "version": "0.3.4", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.2.21", + "version": "0.3.4", "license": "MIT", "dependencies": { "@svgdotjs/svg.js": "^3.0.16", "canvg": "^3.0.7", "deepmerge": "^1.5.2", "eventemitter3": "^4.0.7", + "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jszip": "^3.10.1", + "quill": "^1.3.6", "xml-js": "^1.6.11" }, "devDependencies": { @@ -225,7 +227,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "optional": true, "engines": { "node": ">= 0.6.0" } @@ -251,6 +252,18 @@ "node": ">= 0.4.0" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -294,6 +307,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -351,7 +372,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "optional": true, "dependencies": { "utrie": "^1.0.2" } @@ -373,6 +393,22 @@ } } }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -387,6 +423,21 @@ "node": ">=0.10.0" } }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -586,12 +637,22 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -671,6 +732,32 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -724,6 +811,17 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -733,11 +831,46 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "optional": true, "dependencies": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" @@ -800,6 +933,35 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -830,6 +992,21 @@ "node": ">=8" } }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -969,6 +1146,29 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1030,6 +1230,11 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, + "node_modules/parchment": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz", + "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -1132,6 +1337,37 @@ } ] }, + "node_modules/quill": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz", + "integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==", + "dependencies": { + "clone": "^2.1.1", + "deep-equal": "^1.0.1", + "eventemitter3": "^2.0.3", + "extend": "^3.0.1", + "parchment": "^1.1.4", + "quill-delta": "^3.6.2" + } + }, + "node_modules/quill-delta": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz", + "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", + "dependencies": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.1.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/quill/node_modules/eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" + }, "node_modules/raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -1159,6 +1395,22 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -1336,7 +1588,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "optional": true, "dependencies": { "utrie": "^1.0.2" } @@ -1389,7 +1640,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "optional": true, "dependencies": { "base64-arraybuffer": "^1.0.2" } @@ -1593,8 +1843,7 @@ "base64-arraybuffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", - "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", - "optional": true + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==" }, "brace-expansion": { "version": "1.1.11", @@ -1611,6 +1860,15 @@ "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1642,6 +1900,11 @@ "supports-color": "^7.1.0" } }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1688,7 +1951,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", - "optional": true, "requires": { "utrie": "^1.0.2" } @@ -1702,6 +1964,19 @@ "ms": "2.1.2" } }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, "deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1713,6 +1988,15 @@ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==" }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1860,12 +2144,22 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "fast-diff": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz", + "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==" + }, "fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1933,6 +2227,26 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, "glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -1971,17 +2285,45 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, "html2canvas": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", - "optional": true, "requires": { "css-line-break": "^2.1.0", "text-segmentation": "^1.0.3" @@ -2029,6 +2371,23 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2050,6 +2409,15 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -2168,6 +2536,20 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2214,6 +2596,11 @@ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, + "parchment": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz", + "integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==" + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2275,6 +2662,36 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "quill": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/quill/-/quill-1.3.6.tgz", + "integrity": "sha512-K0mvhimWZN6s+9OQ249CH2IEPZ9JmkFuCQeHAOQax3EZ2nDJ3wfGh59mnlQaZV2i7u8eFarx6wAtvQKgShojug==", + "requires": { + "clone": "^2.1.1", + "deep-equal": "^1.0.1", + "eventemitter3": "^2.0.3", + "extend": "^3.0.1", + "parchment": "^1.1.4", + "quill-delta": "^3.6.2" + }, + "dependencies": { + "eventemitter3": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz", + "integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg==" + } + } + }, + "quill-delta": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz", + "integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==", + "requires": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.1.2" + } + }, "raf": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", @@ -2302,6 +2719,16 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -2419,7 +2846,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", - "optional": true, "requires": { "utrie": "^1.0.2" } @@ -2463,7 +2889,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", - "optional": true, "requires": { "base64-arraybuffer": "^1.0.2" } diff --git a/simple-mind-map/package.json b/simple-mind-map/package.json index 812c681f..00cb8d25 100644 --- a/simple-mind-map/package.json +++ b/simple-mind-map/package.json @@ -1,6 +1,6 @@ { "name": "simple-mind-map", - "version": "0.3.4", + "version": "0.4.0", "description": "一个简单的web在线思维导图", "authors": [ { @@ -28,8 +28,10 @@ "canvg": "^3.0.7", "deepmerge": "^1.5.2", "eventemitter3": "^4.0.7", + "html2canvas": "^1.4.1", "jspdf": "^2.5.1", "jszip": "^3.10.1", + "quill": "^1.3.6", "xml-js": "^1.6.11" }, "keywords": [ diff --git a/simple-mind-map/src/Export.js b/simple-mind-map/src/Export.js index 765dcd8e..2ade1789 100644 --- a/simple-mind-map/src/Export.js +++ b/simple-mind-map/src/Export.js @@ -26,7 +26,7 @@ class Export { } // 获取svg数据 - async getSvgData() { + async getSvgData(domToImage) { let { svg, svgHTML } = this.mindMap.getSvgData() // 把图片的url转换成data:url类型,否则导出会丢失图片 let imageList = svg.find('image') @@ -36,9 +36,17 @@ class Export { item.attr('href', imgData) }) await Promise.all(task) + // 如果开启了富文本编辑,需要把svg中的dom元素转换成图片 + let nodeWithDomToImg = null + if (domToImage && this.mindMap.richText) { + let res = await this.mindMap.richText.handleSvgDomElements(svg) + nodeWithDomToImg = res.svg + svgHTML = res.svgHTML + } return { node: svg, - str: svgHTML + str: svgHTML, + nodeWithDomToImg } } @@ -123,7 +131,7 @@ class Export { * 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换 */ async png() { - let { str } = await this.getSvgData() + let { str } = await this.getSvgData(true) // 转换成blob数据 let blob = new Blob([str], { type: 'image/svg+xml' @@ -191,8 +199,21 @@ class Export { } // 导出为svg - async svg(name) { - let { node } = await this.getSvgData() + // domToImage:是否将svg中的dom节点转换成图片的形式 + // plusCssText:附加的css样式,如果svg中存在dom节点,想要设置一些针对节点的样式可以通过这个参数传入 + async svg(name, domToImage = false, plusCssText) { + let { node, nodeWithDomToImg } = await this.getSvgData(domToImage) + // 开启了节点富文本编辑 + if (this.mindMap.richText) { + if (domToImage) { + node = nodeWithDomToImg + } else if (plusCssText) { + let foreignObjectList = node.find('foreignObject') + if (foreignObjectList.length > 0) { + foreignObjectList[0].add(SVG(``)) + } + } + } node.first().before(SVG(`
${text}
` + this.textEditNode.innerHTML = html + } else { + this.textEditNode.innerHTML = node.nodeData.data.text + } + this.initQuillEditor() + document.querySelector('.ql-editor').style.minHeight = originHeight + 'px' + this.showTextEdit = true + this.selectAll() + if (!node.nodeData.data.richText) { + // 如果是非富文本的情况,需要手动应用文本样式 + this.setTextStyleIfNotRichText(node) + } + } + + // 如果是非富文本的情况,需要手动应用文本样式 + setTextStyleIfNotRichText(node) { + let style = { + font: node.style.merge('fontFamily'), + color: node.style.merge('color'), + italic: node.style.merge('fontStyle') === 'italic', + bold: node.style.merge('fontWeight') === 'bold', + size: node.style.merge('fontSize') + 'px', + underline: node.style.merge('textDecoration') === 'underline', + strike: node.style.merge('textDecoration') === 'line-through' + } + this.formatText(style) + } + + // 隐藏文本编辑控件,即完成编辑 + hideEditText() { + if (!this.showTextEdit) { + return + } + let html = this.quill.container.firstChild.innerHTML + // 去除最后的空行 + html = html.replace(/
<\/p>$/, '')
+ this.mindMap.renderer.activeNodeList.forEach(node => {
+ this.mindMap.execCommand('SET_NODE_TEXT', node, html, true)
+ if (node.isGeneralization) {
+ // 概要节点
+ node.generalizationBelongNode.updateGeneralization()
+ }
+ this.mindMap.render()
+ })
+ this.mindMap.emit(
+ 'hide_text_edit',
+ this.textEditNode,
+ this.mindMap.renderer.activeNodeList
+ )
+ this.textEditNode.style.display = 'none'
+ this.showTextEdit = false
+ this.mindMap.emit('rich_text_selection_change', false)
+ this.node = null
+ }
+
+ // 初始化Quill富文本编辑器
+ initQuillEditor() {
+ this.quill = new Quill(this.textEditNode, {
+ modules: {
+ toolbar: false,
+ keyboard: {
+ bindings: {
+ enter: {
+ key: 13,
+ handler: function () {
+ // 覆盖默认的回车键换行
+ }
+ }
+ }
+ }
+ },
+ theme: 'snow'
+ })
+ this.quill.on('selection-change', range => {
+ this.lastRange = this.range
+ this.range = null
+ if (range) {
+ let bounds = this.quill.getBounds(range.index, range.length)
+ let rect = this.textEditNode.getBoundingClientRect()
+ let rectInfo = {
+ left: bounds.left + rect.left,
+ top: bounds.top + rect.top,
+ right: bounds.right + rect.left,
+ bottom: bounds.bottom + rect.top,
+ width: bounds.width
+ }
+ let formatInfo = this.quill.getFormat(range.index, range.length)
+ let hasRange = false
+ if (range.length == 0) {
+ hasRange = false
+ } else {
+ this.range = range
+ hasRange = true
+ }
+ this.mindMap.emit(
+ 'rich_text_selection_change',
+ hasRange,
+ rectInfo,
+ formatInfo
+ )
+ }
+ })
+ }
+
+ // 选中全部
+ selectAll() {
+ this.quill.setSelection(0, this.quill.getLength())
+ }
+
+ // 格式化当前选中的文本
+ formatText(config = {}) {
+ if (!this.range && !this.lastRange) return
+ this.syncFormatToNodeConfig(config)
+ let rangeLost = !this.range
+ let range = rangeLost ? this.lastRange : this.range
+ this.quill.formatText(range.index, range.length, config)
+ if (rangeLost) {
+ this.quill.setSelection(this.lastRange.index, this.lastRange.length)
+ }
+ }
+
+ // 格式化指定范围的文本
+ formatRangeText(range, config = {}) {
+ if (!range) return
+ this.syncFormatToNodeConfig(config)
+ this.quill.formatText(range.index, range.length, config)
+ }
+
+ // 格式化所有文本
+ formatAllText(config = {}) {
+ this.syncFormatToNodeConfig(config)
+ this.quill.formatText(0, this.quill.getLength(), config)
+ }
+
+ // 同步格式化到节点样式配置
+ syncFormatToNodeConfig(config) {
+ if (!this.node) return
+ let data = this.richTextStyleToNormalStyle(config)
+ this.mindMap.renderer.setNodeData(this.node, data)
+ }
+
+ // 将普通节点样式对象转换成富文本样式对象
+ normalStyleToRichTextStyle(style) {
+ let config = {}
+ Object.keys(style).forEach(prop => {
+ let value = style[prop]
+ switch (prop) {
+ case 'fontFamily':
+ config.font = value
+ break
+ case 'fontSize':
+ config.size = value + 'px'
+ break
+ case 'fontWeight':
+ config.bold = value === 'bold'
+ break
+ case 'fontStyle':
+ config.italic = value === 'italic'
+ break
+ case 'textDecoration':
+ config.underline = value === 'underline'
+ config.strike = value === 'line-through'
+ case 'color':
+ config.color = value
+ break
+ default:
+ break
+ }
+ })
+ return config
+ }
+
+ // 将富文本样式对象转换成普通节点样式对象
+ richTextStyleToNormalStyle(config) {
+ let data = {}
+ Object.keys(config).forEach(prop => {
+ let value = config[prop]
+ switch (prop) {
+ case 'font':
+ data.fontFamily = value
+ break
+ case 'size':
+ data.fontSize = parseFloat(value)
+ break
+ case 'bold':
+ data.fontWeight = value ? 'bold' : 'normal'
+ break
+ case 'italic':
+ data.fontStyle = value ? 'italic' : 'normal'
+ break
+ case 'underline':
+ data.textDecoration = value ? 'underline' : 'none'
+ break
+ case 'strike':
+ data.textDecoration = value ? 'line-through' : 'none'
+ break
+ case 'color':
+ data.color = value
+ break
+ default:
+ break
+ }
+ })
+ return data
+ }
+
+ // 将svg中嵌入的dom元素转换成图片
+ async _handleSvgDomElements(svg) {
+ svg = svg.clone()
+ let foreignObjectList = svg.find('foreignObject')
+ let task = foreignObjectList.map(async item => {
+ let clone = item.first().node.cloneNode(true)
+ let div = document.createElement('div')
+ div.style.cssText = `position: fixed; left: -999999px;`
+ div.appendChild(clone)
+ this.mindMap.el.appendChild(div)
+ let canvas = await html2canvas(clone, {
+ backgroundColor: null
+ })
+ this.mindMap.el.removeChild(div)
+ let imgNode = new SvgImage()
+ .load(canvas.toDataURL())
+ .size(canvas.width, canvas.height)
+ item.replace(imgNode)
+ })
+ await Promise.all(task)
+ return {
+ svg: svg,
+ svgHTML: svg.svg()
+ }
+ }
+
+ // 将svg中嵌入的dom元素转换成图片
+ handleSvgDomElements(svg) {
+ return new Promise((resolve, reject) => {
+ svg = svg.clone()
+ let foreignObjectList = svg.find('foreignObject')
+ let index = 0
+ let len = foreignObjectList.length
+ let transform = async () => {
+ this.mindMap.emit('transforming-dom-to-images', index, len)
+ try {
+ let item = foreignObjectList[index++]
+ let parent = item.parent()
+ let clone = item.first().node.cloneNode(true)
+ let div = document.createElement('div')
+ div.style.cssText = `position: fixed; left: -999999px;`
+ div.appendChild(clone)
+ this.mindMap.el.appendChild(div)
+ let canvas = await html2canvas(clone, {
+ backgroundColor: null
+ })
+ this.mindMap.el.removeChild(div)
+ let imgNode = new SvgImage()
+ .load(canvas.toDataURL())
+ .size(canvas.width, canvas.height)
+ .x((parent ? parent.attr('data-offsetx') : 0) || 0)
+ item.replace(imgNode)
+ if (index <= len - 1) {
+ setTimeout(() => {
+ transform()
+ }, 0)
+ } else {
+ resolve({
+ svg: svg,
+ svgHTML: svg.svg()
+ })
+ }
+ } catch (error) {
+ reject(error)
+ }
+ }
+ if (len > 0) transform()
+ })
+ }
+
+ // 将所有节点转换成非富文本节点
+ transformAllNodesToNormalNode() {
+ let div = document.createElement('div')
+ walk(
+ this.mindMap.renderer.renderTree,
+ null,
+ node => {
+ if (node.data.richText) {
+ node.data.richText = false
+ div.innerHTML = node.data.text
+ node.data.text = div.textContent
+ }
+ },
+ null,
+ true,
+ 0,
+ 0
+ )
+ this.mindMap.reRender()
+ }
+
+ // 插件被移除前做的事情
+ beforePluginRemove() {
+ this.transformAllNodesToNormalNode()
+ }
+}
+
+RichText.instanceName = 'richText'
+
+export default RichText
diff --git a/simple-mind-map/src/TextEdit.js b/simple-mind-map/src/TextEdit.js
index 20fb603a..a71e31b0 100644
--- a/simple-mind-map/src/TextEdit.js
+++ b/simple-mind-map/src/TextEdit.js
@@ -50,7 +50,12 @@ export default class TextEdit {
// 显示文本编辑框
show(node) {
- this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect())
+ let rect = node._textData.node.node.getBoundingClientRect()
+ if (this.mindMap.richText) {
+ this.mindMap.richText.showEditText(node, rect)
+ return
+ }
+ this.showEditTextBox(node, rect)
}
// 显示文本编辑框
@@ -96,6 +101,9 @@ export default class TextEdit {
// 隐藏文本编辑框
hideEditTextBox() {
+ if (this.mindMap.richText) {
+ return this.mindMap.richText.hideEditText()
+ }
if (!this.showTextEdit) {
return
}
diff --git a/simple-mind-map/src/css/quill.css b/simple-mind-map/src/css/quill.css
new file mode 100644
index 00000000..78787c19
--- /dev/null
+++ b/simple-mind-map/src/css/quill.css
@@ -0,0 +1,9 @@
+.ql-editor {
+ overflow: hidden;
+ padding: 0;
+ height: auto;
+}
+
+.ql-container {
+ height: auto;
+}
\ No newline at end of file
diff --git a/web/src/lang/en_us.js b/web/src/lang/en_us.js
index c3eafdde..fe0f116f 100644
--- a/web/src/lang/en_us.js
+++ b/web/src/lang/en_us.js
@@ -34,7 +34,8 @@ export default {
watermarkTextSpacing: 'Text spacing',
watermarkAngle: 'Angle',
watermarkTextOpacity: 'Text opacity',
- watermarkTextFontSize: 'Font size'
+ watermarkTextFontSize: 'Font size',
+ isEnableNodeRichText: 'Enable node rich text editing'
},
color: {
moreColor: 'More color'
@@ -79,7 +80,13 @@ export default {
imageFile: 'Image file',
svgFile: 'svg file',
pdfFile: 'pdf file',
- tips: 'tips:.smm and .json file can be import'
+ tips: 'tips: .smm and .json file can be import',
+ domToImage: 'Whether to convert rich text nodes in svg into pictures',
+ pngTips: 'tips: Exporting pictures in rich text mode is time-consuming. It is recommended to export to svg format',
+ 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'
},
fullscreen: {
fullscreenShow: 'Full screen show',
@@ -178,5 +185,9 @@ export default {
import: 'Import',
export: 'Export',
shortcutKey: 'Shortcut key'
+ },
+ edit: {
+ newFeatureNoticeTitle: 'New feature reminder',
+ newFeatureNoticeMessage: 'This update supports node rich text editing, But there are some defects, The most important impact is that the time to export the image is proportional to the number of nodes, Therefore, if you are more dependent on export requirements, you can use【Base style】-【Other config】-【Enable node rich text editing】Set to turn off rich text editing mode.'
}
}
diff --git a/web/src/lang/zh_cn.js b/web/src/lang/zh_cn.js
index 250d2999..9596aefb 100644
--- a/web/src/lang/zh_cn.js
+++ b/web/src/lang/zh_cn.js
@@ -34,7 +34,8 @@ export default {
watermarkTextSpacing: '水印文字间距',
watermarkAngle: '旋转角度',
watermarkTextOpacity: '文字透明度',
- watermarkTextFontSize: '文字字号'
+ watermarkTextFontSize: '文字字号',
+ isEnableNodeRichText: '是否开启节点富文本编辑'
},
color: {
moreColor: '更多颜色'
@@ -79,7 +80,13 @@ export default {
imageFile: '图片文件',
svgFile: 'svg文件',
pdfFile: 'pdf文件',
- tips: 'tips:.smm和.json文件可用于导入'
+ tips: 'tips:.smm和.json文件可用于导入',
+ domToImage: '是否将svg中富文本节点转换成图片',
+ pngTips: 'tips:富文本模式导出图片非常耗时,建议导出为svg格式',
+ svgTips: 'tips:富文本模式导出图片非常耗时',
+ transformingDomToImages: '正在转换节点:',
+ notifyTitle: '消息',
+ notifyMessage: '如果没有触发下载,请检查是否被浏览器拦截了'
},
fullscreen: {
fullscreenShow: '全屏查看',
@@ -178,5 +185,9 @@ export default {
import: '导入',
export: '导出',
shortcutKey: '快捷键'
+ },
+ edit: {
+ newFeatureNoticeTitle: '新特性提醒',
+ newFeatureNoticeMessage: '本次更新支持了节点富文本编辑,但是存在一定缺陷,最主要的影响是导出为图片的时间和节点数量成正比,所以对导出需求比较依赖的话可以通过【基础样式】-【其他配置】-【是否开启节点富文本编辑】设置关掉富文本编辑模式。'
}
}
diff --git a/web/src/pages/Edit/components/BaseStyle.vue b/web/src/pages/Edit/components/BaseStyle.vue
index 015f870b..7177a3f8 100644
--- a/web/src/pages/Edit/components/BaseStyle.vue
+++ b/web/src/pages/Edit/components/BaseStyle.vue
@@ -429,6 +429,11 @@
">{{ $t('baseStyle.enableFreeDrag') }}
+