mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-22 09:10:29 +08:00
Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b04469649a | ||
|
|
ee57dbdcc5 | ||
|
|
bca744f6fc | ||
|
|
442408dacf | ||
|
|
7297f0a082 | ||
|
|
f0d90941fb | ||
|
|
830962c044 | ||
|
|
eeec71dc65 | ||
|
|
9bd87a22f3 | ||
|
|
88c9f22a15 | ||
|
|
7380fc60d5 | ||
|
|
a178b99d73 | ||
|
|
af9ee04aaf | ||
|
|
01dc98f1f8 | ||
|
|
cbd07246bd | ||
|
|
5bb23ca738 | ||
|
|
0886ba7698 | ||
|
|
a65cffa58b | ||
|
|
02e2d432dd | ||
|
|
c8d23cab40 | ||
|
|
244ced83bc | ||
|
|
5c9c3d7934 | ||
|
|
4ca6713675 | ||
|
|
3d18404fd6 | ||
|
|
98dda26bf8 | ||
|
|
cd4c5ecd83 | ||
|
|
fdc0017ccb | ||
|
|
20a5c12bbb | ||
|
|
4eacec125e |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2021-2023 The MindMap Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
17
README.md
17
README.md
@@ -19,6 +19,12 @@
|
||||
|
||||
在线地址:[https://wanglin2.github.io/mind-map/](https://wanglin2.github.io/mind-map/)
|
||||
|
||||
另外也提供了客户端可供下载使用,支持`Windows`、`Mac`及`Linux`,下载地址:
|
||||
|
||||
Github:[releases](https://github.com/wanglin2/mind-map/releases)。
|
||||
|
||||
百度云盘:[地址](https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3)。
|
||||
|
||||
# 特性
|
||||
|
||||
- [x] 插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小打包体积
|
||||
@@ -84,4 +90,13 @@ MIT
|
||||
|
||||
# 微信交流群
|
||||
|
||||

|
||||
<img src="./qrcode.jpg" style="width: 300px" />
|
||||
|
||||
# 请作者喝杯咖啡
|
||||
|
||||
> 厚椰乳一盒 + 纯牛奶半盒 + 冰块 + 咖啡液 = 生椰拿铁 yyds
|
||||
|
||||
<p>
|
||||
<img src="./web/src/assets/img/alipay.jpg" style="width: 300px" />
|
||||
<img src="./web/src/assets/img/wechat.jpg" style="width: 300px" />
|
||||
</p>
|
||||
File diff suppressed because one or more lines are too long
BIN
qrcode.jpg
BIN
qrcode.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
@@ -10,7 +10,7 @@ import BatchExecution from './src/BatchExecution'
|
||||
import { layoutValueList, CONSTANTS } from './src/utils/constant'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import { simpleDeepClone } from './src/utils'
|
||||
import defaultTheme from './src/themes/default'
|
||||
import defaultTheme, { checkIsNodeSizeIndependenceConfig } from './src/themes/default'
|
||||
|
||||
// 默认选项配置
|
||||
const defaultOpt = {
|
||||
@@ -118,7 +118,11 @@ const defaultOpt = {
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
]
|
||||
],
|
||||
// 节点最大缓存数量
|
||||
maxNodeCacheCount: 1000,
|
||||
// 关联线默认文字
|
||||
defaultAssociativeLineText: '关联'
|
||||
}
|
||||
|
||||
// 思维导图
|
||||
@@ -208,12 +212,12 @@ class MindMap {
|
||||
}
|
||||
|
||||
// 重新渲染
|
||||
reRender(callback) {
|
||||
reRender(callback, source = '') {
|
||||
this.batchExecution.push('render', () => {
|
||||
this.draw.clear()
|
||||
this.initTheme()
|
||||
this.renderer.reRender = true
|
||||
this.renderer.render(callback)
|
||||
this.renderer.render(callback, source)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -263,7 +267,9 @@ class MindMap {
|
||||
// 设置主题配置
|
||||
setThemeConfig(config) {
|
||||
this.opt.themeConfig = config
|
||||
this.render(null, CONSTANTS.CHANGE_THEME)
|
||||
// 检查改变的是否是节点大小无关的主题属性
|
||||
let res = checkIsNodeSizeIndependenceConfig(config)
|
||||
this.render(null, res ? '' : CONSTANTS.CHANGE_THEME)
|
||||
}
|
||||
|
||||
// 获取自定义主题配置
|
||||
@@ -318,7 +324,7 @@ class MindMap {
|
||||
} else {
|
||||
this.renderer.renderTree = data
|
||||
}
|
||||
this.reRender()
|
||||
this.reRender(() => {}, CONSTANTS.SET_DATA)
|
||||
}
|
||||
|
||||
// 动态设置思维导图数据,包括节点数据、布局、主题、视图
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.5.9",
|
||||
"version": "0.5.11",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
|
||||
@@ -3,13 +3,13 @@ import { v4 as uuid } from 'uuid'
|
||||
import {
|
||||
getAssociativeLineTargetIndex,
|
||||
computeCubicBezierPathPoints,
|
||||
joinCubicBezierPath,
|
||||
cubicBezierPath,
|
||||
getNodePoint,
|
||||
computeNodePoints,
|
||||
getNodeLinePath,
|
||||
getDefaultControlPointOffsets
|
||||
getNodeLinePath
|
||||
} from './utils/associativeLineUtils'
|
||||
import associativeLineControlsMethods from './utils/associativeLineControls'
|
||||
import associativeLineTextMethods from './utils/associativeLineText'
|
||||
|
||||
// 关联线类
|
||||
class AssociativeLine {
|
||||
@@ -46,6 +46,14 @@ class AssociativeLine {
|
||||
}
|
||||
// 节流一下,不然很卡
|
||||
this.checkOverlapNode = throttle(this.checkOverlapNode, 100, this)
|
||||
// 控制点相关方法
|
||||
Object.keys(associativeLineControlsMethods).forEach(item => {
|
||||
this[item] = associativeLineControlsMethods[item].bind(this)
|
||||
})
|
||||
// 关联线文字相关方法
|
||||
Object.keys(associativeLineTextMethods).forEach(item => {
|
||||
this[item] = associativeLineTextMethods[item].bind(this)
|
||||
})
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
@@ -89,6 +97,8 @@ class AssociativeLine {
|
||||
window.addEventListener('mouseup', e => {
|
||||
this.onControlPointMouseup(e)
|
||||
})
|
||||
// 缩放事件
|
||||
this.mindMap.on('scale', this.onScale)
|
||||
}
|
||||
|
||||
// 创建箭头
|
||||
@@ -177,36 +187,46 @@ class AssociativeLine {
|
||||
.stroke({ width: associativeLineActiveWidth, color: 'transparent' })
|
||||
.fill({ color: 'none' })
|
||||
clickPath.plot(pathStr)
|
||||
// 文字
|
||||
let text = this.createText({ path, clickPath, node, toNode, startPoint, endPoint, controlPoints })
|
||||
// 点击事件
|
||||
clickPath.click(e => {
|
||||
e.stopPropagation()
|
||||
// 如果当前存在激活节点,那么取消激活节点
|
||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||
this.clearActiveNodes()
|
||||
} else {
|
||||
// 否则清除当前的关联线的激活状态,如果有的话
|
||||
this.clearActiveLine()
|
||||
// 保存当前激活的关联线信息
|
||||
this.activeLine = [path, clickPath, node, toNode]
|
||||
// 让不可见的点击线显示
|
||||
clickPath.stroke({ color: associativeLineActiveColor })
|
||||
// 渲染控制点和连线
|
||||
this.renderControls(
|
||||
startPoint,
|
||||
endPoint,
|
||||
controlPoints[0],
|
||||
controlPoints[1]
|
||||
)
|
||||
this.mindMap.emit(
|
||||
'associative_line_click',
|
||||
path,
|
||||
clickPath,
|
||||
node,
|
||||
toNode
|
||||
)
|
||||
}
|
||||
this.setActiveLine({ path, clickPath, text, node, toNode, startPoint, endPoint, controlPoints })
|
||||
})
|
||||
this.lineList.push([path, clickPath, node, toNode])
|
||||
// 渲染关联线文字
|
||||
this.renderText(this.getText(node, toNode), path, text)
|
||||
this.lineList.push([path, clickPath, text, node, toNode])
|
||||
}
|
||||
|
||||
// 激活某根关联线
|
||||
setActiveLine({ path, clickPath, text, node, toNode, startPoint, endPoint, controlPoints }) {
|
||||
let {
|
||||
associativeLineActiveColor
|
||||
} = this.mindMap.themeConfig
|
||||
// 如果当前存在激活节点,那么取消激活节点
|
||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||
this.clearActiveNodes()
|
||||
} else {
|
||||
// 否则清除当前的关联线的激活状态,如果有的话
|
||||
this.clearActiveLine()
|
||||
// 保存当前激活的关联线信息
|
||||
this.activeLine = [path, clickPath, text, node, toNode]
|
||||
// 让不可见的点击线显示
|
||||
clickPath.stroke({ color: associativeLineActiveColor })
|
||||
// 如果没有输入过关联线文字,那么显示默认文字
|
||||
if (!this.getText(node, toNode)) {
|
||||
this.renderText(this.mindMap.opt.defaultAssociativeLineText, path, text)
|
||||
}
|
||||
// 渲染控制点和连线
|
||||
this.renderControls(
|
||||
startPoint,
|
||||
endPoint,
|
||||
controlPoints[0],
|
||||
controlPoints[1]
|
||||
)
|
||||
this.mindMap.emit('associative_line_click', path, clickPath, node, toNode)
|
||||
}
|
||||
}
|
||||
|
||||
// 移除所有连接线
|
||||
@@ -214,6 +234,7 @@ class AssociativeLine {
|
||||
this.lineList.forEach(line => {
|
||||
line[0].remove()
|
||||
line[1].remove()
|
||||
line[2].remove()
|
||||
})
|
||||
this.lineList = []
|
||||
}
|
||||
@@ -253,7 +274,8 @@ class AssociativeLine {
|
||||
updateCreatingLine(e) {
|
||||
let { x, y } = this.getTransformedEventPos(e)
|
||||
let startPoint = getNodePoint(this.creatingStartNode)
|
||||
let pathStr = cubicBezierPath(startPoint.x, startPoint.y, x, y)
|
||||
let offsetX = x > startPoint.x ? -10 : 10
|
||||
let pathStr = cubicBezierPath(startPoint.x, startPoint.y, x + offsetX, y)
|
||||
this.creatingLine.plot(pathStr)
|
||||
this.checkOverlapNode(x, y)
|
||||
}
|
||||
@@ -349,20 +371,33 @@ class AssociativeLine {
|
||||
// 删除连接线
|
||||
removeLine() {
|
||||
if (!this.activeLine) return
|
||||
let [, , node, toNode] = this.activeLine
|
||||
let [, , , node, toNode] = this.activeLine
|
||||
this.removeControls()
|
||||
let { associativeLineTargets, associativeLineTargetControlOffsets } =
|
||||
let { associativeLineTargets, associativeLineTargetControlOffsets, associativeLineText } =
|
||||
node.nodeData.data
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
// 更新关联线文本数据
|
||||
let newAssociativeLineText = {}
|
||||
if (associativeLineText) {
|
||||
Object.keys(associativeLineText).forEach((item) => {
|
||||
if (item !== toNode.nodeData.data.id) {
|
||||
newAssociativeLineText[item] = associativeLineText[item]
|
||||
}
|
||||
})
|
||||
}
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
// 目标
|
||||
associativeLineTargets: associativeLineTargets.filter((_, index) => {
|
||||
return index !== targetIndex
|
||||
}),
|
||||
// 偏移量
|
||||
associativeLineTargetControlOffsets: associativeLineTargetControlOffsets
|
||||
? associativeLineTargetControlOffsets.filter((_, index) => {
|
||||
return index !== targetIndex
|
||||
})
|
||||
: []
|
||||
: [],
|
||||
// 文本
|
||||
associativeLineText: newAssociativeLineText
|
||||
})
|
||||
}
|
||||
|
||||
@@ -376,9 +411,16 @@ class AssociativeLine {
|
||||
// 清除激活的线
|
||||
clearActiveLine() {
|
||||
if (this.activeLine) {
|
||||
this.activeLine[1].stroke({
|
||||
let [, clickPath, text, node, toNode] = this.activeLine
|
||||
clickPath.stroke({
|
||||
color: 'transparent'
|
||||
})
|
||||
// 隐藏关联线文本编辑框
|
||||
this.hideEditTextBox()
|
||||
// 如果当前关联线没有文字,则清空文字节点
|
||||
if (!this.getText(node, toNode)) {
|
||||
text.clear()
|
||||
}
|
||||
this.activeLine = null
|
||||
this.removeControls()
|
||||
}
|
||||
@@ -391,6 +433,7 @@ class AssociativeLine {
|
||||
this.lineList.forEach(line => {
|
||||
line[0].hide()
|
||||
line[1].hide()
|
||||
line[2].hide()
|
||||
})
|
||||
this.hideControls()
|
||||
}
|
||||
@@ -401,225 +444,11 @@ class AssociativeLine {
|
||||
this.lineList.forEach(line => {
|
||||
line[0].show()
|
||||
line[1].show()
|
||||
line[2].show()
|
||||
})
|
||||
this.showControls()
|
||||
this.isNodeDragging = false
|
||||
}
|
||||
|
||||
// 创建控制点、连线节点
|
||||
createControlNodes() {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
// 连线
|
||||
this.controlLine1 = this.draw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
this.controlLine2 = this.draw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
// 控制点
|
||||
this.controlPoint1 = this.createOneControlNode('controlPoint1')
|
||||
this.controlPoint2 = this.createOneControlNode('controlPoint2')
|
||||
}
|
||||
|
||||
// 创建控制点
|
||||
createOneControlNode(pointKey) {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
return this.draw
|
||||
.circle(this.controlPointDiameter)
|
||||
.stroke({ color: associativeLineActiveColor })
|
||||
.fill({ color: '#fff' })
|
||||
.click(e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
.mousedown(e => {
|
||||
this.onControlPointMousedown(e, pointKey)
|
||||
})
|
||||
}
|
||||
|
||||
// 控制点的鼠标按下事件
|
||||
onControlPointMousedown(e, pointKey) {
|
||||
e.stopPropagation()
|
||||
this.isControlPointMousedown = true
|
||||
this.mousedownControlPointKey = pointKey
|
||||
}
|
||||
|
||||
// 控制点的鼠标移动事件
|
||||
onControlPointMousemove(e) {
|
||||
if (
|
||||
!this.isControlPointMousedown ||
|
||||
!this.mousedownControlPointKey ||
|
||||
!this[this.mousedownControlPointKey]
|
||||
)
|
||||
return
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
let radius = this.controlPointDiameter / 2
|
||||
// 转换鼠标当前的位置
|
||||
let { x, y } = this.getTransformedEventPos(e)
|
||||
this.controlPointMousemoveState.pos = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
// 更新当前拖拽的控制点的位置
|
||||
this[this.mousedownControlPointKey].x(x - radius).y(y - radius)
|
||||
let [path, clickPath, node, toNode] = this.activeLine
|
||||
let [startPoint, endPoint] = computeNodePoints(node, toNode)
|
||||
this.controlPointMousemoveState.startPoint = startPoint
|
||||
this.controlPointMousemoveState.endPoint = endPoint
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
this.controlPointMousemoveState.targetIndex = targetIndex
|
||||
let offsets = []
|
||||
let associativeLineTargetControlOffsets = node.nodeData.data.associativeLineTargetControlOffsets
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsets = getDefaultControlPointOffsets(startPoint, endPoint)
|
||||
} else {
|
||||
offsets = associativeLineTargetControlOffsets[targetIndex]
|
||||
}
|
||||
let point1 = null
|
||||
let point2 = null
|
||||
// 拖拽的是控制点1
|
||||
if (this.mousedownControlPointKey === 'controlPoint1') {
|
||||
point1 = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
point2 = {
|
||||
x: endPoint.x + offsets[1].x,
|
||||
y: endPoint.y + offsets[1].y
|
||||
}
|
||||
// 更新控制点1的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
} else {
|
||||
// 拖拽的是控制点2
|
||||
point1 = {
|
||||
x: startPoint.x + offsets[0].x,
|
||||
y: startPoint.y + offsets[0].y
|
||||
}
|
||||
point2 = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
// 更新控制点2的连线
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
}
|
||||
// 更新关联线
|
||||
let pathStr = joinCubicBezierPath(startPoint, endPoint, point1, point2)
|
||||
path.plot(pathStr)
|
||||
clickPath.plot(pathStr)
|
||||
}
|
||||
|
||||
// 控制点的鼠标移动事件
|
||||
onControlPointMouseup(e) {
|
||||
if (!this.isControlPointMousedown) return
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
let { pos, startPoint, endPoint, targetIndex } =
|
||||
this.controlPointMousemoveState
|
||||
let [, , node] = this.activeLine
|
||||
let offsetList = []
|
||||
let associativeLineTargetControlOffsets = node.nodeData.data.associativeLineTargetControlOffsets
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsetList[targetIndex] = getDefaultControlPointOffsets(startPoint, endPoint)
|
||||
} else {
|
||||
offsetList = associativeLineTargetControlOffsets
|
||||
}
|
||||
let offset1 = null
|
||||
let offset2 = null
|
||||
if (this.mousedownControlPointKey === 'controlPoint1') {
|
||||
// 更新控制点1数据
|
||||
offset1 = {
|
||||
x: pos.x - startPoint.x,
|
||||
y: pos.y - startPoint.y
|
||||
}
|
||||
offset2 = offsetList[targetIndex][1]
|
||||
} else {
|
||||
// 更新控制点2数据
|
||||
offset1 = offsetList[targetIndex][0]
|
||||
offset2 = {
|
||||
x: pos.x - endPoint.x,
|
||||
y: pos.y - endPoint.y
|
||||
}
|
||||
}
|
||||
offsetList[targetIndex] = [offset1, offset2]
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
associativeLineTargetControlOffsets: offsetList
|
||||
})
|
||||
// 这里要加个setTimeout0是因为draw_click事件比mouseup事件触发的晚,所以重置isControlPointMousedown需要等draw_click事件触发完以后
|
||||
setTimeout(() => {
|
||||
this.resetControlPoint()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// 复位控制点移动
|
||||
resetControlPoint() {
|
||||
this.isControlPointMousedown = false
|
||||
this.mousedownControlPointKey = ''
|
||||
this.controlPointMousemoveState = {
|
||||
pos: null,
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
targetIndex: ''
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染控制点
|
||||
renderControls(startPoint, endPoint, point1, point2) {
|
||||
if (!this.controlLine1) {
|
||||
this.createControlNodes()
|
||||
}
|
||||
let radius = this.controlPointDiameter / 2
|
||||
// 控制点和起终点的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
// 控制点
|
||||
this.controlPoint1.x(point1.x - radius).y(point1.y - radius)
|
||||
this.controlPoint2.x(point2.x - radius).y(point2.y - radius)
|
||||
}
|
||||
|
||||
// 删除控制点
|
||||
removeControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.remove()
|
||||
})
|
||||
this.controlLine1 = null
|
||||
this.controlLine2 = null
|
||||
this.controlPoint1 = null
|
||||
this.controlPoint2 = null
|
||||
}
|
||||
|
||||
// 隐藏控制点
|
||||
hideControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.hide()
|
||||
})
|
||||
}
|
||||
|
||||
// 显示控制点
|
||||
showControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.show()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
AssociativeLine.instanceName = 'associativeLine'
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class KeyCommand {
|
||||
if (this.mindMap.richText && this.mindMap.richText.showTextEdit) {
|
||||
return
|
||||
}
|
||||
if (this.mindMap.renderer.textEdit.showTextEdit) {
|
||||
if (this.mindMap.renderer.textEdit.showTextEdit || (this.mindMap.associativeLine && this.mindMap.associativeLine.showTextEdit)) {
|
||||
return
|
||||
}
|
||||
this.isInSvg = false
|
||||
|
||||
@@ -266,7 +266,6 @@ class Render {
|
||||
// 重新渲染需要清除激活状态
|
||||
if (this.reRender) {
|
||||
this.clearActive()
|
||||
this.layout.clearNodePool()
|
||||
}
|
||||
// 计算布局
|
||||
this.layout.doLayout(root => {
|
||||
@@ -289,6 +288,11 @@ class Render {
|
||||
if (this.hasWaitRendering) {
|
||||
this.hasWaitRendering = false
|
||||
this.render(callback, source)
|
||||
} else {
|
||||
// 触发一次保存,因为修改了渲染树的数据
|
||||
if (this.mindMap.richText && [CONSTANTS.CHANGE_THEME, CONSTANTS.SET_DATA].includes(source)) {
|
||||
this.mindMap.command.addHistory()
|
||||
}
|
||||
}
|
||||
}
|
||||
let { enableNodeTransitionMove, nodeTransitionMoveDuration } =
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Node from '../Node'
|
||||
import { CONSTANTS, initRootNodePositionMap } from '../utils/constant'
|
||||
import Lru from '../utils/Lru'
|
||||
|
||||
// 布局基类
|
||||
class Base {
|
||||
@@ -13,8 +14,7 @@ class Base {
|
||||
this.draw = this.mindMap.draw
|
||||
// 根节点
|
||||
this.root = null
|
||||
// 保存所有uid和节点,用于复用
|
||||
this.nodePool = {}
|
||||
this.lru = new Lru(this.mindMap.opt.maxNodeCacheCount)
|
||||
}
|
||||
|
||||
// 计算节点位置
|
||||
@@ -40,16 +40,7 @@ class Base {
|
||||
// 记录本次渲染时的节点
|
||||
this.renderer.nodeCache[uid] = node
|
||||
// 记录所有渲染时的节点
|
||||
this.nodePool[uid] = node
|
||||
// 如果总缓存数量达到1000,直接清空
|
||||
if (Object.keys(this.nodePool).length > 1000) {
|
||||
this.clearNodePool()
|
||||
}
|
||||
}
|
||||
|
||||
// 清空节点存储池
|
||||
clearNodePool() {
|
||||
this.nodePool = {}
|
||||
this.lru.add(uid, node)
|
||||
}
|
||||
|
||||
// 检查当前来源是否需要重新计算节点大小
|
||||
@@ -72,9 +63,9 @@ class Base {
|
||||
newNode.getSize()
|
||||
newNode.needLayout = true
|
||||
}
|
||||
} else if (this.nodePool[data.data.uid] && !this.renderer.reRender) {
|
||||
} else if (this.lru.has(data.data.uid) && !this.renderer.reRender) {
|
||||
// 数据上没有保存节点引用,但是通过uid找到了缓存的节点,也可以复用
|
||||
newNode = this.nodePool[data.data.uid]
|
||||
newNode = this.lru.get(data.data.uid)
|
||||
// 保存该节点上一次的数据
|
||||
let lastData = JSON.stringify(newNode.nodeData.data)
|
||||
newNode.reset()
|
||||
|
||||
57
simple-mind-map/src/themes/autumn.js
Normal file
57
simple-mind-map/src/themes/autumn.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
// 秋天
|
||||
export default merge(defaultTheme, {
|
||||
// 背景颜色
|
||||
backgroundColor: '#fff2df',
|
||||
// 连线的颜色
|
||||
lineColor: '#b0bc47',
|
||||
lineWidth: 3,
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 3,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#b0bc47',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: '#e68112',
|
||||
color: '#fff',
|
||||
borderColor: '#e68112',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 3
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
fillColor: '#ffd683',
|
||||
color: '#8c5416',
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#e68112'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#8c5416',
|
||||
active: {
|
||||
borderColor: '#b0bc47'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fontSize: 14,
|
||||
fillColor: '#ffd683',
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 2,
|
||||
color: '#8c5416',
|
||||
active: {
|
||||
borderColor: '#e68112'
|
||||
}
|
||||
}
|
||||
})
|
||||
57
simple-mind-map/src/themes/avocado.js
Normal file
57
simple-mind-map/src/themes/avocado.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
// 牛油果
|
||||
export default merge(defaultTheme, {
|
||||
// 背景颜色
|
||||
backgroundColor: '#e6f1de',
|
||||
// 连线的颜色
|
||||
lineColor: '#f5ffad',
|
||||
lineWidth: 4,
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 3,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#749336',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: '#94c143',
|
||||
color: '#fff',
|
||||
borderColor: '#94c143',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#749336',
|
||||
borderWidth: 3
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
fillColor: '#cee498',
|
||||
color: '#749336',
|
||||
borderColor: '#aec668',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#749336',
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fontSize: 14,
|
||||
fillColor: '#cee498',
|
||||
borderColor: '#aec668',
|
||||
borderWidth: 2,
|
||||
color: '#749336',
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -34,6 +34,14 @@ export default {
|
||||
associativeLineActiveWidth: 8,
|
||||
// 关联线激活状态的颜色
|
||||
associativeLineActiveColor: 'rgba(2, 167, 240, 1)',
|
||||
// 关联线文字颜色
|
||||
associativeLineTextColor: 'rgb(51, 51, 51)',
|
||||
// 关联线文字大小
|
||||
associativeLineTextFontSize: 14,
|
||||
// 关联线文字行高
|
||||
associativeLineTextLineHeight: 1.2,
|
||||
// 关联线文字字体
|
||||
associativeLineTextFontFamily: '微软雅黑, Microsoft YaHei',
|
||||
// 背景颜色
|
||||
backgroundColor: '#fafafa',
|
||||
// 背景图片
|
||||
@@ -148,4 +156,38 @@ export const supportActiveStyle = [
|
||||
'borderRadius'
|
||||
]
|
||||
|
||||
// 检测主题配置是否是节点大小无关的
|
||||
const nodeSizeIndependenceList = [
|
||||
'lineWidth',
|
||||
'lineColor',
|
||||
'lineDasharray',
|
||||
'lineStyle',
|
||||
'generalizationLineWidth',
|
||||
'generalizationLineColor',
|
||||
'associativeLineWidth',
|
||||
'associativeLineColor',
|
||||
'associativeLineActiveWidth',
|
||||
'associativeLineActiveColor',
|
||||
'associativeLineTextColor',
|
||||
'associativeLineTextFontSize',
|
||||
'associativeLineTextLineHeight',
|
||||
'associativeLineTextFontFamily',
|
||||
'backgroundColor',
|
||||
'backgroundImage',
|
||||
'backgroundRepeat',
|
||||
'backgroundPosition',
|
||||
'backgroundSize'
|
||||
]
|
||||
export const checkIsNodeSizeIndependenceConfig = (config) => {
|
||||
let keys = Object.keys(config)
|
||||
for(let i = 0; i < keys.length; i++) {
|
||||
if (!nodeSizeIndependenceList.find((item) => {
|
||||
return item === keys[i]
|
||||
})) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']
|
||||
|
||||
@@ -27,6 +27,9 @@ import redSpirit from './redSpirit'
|
||||
import blackHumour from './blackHumour'
|
||||
import lateNightOffice from './lateNightOffice'
|
||||
import blackGold from './blackGold'
|
||||
import avocado from './avocado'
|
||||
import autumn from './autumn'
|
||||
import orangeJuice from './orangeJuice'
|
||||
|
||||
export default {
|
||||
default: defaultTheme,
|
||||
@@ -57,5 +60,8 @@ export default {
|
||||
redSpirit,
|
||||
blackHumour,
|
||||
lateNightOffice,
|
||||
blackGold
|
||||
blackGold,
|
||||
avocado,
|
||||
autumn,
|
||||
orangeJuice
|
||||
}
|
||||
|
||||
57
simple-mind-map/src/themes/orangeJuice.js
Normal file
57
simple-mind-map/src/themes/orangeJuice.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import defaultTheme from './default'
|
||||
import merge from 'deepmerge'
|
||||
|
||||
// 橙汁
|
||||
export default merge(defaultTheme, {
|
||||
// 背景颜色
|
||||
backgroundColor: '#070616',
|
||||
// 连线的颜色
|
||||
lineColor: '#fff',
|
||||
lineWidth: 3,
|
||||
// 概要连线的粗细
|
||||
generalizationLineWidth: 3,
|
||||
// 概要连线的颜色
|
||||
generalizationLineColor: '#fff',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: '#ff6811',
|
||||
color: '#110501',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#a9a4a9',
|
||||
borderWidth: 3
|
||||
}
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
fillColor: '#070616',
|
||||
color: '#a9a4a9',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#110501'
|
||||
}
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#a9a4a9',
|
||||
active: {
|
||||
borderColor: '#ff6811'
|
||||
}
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fontSize: 14,
|
||||
fillColor: '',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 2,
|
||||
color: '#a9a4a9',
|
||||
active: {
|
||||
borderColor: '#110501'
|
||||
}
|
||||
}
|
||||
})
|
||||
39
simple-mind-map/src/utils/Lru.js
Normal file
39
simple-mind-map/src/utils/Lru.js
Normal file
@@ -0,0 +1,39 @@
|
||||
// LRU缓存类
|
||||
export default class CRU {
|
||||
constructor(max) {
|
||||
this.max = max || 1000
|
||||
this.size = 0
|
||||
this.pool = new Map()
|
||||
}
|
||||
|
||||
add(key, value) {
|
||||
// 如果该key是否已经存在,则先删除
|
||||
this.delete(key)
|
||||
this.pool.set(key, value)
|
||||
this.size++
|
||||
// 如果数量超出最大值,则删除最早的
|
||||
if (this.size > this.max) {
|
||||
let keys = this.pool.keys()
|
||||
let last = keys.next()
|
||||
this.delete(last.value)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
if (this.pool.has(key)) {
|
||||
this.pool.delete(key)
|
||||
this.size--
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this.pool.has(key)
|
||||
}
|
||||
|
||||
get(key) {
|
||||
if (this.pool.has(key)) {
|
||||
return this.pool.get(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
241
simple-mind-map/src/utils/associativeLineControls.js
Normal file
241
simple-mind-map/src/utils/associativeLineControls.js
Normal file
@@ -0,0 +1,241 @@
|
||||
import {
|
||||
getAssociativeLineTargetIndex,
|
||||
joinCubicBezierPath,
|
||||
computeNodePoints,
|
||||
getDefaultControlPointOffsets
|
||||
} from './associativeLineUtils'
|
||||
|
||||
// 创建控制点、连线节点
|
||||
function createControlNodes() {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
// 连线
|
||||
this.controlLine1 = this.draw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
this.controlLine2 = this.draw
|
||||
.line()
|
||||
.stroke({ color: associativeLineActiveColor, width: 2 })
|
||||
// 控制点
|
||||
this.controlPoint1 = this.createOneControlNode('controlPoint1')
|
||||
this.controlPoint2 = this.createOneControlNode('controlPoint2')
|
||||
}
|
||||
|
||||
// 创建控制点
|
||||
function createOneControlNode(pointKey) {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
return this.draw
|
||||
.circle(this.controlPointDiameter)
|
||||
.stroke({ color: associativeLineActiveColor })
|
||||
.fill({ color: '#fff' })
|
||||
.click(e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
.mousedown(e => {
|
||||
this.onControlPointMousedown(e, pointKey)
|
||||
})
|
||||
}
|
||||
|
||||
// 控制点的鼠标按下事件
|
||||
function onControlPointMousedown(e, pointKey) {
|
||||
e.stopPropagation()
|
||||
this.isControlPointMousedown = true
|
||||
this.mousedownControlPointKey = pointKey
|
||||
}
|
||||
|
||||
// 控制点的鼠标移动事件
|
||||
function onControlPointMousemove(e) {
|
||||
if (
|
||||
!this.isControlPointMousedown ||
|
||||
!this.mousedownControlPointKey ||
|
||||
!this[this.mousedownControlPointKey]
|
||||
)
|
||||
return
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
let radius = this.controlPointDiameter / 2
|
||||
// 转换鼠标当前的位置
|
||||
let { x, y } = this.getTransformedEventPos(e)
|
||||
this.controlPointMousemoveState.pos = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
// 更新当前拖拽的控制点的位置
|
||||
this[this.mousedownControlPointKey].x(x - radius).y(y - radius)
|
||||
let [path, clickPath, text, node, toNode] = this.activeLine
|
||||
let [startPoint, endPoint] = computeNodePoints(node, toNode)
|
||||
this.controlPointMousemoveState.startPoint = startPoint
|
||||
this.controlPointMousemoveState.endPoint = endPoint
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
this.controlPointMousemoveState.targetIndex = targetIndex
|
||||
let offsets = []
|
||||
let associativeLineTargetControlOffsets =
|
||||
node.nodeData.data.associativeLineTargetControlOffsets
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsets = getDefaultControlPointOffsets(startPoint, endPoint)
|
||||
} else {
|
||||
offsets = associativeLineTargetControlOffsets[targetIndex]
|
||||
}
|
||||
let point1 = null
|
||||
let point2 = null
|
||||
// 拖拽的是控制点1
|
||||
if (this.mousedownControlPointKey === 'controlPoint1') {
|
||||
point1 = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
point2 = {
|
||||
x: endPoint.x + offsets[1].x,
|
||||
y: endPoint.y + offsets[1].y
|
||||
}
|
||||
// 更新控制点1的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
} else {
|
||||
// 拖拽的是控制点2
|
||||
point1 = {
|
||||
x: startPoint.x + offsets[0].x,
|
||||
y: startPoint.y + offsets[0].y
|
||||
}
|
||||
point2 = {
|
||||
x,
|
||||
y
|
||||
}
|
||||
// 更新控制点2的连线
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
}
|
||||
// 更新关联线
|
||||
let pathStr = joinCubicBezierPath(startPoint, endPoint, point1, point2)
|
||||
path.plot(pathStr)
|
||||
clickPath.plot(pathStr)
|
||||
this.updateTextPos(path, text)
|
||||
this.updateTextEditBoxPos(text)
|
||||
}
|
||||
|
||||
// 控制点的鼠标移动事件
|
||||
function onControlPointMouseup(e) {
|
||||
if (!this.isControlPointMousedown) return
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
let { pos, startPoint, endPoint, targetIndex } =
|
||||
this.controlPointMousemoveState
|
||||
let [, , , node] = this.activeLine
|
||||
let offsetList = []
|
||||
let associativeLineTargetControlOffsets =
|
||||
node.nodeData.data.associativeLineTargetControlOffsets
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsetList[targetIndex] = getDefaultControlPointOffsets(
|
||||
startPoint,
|
||||
endPoint
|
||||
)
|
||||
} else {
|
||||
offsetList = associativeLineTargetControlOffsets
|
||||
}
|
||||
let offset1 = null
|
||||
let offset2 = null
|
||||
if (this.mousedownControlPointKey === 'controlPoint1') {
|
||||
// 更新控制点1数据
|
||||
offset1 = {
|
||||
x: pos.x - startPoint.x,
|
||||
y: pos.y - startPoint.y
|
||||
}
|
||||
offset2 = offsetList[targetIndex][1]
|
||||
} else {
|
||||
// 更新控制点2数据
|
||||
offset1 = offsetList[targetIndex][0]
|
||||
offset2 = {
|
||||
x: pos.x - endPoint.x,
|
||||
y: pos.y - endPoint.y
|
||||
}
|
||||
}
|
||||
offsetList[targetIndex] = [offset1, offset2]
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
associativeLineTargetControlOffsets: offsetList
|
||||
})
|
||||
// 这里要加个setTimeout0是因为draw_click事件比mouseup事件触发的晚,所以重置isControlPointMousedown需要等draw_click事件触发完以后
|
||||
setTimeout(() => {
|
||||
this.resetControlPoint()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
// 复位控制点移动
|
||||
function resetControlPoint() {
|
||||
this.isControlPointMousedown = false
|
||||
this.mousedownControlPointKey = ''
|
||||
this.controlPointMousemoveState = {
|
||||
pos: null,
|
||||
startPoint: null,
|
||||
endPoint: null,
|
||||
targetIndex: ''
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染控制点
|
||||
function renderControls(startPoint, endPoint, point1, point2) {
|
||||
if (!this.controlLine1) {
|
||||
this.createControlNodes()
|
||||
}
|
||||
let radius = this.controlPointDiameter / 2
|
||||
// 控制点和起终点的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
// 控制点
|
||||
this.controlPoint1.x(point1.x - radius).y(point1.y - radius)
|
||||
this.controlPoint2.x(point2.x - radius).y(point2.y - radius)
|
||||
}
|
||||
|
||||
// 删除控制点
|
||||
function removeControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.remove()
|
||||
})
|
||||
this.controlLine1 = null
|
||||
this.controlLine2 = null
|
||||
this.controlPoint1 = null
|
||||
this.controlPoint2 = null
|
||||
}
|
||||
|
||||
// 隐藏控制点
|
||||
function hideControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.hide()
|
||||
})
|
||||
}
|
||||
|
||||
// 显示控制点
|
||||
function showControls() {
|
||||
if (!this.controlLine1) return
|
||||
;[
|
||||
this.controlLine1,
|
||||
this.controlLine2,
|
||||
this.controlPoint1,
|
||||
this.controlPoint2
|
||||
].forEach(item => {
|
||||
item.show()
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
createControlNodes,
|
||||
createOneControlNode,
|
||||
onControlPointMousedown,
|
||||
onControlPointMousemove,
|
||||
onControlPointMouseup,
|
||||
resetControlPoint,
|
||||
renderControls,
|
||||
removeControls,
|
||||
hideControls,
|
||||
showControls
|
||||
}
|
||||
167
simple-mind-map/src/utils/associativeLineText.js
Normal file
167
simple-mind-map/src/utils/associativeLineText.js
Normal file
@@ -0,0 +1,167 @@
|
||||
import { Text } from '@svgdotjs/svg.js'
|
||||
import { getStrWithBrFromHtml } from './index'
|
||||
|
||||
// 创建文字节点
|
||||
function createText(data) {
|
||||
let g = this.draw.group()
|
||||
const setActive = () => {
|
||||
if (
|
||||
!this.activeLine ||
|
||||
this.activeLine[3] !== data.node ||
|
||||
this.activeLine[4] !== data.toNode
|
||||
) {
|
||||
this.setActiveLine({
|
||||
...data,
|
||||
text: g
|
||||
})
|
||||
}
|
||||
}
|
||||
g.click(e => {
|
||||
e.stopPropagation()
|
||||
setActive()
|
||||
})
|
||||
g.on('dblclick', e => {
|
||||
e.stopPropagation()
|
||||
setActive()
|
||||
if (!this.activeLine) return
|
||||
this.showEditTextBox(g)
|
||||
})
|
||||
return g
|
||||
}
|
||||
|
||||
// 显示文本编辑框
|
||||
function showEditTextBox(g) {
|
||||
this.mindMap.emit('before_show_text_edit')
|
||||
// 注册回车快捷键
|
||||
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
||||
this.hideEditTextBox()
|
||||
})
|
||||
|
||||
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; word-break: break-all;`
|
||||
this.textEditNode.setAttribute('contenteditable', true)
|
||||
this.textEditNode.addEventListener('keyup', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
this.textEditNode.addEventListener('click', e => {
|
||||
e.stopPropagation()
|
||||
})
|
||||
document.body.appendChild(this.textEditNode)
|
||||
}
|
||||
let {
|
||||
associativeLineTextFontSize,
|
||||
associativeLineTextFontFamily,
|
||||
associativeLineTextLineHeight
|
||||
} = this.mindMap.themeConfig
|
||||
let scale = this.mindMap.view.scale
|
||||
let [, , , node, toNode] = this.activeLine
|
||||
let textLines = (
|
||||
this.getText(node, toNode) || this.mindMap.opt.defaultAssociativeLineText
|
||||
).split(/\n/gim)
|
||||
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
|
||||
this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
|
||||
this.textEditNode.style.lineHeight = textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
||||
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
||||
this.textEditNode.innerHTML = textLines.join('<br>')
|
||||
this.textEditNode.style.display = 'block'
|
||||
this.updateTextEditBoxPos(g)
|
||||
this.showTextEdit = true
|
||||
}
|
||||
|
||||
// 处理画布缩放
|
||||
function onScale() {
|
||||
this.hideEditTextBox()
|
||||
}
|
||||
|
||||
// 更新文本编辑框位置
|
||||
function updateTextEditBoxPos(g) {
|
||||
let rect = g.node.getBoundingClientRect()
|
||||
this.textEditNode.style.minWidth = rect.width + 10 + 'px'
|
||||
this.textEditNode.style.minHeight = rect.height + 6 + 'px'
|
||||
this.textEditNode.style.left = rect.left + 'px'
|
||||
this.textEditNode.style.top = rect.top + 'px'
|
||||
}
|
||||
|
||||
// 隐藏文本编辑框
|
||||
function hideEditTextBox() {
|
||||
if (!this.showTextEdit) {
|
||||
return
|
||||
}
|
||||
let [path, , text, node, toNode] = this.activeLine
|
||||
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
associativeLineText: {
|
||||
...(node.nodeData.data.associativeLineText || {}),
|
||||
[toNode.nodeData.data.id]: str
|
||||
}
|
||||
})
|
||||
this.textEditNode.style.display = 'none'
|
||||
this.textEditNode.innerHTML = ''
|
||||
this.showTextEdit = false
|
||||
this.renderText(str, path, text)
|
||||
this.mindMap.emit('hide_text_edit')
|
||||
}
|
||||
|
||||
// 获取某根关联线的文字
|
||||
function getText(node, toNode) {
|
||||
let obj = node.nodeData.data.associativeLineText
|
||||
if (!obj) {
|
||||
return ''
|
||||
}
|
||||
return obj[toNode.nodeData.data.id] || ''
|
||||
}
|
||||
|
||||
// 渲染关联线文字
|
||||
function renderText(str, path, text) {
|
||||
if (!str) return
|
||||
let { associativeLineTextFontSize, associativeLineTextLineHeight } =
|
||||
this.mindMap.themeConfig
|
||||
text.clear()
|
||||
let textArr = str.split(/\n/gim)
|
||||
textArr.forEach((item, index) => {
|
||||
let node = new Text().text(item)
|
||||
node.y(associativeLineTextFontSize * associativeLineTextLineHeight * index)
|
||||
this.styleText(node)
|
||||
text.add(node)
|
||||
})
|
||||
updateTextPos(path, text)
|
||||
}
|
||||
|
||||
// 给文本设置样式
|
||||
function styleText(node) {
|
||||
let {
|
||||
associativeLineTextColor,
|
||||
associativeLineTextFontSize,
|
||||
associativeLineTextFontFamily
|
||||
} = this.mindMap.themeConfig
|
||||
node
|
||||
.fill({
|
||||
color: associativeLineTextColor
|
||||
})
|
||||
.css({
|
||||
'font-family': associativeLineTextFontFamily,
|
||||
'font-size': associativeLineTextFontSize
|
||||
})
|
||||
}
|
||||
|
||||
// 更新关联线文字位置
|
||||
function updateTextPos(path, text) {
|
||||
let pathLength = path.length()
|
||||
let centerPoint = path.pointAt(pathLength / 2)
|
||||
let { width: textWidth, height: textHeight } = text.bbox()
|
||||
text.x(centerPoint.x - textWidth / 2)
|
||||
text.y(centerPoint.y - textHeight / 2)
|
||||
}
|
||||
|
||||
export default {
|
||||
getText,
|
||||
createText,
|
||||
styleText,
|
||||
onScale,
|
||||
showEditTextBox,
|
||||
hideEditTextBox,
|
||||
updateTextEditBoxPos,
|
||||
renderText,
|
||||
updateTextPos
|
||||
}
|
||||
@@ -28,34 +28,6 @@ export const themeList = [
|
||||
name: '默认',
|
||||
value: 'default',
|
||||
},
|
||||
{
|
||||
name: '脑图经典',
|
||||
value: 'classic',
|
||||
},
|
||||
{
|
||||
name: '小黄人',
|
||||
value: 'minions',
|
||||
},
|
||||
{
|
||||
name: '粉红葡萄',
|
||||
value: 'pinkGrape',
|
||||
},
|
||||
{
|
||||
name: '薄荷',
|
||||
value: 'mint',
|
||||
},
|
||||
{
|
||||
name: '金色vip',
|
||||
value: 'gold',
|
||||
},
|
||||
{
|
||||
name: '活力橙',
|
||||
value: 'vitalityOrange',
|
||||
},
|
||||
{
|
||||
name: '绿叶',
|
||||
value: 'greenLeaf',
|
||||
},
|
||||
{
|
||||
name: '暗色2',
|
||||
value: 'dark2',
|
||||
@@ -72,10 +44,6 @@ export const themeList = [
|
||||
name: '脑图经典3',
|
||||
value: 'classic3',
|
||||
},
|
||||
{
|
||||
name: '脑图经典4',
|
||||
value: 'classic4',
|
||||
},
|
||||
{
|
||||
name: '经典绿',
|
||||
value: 'classicGreen',
|
||||
@@ -112,6 +80,38 @@ export const themeList = [
|
||||
name: '浪漫紫',
|
||||
value: 'romanticPurple',
|
||||
},
|
||||
{
|
||||
name: '粉红葡萄',
|
||||
value: 'pinkGrape',
|
||||
},
|
||||
{
|
||||
name: '薄荷',
|
||||
value: 'mint',
|
||||
},
|
||||
{
|
||||
name: '金色vip',
|
||||
value: 'gold',
|
||||
},
|
||||
{
|
||||
name: '活力橙',
|
||||
value: 'vitalityOrange',
|
||||
},
|
||||
{
|
||||
name: '绿叶',
|
||||
value: 'greenLeaf',
|
||||
},
|
||||
{
|
||||
name: '脑图经典',
|
||||
value: 'classic',
|
||||
},
|
||||
{
|
||||
name: '脑图经典4',
|
||||
value: 'classic4',
|
||||
},
|
||||
{
|
||||
name: '小黄人',
|
||||
value: 'minions',
|
||||
},
|
||||
{
|
||||
name: '简约黑',
|
||||
value: 'simpleBlack',
|
||||
@@ -139,12 +139,25 @@ export const themeList = [
|
||||
{
|
||||
name: '黑金',
|
||||
value: 'blackGold',
|
||||
},
|
||||
{
|
||||
name: '牛油果',
|
||||
value: 'avocado',
|
||||
},
|
||||
{
|
||||
name: '秋天',
|
||||
value: 'autumn',
|
||||
},
|
||||
{
|
||||
name: '橙汁',
|
||||
value: 'orangeJuice',
|
||||
}
|
||||
]
|
||||
|
||||
// 常量
|
||||
export const CONSTANTS = {
|
||||
CHANGE_THEME: 'changeTheme',
|
||||
SET_DATA: 'setData',
|
||||
TRANSFORM_TO_NORMAL_NODE: 'transformAllNodesToNormalNode',
|
||||
MODE: {
|
||||
READONLY: 'readonly',
|
||||
|
||||
BIN
web/src/assets/img/autumn.jpg
Normal file
BIN
web/src/assets/img/autumn.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
web/src/assets/img/avocado.jpg
Normal file
BIN
web/src/assets/img/avocado.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
BIN
web/src/assets/img/orangeJuice.jpg
Normal file
BIN
web/src/assets/img/orangeJuice.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
@@ -40,5 +40,8 @@ export const themeMap = {
|
||||
blackHumour: require('../assets/img/blackHumour.jpg'),
|
||||
lateNightOffice: require('../assets/img/lateNightOffice.jpg'),
|
||||
blackGold: require('../assets/img/blackGold.jpg'),
|
||||
autumn: require('../assets/img/autumn.jpg'),
|
||||
avocado: require('../assets/img/avocado.jpg'),
|
||||
orangeJuice: require('../assets/img/orangeJuice.jpg'),
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ let langList = [
|
||||
path: 'en'
|
||||
}
|
||||
]
|
||||
let StartList = ['introduction', 'start', 'deploy', 'translate', 'changelog']
|
||||
let StartList = ['introduction', 'start', 'deploy', 'client', 'translate', 'changelog']
|
||||
let CourseList = new Array(19).fill(0).map((_, index) => {
|
||||
return 'course' + (index + 1)
|
||||
})
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
> The function of adjusting associated line control points is supported from v0.4.6+
|
||||
|
||||
This plugin is used to support the addition of associative lines.
|
||||
> Relevance support for text editing starting from v0.5.11+
|
||||
|
||||
The plugin is currently not fully functional, and does not support adding text to association lines.
|
||||
This plugin is used to support the addition of associative lines.
|
||||
|
||||
## Register
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
<blockquote>
|
||||
<p>The function of adjusting associated line control points is supported from v0.4.6+</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>Relevance support for text editing starting from v0.5.11+</p>
|
||||
</blockquote>
|
||||
<p>This plugin is used to support the addition of associative lines.</p>
|
||||
<p>The plugin is currently not fully functional, and does not support adding text to association lines.</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> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/AssociativeLine.js'</span>
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.11
|
||||
|
||||
New: Supports associative text editing.
|
||||
|
||||
optimization: Optimizing theme configuration updates, changing configurations that do not involve node size does not trigger node recalculation.
|
||||
|
||||
## 0.5.10
|
||||
|
||||
New: Optimize node reuse logic using LRU caching algorithm.
|
||||
|
||||
## 0.5.10-fix.1
|
||||
|
||||
Fix: Fix the issue of import errors.
|
||||
|
||||
## 0.5.10-fix.2
|
||||
|
||||
Fix: Fixed the issue of switching themes and importing data without triggering data changes in rich text mode.
|
||||
|
||||
New: Add three new themes.
|
||||
|
||||
## 0.5.9
|
||||
|
||||
Change: Unified export method format, using `FileReader` instead of `URL.createObjectURL` to convert `blob` data.
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.5.11</h2>
|
||||
<p>New: Supports associative text editing.</p>
|
||||
<p>optimization: Optimizing theme configuration updates, changing configurations that do not involve node size does not trigger node recalculation.</p>
|
||||
<h2>0.5.10</h2>
|
||||
<p>New: Optimize node reuse logic using LRU caching algorithm.</p>
|
||||
<h2>0.5.10-fix.1</h2>
|
||||
<p>Fix: Fix the issue of import errors.</p>
|
||||
<h2>0.5.10-fix.2</h2>
|
||||
<p>Fix: Fixed the issue of switching themes and importing data without triggering data changes in rich text mode.</p>
|
||||
<p>New: Add three new themes.</p>
|
||||
<h2>0.5.9</h2>
|
||||
<p>Change: Unified export method format, using <code>FileReader</code> instead of <code>URL.createObjectURL</code> to convert <code>blob</code> data.</p>
|
||||
<h2>0.5.8</h2>
|
||||
|
||||
@@ -28,7 +28,7 @@ const mindMap = new MindMap({
|
||||
| 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)、timeline(v0.5.4+, timeline)、timeline2(v0.5.4+, up down alternating timeline)、fishbone(v0.5.4+, fishbone diagram) | |
|
||||
| fishboneDeg(v0.5.4+) | Number | 45 | Set the diagonal angle of the fishbone 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, simpleBlack(v0.5.4+), courseGreen(v0.5.4+), coffee(v0.5.4+), redSpirit(v0.5.4+), blackHumour(v0.5.4+), lateNightOffice(v0.5.4+), blackGold(v0.5.4+) | |
|
||||
| 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, simpleBlack(v0.5.4+), courseGreen(v0.5.4+), coffee(v0.5.4+), redSpirit(v0.5.4+), blackHumour(v0.5.4+), lateNightOffice(v0.5.4+), blackGold(v0.5.4+)、、avocado(v.5.10-fix.2+)、autumn(v.5.10-fix.2+)、orangeJuice(v.5.10-fix.2+) | |
|
||||
| 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 | |
|
||||
@@ -61,6 +61,7 @@ const mindMap = new MindMap({
|
||||
| maxHistoryCount(v0.5.6+) | Number | 1000 | | Maximum number of history records |
|
||||
| alwaysShowExpandBtn(v0.5.8+) | Boolean | false | Whether to always display the expand and collapse buttons of nodes, which are only displayed when the mouse is moved up and activated by default | |
|
||||
| iconList(v0.5.8+) | Array | [] | The icons that can be inserted into the extension node, and each item in the array is an object. Please refer to the "Icon Configuration" table below for the detailed structure of the object | |
|
||||
| maxNodeCacheCount(v0.5.10+) | Number | 1000 | The maximum number of cached nodes. To optimize performance, an internal node cache pool is maintained to reuse nodes. This attribute allows you to specify the maximum number of caches in the pool | |
|
||||
|
||||
### Watermark config
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<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, simpleBlack(v0.5.4+), courseGreen(v0.5.4+), coffee(v0.5.4+), redSpirit(v0.5.4+), blackHumour(v0.5.4+), lateNightOffice(v0.5.4+), blackGold(v0.5.4+)</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, simpleBlack(v0.5.4+), courseGreen(v0.5.4+), coffee(v0.5.4+), redSpirit(v0.5.4+), blackHumour(v0.5.4+), lateNightOffice(v0.5.4+), blackGold(v0.5.4+)、、avocado(v.5.10-fix.2+)、autumn(v.5.10-fix.2+)、orangeJuice(v.5.10-fix.2+)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -287,6 +287,13 @@
|
||||
<td>The icons that can be inserted into the extension node, and each item in the array is an object. Please refer to the "Icon Configuration" table below for the detailed structure of the object</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>maxNodeCacheCount(v0.5.10+)</td>
|
||||
<td>Number</td>
|
||||
<td>1000</td>
|
||||
<td>The maximum number of cached nodes. To optimize performance, an internal node cache pool is maintained to reuse nodes. This attribute allows you to specify the maximum number of caches in the pool</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>Watermark config</h3>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
`simple-mind-map` is a simple and powerful web mind map library, not dependent on any specific framework. Can help you quickly develop mind mapping products.
|
||||
|
||||
> If you just want to use mind mapping, you can also use the demo of this project as a regular online mind mapping tool. Click on the 【Online Demo】 in the upper right corner to start using it.
|
||||
>
|
||||
> Additionally, a client is provided for download, support `Windows`、`Mac` and `Linux`, [Click here to learn more](/mind-map/#/doc/zh/client)。
|
||||
|
||||
## Features
|
||||
|
||||
|
||||
@@ -4,24 +4,25 @@
|
||||
<p><code>simple-mind-map</code> is a simple and powerful web mind map library, not dependent on any specific framework. Can help you quickly develop mind mapping products.</p>
|
||||
<blockquote>
|
||||
<p>If you just want to use mind mapping, you can also use the demo of this project as a regular online mind mapping tool. Click on the 【Online Demo】 in the upper right corner to start using it.</p>
|
||||
<p>Additionally, a client is provided for download, support <code>Windows</code>、<code>Mac</code> and <code>Linux</code>, <a href="/mind-map/#/doc/zh/client">Click here to learn more</a>。</p>
|
||||
</blockquote>
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox216" checked="true" /><label for="checkbox216">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="checkbox217" checked="true" /><label for="checkbox217">Supports six types of structures: logical structure diagrams, mind maps,</label>
|
||||
<li><input type="checkbox" id="checkbox90" checked="true" /><label for="checkbox90">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="checkbox91" checked="true" /><label for="checkbox91">Supports six types of structures: logical structure diagrams, mind maps,</label>
|
||||
organizational structure diagrams, directory organization diagrams, timeline, and fishbone diagrams</li>
|
||||
<li><input type="checkbox" id="checkbox218" checked="true" /><label for="checkbox218">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox219" checked="true" /><label for="checkbox219">Supports shortcuts</label></li>
|
||||
<li><input type="checkbox" id="checkbox220" checked="true" /><label for="checkbox220">Node content supports images, icons, hyperlinks, notes, tags, and</label>
|
||||
<li><input type="checkbox" id="checkbox92" checked="true" /><label for="checkbox92">Built-in multiple themes and allows for highly customized styles, and support register new themes</label></li>
|
||||
<li><input type="checkbox" id="checkbox93" checked="true" /><label for="checkbox93">Supports shortcuts</label></li>
|
||||
<li><input type="checkbox" id="checkbox94" checked="true" /><label for="checkbox94">Node content supports images, icons, hyperlinks, notes, tags, and</label>
|
||||
summaries</li>
|
||||
<li><input type="checkbox" id="checkbox221" checked="true" /><label for="checkbox221">Supports forward and backward navigation</label></li>
|
||||
<li><input type="checkbox" id="checkbox222" checked="true" /><label for="checkbox222">Supports dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox223" checked="true" /><label for="checkbox223">Supports right-click and Ctrl + left-click to select multiple items</label></li>
|
||||
<li><input type="checkbox" id="checkbox224" checked="true" /><label for="checkbox224">Supports free dragging and dragging to adjust nodes</label></li>
|
||||
<li><input type="checkbox" id="checkbox225" checked="true" /><label for="checkbox225">Supports various node shapes</label></li>
|
||||
<li><input type="checkbox" id="checkbox226" checked="true" /><label for="checkbox226">Supports export to json, png, svg, pdf markdown, and import from json, xmind, markdown</label></li>
|
||||
<li><input type="checkbox" id="checkbox227" checked="true" /><label for="checkbox227">Supports mini map、support watermark</label></li>
|
||||
<li><input type="checkbox" id="checkbox228" checked="true" /><label for="checkbox228">Supports associative lines</label></li>
|
||||
<li><input type="checkbox" id="checkbox95" checked="true" /><label for="checkbox95">Supports forward and backward navigation</label></li>
|
||||
<li><input type="checkbox" id="checkbox96" checked="true" /><label for="checkbox96">Supports dragging and scaling</label></li>
|
||||
<li><input type="checkbox" id="checkbox97" checked="true" /><label for="checkbox97">Supports right-click and Ctrl + left-click to select multiple items</label></li>
|
||||
<li><input type="checkbox" id="checkbox98" checked="true" /><label for="checkbox98">Supports free dragging and dragging to adjust nodes</label></li>
|
||||
<li><input type="checkbox" id="checkbox99" checked="true" /><label for="checkbox99">Supports various node shapes</label></li>
|
||||
<li><input type="checkbox" id="checkbox100" checked="true" /><label for="checkbox100">Supports export to json, png, svg, pdf markdown, and import from json, xmind, markdown</label></li>
|
||||
<li><input type="checkbox" id="checkbox101" checked="true" /><label for="checkbox101">Supports mini map、support watermark</label></li>
|
||||
<li><input type="checkbox" id="checkbox102" checked="true" /><label for="checkbox102">Supports associative lines</label></li>
|
||||
</ul>
|
||||
<h2>Repository Catalog Introduction</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
@@ -31,16 +32,16 @@ frameworks such as Vue and React, or without a framework.</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="checkbox229" checked="true" /><label for="checkbox229">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
<li><input type="checkbox" id="checkbox103" checked="true" /><label for="checkbox103">Toolbar, which supports inserting and deleting nodes, and editing node</label>
|
||||
images, icons, hyperlinks, notes, tags, and summaries</li>
|
||||
<li><input type="checkbox" id="checkbox230" checked="true" /><label for="checkbox230">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
<li><input type="checkbox" id="checkbox104" checked="true" /><label for="checkbox104">Sidebar, with panels for basic style settings, node style settings,</label>
|
||||
outline, theme selection, and structure selection</li>
|
||||
<li><input type="checkbox" id="checkbox231" checked="true" /><label for="checkbox231">Import and export functionality; data is saved in the browser's local</label>
|
||||
<li><input type="checkbox" id="checkbox105" checked="true" /><label for="checkbox105">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="checkbox232" checked="true" /><label for="checkbox232">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
<li><input type="checkbox" id="checkbox106" checked="true" /><label for="checkbox106">Right-click menu, which supports operations such as expanding, collapsing,</label>
|
||||
and organizing layout</li>
|
||||
<li><input type="checkbox" id="checkbox233" checked="true" /><label for="checkbox233">Bottom bar, which supports node and word count statistics, switching</label>
|
||||
<li><input type="checkbox" id="checkbox107" checked="true" /><label for="checkbox107">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>
|
||||
|
||||
@@ -91,6 +91,7 @@ If you only use library, you don't need to read this section.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd mind-map
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
|
||||
@@ -64,6 +64,7 @@ compile this dependency:</p>
|
||||
<p>If you only use library, you don't need to read this section.</p>
|
||||
<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> mind-map
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# Participate in translation
|
||||
|
||||
Thanks for the first version English translation provided by [Emircan ERKUL](https://github.com/emircanerkul).
|
||||
> Thanks for the first version English translation provided by [Emircan ERKUL](https://github.com/emircanerkul).
|
||||
>
|
||||
> Due to limited energy, most translations currently use machine translation, so accuracy is inevitably problematic.
|
||||
>
|
||||
> At present, the 【Course】 section is not translated. If you are interested, please join us.
|
||||
|
||||
If you want to participate in the translation of this document, you can clone this repository first.
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Participate in translation</h1>
|
||||
<blockquote>
|
||||
<p>Thanks for the first version English translation provided by <a href="https://github.com/emircanerkul">Emircan ERKUL</a>.</p>
|
||||
<p>Due to limited energy, most translations currently use machine translation, so accuracy is inevitably problematic.</p>
|
||||
<p>At present, the 【Course】 section is not translated. If you are interested, please join us.</p>
|
||||
</blockquote>
|
||||
<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>
|
||||
|
||||
@@ -167,4 +167,50 @@ drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
// success
|
||||
}
|
||||
})
|
||||
```
|
||||
```
|
||||
|
||||
## LRU cache class
|
||||
|
||||
> v0.5.10+
|
||||
|
||||
Import:
|
||||
|
||||
```js
|
||||
import Lru from 'simple-mind-map/src/utils/Lru.js'
|
||||
```
|
||||
|
||||
### Constructor
|
||||
|
||||
```js
|
||||
let lru = new Lru(max)
|
||||
```
|
||||
|
||||
`max`: Specify the maximum number of caches.
|
||||
|
||||
### Instance properties
|
||||
|
||||
#### size
|
||||
|
||||
The current number of caches.
|
||||
|
||||
#### pool
|
||||
|
||||
Get cache pool.
|
||||
|
||||
### Instance methods
|
||||
|
||||
#### add(key, value)
|
||||
|
||||
Add cache.
|
||||
|
||||
#### delete(key)
|
||||
|
||||
Delete cache.
|
||||
|
||||
#### has(key)
|
||||
|
||||
Check if a cache exists.
|
||||
|
||||
#### get(key)
|
||||
|
||||
Gets the value of a cache.
|
||||
@@ -112,6 +112,31 @@ drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
}
|
||||
})
|
||||
</code></pre>
|
||||
<h2>LRU cache class</h2>
|
||||
<blockquote>
|
||||
<p>v0.5.10+</p>
|
||||
</blockquote>
|
||||
<p>Import:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> Lru <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/Lru.js'</span>
|
||||
</code></pre>
|
||||
<h3>Constructor</h3>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">let</span> lru = <span class="hljs-keyword">new</span> Lru(max)
|
||||
</code></pre>
|
||||
<p><code>max</code>: Specify the maximum number of caches.</p>
|
||||
<h3>Instance properties</h3>
|
||||
<h4>size</h4>
|
||||
<p>The current number of caches.</p>
|
||||
<h4>pool</h4>
|
||||
<p>Get cache pool.</p>
|
||||
<h3>Instance methods</h3>
|
||||
<h4>add(key, value)</h4>
|
||||
<p>Add cache.</p>
|
||||
<h4>delete(key)</h4>
|
||||
<p>Delete cache.</p>
|
||||
<h4>has(key)</h4>
|
||||
<p>Check if a cache exists.</p>
|
||||
<h4>get(key)</h4>
|
||||
<p>Gets the value of a cache.</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -43,7 +43,8 @@ export default [
|
||||
{ path: 'view', title: 'View实例' },
|
||||
{ path: 'watermark', title: 'Watermark插件' },
|
||||
{ path: 'xmind', title: 'XMind解析' },
|
||||
{ path: 'deploy', title: '部署' }
|
||||
{ path: 'deploy', title: '部署' },
|
||||
{ path: 'client', title: '客户端' }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
|
||||
> 调整关联线控制点的功能从v0.4.6+开始支持
|
||||
|
||||
该插件用于支持添加关联线。
|
||||
> 关联性支持文本编辑从v0.5.11+开始支持
|
||||
|
||||
该插件目前功能还不完善,不支持在关联线上添加文字。
|
||||
该插件用于支持添加关联线。
|
||||
|
||||
## 注册
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@
|
||||
<blockquote>
|
||||
<p>调整关联线控制点的功能从v0.4.6+开始支持</p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>关联性支持文本编辑从v0.5.11+开始支持</p>
|
||||
</blockquote>
|
||||
<p>该插件用于支持添加关联线。</p>
|
||||
<p>该插件目前功能还不完善,不支持在关联线上添加文字。</p>
|
||||
<h2>注册</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> AssociativeLine <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/AssociativeLine.js'</span>
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.11
|
||||
|
||||
新增:支持关联性文本编辑。
|
||||
|
||||
优化:优化主题配置更新,改变不涉及节点大小的配置不触发节点重新计算。
|
||||
|
||||
## 0.5.10
|
||||
|
||||
新增:使用LRU缓存算法优化节点复用逻辑。
|
||||
|
||||
## 0.5.10-fix.1
|
||||
|
||||
修复:修复导入出错的问题。
|
||||
|
||||
## 0.5.10-fix.2
|
||||
|
||||
修复:修复富文本模式下,切换主题、导入数据后没有触发数据改变的问题。
|
||||
|
||||
新增:新增三种主题。
|
||||
|
||||
## 0.5.9
|
||||
|
||||
修改:统一导出方法的格式,使用`FileReader`代替`URL.createObjectURL`转换`blob`数据。
|
||||
|
||||
@@ -1,6 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>Changelog</h1>
|
||||
<h2>0.5.11</h2>
|
||||
<p>新增:支持关联性文本编辑。</p>
|
||||
<p>优化:优化主题配置更新,改变不涉及节点大小的配置不触发节点重新计算。</p>
|
||||
<h2>0.5.10</h2>
|
||||
<p>新增:使用LRU缓存算法优化节点复用逻辑。</p>
|
||||
<h2>0.5.10-fix.1</h2>
|
||||
<p>修复:修复导入出错的问题。</p>
|
||||
<h2>0.5.10-fix.2</h2>
|
||||
<p>修复:修复富文本模式下,切换主题、导入数据后没有触发数据改变的问题。</p>
|
||||
<p>新增:新增三种主题。</p>
|
||||
<h2>0.5.9</h2>
|
||||
<p>修改:统一导出方法的格式,使用<code>FileReader</code>代替<code>URL.createObjectURL</code>转换<code>blob</code>数据。</p>
|
||||
<h2>0.5.8</h2>
|
||||
|
||||
80
web/src/pages/Doc/zh/client/index.md
Normal file
80
web/src/pages/Doc/zh/client/index.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 客户端
|
||||
|
||||
本项目也提供了客户端版本,使用[Electron](https://www.electronjs.org/)开发。支持`Windows`、`Mac`及`Linux`。
|
||||
|
||||
目前功能比较简单:
|
||||
|
||||
1.支持新建、打开文件进行编辑;
|
||||
|
||||
2.支持查看最近编辑文件列表;
|
||||
|
||||
3.支持文件的复制、删除、重命名;
|
||||
|
||||
## 下载
|
||||
|
||||
你可以直接下载对应的客户端安装使用,提供了两个下载地址:
|
||||
|
||||
Github:[releases](https://github.com/wanglin2/mind-map/releases)。
|
||||
|
||||
百度云盘:[地址](https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3)。
|
||||
|
||||
## 开发
|
||||
|
||||
如果有需要,你也可以进行二次开发。
|
||||
|
||||
### clone
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd mind-map
|
||||
git checkout electron
|
||||
```
|
||||
|
||||
### 启动服务
|
||||
|
||||
在项目根目录下执行:
|
||||
|
||||
```bash
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
cd ..
|
||||
cd web
|
||||
npm i
|
||||
npm link simple-mind-map
|
||||
npm run electron:serve
|
||||
```
|
||||
|
||||
### 打包客户端
|
||||
|
||||
你至少需要两台电脑,一台`Windows`和一台`Mac`。
|
||||
|
||||
打包`Windows`应用:
|
||||
|
||||
```bash
|
||||
npm run electron:build-win
|
||||
```
|
||||
|
||||
打包`Mac`应用:
|
||||
|
||||
```bash
|
||||
npm run electron:build-mac
|
||||
```
|
||||
|
||||
打包`Linux`应用:
|
||||
|
||||
```bash
|
||||
npm run electron:build-linux
|
||||
```
|
||||
|
||||
打包全部应用:
|
||||
|
||||
```bash
|
||||
npm run electron:build-all
|
||||
```
|
||||
|
||||
根据你的电脑系统自动打包:
|
||||
|
||||
```bash
|
||||
npm run electron:build
|
||||
```
|
||||
60
web/src/pages/Doc/zh/client/index.vue
Normal file
60
web/src/pages/Doc/zh/client/index.vue
Normal file
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>客户端</h1>
|
||||
<p>本项目也提供了客户端版本,使用<a href="https://www.electronjs.org/">Electron</a>开发。支持<code>Windows</code>、<code>Mac</code>及<code>Linux</code>。</p>
|
||||
<p>目前功能比较简单:</p>
|
||||
<p>1.支持新建、打开文件进行编辑;</p>
|
||||
<p>2.支持查看最近编辑文件列表;</p>
|
||||
<p>3.支持文件的复制、删除、重命名;</p>
|
||||
<h2>下载</h2>
|
||||
<p>你可以直接下载对应的客户端安装使用,提供了两个下载地址:</p>
|
||||
<p>Github:<a href="https://github.com/wanglin2/mind-map/releases">releases</a>。</p>
|
||||
<p>百度云盘:<a href="https://pan.baidu.com/s/1huasEbKsGNH2Af68dvWiOg?pwd=3bp3">地址</a>。</p>
|
||||
<h2>开发</h2>
|
||||
<p>如果有需要,你也可以进行二次开发。</p>
|
||||
<h3>clone</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> mind-map
|
||||
git checkout electron
|
||||
</code></pre>
|
||||
<h3>启动服务</h3>
|
||||
<p>在项目根目录下执行:</p>
|
||||
<pre class="hljs"><code><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 electron:serve
|
||||
</code></pre>
|
||||
<h3>打包客户端</h3>
|
||||
<p>你至少需要两台电脑,一台<code>Windows</code>和一台<code>Mac</code>。</p>
|
||||
<p>打包<code>Windows</code>应用:</p>
|
||||
<pre class="hljs"><code>npm run electron:build-win
|
||||
</code></pre>
|
||||
<p>打包<code>Mac</code>应用:</p>
|
||||
<pre class="hljs"><code>npm run electron:build-mac
|
||||
</code></pre>
|
||||
<p>打包<code>Linux</code>应用:</p>
|
||||
<pre class="hljs"><code>npm run electron:build-linux
|
||||
</code></pre>
|
||||
<p>打包全部应用:</p>
|
||||
<pre class="hljs"><code>npm run electron:build-all
|
||||
</code></pre>
|
||||
<p>根据你的电脑系统自动打包:</p>
|
||||
<pre class="hljs"><code>npm run electron:build
|
||||
</code></pre>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@@ -28,7 +28,7 @@ const mindMap = new MindMap({
|
||||
| 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(组织结构图)、timeline(v0.5.4+,时间轴)、timeline2(v0.5.4+,上下交替型时间轴)、fishbone(v0.5.4+,鱼骨图) | |
|
||||
| fishboneDeg(v0.5.4+) | Number | 45 | 设置鱼骨结构图的斜线角度 | |
|
||||
| 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(浪漫紫)、simpleBlack(v0.5.4+简约黑)、courseGreen(v0.5.4+课程绿)、coffee(v0.5.4+咖啡)、redSpirit(v0.5.4+红色精神)、blackHumour(v0.5.4+黑色幽默)、lateNightOffice(v0.5.4+深夜办公室)、blackGold(v0.5.4+黑金) | |
|
||||
| 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(浪漫紫)、simpleBlack(v0.5.4+简约黑)、courseGreen(v0.5.4+课程绿)、coffee(v0.5.4+咖啡)、redSpirit(v0.5.4+红色精神)、blackHumour(v0.5.4+黑色幽默)、lateNightOffice(v0.5.4+深夜办公室)、blackGold(v0.5.4+黑金)、avocado(v.5.10-fix.2+牛油果)、autumn(v.5.10-fix.2+秋天)、orangeJuice(v.5.10-fix.2+橙汁) | |
|
||||
| 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 | 节点里最多显示的标签数量,多余的会被丢弃 | |
|
||||
@@ -61,6 +61,7 @@ const mindMap = new MindMap({
|
||||
| maxHistoryCount(v0.5.6+) | Number | 1000 | 最大历史记录数 | |
|
||||
| alwaysShowExpandBtn(v0.5.8+) | Boolean | false | 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示 | |
|
||||
| iconList(v0.5.8+) | Array | [] | 扩展节点可插入的图标,数组的每一项为一个对象,对象详细结构请参考下方【图标配置】表格 | |
|
||||
| maxNodeCacheCount(v0.5.10+) | Number | 1000 | 节点最大缓存数量。为了优化性能,内部会维护一个节点缓存池,用来复用节点,通过该属性可以指定池的最大缓存数量 | |
|
||||
|
||||
### 水印配置
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<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(浪漫紫)、simpleBlack(v0.5.4+简约黑)、courseGreen(v0.5.4+课程绿)、coffee(v0.5.4+咖啡)、redSpirit(v0.5.4+红色精神)、blackHumour(v0.5.4+黑色幽默)、lateNightOffice(v0.5.4+深夜办公室)、blackGold(v0.5.4+黑金)</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(浪漫紫)、simpleBlack(v0.5.4+简约黑)、courseGreen(v0.5.4+课程绿)、coffee(v0.5.4+咖啡)、redSpirit(v0.5.4+红色精神)、blackHumour(v0.5.4+黑色幽默)、lateNightOffice(v0.5.4+深夜办公室)、blackGold(v0.5.4+黑金)、avocado(v.5.10-fix.2+牛油果)、autumn(v.5.10-fix.2+秋天)、orangeJuice(v.5.10-fix.2+橙汁)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -287,6 +287,13 @@
|
||||
<td>扩展节点可插入的图标,数组的每一项为一个对象,对象详细结构请参考下方【图标配置】表格</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>maxNodeCacheCount(v0.5.10+)</td>
|
||||
<td>Number</td>
|
||||
<td>1000</td>
|
||||
<td>节点最大缓存数量。为了优化性能,内部会维护一个节点缓存池,用来复用节点,通过该属性可以指定池的最大缓存数量</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h3>水印配置</h3>
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
`icon`目前只能使用内置的图标,完整图标可以在[icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件中查看。
|
||||
`icon`可以使用内置的图标,完整图标可以在[icons.js](https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js)文件中查看。也可以扩展图标,参考[扩展图标](https://wanglin2.github.io/mind-map/#/doc/zh/course19/%E6%89%A9%E5%B1%95%E5%9B%BE%E6%A0%87)。
|
||||
|
||||
创建实例时还支持传递其他很多选项参数,完整选项列表可以在[实例化选项](https://wanglin2.github.io/mind-map/#/doc/zh/constructor/%E5%AE%9E%E4%BE%8B%E5%8C%96%E9%80%89%E9%A1%B9)查看。
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
<span class="hljs-attr">children</span>: []<span class="hljs-comment">// 子节点</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p><code>icon</code>目前只能使用内置的图标,完整图标可以在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">icons.js</a>文件中查看。</p>
|
||||
<p><code>icon</code>可以使用内置的图标,完整图标可以在<a href="https://github.com/wanglin2/mind-map/blob/main/simple-mind-map/src/svg/icons.js">icons.js</a>文件中查看。也可以扩展图标,参考<a href="https://wanglin2.github.io/mind-map/#/doc/zh/course19/%E6%89%A9%E5%B1%95%E5%9B%BE%E6%A0%87">扩展图标</a>。</p>
|
||||
<p>创建实例时还支持传递其他很多选项参数,完整选项列表可以在<a href="https://wanglin2.github.io/mind-map/#/doc/zh/constructor/%E5%AE%9E%E4%BE%8B%E5%8C%96%E9%80%89%E9%A1%B9">实例化选项</a>查看。</p>
|
||||
<p>这样得到的思维导图可以通过鼠标和快捷键进行操作,比如单击某个节点可以激活它,双击某个节点可以编辑节点文本,按下<code>Tab</code>键会给当前激活的节点添加一个子节点,按下<code>Enter</code>键会给当前激活的节点添加一个兄弟节点等等,完整的快捷键列表可以参考<a href="https://github.com/wanglin2/mind-map/blob/main/web/src/config/zh.js#L246">快捷键列表</a>。</p>
|
||||
<p>当然有些功能还是需要UI界面的,比如图标列表、编辑超链接等等,需要注意的是<code>simple-mind-map</code>库并不包含UI界面,所以需要你自己开发,然后通过<code>simple-mind-map</code>提供的相关API来操作,本教程的其他章节会向你介绍如何使用。</p>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
`simple-mind-map`是一个简单&强大的Web思维导图库,不依赖任何特定框架。可以帮助你快速开发思维导图产品。
|
||||
|
||||
> 如果你只是想使用思维导图,你也完全可以把本项目的demo作为一个普通的在线思维导图工具使用。点击右上角的【在线示例】开始使用吧。
|
||||
>
|
||||
> 另外也提供了客户端可供下载,支持`Windows`、`Mac`及`Linux`,[点此了解更多](/mind-map/#/doc/zh/client)。
|
||||
|
||||
## 特性
|
||||
|
||||
|
||||
@@ -4,22 +4,23 @@
|
||||
<p><code>simple-mind-map</code>是一个简单&强大的Web思维导图库,不依赖任何特定框架。可以帮助你快速开发思维导图产品。</p>
|
||||
<blockquote>
|
||||
<p>如果你只是想使用思维导图,你也完全可以把本项目的demo作为一个普通的在线思维导图工具使用。点击右上角的【在线示例】开始使用吧。</p>
|
||||
<p>另外也提供了客户端可供下载,支持<code>Windows</code>、<code>Mac</code>及<code>Linux</code>,<a href="/mind-map/#/doc/zh/client">点此了解更多</a>。</p>
|
||||
</blockquote>
|
||||
<h2>特性</h2>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox180" checked="true" /><label for="checkbox180">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小整体体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox181" checked="true" /><label for="checkbox181">支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴、鱼骨图六种结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox182" checked="true" /><label for="checkbox182">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox183" checked="true" /><label for="checkbox183">支持快捷键</label></li>
|
||||
<li><input type="checkbox" id="checkbox184" checked="true" /><label for="checkbox184">节点内容支持图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox185" checked="true" /><label for="checkbox185">支持前进后退</label></li>
|
||||
<li><input type="checkbox" id="checkbox186" checked="true" /><label for="checkbox186">支持拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox187" checked="true" /><label for="checkbox187">支持右键和Ctrl+左键两种多选方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox188" checked="true" /><label for="checkbox188">支持节点自由拖拽、拖拽调整</label></li>
|
||||
<li><input type="checkbox" id="checkbox189" checked="true" /><label for="checkbox189">支持多种节点形状</label></li>
|
||||
<li><input type="checkbox" id="checkbox190" checked="true" /><label for="checkbox190">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox191" checked="true" /><label for="checkbox191">支持小地图、支持水印</label></li>
|
||||
<li><input type="checkbox" id="checkbox192" checked="true" /><label for="checkbox192">支持关联线</label></li>
|
||||
<li><input type="checkbox" id="checkbox72" checked="true" /><label for="checkbox72">插件化架构,除核心功能外,其他功能作为插件提供,按需使用,减小整体体积</label></li>
|
||||
<li><input type="checkbox" id="checkbox73" checked="true" /><label for="checkbox73">支持逻辑结构图、思维导图、组织结构图、目录组织图、时间轴、鱼骨图六种结构</label></li>
|
||||
<li><input type="checkbox" id="checkbox74" checked="true" /><label for="checkbox74">内置多种主题,允许高度自定义样式,支持注册新主题</label></li>
|
||||
<li><input type="checkbox" id="checkbox75" checked="true" /><label for="checkbox75">支持快捷键</label></li>
|
||||
<li><input type="checkbox" id="checkbox76" checked="true" /><label for="checkbox76">节点内容支持图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox77" checked="true" /><label for="checkbox77">支持前进后退</label></li>
|
||||
<li><input type="checkbox" id="checkbox78" checked="true" /><label for="checkbox78">支持拖动、缩放</label></li>
|
||||
<li><input type="checkbox" id="checkbox79" checked="true" /><label for="checkbox79">支持右键和Ctrl+左键两种多选方式</label></li>
|
||||
<li><input type="checkbox" id="checkbox80" checked="true" /><label for="checkbox80">支持节点自由拖拽、拖拽调整</label></li>
|
||||
<li><input type="checkbox" id="checkbox81" checked="true" /><label for="checkbox81">支持多种节点形状</label></li>
|
||||
<li><input type="checkbox" id="checkbox82" checked="true" /><label for="checkbox82">支持导出为</label><code>json</code>、<code>png</code>、<code>svg</code>、<code>pdf</code>、<code>markdown</code>,支持从<code>json</code>、<code>xmind</code>、<code>markdown</code>导入</li>
|
||||
<li><input type="checkbox" id="checkbox83" checked="true" /><label for="checkbox83">支持小地图、支持水印</label></li>
|
||||
<li><input type="checkbox" id="checkbox84" checked="true" /><label for="checkbox84">支持关联线</label></li>
|
||||
</ul>
|
||||
<h2>仓库目录介绍</h2>
|
||||
<p>1.<code>simple-mind-map</code></p>
|
||||
@@ -27,11 +28,11 @@
|
||||
<p>2.<code>web</code></p>
|
||||
<p>使用<code>simple-mind-map</code>库,基于<code>vue2.x</code>、<code>ElementUI</code>搭建的在线思维导图。特性:</p>
|
||||
<ul>
|
||||
<li><input type="checkbox" id="checkbox193" checked="true" /><label for="checkbox193">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox194" checked="true" /><label for="checkbox194">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox195" checked="true" /><label for="checkbox195">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox196" checked="true" /><label for="checkbox196">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox197" checked="true" /><label for="checkbox197">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
<li><input type="checkbox" id="checkbox85" checked="true" /><label for="checkbox85">工具栏,支持插入节点、删除节点;编辑节点图片、图标、超链接、备注、标签、概要</label></li>
|
||||
<li><input type="checkbox" id="checkbox86" checked="true" /><label for="checkbox86">侧边栏,基础样式设置面板、节点样式设置面板、大纲面板、主题选择面板、结构选择面板</label></li>
|
||||
<li><input type="checkbox" id="checkbox87" checked="true" /><label for="checkbox87">导入导出功能;数据默认保存在浏览器本地存储,也支持直接创建、打开、编辑电脑本地文件</label></li>
|
||||
<li><input type="checkbox" id="checkbox88" checked="true" /><label for="checkbox88">右键菜单,支持展开、收起、整理布局等操作</label></li>
|
||||
<li><input type="checkbox" id="checkbox89" checked="true" /><label for="checkbox89">底部栏,支持节点数量、字数统计;支持切换编辑和只读模式;支持放大缩小;支持全屏切换;支持小地图</label></li>
|
||||
</ul>
|
||||
<p>提供文档页面服务。</p>
|
||||
<p>3.<code>dist</code></p>
|
||||
|
||||
@@ -86,6 +86,7 @@ const mindMap = new MindMap({
|
||||
|
||||
```bash
|
||||
git clone https://github.com/wanglin2/mind-map.git
|
||||
cd mind-map
|
||||
cd simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
<p>如果你只是使用库的话可以不用阅读此小节。</p>
|
||||
<h3>本地开发</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> mind-map
|
||||
<span class="hljs-built_in">cd</span> simple-mind-map
|
||||
npm i
|
||||
npm link
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
# 参与翻译
|
||||
|
||||
感谢[Emircan ERKUL](https://github.com/emircanerkul)提供的第一版英文翻译。
|
||||
> 感谢[Emircan ERKUL](https://github.com/emircanerkul)提供的第一版英文翻译。
|
||||
>
|
||||
>因为精力有限,目前大部分翻译都是使用机翻的,所以准确度难免有问题。
|
||||
>
|
||||
>目前【教程】部分是没有进行翻译的,如果你有兴趣,欢迎加入我们。
|
||||
|
||||
如果你也想参与翻译本文档的话,可以先克隆本仓库。
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>参与翻译</h1>
|
||||
<blockquote>
|
||||
<p>感谢<a href="https://github.com/emircanerkul">Emircan ERKUL</a>提供的第一版英文翻译。</p>
|
||||
<p>因为精力有限,目前大部分翻译都是使用机翻的,所以准确度难免有问题。</p>
|
||||
<p>目前【教程】部分是没有进行翻译的,如果你有兴趣,欢迎加入我们。</p>
|
||||
</blockquote>
|
||||
<p>如果你也想参与翻译本文档的话,可以先克隆本仓库。</p>
|
||||
<p>翻译的文档在<code>/web/src/pages/Doc/</code>目录下,目前支持英文(<code>en</code>)、简体中文(<code>zh</code>)两种语言。</p>
|
||||
<p>如果是新增一种语言类型,那么可以在<code>/web/src/pages/Doc/</code>目录下创建一个新目录,然后给每个章节创建一个文件夹,你也可以直接复制已存在的语言目录下的所有章节目录进行翻译,注意,你只需要编写<code>index.md</code>文件,章节目录下的<code>index.vue</code>文件是脚本根据<code>index.md</code>自动生成的。</p>
|
||||
|
||||
@@ -163,3 +163,49 @@ drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## LRU缓存类
|
||||
|
||||
> v0.5.10+
|
||||
|
||||
引入:
|
||||
|
||||
```js
|
||||
import Lru from 'simple-mind-map/src/utils/Lru.js'
|
||||
```
|
||||
|
||||
### 构造函数
|
||||
|
||||
```js
|
||||
let lru = new Lru(max)
|
||||
```
|
||||
|
||||
`max`:指定最大缓存数量。
|
||||
|
||||
### 实例属性
|
||||
|
||||
#### size
|
||||
|
||||
当前缓存的数量。
|
||||
|
||||
#### pool
|
||||
|
||||
获取缓存池。
|
||||
|
||||
### 实例方法
|
||||
|
||||
#### add(key, value)
|
||||
|
||||
添加缓存。
|
||||
|
||||
#### delete(key)
|
||||
|
||||
删除指定缓存。
|
||||
|
||||
#### has(key)
|
||||
|
||||
检查某个缓存是否存在。
|
||||
|
||||
#### get(key)
|
||||
|
||||
获取某个缓存的值。
|
||||
@@ -107,6 +107,31 @@ drawBackgroundImageToCanvas(ctx, width, height, img, {
|
||||
}
|
||||
})
|
||||
</code></pre>
|
||||
<h2>LRU缓存类</h2>
|
||||
<blockquote>
|
||||
<p>v0.5.10+</p>
|
||||
</blockquote>
|
||||
<p>引入:</p>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">import</span> Lru <span class="hljs-keyword">from</span> <span class="hljs-string">'simple-mind-map/src/utils/Lru.js'</span>
|
||||
</code></pre>
|
||||
<h3>构造函数</h3>
|
||||
<pre class="hljs"><code><span class="hljs-keyword">let</span> lru = <span class="hljs-keyword">new</span> Lru(max)
|
||||
</code></pre>
|
||||
<p><code>max</code>:指定最大缓存数量。</p>
|
||||
<h3>实例属性</h3>
|
||||
<h4>size</h4>
|
||||
<p>当前缓存的数量。</p>
|
||||
<h4>pool</h4>
|
||||
<p>获取缓存池。</p>
|
||||
<h3>实例方法</h3>
|
||||
<h4>add(key, value)</h4>
|
||||
<p>添加缓存。</p>
|
||||
<h4>delete(key)</h4>
|
||||
<p>删除指定缓存。</p>
|
||||
<h4>has(key)</h4>
|
||||
<p>检查某个缓存是否存在。</p>
|
||||
<h4>get(key)</h4>
|
||||
<p>获取某个缓存的值。</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -295,6 +295,67 @@
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 关联线文字 -->
|
||||
<div class="title noTop">关联线文字</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">字体</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
v-model="style.associativeLineTextFontFamily"
|
||||
placeholder=""
|
||||
@change="update('associativeLineTextFontFamily', $event)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in fontFamilyList"
|
||||
:key="item.value"
|
||||
:label="item.name"
|
||||
:value="item.value"
|
||||
:style="{ fontFamily: item.value }"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="rowItem">
|
||||
<span class="name">颜色</span>
|
||||
<span
|
||||
class="block"
|
||||
v-popover:popover6
|
||||
:style="{ backgroundColor: style.associativeLineTextColor }"
|
||||
></span>
|
||||
<el-popover ref="popover6" placement="bottom" trigger="click">
|
||||
<Color
|
||||
:color="style.associativeLineTextColor"
|
||||
@change="
|
||||
color => {
|
||||
update('associativeLineTextColor', color)
|
||||
}
|
||||
"
|
||||
></Color>
|
||||
</el-popover>
|
||||
</div>
|
||||
<div class="rowItem">
|
||||
<span class="name">字号</span>
|
||||
<el-select
|
||||
size="mini"
|
||||
style="width: 80px"
|
||||
v-model="style.associativeLineTextFontSize"
|
||||
placeholder=""
|
||||
@change="update('associativeLineTextFontSize', $event)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in fontSizeList"
|
||||
:key="item"
|
||||
:label="item"
|
||||
:value="item"
|
||||
:style="{ fontSize: item + 'px' }"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 节点边框风格 -->
|
||||
<div class="title noTop">{{ $t('baseStyle.nodeBorderType') }}</div>
|
||||
<div class="row">
|
||||
@@ -546,7 +607,7 @@
|
||||
<script>
|
||||
import Sidebar from './Sidebar'
|
||||
import Color from './Color'
|
||||
import { lineWidthList, lineStyleList, backgroundRepeatList, backgroundPositionList, backgroundSizeList } from '@/config'
|
||||
import { lineWidthList, lineStyleList, backgroundRepeatList, backgroundPositionList, backgroundSizeList, fontFamilyList, fontSizeList } from '@/config'
|
||||
import ImgUpload from '@/components/ImgUpload'
|
||||
import { storeConfig } from '@/api'
|
||||
import { mapState, mapMutations } from 'vuex'
|
||||
@@ -575,6 +636,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
lineWidthList,
|
||||
fontSizeList,
|
||||
activeTab: 'color',
|
||||
marginActiveTab: 'second',
|
||||
style: {
|
||||
@@ -588,6 +650,9 @@ export default {
|
||||
associativeLineWidth: 0,
|
||||
associativeLineActiveWidth: 0,
|
||||
associativeLineActiveColor: '',
|
||||
associativeLineTextFontSize: 0,
|
||||
associativeLineTextColor: '',
|
||||
associativeLineTextFontFamily: '',
|
||||
paddingX: 0,
|
||||
paddingY: 0,
|
||||
imgMaxWidth: 0,
|
||||
@@ -636,6 +701,9 @@ export default {
|
||||
backgroundSizeList() {
|
||||
return backgroundSizeList[this.$i18n.locale] || backgroundSizeList.zh
|
||||
},
|
||||
fontFamilyList() {
|
||||
return fontFamilyList[this.$i18n.locale] || fontFamilyList.zh
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
activeSidebar(val) {
|
||||
@@ -673,6 +741,9 @@ export default {
|
||||
'associativeLineWidth',
|
||||
'associativeLineActiveWidth',
|
||||
'associativeLineActiveColor',
|
||||
'associativeLineTextFontSize',
|
||||
'associativeLineTextColor',
|
||||
'associativeLineTextFontFamily',
|
||||
'paddingX',
|
||||
'paddingY',
|
||||
'imgMaxWidth',
|
||||
|
||||
@@ -42,7 +42,7 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
themeList: [...themeList],// ...customThemeList
|
||||
themeList: [...themeList].reverse(),// ...customThemeList
|
||||
themeMap,
|
||||
theme: ''
|
||||
}
|
||||
|
||||
@@ -4,6 +4,25 @@ import EditPage from '@/pages/Edit/Index'
|
||||
import DocPage from '@/pages/Doc/Index'
|
||||
import routerList from '@/pages/Doc/routerList'
|
||||
|
||||
// 处理没有翻译的章节路由
|
||||
const handleRouterList = () => {
|
||||
let zhList = routerList[0].children
|
||||
for(let i = 1; i < routerList.length; i++) {
|
||||
let list = routerList[i].children
|
||||
zhList.forEach(item => {
|
||||
if (!list.find((item2) => {
|
||||
return item2.path === item.path
|
||||
})) {
|
||||
list.push({
|
||||
...item,
|
||||
lang: 'zh'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
handleRouterList()
|
||||
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const routes = [
|
||||
@@ -25,7 +44,7 @@ const routes = [
|
||||
children: item.children.map((child) => {
|
||||
return {
|
||||
path: `${child.path}/:h?`,
|
||||
component: () => import(`./pages/Doc/${item.lang}/${child.path}/index.vue`)
|
||||
component: () => import(`./pages/Doc/${child.lang || item.lang}/${child.path}/index.vue`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user