diff --git a/package.json b/package.json index 23247f35..9395c609 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mind-elixir", - "version": "1.1.1", + "version": "1.1.2", "description": "Mind elixir is a free open source mind map core.", "main": "dist/MindElixir.js", "scripts": { diff --git a/painter/index.foreignObject.js b/painter/index.foreignObject.js deleted file mode 100644 index bdea866f..00000000 --- a/painter/index.foreignObject.js +++ /dev/null @@ -1,215 +0,0 @@ -import Canvg from 'canvg' -let $d = document -let maxTop = 10000 -let maxBottom = 10000 -let maxLeft = 10000 -let maxRight = 10000 -let imgPadding = 40 -let head = `` -function generateSvgDom() { - let primaryNodes = $d.querySelectorAll('.box > grp, root') - let svgContent = '' - for (let i = 0; i < primaryNodes.length; i++) { - let primaryNode = primaryNodes[i] - let rect = primaryNode.getBoundingClientRect() - let top = primaryNode.offsetTop - let bottom = top + rect.height - let left = primaryNode.offsetLeft - let right = left + rect.width - // console.log(top, bottom, left, right) - if (top < maxTop) { - maxTop = top - } - if (bottom > maxBottom) { - maxBottom = bottom - } - if (left < maxLeft) { - maxLeft = left - } - if (right > maxRight) { - maxRight = right - } - svgContent += PrimaryToSvg(primaryNode) - } - console.log(maxTop, maxBottom, maxLeft, maxRight) - svgContent += RootToSvg() - // 需要添加图片边缘padding - let svgHeight = maxBottom - maxTop + imgPadding * 2 - let svgWidth = maxRight - maxLeft + imgPadding * 2 - let svgFile = createSvg(svgHeight, svgWidth) - svgContent = - `` + - svgContent - svgFile.innerHTML = svgContent - // document.body.append(svgFile) - return svgFile -} - -function createSvg(height, width) { - let svg = $d.createElementNS('http://www.w3.org/2000/svg', 'svg') - svg.setAttribute('height', height) - svg.setAttribute('width', width) - svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - svg.setAttribute('version', '1.2') - svg.setAttribute('xlink', 'http://www.w3.org/1999/xlink') - return svg -} - -function RootToSvg() { - let root = document.querySelector('root') - let rootTpc = document.querySelector('root > tpc') - let rect = rootTpc.getBoundingClientRect() - let top = 0 - let left = 0 - let nodeObj = document.querySelector('root > tpc').nodeObj - let rootOffsetY = root.offsetTop - maxTop - let rootOffsetX = root.offsetLeft - maxLeft - - let svg2ndEle = document.querySelector('.lines') - - let lines = `${svg2ndEle.innerHTML}` - return ( - lines + - ` - - - ${nodeObj.topic} - - ` - ) -} - -function PrimaryToSvg(primaryNode) { - let topics = primaryNode.querySelectorAll('tpc') - let primaryNodeOffsetY = primaryNode.offsetTop - maxTop - let primaryNodeOffsetX = primaryNode.offsetLeft - maxLeft - - let svg = '' - let subLines = primaryNode.querySelector('.subLines') - svg += `` - svg += subLines ? subLines.innerHTML : '' - for (let i = 0; i < topics.length; i++) { - let tpc = topics[i] - let t = tpc.parentNode - let nodeObj = tpc.nodeObj - if (nodeObj.root) { continue } - let tpcRect = tpc.getBoundingClientRect() - let top = t.offsetTop - let left = t.offsetLeft - let tpcStyle = getComputedStyle(tpc) - let tStyle = getComputedStyle(t) - let topicOffsetLeft = - left + parseInt(tStyle.paddingLeft) + parseInt(tpcStyle.paddingLeft) - let topicOffsetTop = - top + - parseInt(tStyle.paddingTop) + - parseInt(tpcStyle.paddingTop) + - parseInt(tpcStyle.fontSize) - let topicOffsetTopTop = - top + - parseInt(tStyle.paddingTop) + - parseInt(tpcStyle.paddingTop) - // style render - let border = '' - if (tpcStyle.borderWidth != '0px') { - border = `` - } - let backgroundColor = '' - if (tpcStyle.backgroundColor != 'rgba(0, 0, 0, 0)') { - backgroundColor = `` - } - // render tags - let tags = '' - if (nodeObj.tags && nodeObj.tags.length) { - let tagsEle = tpc.querySelectorAll('.tags > span') - for (let i = 0; i < tagsEle.length; i++) { - let tag = tagsEle[i] - let tagRect = tag.getBoundingClientRect() - tags += ` - ${tag.innerHTML}` - } - } - let icons = '' - if (nodeObj.icons && nodeObj.icons.length) { - let iconsEle = tpc.querySelectorAll('.icons > span') - for (let i = 0; i < iconsEle.length; i++) { - let icon = iconsEle[i] - let iconRect = icon.getBoundingClientRect() - icons += ` - ${icon.innerHTML}` - } - } - // render every single node - svg += ` - ${border} - ${backgroundColor} - - - ${nodeObj.topic} - ${icons} - - - ${tags} - ` - } - svg += '' - return svg -} - -export let exportSvg = function () { - let svgFile = generateSvgDom() - let dlUrl = URL.createObjectURL( - new Blob([head + svgFile.outerHTML.replace(/ /g, ' ')]) - ) - let a = document.createElement('a') - a.href = dlUrl - a.download = 'me-mindmap.svg' - a.click() -} - -export let exportPng = async function () { - let svgFile = generateSvgDom() - const canvas = document.createElement('canvas') - canvas.style.display = 'none' - const ctx = canvas.getContext('2d') - // Canvg do not support foreignObject - let v = await Canvg.fromString( - ctx, - head + svgFile.outerHTML.replace(/ /g, ' ') - ) - v.start() - let imgURL = canvas.toDataURL('image/png') - let a = document.createElement('a') - a.href = imgURL - a.download = 'me-mindmap.png' - a.click() -} - - -export default { - exportSvg, exportPng -} \ No newline at end of file diff --git a/painter/index.js b/painter/index.js deleted file mode 100644 index 0a89c1dc..00000000 --- a/painter/index.js +++ /dev/null @@ -1,284 +0,0 @@ -import Canvg from 'canvg' - -let head = `` -let IMG_PADDING = 40 -let $d = document -let maxTop, maxBottom, maxLeft, maxRight, svgHeight, svgWidth - -function initVar() { - maxTop = 10000 - maxBottom = 10000 - maxLeft = 10000 - maxRight = 10000 - svgHeight = 0 - svgWidth = 0 -} - -function generateSvgDom() { - let primaryNodes = $d.querySelectorAll('.box > grp, root') - let svgContent = '' - // calculate distance to center from top, left, bottom, right - for (let i = 0; i < primaryNodes.length; i++) { - let primaryNode = primaryNodes[i] - let rect = primaryNode.getBoundingClientRect() - let top = primaryNode.offsetTop - let bottom = top + rect.height - let left = primaryNode.offsetLeft - let right = left + rect.width - - if (top < maxTop) { - maxTop = top - } - if (bottom > maxBottom) { - maxBottom = bottom - } - if (left < maxLeft) { - maxLeft = left - } - if (right > maxRight) { - maxRight = right - } - } - - for (let i = 0; i < primaryNodes.length; i++) { - let primaryNode = primaryNodes[i] - if(primaryNode.tagName === 'ROOT') continue - svgContent += PrimaryToSvg(primaryNode) - } - console.log(maxTop, maxBottom, maxLeft, maxRight) - svgContent += RootToSvg() - // image margin - svgHeight = maxBottom - maxTop + IMG_PADDING * 2 - svgWidth = maxRight - maxLeft + IMG_PADDING * 2 - // svgContent += customLinkTransform() - let svgFile = createSvg(svgHeight, svgWidth) - svgContent = - `` + - svgContent - svgFile.innerHTML = svgContent - // document.body.append(svgFile) - return svgFile -} - -function createSvg(height, width) { - let svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg') - svg.setAttribute('height', height) - svg.setAttribute('width', width) - svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg') - svg.setAttribute('version', '1.2') - svg.setAttribute('xlink', 'http://www.w3.org/1999/xlink') - return svg -} - -function RootToSvg() { - let root = $d.querySelector('root') - let rootTpc = $d.querySelector('root > tpc') - let rect = rootTpc.getBoundingClientRect() - let top = 0 - let left = 0 - let nodeObj = $d.querySelector('root > tpc').nodeObj - let rootOffsetY = root.offsetTop - maxTop - let rootOffsetX = root.offsetLeft - maxLeft - - let svg2ndEle = $d.querySelector('.lines') - - let lines = `${svg2ndEle.innerHTML}` - return ( - lines + - ` - - - ${nodeObj.topic} - - ` - ) -} - -function PrimaryToSvg(primaryNode) { - let topics = primaryNode.querySelectorAll('tpc') - let primaryNodeOffsetY = primaryNode.offsetTop - maxTop - let primaryNodeOffsetX = primaryNode.offsetLeft - maxLeft - - let svg = '' - let subLines = primaryNode.querySelector('.subLines') - svg += `` - svg += subLines ? subLines.innerHTML : '' - for (let i = 0; i < topics.length; i++) { - let tpc = topics[i] - let t = tpc.parentNode - let nodeObj = tpc.nodeObj - if (nodeObj.root) { - continue - } - let tpcRect = tpc.getBoundingClientRect() - let top = t.offsetTop - let left = t.offsetLeft - let tpcStyle = getComputedStyle(tpc) - let tStyle = getComputedStyle(t) - let topicOffsetLeft = - left + parseInt(tStyle.paddingLeft) + parseInt(tpcStyle.paddingLeft) - let topicOffsetTop = - top + - parseInt(tStyle.paddingTop) + - parseInt(tpcStyle.paddingTop) + - parseInt(tpcStyle.fontSize) - // style render - let border = '' - if (tpcStyle.borderWidth != '0px') { - border = `` - } - let backgroundColor = '' - if (tpcStyle.backgroundColor != 'rgba(0, 0, 0, 0)') { - backgroundColor = `` - } - // render tags - let tags = '' - if (nodeObj.tags && nodeObj.tags.length) { - let tagsEle = tpc.querySelectorAll('.tags > span') - for (let i = 0; i < tagsEle.length; i++) { - let tag = tagsEle[i] - let tagRect = tag.getBoundingClientRect() - tags += ` - ${tag.innerHTML}` - } - } - let icons = '' - if (nodeObj.icons && nodeObj.icons.length) { - let iconsEle = tpc.querySelectorAll('.icons > span') - for (let i = 0; i < iconsEle.length; i++) { - let icon = iconsEle[i] - let iconRect = icon.getBoundingClientRect() - icons += ` - ${icon.innerHTML}` - } - } - svg += ` - ${border} - ${backgroundColor} - - ${nodeObj.topic} - ${icons} - - ${tags} - ` - } - svg += '' - return svg -} - -function splitMultipleLineText() { - const maxWidth = 800 // should minus padding - let text = '' - let textEl = document.createElement('span') - textEl.style.cssText = - 'padding:0;margin:0;font-family:微软雅黑;font-size:18px;font-weight:bolder;' - textEl.innerHTML = '' - let lines = [] - for (let i = 0; i < text.length; i++) { - textEl.innerHTML += text[i] - let w = textEl.getBoundingClientRect().width - if (w > maxWidth) { - lines.push(textEl.innerHTML) - textEl.innerHTML = '' - } - } - return lines -} - -function getFileName() { - return $d.querySelector('root > tpc').innerText -} - -function customLinkTransform() { - let customLinks = $d.querySelector('.topiclinks').children - let resLinks = '' - for (let i = 0; i < customLinks.length; i++) { - let customLink = customLinks[i].outerHTML - let cnt = 0 - let data = customLink.replace(/\d+(\.\d+)? /g, function (match) { - match = Number(match) - console.log(match, svgWidth, svgHeight) - let res - if (match < 256) { - res = match - } else { - if (cnt % 2) { - // y - res = match - 10000 + svgHeight / 2 - } else { - // x - res = match - 10000 + svgWidth / 2 - } - } - cnt++ - return res + ' ' - }) - resLinks += data - } - console.log(resLinks) - return resLinks -} - -export let exportSvg = function (instance, fileName) { - if (!instance) throw new Error('Mind-elixir instance is not presented. ---> exportSvg(instance, fileName)') - initVar() - $d = instance.container - let svgFile = generateSvgDom() - let dlUrl = URL.createObjectURL( - new Blob([head + svgFile.outerHTML.replace(/ /g, ' ')]) - ) - let a = document.createElement('a') - a.href = dlUrl - a.download = (fileName || getFileName()) + '.svg' - a.click() -} - -export let exportPng = async function (instance, fileName) { - if (!instance) throw new Error('Mind-elixir instance is not presented. ---> exportSvg(instance, fileName)') - initVar() - $d = instance.container - let svgFile = generateSvgDom() - const canvas = document.createElement('canvas') - canvas.style.display = 'none' - const ctx = canvas.getContext('2d') - - let v = await Canvg.fromString( - ctx, - head + svgFile.outerHTML.replace(/ /g, ' ') - ) - v.start() - let imgURL = canvas.toDataURL('image/png') - let a = document.createElement('a') - a.href = imgURL - a.download = fileName || getFileName() + '.png' - a.click() -} - -export default { - exportSvg, - exportPng, -} diff --git a/readme.md b/readme.md index e91448e4..e2b0c83e 100644 --- a/readme.md +++ b/readme.md @@ -21,11 +21,15 @@ Mind elixir is a free open source mind map core. - High performance -- Small size +- Lightweight - Framework agnostic - Pluginable - Build-in drag and drop / node edit plugin +## Doc + +https://doc.mind-elixir.com/ + ## Try now ![mindelixir](https://raw.githubusercontent.com/ssshooter/mind-elixir-core/master/images/screenshot.png) @@ -78,7 +82,6 @@ import MindElixir, { E } from 'mind-elixir' ```javascript import MindElixir, { E } from 'mind-elixir' -import { exportSvg, exportPng } from '../dist/painter' import example from '../dist/example1' let options = { @@ -212,24 +215,7 @@ let mind = new MindElixir({ }) ``` -### Export as image - -**WIP** - -```javascript -import painter from 'mind-elixir/dist/painter' -painter.exportSvg() -painter.exportPng() -``` - -## Doc - -https://doc.mind-elixir.com/ - ## Not only core - [@mind-elixir/export-xmind](https://github.com/ssshooter/export-xmind) - -## Thanks - -[canvg](https://github.com/canvg/canvg) +- [@mind-elixir/export-image](https://github.com/ssshooter/export-image) (WIP🚧) diff --git a/src/dev.dist.js b/src/dev.dist.js index 95cc3b4d..9a6e54ee 100644 --- a/src/dev.dist.js +++ b/src/dev.dist.js @@ -1,5 +1,4 @@ import MindElixir, { E } from '../dist/MindElixir' -import { exportSvg, exportPng } from '../dist/painter' import example from '../dist/example1' // import example2 from '../dist/example2' @@ -84,5 +83,3 @@ mind.bus.addListener('selectNode', node => { window.m = mind // window.m2 = mind2 window.M = MindElixir -window.exportSvg = exportSvg -window.exportPng = exportPng diff --git a/src/dev.ts b/src/dev.ts index 28a7c13e..3506427f 100644 --- a/src/dev.ts +++ b/src/dev.ts @@ -1,6 +1,5 @@ import MindElixir, { E } from './index' import MindElixirLite from './index.lite' -import { exportSvg, exportPng } from '../painter/index' import example from './exampleData/1' import example2 from './exampleData/2' import example3 from './exampleData/3' @@ -103,5 +102,3 @@ window.m = mind // window.m2 = mind2 window.M = MindElixir window.E = MindElixir.E -window.exportSvg = exportSvg -window.exportPng = exportPng diff --git a/webpack.config.js b/webpack.config.js index 8a335211..d55bd614 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -64,7 +64,6 @@ module.exports = (env, argv) => { entry: { MindElixir: './src/index.ts', MindElixirLite: './src/index.lite.ts', - painter: './painter/index.js', example1: './src/exampleData/1.js', example2: './src/exampleData/2.js', },
- ${nodeObj.topic} - ${icons} -