完成基本逻辑

This commit is contained in:
wanglin 2021-07-10 22:06:45 +08:00
parent da28f89c52
commit 554dab56d3
19 changed files with 1182 additions and 586 deletions

View File

@ -24,6 +24,13 @@ export default {
"data": {
"text": "根节点"
},
"childrens": [
{
"data": {
"text": "二级节点1"
}
}
],
"children": [
{
"data": {
@ -32,286 +39,431 @@ export default {
},
"children": [{
"data": {
"text": "子节点1-1",
"text": "子节点",
...createFullData()
},
}, {
"data": {
"text": "子节点1-2",
}
},]
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
...createFullData()
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}]
},
{
"data": {
"text": "二级节点2"
"text": "二级节点2",
"expand": true,
},
"children": [
{
"data": {
"text": "子节点2-1"
},
"children": [
{
"data": {
"text": "子节点2-1-1",
}
},
{
"data": {
"text": "子节点2-1-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2-2"
}
},
{
"data": {
"text": "子节点2-1-2-2-3",
}
}
]
},
{
"data": {
"text": "子节点4-1-2-3"
}
}
]
},
{
"data": {
"text": "子节点2-1-3",
}
}
]
"children": [{
"data": {
"text": "子节点",
},
{
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点2-2",
"text": "子节点",
},
"children": [
{
"data": {
"text": "子节点2-1-1",
}
},
{
"data": {
"text": "子节点2-1-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2-2"
}
},
{
"data": {
"text": "子节点2-1-2-2-3",
}
}
]
},
{
"data": {
"text": "子节点4-1-2-3"
}
}
]
},
{
"data": {
"text": "子节点2-1-3",
}
}
]
}
]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
},
{
"data": {
"text": "二级节点3",
"expand": true,
},
"children": [
{
"data": {
"text": "子节点3-1",
},
"children": [
{
"data": {
"text": "子节点2-1-1",
}
},
{
"data": {
"text": "子节点2-1-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2-2"
}
},
{
"data": {
"text": "子节点2-1-2-2-3",
}
}
]
},
{
"data": {
"text": "子节点4-1-2-3"
}
}
]
},
{
"data": {
"text": "子节点2-1-3",
}
}
]
"children": [{
"data": {
"text": "子节点",
},
{
"children": [{
"data": {
"text": "子节点3-2"
}
}
]
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}]
},
{
"data": {
"text": "二级节点4",
"expand": true,
},
"children": [
{
"data": {
"text": "子节点4-1",
},
"children": [
{
"data": {
"text": "子节点4-1-1",
},
"children": [
{
"data": {
"text": "子节点2-1-1",
}
},
{
"data": {
"text": "子节点2-1-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2",
},
"children": [
{
"data": {
"text": "子节点2-1-2-2-1",
}
},
{
"data": {
"text": "子节点2-1-2-2-2"
}
},
{
"data": {
"text": "子节点2-1-2-2-3",
}
}
]
},
{
"data": {
"text": "子节点4-1-2-3"
}
}
]
},
{
"data": {
"text": "子节点2-1-3",
}
}
]
},
{
"data": {
"text": "子节点4-1-2",
}
},
{
"data": {
"text": "子节点4-1-3"
}
}
]
"children": [{
"data": {
"text": "子节点",
},
{
"children": [{
"data": {
"text": "子节点4-2",
}
}
]
}
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}]
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}, {
"data": {
"text": "子节点",
},
"children": [{
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}, {
"data": {
"text": "子节点",
},
}]
}]
}]
}]
},
]
},
"theme": {

View File

@ -7,7 +7,7 @@ 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 Export from './src/Export'
import {
SVG
} from '@svgdotjs/svg.js'
@ -101,10 +101,10 @@ class MindMap {
this.batchExecution = new BatchExecution()
// 初始渲染
this.renderer.render()
this.reRender()
setTimeout(() => {
this.command.addHistory()
}, 0);
}, 0)
}
/**
@ -128,12 +128,26 @@ class MindMap {
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 18:47:29
* @Desc: 渲染
* @Desc: 渲染部分渲染
*/
render() {
this.batchExecution.push('render', () => {
this.initTheme()
this.renderer.reRender = false
this.renderer.render()
})
}
/**
* @Author: 王林
* @Date: 2021-07-08 22:05:11
* @Desc: 重新渲染
*/
reRender() {
this.batchExecution.push('render', () => {
this.draw.clear()
this.initTheme()
this.renderer.reRender = true
this.renderer.render()
})
}
@ -184,7 +198,7 @@ class MindMap {
*/
setTheme(theme) {
this.opt.theme = theme
this.render()
this.reRender()
}
/**
@ -193,7 +207,7 @@ class MindMap {
* @Desc: 获取当前主题
*/
getTheme() {
return this.opt.theme;
return this.opt.theme
}
/**
@ -203,7 +217,7 @@ class MindMap {
*/
setThemeConfig(config) {
this.opt.themeConfig = config
this.render()
this.reRender()
}
/**
@ -231,7 +245,7 @@ class MindMap {
*/
async export(...args) {
let result = await this.doExport.export(...args)
return result;
return result
}
}

View File

@ -1,16 +1,18 @@
import Style from './Style'
import {
resizeImgSize,
copyRenderTree,
imgToDataUrl
resizeImgSize
} from './utils'
import {
Image,
SVG,
Circle
Circle,
A,
G,
Rect,
Text
} from '@svgdotjs/svg.js'
import btnsSvg from './svg/btns'
import iconsSvg from './svg/icons';
import iconsSvg from './svg/icons'
/**
* javascript comment
@ -48,8 +50,6 @@ class Node {
this.width = opt.width || 0
// 节点高
this.height = opt.height || 0
// 节点文字内容部分高
this._textContentHeight = 0
// left
this.left = opt.left || 0
// top
@ -60,18 +60,47 @@ class Node {
this.children = opt.children || []
// 节点内容的容器
this.group = null
// 节点内容是否发生了变化,是的话会重新计算和渲染
this.changed = true
// 文本节点
this.textNode = null
// 节点内容对象
this._imgData = null
this._iconData = null
this._textData = null
this._hyperlinkData = null
this._tagData = null
this._noteData = null
this._expandBtn = null
this._lines = []
// 尺寸信息
this._rectInfo = {
imgContentWidth: 0,
imgContentHeight: 0,
textContentHeight: 0,
textContentHeight: 0
}
// icon间距
this._textContentItemMargin = 2
// 图片和文字节点的间距
this._blockContentMargin = 5
// 展开收缩按钮尺寸
this._expandBtnSize = 20
// 计算节点尺寸
this.refreshSize()
// 初始渲染
this._initRender = true
// 初始化
this.createNodeData()
this.getSize()
}
/**
* @Author: 王林
* @Date: 2021-07-05 23:11:39
* @Desc: 复位部分布局时会重新设置的数据
*/
reset() {
this.children = []
this.parent = null
this.isRoot = false
this.layerIndex = 0
this.left = 0
this.top = 0
}
/**
@ -82,7 +111,8 @@ class Node {
handleData(data) {
data.data.expand = data.data.expand === false ? false : true
data.data.isActive = data.data.isActive === true ? true : false
return data;
data.children = data.children || []
return data
}
/**
@ -95,22 +125,84 @@ class Node {
this.children.push(node)
}
/**
* @Author: 王林
* @Date: 2021-07-06 22:08:09
* @Desc: 创建节点的各个内容对象数据
*/
createNodeData() {
this._imgData = this.createImgNode()
this._iconData = this.createIconNode()
this._textData = this.createTextNode()
this._hyperlinkData = this.createHyperlinkNode()
this._tagData = this.createTagNode()
this._noteData = this.createNoteNode()
}
/**
* @Author: 王林
* @Date: 2021-07-10 09:20:02
* @Desc: 解绑所有事件
*/
removeAllEvent() {
if (this._noteData) {
this._noteData.node.off(['mouseover', 'mouseout'])
}
if (this._expandBtn) {
this._expandBtn.off(['mouseover', 'mouseout', 'click'])
}
if (this.group) {
this.group.off(['click', 'dblclick'])
}
}
/**
* @Author: 王林
* @Date: 2021-07-07 21:27:24
* @Desc: 移除节点内容
*/
removeAllNode() {
// 节点内的内容
;[this._imgData, this._iconData, this._textData, this._hyperlinkData, this._tagData, this._noteData].forEach((item) => {
if (item && item.node) item.node.remove()
})
this._imgData = null
this._iconData = null
this._textData = null
this._hyperlinkData = null
this._tagData = null
this._noteData = null
// 展开收缩按钮
if (this._expandBtn) {
this._expandBtn.remove()
this._expandBtn = null
}
// 组
if (this.group) {
this.group.clear()
this.group.remove()
this.group = null
}
}
/**
* javascript comment
* @Author: 王林25
* @Date: 2021-04-09 09:46:23
* @Desc: 刷新节点的宽高
* @Desc: 计算节点的宽高
*/
refreshSize() {
if (!this.changed) {
return;
}
getSize() {
this.removeAllNode()
this.createNodeData()
let {
width,
height
} = this.getNodeRect()
// 判断节点尺寸是否有变化
let changed = this.width !== width || this.height !== height
this.width = width
this.height = height
return changed
}
/**
@ -126,50 +218,42 @@ class Node {
let textContentWidth = 0
let textContentHeight = 0
// 存在图片
let imgObj = this.createImgNode()
if (imgObj) {
imgContentWidth = imgObj.width
imgContentHeight = imgObj.height
if (this._imgData) {
this._rectInfo.imgContentWidth = imgContentWidth = this._imgData.width
this._rectInfo.imgContentHeight = imgContentHeight = this._imgData.height
}
// 图标
let iconObjs = this.createIconNode()
if (iconObjs.length > 0) {
textContentWidth += iconObjs.reduce((sum, cur) => {
if (this._iconData.length > 0) {
textContentWidth += this._iconData.reduce((sum, cur) => {
textContentHeight = Math.max(textContentHeight, cur.height)
return sum += cur.width + this._textContentItemMargin
}, 0)
}
// 文字
let textObj = this.createTextNode()
if (textObj) {
textContentWidth += textObj.width
textContentHeight = Math.max(textContentHeight, textObj.height)
if (this._textData) {
textContentWidth += this._textData.width
textContentHeight = Math.max(textContentHeight, this._textData.height)
}
// 超链接
let hyperlinkObj = this.createHyperlinkNode()
if (hyperlinkObj) {
textContentWidth += hyperlinkObj.width
textContentHeight = Math.max(textContentHeight, hyperlinkObj.height)
hyperlinkObj.node.remove()
if (this._hyperlinkData) {
textContentWidth += this._hyperlinkData.width
textContentHeight = Math.max(textContentHeight, this._hyperlinkData.height)
}
// 标签
let tagObjs = this.createTagNode()
if (tagObjs.length > 0) {
textContentWidth += tagObjs.reduce((sum, cur) => {
if (this._tagData.length > 0) {
textContentWidth += this._tagData.reduce((sum, cur) => {
textContentHeight = Math.max(textContentHeight, cur.height)
cur.node.remove()
return sum += cur.width + this._textContentItemMargin
}, 0)
}
// 备注
let noteObj = this.createNoteNode()
if (noteObj) {
textContentWidth += noteObj.width
textContentHeight = Math.max(textContentHeight, noteObj.height)
noteObj.node.remove()
if (this._noteData) {
textContentWidth += this._noteData.width
textContentHeight = Math.max(textContentHeight, this._noteData.height)
}
// 文字内容部分的高度
this._textContentHeight = textContentHeight
// 文字内容部分的尺寸
this._rectInfo.textContentWidth = textContentWidth
this._rectInfo.textContentHeight = textContentHeight
// 间距
let margin = imgContentHeight > 0 && textContentHeight > 0 ? this._blockContentMargin : 0
let { paddingX, paddingY } = this.getPaddingVale()
@ -221,7 +305,7 @@ class Node {
createIconNode() {
let _data = this.nodeData.data
if (!_data.icon || _data.icon.length <= 0) {
return [];
return []
}
let iconSize = this.themeConfig.iconSize
return _data.icon.map((item) => {
@ -229,8 +313,8 @@ class Node {
node: SVG(iconsSvg.getNodeIconListIcon(item)).size(iconSize, iconSize),
width: iconSize,
height: iconSize
};
});
}
})
}
/**
@ -240,16 +324,21 @@ class Node {
* @Desc: 创建文本节点
*/
createTextNode() {
let node = this.draw.text(this.nodeData.data.text || '')
this.style.text(node)
let g = new G()
let fontSize = this.getStyle('fontSize', this.isRoot, this.nodeData.data.isActive)
let lineHeight = this.getStyle('lineHeight', this.isRoot, this.nodeData.data.isActive)
this.nodeData.data.text.split(/\n/img).forEach((item, index) => {
let node = new Text().text(item)
this.style.text(node)
node.y(fontSize * lineHeight * index)
g.add(node)
})
let {
width,
height
} = node.bbox()
let cloneNode = node.clone()
node.remove()
} = g.bbox()
return {
node: cloneNode,
node: g,
width,
height
}
@ -266,19 +355,24 @@ class Node {
return
}
let iconSize = this.themeConfig.iconSize
let node = this.draw.link(hyperlink).target('_blank')
node.node.addEventListener('click', (e) => {
let node = new SVG()
// 超链接节点
let a = new A().to(hyperlink).target('_blank')
a.node.addEventListener('click', (e) => {
e.stopPropagation()
})
if (hyperlinkTitle) {
node.attr('title', hyperlinkTitle)
a.attr('title', hyperlinkTitle)
}
node.rect(iconSize, iconSize).fill({ color: 'transparent' })
// 添加一个透明的层,作为鼠标区域
a.rect(iconSize, iconSize).fill({ color: 'transparent' })
// 超链接图标
let iconNode = SVG(iconsSvg.hyperlink).size(iconSize, iconSize)
this.style.iconNode(iconNode)
node.add(iconNode)
a.add(iconNode)
node.add(a)
return {
node: node,
node,
width: iconSize,
height: iconSize
}
@ -292,29 +386,29 @@ class Node {
createTagNode() {
let tagData = this.nodeData.data.tag
if (!tagData || tagData.length <= 0) {
return [];
return []
}
let nodes = []
tagData.slice(0, this.mindMap.opt.maxTag).forEach((item, index) => {
let tag = this.draw.group()
let text = this.draw.text(item).x(8).cy(10)
let tag = new G()
// 标签文本
let text = new Text().text(item).x(8).cy(10)
this.style.tagText(text, index)
let {
width,
height
} = text.bbox()
let cloneText = text.clone()
text.remove()
let rect = this.draw.rect(width + 16, 20)
// 标签矩形
let rect = new Rect().size(width + 16, 20)
this.style.tagRect(rect, index)
tag.add(rect).add(cloneText)
tag.add(rect).add(text)
nodes.push({
node: tag,
width: width + 16,
height: 20
})
})
return nodes;
return nodes
}
/**
@ -324,14 +418,17 @@ class Node {
*/
createNoteNode() {
if (!this.nodeData.data.note) {
return null;
return null
}
let node = this.draw.group().attr('cursor', 'pointer')
let iconSize = this.themeConfig.iconSize
node.add(this.draw.rect(iconSize, iconSize).fill({ color: 'transparent' }))
let node = new SVG().attr('cursor', 'pointer')
// 透明的层,用来作为鼠标区域
node.add(new Rect().size(iconSize, iconSize).fill({ color: 'transparent' }))
// 备注图标
let iconNode = SVG(iconsSvg.note).size(iconSize, iconSize)
this.style.iconNode(iconNode)
node.add(iconNode)
// 备注tooltip
let el = document.createElement('div')
el.style.cssText = `
position: absolute;
@ -356,47 +453,43 @@ class Node {
node,
width: iconSize,
height: iconSize
};
}
}
/**
* javascript comment
* @Author: 王林25
* @Date: 2021-04-09 11:10:11
* @Desc: 创建内容节点
* @Desc: 定位节点内容
*/
createNode() {
layout() {
let {
left,
top,
width,
height,
_textContentHeight,
_textContentItemMargin
} = this
let { paddingY } = this.getPaddingVale()
// 创建组
this.group = this.draw.group()
this.group = new G()
this.updatePos(false)
// 节点矩形
this.style.rect(this.group.rect(width, height).x(left).y(top))
this.style.rect(this.group.rect(width, height))
// 图片节点
let imgObj = this.createImgNode()
let imgHeight = 0
if (imgObj) {
imgHeight = imgObj.height
this.group.add(imgObj.node)
imgObj.node.cx(left + width / 2).y(top + paddingY)
if (this._imgData) {
imgHeight = this._imgData.height
this.group.add(this._imgData.node)
this._imgData.node.cx(width / 2).y(paddingY)
}
// 内容节点
let textContentNested = this.draw.group()
let textContentNested = new G()
let textContentOffsetX = 0
// icon
let iconObjs = this.createIconNode()
let iconNested = this.draw.group()
if (iconObjs && iconObjs.length > 0) {
let iconNested = new G()
if (this._iconData && this._iconData.length > 0) {
let iconLeft = 0
iconObjs.forEach((item) => {
item.node.x(textContentOffsetX + iconLeft).y((_textContentHeight - item.height) / 2)
this._iconData.forEach((item) => {
item.node.x(textContentOffsetX + iconLeft).y((this._rectInfo.textContentHeight - item.height) / 2)
iconNested.add(item.node)
iconLeft += item.width + _textContentItemMargin
})
@ -404,27 +497,23 @@ class Node {
textContentOffsetX += iconLeft
}
// 文字
let textObj = this.createTextNode()
if (textObj) {
textObj.node.x(textContentOffsetX).y(0)
this.textNode = textObj
textContentNested.add(textObj.node)
textContentOffsetX += textObj.width + _textContentItemMargin
if (this._textData) {
this._textData.node.x(textContentOffsetX).y(0)
textContentNested.add(this._textData.node)
textContentOffsetX += this._textData.width + _textContentItemMargin
}
// 超链接
let hyperlinkObj = this.createHyperlinkNode()
if (hyperlinkObj) {
hyperlinkObj.node.translate(textContentOffsetX, (_textContentHeight - hyperlinkObj.height) / 2)
textContentNested.add(hyperlinkObj.node)
textContentOffsetX += hyperlinkObj.width + _textContentItemMargin
if (this._hyperlinkData) {
this._hyperlinkData.node.x(textContentOffsetX).y((this._rectInfo.textContentHeight - this._hyperlinkData.height) / 2)
textContentNested.add(this._hyperlinkData.node)
textContentOffsetX += this._hyperlinkData.width + _textContentItemMargin
}
// 标签
let tagObjs = this.createTagNode()
let tagNested = this.draw.group()
if (tagObjs && tagObjs.length > 0) {
let tagNested = new G()
if (this._tagData && this._tagData.length > 0) {
let tagLeft = 0
tagObjs.forEach((item) => {
item.node.x(textContentOffsetX + tagLeft).y((_textContentHeight - item.height) / 2)
this._tagData.forEach((item) => {
item.node.x(textContentOffsetX + tagLeft).y((this._rectInfo.textContentHeight - item.height) / 2)
tagNested.add(item.node)
tagLeft += item.width + _textContentItemMargin
})
@ -432,79 +521,91 @@ class Node {
textContentOffsetX += tagLeft
}
// 备注
let noteObj = this.createNoteNode()
if (noteObj) {
noteObj.node.translate(textContentOffsetX, (_textContentHeight - noteObj.height) / 2)
textContentNested.add(noteObj.node)
textContentOffsetX += noteObj.width
if (this._noteData) {
this._noteData.node.x(textContentOffsetX).y((this._rectInfo.textContentHeight - this._noteData.height) / 2)
textContentNested.add(this._noteData.node)
textContentOffsetX += this._noteData.width
}
// 文字内容整体
textContentNested.translate(
left + width / 2 - textContentNested.bbox().width / 2,
top + imgHeight + paddingY + (imgHeight > 0 && _textContentHeight > 0 ? this._blockContentMargin : 0)
width / 2 - textContentNested.bbox().width / 2,
imgHeight + paddingY + (imgHeight > 0 && this._rectInfo.textContentHeight > 0 ? this._blockContentMargin : 0)
)
this.group.add(textContentNested)
// 单击事件,选中节点
this.group.click((e) => {
e.stopPropagation()
if (this.nodeData.data.isActive) {
return;
}
this.mindMap.emit('before_node_active', this, this.renderer.activeNodeList)
this.renderer.clearActive()
this.mindMap.execCommand('UPDATE_NODE_DATA', this, {
isActive: !this.nodeData.data.isActive
})
this.renderNode()
this.renderer.activeNodeList.push(this)
this.mindMap.emit('node_active', this, this.renderer.activeNodeList)
this.group.on('click', (e) => {
this.active(e)
})
// 双击事件
this.group.dblclick(() => {
this.group.on('dblclick', () => {
this.mindMap.emit('node_dblclick', this)
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 16:44:22
* @Desc: 激活节点
*/
active(e) {
e.stopPropagation()
if (this.nodeData.data.isActive) {
return
}
this.mindMap.emit('before_node_active', this, this.renderer.activeNodeList)
this.renderer.clearActive()
this.mindMap.execCommand('SET_NODE_ACTIVE', this, !this.nodeData.data.isActive)
this.renderer.activeNodeList.push(this)
this.mindMap.emit('node_active', this, this.renderer.activeNodeList)
}
/**
* @Author: 王林
* @Date: 2021-07-04 20:20:09
* @Desc: 渲染节点到画布
* @Desc: 渲染节点到画布会移除旧的创建新的
*/
renderNode() {
if (this.group) {
this.group.remove()
}
this.createNode()
this.removeAllEvent()
this.removeAllNode()
this.createNodeData()
this.layout()
this.renderExpandBtn()
this.draw.add(this.group)
}
/**
* @Author: 王林
* @Date: 2021-07-04 22:47:01
* @Desc: 更新整体位置
* @Desc: 更新节点位置
*/
updatePos() {
updatePos(animate = true) {
if (!this.group) {
return;
}
let t = this.group.transform()
if (animate) {
this.group.animate(300).translate(this.left - t.translateX, this.top - t.translateY)
} else {
this.group.translate(this.left - t.translateX, this.top - t.translateY)
}
}
/**
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 13:55:58
* @Desc: 渲染
* @Desc: 递归渲染
*/
render() {
// 连线
this.renderLine()
// 按钮
this.renderExpandBtn()
// 节点
if (this.changed) {
if (this._initRender) {
this._initRender = false
this.renderNode()
} else {
this.updatePos()
}
this.changed = false
// 子节点
if (this.children && this.children.length && this.nodeData.data.expand !== false) {
this.children.forEach((child) => {
@ -513,6 +614,24 @@ class Node {
}
}
/**
* @Author: 王林
* @Date: 2021-07-10 09:24:55
* @Desc: 递归删除
*/
remove() {
this._initRender = true
this.removeAllEvent()
this.removeAllNode()
this.removeLine()
// 子节点
if (this.children && this.children.length) {
this.children.forEach((child) => {
child.remove()
})
}
}
/**
* @Author: 王林
* @Date: 2021-04-10 22:01:53
@ -520,24 +639,50 @@ class Node {
*/
renderLine() {
if (this.nodeData.data.expand === false) {
return;
return
}
let lines = this.renderer.layout.renderLine(this)
lines.forEach((line) => {
let childrenLen = this.nodeData.children.length
if (childrenLen > this._lines.length) {
// 创建缺少的线
new Array(childrenLen - this._lines.length).fill(0).forEach(() => {
this._lines.push(this.draw.path())
})
} else if (childrenLen < this._lines.length) {
// 删除多余的线
this._lines.slice(childrenLen).forEach((line) => {
line.remove()
})
this._lines = this._lines.slice(0, childrenLen)
}
// 画线
this.renderer.layout.renderLine(this, this._lines)
// 添加样式
this._lines.forEach((line) => {
this.style.line(line)
})
}
/**
* @Author: 王林
* @Date: 2021-04-11 19:47:01
* @Desc: 展开收缩按钮
* @Date: 2021-07-10 16:40:21
* @Desc: 移除连线
*/
renderExpandBtn() {
if (this.children.length <= 0 || this.isRoot) {
return;
removeLine() {
this._lines.forEach((line) => {
line.remove()
})
this._lines = []
}
/**
* @Author: 王林
* @Date: 2021-07-10 17:59:14
* @Desc: 创建或更新展开收缩按钮内容
*/
updateExpandBtnNode() {
if (this._expandBtn) {
this._expandBtn.clear()
}
let g = this.draw.group()
let iconSvg
if (this.nodeData.data.expand === false) {
iconSvg = btnsSvg.open
@ -546,29 +691,43 @@ class Node {
}
let node = SVG(iconSvg).size(this._expandBtnSize, this._expandBtnSize)
let fillNode = new Circle().size(this._expandBtnSize)
this.renderer.layout.renderExpandBtn(this, [node, fillNode])
node.dx(0).dy(-10)
fillNode.dx(0).dy(-10)
node.x(0).y(-this._expandBtnSize / 2)
fillNode.x(0).y(-this._expandBtnSize / 2)
this.style.iconBtn(node, fillNode)
g.mouseover(() => {
g.css({
this._expandBtn.add(fillNode).add(node)
}
/**
* @Author: 王林
* @Date: 2021-04-11 19:47:01
* @Desc: 展开收缩按钮
*/
renderExpandBtn() {
if (!this.nodeData.children || this.nodeData.children.length <= 0 || this.isRoot) {
return
}
this._expandBtn = new G()
this.updateExpandBtnNode()
this._expandBtn.on('mouseover', (e) => {
e.stopPropagation()
this._expandBtn.css({
cursor: 'pointer'
})
})
g.mouseout(() => {
g.css({
this._expandBtn.on('mouseout', (e) => {
e.stopPropagation()
this._expandBtn.css({
cursor: 'auto'
})
})
g.click(() => {
this._expandBtn.on('click', (e) => {
e.stopPropagation()
// 展开收缩
this.mindMap.execCommand('UPDATE_NODE_DATA', this, {
expand: !this.mindMap.nodeData.data.expand
}, children)
this.mindMap.execCommand('SET_NODE_EXPAND', this, !this.nodeData.data.expand)
this.mindMap.emit('expand_btn_click', this)
})
g.add(fillNode)
g.add(node)
this.group.add(this._expandBtn)
this.renderer.layout.renderExpandBtn(this, this._expandBtn)
}
/**
@ -580,7 +739,7 @@ class Node {
return {
paddingX: this.getStyle('paddingX', true, this.nodeData.data.isActive),
paddingY: this.getStyle('paddingY', true, this.nodeData.data.isActive)
};
}
}
/**
@ -599,19 +758,7 @@ class Node {
* @Desc: 修改某个样式
*/
setStyle(prop, value, isActive) {
if (isActive) {
this.mindMap.execCommand('UPDATE_NODE_DATA', this, {
activeStyle: {
...(this.nodeData.data.activeStyle || {}),
[prop]: value
}
})
} else {
this.mindMap.execCommand('UPDATE_NODE_DATA', this, {
[prop]: value
})
}
this.renderNode()
this.mindMap.execCommand('SET_NODE_STYLE', this, prop, value, isActive)
}
/**
@ -620,7 +767,7 @@ class Node {
* @Desc: 获取数据
*/
getData(key) {
return key ? this.nodeData.data[key] || '' : this.nodeData.data;
return key ? this.nodeData.data[key] || '' : this.nodeData.data
}
/**
@ -629,7 +776,61 @@ class Node {
* @Desc: 设置数据
*/
setData(data = {}) {
this.mindMap.execCommand('UPDATE_NODE_DATA', this, data)
this.mindMap.execCommand('SET_NODE_DATA', this, data)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:41:28
* @Desc: 设置文本
*/
setText(text) {
this.mindMap.execCommand('SET_NODE_TEXT', this, text)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:42:19
* @Desc: 设置图片
*/
setImage(imgData) {
this.mindMap.execCommand('SET_NODE_IMAGE', this, imgData)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:47:29
* @Desc: 设置图标
*/
setIcon(icons) {
this.mindMap.execCommand('SET_NODE_ICON', this, icons)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:50:41
* @Desc: 设置超链接
*/
setHyperlink(link, title) {
this.mindMap.execCommand('SET_NODE_HYPERLINK', this, link, title)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:53:24
* @Desc: 设置备注
*/
setNote(note) {
this.mindMap.execCommand('SET_NODE_NOTE', this, note)
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:55:08
* @Desc: 设置标签
*/
setTag(tag) {
this.mindMap.execCommand('SET_NODE_TAG', this, tag)
}
}

View File

@ -34,6 +34,8 @@ class Render {
this.draw = this.mindMap.draw
// 渲染树,操作过程中修改的都是这里的数据
this.renderTree = merge({}, this.mindMap.opt.data || {})
// 是否重新渲染
this.reRender = false
// 当前激活的节点列表
this.activeNodeList = []
// 根节点
@ -70,14 +72,48 @@ class Render {
* @Desc: 注册命令
*/
registerCommands() {
// 插入同级节点
this.insertNode = this.insertNode.bind(this)
this.mindMap.command.add('INSERT_NODE', this.insertNode)
// 插入子节点
this.insertChildNode = this.insertChildNode.bind(this)
this.mindMap.command.add('INSERT_CHILD_NODE', this.insertChildNode)
// 删除节点
this.removeNode = this.removeNode.bind(this)
this.mindMap.command.add('REMOVE_NODE', this.removeNode)
this.updateNodeData = this.updateNodeData.bind(this)
this.mindMap.command.add('UPDATE_NODE_DATA', this.updateNodeData)
// 修改节点样式
this.setNodeStyle = this.setNodeStyle.bind(this)
this.mindMap.command.add('SET_NODE_STYLE', this.setNodeStyle)
// 切换节点是否激活
this.setNodeActive = this.setNodeActive.bind(this)
this.mindMap.command.add('SET_NODE_ACTIVE', this.setNodeActive)
// 清除所有激活节点
this.clearActive = this.clearActive.bind(this)
this.mindMap.command.add('CLEAR_ACTIVE_NODE', this.clearActive)
// 切换节点是否展开
this.setNodeExpand = this.setNodeExpand.bind(this)
this.mindMap.command.add('SET_NODE_EXPAND', this.setNodeExpand)
// 设置节点数据
this.setNodeData = this.setNodeData.bind(this)
this.mindMap.command.add('SET_NODE_DATA', this.setNodeData)
// 设置节点文本
this.setNodeText = this.setNodeText.bind(this)
this.mindMap.command.add('SET_NODE_TEXT', this.setNodeText)
// 设置节点图片
this.setNodeImage = this.setNodeImage.bind(this)
this.mindMap.command.add('SET_NODE_IMAGE', this.setNodeImage)
// 设置节点图标
this.setNodeIcon = this.setNodeIcon.bind(this)
this.mindMap.command.add('SET_NODE_ICON', this.setNodeIcon)
// 设置节点超链接
this.setNodeHyperlink = this.setNodeHyperlink.bind(this)
this.mindMap.command.add('SET_NODE_HYPERLINK', this.setNodeHyperlink)
// 设置节点备注
this.setNodeNote = this.setNodeNote.bind(this)
this.mindMap.command.add('SET_NODE_NOTE', this.setNodeNote)
// 设置节点标签
this.setNodeTag = this.setNodeTag.bind(this)
this.mindMap.command.add('SET_NODE_TAG', this.setNodeTag)
}
/**
@ -87,7 +123,6 @@ class Render {
* @Desc: 渲染
*/
render() {
console.log('渲染')
this.root = this.layout.doLayout()
this.root.render()
}
@ -95,18 +130,27 @@ class Render {
/**
* @Author: 王林
* @Date: 2021-04-12 22:45:01
* @Desc: 当前激活的节点
* @Desc: 当前激活的节点
*/
clearActive() {
this.activeNodeList.forEach((item) => {
this.mindMap.execCommand('UPDATE_NODE_DATA', item, {
isActive: false
})
item.renderNode()
this.mindMap.execCommand('SET_NODE_ACTIVE', item, false)
})
this.activeNodeList = []
}
/**
* @Author: 王林
* @Date: 2021-07-10 10:04:04
* @Desc: 在激活列表里移除某个节点
*/
removeActiveNode(node) {
let index = this.activeNodeList.findIndex((item) => {
return item === node;
})
this.activeNodeList.splice(index, 1)
}
/**
* @Author: 王林
* @Date: 2021-05-04 13:46:08
@ -152,11 +196,12 @@ class Render {
if (this.activeNodeList.length <= 0) {
return;
}
let first = this.activeNodeList[0]
if (!first.nodeData.children) {
first.nodeData.children = []
let node = this.activeNodeList[0]
if (!node.nodeData.children) {
node.nodeData.children = []
}
first.nodeData.children.push({
let len = node.nodeData.children.length
node.nodeData.children.push({
"data": {
"text": "分支主题",
"expand": true
@ -164,6 +209,11 @@ class Render {
"children": []
})
this.mindMap.render()
if (node.isRoot || len <= 0) {
this.mindMap.batchExecution.push('renderNode', () => {
node.renderNode()
})
}
}
/**
@ -177,32 +227,176 @@ class Render {
}
this.activeNodeList.forEach((item) => {
if (item.isRoot) {
item.children.forEach((child) => {
child.remove()
})
item.children = []
item.nodeData.children = []
} else {
this.removeActiveNode(item)
let index = this.getNodeIndex(item)
item.remove()
item.parent.children.splice(index, 1)
item.parent.nodeData.children.splice(index, 1)
}
})
this.clearActive()
this.mindMap.render()
}
/**
* @Author: 王林
* @Date: 2021-07-08 21:54:30
* @Desc: 设置节点样式
*/
setNodeStyle(node, prop, value, isActive) {
let data = {}
if (isActive) {
data = {
activeStyle: {
...(node.nodeData.data.activeStyle || {}),
[prop]: value
}
}
} else {
data = {
[prop]: value
}
}
this.setNodeDataRender(node, data)
}
/**
* @Author: 王林
* @Date: 2021-07-08 22:13:03
* @Desc: 设置节点是否激活
*/
setNodeActive(node, active) {
this.setNodeData(node, {
isActive: active
})
node.renderNode()
}
/**
* @Author: 王林
* @Date: 2021-07-10 16:52:41
* @Desc: 设置节点是否展开
*/
setNodeExpand(node, expand) {
this.setNodeData(node, {
expand
})
if (expand) {// 展开
node.children.forEach((item) => {
item.render()
})
node.renderLine()
node.updateExpandBtnNode()
} else {// 收缩
node.children.forEach((item) => {
item.remove()
})
node.removeLine()
node.updateExpandBtnNode()
}
this.mindMap.render()
}
/**
* @Author: 王林
* @Date: 2021-07-09 22:04:19
* @Desc: 设置节点文本
*/
setNodeText(node, text) {
this.setNodeDataRender(node, {
text
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:37:40
* @Desc: 设置节点图片
*/
setNodeImage(node, { url, title, width, height }) {
this.setNodeDataRender(node, {
image: url,
imageTitle: title || '',
imageSize: {
width,
height,
},
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:44:06
* @Desc: 设置节点图标
*/
setNodeIcon(node, icons) {
this.setNodeDataRender(node, {
icon: icons
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:49:33
* @Desc: 设置节点超链接
*/
setNodeHyperlink(node, link, title = '') {
this.setNodeDataRender(node, {
hyperlink: link,
hyperlinkTitle: title,
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:52:59
* @Desc: 设置节点备注
*/
setNodeNote(node, note) {
this.setNodeDataRender(node, {
note
})
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:54:53
* @Desc: 设置节点标签
*/
setNodeTag(node, tag) {
this.setNodeDataRender(node, {
tag
})
}
/**
* @Author: 王林
* @Date: 2021-05-04 14:19:48
* @Desc: 更新节点数据
*/
updateNodeData(node, data, children) {
setNodeData(node, data) {
Object.keys(data).forEach((key) => {
node.nodeData.data[key] = data[key]
})
if (children) {
node.nodeData.children = children
}
/**
* @Author: 王林
* @Date: 2021-07-10 08:45:48
* @Desc: 设置节点数据并判断是否渲染
*/
setNodeDataRender(node, data) {
this.setNodeData(node, data)
let changed = node.getSize()
node.renderNode()
if (changed) {
this.mindMap.render()
}
node.changed = true
this.mindMap.render()
}
}

View File

@ -59,7 +59,7 @@ export default class TextEdit {
* @Desc: 显示文本编辑框
*/
show(node) {
this.showEditTextBox(node, node.textNode.node.node.getBoundingClientRect())
this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect())
}
/**
@ -95,10 +95,7 @@ export default class TextEdit {
}
this.renderer.activeNodeList.forEach((node) => {
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
this.mindMap.execCommand('UPDATE_NODE_DATA', node, {
text: str
})
node.changed = true
this.mindMap.execCommand('SET_NODE_TEXT', node, str)
this.mindMap.render()
})
this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList)

View File

@ -1,3 +1,5 @@
import Node from '../Node'
/**
* @Author: 王林
* @Date: 2021-04-12 22:24:30
@ -28,7 +30,6 @@ class Base {
* @Desc: 计算节点位置
*/
doLayout() {
console.log('布局')
throw new Error('【computed】方法为必要方法需要子类进行重写')
}
@ -50,6 +51,44 @@ class Base {
throw new Error('【renderExpandBtn】方法为必要方法需要子类进行重写')
}
/**
* @Author: 王林
* @Date: 2021-07-10 21:30:54
* @Desc: 创建节点实例
*/
createNode(data, parent, isRoot, layerIndex) {
// 创建节点
let newNode = null
// 复用节点
if (data && data._node && !this.renderer.reRender) {
newNode = data._node
newNode.reset()
newNode.layerIndex = layerIndex
} else {// 创建新节点
newNode = new Node({
data,
uid: this.mindMap.uid++,
renderer: this.renderer,
mindMap: this.mindMap,
draw: this.draw,
layerIndex
})
newNode.getSize()
// 数据关联实际节点
data._node = newNode
}
// 根节点
if (isRoot) {
newNode.isRoot = true
this.root = newNode
} else {
// 互相收集
newNode.parent = parent._node
parent._node.addChildren(newNode)
}
return newNode;
}
/**
* javascript comment
* @Author: 王林25

View File

@ -2,7 +2,6 @@ import Base from './Base';
import {
walk
} from '../utils'
import Node from '../Node'
/**
* @Author: 王林
@ -44,48 +43,25 @@ class LogicalStructure extends Base {
*/
computedBaseValue() {
walk(this.renderTree, null, (cur, parent, isRoot, layerIndex) => {
// 创建节点
let newNode = null
if (cur && cur._node) {
newNode = cur._node
newNode.children = []
newNode.parent = null
if (cur._node.changed) {
newNode.refreshSize()
}
} else {
newNode = new Node({
data: cur,
uid: this.mindMap.uid++,
renderer: this.renderer,
mindMap: this.mindMap,
draw: this.draw,
layerIndex
})
// 数据关联实际节点
cur._node = newNode
}
let newNode = this.createNode(cur, parent, isRoot, layerIndex)
// 根节点定位在画布中心位置
if (isRoot) {
newNode.isRoot = true
newNode.left = (this.mindMap.width - newNode.width) / 2
newNode.top = (this.mindMap.height - newNode.height) / 2
this.root = newNode
} else {
// 非根节点
let marginX = layerIndex === 1 ? this.mindMap.themeConfig.second.marginX : this.mindMap.themeConfig.node.marginX
// 定位到父节点右侧
newNode.left = parent._node.left + parent._node.width + marginX
// 互相收集
newNode.parent = parent._node
parent._node.addChildren(newNode)
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) : 0
}, 0) + (len + 1) * this.getMarginY(layerIndex + 1) : 0
}, true, 0)
}
@ -97,8 +73,8 @@ class LogicalStructure extends Base {
*/
computedTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => {
if (node.children && node.children.length) {
let marginY = this.getMarginY(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
@ -118,8 +94,11 @@ class LogicalStructure extends Base {
*/
adjustTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => {
if (!node.nodeData.data.expand) {
return;
}
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
let difference = node.childrenAreaHeight - this.getMarginY(layerIndex) - node.height
let difference = node.childrenAreaHeight - this.getMarginY(layerIndex + 1) - node.height
if (difference > 0) {
this.updateBrothers(node, difference / 2)
}
@ -162,7 +141,7 @@ class LogicalStructure extends Base {
* @Date: 2021-04-11 14:42:48
* @Desc: 绘制连线连接该节点到其子节点
*/
renderLine(node) {
renderLine(node, lines) {
if (node.children.length <= 0) {
return [];
}
@ -172,12 +151,7 @@ class LogicalStructure extends Base {
width,
height
} = node
let lines = []
if (!node.isRoot) {
let line = this.draw.line(left + width, top + height / 2, left + width + 20, top + height / 2)
lines.push(line)
}
node.children.forEach((item) => {
node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width / 2 : left + width + 20
let y1 = node.layerIndex === 0 ? top + height / 2 : top + height / 2
let x2 = item.left
@ -188,10 +162,8 @@ class LogicalStructure extends Base {
} else {
path = this.cubicBezierPath(x1, y1, x2, y2)
}
let line = this.draw.path(path)
lines.push(line)
lines[index].plot(path)
})
return lines;
}
/**
@ -199,16 +171,12 @@ class LogicalStructure extends Base {
* @Date: 2021-04-11 19:54:26
* @Desc: 渲染按钮
*/
renderExpandBtn(node, icons) {
renderExpandBtn(node, btn) {
let {
left,
top,
width,
height
} = node
icons.forEach((icon) => {
icon.x(left + width).y(top + height / 2)
})
btn.translate(width, height / 2)
}
}

View File

@ -75,7 +75,7 @@ class Render {
draw: this.draw
})
// 计算节点的宽高
newNode.refreshSize()
newNode.getSize()
// 计算节点的top
if (isRoot) {
newNode.isRoot = true

View File

@ -73,7 +73,7 @@ class Render {
draw: this.draw
})
// 计算节点的宽高
newNode.refreshSize()
newNode.getSize()
// 计算节点的top
if (isRoot) {
newNode.isRoot = true

View File

@ -5,8 +5,8 @@
*/
export default {
// 节点内边距
paddingX: 20,
paddingY: 10,
paddingX: 15,
paddingY: 5,
// 图片显示的最大宽度
imgMaxWidth: 100,
// 图片显示的最大高度
@ -31,6 +31,7 @@ export default {
fontSize: 16,
fontWeight: 'bold',
fontStyle: 'normal',
lineHeight: 1.5,
borderColor: 'transparent',
borderWidth: 0,
borderDasharray: 'none',
@ -52,6 +53,7 @@ export default {
fontSize: 16,
fontWeight: 'noraml',
fontStyle: 'normal',
lineHeight: 1.5,
borderColor: '#549688',
borderWidth: 1,
borderDasharray: 'none',
@ -66,13 +68,14 @@ export default {
// 三级及以下节点样式
node: {
marginX: 50,
marginY: 10,
marginY: 0,
fillColor: 'transparent',
fontFamily: '微软雅黑, Microsoft YaHei',
color: '#6a6d6c',
fontSize: 14,
fontWeight: 'noraml',
fontStyle: 'normal',
lineHeight: 1.5,
borderColor: 'transparent',
borderWidth: 0,
borderRadius: 5,

View File

@ -5,8 +5,11 @@
* @Desc: 深度优先遍历树
*/
export const walk = (root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0) => {
beforeCallback && beforeCallback(root, parent, isRoot, layerIndex, index)
if (root.children && root.children.length > 0) {
let stop = false
if (beforeCallback) {
stop = beforeCallback(root, parent, isRoot, layerIndex, index)
}
if (!stop && root.children && root.children.length > 0) {
let _layerIndex = layerIndex + 1
root.children.forEach((node, nodeIndex) => {
walk(node, root, beforeCallback, afterCallback, false, _layerIndex, nodeIndex)

View File

@ -98,7 +98,10 @@ export default {
});
};
img.onerror = (e) => {
reject(e);
resolve({
width: 0,
height: 0,
});
};
});
},
@ -109,7 +112,7 @@ export default {
* @Desc: 删除图片
*/
deleteImg() {
this.$emit("change", "none");
this.$emit("change", "");
this.file = null;
},
},

View File

@ -46,6 +46,9 @@ export const fontFamilyList = [
// 字号
export const fontSizeList = [10, 12, 16, 18, 24, 32, 48]
// 行高
export const lineHeightList = [1, 1.5, 2, 2.5, 3]
// 颜色
export const colorList = [
'#4D4D4D',

View File

@ -68,10 +68,7 @@ export default {
* @Desc: 确定
*/
confirm() {
this.activeNode.setData({
hyperlink: this.link,
hyperlinkTitle: this.linkTitle,
});
this.activeNode.setHyperlink(this.link, this.linkTitle);
this.cancel();
},
},

View File

@ -67,9 +67,7 @@ export default {
} else {
this.icon.push(type + '_' + name)
}
this.activeNode.setData({
icon: [...this.icon]
})
this.activeNode.setIcon([...this.icon])
}
},
};

View File

@ -20,10 +20,10 @@
<script>
import ImgUpload from "@/components/ImgUpload";
/**
* @Author: 王林
* @Date: 2021-06-24 22:53:45
* @Desc: 节点图片内容设置
/**
* @Author: 王林
* @Date: 2021-06-24 22:53:45
* @Desc: 节点图片内容设置
*/
export default {
name: "NodeImage",
@ -73,16 +73,16 @@ export default {
async confirm() {
try {
let { width, height } = await this.$refs.ImgUpload.getSize();
this.activeNode.setData({
image: this.img,
imageTitle: this.imgTitle,
imageSize: {
width,
height,
},
this.activeNode.setImage({
url: this.img || "none",
title: this.imgTitle,
width,
height,
});
this.cancel();
} catch (error) {}
} catch (error) {
console.log(error);
}
},
},
};

View File

@ -65,9 +65,7 @@ export default {
* @Desc: 确定
*/
confirm() {
this.activeNode.setData({
note: this.note,
});
this.activeNode.setNote(this.note);
this.cancel();
},
},

View File

@ -38,10 +38,10 @@
<script>
import { tagColorList } from "simple-mind-map/src/utils/constant";
/**
* @Author: 王林
* @Date: 2021-06-24 22:54:03
* @Desc: 节点标签内容设置
/**
* @Author: 王林
* @Date: 2021-06-24 22:54:03
* @Desc: 节点标签内容设置
*/
export default {
name: "NodeTag",
@ -105,9 +105,7 @@ export default {
* @Desc: 确定
*/
confirm() {
this.activeNode.setData({
tag: this.tagArr,
});
this.activeNode.setTag(this.tagArr);
this.cancel();
},
},

View File

@ -9,37 +9,62 @@
<!-- 文字 -->
<div class="title noTop">文字</div>
<div class="row">
<el-select
size="mini"
style="width: 160px"
v-model="style.fontFamily"
placeholder=""
@change="update('fontFamily')"
>
<el-option
v-for="item in fontFamilyList"
:key="item.value"
:label="item.name"
:value="item.value"
:style="{ fontFamily: item.value }"
<div class="rowItem">
<span class="name">字体</span>
<el-select
size="mini"
v-model="style.fontFamily"
placeholder=""
@change="update('fontFamily')"
>
</el-option>
</el-select>
<el-select
size="mini"
style="width: 80px"
v-model="style.fontSize"
placeholder=""
@change="update('fontSize')"
>
<el-option
v-for="item in fontSizeList"
:key="item"
:label="item"
:value="item"
<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>
<el-select
size="mini"
style="width: 80px"
v-model="style.fontSize"
placeholder=""
@change="update('fontSize')"
>
</el-option>
</el-select>
<el-option
v-for="item in fontSizeList"
:key="item"
:label="item"
:value="item"
>
</el-option>
</el-select>
</div>
<div class="rowItem">
<span class="name">行高</span>
<el-select
size="mini"
style="width: 80px"
v-model="style.lineHeight"
placeholder=""
@change="update('lineHeight')"
>
<el-option
v-for="item in lineHeightList"
:key="item"
:label="item"
:value="item"
>
</el-option>
</el-select>
</div>
</div>
<div class="row">
<div class="btnGroup">
@ -220,6 +245,7 @@ import {
borderWidthList,
borderDasharrayList,
borderRadiusList,
lineHeightList,
} from "@/config";
/**
@ -240,6 +266,7 @@ export default {
borderWidthList,
borderDasharrayList,
borderRadiusList,
lineHeightList,
activeNode: null,
activeTab: "normal",
style: {
@ -248,6 +275,7 @@ export default {
color: "",
fontFamily: "",
fontSize: "",
lineHeight: "",
textDecoration: "",
fontWeight: "",
fontStyle: "",
@ -297,6 +325,7 @@ export default {
"color",
"fontFamily",
"fontSize",
"lineHeight",
"textDecoration",
"fontWeight",
"fontStyle",
@ -320,7 +349,6 @@ export default {
* @Desc: 修改样式
*/
update(prop) {
console.log(this.style[prop])
this.activeNode.setStyle(
prop,
this.style[prop],