mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-18 22:38:46 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8441986ca7 | ||
|
|
c8b50908e1 | ||
|
|
7e11fde892 | ||
|
|
3d9f3bd7a8 | ||
|
|
46e11649b0 | ||
|
|
161ef7590c | ||
|
|
ca660a3c74 | ||
|
|
7a24872331 | ||
|
|
eb4ea9fb3a | ||
|
|
64228c02ff | ||
|
|
f184a5d948 | ||
|
|
0bf5b2d6f7 | ||
|
|
74a52ea386 | ||
|
|
9914eef5b9 | ||
|
|
f547f741f2 | ||
|
|
c26149fa42 | ||
|
|
b2aa3648eb | ||
|
|
b997604ab2 | ||
|
|
c6929b82ad | ||
|
|
b40da53aef | ||
|
|
1e5dfd97e1 | ||
|
|
97bcc22abd | ||
|
|
bd655839cb | ||
|
|
a53a4e8e1d | ||
|
|
eb01646747 | ||
|
|
d27eee0fae | ||
|
|
92ee241ed8 | ||
|
|
660906e4c5 | ||
|
|
971f0d3446 | ||
|
|
63eccede7f | ||
|
|
5bd6adb488 | ||
|
|
fbdc5e0f39 | ||
|
|
5e994322fe |
1243
README.zh-Hans.md
1243
README.zh-Hans.md
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>一个简单的web思维导图实现</title><link href="dist/js/chunk-2d20ec02.917aff76.js" rel="prefetch"><link href="dist/js/chunk-2d216b67.2d06497a.js" rel="prefetch"><link href="dist/js/chunk-3a2f3e67.13278516.js" rel="prefetch"><link href="dist/css/app.3d234c87.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.94891485.css" rel="preload" as="style"><link href="dist/js/app.54d858bc.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.6cac1a4d.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.94891485.css" rel="stylesheet"><link href="dist/css/app.3d234c87.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="dist/js/chunk-vendors.6cac1a4d.js"></script><script src="dist/js/app.54d858bc.js"></script></body></html>
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="./dist/logo.png"><title>一个简单的web思维导图实现</title><link href="dist/js/chunk-2d0a3179.f79d6590.js" rel="prefetch"><link href="dist/js/chunk-2d0aa579.d901cc5e.js" rel="prefetch"><link href="dist/js/chunk-2d0aa978.ae72a285.js" rel="prefetch"><link href="dist/js/chunk-2d0ab10b.13ffd981.js" rel="prefetch"><link href="dist/js/chunk-2d0abe0f.f7178a38.js" rel="prefetch"><link href="dist/js/chunk-2d0b361e.64d433a0.js" rel="prefetch"><link href="dist/js/chunk-2d0b91e5.de98db92.js" rel="prefetch"><link href="dist/js/chunk-2d0b92c3.a48a667e.js" rel="prefetch"><link href="dist/js/chunk-2d0bd54e.e56450f0.js" rel="prefetch"><link href="dist/js/chunk-2d0be174.1531a230.js" rel="prefetch"><link href="dist/js/chunk-2d0c0a44.d2768274.js" rel="prefetch"><link href="dist/js/chunk-2d0c14fc.a89a80b4.js" rel="prefetch"><link href="dist/js/chunk-2d0c18d8.647d892f.js" rel="prefetch"><link href="dist/js/chunk-2d0c191e.6fb13561.js" rel="prefetch"><link href="dist/js/chunk-2d0c1a01.49c23f9e.js" rel="prefetch"><link href="dist/js/chunk-2d0d9fbc.adce6374.js" rel="prefetch"><link href="dist/js/chunk-2d0da701.2e0766e2.js" rel="prefetch"><link href="dist/js/chunk-2d0dad5f.ec79eebe.js" rel="prefetch"><link href="dist/js/chunk-2d0db0f2.19efc7d4.js" rel="prefetch"><link href="dist/js/chunk-2d0dddce.6a579f6f.js" rel="prefetch"><link href="dist/js/chunk-2d0ddf37.d162efb9.js" rel="prefetch"><link href="dist/js/chunk-2d0de01b.21eae2e6.js" rel="prefetch"><link href="dist/js/chunk-2d0e2326.f3a9c7fc.js" rel="prefetch"><link href="dist/js/chunk-2d0e268c.57926a64.js" rel="prefetch"><link href="dist/js/chunk-2d0e5089.2b202405.js" rel="prefetch"><link href="dist/js/chunk-2d0e9742.a2d22497.js" rel="prefetch"><link href="dist/js/chunk-2d0f026c.67441d40.js" rel="prefetch"><link href="dist/js/chunk-2d2082b9.fe227afb.js" rel="prefetch"><link href="dist/js/chunk-2d208ffa.9df071bd.js" rel="prefetch"><link href="dist/js/chunk-2d20ec02.917aff76.js" rel="prefetch"><link href="dist/js/chunk-2d20f68f.acd7e356.js" rel="prefetch"><link href="dist/js/chunk-2d210a7a.5a4025ce.js" rel="prefetch"><link href="dist/js/chunk-2d216004.905379d5.js" rel="prefetch"><link href="dist/js/chunk-2d216b67.2d06497a.js" rel="prefetch"><link href="dist/js/chunk-2d217907.cc6917a4.js" rel="prefetch"><link href="dist/js/chunk-2d226d0a.3703455b.js" rel="prefetch"><link href="dist/js/chunk-2d2299c3.ffd15e65.js" rel="prefetch"><link href="dist/js/chunk-2d22bd06.cace3b1b.js" rel="prefetch"><link href="dist/js/chunk-2d2308b0.fb49d06b.js" rel="prefetch"><link href="dist/js/chunk-2d238428.266d8f0c.js" rel="prefetch"><link href="dist/js/chunk-3a2f3e67.13278516.js" rel="prefetch"><link href="dist/css/app.8a532989.css" rel="preload" as="style"><link href="dist/css/chunk-vendors.1790fe42.css" rel="preload" as="style"><link href="dist/js/app.52520638.js" rel="preload" as="script"><link href="dist/js/chunk-vendors.7f3b8358.js" rel="preload" as="script"><link href="dist/css/chunk-vendors.1790fe42.css" rel="stylesheet"><link href="dist/css/app.8a532989.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script src="dist/js/chunk-vendors.7f3b8358.js"></script><script src="dist/js/app.52520638.js"></script></body></html>
|
||||
@@ -925,5 +925,6 @@ export default {
|
||||
"layout": "logicalStructure",
|
||||
// "layout": "mindMap",
|
||||
// "layout": "catalogOrganization"
|
||||
// "layout": "organizationStructure"
|
||||
// "layout": "organizationStructure",
|
||||
"config": {}
|
||||
}
|
||||
@@ -62,5 +62,6 @@
|
||||
"sx": 0,
|
||||
"sy": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {}
|
||||
}
|
||||
20
simple-mind-map/full.js
Normal file
20
simple-mind-map/full.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import MindMap from './index'
|
||||
import MiniMap from './src/MiniMap.js'
|
||||
import Watermark from './src/Watermark.js'
|
||||
import KeyboardNavigation from './src/KeyboardNavigation.js'
|
||||
import Export from './src/Export.js'
|
||||
import Drag from './src/Drag.js'
|
||||
import Select from './src/Select.js'
|
||||
import xmind from './src/parse/xmind.js'
|
||||
|
||||
MindMap.xmind = xmind
|
||||
|
||||
MindMap
|
||||
.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
.usePlugin(Drag)
|
||||
.usePlugin(KeyboardNavigation)
|
||||
.usePlugin(Export)
|
||||
.usePlugin(Select)
|
||||
|
||||
export default MindMap
|
||||
@@ -7,15 +7,9 @@ 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'
|
||||
import KeyboardNavigation from './src/KeyboardNavigation'
|
||||
import defaultTheme from './src/themes/default'
|
||||
|
||||
// 默认选项配置
|
||||
@@ -45,13 +39,29 @@ const defaultOpt = {
|
||||
// 多选节点时鼠标移动距边缘多少距离时开始偏移
|
||||
selectTranslateLimit: 20,
|
||||
// 自定义节点备注内容显示
|
||||
customNoteContentShow: null
|
||||
customNoteContentShow: null,
|
||||
/*
|
||||
{
|
||||
show(){},
|
||||
hide(){}
|
||||
}
|
||||
*/
|
||||
// 是否开启节点自由拖拽
|
||||
enableFreeDrag: false,
|
||||
// 水印配置
|
||||
watermarkConfig: {
|
||||
text: '',
|
||||
lineSpacing: 100,
|
||||
textSpacing: 100,
|
||||
angle: 30,
|
||||
textStyle: {
|
||||
color: '#999',
|
||||
opacity: 0.5,
|
||||
fontSize: 14
|
||||
}
|
||||
},
|
||||
// 达到该宽度文本自动换行
|
||||
textAutoWrapWidth: 500
|
||||
}
|
||||
|
||||
// 思维导图
|
||||
@@ -105,34 +115,16 @@ class MindMap {
|
||||
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.keyboardNavigation = new KeyboardNavigation({
|
||||
mindMap: this
|
||||
})
|
||||
|
||||
// 批量执行类
|
||||
this.batchExecution = new BatchExecution()
|
||||
|
||||
// 注册插件
|
||||
MindMap.pluginList.forEach((plugin) => {
|
||||
this[plugin.instanceName] = new plugin({
|
||||
mindMap: this
|
||||
})
|
||||
})
|
||||
|
||||
// 初始渲染
|
||||
this.reRender()
|
||||
setTimeout(() => {
|
||||
@@ -152,21 +144,21 @@ class MindMap {
|
||||
}
|
||||
|
||||
// 渲染,部分渲染
|
||||
render() {
|
||||
render(callback) {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.initTheme()
|
||||
this.renderer.reRender = false
|
||||
this.renderer.render()
|
||||
this.renderer.render(callback)
|
||||
})
|
||||
}
|
||||
|
||||
// 重新渲染
|
||||
reRender() {
|
||||
reRender(callback) {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.draw.clear()
|
||||
this.initTheme()
|
||||
this.renderer.reRender = true
|
||||
this.renderer.render()
|
||||
this.renderer.render(callback)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -229,6 +221,16 @@ class MindMap {
|
||||
return prop === undefined ? this.themeConfig : this.themeConfig[prop]
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
getConfig(prop) {
|
||||
return prop === undefined ? this.opt : this.opt[prop]
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
updateConfig(opt = {}) {
|
||||
this.opt = this.handleOpt(merge.all([defaultOpt, this.opt, opt]))
|
||||
}
|
||||
|
||||
// 获取当前布局结构
|
||||
getLayout() {
|
||||
return this.opt.layout
|
||||
@@ -325,9 +327,61 @@ class MindMap {
|
||||
}
|
||||
this.emit('mode_change', mode)
|
||||
}
|
||||
|
||||
// 获取svg数据
|
||||
getSvgData() {
|
||||
const svg = this.svg
|
||||
const draw = this.draw
|
||||
// 保存原始信息
|
||||
const origWidth = svg.width()
|
||||
const origHeight = svg.height()
|
||||
const origTransform = draw.transform()
|
||||
const elRect = this.el.getBoundingClientRect()
|
||||
// 去除放大缩小的变换效果
|
||||
draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY)
|
||||
// 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法
|
||||
const rect = draw.rbox()
|
||||
// 将svg设置为实际内容的宽高
|
||||
svg.size(rect.width, rect.height)
|
||||
// 把实际内容变换
|
||||
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
|
||||
// 克隆一份数据
|
||||
let clone = svg.clone()
|
||||
// 如果实际图形宽高超出了屏幕宽高,且存在水印的话需要重新绘制水印,否则会出现超出部分没有水印的问题
|
||||
if ((rect.width > origWidth || rect.height > origHeight) && this.watermark && this.watermark.hasWatermark()) {
|
||||
this.width = rect.width
|
||||
this.height = rect.height
|
||||
this.watermark.draw()
|
||||
clone = svg.clone()
|
||||
this.width = origWidth
|
||||
this.height = origHeight
|
||||
this.watermark.draw()
|
||||
}
|
||||
// 恢复原先的大小和变换信息
|
||||
svg.size(origWidth, origHeight)
|
||||
draw.transform(origTransform)
|
||||
|
||||
return {
|
||||
svg: clone, // 思维导图图形的整体svg元素,包括:svg(画布容器)、g(实际的思维导图组)
|
||||
svgHTML: clone.svg(), // svg字符串
|
||||
rect: {
|
||||
...rect, // 思维导图图形未缩放时的位置尺寸等信息
|
||||
ratio: rect.width / rect.height // 思维导图图形的宽高比
|
||||
},
|
||||
origWidth, // 画布宽度
|
||||
origHeight, // 画布高度
|
||||
scaleX: origTransform.scaleX, // 思维导图图形的水平缩放值
|
||||
scaleY: origTransform.scaleY // 思维导图图形的垂直缩放值
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MindMap.xmind = xmind
|
||||
// 插件列表
|
||||
MindMap.pluginList = []
|
||||
MindMap.usePlugin = (plugin) => {
|
||||
MindMap.pluginList.push(plugin)
|
||||
return MindMap
|
||||
}
|
||||
|
||||
// 定义新主题
|
||||
MindMap.defineTheme = (name, config = {}) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.2.23",
|
||||
"version": "0.3.4",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
@@ -22,7 +22,7 @@
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"module": "index.js",
|
||||
"main": "./dist/simpleMindMap.umd.min.js",
|
||||
"__main": "./dist/simpleMindMap.umd.min.js",
|
||||
"dependencies": {
|
||||
"@svgdotjs/svg.js": "^3.0.16",
|
||||
"canvg": "^3.0.7",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// 将/** */类型的注释转换为//类型
|
||||
// 遍历所有js文件
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
@@ -11,13 +11,26 @@ const transform = dir => {
|
||||
if (fs.statSync(file).isDirectory()) {
|
||||
transform(file)
|
||||
} else if (/\.js$/.test(file)) {
|
||||
rewriteComments(file)
|
||||
transformFile(file)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const rewriteComments = file => {
|
||||
const transformFile = file => {
|
||||
console.log(file);
|
||||
let content = fs.readFileSync(file, 'utf-8')
|
||||
countCodeLines(content)
|
||||
// transformComments(file, content)
|
||||
}
|
||||
|
||||
// 统计代码行数
|
||||
let totalLines = 0
|
||||
const countCodeLines = (content) => {
|
||||
totalLines += content.split(/\n/).length
|
||||
}
|
||||
|
||||
// 转换注释类型
|
||||
const transformComments = (file, content) => {
|
||||
console.log('当前转换文件:', file)
|
||||
content = content.replace(/\/\*\*[^/]+\*\//g, str => {
|
||||
let res = /@Desc:([^\n]+)\n/g.exec(str)
|
||||
@@ -29,4 +42,5 @@ const rewriteComments = file => {
|
||||
}
|
||||
|
||||
transform(entryPath)
|
||||
rewriteComments(path.join(__dirname, '../index.js'))
|
||||
transformFile(path.join(__dirname, '../index.js'))
|
||||
console.log(totalLines);
|
||||
@@ -72,6 +72,9 @@ class Command {
|
||||
|
||||
// 添加回退数据
|
||||
addHistory() {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
let data = this.getCopyData()
|
||||
this.history.push(simpleDeepClone(data))
|
||||
this.activeHistoryIndex = this.history.length - 1
|
||||
@@ -85,6 +88,9 @@ class Command {
|
||||
|
||||
// 回退
|
||||
back(step = 1) {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
if (this.activeHistoryIndex - step >= 0) {
|
||||
this.activeHistoryIndex -= step
|
||||
this.mindMap.emit(
|
||||
@@ -98,6 +104,9 @@ class Command {
|
||||
|
||||
// 前进
|
||||
forward(step = 1) {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
let len = this.history.length
|
||||
if (this.activeHistoryIndex + step <= len - 1) {
|
||||
this.activeHistoryIndex += step
|
||||
|
||||
@@ -1,254 +1,265 @@
|
||||
import { bfsWalk, throttle } from './utils'
|
||||
import Base from './layouts/Base'
|
||||
|
||||
// 节点拖动类
|
||||
|
||||
class Drag extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor({ mindMap }) {
|
||||
super(mindMap.renderer)
|
||||
this.mindMap = mindMap
|
||||
this.reset()
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 复位
|
||||
|
||||
reset() {
|
||||
// 当前拖拽节点
|
||||
this.node = null
|
||||
// 当前重叠节点
|
||||
this.overlapNode = null
|
||||
// 当前上一个同级节点
|
||||
this.prevNode = null
|
||||
// 当前下一个同级节点
|
||||
this.nextNode = null
|
||||
// 画布的变换数据
|
||||
this.drawTransform = null
|
||||
// 克隆节点
|
||||
this.clone = null
|
||||
// 连接线
|
||||
this.line = null
|
||||
// 同级位置占位符
|
||||
this.placeholder = null
|
||||
// 鼠标按下位置和节点左上角的偏移量
|
||||
this.offsetX = 0
|
||||
this.offsetY = 0
|
||||
// 克隆节点左上角的坐标
|
||||
this.cloneNodeLeft = 0
|
||||
this.cloneNodeTop = 0
|
||||
// 当前鼠标是否按下
|
||||
this.isMousedown = false
|
||||
// 拖拽的鼠标位置变量
|
||||
this.mouseDownX = 0
|
||||
this.mouseDownY = 0
|
||||
this.mouseMoveX = 0
|
||||
this.mouseMoveY = 0
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
|
||||
bindEvent() {
|
||||
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
|
||||
this.mindMap.on('node_mousedown', (node, e) => {
|
||||
if (this.mindMap.opt.readonly || node.isGeneralization) {
|
||||
return
|
||||
}
|
||||
if (e.which !== 1 || node.isRoot) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
// 计算鼠标按下的位置距离节点左上角的距离
|
||||
this.drawTransform = this.mindMap.draw.transform()
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.offsetX = x - (node.left * scaleX + translateX)
|
||||
this.offsetY = y - (node.top * scaleY + translateY)
|
||||
this.node = node
|
||||
this.isMousedown = true
|
||||
this.mouseDownX = x
|
||||
this.mouseDownY = y
|
||||
})
|
||||
this.mindMap.on('mousemove', e => {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.mouseMoveX = x
|
||||
this.mouseMoveY = y
|
||||
if (
|
||||
Math.abs(x - this.mouseDownX) <= 10 &&
|
||||
Math.abs(y - this.mouseDownY) <= 10 &&
|
||||
!this.node.isDrag
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.mindMap.renderer.clearAllActive()
|
||||
this.onMove(x, y)
|
||||
})
|
||||
this.onMouseup = this.onMouseup.bind(this)
|
||||
this.mindMap.on('node_mouseup', this.onMouseup)
|
||||
this.mindMap.on('mouseup', this.onMouseup)
|
||||
}
|
||||
|
||||
// 鼠标松开事件
|
||||
|
||||
onMouseup(e) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.isMousedown = false
|
||||
let _nodeIsDrag = this.node.isDrag
|
||||
this.node.isDrag = false
|
||||
this.node.show()
|
||||
this.removeCloneNode()
|
||||
// 存在重叠子节点,则移动作为其子节点
|
||||
if (this.overlapNode) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
|
||||
} else if (this.prevNode) {
|
||||
// 存在前一个相邻节点,作为其下一个兄弟节点
|
||||
this.mindMap.renderer.setNodeActive(this.prevNode, false)
|
||||
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
|
||||
} else if (this.nextNode) {
|
||||
// 存在下一个相邻节点,作为其前一个兄弟节点
|
||||
this.mindMap.renderer.setNodeActive(this.nextNode, false)
|
||||
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
|
||||
} else if (_nodeIsDrag) {
|
||||
// 自定义位置
|
||||
let { x, y } = this.mindMap.toPos(
|
||||
e.clientX - this.offsetX,
|
||||
e.clientY - this.offsetY
|
||||
)
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
x = (x - translateX) / scaleX
|
||||
y = (y - translateY) / scaleY
|
||||
this.node.left = x
|
||||
this.node.top = y
|
||||
this.node.customLeft = x
|
||||
this.node.customTop = y
|
||||
this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
|
||||
this.mindMap.render()
|
||||
}
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// 创建克隆节点
|
||||
|
||||
createCloneNode() {
|
||||
if (!this.clone) {
|
||||
// 节点
|
||||
this.clone = this.node.group.clone()
|
||||
this.clone.opacity(0.5)
|
||||
this.clone.css('z-index', 99999)
|
||||
this.node.isDrag = true
|
||||
this.node.hide()
|
||||
// 连接线
|
||||
this.line = this.draw.path()
|
||||
this.line.opacity(0.5)
|
||||
this.node.styleLine(this.line, this.node)
|
||||
// 同级位置占位符
|
||||
this.placeholder = this.draw.rect().fill({
|
||||
color: this.node.style.merge('lineColor', true)
|
||||
})
|
||||
this.mindMap.draw.add(this.clone)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除克隆节点
|
||||
|
||||
removeCloneNode() {
|
||||
if (!this.clone) {
|
||||
return
|
||||
}
|
||||
this.clone.remove()
|
||||
this.line.remove()
|
||||
this.placeholder.remove()
|
||||
}
|
||||
|
||||
// 拖动中
|
||||
|
||||
onMove(x, y) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.createCloneNode()
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
this.cloneNodeLeft = x - this.offsetX
|
||||
this.cloneNodeTop = y - this.offsetY
|
||||
x = (this.cloneNodeLeft - translateX) / scaleX
|
||||
y = (this.cloneNodeTop - translateY) / scaleY
|
||||
let t = this.clone.transform()
|
||||
this.clone.translate(x - t.translateX, y - t.translateY)
|
||||
// 连接线
|
||||
let parent = this.node.parent
|
||||
this.line.plot(
|
||||
this.quadraticCurvePath(
|
||||
parent.left + parent.width / 2,
|
||||
parent.top + parent.height / 2,
|
||||
x + this.node.width / 2,
|
||||
y + this.node.height / 2
|
||||
)
|
||||
)
|
||||
this.checkOverlapNode()
|
||||
}
|
||||
|
||||
// 检测重叠节点
|
||||
|
||||
checkOverlapNode() {
|
||||
if (!this.drawTransform) {
|
||||
return
|
||||
}
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
let checkRight = this.cloneNodeLeft + this.node.width * scaleX
|
||||
let checkBottom = this.cloneNodeTop + this.node.height * scaleX
|
||||
this.overlapNode = null
|
||||
this.prevNode = null
|
||||
this.nextNode = null
|
||||
this.placeholder.size(0, 0)
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(node, false)
|
||||
}
|
||||
if (node === this.node || this.node.isParent(node)) {
|
||||
return
|
||||
}
|
||||
if (this.overlapNode || (this.prevNode && this.nextNode)) {
|
||||
return
|
||||
}
|
||||
let { left, top, width, height } = node
|
||||
let _left = left
|
||||
let _top = top
|
||||
let _bottom = top + height
|
||||
let right = (left + width) * scaleX + translateX
|
||||
let bottom = (top + height) * scaleY + translateY
|
||||
left = left * scaleX + translateX
|
||||
top = top * scaleY + translateY
|
||||
// 检测是否重叠
|
||||
if (!this.overlapNode) {
|
||||
if (
|
||||
left <= checkRight &&
|
||||
right >= this.cloneNodeLeft &&
|
||||
top <= checkBottom &&
|
||||
bottom >= this.cloneNodeTop
|
||||
) {
|
||||
this.overlapNode = node
|
||||
}
|
||||
}
|
||||
// 检测兄弟节点位置
|
||||
if (!this.prevNode && !this.nextNode && !node.isRoot) {
|
||||
// && this.node.isBrother(node)
|
||||
if (left <= checkRight && right >= this.cloneNodeLeft) {
|
||||
if (this.cloneNodeTop > bottom && this.cloneNodeTop <= bottom + 10) {
|
||||
this.prevNode = node
|
||||
this.placeholder.size(node.width, 10).move(_left, _bottom)
|
||||
} else if (checkBottom < top && checkBottom >= top - 10) {
|
||||
this.nextNode = node
|
||||
this.placeholder.size(node.width, 10).move(_left, _top - 10)
|
||||
}
|
||||
}
|
||||
import { bfsWalk, throttle } from './utils'
|
||||
import Base from './layouts/Base'
|
||||
|
||||
// 节点拖动类
|
||||
|
||||
class Drag extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor({ mindMap }) {
|
||||
super(mindMap.renderer)
|
||||
this.mindMap = mindMap
|
||||
this.reset()
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 复位
|
||||
|
||||
reset() {
|
||||
// 当前拖拽节点
|
||||
this.node = null
|
||||
// 当前重叠节点
|
||||
this.overlapNode = null
|
||||
// 当前上一个同级节点
|
||||
this.prevNode = null
|
||||
// 当前下一个同级节点
|
||||
this.nextNode = null
|
||||
// 画布的变换数据
|
||||
this.drawTransform = null
|
||||
// 克隆节点
|
||||
this.clone = null
|
||||
// 连接线
|
||||
this.line = null
|
||||
// 同级位置占位符
|
||||
this.placeholder = null
|
||||
// 鼠标按下位置和节点左上角的偏移量
|
||||
this.offsetX = 0
|
||||
this.offsetY = 0
|
||||
// 克隆节点左上角的坐标
|
||||
this.cloneNodeLeft = 0
|
||||
this.cloneNodeTop = 0
|
||||
// 当前鼠标是否按下
|
||||
this.isMousedown = false
|
||||
// 拖拽的鼠标位置变量
|
||||
this.mouseDownX = 0
|
||||
this.mouseDownY = 0
|
||||
this.mouseMoveX = 0
|
||||
this.mouseMoveY = 0
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
|
||||
bindEvent() {
|
||||
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
|
||||
this.mindMap.on('node_mousedown', (node, e) => {
|
||||
if (this.mindMap.opt.readonly || node.isGeneralization) {
|
||||
return
|
||||
}
|
||||
if (e.which !== 1 || node.isRoot) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
// 计算鼠标按下的位置距离节点左上角的距离
|
||||
this.drawTransform = this.mindMap.draw.transform()
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.offsetX = x - (node.left * scaleX + translateX)
|
||||
this.offsetY = y - (node.top * scaleY + translateY)
|
||||
this.node = node
|
||||
this.isMousedown = true
|
||||
this.mouseDownX = x
|
||||
this.mouseDownY = y
|
||||
})
|
||||
this.mindMap.on('mousemove', e => {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
return
|
||||
}
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.mouseMoveX = x
|
||||
this.mouseMoveY = y
|
||||
if (
|
||||
Math.abs(x - this.mouseDownX) <= 10 &&
|
||||
Math.abs(y - this.mouseDownY) <= 10 &&
|
||||
!this.node.isDrag
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.mindMap.renderer.clearAllActive()
|
||||
this.onMove(x, y)
|
||||
})
|
||||
this.onMouseup = this.onMouseup.bind(this)
|
||||
this.mindMap.on('node_mouseup', this.onMouseup)
|
||||
this.mindMap.on('mouseup', this.onMouseup)
|
||||
}
|
||||
|
||||
// 鼠标松开事件
|
||||
|
||||
onMouseup(e) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.isMousedown = false
|
||||
let _nodeIsDrag = this.node.isDrag
|
||||
this.node.isDrag = false
|
||||
this.node.show()
|
||||
this.removeCloneNode()
|
||||
// 存在重叠子节点,则移动作为其子节点
|
||||
if (this.overlapNode) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
|
||||
} else if (this.prevNode) {
|
||||
// 存在前一个相邻节点,作为其下一个兄弟节点
|
||||
this.mindMap.renderer.setNodeActive(this.prevNode, false)
|
||||
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
|
||||
} else if (this.nextNode) {
|
||||
// 存在下一个相邻节点,作为其前一个兄弟节点
|
||||
this.mindMap.renderer.setNodeActive(this.nextNode, false)
|
||||
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
|
||||
} else if (_nodeIsDrag && this.mindMap.opt.enableFreeDrag) {
|
||||
// 自定义位置
|
||||
let { x, y } = this.mindMap.toPos(
|
||||
e.clientX - this.offsetX,
|
||||
e.clientY - this.offsetY
|
||||
)
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
x = (x - translateX) / scaleX
|
||||
y = (y - translateY) / scaleY
|
||||
this.node.left = x
|
||||
this.node.top = y
|
||||
this.node.customLeft = x
|
||||
this.node.customTop = y
|
||||
this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
|
||||
this.mindMap.render()
|
||||
}
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// 创建克隆节点
|
||||
|
||||
createCloneNode() {
|
||||
if (!this.clone) {
|
||||
// 节点
|
||||
this.clone = this.node.group.clone()
|
||||
this.clone.opacity(0.5)
|
||||
this.clone.css('z-index', 99999)
|
||||
this.node.isDrag = true
|
||||
this.node.hide()
|
||||
// 连接线
|
||||
this.line = this.draw.path()
|
||||
this.line.opacity(0.5)
|
||||
this.node.styleLine(this.line, this.node)
|
||||
// 同级位置占位符
|
||||
this.placeholder = this.draw.rect().fill({
|
||||
color: this.node.style.merge('lineColor', true)
|
||||
})
|
||||
this.mindMap.draw.add(this.clone)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除克隆节点
|
||||
|
||||
removeCloneNode() {
|
||||
if (!this.clone) {
|
||||
return
|
||||
}
|
||||
this.clone.remove()
|
||||
this.line.remove()
|
||||
this.placeholder.remove()
|
||||
}
|
||||
|
||||
// 拖动中
|
||||
|
||||
onMove(x, y) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.createCloneNode()
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
this.cloneNodeLeft = x - this.offsetX
|
||||
this.cloneNodeTop = y - this.offsetY
|
||||
x = (this.cloneNodeLeft - translateX) / scaleX
|
||||
y = (this.cloneNodeTop - translateY) / scaleY
|
||||
let t = this.clone.transform()
|
||||
this.clone.translate(x - t.translateX, y - t.translateY)
|
||||
// 连接线
|
||||
let parent = this.node.parent
|
||||
this.line.plot(
|
||||
this.quadraticCurvePath(
|
||||
parent.left + parent.width / 2,
|
||||
parent.top + parent.height / 2,
|
||||
x + this.node.width / 2,
|
||||
y + this.node.height / 2
|
||||
)
|
||||
)
|
||||
this.checkOverlapNode()
|
||||
}
|
||||
|
||||
// 检测重叠节点
|
||||
|
||||
checkOverlapNode() {
|
||||
if (!this.drawTransform) {
|
||||
return
|
||||
}
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
let checkRight = this.cloneNodeLeft + this.node.width * scaleX
|
||||
let checkBottom = this.cloneNodeTop + this.node.height * scaleX
|
||||
this.overlapNode = null
|
||||
this.prevNode = null
|
||||
this.nextNode = null
|
||||
this.placeholder.size(0, 0)
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(node, false)
|
||||
}
|
||||
if (node === this.node || this.node.isParent(node)) {
|
||||
return
|
||||
}
|
||||
if (this.overlapNode || (this.prevNode && this.nextNode)) {
|
||||
return
|
||||
}
|
||||
let { left, top, width, height } = node
|
||||
let _left = left
|
||||
let _top = top
|
||||
let _bottom = top + height
|
||||
let right = (left + width) * scaleX + translateX
|
||||
let bottom = (top + height) * scaleY + translateY
|
||||
left = left * scaleX + translateX
|
||||
top = top * scaleY + translateY
|
||||
// 检测是否重叠
|
||||
if (!this.overlapNode) {
|
||||
if (
|
||||
left <= checkRight &&
|
||||
right >= this.cloneNodeLeft &&
|
||||
top <= checkBottom &&
|
||||
bottom >= this.cloneNodeTop
|
||||
) {
|
||||
this.overlapNode = node
|
||||
}
|
||||
}
|
||||
// 检测兄弟节点位置
|
||||
if (!this.prevNode && !this.nextNode && !node.isRoot) {
|
||||
// && this.node.isBrother(node)
|
||||
if (left <= checkRight && right >= this.cloneNodeLeft) {
|
||||
if (this.cloneNodeTop > bottom && this.cloneNodeTop <= bottom + 10) {
|
||||
this.prevNode = node
|
||||
this.placeholder.size(node.width, 10).move(_left, _bottom)
|
||||
} else if (checkBottom < top && checkBottom >= top - 10) {
|
||||
this.nextNode = node
|
||||
this.placeholder.size(node.width, 10).move(_left, _top - 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
if (this.overlapNode) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drag.instanceName = 'drag'
|
||||
|
||||
export default Drag
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { imgToDataUrl, downloadFile } from './utils'
|
||||
import JsPDF from 'jspdf'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import drawBackgroundImageToCanvas from './utils/simulateCSSBackgroundInCanvas'
|
||||
const URL = window.URL || window.webkitURL || window
|
||||
|
||||
// 导出类
|
||||
@@ -26,7 +27,7 @@ class Export {
|
||||
|
||||
// 获取svg数据
|
||||
async getSvgData() {
|
||||
let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap()
|
||||
let { svg, svgHTML } = this.mindMap.getSvgData()
|
||||
// 把图片的url转换成data:url类型,否则导出会丢失图片
|
||||
let imageList = svg.find('image')
|
||||
let task = imageList.map(async item => {
|
||||
@@ -85,7 +86,9 @@ class Export {
|
||||
let {
|
||||
backgroundColor = '#fff',
|
||||
backgroundImage,
|
||||
backgroundRepeat = 'repeat'
|
||||
backgroundRepeat = 'no-repeat',
|
||||
backgroundPosition = 'center center',
|
||||
backgroundSize = 'cover',
|
||||
} = this.mindMap.themeConfig
|
||||
// 背景颜色
|
||||
ctx.save()
|
||||
@@ -96,19 +99,18 @@ class Export {
|
||||
// 背景图片
|
||||
if (backgroundImage && backgroundImage !== 'none') {
|
||||
ctx.save()
|
||||
let img = new Image()
|
||||
img.src = backgroundImage
|
||||
img.onload = () => {
|
||||
let pat = ctx.createPattern(img, backgroundRepeat)
|
||||
ctx.rect(0, 0, width, height)
|
||||
ctx.fillStyle = pat
|
||||
ctx.fill()
|
||||
drawBackgroundImageToCanvas(ctx, width, height, backgroundImage, {
|
||||
backgroundRepeat,
|
||||
backgroundPosition,
|
||||
backgroundSize
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
ctx.restore()
|
||||
resolve()
|
||||
}
|
||||
img.onerror = e => {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
@@ -215,4 +217,6 @@ class Export {
|
||||
}
|
||||
}
|
||||
|
||||
Export.instanceName = 'doExport'
|
||||
|
||||
export default Export
|
||||
|
||||
@@ -2,7 +2,7 @@ import { isKey } from './utils/keyMap'
|
||||
import { bfsWalk } from './utils'
|
||||
|
||||
// 键盘导航类
|
||||
export default class KeyboardNavigation {
|
||||
class KeyboardNavigation {
|
||||
// 构造函数
|
||||
constructor(opt) {
|
||||
this.opt = opt
|
||||
@@ -224,3 +224,7 @@ export default class KeyboardNavigation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeyboardNavigation.instanceName = 'keyboardNavigation'
|
||||
|
||||
export default KeyboardNavigation
|
||||
@@ -14,43 +14,6 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取小地图相关数据
|
||||
getMiniMap() {
|
||||
const svg = this.mindMap.svg
|
||||
const draw = this.mindMap.draw
|
||||
// 保存原始信息
|
||||
const origWidth = svg.width()
|
||||
const origHeight = svg.height()
|
||||
const origTransform = draw.transform()
|
||||
const elRect = this.mindMap.el.getBoundingClientRect()
|
||||
// 去除放大缩小的变换效果
|
||||
draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY)
|
||||
// 获取变换后的位置尺寸信息,其实是getBoundingClientRect方法的包装方法
|
||||
const rect = draw.rbox()
|
||||
// 将svg设置为实际内容的宽高
|
||||
svg.size(rect.width, rect.height)
|
||||
// 把实际内容变换
|
||||
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
|
||||
// 克隆一份数据
|
||||
const clone = svg.clone()
|
||||
// 恢复原先的大小和变换信息
|
||||
svg.size(origWidth, origHeight)
|
||||
draw.transform(origTransform)
|
||||
|
||||
return {
|
||||
svg: clone, // 思维导图图形的整体svg元素,包括:svg(画布容器)、g(实际的思维导图组)
|
||||
svgHTML: clone.svg(), // svg字符串
|
||||
rect: {
|
||||
...rect, // 思维导图图形未缩放时的位置尺寸等信息
|
||||
ratio: rect.width / rect.height // 思维导图图形的宽高比
|
||||
},
|
||||
origWidth, // 画布宽度
|
||||
origHeight, // 画布高度
|
||||
scaleX: origTransform.scaleX, // 思维导图图形的水平缩放值
|
||||
scaleY: origTransform.scaleY // 思维导图图形的垂直缩放值
|
||||
}
|
||||
}
|
||||
|
||||
// 计算小地图的渲染数据
|
||||
/**
|
||||
* boxWidth:小地图容器的宽度
|
||||
@@ -58,7 +21,7 @@ class MiniMap {
|
||||
*/
|
||||
calculationMiniMap(boxWidth, boxHeight) {
|
||||
let { svgHTML, rect, origWidth, origHeight, scaleX, scaleY } =
|
||||
this.getMiniMap()
|
||||
this.mindMap.getSvgData()
|
||||
// 计算数据
|
||||
let boxRatio = boxWidth / boxHeight
|
||||
let actWidth = 0
|
||||
@@ -144,4 +107,6 @@ class MiniMap {
|
||||
}
|
||||
}
|
||||
|
||||
MiniMap.instanceName = 'miniMap'
|
||||
|
||||
export default MiniMap
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -167,4 +167,6 @@ class Select {
|
||||
}
|
||||
}
|
||||
|
||||
Select.instanceName = 'select'
|
||||
|
||||
export default Select
|
||||
|
||||
@@ -1,167 +1,200 @@
|
||||
import { tagColorList } from './utils/constant'
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
|
||||
// 样式类
|
||||
|
||||
class Style {
|
||||
// 设置背景样式
|
||||
|
||||
static setBackgroundStyle(el, themeConfig) {
|
||||
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
|
||||
el.style.backgroundColor = backgroundColor
|
||||
if (backgroundImage) {
|
||||
el.style.backgroundImage = `url(${backgroundImage})`
|
||||
el.style.backgroundRepeat = backgroundRepeat
|
||||
}
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
|
||||
constructor(ctx, themeConfig) {
|
||||
this.ctx = ctx
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 更新主题配置
|
||||
|
||||
updateThemeConfig(themeConfig) {
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 合并样式
|
||||
|
||||
merge(prop, root, isActive) {
|
||||
// 三级及以下节点
|
||||
let defaultConfig = this.themeConfig.node
|
||||
if (root || rootProp.includes(prop)) {
|
||||
// 直接使用最外层样式
|
||||
defaultConfig = this.themeConfig
|
||||
} else if (this.ctx.isGeneralization) {
|
||||
// 概要节点
|
||||
defaultConfig = this.themeConfig.generalization
|
||||
} else if (this.ctx.layerIndex === 0) {
|
||||
// 根节点
|
||||
defaultConfig = this.themeConfig.root
|
||||
} else if (this.ctx.layerIndex === 1) {
|
||||
// 二级节点
|
||||
defaultConfig = this.themeConfig.second
|
||||
}
|
||||
// 激活状态
|
||||
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||
if (
|
||||
this.ctx.nodeData.data.activeStyle &&
|
||||
this.ctx.nodeData.data.activeStyle[prop] !== undefined
|
||||
) {
|
||||
return this.ctx.nodeData.data.activeStyle[prop]
|
||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||
return defaultConfig.active[prop]
|
||||
}
|
||||
}
|
||||
// 优先使用节点本身的样式
|
||||
return this.getSelfStyle(prop) !== undefined
|
||||
? this.getSelfStyle(prop)
|
||||
: defaultConfig[prop]
|
||||
}
|
||||
|
||||
// 获取某个样式值
|
||||
|
||||
getStyle(prop, root, isActive) {
|
||||
return this.merge(prop, root, isActive)
|
||||
}
|
||||
|
||||
// 获取自身自定义样式
|
||||
|
||||
getSelfStyle(prop) {
|
||||
return this.ctx.nodeData.data[prop]
|
||||
}
|
||||
|
||||
// 矩形
|
||||
|
||||
rect(node) {
|
||||
this.shape(node)
|
||||
node.radius(this.merge('borderRadius'))
|
||||
}
|
||||
|
||||
// 矩形外的其他形状
|
||||
|
||||
shape(node) {
|
||||
node.fill({
|
||||
color: this.merge('fillColor')
|
||||
})
|
||||
// 节点使用横线样式,不需要渲染非激活状态的边框样式
|
||||
if (
|
||||
!this.ctx.isRoot &&
|
||||
!this.ctx.isGeneralization &&
|
||||
this.themeConfig.nodeUseLineStyle &&
|
||||
!this.ctx.nodeData.data.isActive
|
||||
) {
|
||||
return
|
||||
}
|
||||
node.stroke({
|
||||
color: this.merge('borderColor'),
|
||||
width: this.merge('borderWidth'),
|
||||
dasharray: this.merge('borderDasharray')
|
||||
})
|
||||
}
|
||||
|
||||
// 文字
|
||||
|
||||
text(node) {
|
||||
node
|
||||
.fill({
|
||||
color: this.merge('color')
|
||||
})
|
||||
.css({
|
||||
'font-family': this.merge('fontFamily'),
|
||||
'font-size': this.merge('fontSize'),
|
||||
'font-weight': this.merge('fontWeight'),
|
||||
'font-style': this.merge('fontStyle'),
|
||||
'text-decoration': this.merge('textDecoration')
|
||||
})
|
||||
}
|
||||
|
||||
// html文字节点
|
||||
|
||||
domText(node, fontSizeScale = 1) {
|
||||
node.style.fontFamily = this.merge('fontFamily')
|
||||
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
||||
}
|
||||
|
||||
// 标签文字
|
||||
|
||||
tagText(node, index) {
|
||||
node
|
||||
.fill({
|
||||
color: tagColorList[index].color
|
||||
})
|
||||
.css({
|
||||
'font-size': '12px'
|
||||
})
|
||||
}
|
||||
|
||||
// 标签矩形
|
||||
|
||||
tagRect(node, index) {
|
||||
node.fill({
|
||||
color: tagColorList[index].background
|
||||
})
|
||||
}
|
||||
|
||||
// 内置图标
|
||||
|
||||
iconNode(node) {
|
||||
node.attr({
|
||||
fill: this.merge('color')
|
||||
})
|
||||
}
|
||||
|
||||
// 连线
|
||||
|
||||
line(node, { width, color, dasharray } = {}) {
|
||||
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
|
||||
}
|
||||
|
||||
// 概要连线
|
||||
|
||||
generalizationLine(node) {
|
||||
import { tagColorList } from './utils/constant'
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
|
||||
// 样式类
|
||||
|
||||
class Style {
|
||||
// 设置背景样式
|
||||
|
||||
static setBackgroundStyle(el, themeConfig) {
|
||||
let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig
|
||||
el.style.backgroundColor = backgroundColor
|
||||
if (backgroundImage) {
|
||||
el.style.backgroundImage = `url(${backgroundImage})`
|
||||
el.style.backgroundRepeat = backgroundRepeat
|
||||
el.style.backgroundPosition = backgroundPosition
|
||||
el.style.backgroundSize = backgroundSize
|
||||
} else {
|
||||
el.style.backgroundImage = 'none'
|
||||
}
|
||||
}
|
||||
|
||||
// 构造函数
|
||||
|
||||
constructor(ctx, themeConfig) {
|
||||
this.ctx = ctx
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 更新主题配置
|
||||
|
||||
updateThemeConfig(themeConfig) {
|
||||
this.themeConfig = themeConfig
|
||||
}
|
||||
|
||||
// 合并样式
|
||||
|
||||
merge(prop, root, isActive) {
|
||||
// 三级及以下节点
|
||||
let defaultConfig = this.themeConfig.node
|
||||
if (root || rootProp.includes(prop)) {
|
||||
// 直接使用最外层样式
|
||||
defaultConfig = this.themeConfig
|
||||
} else if (this.ctx.isGeneralization) {
|
||||
// 概要节点
|
||||
defaultConfig = this.themeConfig.generalization
|
||||
} else if (this.ctx.layerIndex === 0) {
|
||||
// 根节点
|
||||
defaultConfig = this.themeConfig.root
|
||||
} else if (this.ctx.layerIndex === 1) {
|
||||
// 二级节点
|
||||
defaultConfig = this.themeConfig.second
|
||||
}
|
||||
// 激活状态
|
||||
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||
if (
|
||||
this.ctx.nodeData.data.activeStyle &&
|
||||
this.ctx.nodeData.data.activeStyle[prop] !== undefined
|
||||
) {
|
||||
return this.ctx.nodeData.data.activeStyle[prop]
|
||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||
return defaultConfig.active[prop]
|
||||
}
|
||||
}
|
||||
// 优先使用节点本身的样式
|
||||
return this.getSelfStyle(prop) !== undefined
|
||||
? this.getSelfStyle(prop)
|
||||
: defaultConfig[prop]
|
||||
}
|
||||
|
||||
// 获取某个样式值
|
||||
|
||||
getStyle(prop, root, isActive) {
|
||||
return this.merge(prop, root, isActive)
|
||||
}
|
||||
|
||||
// 获取自身自定义样式
|
||||
|
||||
getSelfStyle(prop) {
|
||||
return this.ctx.nodeData.data[prop]
|
||||
}
|
||||
|
||||
// 矩形
|
||||
|
||||
rect(node) {
|
||||
this.shape(node)
|
||||
node.radius(this.merge('borderRadius'))
|
||||
}
|
||||
|
||||
// 矩形外的其他形状
|
||||
|
||||
shape(node) {
|
||||
node.fill({
|
||||
color: this.merge('fillColor')
|
||||
})
|
||||
// 节点使用横线样式,不需要渲染非激活状态的边框样式
|
||||
if (
|
||||
!this.ctx.isRoot &&
|
||||
!this.ctx.isGeneralization &&
|
||||
this.themeConfig.nodeUseLineStyle &&
|
||||
!this.ctx.nodeData.data.isActive
|
||||
) {
|
||||
return
|
||||
}
|
||||
node.stroke({
|
||||
color: this.merge('borderColor'),
|
||||
width: this.merge('borderWidth'),
|
||||
dasharray: this.merge('borderDasharray')
|
||||
})
|
||||
}
|
||||
|
||||
// 文字
|
||||
|
||||
text(node) {
|
||||
node
|
||||
.fill({
|
||||
color: this.merge('color')
|
||||
})
|
||||
.css({
|
||||
'font-family': this.merge('fontFamily'),
|
||||
'font-size': this.merge('fontSize'),
|
||||
'font-weight': this.merge('fontWeight'),
|
||||
'font-style': this.merge('fontStyle'),
|
||||
'text-decoration': this.merge('textDecoration')
|
||||
})
|
||||
}
|
||||
|
||||
// 获取文本样式
|
||||
getTextFontStyle() {
|
||||
return {
|
||||
italic: this.merge('fontStyle') === 'italic',
|
||||
bold: this.merge('fontWeight'),
|
||||
fontSize: this.merge('fontSize'),
|
||||
fontFamily: this.merge('fontFamily')
|
||||
}
|
||||
}
|
||||
|
||||
// html文字节点
|
||||
|
||||
domText(node, fontSizeScale = 1) {
|
||||
node.style.fontFamily = this.merge('fontFamily')
|
||||
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
|
||||
node.style.fontWeight = this.merge('fontWeight') || 'normal'
|
||||
node.style.lineHeight = this.merge('lineHeight')
|
||||
node.style.fontStyle = this.merge('fontStyle')
|
||||
}
|
||||
|
||||
// 标签文字
|
||||
|
||||
tagText(node, index) {
|
||||
node
|
||||
.fill({
|
||||
color: tagColorList[index].color
|
||||
})
|
||||
.css({
|
||||
'font-size': '12px'
|
||||
})
|
||||
}
|
||||
|
||||
// 标签矩形
|
||||
|
||||
tagRect(node, index) {
|
||||
node.fill({
|
||||
color: tagColorList[index].background
|
||||
})
|
||||
}
|
||||
|
||||
// 内置图标
|
||||
|
||||
iconNode(node) {
|
||||
node.attr({
|
||||
fill: this.merge('color')
|
||||
})
|
||||
}
|
||||
|
||||
// 连线
|
||||
|
||||
line(node, { width, color, dasharray } = {}) {
|
||||
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
|
||||
}
|
||||
|
||||
// 概要连线
|
||||
|
||||
generalizationLine(node) {
|
||||
node
|
||||
.stroke({
|
||||
width: this.merge('generalizationLineWidth', true),
|
||||
color: this.merge('generalizationLineColor', true)
|
||||
})
|
||||
.fill({ color: 'none' })
|
||||
}
|
||||
|
||||
// 按钮
|
||||
|
||||
iconBtn(node, fillNode) {
|
||||
node.fill({ color: '#808080' })
|
||||
fillNode.fill({ color: '#fff' })
|
||||
}
|
||||
}
|
||||
|
||||
export default Style
|
||||
|
||||
@@ -59,14 +59,17 @@ export default class TextEdit {
|
||||
this.registerTmpShortcut()
|
||||
if (!this.textEditNode) {
|
||||
this.textEditNode = document.createElement('div')
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none;`
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
|
||||
this.textEditNode.setAttribute('contenteditable', true)
|
||||
this.textEditNode.addEventListener('keyup', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
document.body.appendChild(this.textEditNode)
|
||||
}
|
||||
node.style.domText(this.textEditNode, this.mindMap.view.scale)
|
||||
let scale = this.mindMap.view.scale
|
||||
let lineHeight = node.style.merge('lineHeight')
|
||||
let fontSize = node.style.merge('fontSize')
|
||||
node.style.domText(this.textEditNode, scale)
|
||||
this.textEditNode.innerHTML = node.nodeData.data.text
|
||||
.split(/\n/gim)
|
||||
.join('<br>')
|
||||
@@ -75,6 +78,8 @@ export default class TextEdit {
|
||||
this.textEditNode.style.left = rect.left + 'px'
|
||||
this.textEditNode.style.top = rect.top + 'px'
|
||||
this.textEditNode.style.display = 'block'
|
||||
this.textEditNode.style.maxWidth = this.mindMap.opt.textAutoWrapWidth * scale + 'px'
|
||||
this.textEditNode.style.transform = `translateY(${-(lineHeight * fontSize - fontSize) / 2 * scale}px)`
|
||||
this.showTextEdit = true
|
||||
// 选中文本
|
||||
this.selectNodeText()
|
||||
|
||||
120
simple-mind-map/src/Watermark.js
Normal file
120
simple-mind-map/src/Watermark.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import { Text, G } from '@svgdotjs/svg.js'
|
||||
import { degToRad, camelCaseToHyphen } from './utils'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
// 水印类
|
||||
class Watermark {
|
||||
constructor(opt = {}) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.lineSpacing = 0 // 水印行间距
|
||||
this.textSpacing = 0 // 行内水印间距
|
||||
this.angle = 0 // 旋转角度
|
||||
this.text = '' // 水印文字
|
||||
this.textStyle = {} // 水印文字样式
|
||||
this.watermarkDraw = this.mindMap.svg
|
||||
.group()
|
||||
.css({ 'pointer-events': 'none', 'user-select': 'none' })
|
||||
this.maxLong = Math.sqrt(
|
||||
Math.pow(this.mindMap.width, 2) + Math.pow(this.mindMap.height, 2)
|
||||
)
|
||||
this.updateWatermark(this.mindMap.opt.watermarkConfig || {})
|
||||
}
|
||||
|
||||
// 获取是否存在水印
|
||||
hasWatermark() {
|
||||
return !!this.text.trim()
|
||||
}
|
||||
|
||||
// 处理水印配置
|
||||
handleConfig({ text, lineSpacing, textSpacing, angle, textStyle }) {
|
||||
this.text = text === undefined ? '' : String(text).trim()
|
||||
this.lineSpacing =
|
||||
typeof lineSpacing === 'number' && lineSpacing > 0 ? lineSpacing : 100
|
||||
this.textSpacing =
|
||||
typeof textSpacing === 'number' && textSpacing > 0 ? textSpacing : 100
|
||||
this.angle =
|
||||
typeof angle === 'number' && angle >= 0 && angle <= 90 ? angle : 30
|
||||
this.textStyle = Object.assign(this.textStyle, textStyle || {})
|
||||
}
|
||||
|
||||
// 绘制水印
|
||||
// 非精确绘制,会绘制一些超出可视区域的水印
|
||||
draw() {
|
||||
this.watermarkDraw.clear()
|
||||
if (!this.hasWatermark()) {
|
||||
return
|
||||
}
|
||||
let x = 0
|
||||
while (x < this.mindMap.width) {
|
||||
this.drawText(x)
|
||||
x += this.lineSpacing / Math.sin(degToRad(this.angle))
|
||||
}
|
||||
|
||||
let yOffset =
|
||||
this.lineSpacing / Math.cos(degToRad(this.angle)) || this.lineSpacing
|
||||
let y = yOffset
|
||||
while (y < this.mindMap.height) {
|
||||
this.drawText(0, y)
|
||||
y += yOffset
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制文字
|
||||
drawText(x, y) {
|
||||
let long = Math.min(
|
||||
this.maxLong,
|
||||
(this.mindMap.width - x) / Math.cos(degToRad(this.angle))
|
||||
)
|
||||
let g = new G()
|
||||
let bbox = null
|
||||
let bboxWidth = 0
|
||||
let textHeight = -1
|
||||
while (bboxWidth < long) {
|
||||
let text = new Text().text(this.text)
|
||||
g.add(text)
|
||||
text.transform({
|
||||
translateX: bboxWidth
|
||||
})
|
||||
this.setTextStyle(text)
|
||||
bbox = g.bbox()
|
||||
if (textHeight === -1) {
|
||||
textHeight = bbox.height
|
||||
}
|
||||
bboxWidth = bbox.width + this.textSpacing
|
||||
}
|
||||
let params = {
|
||||
rotate: this.angle,
|
||||
origin: 'top left',
|
||||
translateX: x,
|
||||
translateY: textHeight
|
||||
}
|
||||
if (y !== undefined) {
|
||||
params.translateY = y + textHeight
|
||||
}
|
||||
g.transform(params)
|
||||
this.watermarkDraw.add(g)
|
||||
}
|
||||
|
||||
// 给文字设置样式
|
||||
setTextStyle(text) {
|
||||
Object.keys(this.textStyle).forEach(item => {
|
||||
let value = this.textStyle[item]
|
||||
if (item === 'color') {
|
||||
text.fill(value)
|
||||
} else {
|
||||
text.css(camelCaseToHyphen(item), value)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 更新水印
|
||||
updateWatermark(config) {
|
||||
this.mindMap.opt.watermarkConfig = merge(this.mindMap.opt.watermarkConfig, config)
|
||||
this.handleConfig(config)
|
||||
this.draw()
|
||||
}
|
||||
}
|
||||
|
||||
Watermark.instanceName = 'watermark'
|
||||
|
||||
export default Watermark
|
||||
@@ -1,267 +1,289 @@
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 逻辑结构图
|
||||
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
btn.translate(
|
||||
width - translateX,
|
||||
height / 2 - translateY + nodeUseLineStyleOffset
|
||||
)
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
import Base from './Base'
|
||||
import { walk, asyncRun } from '../utils'
|
||||
|
||||
// 逻辑结构图
|
||||
|
||||
class LogicalStructure extends Base {
|
||||
// 构造函数
|
||||
|
||||
constructor(opt = {}) {
|
||||
super(opt)
|
||||
}
|
||||
|
||||
// 布局
|
||||
|
||||
doLayout(callback) {
|
||||
let task = [
|
||||
() => {
|
||||
this.computedBaseValue()
|
||||
},
|
||||
() => {
|
||||
this.computedTopValue()
|
||||
},
|
||||
() => {
|
||||
this.adjustTopValue()
|
||||
},
|
||||
() => {
|
||||
callback(this.root)
|
||||
}
|
||||
]
|
||||
asyncRun(task)
|
||||
}
|
||||
|
||||
// 遍历数据计算节点的left、width、height
|
||||
|
||||
computedBaseValue() {
|
||||
walk(
|
||||
this.renderer.renderTree,
|
||||
null,
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
|
||||
// 根节点定位在画布中心位置
|
||||
if (isRoot) {
|
||||
this.setNodeCenter(newNode)
|
||||
} else {
|
||||
// 非根节点
|
||||
// 定位到父节点右侧
|
||||
newNode.left =
|
||||
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
|
||||
}
|
||||
if (!cur.data.expand) {
|
||||
return true
|
||||
}
|
||||
},
|
||||
(cur, parent, isRoot, layerIndex) => {
|
||||
// 返回时计算节点的areaHeight,也就是子节点所占的高度之和,包括外边距
|
||||
let len = cur.data.expand === false ? 0 : cur._node.children.length
|
||||
cur._node.childrenAreaHeight = len
|
||||
? cur._node.children.reduce((h, item) => {
|
||||
return h + item.height
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
},
|
||||
true,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
// 遍历节点树计算节点的top
|
||||
|
||||
computedTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (
|
||||
node.nodeData.data.expand &&
|
||||
node.children &&
|
||||
node.children.length
|
||||
) {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
|
||||
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
|
||||
let totalTop = top + marginY
|
||||
node.children.forEach(cur => {
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 调整节点top
|
||||
|
||||
adjustTopValue() {
|
||||
walk(
|
||||
this.root,
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (!node.nodeData.data.expand) {
|
||||
return
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
this.updateBrothers(node, difference / 2)
|
||||
}
|
||||
},
|
||||
null,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
// 更新兄弟节点的top
|
||||
|
||||
updateBrothers(node, addHeight) {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
let _offset = 0
|
||||
// 上面的节点往上移
|
||||
if (_index < index) {
|
||||
_offset = -addHeight
|
||||
} else if (_index > index) {
|
||||
// 下面的节点往下移
|
||||
_offset = addHeight
|
||||
}
|
||||
item.top += _offset
|
||||
// 同步更新子节点的位置
|
||||
if (item.children && item.children.length) {
|
||||
this.updateChildren(item.children, 'top', _offset)
|
||||
}
|
||||
})
|
||||
// 更新父节点的位置
|
||||
this.updateBrothers(node.parent, addHeight)
|
||||
}
|
||||
}
|
||||
|
||||
// 绘制连线,连接该节点到其子节点
|
||||
|
||||
renderLine(node, lines, style, lineStyle) {
|
||||
if (lineStyle === 'curve') {
|
||||
this.renderLineCurve(node, lines, style)
|
||||
} else if (lineStyle === 'direct') {
|
||||
this.renderLineDirect(node, lines, style)
|
||||
} else {
|
||||
this.renderLineStraight(node, lines, style)
|
||||
}
|
||||
}
|
||||
|
||||
// 直线风格连线
|
||||
|
||||
renderLineStraight(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 直连风格
|
||||
|
||||
renderLineDirect(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 曲线风格连线
|
||||
|
||||
renderLineCurve(node, lines, style) {
|
||||
if (node.children.length <= 0) {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = nodeUseLineStyle
|
||||
? ` L ${item.left + item.width},${y2}`
|
||||
: ''
|
||||
if (node.isRoot) {
|
||||
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
} else {
|
||||
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
|
||||
}
|
||||
lines[index].plot(path)
|
||||
style && style(lines[index], item)
|
||||
})
|
||||
}
|
||||
|
||||
// 渲染按钮
|
||||
|
||||
renderExpandBtn(node, btn) {
|
||||
let { width, height } = node
|
||||
let { translateX, translateY } = btn.transform()
|
||||
// 节点使用横线风格,需要调整展开收起按钮位置
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
? height / 2
|
||||
: 0
|
||||
btn.translate(
|
||||
width - translateX,
|
||||
height / 2 - translateY + nodeUseLineStyleOffset
|
||||
)
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
|
||||
renderGeneralization(node, gLine, gNode) {
|
||||
let {
|
||||
top,
|
||||
bottom,
|
||||
right,
|
||||
generalizationLineMargin,
|
||||
generalizationNodeMargin
|
||||
} = this.getNodeBoundaries(node, 'h')
|
||||
let x1 = right + generalizationLineMargin
|
||||
let y1 = top
|
||||
let x2 = right + generalizationLineMargin
|
||||
let y2 = bottom
|
||||
let cx = x1 + 20
|
||||
let cy = y1 + (y2 - y1) / 2
|
||||
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
|
||||
gLine.plot(path)
|
||||
gNode.left = right + generalizationNodeMargin
|
||||
gNode.top = top + (bottom - top - gNode.height) / 2
|
||||
}
|
||||
}
|
||||
|
||||
export default LogicalStructure
|
||||
|
||||
@@ -208,11 +208,12 @@ class MindMap extends Base {
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let marginX = this.getMarginX(node.layerIndex + 1)
|
||||
let s1 = (marginX - expandBtnSize) * 0.6
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 = 0
|
||||
let _s = 0
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
let nodeUseLineStyleOffset = nodeUseLineStyle
|
||||
? item.width
|
||||
: 0
|
||||
if (item.dir === 'left') {
|
||||
@@ -226,6 +227,8 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${
|
||||
x2 + nodeUseLineStyleOffset
|
||||
},${y2}`
|
||||
@@ -241,6 +244,7 @@ class MindMap extends Base {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0
|
||||
@@ -251,9 +255,11 @@ class MindMap extends Base {
|
||||
let y1 = top + height / 2
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
if (nodeUseLineStyle) {
|
||||
if (item.dir === 'left') {
|
||||
nodeUseLineStylePath = ` L ${item.left},${y2}`
|
||||
} else {
|
||||
@@ -273,6 +279,7 @@ class MindMap extends Base {
|
||||
return []
|
||||
}
|
||||
let { left, top, width, height, expandBtnSize } = node
|
||||
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
|
||||
node.children.forEach((item, index) => {
|
||||
let x1 =
|
||||
node.layerIndex === 0
|
||||
@@ -284,6 +291,8 @@ class MindMap extends Base {
|
||||
let x2 = item.dir === 'left' ? item.left + item.width : item.left
|
||||
let y2 = item.top + item.height / 2
|
||||
let path = ''
|
||||
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
|
||||
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
|
||||
// 节点使用横线风格,需要额外渲染横线
|
||||
let nodeUseLineStylePath = ''
|
||||
if (this.mindMap.themeConfig.nodeUseLineStyle) {
|
||||
|
||||
@@ -1,142 +1,147 @@
|
||||
// 默认主题
|
||||
|
||||
export default {
|
||||
// 节点内边距
|
||||
paddingX: 15,
|
||||
paddingY: 5,
|
||||
// 图片显示的最大宽度
|
||||
imgMaxWidth: 100,
|
||||
// 图片显示的最大高度
|
||||
imgMaxHeight: 100,
|
||||
// icon的大小
|
||||
iconSize: 20,
|
||||
// 连线的粗细
|
||||
lineWidth: 1,
|
||||
// 连线的颜色
|
||||
lineColor: '#549688',
|
||||
// 连线样式
|
||||
lineDasharray: 'none',
|
||||
// 连线风格
|
||||
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线(curve)、直线(straight)、直连(direct)
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 1,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#549688',
|
||||
// 概要曲线距节点的距离
|
||||
generalizationLineMargin: 0,
|
||||
// 概要节点距节点的距离
|
||||
generalizationNodeMargin: 20,
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
backgroundImage: 'none',
|
||||
// 背景重复
|
||||
backgroundRepeat: 'no-repeat',
|
||||
// 节点使用横线样式
|
||||
nodeUseLineStyle: false,
|
||||
// 根节点样式
|
||||
root: {
|
||||
shape: 'rectangle',
|
||||
fillColor: '#549688',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
shape: 'rectangle',
|
||||
marginX: 50,
|
||||
marginY: 0,
|
||||
fillColor: 'transparent',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#6a6d6c',
|
||||
fontSize: 14,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderRadius: 5,
|
||||
borderDasharray: 'none',
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 支持激活样式的属性
|
||||
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
|
||||
export const supportActiveStyle = [
|
||||
'fillColor',
|
||||
'color',
|
||||
'fontWeight',
|
||||
'fontStyle',
|
||||
'borderColor',
|
||||
'borderWidth',
|
||||
'borderDasharray',
|
||||
'borderRadius',
|
||||
'textDecoration'
|
||||
]
|
||||
|
||||
// 默认主题
|
||||
|
||||
export default {
|
||||
// 节点内边距
|
||||
paddingX: 15,
|
||||
paddingY: 5,
|
||||
// 图片显示的最大宽度
|
||||
imgMaxWidth: 100,
|
||||
// 图片显示的最大高度
|
||||
imgMaxHeight: 100,
|
||||
// icon的大小
|
||||
iconSize: 20,
|
||||
// 连线的粗细
|
||||
lineWidth: 1,
|
||||
// 连线的颜色
|
||||
lineColor: '#549688',
|
||||
// 连线样式
|
||||
lineDasharray: 'none',
|
||||
// 连线风格
|
||||
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线(curve)、直线(straight)、直连(direct)
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 1,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#549688',
|
||||
// 概要曲线距节点的距离
|
||||
generalizationLineMargin: 0,
|
||||
// 概要节点距节点的距离
|
||||
generalizationNodeMargin: 20,
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
backgroundImage: 'none',
|
||||
// 背景重复
|
||||
backgroundRepeat: 'no-repeat',
|
||||
// 设置背景图像的起始位置
|
||||
backgroundPosition: 'center center',
|
||||
// 设置背景图片大小
|
||||
backgroundSize: 'cover',
|
||||
// 节点使用横线样式
|
||||
nodeUseLineStyle: false,
|
||||
// 根节点样式
|
||||
root: {
|
||||
shape: 'rectangle',
|
||||
fillColor: '#549688',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
shape: 'rectangle',
|
||||
marginX: 50,
|
||||
marginY: 0,
|
||||
fillColor: 'transparent',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#6a6d6c',
|
||||
fontSize: 14,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 0,
|
||||
borderRadius: 5,
|
||||
borderDasharray: 'none',
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
shape: 'rectangle',
|
||||
marginX: 100,
|
||||
marginY: 40,
|
||||
fillColor: '#fff',
|
||||
fontFamily: '微软雅黑, Microsoft YaHei',
|
||||
color: '#565656',
|
||||
fontSize: 16,
|
||||
fontWeight: 'noraml',
|
||||
fontStyle: 'normal',
|
||||
lineHeight: 1.5,
|
||||
borderColor: '#549688',
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 支持激活样式的属性
|
||||
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
|
||||
export const supportActiveStyle = [
|
||||
'fillColor',
|
||||
'color',
|
||||
'fontWeight',
|
||||
'fontStyle',
|
||||
'borderColor',
|
||||
'borderWidth',
|
||||
'borderDasharray',
|
||||
'borderRadius',
|
||||
'textDecoration'
|
||||
]
|
||||
|
||||
export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']
|
||||
|
||||
@@ -224,3 +224,45 @@ export const asyncRun = (taskList, callback = () => {}) => {
|
||||
}
|
||||
loop()
|
||||
}
|
||||
|
||||
// 角度转弧度
|
||||
export const degToRad = deg => {
|
||||
return deg * (Math.PI / 180)
|
||||
}
|
||||
|
||||
// 驼峰转连字符
|
||||
export const camelCaseToHyphen = (str) => {
|
||||
return str.replace(/([a-z])([A-Z])/g, (...args) => {
|
||||
return args[1] + '-' + args[2].toLowerCase()
|
||||
})
|
||||
}
|
||||
|
||||
//计算节点的文本长宽
|
||||
let measureTextContext = null
|
||||
export const measureText = (text, { italic, bold, fontSize, fontFamily }) => {
|
||||
const font = joinFontStr({
|
||||
italic,
|
||||
bold,
|
||||
fontSize,
|
||||
fontFamily
|
||||
})
|
||||
if (!measureTextContext) {
|
||||
const canvas = document.createElement('canvas')
|
||||
measureTextContext = canvas.getContext('2d')
|
||||
}
|
||||
measureTextContext.save()
|
||||
measureTextContext.font = font
|
||||
const {
|
||||
width,
|
||||
actualBoundingBoxAscent,
|
||||
actualBoundingBoxDescent
|
||||
} = measureTextContext.measureText(text)
|
||||
measureTextContext.restore()
|
||||
const height = actualBoundingBoxAscent + actualBoundingBoxDescent
|
||||
return { width, height }
|
||||
}
|
||||
|
||||
// 拼接font字符串
|
||||
export const joinFontStr = ({ italic, bold, fontSize, fontFamily }) => {
|
||||
return `${italic ? 'italic ' : ''} ${bold ? 'bold ' : ''} ${fontSize}px ${fontFamily} `
|
||||
}
|
||||
354
simple-mind-map/src/utils/simulateCSSBackgroundInCanvas.js
Normal file
354
simple-mind-map/src/utils/simulateCSSBackgroundInCanvas.js
Normal file
@@ -0,0 +1,354 @@
|
||||
// 将以空格分隔的字符串值转换成成数字/单位/值数组
|
||||
const getNumberValueFromStr = value => {
|
||||
let arr = String(value).split(/\s+/)
|
||||
return arr.map(item => {
|
||||
if (/^[\d.]+/.test(item)) {
|
||||
// 数字+单位
|
||||
let res = /^([\d.]+)(.*)$/.exec(item)
|
||||
return [Number(res[1]), res[2]]
|
||||
} else {
|
||||
// 单个值
|
||||
return item
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 缩放宽度
|
||||
const zoomWidth = (ratio, height) => {
|
||||
// w / height = ratio
|
||||
return ratio * height
|
||||
}
|
||||
|
||||
// 缩放高度
|
||||
const zoomHeight = (ratio, width) => {
|
||||
// width / h = ratio
|
||||
return width / ratio
|
||||
}
|
||||
|
||||
// 关键词到百分比值的映射
|
||||
const keyWordToPercentageMap = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
center: 50,
|
||||
bottom: 100,
|
||||
right: 100
|
||||
}
|
||||
|
||||
// 模拟background-size
|
||||
const handleBackgroundSize = ({
|
||||
backgroundSize,
|
||||
drawOpt,
|
||||
imageRatio,
|
||||
canvasWidth,
|
||||
canvasHeight,
|
||||
canvasRatio
|
||||
}) => {
|
||||
if (backgroundSize) {
|
||||
// 将值转换成数组
|
||||
let backgroundSizeValueArr = getNumberValueFromStr(backgroundSize)
|
||||
// 两个值都为auto,那就相当于不设置
|
||||
if (
|
||||
backgroundSizeValueArr[0] === 'auto' &&
|
||||
backgroundSizeValueArr[1] === 'auto'
|
||||
) {
|
||||
return
|
||||
}
|
||||
// 值为cover
|
||||
if (backgroundSizeValueArr[0] === 'cover') {
|
||||
if (imageRatio > canvasRatio) {
|
||||
// 图片的宽高比大于canvas的宽高比,那么图片高度缩放到和canvas的高度一致,宽度自适应
|
||||
drawOpt.height = canvasHeight
|
||||
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
|
||||
} else {
|
||||
// 否则图片宽度缩放到和canvas的宽度一致,高度自适应
|
||||
drawOpt.width = canvasWidth
|
||||
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 值为contain
|
||||
if (backgroundSizeValueArr[0] === 'contain') {
|
||||
if (imageRatio > canvasRatio) {
|
||||
// 图片的宽高比大于canvas的宽高比,那么图片宽度缩放到和canvas的宽度一致,高度自适应
|
||||
drawOpt.width = canvasWidth
|
||||
drawOpt.height = zoomHeight(imageRatio, canvasWidth)
|
||||
} else {
|
||||
// 否则图片高度缩放到和canvas的高度一致,宽度自适应
|
||||
drawOpt.height = canvasHeight
|
||||
drawOpt.width = zoomWidth(imageRatio, canvasHeight)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 图片宽度
|
||||
let newNumberWidth = -1
|
||||
if (backgroundSizeValueArr[0]) {
|
||||
if (Array.isArray(backgroundSizeValueArr[0])) {
|
||||
// 数字+单位类型
|
||||
if (backgroundSizeValueArr[0][1] === '%') {
|
||||
// %单位
|
||||
drawOpt.width = (backgroundSizeValueArr[0][0] / 100) * canvasWidth
|
||||
newNumberWidth = drawOpt.width
|
||||
} else {
|
||||
// 其他都认为是px单位
|
||||
drawOpt.width = backgroundSizeValueArr[0][0]
|
||||
newNumberWidth = backgroundSizeValueArr[0][0]
|
||||
}
|
||||
} else if (backgroundSizeValueArr[0] === 'auto') {
|
||||
// auto类型,那么根据设置的新高度以图片原宽高比进行自适应
|
||||
if (backgroundSizeValueArr[1]) {
|
||||
if (backgroundSizeValueArr[1][1] === '%') {
|
||||
// 高度为%单位
|
||||
drawOpt.width = zoomWidth(
|
||||
imageRatio,
|
||||
(backgroundSizeValueArr[1][0] / 100) * canvasHeight
|
||||
)
|
||||
} else {
|
||||
// 其他都认为是px单位
|
||||
drawOpt.width = zoomWidth(imageRatio, backgroundSizeValueArr[1][0])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 设置了图片高度
|
||||
if (backgroundSizeValueArr[1] && Array.isArray(backgroundSizeValueArr[1])) {
|
||||
// 数字+单位类型
|
||||
if (backgroundSizeValueArr[1][1] === '%') {
|
||||
// 高度为%单位
|
||||
drawOpt.height = (backgroundSizeValueArr[1][0] / 100) * canvasHeight
|
||||
} else {
|
||||
// 其他都认为是px单位
|
||||
drawOpt.height = backgroundSizeValueArr[1][0]
|
||||
}
|
||||
} else if (newNumberWidth !== -1) {
|
||||
// 没有设置图片高度或者设置为auto,那么根据设置的新宽度以图片原宽高比进行自适应
|
||||
drawOpt.height = zoomHeight(imageRatio, newNumberWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟background-position
|
||||
const handleBackgroundPosition = ({
|
||||
backgroundPosition,
|
||||
drawOpt,
|
||||
imgWidth,
|
||||
imgHeight,
|
||||
canvasWidth,
|
||||
canvasHeight
|
||||
}) => {
|
||||
if (backgroundPosition) {
|
||||
// 将值转换成数组
|
||||
let backgroundPositionValueArr = getNumberValueFromStr(backgroundPosition)
|
||||
// 将关键词转为百分比
|
||||
backgroundPositionValueArr = backgroundPositionValueArr.map(item => {
|
||||
if (typeof item === 'string') {
|
||||
return keyWordToPercentageMap[item] !== undefined
|
||||
? [keyWordToPercentageMap[item], '%']
|
||||
: item
|
||||
}
|
||||
return item
|
||||
})
|
||||
if (Array.isArray(backgroundPositionValueArr[0])) {
|
||||
if (backgroundPositionValueArr.length === 1) {
|
||||
// 如果只设置了一个值,第二个默认为50%
|
||||
backgroundPositionValueArr.push([50, '%'])
|
||||
}
|
||||
// 水平位置
|
||||
if (backgroundPositionValueArr[0][1] === '%') {
|
||||
// 单位为%
|
||||
let canvasX = (backgroundPositionValueArr[0][0] / 100) * canvasWidth
|
||||
let imgX = (backgroundPositionValueArr[0][0] / 100) * imgWidth
|
||||
// 计算差值
|
||||
drawOpt.x = canvasX - imgX
|
||||
} else {
|
||||
// 其他单位默认都为px
|
||||
drawOpt.x = backgroundPositionValueArr[0][0]
|
||||
}
|
||||
// 垂直位置
|
||||
if (backgroundPositionValueArr[1][1] === '%') {
|
||||
// 单位为%
|
||||
let canvasY = (backgroundPositionValueArr[1][0] / 100) * canvasHeight
|
||||
let imgY = (backgroundPositionValueArr[1][0] / 100) * imgHeight
|
||||
// 计算差值
|
||||
drawOpt.y = canvasY - imgY
|
||||
} else {
|
||||
// 其他单位默认都为px
|
||||
drawOpt.y = backgroundPositionValueArr[1][0]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 模拟background-repeat
|
||||
const handleBackgroundRepeat = ({
|
||||
ctx,
|
||||
image,
|
||||
backgroundRepeat,
|
||||
drawOpt,
|
||||
imgWidth,
|
||||
imgHeight,
|
||||
canvasWidth,
|
||||
canvasHeight
|
||||
}) => {
|
||||
if (backgroundRepeat) {
|
||||
// 保存在handleBackgroundPosition中计算出来的x、y
|
||||
let ox = drawOpt.x
|
||||
let oy = drawOpt.y
|
||||
// 计算ox和oy能平铺的图片数量
|
||||
let oxRepeatNum = Math.ceil(ox / imgWidth)
|
||||
let oyRepeatNum = Math.ceil(oy / imgHeight)
|
||||
// 计算ox和oy第一张图片的位置
|
||||
let oxRepeatX = ox - oxRepeatNum * imgWidth
|
||||
let oxRepeatY = oy - oyRepeatNum * imgHeight
|
||||
// 将值转换成数组
|
||||
let backgroundRepeatValueArr = getNumberValueFromStr(backgroundRepeat)
|
||||
// 不处理
|
||||
if (
|
||||
backgroundRepeatValueArr[0] === 'no-repeat' ||
|
||||
(imgWidth >= canvasWidth && imgHeight >= canvasHeight)
|
||||
) {
|
||||
return
|
||||
}
|
||||
// 水平平铺
|
||||
if (backgroundRepeatValueArr[0] === 'repeat-x') {
|
||||
if (canvasWidth > imgWidth) {
|
||||
let x = oxRepeatX
|
||||
while (x < canvasWidth) {
|
||||
drawImage(ctx, image, {
|
||||
...drawOpt,
|
||||
x
|
||||
})
|
||||
x += imgWidth
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 垂直平铺
|
||||
if (backgroundRepeatValueArr[0] === 'repeat-y') {
|
||||
if (canvasHeight > imgHeight) {
|
||||
let y = oxRepeatY
|
||||
while (y < canvasHeight) {
|
||||
drawImage(ctx, image, {
|
||||
...drawOpt,
|
||||
y
|
||||
})
|
||||
y += imgHeight
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
// 平铺
|
||||
if (backgroundRepeatValueArr[0] === 'repeat') {
|
||||
let x = oxRepeatX
|
||||
while (x < canvasWidth) {
|
||||
if (canvasHeight > imgHeight) {
|
||||
let y = oxRepeatY
|
||||
while (y < canvasHeight) {
|
||||
drawImage(ctx, image, {
|
||||
...drawOpt,
|
||||
x,
|
||||
y
|
||||
})
|
||||
y += imgHeight
|
||||
}
|
||||
}
|
||||
x += imgWidth
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 根据参数绘制图片
|
||||
const drawImage = (ctx, image, drawOpt) => {
|
||||
ctx.drawImage(
|
||||
image,
|
||||
drawOpt.sx,
|
||||
drawOpt.sy,
|
||||
drawOpt.swidth,
|
||||
drawOpt.sheight,
|
||||
drawOpt.x,
|
||||
drawOpt.y,
|
||||
drawOpt.width,
|
||||
drawOpt.height
|
||||
)
|
||||
}
|
||||
|
||||
const drawBackgroundImageToCanvas = (
|
||||
ctx,
|
||||
width,
|
||||
height,
|
||||
img,
|
||||
{ backgroundSize, backgroundPosition, backgroundRepeat },
|
||||
callback = () => {}
|
||||
) => {
|
||||
// 画布的长宽比
|
||||
let canvasRatio = width / height
|
||||
// 加载图片
|
||||
let image = new Image()
|
||||
image.src = img
|
||||
image.onload = () => {
|
||||
// 图片的宽度及长宽比
|
||||
let imgWidth = image.width
|
||||
let imgHeight = image.height
|
||||
let imageRatio = imgWidth / imgHeight
|
||||
// 绘制图片
|
||||
// drawImage方法的参数值
|
||||
let drawOpt = {
|
||||
sx: 0,
|
||||
sy: 0,
|
||||
swidth: imgWidth,
|
||||
sheight: imgHeight,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: imgWidth,
|
||||
height: imgHeight
|
||||
}
|
||||
// 模拟background-size
|
||||
handleBackgroundSize({
|
||||
backgroundSize,
|
||||
drawOpt,
|
||||
imageRatio,
|
||||
canvasWidth: width,
|
||||
canvasHeight: height,
|
||||
canvasRatio
|
||||
})
|
||||
|
||||
// 模拟background-position
|
||||
handleBackgroundPosition({
|
||||
backgroundPosition,
|
||||
drawOpt,
|
||||
imgWidth: drawOpt.width,
|
||||
imgHeight: drawOpt.height,
|
||||
imageRatio,
|
||||
canvasWidth: width,
|
||||
canvasHeight: height,
|
||||
canvasRatio
|
||||
})
|
||||
|
||||
// 模拟background-repeat
|
||||
let notNeedDraw = handleBackgroundRepeat({
|
||||
ctx,
|
||||
image,
|
||||
backgroundRepeat,
|
||||
drawOpt,
|
||||
imgWidth: drawOpt.width,
|
||||
imgHeight: drawOpt.height,
|
||||
imageRatio,
|
||||
canvasWidth: width,
|
||||
canvasHeight: height,
|
||||
canvasRatio
|
||||
})
|
||||
|
||||
// 绘制图片
|
||||
if (!notNeedDraw) {
|
||||
drawImage(ctx, image, drawOpt)
|
||||
}
|
||||
|
||||
callback()
|
||||
}
|
||||
image.onerror = e => {
|
||||
callback(e)
|
||||
}
|
||||
}
|
||||
|
||||
export default drawBackgroundImageToCanvas
|
||||
163
web/package-lock.json
generated
163
web/package-lock.json
generated
@@ -11,6 +11,7 @@
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
"core-js": "^3.6.5",
|
||||
"element-ui": "^2.15.1",
|
||||
"highlight.js": "^10.7.3",
|
||||
"v-viewer": "^1.6.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.27.2",
|
||||
@@ -23,10 +24,13 @@
|
||||
"@vue/cli-plugin-eslint": "^4.5.0",
|
||||
"@vue/cli-service": "^4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"less": "^3.12.2",
|
||||
"less-loader": "^7.1.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-checkbox": "^1.1.0",
|
||||
"prettier": "^1.19.1",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack": "^4.44.2"
|
||||
@@ -3521,7 +3525,6 @@
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
@@ -4135,7 +4138,6 @@
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -4157,7 +4159,6 @@
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
},
|
||||
@@ -4170,7 +4171,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@@ -4183,7 +4183,6 @@
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-glob": "^4.0.1"
|
||||
},
|
||||
@@ -4196,7 +4195,6 @@
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
@@ -4206,7 +4204,6 @@
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
@@ -7846,7 +7843,6 @@
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -8604,7 +8600,6 @@
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
@@ -9334,6 +9329,15 @@
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/loader-fs-cache": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz",
|
||||
@@ -9554,6 +9558,49 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
},
|
||||
"bin": {
|
||||
"markdown-it": "bin/markdown-it.js"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it-checkbox": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it-checkbox/-/markdown-it-checkbox-1.1.0.tgz",
|
||||
"integrity": "sha512-NkZVjnXo5G+cLNdi7DPZxICypBuxFE9F8sx3YGMZn+Cfizr8EZ/1TFUKl7ZnefF6cr1aFHbnQ5iA3rc4cp7EyA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"underscore": "^1.8.2"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-it/node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/markdown-it/node_modules/entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
@@ -9571,6 +9618,12 @@
|
||||
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
@@ -12049,7 +12102,6 @@
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
@@ -14266,6 +14318,12 @@
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/uglify-js": {
|
||||
"version": "3.4.10",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
|
||||
@@ -14303,6 +14361,12 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/underscore": {
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
|
||||
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/unicode-canonical-property-names-ecmascript": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
|
||||
@@ -18871,8 +18935,7 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"bindings": {
|
||||
"version": "1.5.0",
|
||||
@@ -19382,7 +19445,6 @@
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -19399,7 +19461,6 @@
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
}
|
||||
@@ -19409,7 +19470,6 @@
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
}
|
||||
@@ -19419,7 +19479,6 @@
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
@@ -19428,15 +19487,13 @@
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
}
|
||||
@@ -22289,8 +22346,7 @@
|
||||
"highlight.js": {
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
@@ -22870,7 +22926,6 @@
|
||||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
}
|
||||
@@ -23414,6 +23469,15 @@
|
||||
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
|
||||
"dev": true
|
||||
},
|
||||
"linkify-it": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
|
||||
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"uc.micro": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"loader-fs-cache": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.3.tgz",
|
||||
@@ -23593,6 +23657,42 @@
|
||||
"object-visit": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"markdown-it": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
|
||||
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"argparse": "^2.0.1",
|
||||
"entities": "~3.0.1",
|
||||
"linkify-it": "^4.0.1",
|
||||
"mdurl": "^1.0.1",
|
||||
"uc.micro": "^1.0.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"entities": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
|
||||
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown-it-checkbox": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-it-checkbox/-/markdown-it-checkbox-1.1.0.tgz",
|
||||
"integrity": "sha512-NkZVjnXo5G+cLNdi7DPZxICypBuxFE9F8sx3YGMZn+Cfizr8EZ/1TFUKl7ZnefF6cr1aFHbnQ5iA3rc4cp7EyA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"underscore": "^1.8.2"
|
||||
}
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
@@ -23610,6 +23710,12 @@
|
||||
"integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
|
||||
"dev": true
|
||||
},
|
||||
"mdurl": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
|
||||
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
|
||||
"dev": true
|
||||
},
|
||||
"media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
@@ -25678,7 +25784,6 @@
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
@@ -27502,6 +27607,12 @@
|
||||
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
|
||||
"dev": true
|
||||
},
|
||||
"uc.micro": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
|
||||
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.4.10",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
|
||||
@@ -27532,6 +27643,12 @@
|
||||
"which-boxed-primitive": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"underscore": {
|
||||
"version": "1.13.6",
|
||||
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
|
||||
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==",
|
||||
"dev": true
|
||||
},
|
||||
"unicode-canonical-property-names-ecmascript": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
|
||||
|
||||
@@ -6,13 +6,16 @@
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build && node ../copy.js",
|
||||
"lint": "vue-cli-service lint",
|
||||
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/index.js --dest ../simple-mind-map/dist",
|
||||
"format": "prettier --write src/* src/*/* src/*/*/* src/*/*/*/*"
|
||||
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/full.js --dest ../simple-mind-map/dist",
|
||||
"format": "prettier --write src/* src/*/* src/*/*/* src/*/*/*/*",
|
||||
"buildDoc": "node ./scripts/buildDoc.js",
|
||||
"autoBuildDoc": "node ./scripts/autoBuildDoc.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@toast-ui/editor": "^3.1.5",
|
||||
"core-js": "^3.6.5",
|
||||
"element-ui": "^2.15.1",
|
||||
"highlight.js": "^10.7.3",
|
||||
"v-viewer": "^1.6.4",
|
||||
"vue": "^2.6.11",
|
||||
"vue-i18n": "^8.27.2",
|
||||
@@ -25,10 +28,13 @@
|
||||
"@vue/cli-plugin-eslint": "^4.5.0",
|
||||
"@vue/cli-service": "^4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"less": "^3.12.2",
|
||||
"less-loader": "^7.1.0",
|
||||
"markdown-it": "^13.0.1",
|
||||
"markdown-it-checkbox": "^1.1.0",
|
||||
"prettier": "^1.19.1",
|
||||
"vue-template-compiler": "^2.6.11",
|
||||
"webpack": "^4.44.2"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<link rel="icon" href="./dist/logo.png">
|
||||
<title>一个简单的web思维导图实现</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
BIN
web/public/logo.png
Normal file
BIN
web/public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
38
web/scripts/autoBuildDoc.js
Normal file
38
web/scripts/autoBuildDoc.js
Normal file
@@ -0,0 +1,38 @@
|
||||
const chokidar = require('chokidar')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const { exec } = require('node:child_process')
|
||||
const { transformMdToVue } = require('./transformMdToVue')
|
||||
|
||||
const reBuildAll = () => {
|
||||
exec(
|
||||
'node ./buildDoc.js',
|
||||
{
|
||||
cwd: path.resolve(__dirname)
|
||||
},
|
||||
(error, msg) => {
|
||||
console.log(error, msg)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
const buildOne = file => {
|
||||
let content = fs.readFileSync(file, 'utf-8')
|
||||
let doc = transformMdToVue(content)
|
||||
let destPath = path.join(path.dirname(file), './index.vue')
|
||||
fs.writeFileSync(destPath, doc)
|
||||
}
|
||||
|
||||
chokidar
|
||||
.watch(path.join(__dirname, '../src/pages/Doc/'), {
|
||||
ignoreInitial: true
|
||||
})
|
||||
.on('all', (event, file) => {
|
||||
if (/\.md$/.test(file)) {
|
||||
if (event === 'change') {
|
||||
buildOne(file)
|
||||
} else {
|
||||
reBuildAll()
|
||||
}
|
||||
}
|
||||
})
|
||||
85
web/scripts/buildDoc.js
Normal file
85
web/scripts/buildDoc.js
Normal file
@@ -0,0 +1,85 @@
|
||||
// 编译文档
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const { transformMdToVue } = require('./transformMdToVue')
|
||||
|
||||
// 文档语言种类
|
||||
let langList = ['zh', 'en']
|
||||
|
||||
// 开始转换
|
||||
const transform = (dir, routerList) => {
|
||||
let dirs = fs.readdirSync(dir)
|
||||
dirs.forEach(item => {
|
||||
let cur = path.join(dir, item)
|
||||
if (fs.statSync(cur).isDirectory()) {
|
||||
compilerDir(cur, item, routerList)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 编译某种语言下的文档
|
||||
const compilerDir = (dir, dirName, routerList) => {
|
||||
let files = fs.readdirSync(dir)
|
||||
files.forEach(file => {
|
||||
if (file.endsWith('.md')) {
|
||||
compilerFile(dir, file, dirName, routerList)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 编译具体的文档
|
||||
const compilerFile = (dir, file, dirName, routerList) => {
|
||||
let filePath = path.join(dir, file)
|
||||
let destPath = path.join(dir, './index.vue')
|
||||
let content = fs.readFileSync(filePath, 'utf-8')
|
||||
let title = /(^|\n\r)\s*#\s+([^\n\r]+)/g.exec(content)
|
||||
if (title && title[2]) {
|
||||
addRouter(dirName, routerList, title[2])
|
||||
}
|
||||
let doc = transformMdToVue(content)
|
||||
fs.writeFileSync(destPath, doc)
|
||||
}
|
||||
|
||||
// 收集文档路由
|
||||
const addRouter = (item, routerList, title) => {
|
||||
routerList.push({
|
||||
path: item,
|
||||
title
|
||||
})
|
||||
}
|
||||
|
||||
// 创建路由
|
||||
const createRouter = () => {
|
||||
let content = `
|
||||
export default ${JSON.stringify(
|
||||
routerTypeList.map(item => {
|
||||
return {
|
||||
lang: item.lang,
|
||||
children: item.routerList
|
||||
}
|
||||
})
|
||||
)}
|
||||
`
|
||||
fs.writeFileSync(
|
||||
path.join(__dirname, '../src/pages/Doc/routerList.js'),
|
||||
content
|
||||
)
|
||||
}
|
||||
|
||||
// 创建目录列表
|
||||
const createCatalogList = () => {}
|
||||
|
||||
// 开始编译
|
||||
let routerTypeList = []
|
||||
langList.forEach(lang => {
|
||||
let dir = path.join(__dirname, '../src/pages/Doc/', `./${lang}/`)
|
||||
let routerList = []
|
||||
transform(dir, routerList)
|
||||
routerTypeList.push({
|
||||
lang,
|
||||
routerList
|
||||
})
|
||||
})
|
||||
// 创建路由
|
||||
createRouter()
|
||||
console.log('编译完成')
|
||||
31
web/scripts/transformMdToVue.js
Normal file
31
web/scripts/transformMdToVue.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
const hljs = require('highlight.js')
|
||||
const md = require('markdown-it')({
|
||||
highlight: function(str, lang) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return (
|
||||
'<pre class="hljs"><code>' +
|
||||
hljs.highlight(str, {
|
||||
language: lang,
|
||||
ignoreIllegals: true
|
||||
}).value +
|
||||
'</code></pre>'
|
||||
)
|
||||
} catch (__) {}
|
||||
}
|
||||
|
||||
return (
|
||||
'<pre class="hljs"><code>' + md.utils.escapeHtml(str) + '</code></pre>'
|
||||
)
|
||||
}
|
||||
}).use(require('markdown-it-checkbox'))
|
||||
|
||||
const templatePath = path.join(__dirname, '../src/pages/Doc/Template.vue')
|
||||
|
||||
exports.transformMdToVue = (content) => {
|
||||
let result = md.render(content)
|
||||
let template = fs.readFileSync(templatePath, 'utf-8')
|
||||
return template.replace('$$$$', result)
|
||||
}
|
||||
@@ -54,6 +54,12 @@
|
||||
<div class="content unicode" style="display: block;">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">github</div>
|
||||
<div class="code-name">&#xe64f;</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont"></span>
|
||||
<div class="name">选择</div>
|
||||
@@ -342,9 +348,9 @@
|
||||
<pre><code class="language-css"
|
||||
>@font-face {
|
||||
font-family: 'iconfont';
|
||||
src: url('iconfont.woff2?t=1668512547595') format('woff2'),
|
||||
url('iconfont.woff?t=1668512547595') format('woff'),
|
||||
url('iconfont.ttf?t=1668512547595') format('truetype');
|
||||
src: url('iconfont.woff2?t=1673600274529') format('woff2'),
|
||||
url('iconfont.woff?t=1673600274529') format('woff'),
|
||||
url('iconfont.ttf?t=1673600274529') format('truetype');
|
||||
}
|
||||
</code></pre>
|
||||
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
|
||||
@@ -370,6 +376,15 @@
|
||||
<div class="content font-class">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont icongithub"></span>
|
||||
<div class="name">
|
||||
github
|
||||
</div>
|
||||
<div class="code-name">.icongithub
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<span class="icon iconfont iconchoose1"></span>
|
||||
<div class="name">
|
||||
@@ -802,6 +817,14 @@
|
||||
<div class="content symbol">
|
||||
<ul class="icon_lists dib-box">
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#icongithub"></use>
|
||||
</svg>
|
||||
<div class="name">github</div>
|
||||
<div class="code-name">#icongithub</div>
|
||||
</li>
|
||||
|
||||
<li class="dib">
|
||||
<svg class="icon svg-icon" aria-hidden="true">
|
||||
<use xlink:href="#iconchoose1"></use>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
@font-face {
|
||||
font-family: "iconfont"; /* Project id 2479351 */
|
||||
src: url('iconfont.woff2?t=1668512547595') format('woff2'),
|
||||
url('iconfont.woff?t=1668512547595') format('woff'),
|
||||
url('iconfont.ttf?t=1668512547595') format('truetype');
|
||||
src: url('iconfont.woff2?t=1673600274529') format('woff2'),
|
||||
url('iconfont.woff?t=1673600274529') format('woff'),
|
||||
url('iconfont.ttf?t=1673600274529') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
@@ -13,6 +13,10 @@
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icongithub:before {
|
||||
content: "\e64f";
|
||||
}
|
||||
|
||||
.iconchoose1:before {
|
||||
content: "\e6c5";
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,6 +5,13 @@
|
||||
"css_prefix_text": "icon",
|
||||
"description": "思维导图",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "8760187",
|
||||
"name": "github",
|
||||
"font_class": "github",
|
||||
"unicode": "e64f",
|
||||
"unicode_decimal": 58959
|
||||
},
|
||||
{
|
||||
"icon_id": "1009019",
|
||||
"name": "选择",
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
web/src/assets/img/logo.png
Normal file
BIN
web/src/assets/img/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.5 KiB |
@@ -166,6 +166,22 @@ export const backgroundPositionList = [
|
||||
}
|
||||
]
|
||||
|
||||
// 背景图片大小
|
||||
export const backgroundSizeList = [
|
||||
{
|
||||
name: 'Auto',
|
||||
value: 'auto'
|
||||
},
|
||||
{
|
||||
name: 'Cover',
|
||||
value: 'cover'
|
||||
},
|
||||
{
|
||||
name: 'Contain',
|
||||
value: 'contain'
|
||||
}
|
||||
]
|
||||
|
||||
// 快捷键列表
|
||||
export const shortcutKeyList = [
|
||||
{
|
||||
|
||||
@@ -14,7 +14,8 @@ import {
|
||||
backgroundPositionList as backgroundPositionListZh,
|
||||
shortcutKeyList as shortcutKeyListZh,
|
||||
shapeList as shapeListZh,
|
||||
sidebarTriggerList as sidebarTriggerListZh
|
||||
sidebarTriggerList as sidebarTriggerListZh,
|
||||
backgroundSizeList as backgroundSizeListZh
|
||||
} from './zh'
|
||||
import {
|
||||
fontFamilyList as fontFamilyListEn,
|
||||
@@ -24,7 +25,8 @@ import {
|
||||
backgroundPositionList as backgroundPositionListEn,
|
||||
shortcutKeyList as shortcutKeyListEn,
|
||||
shapeList as shapeListEn,
|
||||
sidebarTriggerList as sidebarTriggerListEn
|
||||
sidebarTriggerList as sidebarTriggerListEn,
|
||||
backgroundSizeList as backgroundSizeListEn
|
||||
} from './en'
|
||||
|
||||
const fontFamilyList = {
|
||||
@@ -52,6 +54,11 @@ const backgroundPositionList = {
|
||||
en: backgroundPositionListEn
|
||||
}
|
||||
|
||||
const backgroundSizeList = {
|
||||
zh: backgroundSizeListZh,
|
||||
en: backgroundSizeListEn
|
||||
}
|
||||
|
||||
const shortcutKeyList = {
|
||||
zh: shortcutKeyListZh,
|
||||
en: shortcutKeyListEn
|
||||
@@ -81,6 +88,7 @@ export {
|
||||
lineStyleList,
|
||||
backgroundRepeatList,
|
||||
backgroundPositionList,
|
||||
backgroundSizeList,
|
||||
shortcutKeyList,
|
||||
shapeList,
|
||||
sidebarTriggerList
|
||||
|
||||
@@ -221,6 +221,22 @@ export const backgroundPositionList = [
|
||||
}
|
||||
]
|
||||
|
||||
// 背景图片大小
|
||||
export const backgroundSizeList = [
|
||||
{
|
||||
name: '自动',
|
||||
value: 'auto'
|
||||
},
|
||||
{
|
||||
name: '覆盖',
|
||||
value: 'cover'
|
||||
},
|
||||
{
|
||||
name: '保持',
|
||||
value: 'contain'
|
||||
}
|
||||
]
|
||||
|
||||
// 数据存储
|
||||
export const store = {
|
||||
sidebarZIndex: 1 //侧边栏zIndex
|
||||
|
||||
@@ -5,6 +5,8 @@ export default {
|
||||
color: 'Color',
|
||||
image: 'Image',
|
||||
imageRepeat: 'Image repeat',
|
||||
imagePosition: 'Image position',
|
||||
imageSize: 'Image size',
|
||||
line: 'Line',
|
||||
width: 'Width',
|
||||
style: 'Style',
|
||||
@@ -20,7 +22,19 @@ export default {
|
||||
level2Node: 'Level2 node',
|
||||
belowLevel2Node: 'Below level2 node',
|
||||
nodeBorderType: 'Node border style',
|
||||
nodeUseLineStyle: 'Use only has bottom border style'
|
||||
nodeUseLineStyle: 'Use only has bottom border style',
|
||||
otherConfig: 'Other config',
|
||||
enableFreeDrag: 'Enable node free drag',
|
||||
watermark: 'Watermark',
|
||||
showWatermark: 'Is show watermark',
|
||||
watermarkDefaultText: 'Watermark text',
|
||||
watermarkText: 'Watermark text',
|
||||
watermarkTextColor: 'Text color',
|
||||
watermarkLineSpacing: 'Line spacing',
|
||||
watermarkTextSpacing: 'Text spacing',
|
||||
watermarkAngle: 'Angle',
|
||||
watermarkTextOpacity: 'Text opacity',
|
||||
watermarkTextFontSize: 'Font size'
|
||||
},
|
||||
color: {
|
||||
moreColor: 'More color'
|
||||
|
||||
@@ -5,6 +5,8 @@ export default {
|
||||
color: '颜色',
|
||||
image: '图片',
|
||||
imageRepeat: '图片重复',
|
||||
imagePosition: '图片位置',
|
||||
imageSize: '图片大小',
|
||||
line: '连线',
|
||||
width: '粗细',
|
||||
style: '风格',
|
||||
@@ -20,7 +22,19 @@ export default {
|
||||
level2Node: '二级节点',
|
||||
belowLevel2Node: '三级及以下节点',
|
||||
nodeBorderType: '节点边框风格',
|
||||
nodeUseLineStyle: '是否使用只有底边框的风格'
|
||||
nodeUseLineStyle: '是否使用只有底边框的风格',
|
||||
otherConfig: '其他配置',
|
||||
enableFreeDrag: '是否开启节点自由拖拽',
|
||||
watermark: '水印',
|
||||
showWatermark: '是否显示水印',
|
||||
watermarkDefaultText: '水印文字',
|
||||
watermarkText: '水印文字',
|
||||
watermarkTextColor: '文字颜色',
|
||||
watermarkLineSpacing: '水印行间距',
|
||||
watermarkTextSpacing: '水印文字间距',
|
||||
watermarkAngle: '旋转角度',
|
||||
watermarkTextOpacity: '文字透明度',
|
||||
watermarkTextFontSize: '文字字号'
|
||||
},
|
||||
color: {
|
||||
moreColor: '更多颜色'
|
||||
|
||||
191
web/src/pages/Doc/Index.vue
Normal file
191
web/src/pages/Doc/Index.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<div class="docContainer">
|
||||
<Header></Header>
|
||||
<div class="content">
|
||||
<Sidebar></Sidebar>
|
||||
<div class="doc" ref="doc" id="doc" @scroll="onScroll">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
<CatalogBar :scrollTop="scrollTop" @scroll="doScroll"></CatalogBar>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Header from './components/Header.vue'
|
||||
import Sidebar from './components/Sidebar.vue'
|
||||
import CatalogBar from './components/CatalogBar.vue'
|
||||
import 'highlight.js/styles/atom-one-dark.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Header,
|
||||
Sidebar,
|
||||
CatalogBar
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
scrollTop: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doScroll(top) {
|
||||
this.$nextTick(() => {
|
||||
try {
|
||||
this.$refs.doc.scrollTop = top
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
onScroll() {
|
||||
this.scrollTop = this.$refs.doc.scrollTop
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less">
|
||||
.docContainer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: Quotes, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.doc {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
font-weight: 400;
|
||||
color: #213547;
|
||||
font-size: 16px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
line-height: 1.7;
|
||||
padding: 30px;
|
||||
|
||||
h1 {
|
||||
margin: 30px 0;
|
||||
font-size: 38px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 20px 0;
|
||||
border-top: 1px solid rgba(60, 60, 60, 0.12);
|
||||
font-size: 24px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 19px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: #42b883;
|
||||
transition: color 0.25s;
|
||||
|
||||
&:hover {
|
||||
color: #33a06f;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
margin-bottom: 20px;
|
||||
border-radius: 5px;
|
||||
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
|
||||
code {
|
||||
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
|
||||
}
|
||||
}
|
||||
|
||||
:not(pre) > code {
|
||||
background-color: #f1f1f1;
|
||||
padding: 0.15em 0.5em;
|
||||
border-radius: 4px;
|
||||
color: #476582;
|
||||
transition: color 0.5s, background-color 0.5s;
|
||||
font-family: Quotes, -apple-system, BlinkMacSystemFont, 'Segoe UI',
|
||||
Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans',
|
||||
'Helvetica Neue', sans-serif;
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding-left: 1.25rem;
|
||||
|
||||
> li {
|
||||
position: relative;
|
||||
margin: 1px 0;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(60, 60, 60, 0.33);
|
||||
transition: background-color 0.5s;
|
||||
left: -1.25rem;
|
||||
top: 0.75rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
margin-top: 0.8rem;
|
||||
margin-bottom: 1.4rem;
|
||||
}
|
||||
|
||||
tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 5px 14px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin: 1rem 0;
|
||||
border-left: 0.2rem solid rgba(60, 60, 60, 0.29);
|
||||
padding-left: 1rem;
|
||||
transition: border-color 0.5s;
|
||||
|
||||
> p {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
color: rgba(60, 60, 60, 0.7);
|
||||
transition: color 0.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
15
web/src/pages/Doc/Template.vue
Normal file
15
web/src/pages/Doc/Template.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<div>
|
||||
$$$$
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
78
web/src/pages/Doc/catalogList.js
Normal file
78
web/src/pages/Doc/catalogList.js
Normal file
@@ -0,0 +1,78 @@
|
||||
import routerList from './routerList'
|
||||
|
||||
let langList = [
|
||||
{
|
||||
name: '中文',
|
||||
path: 'zh'
|
||||
},
|
||||
{
|
||||
name: 'English',
|
||||
path: 'en'
|
||||
}
|
||||
]
|
||||
let StartList = ['introduction', 'start', 'translate', 'changelog']
|
||||
let APIList = [
|
||||
'constructor',
|
||||
'node',
|
||||
'render',
|
||||
'view',
|
||||
'keyCommand',
|
||||
'command',
|
||||
'batchExecution',
|
||||
'select',
|
||||
'drag',
|
||||
'keyboardNavigation',
|
||||
'doExport',
|
||||
'miniMap',
|
||||
'watermark',
|
||||
'xmind',
|
||||
'utils'
|
||||
]
|
||||
|
||||
const createList = (lang, list) => {
|
||||
let langRouter = routerList.find(item => {
|
||||
return item.lang === lang
|
||||
})
|
||||
let children = langRouter.children
|
||||
return list
|
||||
.filter(item => {
|
||||
return children.find(child => {
|
||||
return child.path === item
|
||||
})
|
||||
})
|
||||
.map(item => {
|
||||
return {
|
||||
path: item,
|
||||
name: children.find(child => {
|
||||
return child.path === item
|
||||
}).title
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
zh: [
|
||||
{
|
||||
groupName: '开始',
|
||||
list: createList('zh', StartList)
|
||||
},
|
||||
{
|
||||
groupName: 'API',
|
||||
list: createList('zh', APIList)
|
||||
}
|
||||
],
|
||||
en: [
|
||||
{
|
||||
groupName: 'Start',
|
||||
list: createList('en', StartList)
|
||||
},
|
||||
{
|
||||
groupName: 'API',
|
||||
list: createList('en', APIList)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export {
|
||||
langList
|
||||
}
|
||||
236
web/src/pages/Doc/components/CatalogBar.vue
Normal file
236
web/src/pages/Doc/components/CatalogBar.vue
Normal file
@@ -0,0 +1,236 @@
|
||||
<template>
|
||||
<div class="catalogBarContainer">
|
||||
<div class="catalogBarTitle">{{ pageCatalogTitle }}</div>
|
||||
<div class="catalogList">
|
||||
<div
|
||||
class="catalogItem"
|
||||
v-for="(item, index) in list"
|
||||
:key="item.title + index"
|
||||
:class="{ active: item.title === activeCatalog }"
|
||||
@click="scrollTo(item, index)"
|
||||
>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div
|
||||
v-if="activeCatalogIndex !== -1"
|
||||
class="activeBar"
|
||||
:style="{ top: 4 + activeCatalogIndex * 28 + 'px' }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import t from '../i18n'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
scrollTop: {
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
lang: '',
|
||||
list: [],
|
||||
activeCatalog: '',
|
||||
activeCatalogIndex: -1,
|
||||
appointCatalog: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pageCatalogTitle() {
|
||||
return t('pageCatalog', this.lang)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(newVal, oldVal) {
|
||||
this.initLang()
|
||||
this.initCatalogList(newVal.path, oldVal.path)
|
||||
},
|
||||
scrollTop() {
|
||||
this.onScroll()
|
||||
},
|
||||
lang(newVal, oldVal) {
|
||||
console.log(newVal, oldVal)
|
||||
if (!oldVal) {
|
||||
return
|
||||
}
|
||||
this.initCatalogList()
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initLang()
|
||||
this.initCatalogList()
|
||||
this.scrollToCatalog()
|
||||
},
|
||||
methods: {
|
||||
// 获取当前语言
|
||||
initLang() {
|
||||
let lang = /^\/doc\/([^\/]+)\//.exec(this.$route.path)
|
||||
if (lang && lang[1]) {
|
||||
this.lang = lang[1]
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化二级标题目录
|
||||
initCatalogList(newPath, oldPath) {
|
||||
let newPathRes = /^\/doc\/[^\/]+\/([^\/]+)/.exec(newPath)
|
||||
let oldPathRes = /^\/doc\/[^\/]+\/([^\/]+)/.exec(oldPath)
|
||||
// 语言变了、章节变了,需要重新获取二级标题目录
|
||||
if ((!newPath && !oldPath) || newPathRes[1] !== oldPathRes[1]) {
|
||||
this.$emit('scroll', 0)
|
||||
this.resetActive()
|
||||
let container = document.getElementById('doc')
|
||||
let els = document.querySelectorAll('#doc h2')
|
||||
this.list = Array.from(els).map(item => {
|
||||
return {
|
||||
title: item.textContent,
|
||||
top: item.offsetTop - container.offsetTop
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 如果url中存在二级标题,那么滚动到该标题所在位置
|
||||
scrollToCatalog() {
|
||||
let url = /^\/doc\/[^\/]+\/[^\/]+\/([^\/]+)($|\/)/.exec(this.$route.path)
|
||||
if (url && url[1]) {
|
||||
let h = decodeURIComponent(url[1])
|
||||
let item = this.list.find(item => {
|
||||
return item.title === h
|
||||
})
|
||||
let index = this.list.findIndex(item => {
|
||||
return item.title === h
|
||||
})
|
||||
if (item) {
|
||||
this.activeCatalog = item.title
|
||||
this.activeCatalogIndex = index
|
||||
this.$emit('scroll', item.top)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 手动点击切换到指定二级标题
|
||||
scrollTo(item, index) {
|
||||
this.appointCatalog = true
|
||||
this.routeToNewCatalog(item.title)
|
||||
this.$nextTick(() => {
|
||||
this.activeCatalog = item.title
|
||||
this.activeCatalogIndex = index
|
||||
this.scrollToCatalog()
|
||||
})
|
||||
},
|
||||
|
||||
// 路由到指定二级标题
|
||||
routeToNewCatalog(title) {
|
||||
let path = this.$route.path
|
||||
let url = ''
|
||||
if (!title) {
|
||||
url = path.replace(/^(\/doc\/[^\/]+\/[^\/]+)($|\/|.*)$/, '$1')
|
||||
} else if (/^\/doc\/[^\/]+\/[^\/]+($|\/)$/.test(path)) {
|
||||
url = path.replace(
|
||||
/^(\/doc\/[^\/]+\/[^\/]+)($|\/)$/,
|
||||
'$1/' + encodeURIComponent(title)
|
||||
)
|
||||
} else {
|
||||
url = path.replace(
|
||||
/^(\/doc\/[^\/]+\/[^\/]+\/)([^\/]+)($|\/)/,
|
||||
(...args) => {
|
||||
return args[1] + encodeURIComponent(title)
|
||||
}
|
||||
)
|
||||
}
|
||||
if (path === url) {
|
||||
return
|
||||
}
|
||||
this.$router.push(url)
|
||||
},
|
||||
|
||||
// 文档滚动时判断当前滚动到哪个二级标题
|
||||
onScroll() {
|
||||
if (this.appointCatalog) {
|
||||
this.appointCatalog = false
|
||||
return
|
||||
}
|
||||
let find = false
|
||||
for (let i = 0; i < this.list.length; i++) {
|
||||
let cur = this.list[i]
|
||||
let next = this.list[i + 1]
|
||||
if (this.scrollTop >= cur.top && (!next || this.scrollTop < next.top)) {
|
||||
find = true
|
||||
if (cur.title === this.activeCatalog) {
|
||||
break
|
||||
}
|
||||
this.activeCatalog = cur.title
|
||||
this.activeCatalogIndex = i
|
||||
this.routeToNewCatalog(cur.title)
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!find) {
|
||||
this.resetActive()
|
||||
this.routeToNewCatalog('')
|
||||
}
|
||||
},
|
||||
|
||||
resetActive() {
|
||||
this.activeCatalog = ''
|
||||
this.activeCatalogIndex = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.catalogBarContainer {
|
||||
width: 20%;
|
||||
flex-shrink: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
padding-top: 60px;
|
||||
padding-bottom: 30px;
|
||||
padding-left: 20px;
|
||||
|
||||
.catalogBarTitle {
|
||||
font-weight: 700;
|
||||
margin-bottom: 4px;
|
||||
text-transform: uppercase;
|
||||
font-size: 11px;
|
||||
letter-spacing: 0.4px;
|
||||
}
|
||||
|
||||
.catalogList {
|
||||
position: relative;
|
||||
|
||||
.catalogItem {
|
||||
color: rgba(60, 60, 60, 0.7);
|
||||
transition: color 0.5s;
|
||||
line-height: 28px;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
|
||||
&.active {
|
||||
color: rgba(60, 60, 60, 1);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.activeBar {
|
||||
position: absolute;
|
||||
left: -10px;
|
||||
width: 4px;
|
||||
height: 20px;
|
||||
background-color: #42b883;
|
||||
border-radius: 4px;
|
||||
transition: top 0.25s cubic-bezier(0, 1, 0.5, 1), opacity 0.25s,
|
||||
background-color 0.5s;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
171
web/src/pages/Doc/components/Header.vue
Normal file
171
web/src/pages/Doc/components/Header.vue
Normal file
@@ -0,0 +1,171 @@
|
||||
<template>
|
||||
<div class="headerContainer">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
<img src="../../../assets/img/logo.png" alt="">
|
||||
SimpleMindMap
|
||||
</div>
|
||||
</div>
|
||||
<div class="center">
|
||||
<div class="btn" @click="toDemo">{{ demoName }}</div>
|
||||
<el-dropdown
|
||||
trigger="click"
|
||||
placement="bottom-start"
|
||||
@command="handleCommand"
|
||||
>
|
||||
<span class="translateBtn">
|
||||
{{ currentLangName }}<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item
|
||||
v-for="item in otherLangList"
|
||||
:key="item.path"
|
||||
:command="item.path"
|
||||
>{{ item.name }}</el-dropdown-item
|
||||
>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
|
||||
<a href="https://github.com/wanglin2/mind-map" target="_blank">
|
||||
<span class="iconfont icongithub"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { langList } from '../catalogList'
|
||||
import t from '../i18n'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
lang: '',
|
||||
currentLangName: '',
|
||||
otherLangList: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
demoName() {
|
||||
return t('demo', this.lang)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.init()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
let lang = /^\/doc\/([^\/]+)\//.exec(this.$route.path)
|
||||
if (lang && lang[1]) {
|
||||
this.lang = lang[1]
|
||||
let currentLang = langList.find(item => {
|
||||
return item.path === this.lang
|
||||
})
|
||||
this.currentLangName = currentLang.name
|
||||
this.otherLangList = langList.filter(item => {
|
||||
return item.path !== this.lang
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
toDemo() {
|
||||
this.$router.push('/')
|
||||
},
|
||||
|
||||
handleCommand(path) {
|
||||
let url = this.$route.path.replace(/^\/doc\/([^\/]+)\//, (...args) => {
|
||||
return `/doc/${path}/`
|
||||
})
|
||||
this.$router.push(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.headerContainer {
|
||||
height: 55px;
|
||||
border-bottom: 1px solid rgba(60, 60, 60, 0.12);
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.left {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.title {
|
||||
width: 200px;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 30px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
|
||||
.btn {
|
||||
color: #213547;
|
||||
cursor: pointer;
|
||||
transition: color 0.5s;
|
||||
margin-right: 15px;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
color: #42b883;
|
||||
}
|
||||
}
|
||||
|
||||
.translateBtn {
|
||||
margin-right: 15px;
|
||||
font-size: 16px;
|
||||
color: #213547;
|
||||
cursor: pointer;
|
||||
margin-top: 1px;
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: rgba(60, 60, 60, 0.7);
|
||||
transition: color 0.5s;
|
||||
margin-right: 15px;
|
||||
|
||||
&:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: rgba(60, 60, 60, 1);
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-size: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 20%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
118
web/src/pages/Doc/components/Sidebar.vue
Normal file
118
web/src/pages/Doc/components/Sidebar.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="sideBarContainer">
|
||||
<div class="catalogGroupList">
|
||||
<div
|
||||
class="catalogGroup"
|
||||
v-for="(group, groupIndex) in groupList"
|
||||
:key="groupIndex"
|
||||
>
|
||||
<div class="catalogGroupName">{{ group.groupName }}</div>
|
||||
<div class="catalogList">
|
||||
<div
|
||||
class="catalogItem"
|
||||
v-for="item in group.list"
|
||||
:key="groupIndex + item.path"
|
||||
:class="{ active: item.path === currentPath }"
|
||||
@click="jump(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import catalogList from '../catalogList'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
groupList: [],
|
||||
lang: '',
|
||||
currentPath: ''
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.initCatalog()
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.initCatalog()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
jump(item) {
|
||||
if (item.path === this.currentPath) {
|
||||
return
|
||||
}
|
||||
this.$router.push(`/doc/${this.lang}/${item.path}`)
|
||||
},
|
||||
|
||||
initCatalog() {
|
||||
// 目录列表
|
||||
let lang = /^\/doc\/([^\/]+)\//.exec(this.$route.path)
|
||||
if (lang && lang[1]) {
|
||||
this.lang = lang[1]
|
||||
this.groupList = catalogList[this.lang]
|
||||
}
|
||||
// 当前所在路径
|
||||
let path = /^\/doc\/[^\/]+\/([^\/]+)(\/|$)/.exec(this.$route.path)
|
||||
if (path && path[1]) {
|
||||
this.currentPath = path[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.sideBarContainer {
|
||||
width: 30%;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-top: 60px;
|
||||
padding-bottom: 30px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.catalogGroupList {
|
||||
width: 200px;
|
||||
|
||||
.catalogGroup {
|
||||
padding-bottom: 16px;
|
||||
|
||||
.catalogGroupName {
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #213547;
|
||||
transition: color 0.5s;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.catalogList {
|
||||
.catalogItem {
|
||||
line-height: 20px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: rgba(60, 60, 60, 0.7);
|
||||
transition: color 0.5s;
|
||||
cursor: pointer;
|
||||
padding: 4px 0;
|
||||
|
||||
&:hover {
|
||||
color: rgba(60, 60, 60, 1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #42b883;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
16
web/src/pages/Doc/en/batchExecution/index.md
Normal file
16
web/src/pages/Doc/en/batchExecution/index.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# batchExecution instance
|
||||
|
||||
The `batchExecution` is used to batch asynchronously perform some operations,
|
||||
and if a certain operation is called multiple times at the same time, it will
|
||||
only be executed once in the next event loop. Can be obtained through
|
||||
`mindMap.batchExecution`
|
||||
|
||||
## Method
|
||||
|
||||
### push(name, fn)
|
||||
|
||||
Add task.
|
||||
|
||||
`name`: task name
|
||||
|
||||
`fn`: task
|
||||
25
web/src/pages/Doc/en/batchExecution/index.vue
Normal file
25
web/src/pages/Doc/en/batchExecution/index.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>batchExecution instance</h1>
|
||||
<p>The <code>batchExecution</code> is used to batch asynchronously perform some operations,
|
||||
and if a certain operation is called multiple times at the same time, it will
|
||||
only be executed once in the next event loop. Can be obtained through
|
||||
<code>mindMap.batchExecution</code></p>
|
||||
<h2>Method</h2>
|
||||
<h3>push(name, fn)</h3>
|
||||
<p>Add task.</p>
|
||||
<p><code>name</code>: task name</p>
|
||||
<p><code>fn</code>: task</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
173
web/src/pages/Doc/en/changelog/index.md
Normal file
173
web/src/pages/Doc/en/changelog/index.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Changelog
|
||||
|
||||
## 0.3.4
|
||||
|
||||
New:Automatic line wrapping function is added to node text.
|
||||
|
||||
Fix: 1.Fix the problem of deletion exceptions if there are root nodes in the batch deleted nodes. 2.Fix the problem that high node height will overlap with other nodes in the case of bottom edge style.
|
||||
|
||||
## 0.3.3
|
||||
|
||||
Fix: The root node text cannot wrap.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
Fix: 1.Fix the problem that the node style is not updated when the secondary node is dragged to other nodes or other nodes are dragged to the secondary node; 2.Fix the problem that when the actual content of the mind map is larger than the screen width and height, the excess part is not watermarked when exporting.
|
||||
|
||||
## 0.3.1
|
||||
|
||||
Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.
|
||||
|
||||
New: Add position and size settings for background image display. This setting is also supported for exported pictures.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
Upgrade to plugin architecture, pull out some non-core functions as plugins, register as needed, and reduce the overall volume.
|
||||
|
||||
## 0.2.24
|
||||
|
||||
New: Node free drag is changed to configurable, the default is `false`, not open; Support add watermark.
|
||||
|
||||
## 0.2.23
|
||||
|
||||
New: Support register new theme.
|
||||
|
||||
## 0.2.22
|
||||
|
||||
optimization:The theme and structure pictures of the built-in `simple-mind-map` package are removed and replaced by user self-maintenance. The original pictures can be found in the `web/assets/img/` directory.
|
||||
|
||||
## 0.2.21
|
||||
|
||||
New: Support node horizontal line style.
|
||||
|
||||
## 0.2.20
|
||||
|
||||
fix:When the distance from the canvas to the upper left corner of the window is not 0, the node dragging will have an offset problem.
|
||||
|
||||
## 0.2.19
|
||||
|
||||
fix:When the node is not activated, pressing any key will trigger the problem of automatic focus.
|
||||
|
||||
## 0.2.18
|
||||
|
||||
optimization:Keyboard navigation algorithm for finding focus, supporting simple algorithm, region algorithm and shadow algorithm.
|
||||
|
||||
## 0.2.17
|
||||
|
||||
New:Keyboard navigation, that is, switch the active nodes through the direction keys; The node text content can be edited directly in the outline.
|
||||
|
||||
## 0.2.16
|
||||
|
||||
optimization:Mini map; drag performance.
|
||||
|
||||
## 0.2.15
|
||||
|
||||
optimization:Local file editing.
|
||||
|
||||
New:Double-click the image in the node to preview the large image.
|
||||
|
||||
## 0.2.14
|
||||
|
||||
optimization:Automatically expand when inserting child nodes.
|
||||
|
||||
fix:The error occurred when the mini map was closed.
|
||||
|
||||
## 0.2.13
|
||||
|
||||
fix:The child node is missing when collapsing state replication.
|
||||
|
||||
## 0.2.11
|
||||
|
||||
fix:Fix the problem that is lost when the child node collapses state replication.
|
||||
|
||||
New:Support mini map.
|
||||
|
||||
## 0.2.10
|
||||
|
||||
optimization:Focus immediately when you manually create a node.
|
||||
|
||||
fix:Connection style depth update problem.
|
||||
|
||||
New:Logical structure diagram and mind map add linear connection style and direct connection style.
|
||||
|
||||
## 0.2.9
|
||||
|
||||
New:Support the creation, opening and saving of local files on the computer.
|
||||
|
||||
## 0.2.8
|
||||
|
||||
fix:Xmind8 version file import failed.
|
||||
|
||||
New:Expanding to the specified level is supported.
|
||||
|
||||
## 0.2.7
|
||||
|
||||
fix:The root node adds multiple nodes to burst the stack.
|
||||
|
||||
New:Support import .xmind file.
|
||||
|
||||
## 0.2.6
|
||||
|
||||
New:The title tag is added when exporting svg.
|
||||
|
||||
## 0.2.5
|
||||
|
||||
fix:Bugs caused by node expansion and collapse.
|
||||
|
||||
New:Node supports custom line styles.
|
||||
|
||||
## 0.2.4
|
||||
|
||||
New:Nodes support multiple shapes.
|
||||
|
||||
## 0.2.3
|
||||
|
||||
fix:Shortcut key conflicts when editing node text; Right-click menu shortcut prompt error; Right-click menu shortcut prompt.
|
||||
|
||||
## 0.2.2
|
||||
|
||||
fix:The input string '/' conflicts with the shortcut key '/'.
|
||||
|
||||
## 0.2.1
|
||||
|
||||
New:Support export as pdf.
|
||||
|
||||
## 0.2.0
|
||||
|
||||
New:Classic4 theme;Support adding summary; Support free drag; Move Node Up, Move Node Down, Copy Node, Cut Node, Paste Node, One-click Organize Cloth Shortcut; Library packaging; Ctrl+left click to select multiple.
|
||||
|
||||
## 0.1.18
|
||||
|
||||
fix:The problem that the node icon cannot be deleted; The tool button is grayed out and can still be clicked.
|
||||
|
||||
## 0.1.17
|
||||
|
||||
New:Add read-only mode.
|
||||
|
||||
## 0.1.16
|
||||
|
||||
New:Node notes support markdown and rich text.
|
||||
|
||||
fix:Can't select text; Node annotations cannot hide problems after node activation; When editing text such as hyperlinks, notes, labels, etc., the return key and return key conflict with the shortcut key of mind map.
|
||||
|
||||
## 0.1.15
|
||||
|
||||
New:The status data supports saving the active status and view status (drag position, zoom value);Support node drag.
|
||||
|
||||
## 0.1.14
|
||||
|
||||
fix:There are problems with setting topics when activating nodes.
|
||||
|
||||
## 0.1.13
|
||||
|
||||
New:Shortcut key function; Support export as json。
|
||||
|
||||
optimization:Some details.
|
||||
|
||||
## 0.1.12
|
||||
|
||||
New:Local storage;Right-click menu function, etc.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
Complete basic functions.
|
||||
102
web/src/pages/Doc/en/changelog/index.vue
Normal file
102
web/src/pages/Doc/en/changelog/index.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.3.4</h2>
|
||||
<p>New:Automatic line wrapping function is added to node text.</p>
|
||||
<p>Fix: 1.Fix the problem of deletion exceptions if there are root nodes in the batch deleted nodes. 2.Fix the problem that high node height will overlap with other nodes in the case of bottom edge style.</p>
|
||||
<h2>0.3.3</h2>
|
||||
<p>Fix: The root node text cannot wrap.</p>
|
||||
<h2>0.3.2</h2>
|
||||
<p>Fix: 1.Fix the problem that the node style is not updated when the secondary node is dragged to other nodes or other nodes are dragged to the secondary node; 2.Fix the problem that when the actual content of the mind map is larger than the screen width and height, the excess part is not watermarked when exporting.</p>
|
||||
<h2>0.3.1</h2>
|
||||
<p>Fix: 1.The problem that deleting the background image does not take effect; 2.The problem that the connector runs above the root node when the node is dragged to the root node.</p>
|
||||
<p>New: Add position and size settings for background image display. This setting is also supported for exported pictures.</p>
|
||||
<h2>0.3.0</h2>
|
||||
<p>Upgrade to plugin architecture, pull out some non-core functions as plugins, register as needed, and reduce the overall volume.</p>
|
||||
<h2>0.2.24</h2>
|
||||
<p>New: Node free drag is changed to configurable, the default is <code>false</code>, not open; Support add watermark.</p>
|
||||
<h2>0.2.23</h2>
|
||||
<p>New: Support register new theme.</p>
|
||||
<h2>0.2.22</h2>
|
||||
<p>optimization:The theme and structure pictures of the built-in <code>simple-mind-map</code> package are removed and replaced by user self-maintenance. The original pictures can be found in the <code>web/assets/img/</code> directory.</p>
|
||||
<h2>0.2.21</h2>
|
||||
<p>New: Support node horizontal line style.</p>
|
||||
<h2>0.2.20</h2>
|
||||
<p>fix:When the distance from the canvas to the upper left corner of the window is not 0, the node dragging will have an offset problem.</p>
|
||||
<h2>0.2.19</h2>
|
||||
<p>fix:When the node is not activated, pressing any key will trigger the problem of automatic focus.</p>
|
||||
<h2>0.2.18</h2>
|
||||
<p>optimization:Keyboard navigation algorithm for finding focus, supporting simple algorithm, region algorithm and shadow algorithm.</p>
|
||||
<h2>0.2.17</h2>
|
||||
<p>New:Keyboard navigation, that is, switch the active nodes through the direction keys; The node text content can be edited directly in the outline.</p>
|
||||
<h2>0.2.16</h2>
|
||||
<p>optimization:Mini map; drag performance.</p>
|
||||
<h2>0.2.15</h2>
|
||||
<p>optimization:Local file editing.</p>
|
||||
<p>New:Double-click the image in the node to preview the large image.</p>
|
||||
<h2>0.2.14</h2>
|
||||
<p>optimization:Automatically expand when inserting child nodes.</p>
|
||||
<p>fix:The error occurred when the mini map was closed.</p>
|
||||
<h2>0.2.13</h2>
|
||||
<p>fix:The child node is missing when collapsing state replication.</p>
|
||||
<h2>0.2.11</h2>
|
||||
<p>fix:Fix the problem that is lost when the child node collapses state replication.</p>
|
||||
<p>New:Support mini map.</p>
|
||||
<h2>0.2.10</h2>
|
||||
<p>optimization:Focus immediately when you manually create a node.</p>
|
||||
<p>fix:Connection style depth update problem.</p>
|
||||
<p>New:Logical structure diagram and mind map add linear connection style and direct connection style.</p>
|
||||
<h2>0.2.9</h2>
|
||||
<p>New:Support the creation, opening and saving of local files on the computer.</p>
|
||||
<h2>0.2.8</h2>
|
||||
<p>fix:Xmind8 version file import failed.</p>
|
||||
<p>New:Expanding to the specified level is supported.</p>
|
||||
<h2>0.2.7</h2>
|
||||
<p>fix:The root node adds multiple nodes to burst the stack.</p>
|
||||
<p>New:Support import .xmind file.</p>
|
||||
<h2>0.2.6</h2>
|
||||
<p>New:The title tag is added when exporting svg.</p>
|
||||
<h2>0.2.5</h2>
|
||||
<p>fix:Bugs caused by node expansion and collapse.</p>
|
||||
<p>New:Node supports custom line styles.</p>
|
||||
<h2>0.2.4</h2>
|
||||
<p>New:Nodes support multiple shapes.</p>
|
||||
<h2>0.2.3</h2>
|
||||
<p>fix:Shortcut key conflicts when editing node text; Right-click menu shortcut prompt error; Right-click menu shortcut prompt.</p>
|
||||
<h2>0.2.2</h2>
|
||||
<p>fix:The input string '/' conflicts with the shortcut key '/'.</p>
|
||||
<h2>0.2.1</h2>
|
||||
<p>New:Support export as pdf.</p>
|
||||
<h2>0.2.0</h2>
|
||||
<p>New:Classic4 theme;Support adding summary; Support free drag; Move Node Up, Move Node Down, Copy Node, Cut Node, Paste Node, One-click Organize Cloth Shortcut; Library packaging; Ctrl+left click to select multiple.</p>
|
||||
<h2>0.1.18</h2>
|
||||
<p>fix:The problem that the node icon cannot be deleted; The tool button is grayed out and can still be clicked.</p>
|
||||
<h2>0.1.17</h2>
|
||||
<p>New:Add read-only mode.</p>
|
||||
<h2>0.1.16</h2>
|
||||
<p>New:Node notes support markdown and rich text.</p>
|
||||
<p>fix:Can't select text; Node annotations cannot hide problems after node activation; When editing text such as hyperlinks, notes, labels, etc., the return key and return key conflict with the shortcut key of mind map.</p>
|
||||
<h2>0.1.15</h2>
|
||||
<p>New:The status data supports saving the active status and view status (drag position, zoom value);Support node drag.</p>
|
||||
<h2>0.1.14</h2>
|
||||
<p>fix:There are problems with setting topics when activating nodes.</p>
|
||||
<h2>0.1.13</h2>
|
||||
<p>New:Shortcut key function; Support export as json。</p>
|
||||
<p>optimization:Some details.</p>
|
||||
<h2>0.1.12</h2>
|
||||
<p>New:Local storage;Right-click menu function, etc.</p>
|
||||
<h2>0.1.0</h2>
|
||||
<p>Complete basic functions.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
33
web/src/pages/Doc/en/command/index.md
Normal file
33
web/src/pages/Doc/en/command/index.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# command instance
|
||||
|
||||
The `command` instance is responsible for adding and executing commands. It
|
||||
includes many built-in commands and can also be added manually. A command refers
|
||||
to an operation that needs to add a copy to the history stack data. The
|
||||
`mindMap.command` instance can be obtained through this."
|
||||
|
||||
## Methods
|
||||
|
||||
### add(name, fn)
|
||||
|
||||
Add a command.
|
||||
|
||||
`name`: Command name
|
||||
|
||||
`fn`: Method to be executed by the command
|
||||
|
||||
### remove(name, fn)
|
||||
|
||||
Remove a command.
|
||||
|
||||
`name`: Name of the command to be removed
|
||||
|
||||
`fn`: Method to be removed, if not provided all methods for the command will be
|
||||
removed
|
||||
|
||||
### getCopyData()
|
||||
|
||||
Get a copy of the rendering tree data
|
||||
|
||||
### clearHistory()
|
||||
|
||||
Clear the history stack data
|
||||
34
web/src/pages/Doc/en/command/index.vue
Normal file
34
web/src/pages/Doc/en/command/index.vue
Normal file
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>command instance</h1>
|
||||
<p>The <code>command</code> instance is responsible for adding and executing commands. It
|
||||
includes many built-in commands and can also be added manually. A command refers
|
||||
to an operation that needs to add a copy to the history stack data. The
|
||||
<code>mindMap.command</code> instance can be obtained through this."</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>add(name, fn)</h3>
|
||||
<p>Add a command.</p>
|
||||
<p><code>name</code>: Command name</p>
|
||||
<p><code>fn</code>: Method to be executed by the command</p>
|
||||
<h3>remove(name, fn)</h3>
|
||||
<p>Remove a command.</p>
|
||||
<p><code>name</code>: Name of the command to be removed</p>
|
||||
<p><code>fn</code>: Method to be removed, if not provided all methods for the command will be
|
||||
removed</p>
|
||||
<h3>getCopyData()</h3>
|
||||
<p>Get a copy of the rendering tree data</p>
|
||||
<h3>clearHistory()</h3>
|
||||
<p>Clear the history stack data</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
327
web/src/pages/Doc/en/constructor/index.md
Normal file
327
web/src/pages/Doc/en/constructor/index.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# Constructor
|
||||
|
||||
## Basic use
|
||||
|
||||
```html
|
||||
<div id="mindMapContainer"></div>
|
||||
```
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map";
|
||||
|
||||
const mindMap = new MindMap({
|
||||
el: document.getElementById("mindMapContainer"),
|
||||
data: {
|
||||
"data": {
|
||||
"text": "Root Node"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Instantiation options
|
||||
|
||||
| Field Name | Type | Default Value | Description | Required |
|
||||
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ | -------- |
|
||||
| el | Element | | Container element, must be a DOM element | Yes |
|
||||
| data | Object | {} | Mind map data, refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js | |
|
||||
| layout | String | logicalStructure | Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram) | |
|
||||
| theme | String | default | Theme, options: default, classic, minions, pinkGrape, mint, gold, vitalityOrange, greenLeaf, dark2, skyGreen, classic2, classic3, classic4 (v0.2.0+), classicGreen, classicBlue, blueSky, brainImpairedPink, dark, earthYellow, freshGreen, freshRed, romanticPurple | |
|
||||
| themeConfig | Object | {} | Theme configuration, will be merged with the selected theme, available fields refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js | |
|
||||
| scaleRatio | Number | 0.1 | The incremental scaling ratio | |
|
||||
| maxTag | Number | 5 | The maximum number of tags displayed in the node, any additional tags will be discarded | |
|
||||
| exportPadding | Number | 20 | The padding for exporting images | |
|
||||
| imgTextMargin | Number | 5 | The spacing between the image and text in the node | |
|
||||
| textContentMargin | Number | 2 | The spacing between various text information in the node, such as the spacing between the icon and text | |
|
||||
| selectTranslateStep | Number | 3 | The canvas offset when mouse moves to the edge during multi-select node | |
|
||||
| selectTranslateLimit | Number | 20 | The distance from the edge when the canvas begins to offset during multi-select node | |
|
||||
| customNoteContentShow(v0.1.6+) | Object | null | Custom node note content display, object type, structure: {show: (noteContent, left, top) => {// your display node note logic }, hide: () => {// your hide node note logic }} | |
|
||||
| readonly(v0.1.7+) | Boolean | false | Whether it is read-only mode | |
|
||||
| enableFreeDrag(v0.2.4+) | Boolean | false | Enable node free drag | |
|
||||
| watermarkConfig(v0.2.4+) | Object | | Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration | |
|
||||
| textAutoWrapWidth(v0.3.4+) | Number | 500 | Each line of text in the node will wrap automatically when it reaches the width | |
|
||||
|
||||
### Watermark config
|
||||
|
||||
| Field Name | Type | Default Value | Description |
|
||||
| ----------- | ------ | ------------------------------------------- | ------------------------------------------------------------ |
|
||||
| text | String | '' | Watermark text. If it is an empty string, the watermark will not be displayed |
|
||||
| lineSpacing | Number | 100 | Spacing between watermark lines |
|
||||
| textSpacing | Number | 100 | Spacing between watermarks in the same row |
|
||||
| angle | Number | 30 | Tilt angle of watermark, range: [0, 90] |
|
||||
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | Watermark text style |
|
||||
|
||||
## Static methods
|
||||
|
||||
### defineTheme(name, config)
|
||||
|
||||
> v0.2.23+
|
||||
|
||||
Define new theme.
|
||||
|
||||
`name`:New theme name
|
||||
|
||||
`config`:New theme config
|
||||
|
||||
`Simple-mind-map ` Built-in many themes. In addition, you can register new theme. It is recommended to register before instantiation, so that you can directly use the newly registered theme during instantiation. Use example:
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
// 注册新主题
|
||||
MindMap.defineTheme('Theme name', {})
|
||||
|
||||
// 1.实例化时使用新注册的主题
|
||||
const mindMap = new MindMap({
|
||||
theme: 'Theme name'
|
||||
})
|
||||
|
||||
// 2.动态切换新主题
|
||||
mindMap.setTheme('Theme name')
|
||||
```
|
||||
|
||||
For all configurations of theme, please refer to [Default Topic](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js). The `defineTheme`method will merge the configuration you passed in with the default configuration. Most of the themes do not need custom many parts. For a typical customized theme configuration, please refer to [blueSky](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js).
|
||||
|
||||
### usePlugin(plugin)
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
If you need to use some non-core functions, such as mini map, watermark, etc, you can register plugin through this method. Can be called in chain.
|
||||
|
||||
Note: The plugin needs to be registered before instantiating `MindMap`.
|
||||
|
||||
## Static props
|
||||
|
||||
### pluginList
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
List of all currently registered plugins.
|
||||
|
||||
|
||||
|
||||
## Instance methods
|
||||
|
||||
### getSvgData()
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
Get the `svg` data and return an object. The detailed structure is as follows:
|
||||
|
||||
```js
|
||||
{
|
||||
svg, // Element, the overall svg element of the mind map graphics, including: svg (canvas container), g (actual mind map group)
|
||||
svgHTML, // String, svg string, i.e. html string, can be directly rendered to the small map container you prepared
|
||||
rect: // Object, position, size, etc. of mind map graphics before zoom
|
||||
origWidth, // Number, canvas width
|
||||
origHeight, // Number, canvas height
|
||||
scaleX, // Number, horizontal zoom value of mind map graphics
|
||||
scaleY, // Number, vertical zoom value of mind map graphics
|
||||
}
|
||||
```
|
||||
|
||||
### render(callback)
|
||||
|
||||
- `callback`: `v0.3.2+`, `Function`, Called when the re-rendering is complete
|
||||
|
||||
Triggers a full rendering, which will reuse nodes for better performance. If
|
||||
only the node positions have changed, this method can be called to `reRender`.
|
||||
|
||||
### reRender(callback)
|
||||
|
||||
- `callback`: `v0.3.2+`, `Function`, Called when the re-rendering is complete
|
||||
|
||||
Performs a full re-render, clearing the canvas and creating new nodes. This has
|
||||
poor performance and should be used sparingly.
|
||||
|
||||
### resize()
|
||||
|
||||
After the container size has changed, this method should be called to adjust.
|
||||
|
||||
### setMode(mode)
|
||||
|
||||
> v0.1.7+
|
||||
|
||||
Switches between readonly and edit mode.
|
||||
|
||||
`mode`:readonly、edit
|
||||
|
||||
### on(event, fn)
|
||||
|
||||
Listen to an event. Event list:
|
||||
|
||||
| Event Name | Description | Callback Parameters |
|
||||
| -------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------- |
|
||||
| data_change | Tree rendering data change, listen to this method to get the latest data | data (current tree rendering data) |
|
||||
| view_data_change(v0.1.1+) | View change data, such as when dragging or zooming | data (current view state data) |
|
||||
| back_forward | Forward or backward | activeHistoryIndex (current index in the history data array), length (current length of the history data array) |
|
||||
| draw_click | Canvas click event | e (event object) |
|
||||
| svg_mousedown | svg canvas mouse down event | e (event object) |
|
||||
| mousedown | el element mouse down event | e (event object), this (Event event class instance) |
|
||||
| mousemove | el element mouse move event | e (event object), this (Event event class instance) |
|
||||
| drag | If it is a drag event while holding down the left button | e (event object), this (Event event class instance) |
|
||||
| mouseup | el element mouse up event | e (event object), this (Event event class instance) |
|
||||
| mousewheel | Mouse scroll event | e (event object), dir (up or down scroll), this (Event event class instance) |
|
||||
| contextmenu | svg canvas right mouse button menu event | e (event object) |
|
||||
| node_click | Node click event | this (node instance), e (event object) |
|
||||
| node_mousedown | Node mouse down event | this (node instance), e (event object) |
|
||||
| node_mouseup | node mouseup event | this (node instance), e (event object) |
|
||||
| node_mouseup | Node mouseup event | this (node instance), e (event object) |
|
||||
| node_dblclick | Node double-click event | this (node instance), e (event object) |
|
||||
| node_contextmenu | Node right-click menu event | e (event object), this (node instance) |
|
||||
| before_node_active | Event before node activation | this (node instance), activeNodeList (current list of active nodes) |
|
||||
| node_active | Node activation event | this (node instance), activeNodeList (current list of active nodes) |
|
||||
| expand_btn_click | Node expand or collapse event | this (node instance) |
|
||||
| before_show_text_edit | Event before node text edit box opens | |
|
||||
| hide_text_edit | Node text edit box close event | textEditNode (text edit box DOM node), activeNodeList (current list of active nodes) |
|
||||
| scale | Zoom event | scale (zoom ratio) |
|
||||
| node_img_dblclick(v0.2.15+) | Node image double-click event | this (node instance), e (event object) |
|
||||
| node_tree_render_end(v0.2.16+) | Node tree render end event | |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
Trigger an event, which can be one of the events listed above or a custom event.
|
||||
|
||||
### off(event, fn)
|
||||
|
||||
Unbind an event.
|
||||
|
||||
### setTheme(theme)
|
||||
|
||||
Switches the theme. Available themes can be found in the options table above.
|
||||
|
||||
### getTheme()
|
||||
|
||||
Gets the current theme.
|
||||
|
||||
### setThemeConfig(config)
|
||||
|
||||
Sets the theme configuration. `config` is the same as the `themeConfig` option
|
||||
in the options table above.
|
||||
|
||||
### getCustomThemeConfig()
|
||||
|
||||
Gets the custom theme configuration.
|
||||
|
||||
### getThemeConfig(prop)
|
||||
|
||||
Gets the value of a specific theme configuration property.
|
||||
|
||||
### getConfig(*prop*)
|
||||
|
||||
> 0.2.24+
|
||||
|
||||
`prop`:Get the value of the specified configuration, and return the entire configuration if not passed
|
||||
|
||||
Get config, That is, `opt` of `new MindMap (opt)`
|
||||
|
||||
### updateConfig(*opt* = {})
|
||||
|
||||
> 0.2.24+
|
||||
|
||||
`opt`:Configuration to update
|
||||
|
||||
Update config,That is update `opt` of `new MindMap(opt)`,You can only update some data, such as:
|
||||
|
||||
```js
|
||||
mindMap.updateConfig({
|
||||
enableFreeDrag: true// 开启节点自由拖拽
|
||||
})
|
||||
```
|
||||
|
||||
This method only updates the configuration and has no other side effects, such as triggering canvas re-rendering
|
||||
|
||||
### getLayout()
|
||||
|
||||
Gets the current layout structure.
|
||||
|
||||
### setLayout(layout)
|
||||
|
||||
Sets the layout structure. Available values can be found in the `layout` field
|
||||
in the options table above.
|
||||
|
||||
### execCommand(name, ...args)
|
||||
|
||||
Executes a command, which will add a record to the history stack for undo or
|
||||
redo. All commands are as follows:
|
||||
|
||||
| Command name | Description | Parameters |
|
||||
| ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| SELECT_ALL | Select all | |
|
||||
| BACK | Go back a specified number of steps | step (the number of steps to go back, default is 1) |
|
||||
| FORWARD | Go forward a specified number of steps | step (the number of steps to go forward, default is 1) |
|
||||
| INSERT_NODE | Insert a sibling node, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective | |
|
||||
| INSERT_CHILD_NODE | Insert a child node, the active node will be the operation node | |
|
||||
| UP_NODE | Move node up, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the first node in the list will be invalid | |
|
||||
| DOWN_NODE | Move node down, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the last node in the list will be invalid | |
|
||||
| REMOVE_NODE | Remove node, the active node will be the operation node | |
|
||||
| PASTE_NODE | Paste node to a node, the active node will be the operation node | data (the node data to paste, usually obtained through the renderer.copyNode() and renderer.cutNode() methods) |
|
||||
| SET_NODE_STYLE | Modify node style | node (the node to set the style of), prop (style property), value (style property value), isActive (boolean, whether the style being set is for the active state) |
|
||||
| SET_NODE_ACTIVE | Set whether the node is active | node (the node to set), active (boolean, whether to activate) |
|
||||
| CLEAR_ACTIVE_NODE | Clear the active state of the currently active node(s), the active node will be the operation node | |
|
||||
| SET_NODE_EXPAND | Set whether the node is expanded | node (the node to set), expand (boolean, whether to expand) |
|
||||
| EXPAND_ALL | Expand all nodes | |
|
||||
| UNEXPAND_ALL | Collapse all nodes | |
|
||||
| UNEXPAND_TO_LEVEL (v0.2.8+) | Expand to a specified level | level (the level to expand to, 1, 2, 3...) |
|
||||
| SET_NODE_DATA | Update node data, that is, update the data in the data object of the node data object | node (the node to set), data (object, the data to update, e.g. `{expand: true}`) |
|
||||
| SET_NODE_TEXT | Set node text | node (the node to set), text (the new text for the node) |
|
||||
| SET_NODE_IMAGE | Set Node Image | node (node to set), imgData (object, image information, structured as: `{url, title, width, height}`, the width and height of the image must be passed) |
|
||||
| SET_NODE_ICON | Set Node Icon | node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js) file, icon name is type_name, such as ['priority_1']) |
|
||||
| SET_NODE_HYPERLINK | Set Node Hyperlink | node (node to set), link (hyperlink address), title (hyperlink name, optional) |
|
||||
| SET_NODE_NOTE | Set Node Note | node (node to set), note (note text) |
|
||||
| SET_NODE_TAG | Set Node Tag | node (node to set), tag (string array, built-in color information can be obtained in [https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js)) |
|
||||
| INSERT_AFTER (v0.1.5+) | Move Node to After Another Node | node (node to move), exist (target node) |
|
||||
| INSERT_BEFORE (v0.1.5+) | Move Node to Before Another Node | node (node to move), exist (target node) |
|
||||
| MOVE_NODE_TO (v0.1.5+) | Move a node as a child of another node | node (the node to move), toNode (the target node) |
|
||||
| ADD_GENERALIZATION (v0.2.0+) | Add a node summary | data (the data for the summary, in object format, all numerical fields of the node are supported, default is `{text: 'summary'}`) |
|
||||
| REMOVE_GENERALIZATION (v0.2.0+) | Remove a node summary | |
|
||||
| SET_NODE_CUSTOM_POSITION (v0.2.0+) | Set a custom position for a node | node (the node to set), left (custom x coordinate, default is undefined), top (custom y coordinate, default is undefined) |
|
||||
| RESET_LAYOUT (v0.2.0+) | Arrange layout with one click | |
|
||||
| SET_NODE_SHAPE (v0.2.4+) | Set the shape of a node | node (the node to set), shape (the shape, all shapes: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
||||
|
||||
### setData(data)
|
||||
|
||||
Dynamic setting of mind map data, pure node data
|
||||
|
||||
`data`: mind map structure data
|
||||
|
||||
### setFullData(_data_)
|
||||
|
||||
> v0.2.7+
|
||||
|
||||
Dynamic setting of mind map data, including node data, layout, theme, view
|
||||
|
||||
`data`: complete data, structure can refer to
|
||||
[exportFullData](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json)
|
||||
|
||||
### getData(withConfig)
|
||||
|
||||
> v0.2.9+
|
||||
|
||||
Gets mind map data
|
||||
|
||||
`withConfig`: `Boolean`, default is `false`, that is, the obtained data only
|
||||
includes the node tree, if `true` is passed, it will also include theme, layout,
|
||||
view, etc. data
|
||||
|
||||
### export(type, isDownload, fileName)
|
||||
|
||||
> You need to register the `Export` plugin first
|
||||
|
||||
Export
|
||||
|
||||
`type`: the type to be exported, optional values: png, svg, json, pdf (v0.2.1+),
|
||||
smm (essentially also json)
|
||||
|
||||
`isDownload`: whether to directly trigger download, Boolean value, default is
|
||||
`false`
|
||||
|
||||
`fileName`: (v0.1.6+) the name of the exported file, default is `思维导图` (mind
|
||||
map).
|
||||
|
||||
### toPos(x, y)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Convert the coordinates of the browser's visible window to coordinates relative
|
||||
to the canvas.
|
||||
656
web/src/pages/Doc/en/constructor/index.vue
Normal file
656
web/src/pages/Doc/en/constructor/index.vue
Normal file
@@ -0,0 +1,656 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Constructor</h1>
|
||||
<h2>Basic use</h2>
|
||||
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mindMapContainer"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>
|
||||
</code></pre>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map"</span>;
|
||||
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">el</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"mindMapContainer"</span>),
|
||||
<span class="hljs-attr">data</span>: {
|
||||
<span class="hljs-string">"data"</span>: {
|
||||
<span class="hljs-string">"text"</span>: <span class="hljs-string">"Root Node"</span>
|
||||
},
|
||||
<span class="hljs-string">"children"</span>: []
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
<h2>Instantiation options</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field Name</th>
|
||||
<th>Type</th>
|
||||
<th>Default Value</th>
|
||||
<th>Description</th>
|
||||
<th>Required</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>el</td>
|
||||
<td>Element</td>
|
||||
<td></td>
|
||||
<td>Container element, must be a DOM element</td>
|
||||
<td>Yes</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data</td>
|
||||
<td>Object</td>
|
||||
<td>{}</td>
|
||||
<td>Mind map data, refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>layout</td>
|
||||
<td>String</td>
|
||||
<td>logicalStructure</td>
|
||||
<td>Layout type, options: logicalStructure (logical structure diagram), mindMap (mind map), catalogOrganization (catalog organization diagram), organizationStructure (organization structure diagram)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>theme</td>
|
||||
<td>String</td>
|
||||
<td>default</td>
|
||||
<td>Theme, options: default, classic, minions, pinkGrape, mint, gold, vitalityOrange, greenLeaf, dark2, skyGreen, classic2, classic3, classic4 (v0.2.0+), classicGreen, classicBlue, blueSky, brainImpairedPink, dark, earthYellow, freshGreen, freshRed, romanticPurple</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>themeConfig</td>
|
||||
<td>Object</td>
|
||||
<td>{}</td>
|
||||
<td>Theme configuration, will be merged with the selected theme, available fields refer to: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scaleRatio</td>
|
||||
<td>Number</td>
|
||||
<td>0.1</td>
|
||||
<td>The incremental scaling ratio</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>maxTag</td>
|
||||
<td>Number</td>
|
||||
<td>5</td>
|
||||
<td>The maximum number of tags displayed in the node, any additional tags will be discarded</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>exportPadding</td>
|
||||
<td>Number</td>
|
||||
<td>20</td>
|
||||
<td>The padding for exporting images</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>imgTextMargin</td>
|
||||
<td>Number</td>
|
||||
<td>5</td>
|
||||
<td>The spacing between the image and text in the node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textContentMargin</td>
|
||||
<td>Number</td>
|
||||
<td>2</td>
|
||||
<td>The spacing between various text information in the node, such as the spacing between the icon and text</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>selectTranslateStep</td>
|
||||
<td>Number</td>
|
||||
<td>3</td>
|
||||
<td>The canvas offset when mouse moves to the edge during multi-select node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>selectTranslateLimit</td>
|
||||
<td>Number</td>
|
||||
<td>20</td>
|
||||
<td>The distance from the edge when the canvas begins to offset during multi-select node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customNoteContentShow(v0.1.6+)</td>
|
||||
<td>Object</td>
|
||||
<td>null</td>
|
||||
<td>Custom node note content display, object type, structure: {show: (noteContent, left, top) => {// your display node note logic }, hide: () => {// your hide node note logic }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>readonly(v0.1.7+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>Whether it is read-only mode</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>enableFreeDrag(v0.2.4+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>Enable node free drag</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>watermarkConfig(v0.2.4+)</td>
|
||||
<td>Object</td>
|
||||
<td></td>
|
||||
<td>Watermark config, Please refer to the table 【Watermark config】 below for detailed configuration</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textAutoWrapWidth(v0.3.4+)</td>
|
||||
<td>Number</td>
|
||||
<td>500</td>
|
||||
<td>Each line of text in the node will wrap automatically when it reaches the width</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Watermark config</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field Name</th>
|
||||
<th>Type</th>
|
||||
<th>Default Value</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>text</td>
|
||||
<td>String</td>
|
||||
<td>''</td>
|
||||
<td>Watermark text. If it is an empty string, the watermark will not be displayed</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lineSpacing</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>Spacing between watermark lines</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textSpacing</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>Spacing between watermarks in the same row</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>angle</td>
|
||||
<td>Number</td>
|
||||
<td>30</td>
|
||||
<td>Tilt angle of watermark, range: [0, 90]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textStyle</td>
|
||||
<td>Object</td>
|
||||
<td>{color: '#999', opacity: 0.5, fontSize: 14}</td>
|
||||
<td>Watermark text style</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Static methods</h2>
|
||||
<h3>defineTheme(name, config)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.23+</p>
|
||||
</blockquote>
|
||||
<p>Define new theme.</p>
|
||||
<p><code>name</code>:New theme name</p>
|
||||
<p><code>config</code>:New theme config</p>
|
||||
<p><code>Simple-mind-map </code> Built-in many themes. In addition, you can register new theme. It is recommended to register before instantiation, so that you can directly use the newly registered theme during instantiation. Use example:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-comment">// 注册新主题</span>
|
||||
MindMap.defineTheme(<span class="hljs-string">'Theme name'</span>, {})
|
||||
|
||||
<span class="hljs-comment">// 1.实例化时使用新注册的主题</span>
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">theme</span>: <span class="hljs-string">'Theme name'</span>
|
||||
})
|
||||
|
||||
<span class="hljs-comment">// 2.动态切换新主题</span>
|
||||
mindMap.setTheme(<span class="hljs-string">'Theme name'</span>)
|
||||
</code></pre>
|
||||
<p>For all configurations of theme, please refer to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">Default Topic</a>. The <code>defineTheme</code>method will merge the configuration you passed in with the default configuration. Most of the themes do not need custom many parts. For a typical customized theme configuration, please refer to <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js">blueSky</a>.</p>
|
||||
<h3>usePlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>If you need to use some non-core functions, such as mini map, watermark, etc, you can register plugin through this method. Can be called in chain.</p>
|
||||
<p>Note: The plugin needs to be registered before instantiating <code>MindMap</code>.</p>
|
||||
<h2>Static props</h2>
|
||||
<h3>pluginList</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>List of all currently registered plugins.</p>
|
||||
<h2>Instance methods</h2>
|
||||
<h3>getSvgData()</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>Get the <code>svg</code> data and return an object. The detailed structure is as follows:</p>
|
||||
<pre class="hljs"><code>{
|
||||
svg, <span class="hljs-comment">// Element, the overall svg element of the mind map graphics, including: svg (canvas container), g (actual mind map group)</span>
|
||||
svgHTML, <span class="hljs-comment">// String, svg string, i.e. html string, can be directly rendered to the small map container you prepared</span>
|
||||
<span class="hljs-attr">rect</span>: <span class="hljs-comment">// Object, position, size, etc. of mind map graphics before zoom</span>
|
||||
origWidth, <span class="hljs-comment">// Number, canvas width</span>
|
||||
origHeight, <span class="hljs-comment">// Number, canvas height</span>
|
||||
scaleX, <span class="hljs-comment">// Number, horizontal zoom value of mind map graphics</span>
|
||||
scaleY, <span class="hljs-comment">// Number, vertical zoom value of mind map graphics</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>render(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>: <code>v0.3.2+</code>, <code>Function</code>, Called when the re-rendering is complete</li>
|
||||
</ul>
|
||||
<p>Triggers a full rendering, which will reuse nodes for better performance. If
|
||||
only the node positions have changed, this method can be called to <code>reRender</code>.</p>
|
||||
<h3>reRender(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>: <code>v0.3.2+</code>, <code>Function</code>, Called when the re-rendering is complete</li>
|
||||
</ul>
|
||||
<p>Performs a full re-render, clearing the canvas and creating new nodes. This has
|
||||
poor performance and should be used sparingly.</p>
|
||||
<h3>resize()</h3>
|
||||
<p>After the container size has changed, this method should be called to adjust.</p>
|
||||
<h3>setMode(mode)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.7+</p>
|
||||
</blockquote>
|
||||
<p>Switches between readonly and edit mode.</p>
|
||||
<p><code>mode</code>:readonly、edit</p>
|
||||
<h3>on(event, fn)</h3>
|
||||
<p>Listen to an event. Event list:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Event Name</th>
|
||||
<th>Description</th>
|
||||
<th>Callback Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>data_change</td>
|
||||
<td>Tree rendering data change, listen to this method to get the latest data</td>
|
||||
<td>data (current tree rendering data)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>view_data_change(v0.1.1+)</td>
|
||||
<td>View change data, such as when dragging or zooming</td>
|
||||
<td>data (current view state data)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>back_forward</td>
|
||||
<td>Forward or backward</td>
|
||||
<td>activeHistoryIndex (current index in the history data array), length (current length of the history data array)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>draw_click</td>
|
||||
<td>Canvas click event</td>
|
||||
<td>e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>svg_mousedown</td>
|
||||
<td>svg canvas mouse down event</td>
|
||||
<td>e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousedown</td>
|
||||
<td>el element mouse down event</td>
|
||||
<td>e (event object), this (Event event class instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousemove</td>
|
||||
<td>el element mouse move event</td>
|
||||
<td>e (event object), this (Event event class instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>drag</td>
|
||||
<td>If it is a drag event while holding down the left button</td>
|
||||
<td>e (event object), this (Event event class instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mouseup</td>
|
||||
<td>el element mouse up event</td>
|
||||
<td>e (event object), this (Event event class instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheel</td>
|
||||
<td>Mouse scroll event</td>
|
||||
<td>e (event object), dir (up or down scroll), this (Event event class instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>contextmenu</td>
|
||||
<td>svg canvas right mouse button menu event</td>
|
||||
<td>e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_click</td>
|
||||
<td>Node click event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mousedown</td>
|
||||
<td>Node mouse down event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseup</td>
|
||||
<td>node mouseup event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseup</td>
|
||||
<td>Node mouseup event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dblclick</td>
|
||||
<td>Node double-click event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_contextmenu</td>
|
||||
<td>Node right-click menu event</td>
|
||||
<td>e (event object), this (node instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_node_active</td>
|
||||
<td>Event before node activation</td>
|
||||
<td>this (node instance), activeNodeList (current list of active nodes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_active</td>
|
||||
<td>Node activation event</td>
|
||||
<td>this (node instance), activeNodeList (current list of active nodes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>expand_btn_click</td>
|
||||
<td>Node expand or collapse event</td>
|
||||
<td>this (node instance)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_show_text_edit</td>
|
||||
<td>Event before node text edit box opens</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hide_text_edit</td>
|
||||
<td>Node text edit box close event</td>
|
||||
<td>textEditNode (text edit box DOM node), activeNodeList (current list of active nodes)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scale</td>
|
||||
<td>Zoom event</td>
|
||||
<td>scale (zoom ratio)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_img_dblclick(v0.2.15+)</td>
|
||||
<td>Node image double-click event</td>
|
||||
<td>this (node instance), e (event object)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_tree_render_end(v0.2.16+)</td>
|
||||
<td>Node tree render end event</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
<p>Trigger an event, which can be one of the events listed above or a custom event.</p>
|
||||
<h3>off(event, fn)</h3>
|
||||
<p>Unbind an event.</p>
|
||||
<h3>setTheme(theme)</h3>
|
||||
<p>Switches the theme. Available themes can be found in the options table above.</p>
|
||||
<h3>getTheme()</h3>
|
||||
<p>Gets the current theme.</p>
|
||||
<h3>setThemeConfig(config)</h3>
|
||||
<p>Sets the theme configuration. <code>config</code> is the same as the <code>themeConfig</code> option
|
||||
in the options table above.</p>
|
||||
<h3>getCustomThemeConfig()</h3>
|
||||
<p>Gets the custom theme configuration.</p>
|
||||
<h3>getThemeConfig(prop)</h3>
|
||||
<p>Gets the value of a specific theme configuration property.</p>
|
||||
<h3>getConfig(<em>prop</em>)</h3>
|
||||
<blockquote>
|
||||
<p>0.2.24+</p>
|
||||
</blockquote>
|
||||
<p><code>prop</code>:Get the value of the specified configuration, and return the entire configuration if not passed</p>
|
||||
<p>Get config, That is, <code>opt</code> of <code>new MindMap (opt)</code></p>
|
||||
<h3>updateConfig(<em>opt</em> = {})</h3>
|
||||
<blockquote>
|
||||
<p>0.2.24+</p>
|
||||
</blockquote>
|
||||
<p><code>opt</code>:Configuration to update</p>
|
||||
<p>Update config,That is update <code>opt</code> of <code>new MindMap(opt)</code>,You can only update some data, such as:</p>
|
||||
<pre class="hljs"><code>mindMap.updateConfig({
|
||||
<span class="hljs-attr">enableFreeDrag</span>: <span class="hljs-literal">true</span><span class="hljs-comment">// 开启节点自由拖拽</span>
|
||||
})
|
||||
</code></pre>
|
||||
<p>This method only updates the configuration and has no other side effects, such as triggering canvas re-rendering</p>
|
||||
<h3>getLayout()</h3>
|
||||
<p>Gets the current layout structure.</p>
|
||||
<h3>setLayout(layout)</h3>
|
||||
<p>Sets the layout structure. Available values can be found in the <code>layout</code> field
|
||||
in the options table above.</p>
|
||||
<h3>execCommand(name, ...args)</h3>
|
||||
<p>Executes a command, which will add a record to the history stack for undo or
|
||||
redo. All commands are as follows:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Command name</th>
|
||||
<th>Description</th>
|
||||
<th>Parameters</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>SELECT_ALL</td>
|
||||
<td>Select all</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BACK</td>
|
||||
<td>Go back a specified number of steps</td>
|
||||
<td>step (the number of steps to go back, default is 1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FORWARD</td>
|
||||
<td>Go forward a specified number of steps</td>
|
||||
<td>step (the number of steps to go forward, default is 1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_NODE</td>
|
||||
<td>Insert a sibling node, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_CHILD_NODE</td>
|
||||
<td>Insert a child node, the active node will be the operation node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UP_NODE</td>
|
||||
<td>Move node up, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the first node in the list will be invalid</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DOWN_NODE</td>
|
||||
<td>Move node down, the active node will be the operation node. If there are multiple active nodes, only the first one will be effective. Using this command on the root node or the last node in the list will be invalid</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>REMOVE_NODE</td>
|
||||
<td>Remove node, the active node will be the operation node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PASTE_NODE</td>
|
||||
<td>Paste node to a node, the active node will be the operation node</td>
|
||||
<td>data (the node data to paste, usually obtained through the renderer.copyNode() and renderer.cutNode() methods)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_STYLE</td>
|
||||
<td>Modify node style</td>
|
||||
<td>node (the node to set the style of), prop (style property), value (style property value), isActive (boolean, whether the style being set is for the active state)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_ACTIVE</td>
|
||||
<td>Set whether the node is active</td>
|
||||
<td>node (the node to set), active (boolean, whether to activate)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CLEAR_ACTIVE_NODE</td>
|
||||
<td>Clear the active state of the currently active node(s), the active node will be the operation node</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_EXPAND</td>
|
||||
<td>Set whether the node is expanded</td>
|
||||
<td>node (the node to set), expand (boolean, whether to expand)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EXPAND_ALL</td>
|
||||
<td>Expand all nodes</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UNEXPAND_ALL</td>
|
||||
<td>Collapse all nodes</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UNEXPAND_TO_LEVEL (v0.2.8+)</td>
|
||||
<td>Expand to a specified level</td>
|
||||
<td>level (the level to expand to, 1, 2, 3...)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_DATA</td>
|
||||
<td>Update node data, that is, update the data in the data object of the node data object</td>
|
||||
<td>node (the node to set), data (object, the data to update, e.g. <code>{expand: true}</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_TEXT</td>
|
||||
<td>Set node text</td>
|
||||
<td>node (the node to set), text (the new text for the node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_IMAGE</td>
|
||||
<td>Set Node Image</td>
|
||||
<td>node (node to set), imgData (object, image information, structured as: <code>{url, title, width, height}</code>, the width and height of the image must be passed)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_ICON</td>
|
||||
<td>Set Node Icon</td>
|
||||
<td>node (node to set), icons (array, predefined image names array, available icons can be obtained in the nodeIconList list in the <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js</a> file, icon name is type_name, such as ['priority_1'])</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_HYPERLINK</td>
|
||||
<td>Set Node Hyperlink</td>
|
||||
<td>node (node to set), link (hyperlink address), title (hyperlink name, optional)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_NOTE</td>
|
||||
<td>Set Node Note</td>
|
||||
<td>node (node to set), note (note text)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_TAG</td>
|
||||
<td>Set Node Tag</td>
|
||||
<td>node (node to set), tag (string array, built-in color information can be obtained in <a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js</a>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_AFTER (v0.1.5+)</td>
|
||||
<td>Move Node to After Another Node</td>
|
||||
<td>node (node to move), exist (target node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_BEFORE (v0.1.5+)</td>
|
||||
<td>Move Node to Before Another Node</td>
|
||||
<td>node (node to move), exist (target node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MOVE_NODE_TO (v0.1.5+)</td>
|
||||
<td>Move a node as a child of another node</td>
|
||||
<td>node (the node to move), toNode (the target node)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ADD_GENERALIZATION (v0.2.0+)</td>
|
||||
<td>Add a node summary</td>
|
||||
<td>data (the data for the summary, in object format, all numerical fields of the node are supported, default is <code>{text: 'summary'}</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>REMOVE_GENERALIZATION (v0.2.0+)</td>
|
||||
<td>Remove a node summary</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_CUSTOM_POSITION (v0.2.0+)</td>
|
||||
<td>Set a custom position for a node</td>
|
||||
<td>node (the node to set), left (custom x coordinate, default is undefined), top (custom y coordinate, default is undefined)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RESET_LAYOUT (v0.2.0+)</td>
|
||||
<td>Arrange layout with one click</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_SHAPE (v0.2.4+)</td>
|
||||
<td>Set the shape of a node</td>
|
||||
<td>node (the node to set), shape (the shape, all shapes: https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>setData(data)</h3>
|
||||
<p>Dynamic setting of mind map data, pure node data</p>
|
||||
<p><code>data</code>: mind map structure data</p>
|
||||
<h3>setFullData(<em>data</em>)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.7+</p>
|
||||
</blockquote>
|
||||
<p>Dynamic setting of mind map data, including node data, layout, theme, view</p>
|
||||
<p><code>data</code>: complete data, structure can refer to
|
||||
<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json">exportFullData</a></p>
|
||||
<h3>getData(withConfig)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.9+</p>
|
||||
</blockquote>
|
||||
<p>Gets mind map data</p>
|
||||
<p><code>withConfig</code>: <code>Boolean</code>, default is <code>false</code>, that is, the obtained data only
|
||||
includes the node tree, if <code>true</code> is passed, it will also include theme, layout,
|
||||
view, etc. data</p>
|
||||
<h3>export(type, isDownload, fileName)</h3>
|
||||
<blockquote>
|
||||
<p>You need to register the <code>Export</code> plugin first</p>
|
||||
</blockquote>
|
||||
<p>Export</p>
|
||||
<p><code>type</code>: the type to be exported, optional values: png, svg, json, pdf (v0.2.1+),
|
||||
smm (essentially also json)</p>
|
||||
<p><code>isDownload</code>: whether to directly trigger download, Boolean value, default is
|
||||
<code>false</code></p>
|
||||
<p><code>fileName</code>: (v0.1.6+) the name of the exported file, default is <code>思维导图</code> (mind
|
||||
map).</p>
|
||||
<h3>toPos(x, y)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Convert the coordinates of the browser's visible window to coordinates relative
|
||||
to the canvas.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
53
web/src/pages/Doc/en/doExport/index.md
Normal file
53
web/src/pages/Doc/en/doExport/index.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Export plugin
|
||||
|
||||
The `Export` plugin provides the export function.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Export from 'simple-mind-map/src/Export.js'
|
||||
|
||||
MindMap.usePlugin(Export)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.doExport`.
|
||||
|
||||
## Methods
|
||||
|
||||
### png()
|
||||
|
||||
Exports as `png`, an async method that returns image data, `data:url` data which
|
||||
can be downloaded or displayed.
|
||||
|
||||
### svg()
|
||||
|
||||
Exports as `svg`, an async method that returns `svg` data, `data:url` data which
|
||||
can be downloaded or displayed.
|
||||
|
||||
### getSvgData()
|
||||
|
||||
Gets `svg` data, an async method that returns an object:
|
||||
|
||||
```js
|
||||
{
|
||||
node; // svg object
|
||||
str; // svg string
|
||||
}
|
||||
```
|
||||
|
||||
### pdf(name)
|
||||
|
||||
> v0.2.1+
|
||||
|
||||
`name`:File name
|
||||
|
||||
Export as `pdf`
|
||||
|
||||
### json(name, withConfig)
|
||||
|
||||
`name`:It is temporarily useless, just pass an empty string
|
||||
|
||||
`withConfig``:Boolean`, default `true`, Whether the data contains configuration, otherwise it is pure mind map node data
|
||||
|
||||
Return `json` data, `data:url` type, you can download it yourself
|
||||
48
web/src/pages/Doc/en/doExport/index.vue
Normal file
48
web/src/pages/Doc/en/doExport/index.vue
Normal file
@@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Export plugin</h1>
|
||||
<p>The <code>Export</code> plugin provides the export function.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> Export <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/Export.js'</span>
|
||||
|
||||
MindMap.usePlugin(Export)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.doExport</code>.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>png()</h3>
|
||||
<p>Exports as <code>png</code>, an async method that returns image data, <code>data:url</code> data which
|
||||
can be downloaded or displayed.</p>
|
||||
<h3>svg()</h3>
|
||||
<p>Exports as <code>svg</code>, an async method that returns <code>svg</code> data, <code>data:url</code> data which
|
||||
can be downloaded or displayed.</p>
|
||||
<h3>getSvgData()</h3>
|
||||
<p>Gets <code>svg</code> data, an async method that returns an object:</p>
|
||||
<pre class="hljs"><code>{
|
||||
node; <span class="hljs-comment">// svg object</span>
|
||||
str; <span class="hljs-comment">// svg string</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>pdf(name)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.1+</p>
|
||||
</blockquote>
|
||||
<p><code>name</code>:File name</p>
|
||||
<p>Export as <code>pdf</code></p>
|
||||
<h3>json(name, withConfig)</h3>
|
||||
<p><code>name</code>:It is temporarily useless, just pass an empty string</p>
|
||||
<p><code>withConfig``:Boolean</code>, default <code>true</code>, Whether the data contains configuration, otherwise it is pure mind map node data</p>
|
||||
<p>Return <code>json</code> data, <code>data:url</code> type, you can download it yourself</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
21
web/src/pages/Doc/en/drag/index.md
Normal file
21
web/src/pages/Doc/en/drag/index.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Drag plugin
|
||||
|
||||
The `Drag` plugin provides the function of node dragging, including:
|
||||
|
||||
1.Drag the node to move and change its position in the node tree, That is, as a child node, sibling node, etc. of other nodes
|
||||
|
||||
2.Drag the node to the custom canvas location
|
||||
|
||||
Please refer to the [Instantiation Options](/mind-map/#/doc/zh/constructor) of the `MindMap` class for configuration.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Drag from 'simple-mind-map/src/Drag.js'
|
||||
|
||||
MindMap.usePlugin(Drag)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.drag`.
|
||||
|
||||
27
web/src/pages/Doc/en/drag/index.vue
Normal file
27
web/src/pages/Doc/en/drag/index.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Drag plugin</h1>
|
||||
<p>The <code>Drag</code> plugin provides the function of node dragging, including:</p>
|
||||
<p>1.Drag the node to move and change its position in the node tree, That is, as a child node, sibling node, etc. of other nodes</p>
|
||||
<p>2.Drag the node to the custom canvas location</p>
|
||||
<p>Please refer to the <a href="/mind-map/#/doc/zh/constructor">Instantiation Options</a> of the <code>MindMap</code> class for configuration.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> Drag <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/Drag.js'</span>
|
||||
|
||||
MindMap.usePlugin(Drag)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.drag</code>.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
81
web/src/pages/Doc/en/introduction/index.md
Normal file
81
web/src/pages/Doc/en/introduction/index.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Introduction
|
||||
|
||||
`simple-mind-map` is a simple and powerful web mind map library, not dependent on any specific framework.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] Plugin architecture. In addition to core functions, other functions are provided as plugins, which can be used as needed to reduce the overall volume
|
||||
- [x] Supports four types of structures: logical structure diagrams, mind maps,
|
||||
organizational structure diagrams, and directory organization diagrams
|
||||
- [x] Built-in multiple themes and allows for highly customized styles, and support register new themes
|
||||
- [x] Supports shortcuts
|
||||
- [x] Node content supports images, icons, hyperlinks, notes, tags, and
|
||||
summaries
|
||||
- [x] Supports forward and backward navigation
|
||||
- [x] Supports dragging and scaling
|
||||
- [x] Supports right-click and Ctrl + left-click to select multiple items
|
||||
- [x] Supports free dragging and dragging to adjust nodes
|
||||
- [x] Supports various node shapes
|
||||
- [x] Supports export to json, png, svg, pdf, and import from json, xmind
|
||||
- [x] Supports mini map、support watermark
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1.`simple-mind-map`
|
||||
|
||||
This is a mind map tool library that is framework-agnostic and can be used with
|
||||
frameworks such as Vue and React, or without a framework.
|
||||
|
||||
2.`web`
|
||||
|
||||
This is an online mind map built using the `simple-mind-map` library and based
|
||||
on `Vue2.x` and `ElementUI`. Features include:
|
||||
|
||||
- [x] Toolbar, which supports inserting and deleting nodes, and editing node
|
||||
images, icons, hyperlinks, notes, tags, and summaries
|
||||
- [x] Sidebar, with panels for basic style settings, node style settings,
|
||||
outline, theme selection, and structure selection
|
||||
- [x] Import and export functionality; data is saved in the browser's local
|
||||
storage by default, but it also supports creating, opening, and editing
|
||||
local files on the computer directly
|
||||
- [x] Right-click menu, which supports operations such as expanding, collapsing,
|
||||
and organizing layout
|
||||
- [x] Bottom bar, which supports node and word count statistics, switching
|
||||
between edit and read-only modes, zooming in and out, and switching to
|
||||
full screen, support mini map
|
||||
|
||||
Provide document page service.
|
||||
|
||||
3.`dist`
|
||||
|
||||
The folder containing the packaged resources for the `web` folder.
|
||||
|
||||
4.`docs`
|
||||
|
||||
Documentation, etc.
|
||||
|
||||
## Related Articles
|
||||
|
||||
[Technical Analysis of Web Mind Map Implementation (chi)](https://juejin.cn/post/6987711560521089061)
|
||||
|
||||
[Only a hundred lines of code are needed to add local file operation capability to your Web page. Are you sure not to try?](https://juejin.cn/post/7157681502506090510)
|
||||
|
||||
[When you press the direction key, how does the TV find the next focus](https://juejin.cn/post/7199666255883927612)
|
||||
|
||||
## Special Note
|
||||
|
||||
This project is rough and has not been thoroughly tested, its features are not
|
||||
yet fully developed, and there are some performance issues, especially when the number of nodes is large. It is only for
|
||||
learning and reference purposes and please use it carefully for actual projects.
|
||||
|
||||
The built-in themes and icons in the project come from:
|
||||
|
||||
[Baidu Mind Map](https://naotu.baidu.com/)
|
||||
|
||||
[Zhixi Mind Map](https://www.zhixi.com/)
|
||||
|
||||
Respect the copyright, and do not use the theme and icons directly for commercial projects.
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://opensource.org/licenses/MIT)
|
||||
74
web/src/pages/Doc/en/introduction/index.vue
Normal file
74
web/src/pages/Doc/en/introduction/index.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Introduction</h1>
|
||||
<p><code>simple-mind-map</code> is a simple and powerful web mind map library, not dependent on any specific framework.</p>
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox51" checked="true"><label for="checkbox51">Plugin architecture. In addition to core functions, other functions are provided as plugins, which can be used as needed to reduce the overall volume</label></li>
|
||||
<li><input type="checkbox" id="checkbox52" checked="true"><label for="checkbox52">Supports four types of structures: logical structure diagrams, mind maps,</label>
|
||||
organizational structure diagrams, and directory organization diagrams</li>
|
||||
<li><input type="checkbox" id="checkbox53" checked="true"><label for="checkbox53">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox54" checked="true"><label for="checkbox54">Supports shortcuts</label></li>
|
||||
<li><input type="checkbox" id="checkbox55" checked="true"><label for="checkbox55">Node content supports images, icons, hyperlinks, notes, tags, and</label>
|
||||
summaries</li>
|
||||
<li><input type="checkbox" id="checkbox56" checked="true"><label for="checkbox56">Supports forward and backward navigation</label></li>
|
||||
<li><input type="checkbox" id="checkbox57" checked="true"><label for="checkbox57">Supports dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox58" checked="true"><label for="checkbox58">Supports right-click and Ctrl + left-click to select multiple items</label></li>
|
||||
<li><input type="checkbox" id="checkbox59" checked="true"><label for="checkbox59">Supports free dragging and dragging to adjust nodes</label></li>
|
||||
<li><input type="checkbox" id="checkbox60" checked="true"><label for="checkbox60">Supports various node shapes</label></li>
|
||||
<li><input type="checkbox" id="checkbox61" checked="true"><label for="checkbox61">Supports export to json, png, svg, pdf, and import from json, xmind</label></li>
|
||||
<li><input type="checkbox" id="checkbox62" checked="true"><label for="checkbox62">Supports mini map、support watermark</label></li>
|
||||
</ul>
|
||||
<h2>Table of Contents</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
<p>This is a mind map tool library that is framework-agnostic and can be used with
|
||||
frameworks such as Vue and React, or without a framework.</p>
|
||||
<p>2.<code>web</code></p>
|
||||
<p>This is an online mind map built using the <code>simple-mind-map</code> library and based
|
||||
on <code>Vue2.x</code> and <code>ElementUI</code>. Features include:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox63" checked="true"><label for="checkbox63">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
images, icons, hyperlinks, notes, tags, and summaries</li>
|
||||
<li><input type="checkbox" id="checkbox64" checked="true"><label for="checkbox64">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
outline, theme selection, and structure selection</li>
|
||||
<li><input type="checkbox" id="checkbox65" checked="true"><label for="checkbox65">Import and export functionality; data is saved in the browser's local</label>
|
||||
storage by default, but it also supports creating, opening, and editing
|
||||
local files on the computer directly</li>
|
||||
<li><input type="checkbox" id="checkbox66" checked="true"><label for="checkbox66">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
and organizing layout</li>
|
||||
<li><input type="checkbox" id="checkbox67" checked="true"><label for="checkbox67">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
between edit and read-only modes, zooming in and out, and switching to
|
||||
full screen, support mini map</li>
|
||||
</ul>
|
||||
<p>Provide document page service.</p>
|
||||
<p>3.<code>dist</code></p>
|
||||
<p>The folder containing the packaged resources for the <code>web</code> folder.</p>
|
||||
<p>4.<code>docs</code></p>
|
||||
<p>Documentation, etc.</p>
|
||||
<h2>Related Articles</h2>
|
||||
<p><a href="https://juejin.cn/post/6987711560521089061">Technical Analysis of Web Mind Map Implementation (chi)</a></p>
|
||||
<p><a href="https://juejin.cn/post/7157681502506090510">Only a hundred lines of code are needed to add local file operation capability to your Web page. Are you sure not to try?</a></p>
|
||||
<p><a href="https://juejin.cn/post/7199666255883927612">When you press the direction key, how does the TV find the next focus</a></p>
|
||||
<h2>Special Note</h2>
|
||||
<p>This project is rough and has not been thoroughly tested, its features are not
|
||||
yet fully developed, and there are some performance issues, especially when the number of nodes is large. It is only for
|
||||
learning and reference purposes and please use it carefully for actual projects.</p>
|
||||
<p>The built-in themes and icons in the project come from:</p>
|
||||
<p><a href="https://naotu.baidu.com/">Baidu Mind Map</a></p>
|
||||
<p><a href="https://www.zhixi.com/">Zhixi Mind Map</a></p>
|
||||
<p>Respect the copyright, and do not use the theme and icons directly for commercial projects.</p>
|
||||
<h2>License</h2>
|
||||
<p><a href="https://opensource.org/licenses/MIT">MIT</a></p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
61
web/src/pages/Doc/en/keyCommand/index.md
Normal file
61
web/src/pages/Doc/en/keyCommand/index.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# KeyCommand instance
|
||||
|
||||
The `keyCommand` instance is responsible for adding and triggering shortcuts. It
|
||||
includes some built-in shortcuts and can also be added manually. The
|
||||
`mindMap.keyCommand` instance can be obtained through this.
|
||||
|
||||
## Methods
|
||||
|
||||
### addShortcut(key, fn)
|
||||
|
||||
Add a shortcut
|
||||
|
||||
`key`: Shortcut key, key values can be viewed at
|
||||
[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js)
|
||||
Example:
|
||||
|
||||
```js
|
||||
// Single key
|
||||
mindMap.keyCommand.addShortcut("Enter", () => {});
|
||||
// Or
|
||||
mindMap.keyCommand.addShortcut("Del|Backspace", () => {});
|
||||
// Combination key
|
||||
mindMap.keyCommand.addShortcut("Control+Enter", () => {});
|
||||
```
|
||||
|
||||
`fn`: Method to be executed
|
||||
|
||||
### removeShortcut(key, fn)
|
||||
|
||||
Remove a shortcut command, if `fn` is not specified, all callback methods for
|
||||
the shortcut will be removed
|
||||
|
||||
### getShortcutFn(key)
|
||||
|
||||
> v0.2.2+
|
||||
|
||||
Get the processing function for the specified shortcut
|
||||
|
||||
### pause()
|
||||
|
||||
> v0.2.2+
|
||||
|
||||
Pause all shortcut responses
|
||||
|
||||
### recovery()
|
||||
|
||||
> v0.2.2+
|
||||
|
||||
Restore shortcut responses
|
||||
|
||||
### save()
|
||||
|
||||
> v0.2.3+
|
||||
|
||||
Save the current registered shortcut data, then clear the shortcut data
|
||||
|
||||
### restore()
|
||||
|
||||
> v0.2.3+
|
||||
|
||||
Restore saved shortcut data, then clear the cache data
|
||||
61
web/src/pages/Doc/en/keyCommand/index.vue
Normal file
61
web/src/pages/Doc/en/keyCommand/index.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>KeyCommand instance</h1>
|
||||
<p>The <code>keyCommand</code> instance is responsible for adding and triggering shortcuts. It
|
||||
includes some built-in shortcuts and can also be added manually. The
|
||||
<code>mindMap.keyCommand</code> instance can be obtained through this.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>addShortcut(key, fn)</h3>
|
||||
<p>Add a shortcut</p>
|
||||
<p><code>key</code>: Shortcut key, key values can be viewed at
|
||||
<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/keyMap.js</a>
|
||||
Example:</p>
|
||||
<pre class="hljs"><code><span class="hljs-comment">// Single key</span>
|
||||
mindMap.keyCommand.addShortcut(<span class="hljs-string">"Enter"</span>, <span class="hljs-function">() =></span> {});
|
||||
<span class="hljs-comment">// Or</span>
|
||||
mindMap.keyCommand.addShortcut(<span class="hljs-string">"Del|Backspace"</span>, <span class="hljs-function">() =></span> {});
|
||||
<span class="hljs-comment">// Combination key</span>
|
||||
mindMap.keyCommand.addShortcut(<span class="hljs-string">"Control+Enter"</span>, <span class="hljs-function">() =></span> {});
|
||||
</code></pre>
|
||||
<p><code>fn</code>: Method to be executed</p>
|
||||
<h3>removeShortcut(key, fn)</h3>
|
||||
<p>Remove a shortcut command, if <code>fn</code> is not specified, all callback methods for
|
||||
the shortcut will be removed</p>
|
||||
<h3>getShortcutFn(key)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.2+</p>
|
||||
</blockquote>
|
||||
<p>Get the processing function for the specified shortcut</p>
|
||||
<h3>pause()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.2+</p>
|
||||
</blockquote>
|
||||
<p>Pause all shortcut responses</p>
|
||||
<h3>recovery()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.2+</p>
|
||||
</blockquote>
|
||||
<p>Restore shortcut responses</p>
|
||||
<h3>save()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.3+</p>
|
||||
</blockquote>
|
||||
<p>Save the current registered shortcut data, then clear the shortcut data</p>
|
||||
<h3>restore()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.3+</p>
|
||||
</blockquote>
|
||||
<p>Restore saved shortcut data, then clear the cache data</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
51
web/src/pages/Doc/en/keyboardNavigation/index.md
Normal file
51
web/src/pages/Doc/en/keyboardNavigation/index.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# KeyboardNavigation plugin
|
||||
|
||||
> v0.2.17+
|
||||
|
||||
`KeyboardNavigation` plugin provides keyboard navigation function, that is, when you press the direction key, it will automatically find the next node and activate it.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import KeyboardNavigation from 'simple-mind-map/src/KeyboardNavigation.js'
|
||||
|
||||
MindMap.usePlugin(KeyboardNavigation)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.keyboardNavigation`.
|
||||
|
||||
## Methods
|
||||
|
||||
### focus(dir)
|
||||
|
||||
`dir`:Which direction to find the next node,Optional value:`Left`、 `Up`、 `Right`、 `Down`
|
||||
|
||||
Focus on the next node
|
||||
|
||||
### getNodeRect(node)
|
||||
|
||||
`node`:Node
|
||||
|
||||
Get the location information of the node and return an object:
|
||||
|
||||
```js
|
||||
{
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom
|
||||
}
|
||||
```
|
||||
|
||||
### getDistance(node1Rect, node2Rect)
|
||||
|
||||
`node1Rect`、`node2Rect`:The location data of nodes can be obtained through the `getNodeRect(node)`
|
||||
|
||||
Get the distance between two nodes
|
||||
|
||||
### getCenter(nodeRect)
|
||||
|
||||
`nodeRect`:The location data of nodes can be obtained through the `getNodeRect(node)`
|
||||
|
||||
Get the center point of the node
|
||||
47
web/src/pages/Doc/en/keyboardNavigation/index.vue
Normal file
47
web/src/pages/Doc/en/keyboardNavigation/index.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>KeyboardNavigation plugin</h1>
|
||||
<blockquote>
|
||||
<p>v0.2.17+</p>
|
||||
</blockquote>
|
||||
<p><code>KeyboardNavigation</code> plugin provides keyboard navigation function, that is, when you press the direction key, it will automatically find the next node and activate it.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> KeyboardNavigation <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/KeyboardNavigation.js'</span>
|
||||
|
||||
MindMap.usePlugin(KeyboardNavigation)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.keyboardNavigation</code>.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>focus(dir)</h3>
|
||||
<p><code>dir</code>:Which direction to find the next node,Optional value:<code>Left</code>、 <code>Up</code>、 <code>Right</code>、 <code>Down</code></p>
|
||||
<p>Focus on the next node</p>
|
||||
<h3>getNodeRect(node)</h3>
|
||||
<p><code>node</code>:Node</p>
|
||||
<p>Get the location information of the node and return an object:</p>
|
||||
<pre class="hljs"><code>{
|
||||
left,
|
||||
top,
|
||||
right,
|
||||
bottom
|
||||
}
|
||||
</code></pre>
|
||||
<h3>getDistance(node1Rect, node2Rect)</h3>
|
||||
<p><code>node1Rect</code>、<code>node2Rect</code>:The location data of nodes can be obtained through the <code>getNodeRect(node)</code></p>
|
||||
<p>Get the distance between two nodes</p>
|
||||
<h3>getCenter(nodeRect)</h3>
|
||||
<p><code>nodeRect</code>:The location data of nodes can be obtained through the <code>getNodeRect(node)</code></p>
|
||||
<p>Get the center point of the node</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
95
web/src/pages/Doc/en/miniMap/index.md
Normal file
95
web/src/pages/Doc/en/miniMap/index.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# MiniMap plugin
|
||||
|
||||
> v0.2.11+
|
||||
|
||||
Used to help quickly develop a small map feature, the small map consists of two
|
||||
parts, one is the current canvas content, and the other is the viewport frame.
|
||||
When zoomed, moved, or there are too many elements, the canvas may only display
|
||||
part of the mind map content. The viewport frame can be used to view the current
|
||||
viewport location, and can be quickly positioned by dragging on the small map.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import MiniMap from 'simple-mind-map/src/MiniMap.js'
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.miniMap`.
|
||||
|
||||
## Methods
|
||||
|
||||
### calculationMiniMap(boxWidth, boxHeight)
|
||||
|
||||
"Calculate the rendering data for the small map, this function will call the
|
||||
`getMiniMap()` method, so using this function is sufficient.
|
||||
|
||||
`boxWidth`: the width of the small map container
|
||||
|
||||
`boxHeight`: the height of the small map container
|
||||
|
||||
Function return content:
|
||||
|
||||
```js
|
||||
{
|
||||
svgHTML, // small map html
|
||||
viewBoxStyle, // view box position information
|
||||
miniMapBoxScale, // view box zoom value
|
||||
miniMapBoxLeft, // view box left value
|
||||
miniMapBoxTop, // view box top value
|
||||
}
|
||||
```
|
||||
|
||||
Small map idea:
|
||||
|
||||
1.Prepare a container element `container`, position is not `static`
|
||||
|
||||
2.In `container`, create a small map container element `miniMapContainer`,
|
||||
absolute positioning
|
||||
|
||||
3.In `container`, create a view box element `viewBoxContainer`, absolute
|
||||
positioning, set border style, transition property (optional)
|
||||
|
||||
4.Listen for `data_change` and `view_data_change` events, and in this event call
|
||||
the `calculationMiniMap` method to get calculation data, then render `svgHTML`
|
||||
to the `miniMapContainer` element and set its style:
|
||||
|
||||
```js
|
||||
:style="{
|
||||
transform: `scale(${svgBoxScale})`,
|
||||
left: svgBoxLeft + 'px',
|
||||
top: svgBoxTop + 'px',
|
||||
}"
|
||||
```
|
||||
|
||||
5.Set the `viewBoxStyle` object as the style of the `viewBoxContainer` element
|
||||
|
||||
At this point, when the mind map on the canvas changes, the small map will also
|
||||
be updated in real time, and the view box element will reflect the position of
|
||||
the viewport on the mind map graph in real time
|
||||
|
||||
6.Listen for the `mousedown`, `mousemove`, and `mouseup` events of the
|
||||
`container` element, and call the three methods that will be introduced below to
|
||||
achieve the effect of the mind map on the canvas being dragged with the mouse
|
||||
|
||||
### onMousedown(e)
|
||||
|
||||
Small map mouse down event executes this function
|
||||
|
||||
`e`: event object
|
||||
|
||||
### onMousemove(e, sensitivityNum = 5)
|
||||
|
||||
This function is executed on the small map mouse move event.
|
||||
|
||||
`e`: event object
|
||||
|
||||
`sensitivityNum`: drag sensitivity, the higher the sensitivity, the greater the
|
||||
actual canvas dragging distance on the small map when dragging the same distance
|
||||
on the small map
|
||||
|
||||
### onMouseup()
|
||||
|
||||
This function is executed on the small map mouse release event.
|
||||
79
web/src/pages/Doc/en/miniMap/index.vue
Normal file
79
web/src/pages/Doc/en/miniMap/index.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>MiniMap plugin</h1>
|
||||
<blockquote>
|
||||
<p>v0.2.11+</p>
|
||||
</blockquote>
|
||||
<p>Used to help quickly develop a small map feature, the small map consists of two
|
||||
parts, one is the current canvas content, and the other is the viewport frame.
|
||||
When zoomed, moved, or there are too many elements, the canvas may only display
|
||||
part of the mind map content. The viewport frame can be used to view the current
|
||||
viewport location, and can be quickly positioned by dragging on the small map.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> MiniMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/MiniMap.js'</span>
|
||||
|
||||
MindMap.usePlugin(MiniMap)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.miniMap</code>.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>calculationMiniMap(boxWidth, boxHeight)</h3>
|
||||
<p>"Calculate the rendering data for the small map, this function will call the
|
||||
<code>getMiniMap()</code> method, so using this function is sufficient.</p>
|
||||
<p><code>boxWidth</code>: the width of the small map container</p>
|
||||
<p><code>boxHeight</code>: the height of the small map container</p>
|
||||
<p>Function return content:</p>
|
||||
<pre class="hljs"><code>{
|
||||
svgHTML, <span class="hljs-comment">// small map html</span>
|
||||
viewBoxStyle, <span class="hljs-comment">// view box position information</span>
|
||||
miniMapBoxScale, <span class="hljs-comment">// view box zoom value</span>
|
||||
miniMapBoxLeft, <span class="hljs-comment">// view box left value</span>
|
||||
miniMapBoxTop, <span class="hljs-comment">// view box top value</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Small map idea:</p>
|
||||
<p>1.Prepare a container element <code>container</code>, position is not <code>static</code></p>
|
||||
<p>2.In <code>container</code>, create a small map container element <code>miniMapContainer</code>,
|
||||
absolute positioning</p>
|
||||
<p>3.In <code>container</code>, create a view box element <code>viewBoxContainer</code>, absolute
|
||||
positioning, set border style, transition property (optional)</p>
|
||||
<p>4.Listen for <code>data_change</code> and <code>view_data_change</code> events, and in this event call
|
||||
the <code>calculationMiniMap</code> method to get calculation data, then render <code>svgHTML</code>
|
||||
to the <code>miniMapContainer</code> element and set its style:</p>
|
||||
<pre class="hljs"><code>:style=<span class="hljs-string">"{
|
||||
transform: `scale(${svgBoxScale})`,
|
||||
left: svgBoxLeft + 'px',
|
||||
top: svgBoxTop + 'px',
|
||||
}"</span>
|
||||
</code></pre>
|
||||
<p>5.Set the <code>viewBoxStyle</code> object as the style of the <code>viewBoxContainer</code> element</p>
|
||||
<p>At this point, when the mind map on the canvas changes, the small map will also
|
||||
be updated in real time, and the view box element will reflect the position of
|
||||
the viewport on the mind map graph in real time</p>
|
||||
<p>6.Listen for the <code>mousedown</code>, <code>mousemove</code>, and <code>mouseup</code> events of the
|
||||
<code>container</code> element, and call the three methods that will be introduced below to
|
||||
achieve the effect of the mind map on the canvas being dragged with the mouse</p>
|
||||
<h3>onMousedown(e)</h3>
|
||||
<p>Small map mouse down event executes this function</p>
|
||||
<p><code>e</code>: event object</p>
|
||||
<h3>onMousemove(e, sensitivityNum = 5)</h3>
|
||||
<p>This function is executed on the small map mouse move event.</p>
|
||||
<p><code>e</code>: event object</p>
|
||||
<p><code>sensitivityNum</code>: drag sensitivity, the higher the sensitivity, the greater the
|
||||
actual canvas dragging distance on the small map when dragging the same distance
|
||||
on the small map</p>
|
||||
<h3>onMouseup()</h3>
|
||||
<p>This function is executed on the small map mouse release event.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
236
web/src/pages/Doc/en/node/index.md
Normal file
236
web/src/pages/Doc/en/node/index.md
Normal file
@@ -0,0 +1,236 @@
|
||||
# Node instance
|
||||
|
||||
Each node will instantiate a `node` instance
|
||||
|
||||
## Property
|
||||
|
||||
### nodeData
|
||||
|
||||
The real data corresponding to this node
|
||||
|
||||
### uid
|
||||
|
||||
The unique identifier of this node
|
||||
|
||||
### isRoot
|
||||
|
||||
Whether it is the root node
|
||||
|
||||
### layerIndex
|
||||
|
||||
Node level
|
||||
|
||||
### width
|
||||
|
||||
Width of the node
|
||||
|
||||
### height
|
||||
|
||||
Height of the node
|
||||
|
||||
### left
|
||||
|
||||
`left` position of the node
|
||||
|
||||
### top
|
||||
|
||||
`top` position of the node
|
||||
|
||||
### parent
|
||||
|
||||
Parent node of the node
|
||||
|
||||
### children
|
||||
|
||||
List of child nodes of the node
|
||||
|
||||
### group
|
||||
|
||||
Node is the content container, `svg` object
|
||||
|
||||
### isDrag
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Whether the node is currently being dragged
|
||||
|
||||
## Methods
|
||||
|
||||
### addChildren(node)
|
||||
|
||||
Add a child node
|
||||
|
||||
### getSize()
|
||||
|
||||
Calculate the width and height of the node, return a boolean indicating whether
|
||||
the width and height have changed
|
||||
|
||||
### renderNode()
|
||||
|
||||
Render the node to the canvas, will remove the old content node and create a new
|
||||
one
|
||||
|
||||
### render()
|
||||
|
||||
Recursively render this node and all its child nodes. The first call will create
|
||||
the node content, subsequent calls will only update the node position. To
|
||||
re-render the content, set the `initRender` attribute to `true` first.
|
||||
|
||||
### remove()
|
||||
|
||||
Recursively delete this node and all its child nodes
|
||||
|
||||
### renderLine()
|
||||
|
||||
Re-render the line from this node to its child nodes
|
||||
|
||||
### removeLine()
|
||||
|
||||
Remove the line from this node to its child nodes
|
||||
|
||||
### renderExpandBtn()
|
||||
|
||||
Render the content of the expand/collapse button
|
||||
|
||||
### removeExpandBtn()
|
||||
|
||||
Remove the expand/collapse button
|
||||
|
||||
### getStyle(prop, root, isActive)
|
||||
|
||||
Get the final style value applied to this node
|
||||
|
||||
`prop`: the style property to get
|
||||
|
||||
`root`: whether it is the root node, default `false`
|
||||
|
||||
`isActive`: whether the value being fetched is the active state style value,
|
||||
default `false`
|
||||
|
||||
### setStyle(prop, value, isActive)
|
||||
|
||||
Modify a style of the node, a shortcut method for the `SET_NODE_STYLE` command
|
||||
|
||||
### getData(key)
|
||||
|
||||
Get the specified value in the `data` object of the node's real data `nodeData`,
|
||||
if `key` is not passed, return the `data` object
|
||||
|
||||
### setData(data)
|
||||
|
||||
Set the value of the specified key in the data object of the node's real data
|
||||
nodeData, `SET_NODE_DATA` command's shortcut method
|
||||
|
||||
### setText(text)
|
||||
|
||||
Setting the node text, a shortcut for the `SET_NODE_TEXT` command
|
||||
|
||||
### setImage(imgData)
|
||||
|
||||
Setting the node image, a shortcut for the `SET_NODE_IMAGE` command
|
||||
|
||||
### setIcon(icons)
|
||||
|
||||
Setting the node icon, a shortcut for the `SET_NODE_ICON` command
|
||||
|
||||
### setHyperlink(link, title)
|
||||
|
||||
Setting the node hyperlink, a shortcut for the `SET_NODE_HYPERLINK` command
|
||||
|
||||
### setNote(note)
|
||||
|
||||
Setting the node note, a shortcut for the `SET_NODE_NOTE` command
|
||||
|
||||
### setTag(tag)
|
||||
|
||||
Setting the node tag, a shortcut for the `SET_NODE_TAG` command"
|
||||
|
||||
### hide()
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Hide node and its sub-nodes
|
||||
|
||||
### show()
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Show node and its sub-nodes
|
||||
|
||||
### isParent(node)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Check if the current node is an ancestor of a certain node
|
||||
|
||||
### isBrother(node)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Check if the current node is a sibling of a certain node
|
||||
|
||||
### checkHasGeneralization()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Check if there is a summary
|
||||
|
||||
### hideGeneralization()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Hide summary node
|
||||
|
||||
### showGeneralization()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Show summary node
|
||||
|
||||
### updateGeneralization()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Update summary node
|
||||
|
||||
### hasCustomPosition()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Check if the node has custom data
|
||||
|
||||
### ancestorHasCustomPosition()
|
||||
|
||||
> v0.2.0+
|
||||
|
||||
Check if there is an ancestor node with custom position
|
||||
|
||||
### getShape()
|
||||
|
||||
> v0.2.4+
|
||||
|
||||
Get node shape
|
||||
|
||||
### setShape(shape)
|
||||
|
||||
> v0.2.4+
|
||||
|
||||
Set node shape, a shortcut method for the `SET_NODE_SHAPE` command
|
||||
|
||||
### getSelfStyle(prop)
|
||||
|
||||
> v0.2.5+
|
||||
|
||||
Get the node's own custom style
|
||||
|
||||
### getParentSelfStyle(prop)
|
||||
|
||||
> v0.2.5+
|
||||
|
||||
Get the custom style of the nearest ancestor node with its own custom style
|
||||
|
||||
### getSelfInhertStyle(prop)
|
||||
|
||||
> v0.2.5+
|
||||
|
||||
Get the node's own inheritable custom style
|
||||
169
web/src/pages/Doc/en/node/index.vue
Normal file
169
web/src/pages/Doc/en/node/index.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Node instance</h1>
|
||||
<p>Each node will instantiate a <code>node</code> instance</p>
|
||||
<h2>Property</h2>
|
||||
<h3>nodeData</h3>
|
||||
<p>The real data corresponding to this node</p>
|
||||
<h3>uid</h3>
|
||||
<p>The unique identifier of this node</p>
|
||||
<h3>isRoot</h3>
|
||||
<p>Whether it is the root node</p>
|
||||
<h3>layerIndex</h3>
|
||||
<p>Node level</p>
|
||||
<h3>width</h3>
|
||||
<p>Width of the node</p>
|
||||
<h3>height</h3>
|
||||
<p>Height of the node</p>
|
||||
<h3>left</h3>
|
||||
<p><code>left</code> position of the node</p>
|
||||
<h3>top</h3>
|
||||
<p><code>top</code> position of the node</p>
|
||||
<h3>parent</h3>
|
||||
<p>Parent node of the node</p>
|
||||
<h3>children</h3>
|
||||
<p>List of child nodes of the node</p>
|
||||
<h3>group</h3>
|
||||
<p>Node is the content container, <code>svg</code> object</p>
|
||||
<h3>isDrag</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Whether the node is currently being dragged</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>addChildren(node)</h3>
|
||||
<p>Add a child node</p>
|
||||
<h3>getSize()</h3>
|
||||
<p>Calculate the width and height of the node, return a boolean indicating whether
|
||||
the width and height have changed</p>
|
||||
<h3>renderNode()</h3>
|
||||
<p>Render the node to the canvas, will remove the old content node and create a new
|
||||
one</p>
|
||||
<h3>render()</h3>
|
||||
<p>Recursively render this node and all its child nodes. The first call will create
|
||||
the node content, subsequent calls will only update the node position. To
|
||||
re-render the content, set the <code>initRender</code> attribute to <code>true</code> first.</p>
|
||||
<h3>remove()</h3>
|
||||
<p>Recursively delete this node and all its child nodes</p>
|
||||
<h3>renderLine()</h3>
|
||||
<p>Re-render the line from this node to its child nodes</p>
|
||||
<h3>removeLine()</h3>
|
||||
<p>Remove the line from this node to its child nodes</p>
|
||||
<h3>renderExpandBtn()</h3>
|
||||
<p>Render the content of the expand/collapse button</p>
|
||||
<h3>removeExpandBtn()</h3>
|
||||
<p>Remove the expand/collapse button</p>
|
||||
<h3>getStyle(prop, root, isActive)</h3>
|
||||
<p>Get the final style value applied to this node</p>
|
||||
<p><code>prop</code>: the style property to get</p>
|
||||
<p><code>root</code>: whether it is the root node, default <code>false</code></p>
|
||||
<p><code>isActive</code>: whether the value being fetched is the active state style value,
|
||||
default <code>false</code></p>
|
||||
<h3>setStyle(prop, value, isActive)</h3>
|
||||
<p>Modify a style of the node, a shortcut method for the <code>SET_NODE_STYLE</code> command</p>
|
||||
<h3>getData(key)</h3>
|
||||
<p>Get the specified value in the <code>data</code> object of the node's real data <code>nodeData</code>,
|
||||
if <code>key</code> is not passed, return the <code>data</code> object</p>
|
||||
<h3>setData(data)</h3>
|
||||
<p>Set the value of the specified key in the data object of the node's real data
|
||||
nodeData, <code>SET_NODE_DATA</code> command's shortcut method</p>
|
||||
<h3>setText(text)</h3>
|
||||
<p>Setting the node text, a shortcut for the <code>SET_NODE_TEXT</code> command</p>
|
||||
<h3>setImage(imgData)</h3>
|
||||
<p>Setting the node image, a shortcut for the <code>SET_NODE_IMAGE</code> command</p>
|
||||
<h3>setIcon(icons)</h3>
|
||||
<p>Setting the node icon, a shortcut for the <code>SET_NODE_ICON</code> command</p>
|
||||
<h3>setHyperlink(link, title)</h3>
|
||||
<p>Setting the node hyperlink, a shortcut for the <code>SET_NODE_HYPERLINK</code> command</p>
|
||||
<h3>setNote(note)</h3>
|
||||
<p>Setting the node note, a shortcut for the <code>SET_NODE_NOTE</code> command</p>
|
||||
<h3>setTag(tag)</h3>
|
||||
<p>Setting the node tag, a shortcut for the <code>SET_NODE_TAG</code> command"</p>
|
||||
<h3>hide()</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Hide node and its sub-nodes</p>
|
||||
<h3>show()</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Show node and its sub-nodes</p>
|
||||
<h3>isParent(node)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Check if the current node is an ancestor of a certain node</p>
|
||||
<h3>isBrother(node)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Check if the current node is a sibling of a certain node</p>
|
||||
<h3>checkHasGeneralization()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Check if there is a summary</p>
|
||||
<h3>hideGeneralization()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Hide summary node</p>
|
||||
<h3>showGeneralization()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Show summary node</p>
|
||||
<h3>updateGeneralization()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Update summary node</p>
|
||||
<h3>hasCustomPosition()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Check if the node has custom data</p>
|
||||
<h3>ancestorHasCustomPosition()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.0+</p>
|
||||
</blockquote>
|
||||
<p>Check if there is an ancestor node with custom position</p>
|
||||
<h3>getShape()</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.4+</p>
|
||||
</blockquote>
|
||||
<p>Get node shape</p>
|
||||
<h3>setShape(shape)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.4+</p>
|
||||
</blockquote>
|
||||
<p>Set node shape, a shortcut method for the <code>SET_NODE_SHAPE</code> command</p>
|
||||
<h3>getSelfStyle(prop)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.5+</p>
|
||||
</blockquote>
|
||||
<p>Get the node's own custom style</p>
|
||||
<h3>getParentSelfStyle(prop)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.5+</p>
|
||||
</blockquote>
|
||||
<p>Get the custom style of the nearest ancestor node with its own custom style</p>
|
||||
<h3>getSelfInhertStyle(prop)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.5+</p>
|
||||
</blockquote>
|
||||
<p>Get the node's own inheritable custom style</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
94
web/src/pages/Doc/en/render/index.md
Normal file
94
web/src/pages/Doc/en/render/index.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Render instance
|
||||
|
||||
The `render` instance is responsible for the entire rendering process and can be
|
||||
accessed through `mindMap.renderer`.
|
||||
|
||||
## Properties
|
||||
|
||||
### activeNodeList
|
||||
|
||||
Gets the current list of active nodes
|
||||
|
||||
### root
|
||||
|
||||
Gets the root node of the node tree
|
||||
|
||||
## Methods
|
||||
|
||||
### clearActive()
|
||||
|
||||
Clears the currently active node
|
||||
|
||||
### clearAllActive()
|
||||
|
||||
Clears all currently active nodes and triggers the `node_active` event
|
||||
|
||||
### startTextEdit()
|
||||
|
||||
> v0.1.6+
|
||||
|
||||
If there is a text editing requirement, this method can be called to
|
||||
disable the enter key and delete key related shortcuts to prevent conflicts
|
||||
|
||||
### endTextEdit()
|
||||
|
||||
> v0.1.6+
|
||||
|
||||
End text editing, restore enter key and delete key related shortcuts
|
||||
|
||||
### addActiveNode(node)
|
||||
|
||||
Add a node to the active list
|
||||
|
||||
### removeActiveNode(node)
|
||||
|
||||
Remove a node from the active list
|
||||
|
||||
### findActiveNodeIndex(node)
|
||||
|
||||
Search for the index of a node in the active list
|
||||
|
||||
### getNodeIndex(node)
|
||||
|
||||
Get the position index of a node among its siblings
|
||||
|
||||
### removeOneNode(node)
|
||||
|
||||
Delete a specific node
|
||||
|
||||
### copyNode()
|
||||
|
||||
Copy a node, the active node is the node to be operated on, if there are
|
||||
multiple active nodes, only the first node will be operated on
|
||||
|
||||
### setNodeDataRender(node, data)
|
||||
|
||||
Set node `data`, i.e. the data in the data field, and will determine whether the
|
||||
node needs to be re-rendered based on whether the node size has changed, `data`
|
||||
is an object, e.g. `{text: 'I am new text'}`
|
||||
|
||||
### moveNodeTo(node, toNode)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Move a node as a child of another node
|
||||
|
||||
### insertBefore(node, exist)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Move a node in front of another node
|
||||
|
||||
### insertAfter(node, exist)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
Move a node behind another node
|
||||
|
||||
### moveNodeToCenter(node)
|
||||
|
||||
> v0.2.17+
|
||||
|
||||
Move a node to the center of the canvas.
|
||||
|
||||
Currently, if there is zoom, returning to the center will reset the zoom.
|
||||
77
web/src/pages/Doc/en/render/index.vue
Normal file
77
web/src/pages/Doc/en/render/index.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Render instance</h1>
|
||||
<p>The <code>render</code> instance is responsible for the entire rendering process and can be
|
||||
accessed through <code>mindMap.renderer</code>.</p>
|
||||
<h2>Properties</h2>
|
||||
<h3>activeNodeList</h3>
|
||||
<p>Gets the current list of active nodes</p>
|
||||
<h3>root</h3>
|
||||
<p>Gets the root node of the node tree</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>clearActive()</h3>
|
||||
<p>Clears the currently active node</p>
|
||||
<h3>clearAllActive()</h3>
|
||||
<p>Clears all currently active nodes and triggers the <code>node_active</code> event</p>
|
||||
<h3>startTextEdit()</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.6+</p>
|
||||
</blockquote>
|
||||
<p>If there is a text editing requirement, this method can be called to
|
||||
disable the enter key and delete key related shortcuts to prevent conflicts</p>
|
||||
<h3>endTextEdit()</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.6+</p>
|
||||
</blockquote>
|
||||
<p>End text editing, restore enter key and delete key related shortcuts</p>
|
||||
<h3>addActiveNode(node)</h3>
|
||||
<p>Add a node to the active list</p>
|
||||
<h3>removeActiveNode(node)</h3>
|
||||
<p>Remove a node from the active list</p>
|
||||
<h3>findActiveNodeIndex(node)</h3>
|
||||
<p>Search for the index of a node in the active list</p>
|
||||
<h3>getNodeIndex(node)</h3>
|
||||
<p>Get the position index of a node among its siblings</p>
|
||||
<h3>removeOneNode(node)</h3>
|
||||
<p>Delete a specific node</p>
|
||||
<h3>copyNode()</h3>
|
||||
<p>Copy a node, the active node is the node to be operated on, if there are
|
||||
multiple active nodes, only the first node will be operated on</p>
|
||||
<h3>setNodeDataRender(node, data)</h3>
|
||||
<p>Set node <code>data</code>, i.e. the data in the data field, and will determine whether the
|
||||
node needs to be re-rendered based on whether the node size has changed, <code>data</code>
|
||||
is an object, e.g. <code>{text: 'I am new text'}</code></p>
|
||||
<h3>moveNodeTo(node, toNode)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Move a node as a child of another node</p>
|
||||
<h3>insertBefore(node, exist)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Move a node in front of another node</p>
|
||||
<h3>insertAfter(node, exist)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>Move a node behind another node</p>
|
||||
<h3>moveNodeToCenter(node)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.17+</p>
|
||||
</blockquote>
|
||||
<p>Move a node to the center of the canvas.</p>
|
||||
<p>Currently, if there is zoom, returning to the center will reset the zoom.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
20
web/src/pages/Doc/en/select/index.md
Normal file
20
web/src/pages/Doc/en/select/index.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Select plugin
|
||||
|
||||
The `Select` plugin provides the function of right-clicking to select multiple nodes.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Select from 'simple-mind-map/src/Select.js'
|
||||
|
||||
MindMap.usePlugin(Select)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.select`.
|
||||
|
||||
## Method
|
||||
|
||||
### toPos(x, y)
|
||||
|
||||
Convert mouse position to position relative to the container `el`
|
||||
27
web/src/pages/Doc/en/select/index.vue
Normal file
27
web/src/pages/Doc/en/select/index.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Select plugin</h1>
|
||||
<p>The <code>Select</code> plugin provides the function of right-clicking to select multiple nodes.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> Select <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/Select.js'</span>
|
||||
|
||||
MindMap.usePlugin(Select)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.select</code>.</p>
|
||||
<h2>Method</h2>
|
||||
<h3>toPos(x, y)</h3>
|
||||
<p>Convert mouse position to position relative to the container <code>el</code></p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
135
web/src/pages/Doc/en/start/index.md
Normal file
135
web/src/pages/Doc/en/start/index.md
Normal file
@@ -0,0 +1,135 @@
|
||||
# Start
|
||||
|
||||
## Development
|
||||
|
||||
### Local Development
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
cd ..
|
||||
cd web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Packaging the Library
|
||||
|
||||
Since version `0.2.0`, we have added support for packaging the core library
|
||||
simple-mind-map. This uses the same packaging tool as the sample project web.
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run buildLibrary
|
||||
```
|
||||
|
||||
The `package.json` file in the `simple-mind-map` library provides two export
|
||||
fields:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": "index.js",
|
||||
"main": "./dist/simpleMindMap.umd.min.js"
|
||||
}
|
||||
```
|
||||
|
||||
Environments that support the `module` field will use `index.js` as the entry
|
||||
point, otherwise the packed `simpleMindMap.umd.min.js` will be used as the entry
|
||||
point.
|
||||
|
||||
### Compile the doc
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run buildDoc
|
||||
```
|
||||
|
||||
### Packaging the Demo
|
||||
|
||||
```bash
|
||||
cd web
|
||||
npm run build
|
||||
```
|
||||
|
||||
The `index.html` file will be automatically moved to the root directory.
|
||||
|
||||
## Installation
|
||||
|
||||
> Things to note before version 0.2.0:
|
||||
|
||||
```bash
|
||||
npm i simple-mind-map
|
||||
```
|
||||
|
||||
`0.2.0` Notes for previous versions:
|
||||
|
||||
> Note: This project is directly published in source code form and has not been
|
||||
> packaged. If compilation fails, a Vue CLI-created project can add the
|
||||
> following configuration to the vue.config.js file to allow babel-loader to
|
||||
> compile this dependency:
|
||||
>
|
||||
> ```js
|
||||
> module.exports = {
|
||||
> transpileDependencies: ["simple-mind-map"],
|
||||
> };
|
||||
> ```
|
||||
>
|
||||
> Other projects should modify the packaging configuration as needed.
|
||||
|
||||
## Usage
|
||||
|
||||
```html
|
||||
<div id="mindMapContainer"></div>
|
||||
```
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map";
|
||||
|
||||
const mindMap = new MindMap({
|
||||
el: document.getElementById('mindMapContainer'),
|
||||
data: {
|
||||
"data": {
|
||||
"text": "Root Node"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
The non-packaged 'ES' module is introduced by default, and only contains core functions, not unregistered plugin content, which can effectively reduce the size. However, you need to configure the `babel` compilation `simple mind-map` in your project to prevent some newer `js` syntax some browsers not supporting it.
|
||||
|
||||
If you need a file in the format of `umd` module, such as `CDN` in the browser, you can import it in the following way:
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map/dist/simpleMindMap.umd.min.js";
|
||||
```
|
||||
|
||||
The disadvantage of this method is that it will contain all the content, including the plugins you have not registered, so the overall volume will be relatively large.
|
||||
|
||||
## Problems
|
||||
|
||||
### Error when using in Vite, indicating xml-js dependency error
|
||||
|
||||
Solution: use the following import method:
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map/dist/simpleMindMap.umd.min";
|
||||
```
|
||||
|
||||
The `simple-mind-map` package provides the unpacked entry field `module`, and
|
||||
the `xml-js` package dependency needs to import the package in the `node`
|
||||
environment. Therefore, it cannot be obtained in `Vite` and an error will be
|
||||
reported. Therefore, specify the import of the packed entry, and all relevant
|
||||
packages are packed into the product, so there will be no error.
|
||||
|
||||
If you need to do further development, that is, you must use the unpacked code,
|
||||
and if you do not need to parse the `xmind` file, you can remove the `xmind`
|
||||
module. If you need it, you can try using other libraries to parse `xml` to
|
||||
`json`.
|
||||
|
||||
### Error `Getting bbox of element "text" is not possible: TypeError: Cannot read properties of undefined (reading 'apply')`
|
||||
|
||||
The reason is that the installed version of `@svgdotjs/svg.js` is too high. You can manually reduce it to the version of `3.0.16`.
|
||||
107
web/src/pages/Doc/en/start/index.vue
Normal file
107
web/src/pages/Doc/en/start/index.vue
Normal file
@@ -0,0 +1,107 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Start</h1>
|
||||
<h2>Development</h2>
|
||||
<h3>Local Development</h3>
|
||||
<pre class="hljs"><code>git <span class="hljs-built_in">clone</span> https://github.com/wanglin2/mind-map.git
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
<span class="hljs-built_in">cd</span> ..
|
||||
<span class="hljs-built_in">cd</span> web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
npm run serve
|
||||
</code></pre>
|
||||
<h3>Packaging the Library</h3>
|
||||
<p>Since version <code>0.2.0</code>, we have added support for packaging the core library
|
||||
simple-mind-map. This uses the same packaging tool as the sample project web.</p>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run buildLibrary
|
||||
</code></pre>
|
||||
<p>The <code>package.json</code> file in the <code>simple-mind-map</code> library provides two export
|
||||
fields:</p>
|
||||
<pre class="hljs"><code>{
|
||||
<span class="hljs-attr">"module"</span>: <span class="hljs-string">"index.js"</span>,
|
||||
<span class="hljs-attr">"main"</span>: <span class="hljs-string">"./dist/simpleMindMap.umd.min.js"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>Environments that support the <code>module</code> field will use <code>index.js</code> as the entry
|
||||
point, otherwise the packed <code>simpleMindMap.umd.min.js</code> will be used as the entry
|
||||
point.</p>
|
||||
<h3>Compile the doc</h3>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run buildDoc
|
||||
</code></pre>
|
||||
<h3>Packaging the Demo</h3>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">cd</span> web
|
||||
npm run build
|
||||
</code></pre>
|
||||
<p>The <code>index.html</code> file will be automatically moved to the root directory.</p>
|
||||
<h2>Installation</h2>
|
||||
<blockquote>
|
||||
<p>Things to note before version 0.2.0:</p>
|
||||
</blockquote>
|
||||
<pre class="hljs"><code>npm i simple-mind-map
|
||||
</code></pre>
|
||||
<p><code>0.2.0</code> Notes for previous versions:</p>
|
||||
<blockquote>
|
||||
<p>Note: This project is directly published in source code form and has not been
|
||||
packaged. If compilation fails, a Vue CLI-created project can add the
|
||||
following configuration to the vue.config.js file to allow babel-loader to
|
||||
compile this dependency:</p>
|
||||
<pre class="hljs"><code><span class="hljs-built_in">module</span>.exports = {
|
||||
<span class="hljs-attr">transpileDependencies</span>: [<span class="hljs-string">"simple-mind-map"</span>],
|
||||
};
|
||||
</code></pre>
|
||||
<p>Other projects should modify the packaging configuration as needed.</p>
|
||||
</blockquote>
|
||||
<h2>Usage</h2>
|
||||
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mindMapContainer"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>
|
||||
</code></pre>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map"</span>;
|
||||
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">el</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'mindMapContainer'</span>),
|
||||
<span class="hljs-attr">data</span>: {
|
||||
<span class="hljs-string">"data"</span>: {
|
||||
<span class="hljs-string">"text"</span>: <span class="hljs-string">"Root Node"</span>
|
||||
},
|
||||
<span class="hljs-string">"children"</span>: []
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
<p>The non-packaged 'ES' module is introduced by default, and only contains core functions, not unregistered plugin content, which can effectively reduce the size. However, you need to configure the <code>babel</code> compilation <code>simple mind-map</code> in your project to prevent some newer <code>js</code> syntax some browsers not supporting it.</p>
|
||||
<p>If you need a file in the format of <code>umd</code> module, such as <code>CDN</code> in the browser, you can import it in the following way:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map/dist/simpleMindMap.umd.min.js"</span>;
|
||||
</code></pre>
|
||||
<p>The disadvantage of this method is that it will contain all the content, including the plugins you have not registered, so the overall volume will be relatively large.</p>
|
||||
<h2>Problems</h2>
|
||||
<h3>Error when using in Vite, indicating xml-js dependency error</h3>
|
||||
<p>Solution: use the following import method:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map/dist/simpleMindMap.umd.min"</span>;
|
||||
</code></pre>
|
||||
<p>The <code>simple-mind-map</code> package provides the unpacked entry field <code>module</code>, and
|
||||
the <code>xml-js</code> package dependency needs to import the package in the <code>node</code>
|
||||
environment. Therefore, it cannot be obtained in <code>Vite</code> and an error will be
|
||||
reported. Therefore, specify the import of the packed entry, and all relevant
|
||||
packages are packed into the product, so there will be no error.</p>
|
||||
<p>If you need to do further development, that is, you must use the unpacked code,
|
||||
and if you do not need to parse the <code>xmind</code> file, you can remove the <code>xmind</code>
|
||||
module. If you need it, you can try using other libraries to parse <code>xml</code> to
|
||||
<code>json</code>.</p>
|
||||
<h3>Error <code>Getting bbox of element "text" is not possible: TypeError: Cannot read properties of undefined (reading 'apply')</code></h3>
|
||||
<p>The reason is that the installed version of <code>@svgdotjs/svg.js</code> is too high. You can manually reduce it to the version of <code>3.0.16</code>.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
18
web/src/pages/Doc/en/translate/index.md
Normal file
18
web/src/pages/Doc/en/translate/index.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Participate in translation
|
||||
|
||||
Thanks for the English translation provided by [Emircan ERKUL](https://github.com/emircanerkul).
|
||||
|
||||
If you want to participate in the translation of this document, you can clone this repository first.
|
||||
|
||||
The translated documents are in the `/web/src/pages/Doc/` directory, and currently support English(`en`) and Simplified Chinese(`zh`).
|
||||
|
||||
If you are adding a new language type, you can create a new directory under the `/web/src/pages/Doc/` directory, Then create a folder for each chapter, You can also directly copy all chapter directories under the existing language directory for translation, Note that you only need to write the `index.md` file, The `index.vue` file under the chapter directory is automatically generated by the script according to `index.md`.
|
||||
|
||||
If you are adding a translation chapter to an existing language type, You can create a new chapter directory under the target language directory, You only need to create a `index.md` file under the directory.
|
||||
|
||||
After you complete the translation, you can directly submit `Pull requests`.
|
||||
|
||||
If you are a front-end programmer and want to run the service, check the effect of the document page, If a new chapter is added, the file `/web/src/pages/Doc/catalogList.js` needs to be modified, Select the appropriate location in the `StartList` or `APIList` array to insert the `path` of the new chapter. Then you need to run `npm run buildDoc` under the `web` directory to compile the directory and route. Finally, run `npm run serve` starts the local service. Open the following path to view the document:
|
||||
|
||||
`ip:port/#/doc/zh/introduction`
|
||||
|
||||
24
web/src/pages/Doc/en/translate/index.vue
Normal file
24
web/src/pages/Doc/en/translate/index.vue
Normal file
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Participate in translation</h1>
|
||||
<p>Thanks for the English translation provided by <a href="https://github.com/emircanerkul">Emircan ERKUL</a>.</p>
|
||||
<p>If you want to participate in the translation of this document, you can clone this repository first.</p>
|
||||
<p>The translated documents are in the <code>/web/src/pages/Doc/</code> directory, and currently support English(<code>en</code>) and Simplified Chinese(<code>zh</code>).</p>
|
||||
<p>If you are adding a new language type, you can create a new directory under the <code>/web/src/pages/Doc/</code> directory, Then create a folder for each chapter, You can also directly copy all chapter directories under the existing language directory for translation, Note that you only need to write the <code>index.md</code> file, The <code>index.vue</code> file under the chapter directory is automatically generated by the script according to <code>index.md</code>.</p>
|
||||
<p>If you are adding a translation chapter to an existing language type, You can create a new chapter directory under the target language directory, You only need to create a <code>index.md</code> file under the directory.</p>
|
||||
<p>After you complete the translation, you can directly submit <code>Pull requests</code>.</p>
|
||||
<p>If you are a front-end programmer and want to run the service, check the effect of the document page, If a new chapter is added, the file <code>/web/src/pages/Doc/catalogList.js</code> needs to be modified, Select the appropriate location in the <code>StartList</code> or <code>APIList</code> array to insert the <code>path</code> of the new chapter. Then you need to run <code>npm run buildDoc</code> under the <code>web</code> directory to compile the directory and route. Finally, run <code>npm run serve</code> starts the local service. Open the following path to view the document:</p>
|
||||
<p><code>ip:port/#/doc/zh/introduction</code></p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
156
web/src/pages/Doc/en/utils/index.md
Normal file
156
web/src/pages/Doc/en/utils/index.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# Utility Methods
|
||||
|
||||
## Base utility Methods
|
||||
|
||||
Reference:
|
||||
|
||||
```js
|
||||
import {walk, ...} from 'simple-mind-map/src/utils'
|
||||
```
|
||||
|
||||
### Methods
|
||||
|
||||
#### walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)
|
||||
|
||||
Depth-first traversal of a tree
|
||||
|
||||
`root`: the root node of the tree to be traversed
|
||||
|
||||
`parent`: parent node
|
||||
|
||||
`beforeCallback`: preorder traversal callback function, callback parameters are:
|
||||
root, parent, isRoot, layerIndex, index
|
||||
|
||||
`afterCallback`: postorder traversal callback function, callback parameters are:
|
||||
root, parent, isRoot, layerIndex, index
|
||||
|
||||
`isRoot`: whether it is the root node
|
||||
|
||||
`layerIndex`: node level
|
||||
|
||||
`index`: index of the node among its siblings
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
walk(tree, null, () => {}, () => {}, false, 0, 0);
|
||||
```
|
||||
|
||||
#### bfsWalk(root, callback)
|
||||
|
||||
Breadth-first traversal of a tree
|
||||
|
||||
#### resizeImgSize(width, height, maxWidth, maxHeight)
|
||||
|
||||
Resize image size
|
||||
|
||||
`width`: original width of the image
|
||||
|
||||
`height`: original height of the image
|
||||
|
||||
`maxWidth`: the width to resize to
|
||||
|
||||
`maxHeight`: the height to resize to
|
||||
|
||||
`maxWidth` and `maxHeight` can both be passed, or only one of them can be passed
|
||||
|
||||
#### resizeImg(imgUrl, maxWidth, maxHeight)
|
||||
|
||||
Resize image, internally loads the image first, then calls the `resizeImgSize`
|
||||
method, and returns a `promise`
|
||||
|
||||
#### simpleDeepClone(data)
|
||||
|
||||
Extremely simple deep copy method, can only be used for objects that are all
|
||||
basic data, otherwise it will throw an error
|
||||
|
||||
#### copyRenderTree(tree, root)
|
||||
|
||||
Copy render tree data, example:
|
||||
|
||||
```js
|
||||
copyRenderTree({}, this.mindMap.renderer.renderTree);
|
||||
```
|
||||
|
||||
#### copyNodeTree(tree, root)
|
||||
|
||||
Copy node tree data, mainly eliminating the reference `node` instance `_node`
|
||||
and copying the `data` of the data object, example:
|
||||
|
||||
```js
|
||||
copyNodeTree({}, node);
|
||||
```
|
||||
|
||||
#### imgToDataUrl(src)
|
||||
|
||||
Convert image to dataURL
|
||||
|
||||
#### downloadFile(file, fileName)
|
||||
|
||||
Download file
|
||||
|
||||
#### throttle(fn, time = 300, ctx)
|
||||
|
||||
Throttle function
|
||||
|
||||
#### asyncRun(taskList, callback = () => {})
|
||||
|
||||
Run tasks in task list asynchronously, tasks are run synchronously without order
|
||||
|
||||
#### degToRad(deg)
|
||||
|
||||
> v0.2.24+
|
||||
|
||||
Angle to radian
|
||||
|
||||
#### camelCaseToHyphen(str)
|
||||
|
||||
> v0.2.24+
|
||||
|
||||
CamelCase to hyphen
|
||||
|
||||
#### joinFontStr({ italic, bold, fontSize, fontFamily })
|
||||
|
||||
> v0.3.4+
|
||||
|
||||
Join the `font` attribute value of the `css` font
|
||||
|
||||
#### measureText(text, { italic, bold, fontSize, fontFamily })
|
||||
|
||||
> v0.3.4+
|
||||
|
||||
Measure the width and height of the text, return value:
|
||||
|
||||
```js
|
||||
{ width, height }
|
||||
```
|
||||
|
||||
## Simulate CSS background in Canvas
|
||||
|
||||
Import:
|
||||
|
||||
```js
|
||||
import drawBackgroundImageToCanvas from 'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```js
|
||||
let width = 500
|
||||
let height = 500
|
||||
let img = '/1.jpg'
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
backgroundRepeat: 'repeat-y',
|
||||
backgroundSize: '60%',
|
||||
backgroundPosition: 'center center'
|
||||
}, (err) => {
|
||||
if (err) {
|
||||
// fail
|
||||
} else {
|
||||
// success
|
||||
}
|
||||
})
|
||||
```
|
||||
112
web/src/pages/Doc/en/utils/index.vue
Normal file
112
web/src/pages/Doc/en/utils/index.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Utility Methods</h1>
|
||||
<h2>Base utility Methods</h2>
|
||||
<p>Reference:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> {walk, ...} <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils'</span>
|
||||
</code></pre>
|
||||
<h3>Methods</h3>
|
||||
<h4>walk(root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0)</h4>
|
||||
<p>Depth-first traversal of a tree</p>
|
||||
<p><code>root</code>: the root node of the tree to be traversed</p>
|
||||
<p><code>parent</code>: parent node</p>
|
||||
<p><code>beforeCallback</code>: preorder traversal callback function, callback parameters are:
|
||||
root, parent, isRoot, layerIndex, index</p>
|
||||
<p><code>afterCallback</code>: postorder traversal callback function, callback parameters are:
|
||||
root, parent, isRoot, layerIndex, index</p>
|
||||
<p><code>isRoot</code>: whether it is the root node</p>
|
||||
<p><code>layerIndex</code>: node level</p>
|
||||
<p><code>index</code>: index of the node among its siblings</p>
|
||||
<p>Example:</p>
|
||||
<pre class="hljs"><code>walk(tree, <span class="hljs-literal">null</span>, <span class="hljs-function">() =></span> {}, <span class="hljs-function">() =></span> {}, <span class="hljs-literal">false</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
|
||||
</code></pre>
|
||||
<h4>bfsWalk(root, callback)</h4>
|
||||
<p>Breadth-first traversal of a tree</p>
|
||||
<h4>resizeImgSize(width, height, maxWidth, maxHeight)</h4>
|
||||
<p>Resize image size</p>
|
||||
<p><code>width</code>: original width of the image</p>
|
||||
<p><code>height</code>: original height of the image</p>
|
||||
<p><code>maxWidth</code>: the width to resize to</p>
|
||||
<p><code>maxHeight</code>: the height to resize to</p>
|
||||
<p><code>maxWidth</code> and <code>maxHeight</code> can both be passed, or only one of them can be passed</p>
|
||||
<h4>resizeImg(imgUrl, maxWidth, maxHeight)</h4>
|
||||
<p>Resize image, internally loads the image first, then calls the <code>resizeImgSize</code>
|
||||
method, and returns a <code>promise</code></p>
|
||||
<h4>simpleDeepClone(data)</h4>
|
||||
<p>Extremely simple deep copy method, can only be used for objects that are all
|
||||
basic data, otherwise it will throw an error</p>
|
||||
<h4>copyRenderTree(tree, root)</h4>
|
||||
<p>Copy render tree data, example:</p>
|
||||
<pre class="hljs"><code>copyRenderTree({}, <span class="hljs-built_in">this</span>.mindMap.renderer.renderTree);
|
||||
</code></pre>
|
||||
<h4>copyNodeTree(tree, root)</h4>
|
||||
<p>Copy node tree data, mainly eliminating the reference <code>node</code> instance <code>_node</code>
|
||||
and copying the <code>data</code> of the data object, example:</p>
|
||||
<pre class="hljs"><code>copyNodeTree({}, node);
|
||||
</code></pre>
|
||||
<h4>imgToDataUrl(src)</h4>
|
||||
<p>Convert image to dataURL</p>
|
||||
<h4>downloadFile(file, fileName)</h4>
|
||||
<p>Download file</p>
|
||||
<h4>throttle(fn, time = 300, ctx)</h4>
|
||||
<p>Throttle function</p>
|
||||
<h4>asyncRun(taskList, callback = () => {})</h4>
|
||||
<p>Run tasks in task list asynchronously, tasks are run synchronously without order</p>
|
||||
<h4>degToRad(deg)</h4>
|
||||
<blockquote>
|
||||
<p>v0.2.24+</p>
|
||||
</blockquote>
|
||||
<p>Angle to radian</p>
|
||||
<h4>camelCaseToHyphen(str)</h4>
|
||||
<blockquote>
|
||||
<p>v0.2.24+</p>
|
||||
</blockquote>
|
||||
<p>CamelCase to hyphen</p>
|
||||
<h4>joinFontStr({ italic, bold, fontSize, fontFamily })</h4>
|
||||
<blockquote>
|
||||
<p>v0.3.4+</p>
|
||||
</blockquote>
|
||||
<p>Join the <code>font</code> attribute value of the <code>css</code> font</p>
|
||||
<h4>measureText(text, { italic, bold, fontSize, fontFamily })</h4>
|
||||
<blockquote>
|
||||
<p>v0.3.4+</p>
|
||||
</blockquote>
|
||||
<p>Measure the width and height of the text, return value:</p>
|
||||
<pre class="hljs"><code>{ width, height }
|
||||
</code></pre>
|
||||
<h2>Simulate CSS background in Canvas</h2>
|
||||
<p>Import:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> drawBackgroundImageToCanvas <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/simulateCSSBackgroundInCanvas'</span>
|
||||
</code></pre>
|
||||
<p>Usage:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">let</span> width = <span class="hljs-number">500</span>
|
||||
<span class="hljs-keyword">let</span> height = <span class="hljs-number">500</span>
|
||||
<span class="hljs-keyword">let</span> img = <span class="hljs-string">'/1.jpg'</span>
|
||||
<span class="hljs-keyword">let</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'canvas'</span>)
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
<span class="hljs-attr">backgroundRepeat</span>: <span class="hljs-string">'repeat-y'</span>,
|
||||
<span class="hljs-attr">backgroundSize</span>: <span class="hljs-string">'60%'</span>,
|
||||
<span class="hljs-attr">backgroundPosition</span>: <span class="hljs-string">'center center'</span>
|
||||
}, <span class="hljs-function">(<span class="hljs-params">err</span>) =></span> {
|
||||
<span class="hljs-keyword">if</span> (err) {
|
||||
<span class="hljs-comment">// fail</span>
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-comment">// success</span>
|
||||
}
|
||||
})
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
57
web/src/pages/Doc/en/view/index.md
Normal file
57
web/src/pages/Doc/en/view/index.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# View instance
|
||||
|
||||
The `view` instance is responsible for view operations, and can be obtained
|
||||
through `mindMap.view`
|
||||
|
||||
## Methods
|
||||
|
||||
### translateX(step)
|
||||
|
||||
Translate in the `x` direction, `step`: number of pixels to translate
|
||||
|
||||
### translateY(step)
|
||||
|
||||
Translate in the `y` direction, `step`: number of pixels to translate
|
||||
|
||||
### translateXTo(x)
|
||||
|
||||
> v0.2.11+
|
||||
|
||||
Translate the `x` direction to a specific position
|
||||
|
||||
### translateYTo(y)
|
||||
|
||||
> v0.2.11+
|
||||
|
||||
Translate the `y` direction to a specific position
|
||||
|
||||
### reset()
|
||||
|
||||
Revert to the default transformation
|
||||
|
||||
### narrow()
|
||||
|
||||
Zoom out
|
||||
|
||||
### enlarge()
|
||||
|
||||
Zoom in
|
||||
|
||||
### getTransformData()
|
||||
|
||||
> v0.1.1+
|
||||
|
||||
Get the current transform data, can be used for display
|
||||
|
||||
### setTransformData(data)
|
||||
|
||||
> v0.1.1+
|
||||
|
||||
Dynamically set transform data, transform data can be obtained through the
|
||||
getTransformData method"
|
||||
|
||||
### setScale(scale)
|
||||
|
||||
> v0.2.17+
|
||||
|
||||
Setting Zoom
|
||||
55
web/src/pages/Doc/en/view/index.vue
Normal file
55
web/src/pages/Doc/en/view/index.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>View instance</h1>
|
||||
<p>The <code>view</code> instance is responsible for view operations, and can be obtained
|
||||
through <code>mindMap.view</code></p>
|
||||
<h2>Methods</h2>
|
||||
<h3>translateX(step)</h3>
|
||||
<p>Translate in the <code>x</code> direction, <code>step</code>: number of pixels to translate</p>
|
||||
<h3>translateY(step)</h3>
|
||||
<p>Translate in the <code>y</code> direction, <code>step</code>: number of pixels to translate</p>
|
||||
<h3>translateXTo(x)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.11+</p>
|
||||
</blockquote>
|
||||
<p>Translate the <code>x</code> direction to a specific position</p>
|
||||
<h3>translateYTo(y)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.11+</p>
|
||||
</blockquote>
|
||||
<p>Translate the <code>y</code> direction to a specific position</p>
|
||||
<h3>reset()</h3>
|
||||
<p>Revert to the default transformation</p>
|
||||
<h3>narrow()</h3>
|
||||
<p>Zoom out</p>
|
||||
<h3>enlarge()</h3>
|
||||
<p>Zoom in</p>
|
||||
<h3>getTransformData()</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.1+</p>
|
||||
</blockquote>
|
||||
<p>Get the current transform data, can be used for display</p>
|
||||
<h3>setTransformData(data)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.1+</p>
|
||||
</blockquote>
|
||||
<p>Dynamically set transform data, transform data can be obtained through the
|
||||
getTransformData method"</p>
|
||||
<h3>setScale(scale)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.17+</p>
|
||||
</blockquote>
|
||||
<p>Setting Zoom</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
50
web/src/pages/Doc/en/watermark/index.md
Normal file
50
web/src/pages/Doc/en/watermark/index.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Watermark plugin
|
||||
|
||||
> 0.2.24+
|
||||
|
||||
`Watermark` instance is responsible for displaying the watermark.
|
||||
|
||||
Please refer to the [Instantiation Options](/mind-map/#/doc/zh/constructor) of the `MindMap` class for configuration.
|
||||
|
||||
## Register
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Watermark from 'simple-mind-map/src/Watermark.js'
|
||||
|
||||
MindMap.usePlugin(Watermark)
|
||||
```
|
||||
|
||||
After registration and instantiation of `MindMap`, the instance can be obtained through `mindMap.watermark`.
|
||||
|
||||
## Methods
|
||||
|
||||
### draw()
|
||||
|
||||
Redraw the watermark.
|
||||
|
||||
Note: For imprecise rendering, some watermarks beyond the visible area will be drawn. If you have extreme performance requirements, it is recommended to develop the watermark function yourself.
|
||||
|
||||
### updateWatermark(config)
|
||||
|
||||
Update watermark config. Example:
|
||||
|
||||
```js
|
||||
mindMap.watermark.updateWatermark({
|
||||
text: 'Watermark text',
|
||||
lineSpacing: 100,
|
||||
textSpacing: 100,
|
||||
angle: 50,
|
||||
textStyle: {
|
||||
color: '#000',
|
||||
opacity: 1,
|
||||
fontSize: 20
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### hasWatermark()
|
||||
|
||||
> v0.3.2+
|
||||
|
||||
Gets whether the watermark exists.
|
||||
51
web/src/pages/Doc/en/watermark/index.vue
Normal file
51
web/src/pages/Doc/en/watermark/index.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Watermark plugin</h1>
|
||||
<blockquote>
|
||||
<p>0.2.24+</p>
|
||||
</blockquote>
|
||||
<p><code>Watermark</code> instance is responsible for displaying the watermark.</p>
|
||||
<p>Please refer to the <a href="/mind-map/#/doc/zh/constructor">Instantiation Options</a> of the <code>MindMap</code> class for configuration.</p>
|
||||
<h2>Register</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-keyword">import</span> Watermark <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/Watermark.js'</span>
|
||||
|
||||
MindMap.usePlugin(Watermark)
|
||||
</code></pre>
|
||||
<p>After registration and instantiation of <code>MindMap</code>, the instance can be obtained through <code>mindMap.watermark</code>.</p>
|
||||
<h2>Methods</h2>
|
||||
<h3>draw()</h3>
|
||||
<p>Redraw the watermark.</p>
|
||||
<p>Note: For imprecise rendering, some watermarks beyond the visible area will be drawn. If you have extreme performance requirements, it is recommended to develop the watermark function yourself.</p>
|
||||
<h3>updateWatermark(config)</h3>
|
||||
<p>Update watermark config. Example:</p>
|
||||
<pre class="hljs"><code>mindMap.watermark.updateWatermark({
|
||||
<span class="hljs-attr">text</span>: <span class="hljs-string">'Watermark text'</span>,
|
||||
<span class="hljs-attr">lineSpacing</span>: <span class="hljs-number">100</span>,
|
||||
<span class="hljs-attr">textSpacing</span>: <span class="hljs-number">100</span>,
|
||||
<span class="hljs-attr">angle</span>: <span class="hljs-number">50</span>,
|
||||
<span class="hljs-attr">textStyle</span>: {
|
||||
<span class="hljs-attr">color</span>: <span class="hljs-string">'#000'</span>,
|
||||
<span class="hljs-attr">opacity</span>: <span class="hljs-number">1</span>,
|
||||
<span class="hljs-attr">fontSize</span>: <span class="hljs-number">20</span>
|
||||
}
|
||||
})
|
||||
</code></pre>
|
||||
<h3>hasWatermark()</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.2+</p>
|
||||
</blockquote>
|
||||
<p>Gets whether the watermark exists.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
51
web/src/pages/Doc/en/xmind/index.md
Normal file
51
web/src/pages/Doc/en/xmind/index.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# XMind parse
|
||||
|
||||
> v0.2.7+
|
||||
|
||||
Provides methods for importing `XMind` files.
|
||||
|
||||
## Import
|
||||
|
||||
```js
|
||||
import xmind from 'simple-mind-map/src/parse/xmind.js'
|
||||
```
|
||||
|
||||
If you are using the file in the format of `umd`, you can obtain it in the following way:
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map/dist/simpleMindMap.umd.min"
|
||||
|
||||
MindMap.xmind
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
### xmind.parseXmindFile(file)
|
||||
|
||||
Parsing the `.xmind` file and returning the parsed data. Note that this is
|
||||
complete data, including the node tree, theme, and structure. You can use
|
||||
`mindMap.setFullData(data)` to render the returned data to the canvas.
|
||||
|
||||
`file`: `File` object
|
||||
|
||||
### xmind.transformXmind(content)
|
||||
|
||||
Convert `xmind` data. The `.xmind` file is essentially a `zip` file that can be
|
||||
decompressed by changing the suffix to zip. Inside, there is a `content.json`
|
||||
file. If you have parsed this file yourself, you can pass the contents of this
|
||||
file to this method for conversion. The converted data is the complete data,
|
||||
including the node tree, theme, structure, etc. You can use
|
||||
`mindMap.setFullData(data)` to render the returned data to the canvas.
|
||||
|
||||
`content`: the contents of the `content.json` file within the `.xmind` zip
|
||||
package
|
||||
|
||||
### xmind.transformOldXmind(content)
|
||||
|
||||
> v0.2.8+
|
||||
|
||||
For data parsing of the `xmind8` version, because the `.xmind` file in this
|
||||
version does not have a `content.json`, it corresponds to `content.xml`.
|
||||
|
||||
`content`: the contents of the `content.xml` file within the `.xmind` zip
|
||||
package
|
||||
51
web/src/pages/Doc/en/xmind/index.vue
Normal file
51
web/src/pages/Doc/en/xmind/index.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>XMind parse</h1>
|
||||
<blockquote>
|
||||
<p>v0.2.7+</p>
|
||||
</blockquote>
|
||||
<p>Provides methods for importing <code>XMind</code> files.</p>
|
||||
<h2>Import</h2>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> xmind <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/parse/xmind.js'</span>
|
||||
</code></pre>
|
||||
<p>If you are using the file in the format of <code>umd</code>, you can obtain it in the following way:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map/dist/simpleMindMap.umd.min"</span>
|
||||
|
||||
MindMap.xmind
|
||||
</code></pre>
|
||||
<h2>Methods</h2>
|
||||
<h3>xmind.parseXmindFile(file)</h3>
|
||||
<p>Parsing the <code>.xmind</code> file and returning the parsed data. Note that this is
|
||||
complete data, including the node tree, theme, and structure. You can use
|
||||
<code>mindMap.setFullData(data)</code> to render the returned data to the canvas.</p>
|
||||
<p><code>file</code>: <code>File</code> object</p>
|
||||
<h3>xmind.transformXmind(content)</h3>
|
||||
<p>Convert <code>xmind</code> data. The <code>.xmind</code> file is essentially a <code>zip</code> file that can be
|
||||
decompressed by changing the suffix to zip. Inside, there is a <code>content.json</code>
|
||||
file. If you have parsed this file yourself, you can pass the contents of this
|
||||
file to this method for conversion. The converted data is the complete data,
|
||||
including the node tree, theme, structure, etc. You can use
|
||||
<code>mindMap.setFullData(data)</code> to render the returned data to the canvas.</p>
|
||||
<p><code>content</code>: the contents of the <code>content.json</code> file within the <code>.xmind</code> zip
|
||||
package</p>
|
||||
<h3>xmind.transformOldXmind(content)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.8+</p>
|
||||
</blockquote>
|
||||
<p>For data parsing of the <code>xmind8</code> version, because the <code>.xmind</code> file in this
|
||||
version does not have a <code>content.json</code>, it corresponds to <code>content.xml</code>.</p>
|
||||
<p><code>content</code>: the contents of the <code>content.xml</code> file within the <code>.xmind</code> zip
|
||||
package</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
15
web/src/pages/Doc/i18n.js
Normal file
15
web/src/pages/Doc/i18n.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const data = {
|
||||
pageCatalog: {
|
||||
zh: '本页目录',
|
||||
en: 'Page catalog'
|
||||
},
|
||||
demo: {
|
||||
zh: '在线示例',
|
||||
en: 'Online Demo'
|
||||
}
|
||||
}
|
||||
|
||||
const t = (str, lang) => {
|
||||
return data[str] ? data[str][lang] || data[str].zh : ''
|
||||
}
|
||||
export default t
|
||||
3
web/src/pages/Doc/routerList.js
Normal file
3
web/src/pages/Doc/routerList.js
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
export default [{"lang":"zh","children":[{"path":"batchExecution","title":"BatchExecution实例"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"Command实例"},{"path":"constructor","title":"构造函数"},{"path":"doExport","title":"Export 插件"},{"path":"drag","title":"Drag插件"},{"path":"introduction","title":"简介"},{"path":"keyboardNavigation","title":"KeyboardNavigation插件"},{"path":"keyCommand","title":"KeyCommand实例"},{"path":"miniMap","title":"MiniMap插件"},{"path":"node","title":"Node实例"},{"path":"render","title":"Render实例"},{"path":"select","title":"Select 插件 "},{"path":"start","title":"开始"},{"path":"translate","title":"参与翻译"},{"path":"utils","title":"内置工具方法"},{"path":"view","title":"View实例"},{"path":"watermark","title":"Watermark插件"},{"path":"xmind","title":"XMind解析"}]},{"lang":"en","children":[{"path":"batchExecution","title":"batchExecution instance"},{"path":"changelog","title":"Changelog"},{"path":"command","title":"command instance"},{"path":"constructor","title":"Constructor"},{"path":"doExport","title":"Export plugin"},{"path":"drag","title":"Drag plugin"},{"path":"introduction","title":"Introduction"},{"path":"keyboardNavigation","title":"KeyboardNavigation plugin"},{"path":"keyCommand","title":"KeyCommand instance"},{"path":"miniMap","title":"MiniMap plugin"},{"path":"node","title":"Node instance"},{"path":"render","title":"Render instance"},{"path":"select","title":"Select plugin"},{"path":"start","title":"Start"},{"path":"translate","title":"Participate in translation"},{"path":"utils","title":"Utility Methods"},{"path":"view","title":"View instance"},{"path":"watermark","title":"Watermark plugin"},{"path":"xmind","title":"XMind parse"}]}]
|
||||
|
||||
13
web/src/pages/Doc/zh/batchExecution/index.md
Normal file
13
web/src/pages/Doc/zh/batchExecution/index.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# BatchExecution实例
|
||||
|
||||
`batchExecution`用来批量异步的执行一些操作,如果某个操作同时多次调用,那么只会在下一个事件循环里执行一次。可以通过`mindMap.batchExecution`获取到该实例
|
||||
|
||||
## 方法
|
||||
|
||||
### push(name, fn)
|
||||
|
||||
添加任务。
|
||||
|
||||
`name`:任务名称
|
||||
|
||||
`fn`:任务
|
||||
22
web/src/pages/Doc/zh/batchExecution/index.vue
Normal file
22
web/src/pages/Doc/zh/batchExecution/index.vue
Normal file
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>BatchExecution实例</h1>
|
||||
<p><code>batchExecution</code>用来批量异步的执行一些操作,如果某个操作同时多次调用,那么只会在下一个事件循环里执行一次。可以通过<code>mindMap.batchExecution</code>获取到该实例</p>
|
||||
<h2>方法</h2>
|
||||
<h3>push(name, fn)</h3>
|
||||
<p>添加任务。</p>
|
||||
<p><code>name</code>:任务名称</p>
|
||||
<p><code>fn</code>:任务</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
173
web/src/pages/Doc/zh/changelog/index.md
Normal file
173
web/src/pages/Doc/zh/changelog/index.md
Normal file
@@ -0,0 +1,173 @@
|
||||
# Changelog
|
||||
|
||||
## 0.3.4
|
||||
|
||||
New:节点文本增加自动换行功能。
|
||||
|
||||
Fix:1.修复批量删除的节点中如果存在根节点会出现删除异常的问题。2.修复底边风格的情况下,节点高度过高会和其他节点重叠的问题。
|
||||
|
||||
## 0.3.3
|
||||
|
||||
修复:根节点文字无法换行的问题。
|
||||
|
||||
## 0.3.2
|
||||
|
||||
修复:1.修复二级节点拖拽到其他节点或其他节点拖拽到二级节点时节点样式没有更新的问题;2.修复当思维导图实际内容大于屏幕宽高时,导出的时候超出的部分没有绘制水印的问题。
|
||||
|
||||
## 0.3.1
|
||||
|
||||
修复:1.删除背景图片不生效的问题;2.节点拖拽到根节点时连接线跑到根节点上方的问题。
|
||||
|
||||
新增:背景图片展示增加位置和大小设置。导出的图片也同步支持该设置。
|
||||
|
||||
## 0.3.0
|
||||
|
||||
升级为插件化架构,将一些非核心功能抽离出来作为插件,按需注册,减小整体体积。
|
||||
|
||||
## 0.2.24
|
||||
|
||||
新增:节点自由拖拽改为可配置,默认为`false`不开启;支持添加水印。
|
||||
|
||||
## 0.2.23
|
||||
|
||||
新增:支持注册新主题。
|
||||
|
||||
## 0.2.22
|
||||
|
||||
优化:取消内置`simple-mind-map`包的主题和结构图片,改为由使用者自行维护,原有图片可在`web/assets/img/`目录找到。
|
||||
|
||||
## 0.2.21
|
||||
|
||||
新增:支持节点横线风格。
|
||||
|
||||
## 0.2.20
|
||||
|
||||
修复:画布距窗口左上角不为0时节点拖拽出现偏移的问题。
|
||||
|
||||
## 0.2.19
|
||||
|
||||
修复:没有激活节点时随便按什么键都会触发自动聚焦的问题。
|
||||
|
||||
## 0.2.18
|
||||
|
||||
优化:键盘导航寻找焦点的算法,支持简单算法、区域算法、阴影算法。
|
||||
|
||||
## 0.2.17
|
||||
|
||||
新增:键盘导航,即通过方向键来切换激活的节点;支持在大纲直接编辑节点文本内容。
|
||||
|
||||
## 0.2.16
|
||||
|
||||
优化:小地图、拖拽性能。
|
||||
|
||||
## 0.2.15
|
||||
|
||||
优化:本地文件编辑。
|
||||
|
||||
新增:支持双击节点内图片进行大图预览。
|
||||
|
||||
## 0.2.14
|
||||
|
||||
优化:插入子节点时自动展开。
|
||||
|
||||
修复:小地图关闭时报错的问题。
|
||||
|
||||
## 0.2.13
|
||||
|
||||
修复:子节点收起状态复制时丢失的问题。
|
||||
|
||||
## 0.2.11
|
||||
|
||||
修复:修复子节点收起状态复制时丢失的问题。
|
||||
|
||||
新增:支持小地图。
|
||||
|
||||
## 0.2.10
|
||||
|
||||
优化:手动创建节点时立即聚焦。
|
||||
|
||||
修复:连线样式深度更新问题。
|
||||
|
||||
新增:逻辑结构图、思维导图新增直线连接风格、直连风格。
|
||||
|
||||
## 0.2.9
|
||||
|
||||
新增:支持新建、打开、保存到电脑本地文件。
|
||||
|
||||
## 0.2.8
|
||||
|
||||
修复:xmind8版本文件导入失败的问题。
|
||||
|
||||
新增:支持展开到指定层级。
|
||||
|
||||
## 0.2.7
|
||||
|
||||
修复:根节点添加多个节点爆栈的问题。
|
||||
|
||||
新增:支持导入.xmind文件。
|
||||
|
||||
## 0.2.6
|
||||
|
||||
新增:导出svg增加title标签。
|
||||
|
||||
## 0.2.5
|
||||
|
||||
修复:节点展开收起的bug。
|
||||
|
||||
新增:节点支持自定义线条样式。
|
||||
|
||||
## 0.2.4
|
||||
|
||||
新增:节点支持多种形状。
|
||||
|
||||
## 0.2.3
|
||||
|
||||
修复:编辑节点文本时快捷键冲突的问题;右键菜单快捷键提示错误;右键菜单快捷键提示。
|
||||
|
||||
## 0.2.2
|
||||
|
||||
修复:输入字符串'/'和快捷键'/'冲突问题。
|
||||
|
||||
## 0.2.1
|
||||
|
||||
新增:支持导出为pdf。
|
||||
|
||||
## 0.2.0
|
||||
|
||||
新增:经典4主题;支持添加概要;支持自由拖拽;上移节点、下移节点、复制节点、剪切节点、粘贴节点、一键整理布快捷键;库打包;Ctrl+左键多选。
|
||||
|
||||
## 0.1.18
|
||||
|
||||
修复:节点图标不能删除的问题;工具按钮置灰仍然可以点击的问题。
|
||||
|
||||
## 0.1.17
|
||||
|
||||
新增:增加只读模式。
|
||||
|
||||
## 0.1.16
|
||||
|
||||
新增:节点备注支持markdown及富文本。
|
||||
|
||||
修复:不能选中文字的问题;节点标注在节点激活后无法隐藏问题;超链接、备注、标签等文字编辑时返回键和回车键与思维导图快捷键冲突的问题。
|
||||
|
||||
## 0.1.15
|
||||
|
||||
新增:状态数据支持保存激活状态、视图状态(拖动位置、缩放值);支持节点拖拽。
|
||||
|
||||
## 0.1.14
|
||||
|
||||
修复:存在激活节点时设置主题存在的问题。
|
||||
|
||||
## 0.1.13
|
||||
|
||||
新增:快捷键功能;新增导出为json。
|
||||
|
||||
优化:一些细节。
|
||||
|
||||
## 0.1.12
|
||||
|
||||
新增:本地存储;右键菜单功能等。
|
||||
|
||||
## 0.1.0
|
||||
|
||||
完成基本功能。
|
||||
102
web/src/pages/Doc/zh/changelog/index.vue
Normal file
102
web/src/pages/Doc/zh/changelog/index.vue
Normal file
@@ -0,0 +1,102 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.3.4</h2>
|
||||
<p>New:节点文本增加自动换行功能。</p>
|
||||
<p>Fix:1.修复批量删除的节点中如果存在根节点会出现删除异常的问题。2.修复底边风格的情况下,节点高度过高会和其他节点重叠的问题。</p>
|
||||
<h2>0.3.3</h2>
|
||||
<p>修复:根节点文字无法换行的问题。</p>
|
||||
<h2>0.3.2</h2>
|
||||
<p>修复:1.修复二级节点拖拽到其他节点或其他节点拖拽到二级节点时节点样式没有更新的问题;2.修复当思维导图实际内容大于屏幕宽高时,导出的时候超出的部分没有绘制水印的问题。</p>
|
||||
<h2>0.3.1</h2>
|
||||
<p>修复:1.删除背景图片不生效的问题;2.节点拖拽到根节点时连接线跑到根节点上方的问题。</p>
|
||||
<p>新增:背景图片展示增加位置和大小设置。导出的图片也同步支持该设置。</p>
|
||||
<h2>0.3.0</h2>
|
||||
<p>升级为插件化架构,将一些非核心功能抽离出来作为插件,按需注册,减小整体体积。</p>
|
||||
<h2>0.2.24</h2>
|
||||
<p>新增:节点自由拖拽改为可配置,默认为<code>false</code>不开启;支持添加水印。</p>
|
||||
<h2>0.2.23</h2>
|
||||
<p>新增:支持注册新主题。</p>
|
||||
<h2>0.2.22</h2>
|
||||
<p>优化:取消内置<code>simple-mind-map</code>包的主题和结构图片,改为由使用者自行维护,原有图片可在<code>web/assets/img/</code>目录找到。</p>
|
||||
<h2>0.2.21</h2>
|
||||
<p>新增:支持节点横线风格。</p>
|
||||
<h2>0.2.20</h2>
|
||||
<p>修复:画布距窗口左上角不为0时节点拖拽出现偏移的问题。</p>
|
||||
<h2>0.2.19</h2>
|
||||
<p>修复:没有激活节点时随便按什么键都会触发自动聚焦的问题。</p>
|
||||
<h2>0.2.18</h2>
|
||||
<p>优化:键盘导航寻找焦点的算法,支持简单算法、区域算法、阴影算法。</p>
|
||||
<h2>0.2.17</h2>
|
||||
<p>新增:键盘导航,即通过方向键来切换激活的节点;支持在大纲直接编辑节点文本内容。</p>
|
||||
<h2>0.2.16</h2>
|
||||
<p>优化:小地图、拖拽性能。</p>
|
||||
<h2>0.2.15</h2>
|
||||
<p>优化:本地文件编辑。</p>
|
||||
<p>新增:支持双击节点内图片进行大图预览。</p>
|
||||
<h2>0.2.14</h2>
|
||||
<p>优化:插入子节点时自动展开。</p>
|
||||
<p>修复:小地图关闭时报错的问题。</p>
|
||||
<h2>0.2.13</h2>
|
||||
<p>修复:子节点收起状态复制时丢失的问题。</p>
|
||||
<h2>0.2.11</h2>
|
||||
<p>修复:修复子节点收起状态复制时丢失的问题。</p>
|
||||
<p>新增:支持小地图。</p>
|
||||
<h2>0.2.10</h2>
|
||||
<p>优化:手动创建节点时立即聚焦。</p>
|
||||
<p>修复:连线样式深度更新问题。</p>
|
||||
<p>新增:逻辑结构图、思维导图新增直线连接风格、直连风格。</p>
|
||||
<h2>0.2.9</h2>
|
||||
<p>新增:支持新建、打开、保存到电脑本地文件。</p>
|
||||
<h2>0.2.8</h2>
|
||||
<p>修复:xmind8版本文件导入失败的问题。</p>
|
||||
<p>新增:支持展开到指定层级。</p>
|
||||
<h2>0.2.7</h2>
|
||||
<p>修复:根节点添加多个节点爆栈的问题。</p>
|
||||
<p>新增:支持导入.xmind文件。</p>
|
||||
<h2>0.2.6</h2>
|
||||
<p>新增:导出svg增加title标签。</p>
|
||||
<h2>0.2.5</h2>
|
||||
<p>修复:节点展开收起的bug。</p>
|
||||
<p>新增:节点支持自定义线条样式。</p>
|
||||
<h2>0.2.4</h2>
|
||||
<p>新增:节点支持多种形状。</p>
|
||||
<h2>0.2.3</h2>
|
||||
<p>修复:编辑节点文本时快捷键冲突的问题;右键菜单快捷键提示错误;右键菜单快捷键提示。</p>
|
||||
<h2>0.2.2</h2>
|
||||
<p>修复:输入字符串'/'和快捷键'/'冲突问题。</p>
|
||||
<h2>0.2.1</h2>
|
||||
<p>新增:支持导出为pdf。</p>
|
||||
<h2>0.2.0</h2>
|
||||
<p>新增:经典4主题;支持添加概要;支持自由拖拽;上移节点、下移节点、复制节点、剪切节点、粘贴节点、一键整理布快捷键;库打包;Ctrl+左键多选。</p>
|
||||
<h2>0.1.18</h2>
|
||||
<p>修复:节点图标不能删除的问题;工具按钮置灰仍然可以点击的问题。</p>
|
||||
<h2>0.1.17</h2>
|
||||
<p>新增:增加只读模式。</p>
|
||||
<h2>0.1.16</h2>
|
||||
<p>新增:节点备注支持markdown及富文本。</p>
|
||||
<p>修复:不能选中文字的问题;节点标注在节点激活后无法隐藏问题;超链接、备注、标签等文字编辑时返回键和回车键与思维导图快捷键冲突的问题。</p>
|
||||
<h2>0.1.15</h2>
|
||||
<p>新增:状态数据支持保存激活状态、视图状态(拖动位置、缩放值);支持节点拖拽。</p>
|
||||
<h2>0.1.14</h2>
|
||||
<p>修复:存在激活节点时设置主题存在的问题。</p>
|
||||
<h2>0.1.13</h2>
|
||||
<p>新增:快捷键功能;新增导出为json。</p>
|
||||
<p>优化:一些细节。</p>
|
||||
<h2>0.1.12</h2>
|
||||
<p>新增:本地存储;右键菜单功能等。</p>
|
||||
<h2>0.1.0</h2>
|
||||
<p>完成基本功能。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
29
web/src/pages/Doc/zh/command/index.md
Normal file
29
web/src/pages/Doc/zh/command/index.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Command实例
|
||||
|
||||
`command`实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过`mindMap.command`获取到该实例
|
||||
|
||||
## 方法
|
||||
|
||||
### add(name, fn)
|
||||
|
||||
添加命令。
|
||||
|
||||
`name`:命令名称
|
||||
|
||||
`fn`:命令要执行的方法
|
||||
|
||||
### remove(name, fn)
|
||||
|
||||
移除命令。
|
||||
|
||||
`name`:要移除的命令名称
|
||||
|
||||
`fn`:要移除的方法,不传的话移除该命令所有的方法
|
||||
|
||||
### getCopyData()
|
||||
|
||||
获取渲染树数据副本
|
||||
|
||||
### clearHistory()
|
||||
|
||||
清空历史堆栈数据
|
||||
30
web/src/pages/Doc/zh/command/index.vue
Normal file
30
web/src/pages/Doc/zh/command/index.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Command实例</h1>
|
||||
<p><code>command</code>实例负责命令的添加及执行,内置了很多命令,也可以自行添加,命令指需要在历史堆栈数据里添加副本的操作。可通过<code>mindMap.command</code>获取到该实例</p>
|
||||
<h2>方法</h2>
|
||||
<h3>add(name, fn)</h3>
|
||||
<p>添加命令。</p>
|
||||
<p><code>name</code>:命令名称</p>
|
||||
<p><code>fn</code>:命令要执行的方法</p>
|
||||
<h3>remove(name, fn)</h3>
|
||||
<p>移除命令。</p>
|
||||
<p><code>name</code>:要移除的命令名称</p>
|
||||
<p><code>fn</code>:要移除的方法,不传的话移除该命令所有的方法</p>
|
||||
<h3>getCopyData()</h3>
|
||||
<p>获取渲染树数据副本</p>
|
||||
<h3>clearHistory()</h3>
|
||||
<p>清空历史堆栈数据</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
315
web/src/pages/Doc/zh/constructor/index.md
Normal file
315
web/src/pages/Doc/zh/constructor/index.md
Normal file
@@ -0,0 +1,315 @@
|
||||
# 构造函数
|
||||
|
||||
## 基本使用
|
||||
|
||||
```html
|
||||
<div id="mindMapContainer"></div>
|
||||
```
|
||||
|
||||
```js
|
||||
import MindMap from "simple-mind-map";
|
||||
|
||||
const mindMap = new MindMap({
|
||||
el: document.getElementById('mindMapContainer'),
|
||||
data: {
|
||||
"data": {
|
||||
"text": "根节点"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## 实例化选项
|
||||
|
||||
| 字段名称 | 类型 | 默认值 | 描述 | 是否必填 |
|
||||
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------ | -------- |
|
||||
| el | Element | | 容器元素,必须为DOM元素 | 是 |
|
||||
| data | Object | {} | 思维导图数据,可参考:[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js) | |
|
||||
| layout | String | logicalStructure | 布局类型,可选列表:logicalStructure(逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图) | |
|
||||
| theme | String | default | 主题,可选列表:default(默认)、classic(脑图经典)、minions(小黄人)、pinkGrape(粉红葡萄)、mint(薄荷)、gold(金色vip)、vitalityOrange(活力橙)、greenLeaf(绿叶)、dark2(暗色2)、skyGreen(天清绿)、classic2(脑图经典2)、classic3(脑图经典3)、classic4(脑图经典4,v0.2.0+)、classicGreen(经典绿)、classicBlue(经典蓝)、blueSky(天空蓝)、brainImpairedPink(脑残粉)、dark(暗色)、earthYellow(泥土黄)、freshGreen(清新绿)、freshRed(清新红)、romanticPurple(浪漫紫) | |
|
||||
| themeConfig | Object | {} | 主题配置,会和所选择的主题进行合并,可用字段可参考:[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js) | |
|
||||
| scaleRatio | Number | 0.1 | 放大缩小的增量比例 | |
|
||||
| maxTag | Number | 5 | 节点里最多显示的标签数量,多余的会被丢弃 | |
|
||||
| exportPadding | Number | 20 | 导出图片时的内边距 | |
|
||||
| imgTextMargin | Number | 5 | 节点里图片和文字的间距 | |
|
||||
| textContentMargin | Number | 2 | 节点里各种文字信息的间距,如图标和文字的间距 | |
|
||||
| selectTranslateStep | Number | 3 | 多选节点时鼠标移动到边缘时的画布移动偏移量 | |
|
||||
| selectTranslateLimit | Number | 20 | 多选节点时鼠标移动距边缘多少距离时开始偏移 | |
|
||||
| customNoteContentShow(v0.1.6+) | Object | null | 自定义节点备注内容显示,Object类型,结构为:{show: (noteContent, left, top) => {// 你的显示节点备注逻辑 }, hide: () => {// 你的隐藏节点备注逻辑 }} | |
|
||||
| readonly(v0.1.7+) | Boolean | false | 是否是只读模式 | |
|
||||
| enableFreeDrag(v0.2.4+) | Boolean | false | 是否开启节点自由拖拽 | |
|
||||
| watermarkConfig(v0.2.4+) | Object | | 水印配置,详细配置请参考下方表格【水印配置】 | |
|
||||
| textAutoWrapWidth(v0.3.4+) | Number | 500 | 节点内每行文本达到该宽度后自动换行 | |
|
||||
|
||||
### 水印配置
|
||||
|
||||
| 字段名称 | 类型 | 默认值 | 描述 |
|
||||
| ----------- | ------ | ------------------------------------------- | ------------------------------------ |
|
||||
| text | String | '' | 水印文字,如果为空字符串则不显示水印 |
|
||||
| lineSpacing | Number | 100 | 水印每行之间的间距 |
|
||||
| textSpacing | Number | 100 | 同一行水印之间的间距 |
|
||||
| angle | Number | 30 | 水印的倾斜角度,范围:[0, 90] |
|
||||
| textStyle | Object | {color: '#999', opacity: 0.5, fontSize: 14} | 水印文字样式 |
|
||||
|
||||
|
||||
|
||||
## 静态方法
|
||||
|
||||
### defineTheme(name, config)
|
||||
|
||||
> v0.2.23+
|
||||
|
||||
定义新主题。
|
||||
|
||||
`name`:新主题名称
|
||||
|
||||
`config`:主题数据
|
||||
|
||||
`simple-mind-map`内置了众多主题,另外你也可以注册新主题,建议在实例化之前进行注册,这样在实例化时可以直接使用新注册的主题,使用示例:
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
// 注册新主题
|
||||
MindMap.defineTheme('主题名称', {})
|
||||
|
||||
// 1.实例化时使用新注册的主题
|
||||
const mindMap = new MindMap({
|
||||
theme: '主题名称'
|
||||
})
|
||||
|
||||
// 2.动态切换新主题
|
||||
mindMap.setTheme('主题名称')
|
||||
```
|
||||
|
||||
主题的所有配置可以参考[默认主题](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js)。`defineTheme`方法会把你传入的配置和默认配置做合并。大部分主题其实需要自定义的部分不是很多,一个典型的自定义主题配置可以参考[blueSky](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js)。
|
||||
|
||||
### usePlugin(plugin)
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
注册插件,如果需要使用非核心的一些功能,比如小地图、水印等,可以通过该方法进行注册。可链式调用。
|
||||
|
||||
注意:插件需要在实例化`MindMap`前注册。
|
||||
|
||||
## 静态属性
|
||||
|
||||
### pluginList
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
当前注册的所有插件列表。
|
||||
|
||||
## 实例方法
|
||||
|
||||
### getSvgData()
|
||||
|
||||
> v0.3.0+
|
||||
|
||||
获取`svg`数据,返回一个对象,详细结构如下:
|
||||
|
||||
```js
|
||||
{
|
||||
svg, // Element,思维导图图形的整体svg元素,包括:svg(画布容器)、g(实际的思维导图组)
|
||||
svgHTML, // String,svg字符串,即html字符串,可以直接渲染到你准备的小地图容器内
|
||||
rect: // Object,思维导图图形未缩放时的位置尺寸等信息
|
||||
origWidth, // Number,画布宽度
|
||||
origHeight, // Number,画布高度
|
||||
scaleX, // Number,思维导图图形的水平缩放值
|
||||
scaleY, // Number,思维导图图形的垂直缩放值
|
||||
}
|
||||
```
|
||||
|
||||
### render(callback)
|
||||
|
||||
- `callback`:`v0.3.2+`,`Function`,当重新渲染完成时调用
|
||||
|
||||
触发整体渲染,会进行节点复用,性能较`reRender`会更好一点,如果只是节点位置变化了可以调用该方法进行渲染
|
||||
|
||||
### reRender(callback)
|
||||
|
||||
- `callback`:`v0.3.2+`,`Function`,当重新渲染完成时调用
|
||||
|
||||
整体重新渲染,会清空画布,节点也会重新创建,性能不好,慎重使用
|
||||
|
||||
### resize()
|
||||
|
||||
容器尺寸变化后,需要调用该方法进行适应
|
||||
|
||||
### setMode(mode)
|
||||
|
||||
> v0.1.7+
|
||||
|
||||
切换模式为只读或编辑。
|
||||
|
||||
`mode`:readonly、edit
|
||||
|
||||
### on(event, fn)
|
||||
|
||||
监听事件,事件列表:
|
||||
|
||||
| 事件名称 | 描述 | 回调参数 |
|
||||
| -------------------------------- | ------------------------------------------ | ------------------------------------------------------------ |
|
||||
| data_change | 渲染树数据变化,可以监听该方法获取最新数据 | data(当前渲染树数据) |
|
||||
| view_data_change(v0.1.1+) | 视图变化数据,比如拖动或缩放时会触发 | data(当前视图状态数据) |
|
||||
| back_forward | 前进或回退 | activeHistoryIndex(当前在历史数据数组里的索引)、length(当前历史数据数组的长度) |
|
||||
| draw_click | *画布的单击事件* | e(事件对象) |
|
||||
| svg_mousedown | svg画布的鼠标按下事件 | e(事件对象) |
|
||||
| mousedown | el元素的鼠标按下事件 | e(事件对象)、this(Event事件类实例) |
|
||||
| mousemove | el元素的鼠标移动事件 | e(事件对象)、this(Event事件类实例) |
|
||||
| drag | 如果是按住左键拖动的话会触发拖动事件 | e(事件对象)、this(Event事件类实例) |
|
||||
| mouseup | el元素的鼠标松开事件 | e(事件对象)、this(Event事件类实例) |
|
||||
| mousewheel | 鼠标滚动事件 | e(事件对象)、dir(向上up还是向下down滚动)、this(Event事件类实例) |
|
||||
| contextmenu | svg画布的鼠标右键菜单事件 | e(事件对象) |
|
||||
| node_click | 节点的单击事件 | this(节点实例)、e(事件对象) |
|
||||
| node_mousedown | 节点的鼠标按下事件 | this(节点实例)、e(事件对象) |
|
||||
| node_mouseup | 节点的鼠标松开事件 | this(节点实例)、e(事件对象) |
|
||||
| node_dblclick | 节点的双击事件 | this(节点实例)、e(事件对象) |
|
||||
| node_contextmenu | 节点的右键菜单事件 | e(事件对象)、this(节点实例) |
|
||||
| before_node_active | 节点激活前事件 | this(节点实例)、activeNodeList(当前激活的所有节点列表) |
|
||||
| node_active | 节点激活事件 | this(节点实例)、activeNodeList(当前激活的所有节点列表) |
|
||||
| expand_btn_click | 节点展开或收缩事件 | this(节点实例) |
|
||||
| before_show_text_edit | 节点文本编辑框即将打开事件 | |
|
||||
| hide_text_edit | 节点文本编辑框关闭事件 | textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表) |
|
||||
| scale | 放大缩小事件 | scale(缩放比例) |
|
||||
| node_img_dblclick(v0.2.15+) | 节点内图片的双击事件 | this(节点实例)、e(事件对象) |
|
||||
| node_tree_render_end(v0.2.16+) | 节点树渲染完毕事件 | |
|
||||
|
||||
### emit(event, ...args)
|
||||
|
||||
触发事件,可以是上面表格里的事件,也可以是自定义事件
|
||||
|
||||
### off(event, fn)
|
||||
|
||||
解绑事件
|
||||
|
||||
### setTheme(theme)
|
||||
|
||||
切换主题,可选主题见上面的选项表格
|
||||
|
||||
### getTheme()
|
||||
|
||||
获取当前主题
|
||||
|
||||
### setThemeConfig(config)
|
||||
|
||||
设置主题配置,`config`同上面选项表格里的选项`themeConfig`
|
||||
|
||||
### getCustomThemeConfig()
|
||||
|
||||
获取自定义主题配置
|
||||
|
||||
### getThemeConfig(prop)
|
||||
|
||||
获取某个主题配置属性值
|
||||
|
||||
### getConfig(*prop*)
|
||||
|
||||
> 0.2.24+
|
||||
|
||||
`prop`:获取指定配置的值,不传则返回整个配置
|
||||
|
||||
获取配置,即`new MindMap(opt)`的`opt`
|
||||
|
||||
### updateConfig(*opt* = {})
|
||||
|
||||
> 0.2.24+
|
||||
|
||||
`opt`:要更新的配置
|
||||
|
||||
更新配置,即更新`new MindMap(opt)`的`opt`,可以只更新部分数据,比如:
|
||||
|
||||
```js
|
||||
mindMap.updateConfig({
|
||||
enableFreeDrag: true// 开启节点自由拖拽
|
||||
})
|
||||
```
|
||||
|
||||
该方法只做更新配置的事情,没有其他副作用,比如触发画布重新渲染之类的
|
||||
|
||||
### getLayout()
|
||||
|
||||
获取当前的布局结构
|
||||
|
||||
### setLayout(layout)
|
||||
|
||||
设置布局结构,可选值见上面选项表格的`layout`字段
|
||||
|
||||
### execCommand(name, ...args)
|
||||
|
||||
执行命令,每执行一个命令就会在历史堆栈里添加一条记录用于回退或前进。所有命令如下:
|
||||
|
||||
| 命令名称 | 描述 | 参数 |
|
||||
| --------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| SELECT_ALL | 全选 | |
|
||||
| BACK | 回退指定的步数 | step(要回退的步数,默认为1) |
|
||||
| FORWARD | 前进指定的步数 | step(要前进的步数,默认为1) |
|
||||
| INSERT_NODE | 插入同级节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效 | |
|
||||
| INSERT_CHILD_NODE | 插入子节点,操作节点为当前激活的节点 | |
|
||||
| UP_NODE | 上移节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的第一个节点使用无效 | |
|
||||
| DOWN_NODE | 操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的最后一个节点使用无效 | |
|
||||
| REMOVE_NODE | 删除节点,操作节点为当前激活的节点 | |
|
||||
| PASTE_NODE | 粘贴节点到节点,操作节点为当前激活的节点 | data(要粘贴的节点数据,一般通过`renderer.copyNode()`方法和`renderer.cutNode()`方法获取) |
|
||||
| CUT_NODE | 剪切节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点使用无效 | callback(回调函数,剪切的节点数据会通过调用该函数并通过参数返回) |
|
||||
| SET_NODE_STYLE | 修改节点样式 | node(要设置样式的节点)、prop(样式属性)、value(样式属性值)、isActive(布尔值,是否设置的是激活状态的样式) |
|
||||
| SET_NODE_ACTIVE | 设置节点是否激活 | node(要设置的节点)、active(布尔值,是否激活) |
|
||||
| CLEAR_ACTIVE_NODE | 清除当前已激活节点的激活状态,操作节点为当前激活的节点 | |
|
||||
| SET_NODE_EXPAND | 设置节点是否展开 | node(要设置的节点)、expand(布尔值,是否展开) |
|
||||
| EXPAND_ALL | 展开所有节点 | |
|
||||
| UNEXPAND_ALL | 收起所有节点 | |
|
||||
| UNEXPAND_TO_LEVEL(v0.2.8+) | 展开到指定层级 | level(要展开到的层级,1、2、3...) |
|
||||
| SET_NODE_DATA | 更新节点数据,即更新节点数据对象里`data`对象的数据 | node(要设置的节点)、data(对象,要更新的数据,如`{expand: true}`) |
|
||||
| SET_NODE_TEXT | 设置节点文本 | node(要设置的节点)、text(要设置的文本字符串,换行可以使用`\n`) |
|
||||
| SET_NODE_IMAGE | 设置节点图片 | node(要设置的节点)、imgData(对象,图片信息,结构为:`{url, title, width, height}`,图片的宽高必须要传) |
|
||||
| SET_NODE_ICON | 设置节点图标 | node(要设置的节点)、icons(数组,预定义的图片名称组成的数组,可用图标可在[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件里的`nodeIconList`列表里获取到,图标名称为`type_name`,如`['priority_1']`) |
|
||||
| SET_NODE_HYPERLINK | 设置节点超链接 | node(要设置的节点)、link(超链接地址)、title(超链接名称,可选) |
|
||||
| SET_NODE_NOTE | 设置节点备注 | node(要设置的节点)、note(备注文字) |
|
||||
| SET_NODE_TAG | 设置节点标签 | node(要设置的节点)、tag(字符串数组,内置颜色信息可在[https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js)里获取到) |
|
||||
| INSERT_AFTER(v0.1.5+) | 将节点移动到另一个节点的后面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| INSERT_BEFORE(v0.1.5+) | 将节点移动到另一个节点的前面 | node(要移动的节点)、 exist(目标节点) |
|
||||
| MOVE_NODE_TO(v0.1.5+) | 移动一个节点作为另一个节点的子节点 | node(要移动的节点)、 toNode(目标节点) |
|
||||
| ADD_GENERALIZATION(v0.2.0+) | 添加节点概要 | data(概要的数据,对象格式,节点的数字段都支持,默认为{text: '概要'}) |
|
||||
| REMOVE_GENERALIZATION(v0.2.0+) | 删除节点概要 | |
|
||||
| SET_NODE_CUSTOM_POSITION(v0.2.0+) | 设置节点自定义位置 | node(要设置的节点)、 left(自定义的x坐标,默认为undefined)、 top(自定义的y坐标,默认为undefined) |
|
||||
| RESET_LAYOUT(v0.2.0+) | 一键整理布局 | |
|
||||
| SET_NODE_SHAPE(v0.2.4+) | 设置节点形状 | node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js) |
|
||||
|
||||
### setData(data)
|
||||
|
||||
动态设置思维导图数据,纯节点数据
|
||||
|
||||
`data`:思维导图结构数据
|
||||
|
||||
### setFullData(*data*)
|
||||
|
||||
> v0.2.7+
|
||||
|
||||
动态设置思维导图数据,包括节点数据、布局、主题、视图
|
||||
|
||||
`data`:完整数据,结构可参考[exportFullData](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json)
|
||||
|
||||
### getData(withConfig)
|
||||
|
||||
> v0.2.9+
|
||||
|
||||
获取思维导图数据
|
||||
|
||||
`withConfig`:`Boolean`,默认为`false`,即获取的数据只包括节点树,如果传`true`则会包含主题、布局、视图等数据
|
||||
|
||||
### export(type, isDownload, fileName)
|
||||
|
||||
> 需要先注册`Export`插件
|
||||
|
||||
导出
|
||||
|
||||
`type`:要导出的类型,可选值:png、svg、json、pdf(v0.2.1+)、smm(本质也是json)
|
||||
|
||||
`isDownload`:是否需要直接触发下载,布尔值,默认为`false`
|
||||
|
||||
`fileName`:(v0.1.6+)导出文件的名称,默认为`思维导图`
|
||||
|
||||
### toPos(x, y)
|
||||
|
||||
> v0.1.5+
|
||||
|
||||
将浏览器可视窗口的坐标转换成相对于画布的坐标
|
||||
644
web/src/pages/Doc/zh/constructor/index.vue
Normal file
644
web/src/pages/Doc/zh/constructor/index.vue
Normal file
@@ -0,0 +1,644 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>构造函数</h1>
|
||||
<h2>基本使用</h2>
|
||||
<pre class="hljs"><code><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"mindMapContainer"</span>></span><span class="hljs-tag"></<span class="hljs-name">div</span>></span>
|
||||
</code></pre>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">"simple-mind-map"</span>;
|
||||
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">el</span>: <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'mindMapContainer'</span>),
|
||||
<span class="hljs-attr">data</span>: {
|
||||
<span class="hljs-string">"data"</span>: {
|
||||
<span class="hljs-string">"text"</span>: <span class="hljs-string">"根节点"</span>
|
||||
},
|
||||
<span class="hljs-string">"children"</span>: []
|
||||
}
|
||||
});
|
||||
</code></pre>
|
||||
<h2>实例化选项</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>字段名称</th>
|
||||
<th>类型</th>
|
||||
<th>默认值</th>
|
||||
<th>描述</th>
|
||||
<th>是否必填</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>el</td>
|
||||
<td>Element</td>
|
||||
<td></td>
|
||||
<td>容器元素,必须为DOM元素</td>
|
||||
<td>是</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data</td>
|
||||
<td>Object</td>
|
||||
<td>{}</td>
|
||||
<td>思维导图数据,可参考:<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exampleData.js</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>layout</td>
|
||||
<td>String</td>
|
||||
<td>logicalStructure</td>
|
||||
<td>布局类型,可选列表:logicalStructure(逻辑结构图)、mindMap(思维导图)、catalogOrganization(目录组织图)、organizationStructure(组织结构图)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>theme</td>
|
||||
<td>String</td>
|
||||
<td>default</td>
|
||||
<td>主题,可选列表:default(默认)、classic(脑图经典)、minions(小黄人)、pinkGrape(粉红葡萄)、mint(薄荷)、gold(金色vip)、vitalityOrange(活力橙)、greenLeaf(绿叶)、dark2(暗色2)、skyGreen(天清绿)、classic2(脑图经典2)、classic3(脑图经典3)、classic4(脑图经典4,v0.2.0+)、classicGreen(经典绿)、classicBlue(经典蓝)、blueSky(天空蓝)、brainImpairedPink(脑残粉)、dark(暗色)、earthYellow(泥土黄)、freshGreen(清新绿)、freshRed(清新红)、romanticPurple(浪漫紫)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>themeConfig</td>
|
||||
<td>Object</td>
|
||||
<td>{}</td>
|
||||
<td>主题配置,会和所选择的主题进行合并,可用字段可参考:<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js</a></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scaleRatio</td>
|
||||
<td>Number</td>
|
||||
<td>0.1</td>
|
||||
<td>放大缩小的增量比例</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>maxTag</td>
|
||||
<td>Number</td>
|
||||
<td>5</td>
|
||||
<td>节点里最多显示的标签数量,多余的会被丢弃</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>exportPadding</td>
|
||||
<td>Number</td>
|
||||
<td>20</td>
|
||||
<td>导出图片时的内边距</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>imgTextMargin</td>
|
||||
<td>Number</td>
|
||||
<td>5</td>
|
||||
<td>节点里图片和文字的间距</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textContentMargin</td>
|
||||
<td>Number</td>
|
||||
<td>2</td>
|
||||
<td>节点里各种文字信息的间距,如图标和文字的间距</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>selectTranslateStep</td>
|
||||
<td>Number</td>
|
||||
<td>3</td>
|
||||
<td>多选节点时鼠标移动到边缘时的画布移动偏移量</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>selectTranslateLimit</td>
|
||||
<td>Number</td>
|
||||
<td>20</td>
|
||||
<td>多选节点时鼠标移动距边缘多少距离时开始偏移</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>customNoteContentShow(v0.1.6+)</td>
|
||||
<td>Object</td>
|
||||
<td>null</td>
|
||||
<td>自定义节点备注内容显示,Object类型,结构为:{show: (noteContent, left, top) => {// 你的显示节点备注逻辑 }, hide: () => {// 你的隐藏节点备注逻辑 }}</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>readonly(v0.1.7+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>是否是只读模式</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>enableFreeDrag(v0.2.4+)</td>
|
||||
<td>Boolean</td>
|
||||
<td>false</td>
|
||||
<td>是否开启节点自由拖拽</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>watermarkConfig(v0.2.4+)</td>
|
||||
<td>Object</td>
|
||||
<td></td>
|
||||
<td>水印配置,详细配置请参考下方表格【水印配置】</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textAutoWrapWidth(v0.3.4+)</td>
|
||||
<td>Number</td>
|
||||
<td>500</td>
|
||||
<td>节点内每行文本达到该宽度后自动换行</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>水印配置</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>字段名称</th>
|
||||
<th>类型</th>
|
||||
<th>默认值</th>
|
||||
<th>描述</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>text</td>
|
||||
<td>String</td>
|
||||
<td>''</td>
|
||||
<td>水印文字,如果为空字符串则不显示水印</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lineSpacing</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>水印每行之间的间距</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textSpacing</td>
|
||||
<td>Number</td>
|
||||
<td>100</td>
|
||||
<td>同一行水印之间的间距</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>angle</td>
|
||||
<td>Number</td>
|
||||
<td>30</td>
|
||||
<td>水印的倾斜角度,范围:[0, 90]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>textStyle</td>
|
||||
<td>Object</td>
|
||||
<td>{color: '#999', opacity: 0.5, fontSize: 14}</td>
|
||||
<td>水印文字样式</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>静态方法</h2>
|
||||
<h3>defineTheme(name, config)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.23+</p>
|
||||
</blockquote>
|
||||
<p>定义新主题。</p>
|
||||
<p><code>name</code>:新主题名称</p>
|
||||
<p><code>config</code>:主题数据</p>
|
||||
<p><code>simple-mind-map</code>内置了众多主题,另外你也可以注册新主题,建议在实例化之前进行注册,这样在实例化时可以直接使用新注册的主题,使用示例:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> MindMap <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map'</span>
|
||||
<span class="hljs-comment">// 注册新主题</span>
|
||||
MindMap.defineTheme(<span class="hljs-string">'主题名称'</span>, {})
|
||||
|
||||
<span class="hljs-comment">// 1.实例化时使用新注册的主题</span>
|
||||
<span class="hljs-keyword">const</span> mindMap = <span class="hljs-keyword">new</span> MindMap({
|
||||
<span class="hljs-attr">theme</span>: <span class="hljs-string">'主题名称'</span>
|
||||
})
|
||||
|
||||
<span class="hljs-comment">// 2.动态切换新主题</span>
|
||||
mindMap.setTheme(<span class="hljs-string">'主题名称'</span>)
|
||||
</code></pre>
|
||||
<p>主题的所有配置可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/default.js">默认主题</a>。<code>defineTheme</code>方法会把你传入的配置和默认配置做合并。大部分主题其实需要自定义的部分不是很多,一个典型的自定义主题配置可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/themes/blueSky.js">blueSky</a>。</p>
|
||||
<h3>usePlugin(plugin)</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>注册插件,如果需要使用非核心的一些功能,比如小地图、水印等,可以通过该方法进行注册。可链式调用。</p>
|
||||
<p>注意:插件需要在实例化<code>MindMap</code>前注册。</p>
|
||||
<h2>静态属性</h2>
|
||||
<h3>pluginList</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>当前注册的所有插件列表。</p>
|
||||
<h2>实例方法</h2>
|
||||
<h3>getSvgData()</h3>
|
||||
<blockquote>
|
||||
<p>v0.3.0+</p>
|
||||
</blockquote>
|
||||
<p>获取<code>svg</code>数据,返回一个对象,详细结构如下:</p>
|
||||
<pre class="hljs"><code>{
|
||||
svg, <span class="hljs-comment">// Element,思维导图图形的整体svg元素,包括:svg(画布容器)、g(实际的思维导图组)</span>
|
||||
svgHTML, <span class="hljs-comment">// String,svg字符串,即html字符串,可以直接渲染到你准备的小地图容器内</span>
|
||||
<span class="hljs-attr">rect</span>: <span class="hljs-comment">// Object,思维导图图形未缩放时的位置尺寸等信息</span>
|
||||
origWidth, <span class="hljs-comment">// Number,画布宽度</span>
|
||||
origHeight, <span class="hljs-comment">// Number,画布高度</span>
|
||||
scaleX, <span class="hljs-comment">// Number,思维导图图形的水平缩放值</span>
|
||||
scaleY, <span class="hljs-comment">// Number,思维导图图形的垂直缩放值</span>
|
||||
}
|
||||
</code></pre>
|
||||
<h3>render(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>:<code>v0.3.2+</code>,<code>Function</code>,当重新渲染完成时调用</li>
|
||||
</ul>
|
||||
<p>触发整体渲染,会进行节点复用,性能较<code>reRender</code>会更好一点,如果只是节点位置变化了可以调用该方法进行渲染</p>
|
||||
<h3>reRender(callback)</h3>
|
||||
<ul>
|
||||
<li><code>callback</code>:<code>v0.3.2+</code>,<code>Function</code>,当重新渲染完成时调用</li>
|
||||
</ul>
|
||||
<p>整体重新渲染,会清空画布,节点也会重新创建,性能不好,慎重使用</p>
|
||||
<h3>resize()</h3>
|
||||
<p>容器尺寸变化后,需要调用该方法进行适应</p>
|
||||
<h3>setMode(mode)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.7+</p>
|
||||
</blockquote>
|
||||
<p>切换模式为只读或编辑。</p>
|
||||
<p><code>mode</code>:readonly、edit</p>
|
||||
<h3>on(event, fn)</h3>
|
||||
<p>监听事件,事件列表:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>事件名称</th>
|
||||
<th>描述</th>
|
||||
<th>回调参数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>data_change</td>
|
||||
<td>渲染树数据变化,可以监听该方法获取最新数据</td>
|
||||
<td>data(当前渲染树数据)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>view_data_change(v0.1.1+)</td>
|
||||
<td>视图变化数据,比如拖动或缩放时会触发</td>
|
||||
<td>data(当前视图状态数据)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>back_forward</td>
|
||||
<td>前进或回退</td>
|
||||
<td>activeHistoryIndex(当前在历史数据数组里的索引)、length(当前历史数据数组的长度)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>draw_click</td>
|
||||
<td><em>画布的单击事件</em></td>
|
||||
<td>e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>svg_mousedown</td>
|
||||
<td>svg画布的鼠标按下事件</td>
|
||||
<td>e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousedown</td>
|
||||
<td>el元素的鼠标按下事件</td>
|
||||
<td>e(事件对象)、this(Event事件类实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousemove</td>
|
||||
<td>el元素的鼠标移动事件</td>
|
||||
<td>e(事件对象)、this(Event事件类实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>drag</td>
|
||||
<td>如果是按住左键拖动的话会触发拖动事件</td>
|
||||
<td>e(事件对象)、this(Event事件类实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mouseup</td>
|
||||
<td>el元素的鼠标松开事件</td>
|
||||
<td>e(事件对象)、this(Event事件类实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>mousewheel</td>
|
||||
<td>鼠标滚动事件</td>
|
||||
<td>e(事件对象)、dir(向上up还是向下down滚动)、this(Event事件类实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>contextmenu</td>
|
||||
<td>svg画布的鼠标右键菜单事件</td>
|
||||
<td>e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_click</td>
|
||||
<td>节点的单击事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mousedown</td>
|
||||
<td>节点的鼠标按下事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_mouseup</td>
|
||||
<td>节点的鼠标松开事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_dblclick</td>
|
||||
<td>节点的双击事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_contextmenu</td>
|
||||
<td>节点的右键菜单事件</td>
|
||||
<td>e(事件对象)、this(节点实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_node_active</td>
|
||||
<td>节点激活前事件</td>
|
||||
<td>this(节点实例)、activeNodeList(当前激活的所有节点列表)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_active</td>
|
||||
<td>节点激活事件</td>
|
||||
<td>this(节点实例)、activeNodeList(当前激活的所有节点列表)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>expand_btn_click</td>
|
||||
<td>节点展开或收缩事件</td>
|
||||
<td>this(节点实例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>before_show_text_edit</td>
|
||||
<td>节点文本编辑框即将打开事件</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hide_text_edit</td>
|
||||
<td>节点文本编辑框关闭事件</td>
|
||||
<td>textEditNode(文本编辑框DOM节点)、activeNodeList(当前激活的所有节点列表)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>scale</td>
|
||||
<td>放大缩小事件</td>
|
||||
<td>scale(缩放比例)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_img_dblclick(v0.2.15+)</td>
|
||||
<td>节点内图片的双击事件</td>
|
||||
<td>this(节点实例)、e(事件对象)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>node_tree_render_end(v0.2.16+)</td>
|
||||
<td>节点树渲染完毕事件</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>emit(event, ...args)</h3>
|
||||
<p>触发事件,可以是上面表格里的事件,也可以是自定义事件</p>
|
||||
<h3>off(event, fn)</h3>
|
||||
<p>解绑事件</p>
|
||||
<h3>setTheme(theme)</h3>
|
||||
<p>切换主题,可选主题见上面的选项表格</p>
|
||||
<h3>getTheme()</h3>
|
||||
<p>获取当前主题</p>
|
||||
<h3>setThemeConfig(config)</h3>
|
||||
<p>设置主题配置,<code>config</code>同上面选项表格里的选项<code>themeConfig</code></p>
|
||||
<h3>getCustomThemeConfig()</h3>
|
||||
<p>获取自定义主题配置</p>
|
||||
<h3>getThemeConfig(prop)</h3>
|
||||
<p>获取某个主题配置属性值</p>
|
||||
<h3>getConfig(<em>prop</em>)</h3>
|
||||
<blockquote>
|
||||
<p>0.2.24+</p>
|
||||
</blockquote>
|
||||
<p><code>prop</code>:获取指定配置的值,不传则返回整个配置</p>
|
||||
<p>获取配置,即<code>new MindMap(opt)</code>的<code>opt</code></p>
|
||||
<h3>updateConfig(<em>opt</em> = {})</h3>
|
||||
<blockquote>
|
||||
<p>0.2.24+</p>
|
||||
</blockquote>
|
||||
<p><code>opt</code>:要更新的配置</p>
|
||||
<p>更新配置,即更新<code>new MindMap(opt)</code>的<code>opt</code>,可以只更新部分数据,比如:</p>
|
||||
<pre class="hljs"><code>mindMap.updateConfig({
|
||||
<span class="hljs-attr">enableFreeDrag</span>: <span class="hljs-literal">true</span><span class="hljs-comment">// 开启节点自由拖拽</span>
|
||||
})
|
||||
</code></pre>
|
||||
<p>该方法只做更新配置的事情,没有其他副作用,比如触发画布重新渲染之类的</p>
|
||||
<h3>getLayout()</h3>
|
||||
<p>获取当前的布局结构</p>
|
||||
<h3>setLayout(layout)</h3>
|
||||
<p>设置布局结构,可选值见上面选项表格的<code>layout</code>字段</p>
|
||||
<h3>execCommand(name, ...args)</h3>
|
||||
<p>执行命令,每执行一个命令就会在历史堆栈里添加一条记录用于回退或前进。所有命令如下:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>命令名称</th>
|
||||
<th>描述</th>
|
||||
<th>参数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>SELECT_ALL</td>
|
||||
<td>全选</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BACK</td>
|
||||
<td>回退指定的步数</td>
|
||||
<td>step(要回退的步数,默认为1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FORWARD</td>
|
||||
<td>前进指定的步数</td>
|
||||
<td>step(要前进的步数,默认为1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_NODE</td>
|
||||
<td>插入同级节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_CHILD_NODE</td>
|
||||
<td>插入子节点,操作节点为当前激活的节点</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UP_NODE</td>
|
||||
<td>上移节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的第一个节点使用无效</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DOWN_NODE</td>
|
||||
<td>操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点或在列表里的最后一个节点使用无效</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>REMOVE_NODE</td>
|
||||
<td>删除节点,操作节点为当前激活的节点</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PASTE_NODE</td>
|
||||
<td>粘贴节点到节点,操作节点为当前激活的节点</td>
|
||||
<td>data(要粘贴的节点数据,一般通过<code>renderer.copyNode()</code>方法和<code>renderer.cutNode()</code>方法获取)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CUT_NODE</td>
|
||||
<td>剪切节点,操作节点为当前激活的节点,如果有多个激活节点,只会对第一个有效,对根节点使用无效</td>
|
||||
<td>callback(回调函数,剪切的节点数据会通过调用该函数并通过参数返回)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_STYLE</td>
|
||||
<td>修改节点样式</td>
|
||||
<td>node(要设置样式的节点)、prop(样式属性)、value(样式属性值)、isActive(布尔值,是否设置的是激活状态的样式)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_ACTIVE</td>
|
||||
<td>设置节点是否激活</td>
|
||||
<td>node(要设置的节点)、active(布尔值,是否激活)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CLEAR_ACTIVE_NODE</td>
|
||||
<td>清除当前已激活节点的激活状态,操作节点为当前激活的节点</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_EXPAND</td>
|
||||
<td>设置节点是否展开</td>
|
||||
<td>node(要设置的节点)、expand(布尔值,是否展开)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EXPAND_ALL</td>
|
||||
<td>展开所有节点</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UNEXPAND_ALL</td>
|
||||
<td>收起所有节点</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>UNEXPAND_TO_LEVEL(v0.2.8+)</td>
|
||||
<td>展开到指定层级</td>
|
||||
<td>level(要展开到的层级,1、2、3...)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_DATA</td>
|
||||
<td>更新节点数据,即更新节点数据对象里<code>data</code>对象的数据</td>
|
||||
<td>node(要设置的节点)、data(对象,要更新的数据,如<code>{expand: true}</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_TEXT</td>
|
||||
<td>设置节点文本</td>
|
||||
<td>node(要设置的节点)、text(要设置的文本字符串,换行可以使用<code>\n</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_IMAGE</td>
|
||||
<td>设置节点图片</td>
|
||||
<td>node(要设置的节点)、imgData(对象,图片信息,结构为:<code>{url, title, width, height}</code>,图片的宽高必须要传)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_ICON</td>
|
||||
<td>设置节点图标</td>
|
||||
<td>node(要设置的节点)、icons(数组,预定义的图片名称组成的数组,可用图标可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js</a>文件里的<code>nodeIconList</code>列表里获取到,图标名称为<code>type_name</code>,如<code>['priority_1']</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_HYPERLINK</td>
|
||||
<td>设置节点超链接</td>
|
||||
<td>node(要设置的节点)、link(超链接地址)、title(超链接名称,可选)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_NOTE</td>
|
||||
<td>设置节点备注</td>
|
||||
<td>node(要设置的节点)、note(备注文字)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_TAG</td>
|
||||
<td>设置节点标签</td>
|
||||
<td>node(要设置的节点)、tag(字符串数组,内置颜色信息可在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js">https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/utils/constant.js</a>里获取到)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_AFTER(v0.1.5+)</td>
|
||||
<td>将节点移动到另一个节点的后面</td>
|
||||
<td>node(要移动的节点)、 exist(目标节点)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>INSERT_BEFORE(v0.1.5+)</td>
|
||||
<td>将节点移动到另一个节点的前面</td>
|
||||
<td>node(要移动的节点)、 exist(目标节点)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MOVE_NODE_TO(v0.1.5+)</td>
|
||||
<td>移动一个节点作为另一个节点的子节点</td>
|
||||
<td>node(要移动的节点)、 toNode(目标节点)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ADD_GENERALIZATION(v0.2.0+)</td>
|
||||
<td>添加节点概要</td>
|
||||
<td>data(概要的数据,对象格式,节点的数字段都支持,默认为{text: '概要'})</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>REMOVE_GENERALIZATION(v0.2.0+)</td>
|
||||
<td>删除节点概要</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_CUSTOM_POSITION(v0.2.0+)</td>
|
||||
<td>设置节点自定义位置</td>
|
||||
<td>node(要设置的节点)、 left(自定义的x坐标,默认为undefined)、 top(自定义的y坐标,默认为undefined)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>RESET_LAYOUT(v0.2.0+)</td>
|
||||
<td>一键整理布局</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_NODE_SHAPE(v0.2.4+)</td>
|
||||
<td>设置节点形状</td>
|
||||
<td>node(要设置的节点)、shape(形状,全部形状:https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/Shape.js)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>setData(data)</h3>
|
||||
<p>动态设置思维导图数据,纯节点数据</p>
|
||||
<p><code>data</code>:思维导图结构数据</p>
|
||||
<h3>setFullData(<em>data</em>)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.7+</p>
|
||||
</blockquote>
|
||||
<p>动态设置思维导图数据,包括节点数据、布局、主题、视图</p>
|
||||
<p><code>data</code>:完整数据,结构可参考<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/example/exportFullData.json">exportFullData</a></p>
|
||||
<h3>getData(withConfig)</h3>
|
||||
<blockquote>
|
||||
<p>v0.2.9+</p>
|
||||
</blockquote>
|
||||
<p>获取思维导图数据</p>
|
||||
<p><code>withConfig</code>:<code>Boolean</code>,默认为<code>false</code>,即获取的数据只包括节点树,如果传<code>true</code>则会包含主题、布局、视图等数据</p>
|
||||
<h3>export(type, isDownload, fileName)</h3>
|
||||
<blockquote>
|
||||
<p>需要先注册<code>Export</code>插件</p>
|
||||
</blockquote>
|
||||
<p>导出</p>
|
||||
<p><code>type</code>:要导出的类型,可选值:png、svg、json、pdf(v0.2.1+)、smm(本质也是json)</p>
|
||||
<p><code>isDownload</code>:是否需要直接触发下载,布尔值,默认为<code>false</code></p>
|
||||
<p><code>fileName</code>:(v0.1.6+)导出文件的名称,默认为<code>思维导图</code></p>
|
||||
<h3>toPos(x, y)</h3>
|
||||
<blockquote>
|
||||
<p>v0.1.5+</p>
|
||||
</blockquote>
|
||||
<p>将浏览器可视窗口的坐标转换成相对于画布的坐标</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
51
web/src/pages/Doc/zh/doExport/index.md
Normal file
51
web/src/pages/Doc/zh/doExport/index.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Export 插件
|
||||
|
||||
`Export`插件提供导出的功能。
|
||||
|
||||
## 注册
|
||||
|
||||
```js
|
||||
import MindMap from 'simple-mind-map'
|
||||
import Export from 'simple-mind-map/src/Export.js'
|
||||
|
||||
MindMap.usePlugin(Export)
|
||||
```
|
||||
|
||||
注册完且实例化`MindMap`后可通过`mindMap.doExport`获取到该实例。
|
||||
|
||||
## 方法
|
||||
|
||||
### png()
|
||||
|
||||
导出为`png`,异步方法,返回图片数据,`data:url`数据,可以自行下载或显示
|
||||
|
||||
### svg()
|
||||
|
||||
导出为`svg`,异步方法,返回`svg`数据,`data:url`数据,可以自行下载或显示
|
||||
|
||||
### getSvgData()
|
||||
|
||||
获取`svg`数据,异步方法,返回一个对象:
|
||||
|
||||
```js
|
||||
{
|
||||
node// svg对象
|
||||
str// svg字符串
|
||||
}
|
||||
```
|
||||
|
||||
### pdf(name)
|
||||
|
||||
> v0.2.1+
|
||||
|
||||
`name`:文件名称
|
||||
|
||||
导出为`pdf`
|
||||
|
||||
### json(name, withConfig)
|
||||
|
||||
`name`:暂时没有用处,传空字符串即可
|
||||
|
||||
`withConfig``:Boolean`, 默认为`true`,数据中是否包含配置,否则为纯思维导图节点数据
|
||||
|
||||
返回`json`数据,`data:url`数据,可以自行下载
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user