import View from './src/View' import Event from './src/Event' import Render from './src/Render' import merge from 'deepmerge' import theme from './src/themes' import Style from './src/Style' import KeyCommand from './src/KeyCommand' import Command from './src/Command' import BatchExecution from './src/BatchExecution' import Export from './src/Export' import Select from './src/Select' import Drag from './src/Drag' import MiniMap from './src/MiniMap'; import { layoutValueList } from './src/utils/constant' import { SVG } from '@svgdotjs/svg.js' import xmind from './src/parse/xmind' import { simpleDeepClone } from './src/utils'; // 默认选项配置 const defaultOpt = { // 是否只读 readonly: false, // 布局 layout: 'logicalStructure', // 主题 theme: 'default', // 内置主题:default(默认主题) // 主题配置,会和所选择的主题进行合并 themeConfig: {}, // 放大缩小的增量比例 scaleRatio: 0.1, // 最多显示几个标签 maxTag: 5, // 导出图片时的内边距 exportPadding: 20, // 展开收缩按钮尺寸 expandBtnSize: 20, // 节点里图片和文字的间距 imgTextMargin: 5, // 节点里各种文字信息的间距,如图标和文字的间距 textContentMargin: 2, // 多选节点时鼠标移动到边缘时的画布移动偏移量 selectTranslateStep: 3, // 多选节点时鼠标移动距边缘多少距离时开始偏移 selectTranslateLimit: 20, // 自定义节点备注内容显示 customNoteContentShow: null /* { show(){}, hide(){} } */ } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-06 11:18:47 * @Desc: 思维导图 */ class MindMap { /** * javascript comment * @Author: 王林25 * @Date: 2021-04-06 11:19:01 * @Desc: 构造函数 */ constructor(opt = {}) { // 合并选项 this.opt = this.handleOpt(merge(defaultOpt, opt)) // 容器元素 this.el = this.opt.el this.elRect = this.el.getBoundingClientRect() // 画布宽高 this.width = this.elRect.width this.height = this.elRect.height // 画布 this.svg = SVG().addTo(this.el).size(this.width, this.height) this.draw = this.svg.group() // 节点id this.uid = 0 // 初始化主题 this.initTheme() // 事件类 this.event = new Event({ mindMap: this }) // 按键类 this.keyCommand = new KeyCommand({ mindMap: this }) // 命令类 this.command = new Command({ mindMap: this }) // 渲染类 this.renderer = new Render({ mindMap: this }) // 视图操作类 this.view = new View({ mindMap: this, draw: this.draw }) // 小地图类 this.miniMap = new MiniMap({ mindMap: this }) // 导出类 this.doExport = new Export({ mindMap: this }) // 选择类 this.select = new Select({ mindMap: this }) // 拖动类 this.drag = new Drag({ mindMap: this }) // 批量执行类 this.batchExecution = new BatchExecution() // 初始渲染 this.reRender() setTimeout(() => { this.command.addHistory() }, 0) } /** * @Author: 王林 * @Date: 2021-07-01 22:15:22 * @Desc: 配置参数处理 */ handleOpt(opt) { // 检查布局配置 if (!layoutValueList.includes(opt.layout)) { opt.layout = 'logicalStructure' } // 检查主题配置 opt.theme = opt.theme && theme[opt.theme] ? opt.theme : 'default' return opt } /** * javascript comment * @Author: 王林25 * @Date: 2021-04-06 18:47:29 * @Desc: 渲染,部分渲染 */ render() { this.batchExecution.push('render', () => { this.initTheme() this.renderer.reRender = false this.renderer.render() }) } /** * @Author: 王林 * @Date: 2021-07-08 22:05:11 * @Desc: 重新渲染 */ reRender() { this.batchExecution.push('render', () => { this.draw.clear() this.initTheme() this.renderer.reRender = true this.renderer.render() }) } /** * @Author: 王林 * @Date: 2021-07-11 21:16:52 * @Desc: 容器尺寸变化,调整尺寸 */ resize() { this.elRect = this.el.getBoundingClientRect() this.width = this.elRect.width this.height = this.elRect.height this.svg.size(this.width, this.height) } /** * @Author: 王林 * @Date: 2021-04-24 13:25:50 * @Desc: 监听事件 */ on(event, fn) { this.event.on(event, fn) } /** * @Author: 王林 * @Date: 2021-04-24 13:51:35 * @Desc: 触发事件 */ emit(event, ...args) { this.event.emit(event, ...args) } /** * @Author: 王林 * @Date: 2021-04-24 13:53:54 * @Desc: 解绑事件 */ off(event, fn) { this.event.off(event, fn) } /** * @Author: 王林 * @Date: 2021-05-05 13:32:43 * @Desc: 设置主题 */ initTheme() { // 合并主题配置 this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig) // 设置背景样式 Style.setBackgroundStyle(this.el, this.themeConfig) } /** * @Author: 王林 * @Date: 2021-05-05 13:52:08 * @Desc: 设置主题 */ setTheme(theme) { this.renderer.clearAllActive() this.opt.theme = theme this.reRender() } /** * @Author: 王林 * @Date: 2021-06-25 23:52:37 * @Desc: 获取当前主题 */ getTheme() { return this.opt.theme } /** * @Author: 王林 * @Date: 2021-05-05 13:50:17 * @Desc: 设置主题配置 */ setThemeConfig(config) { this.opt.themeConfig = config this.reRender() } /** * @Author: 王林 * @Date: 2021-08-01 10:38:34 * @Desc: 获取自定义主题配置 */ getCustomThemeConfig() { return this.opt.themeConfig } /** * @Author: 王林 * @Date: 2021-05-05 14:01:29 * @Desc: 获取某个主题配置值 */ getThemeConfig(prop) { return prop === undefined ? this.themeConfig : this.themeConfig[prop] } /** * javascript comment * @Author: 王林25 * @Date: 2021-07-13 16:17:06 * @Desc: 获取当前布局结构 */ getLayout() { return this.opt.layout } /** * javascript comment * @Author: 王林25 * @Date: 2021-07-13 16:17:33 * @Desc: 设置布局结构 */ setLayout(layout) { // 检查布局配置 if (!layoutValueList.includes(layout)) { layout = 'logicalStructure' } this.opt.layout = layout this.renderer.setLayout() this.render() } /** * @Author: 王林 * @Date: 2021-05-04 13:01:00 * @Desc: 执行命令 */ execCommand(...args) { this.command.exec(...args) } /** * @Author: 王林 * @Date: 2021-08-03 22:58:12 * @Desc: 动态设置思维导图数据,纯节点数据 */ setData(data) { this.execCommand('CLEAR_ACTIVE_NODE') this.command.clearHistory() this.renderer.renderTree = data this.reRender() } /** * javascript comment * @Author: 王林25 * @Date: 2022-09-21 16:39:13 * @Desc: 动态设置思维导图数据,包括节点数据、布局、主题、视图 */ setFullData(data) { if (data.root) { this.setData(data.root) } if (data.layout) { this.setLayout(data.layout) } if (data.theme) { if (data.theme.template) { this.setTheme(data.theme.template) } if (data.theme.config) { this.setThemeConfig(data.theme.config) } } if (data.view) { this.view.setTransformData(data.view) } } /** * javascript comment * @Author: 王林 * @Date: 2022-09-24 14:42:07 * @Desc: 获取思维导图数据,节点树、主题、布局等 */ getData(withConfig) { let nodeData = this.command.getCopyData() let data = {} if (withConfig) { data = { layout: this.getLayout(), root: nodeData, theme: { template: this.getTheme(), config: this.getCustomThemeConfig() }, view: this.view.getTransformData() } } else { data = nodeData } return simpleDeepClone(data) } /** * @Author: 王林 * @Date: 2021-07-01 22:06:38 * @Desc: 导出 */ async export(...args) { let result = await this.doExport.export(...args) return result } /** * @Author: 王林 * @Date: 2021-07-11 09:20:03 * @Desc: 转换位置 */ toPos(x, y) { return { x: x - this.elRect.left, y: y - this.elRect.top } } /** * javascript comment * @Author: 王林25 * @Date: 2022-06-08 14:12:38 * @Desc: 设置只读模式、编辑模式 */ setMode(mode) { if (!['readonly', 'edit'].includes(mode)) { return } this.opt.readonly = mode === 'readonly' if (this.opt.readonly) { // 取消当前激活的元素 this.renderer.clearAllActive() } this.emit('mode_change', mode) } } MindMap.xmind = xmind export default MindMap