diff --git a/simple-mind-map/index.js b/simple-mind-map/index.js index 48587f37..23db2ceb 100644 --- a/simple-mind-map/index.js +++ b/simple-mind-map/index.js @@ -19,7 +19,8 @@ import { simpleDeepClone, getType, getObjectChangedProps, - isUndef + isUndef, + handleGetSvgDataExtraContent } from './src/utils' import defaultTheme, { checkIsNodeSizeIndependenceConfig @@ -414,7 +415,18 @@ class MindMap { } // 获取svg数据 - getSvgData({ paddingX = 0, paddingY = 0, ignoreWatermark = false } = {}) { + getSvgData({ + paddingX = 0, + paddingY = 0, + ignoreWatermark = false, + addContentToHeader, + addContentToFooter + } = {}) { + const { cssTextList, header, headerHeight, footer, footerHeight } = + handleGetSvgDataExtraContent({ + addContentToHeader, + addContentToFooter + }) const svg = this.svg const draw = this.draw // 保存原始信息 @@ -427,8 +439,9 @@ class MindMap { // 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法 const rect = draw.rbox() // 内边距 + const fixHeight = 0 rect.width += paddingX * 2 - rect.height += paddingY * 2 + rect.height += paddingY * 2 + fixHeight + headerHeight + footerHeight draw.translate(paddingX, paddingY) // 将svg设置为实际内容的宽高 svg.size(rect.width, rect.height) @@ -466,7 +479,21 @@ class MindMap { this.watermark.isInExport = false } // 添加必要的样式 - clone.add(SVG(``)) + ;[cssContent, ...cssTextList].forEach(s => { + clone.add(SVG(``)) + }) + // 附加内容 + if (header && headerHeight > 0) { + clone.findOne('.smm-container').translate(0, headerHeight) + header.width(rect.width) + header.y(paddingY) + clone.add(header, 0) + } + if (footer && footerHeight > 0) { + footer.width(rect.width) + footer.y(rect.height - paddingY - footerHeight) + clone.add(footer) + } // 修正defs里定义的元素的id,因为clone时defs里的元素的id会继续递增,导致和内容中引用的id对不上 const defs = svg.find('defs') const defs2 = clone.find('defs') diff --git a/simple-mind-map/src/constants/defaultOptions.js b/simple-mind-map/src/constants/defaultOptions.js index fa1f8549..cab8da64 100644 --- a/simple-mind-map/src/constants/defaultOptions.js +++ b/simple-mind-map/src/constants/defaultOptions.js @@ -294,8 +294,8 @@ export const defaultOpt = { beforeShortcutRun: null, // 彩虹线条配置,需要先注册RainbowLines插件 rainbowLinesConfig: { - open: false,// 是否开启彩虹线条 - colorsList: []// 自定义彩虹线条的颜色列表,如果不设置,会使用默认颜色列表 + open: false, // 是否开启彩虹线条 + colorsList: [] // 自定义彩虹线条的颜色列表,如果不设置,会使用默认颜色列表 /* [ 'rgb(255, 213, 73)', @@ -307,5 +307,16 @@ export const defaultOpt = { 'rgb(152, 132, 234)' ] */ - } + }, + // 导出png、svg、pdf时在头部和尾部添加自定义内容 + // 可传递一个函数,这个函数需要返回如下数据: + /* + { + el,// 要追加的自定义DOM节点,样式可内联 + cssText,// 可选,如果样式不想内联,可以传递该值,一个css字符串 + height: 50// 返回的DOM节点的高度,必须传递 + } + */ + addContentToHeader: null, + addContentToFooter: null } diff --git a/simple-mind-map/src/plugins/Export.js b/simple-mind-map/src/plugins/Export.js index a556e5fd..589ff89a 100644 --- a/simple-mind-map/src/plugins/Export.js +++ b/simple-mind-map/src/plugins/Export.js @@ -48,11 +48,13 @@ class Export { // 获取svg数据 async getSvgData() { - let { exportPaddingX, exportPaddingY, errorHandler, resetCss } = + let { exportPaddingX, exportPaddingY, errorHandler, resetCss, addContentToHeader, addContentToFooter } = this.mindMap.opt let { svg, svgHTML } = this.mindMap.getSvgData({ paddingX: exportPaddingX, - paddingY: exportPaddingY + paddingY: exportPaddingY, + addContentToHeader, + addContentToFooter }) // svg的image标签,把图片的url转换成data:url类型,否则导出会丢失图片 const task1 = this.createTransformImgTaskList( diff --git a/simple-mind-map/src/utils/index.js b/simple-mind-map/src/utils/index.js index 87292a59..d234d976 100644 --- a/simple-mind-map/src/utils/index.js +++ b/simple-mind-map/src/utils/index.js @@ -4,6 +4,7 @@ import { selfCloseTagList } from '../constants/constant' import MersenneTwister from './mersenneTwister' +import { ForeignObject } from '@svgdotjs/svg.js' // 深度优先遍历树 export const walk = ( @@ -1315,3 +1316,46 @@ export const getRectRelativePosition = (rect1, rect2) => { return 'overlap' } } + +// 处理获取svg内容时添加额外内容 +export const handleGetSvgDataExtraContent = ({ + addContentToHeader, + addContentToFooter +}) => { + // 追加内容 + const cssTextList = [] + let header = null + let headerHeight = 0 + let footer = null + let footerHeight = 0 + const handle = (fn, callback) => { + if (typeof fn === 'function') { + const { el, cssText, height } = fn() + if (el instanceof HTMLElement) { + el.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml') + const foreignObject = new ForeignObject() + foreignObject.height(height) + foreignObject.add(el) + callback(foreignObject, height) + } + if (cssText) { + cssTextList.push(cssText) + } + } + } + handle(addContentToHeader, (foreignObject, height) => { + header = foreignObject + headerHeight = height + }) + handle(addContentToFooter, (foreignObject, height) => { + footer = foreignObject + footerHeight = height + }) + return { + cssTextList, + header, + headerHeight, + footer, + footerHeight + } +}