优化注释,去掉冗余信息

This commit is contained in:
wanglin2 2023-01-10 11:08:55 +08:00
parent e634fee753
commit 0d3c1b7417
49 changed files with 3524 additions and 5135 deletions

View File

@ -53,19 +53,9 @@ const defaultOpt = {
*/ */
} }
/** // 思维导图
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 11:18:47
* @Desc: 思维导图
*/
class MindMap { class MindMap {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 11:19:01
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
// 合并选项 // 合并选项
this.opt = this.handleOpt(merge(defaultOpt, opt)) this.opt = this.handleOpt(merge(defaultOpt, opt))
@ -149,11 +139,7 @@ class MindMap {
}, 0) }, 0)
} }
/** // 配置参数处理
* @Author: 王林
* @Date: 2021-07-01 22:15:22
* @Desc: 配置参数处理
*/
handleOpt(opt) { handleOpt(opt) {
// 检查布局配置 // 检查布局配置
if (!layoutValueList.includes(opt.layout)) { if (!layoutValueList.includes(opt.layout)) {
@ -164,12 +150,7 @@ class MindMap {
return opt return opt
} }
/** // 渲染,部分渲染
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 18:47:29
* @Desc: 渲染部分渲染
*/
render() { render() {
this.batchExecution.push('render', () => { this.batchExecution.push('render', () => {
this.initTheme() this.initTheme()
@ -178,11 +159,7 @@ class MindMap {
}) })
} }
/** // 重新渲染
* @Author: 王林
* @Date: 2021-07-08 22:05:11
* @Desc: 重新渲染
*/
reRender() { reRender() {
this.batchExecution.push('render', () => { this.batchExecution.push('render', () => {
this.draw.clear() this.draw.clear()
@ -192,11 +169,7 @@ class MindMap {
}) })
} }
/** // 容器尺寸变化,调整尺寸
* @Author: 王林
* @Date: 2021-07-11 21:16:52
* @Desc: 容器尺寸变化调整尺寸
*/
resize() { resize() {
this.elRect = this.el.getBoundingClientRect() this.elRect = this.el.getBoundingClientRect()
this.width = this.elRect.width this.width = this.elRect.width
@ -204,38 +177,22 @@ class MindMap {
this.svg.size(this.width, this.height) this.svg.size(this.width, this.height)
} }
/** // 监听事件
* @Author: 王林
* @Date: 2021-04-24 13:25:50
* @Desc: 监听事件
*/
on(event, fn) { on(event, fn) {
this.event.on(event, fn) this.event.on(event, fn)
} }
/** // 触发事件
* @Author: 王林
* @Date: 2021-04-24 13:51:35
* @Desc: 触发事件
*/
emit(event, ...args) { emit(event, ...args) {
this.event.emit(event, ...args) this.event.emit(event, ...args)
} }
/** // 解绑事件
* @Author: 王林
* @Date: 2021-04-24 13:53:54
* @Desc: 解绑事件
*/
off(event, fn) { off(event, fn) {
this.event.off(event, fn) this.event.off(event, fn)
} }
/** // 设置主题
* @Author: 王林
* @Date: 2021-05-05 13:32:43
* @Desc: 设置主题
*/
initTheme() { initTheme() {
// 合并主题配置 // 合并主题配置
this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig) this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig)
@ -243,70 +200,40 @@ class MindMap {
Style.setBackgroundStyle(this.el, this.themeConfig) Style.setBackgroundStyle(this.el, this.themeConfig)
} }
/** // 设置主题
* @Author: 王林
* @Date: 2021-05-05 13:52:08
* @Desc: 设置主题
*/
setTheme(theme) { setTheme(theme) {
this.renderer.clearAllActive() this.renderer.clearAllActive()
this.opt.theme = theme this.opt.theme = theme
this.reRender() this.reRender()
} }
/** // 获取当前主题
* @Author: 王林
* @Date: 2021-06-25 23:52:37
* @Desc: 获取当前主题
*/
getTheme() { getTheme() {
return this.opt.theme return this.opt.theme
} }
/** // 设置主题配置
* @Author: 王林
* @Date: 2021-05-05 13:50:17
* @Desc: 设置主题配置
*/
setThemeConfig(config) { setThemeConfig(config) {
this.opt.themeConfig = config this.opt.themeConfig = config
this.reRender() this.reRender()
} }
/** // 获取自定义主题配置
* @Author: 王林
* @Date: 2021-08-01 10:38:34
* @Desc: 获取自定义主题配置
*/
getCustomThemeConfig() { getCustomThemeConfig() {
return this.opt.themeConfig return this.opt.themeConfig
} }
/** // 获取某个主题配置值
* @Author: 王林
* @Date: 2021-05-05 14:01:29
* @Desc: 获取某个主题配置值
*/
getThemeConfig(prop) { getThemeConfig(prop) {
return prop === undefined ? this.themeConfig : this.themeConfig[prop] return prop === undefined ? this.themeConfig : this.themeConfig[prop]
} }
/** // 获取当前布局结构
* javascript comment
* @Author: 王林25
* @Date: 2021-07-13 16:17:06
* @Desc: 获取当前布局结构
*/
getLayout() { getLayout() {
return this.opt.layout return this.opt.layout
} }
/** // 设置布局结构
* javascript comment
* @Author: 王林25
* @Date: 2021-07-13 16:17:33
* @Desc: 设置布局结构
*/
setLayout(layout) { setLayout(layout) {
// 检查布局配置 // 检查布局配置
if (!layoutValueList.includes(layout)) { if (!layoutValueList.includes(layout)) {
@ -317,20 +244,12 @@ class MindMap {
this.render() this.render()
} }
/** // 执行命令
* @Author: 王林
* @Date: 2021-05-04 13:01:00
* @Desc: 执行命令
*/
execCommand(...args) { execCommand(...args) {
this.command.exec(...args) this.command.exec(...args)
} }
/** // 动态设置思维导图数据,纯节点数据
* @Author: 王林
* @Date: 2021-08-03 22:58:12
* @Desc: 动态设置思维导图数据纯节点数据
*/
setData(data) { setData(data) {
this.execCommand('CLEAR_ACTIVE_NODE') this.execCommand('CLEAR_ACTIVE_NODE')
this.command.clearHistory() this.command.clearHistory()
@ -338,12 +257,7 @@ class MindMap {
this.reRender() this.reRender()
} }
/** // 动态设置思维导图数据,包括节点数据、布局、主题、视图
* javascript comment
* @Author: 王林25
* @Date: 2022-09-21 16:39:13
* @Desc: 动态设置思维导图数据包括节点数据布局主题视图
*/
setFullData(data) { setFullData(data) {
if (data.root) { if (data.root) {
this.setData(data.root) this.setData(data.root)
@ -364,12 +278,7 @@ class MindMap {
} }
} }
/** // 获取思维导图数据,节点树、主题、布局等
* javascript comment
* @Author: 王林
* @Date: 2022-09-24 14:42:07
* @Desc: 获取思维导图数据节点树主题布局等
*/
getData(withConfig) { getData(withConfig) {
let nodeData = this.command.getCopyData() let nodeData = this.command.getCopyData()
let data = {} let data = {}
@ -389,21 +298,13 @@ class MindMap {
return simpleDeepClone(data) return simpleDeepClone(data)
} }
/** // 导出
* @Author: 王林
* @Date: 2021-07-01 22:06:38
* @Desc: 导出
*/
async export(...args) { async export(...args) {
let result = await this.doExport.export(...args) let result = await this.doExport.export(...args)
return result return result
} }
/** // 转换位置
* @Author: 王林
* @Date: 2021-07-11 09:20:03
* @Desc: 转换位置
*/
toPos(x, y) { toPos(x, y) {
return { return {
x: x - this.elRect.left, x: x - this.elRect.left,
@ -411,12 +312,7 @@ class MindMap {
} }
} }
/** // 设置只读模式、编辑模式
* javascript comment
* @Author: 王林25
* @Date: 2022-06-08 14:12:38
* @Desc: 设置只读模式编辑模式
*/
setMode(mode) { setMode(mode) {
if (!['readonly', 'edit'].includes(mode)) { if (!['readonly', 'edit'].includes(mode)) {
return return

View File

@ -0,0 +1,32 @@
// 将/** */类型的注释转换为//类型
const path = require('path')
const fs = require('fs')
const entryPath = path.resolve(__dirname, '../src')
const transform = dir => {
let dirs = fs.readdirSync(dir)
dirs.forEach(item => {
let file = path.join(dir, item)
if (fs.statSync(file).isDirectory()) {
transform(file)
} else if (/\.js$/.test(file)) {
rewriteComments(file)
}
})
}
const rewriteComments = file => {
let content = fs.readFileSync(file, 'utf-8')
console.log('当前转换文件:', file)
content = content.replace(/\/\*\*[^/]+\*\//g, str => {
let res = /@Desc:([^\n]+)\n/g.exec(str)
if (res.length > 0) {
return '// ' + res[1]
}
})
fs.writeFileSync(file, content)
}
transform(entryPath)
rewriteComments(path.join(__dirname, '../index.js'))

View File

@ -1,8 +1,4 @@
/** // 在下一个事件循环里执行任务
* @Author: 王林
* @Date: 2021-06-27 13:16:23
* @Desc: 在下一个事件循环里执行任务
*/
const nextTick = function (fn, ctx) { const nextTick = function (fn, ctx) {
let pending = false let pending = false
let timerFunc = null let timerFunc = null
@ -33,28 +29,16 @@ const nextTick = function (fn, ctx) {
} }
} }
/** // 批量执行
* @Author: 王林
* @Date: 2021-06-26 22:40:52
* @Desc: 批量执行
*/
class BatchExecution { class BatchExecution {
/** // 构造函数
* @Author: 王林
* @Date: 2021-06-26 22:41:41
* @Desc: 构造函数
*/
constructor() { constructor() {
this.has = {} this.has = {}
this.queue = [] this.queue = []
this.nextTick = nextTick(this.flush, this) this.nextTick = nextTick(this.flush, this)
} }
/** // 添加任务
* @Author: 王林
* @Date: 2021-06-27 12:54:04
* @Desc: 添加任务
*/
push(name, fn) { push(name, fn) {
if (this.has[name]) { if (this.has[name]) {
return return
@ -67,11 +51,7 @@ class BatchExecution {
this.nextTick() this.nextTick()
} }
/** // 执行队列
* @Author: 王林
* @Date: 2021-06-27 13:09:24
* @Desc: 执行队列
*/
flush() { flush() {
let fns = this.queue.slice(0) let fns = this.queue.slice(0)
this.queue = [] this.queue = []

View File

@ -1,16 +1,8 @@
import { copyRenderTree, simpleDeepClone } from './utils' import { copyRenderTree, simpleDeepClone } from './utils'
/** // 命令类
* @Author: 王林
* @Date: 2021-05-04 13:10:06
* @Desc: 命令类
*/
class Command { class Command {
/** // 构造函数
* @Author: 王林
* @Date: 2021-05-04 13:10:24
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
this.opt = opt this.opt = opt
this.mindMap = opt.mindMap this.mindMap = opt.mindMap
@ -21,22 +13,14 @@ class Command {
this.registerShortcutKeys() this.registerShortcutKeys()
} }
/** // 清空历史数据
* @Author: 王林
* @Date: 2021-08-03 23:06:55
* @Desc: 清空历史数据
*/
clearHistory() { clearHistory() {
this.history = [] this.history = []
this.activeHistoryIndex = 0 this.activeHistoryIndex = 0
this.mindMap.emit('back_forward', 0, 0) this.mindMap.emit('back_forward', 0, 0)
} }
/** // 注册快捷键
* @Author: 王林
* @Date: 2021-08-02 23:23:19
* @Desc: 注册快捷键
*/
registerShortcutKeys() { registerShortcutKeys() {
this.mindMap.keyCommand.addShortcut('Control+z', () => { this.mindMap.keyCommand.addShortcut('Control+z', () => {
this.mindMap.execCommand('BACK') this.mindMap.execCommand('BACK')
@ -46,11 +30,7 @@ class Command {
}) })
} }
/** // 执行命令
* @Author: 王林
* @Date: 2021-05-04 13:12:30
* @Desc: 执行命令
*/
exec(name, ...args) { exec(name, ...args) {
if (this.commands[name]) { if (this.commands[name]) {
this.commands[name].forEach(fn => { this.commands[name].forEach(fn => {
@ -63,11 +43,7 @@ class Command {
} }
} }
/** // 添加命令
* @Author: 王林
* @Date: 2021-05-04 13:13:01
* @Desc: 添加命令
*/
add(name, fn) { add(name, fn) {
if (this.commands[name]) { if (this.commands[name]) {
this.commands[name].push(fn) this.commands[name].push(fn)
@ -76,11 +52,7 @@ class Command {
} }
} }
/** // 移除命令
* @Author: 王林
* @Date: 2021-07-15 23:02:41
* @Desc: 移除命令
*/
remove(name, fn) { remove(name, fn) {
if (!this.commands[name]) { if (!this.commands[name]) {
return return
@ -98,11 +70,7 @@ class Command {
} }
} }
/** // 添加回退数据
* @Author: 王林
* @Date: 2021-05-04 14:35:43
* @Desc: 添加回退数据
*/
addHistory() { addHistory() {
let data = this.getCopyData() let data = this.getCopyData()
this.history.push(simpleDeepClone(data)) this.history.push(simpleDeepClone(data))
@ -115,11 +83,7 @@ class Command {
) )
} }
/** // 回退
* @Author: 王林
* @Date: 2021-07-11 22:34:53
* @Desc: 回退
*/
back(step = 1) { back(step = 1) {
if (this.activeHistoryIndex - step >= 0) { if (this.activeHistoryIndex - step >= 0) {
this.activeHistoryIndex -= step this.activeHistoryIndex -= step
@ -132,12 +96,7 @@ class Command {
} }
} }
/** // 前进
* javascript comment
* @Author: 王林25
* @Date: 2021-07-12 10:45:31
* @Desc: 前进
*/
forward(step = 1) { forward(step = 1) {
let len = this.history.length let len = this.history.length
if (this.activeHistoryIndex + step <= len - 1) { if (this.activeHistoryIndex + step <= len - 1) {
@ -147,11 +106,7 @@ class Command {
} }
} }
/** // 获取渲染树数据副本
* @Author: 王林
* @Date: 2021-05-04 15:02:58
* @Desc: 获取渲染树数据副本
*/
getCopyData() { getCopyData() {
return copyRenderTree({}, this.mindMap.renderer.renderTree) return copyRenderTree({}, this.mindMap.renderer.renderTree)
} }

View File

@ -1,296 +1,254 @@
import { bfsWalk, throttle } from './utils' import { bfsWalk, throttle } from './utils'
import Base from './layouts/Base' import Base from './layouts/Base'
/** // 节点拖动类
* javascript comment class Drag extends Base {
* @Author: 王林25 // 构造函数
* @Date: 2021-11-23 17:38:55 constructor({ mindMap }) {
* @Desc: 节点拖动类 super(mindMap.renderer)
*/ this.mindMap = mindMap
class Drag extends Base { this.reset()
/** this.bindEvent()
* @Author: 王林 }
* @Date: 2021-07-10 22:35:16
* @Desc: 构造函数 // 复位
*/ reset() {
constructor({ mindMap }) { // 当前拖拽节点
super(mindMap.renderer) this.node = null
this.mindMap = mindMap // 当前重叠节点
this.reset() this.overlapNode = null
this.bindEvent() // 当前上一个同级节点
} this.prevNode = null
// 当前下一个同级节点
/** this.nextNode = null
* javascript comment // 画布的变换数据
* @Author: 王林25 this.drawTransform = null
* @Date: 2021-11-23 19:33:56 // 克隆节点
* @Desc: 复位 this.clone = null
*/ // 连接线
reset() { this.line = null
// 当前拖拽节点 // 同级位置占位符
this.node = null this.placeholder = null
// 当前重叠节点 // 鼠标按下位置和节点左上角的偏移量
this.overlapNode = null this.offsetX = 0
// 当前上一个同级节点 this.offsetY = 0
this.prevNode = null // 克隆节点左上角的坐标
// 当前下一个同级节点 this.cloneNodeLeft = 0
this.nextNode = null this.cloneNodeTop = 0
// 画布的变换数据 // 当前鼠标是否按下
this.drawTransform = null this.isMousedown = false
// 克隆节点 // 拖拽的鼠标位置变量
this.clone = null this.mouseDownX = 0
// 连接线 this.mouseDownY = 0
this.line = null this.mouseMoveX = 0
// 同级位置占位符 this.mouseMoveY = 0
this.placeholder = null }
// 鼠标按下位置和节点左上角的偏移量
this.offsetX = 0 // 绑定事件
this.offsetY = 0 bindEvent() {
// 克隆节点左上角的坐标 this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this)
this.cloneNodeLeft = 0 this.mindMap.on('node_mousedown', (node, e) => {
this.cloneNodeTop = 0 if (this.mindMap.opt.readonly || node.isGeneralization) {
// 当前鼠标是否按下 return
this.isMousedown = false }
// 拖拽的鼠标位置变量 if (e.which !== 1 || node.isRoot) {
this.mouseDownX = 0 return
this.mouseDownY = 0 }
this.mouseMoveX = 0 e.preventDefault()
this.mouseMoveY = 0 // 计算鼠标按下的位置距离节点左上角的距离
} this.drawTransform = this.mindMap.draw.transform()
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
/** let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
* @Author: 王林 this.offsetX = x - (node.left * scaleX + translateX)
* @Date: 2021-07-10 22:36:36 this.offsetY = y - (node.top * scaleY + translateY)
* @Desc: 绑定事件 this.node = node
*/ this.isMousedown = true
bindEvent() { this.mouseDownX = x
this.checkOverlapNode = throttle(this.checkOverlapNode, 300, this) this.mouseDownY = y
this.mindMap.on('node_mousedown', (node, e) => { })
if (this.mindMap.opt.readonly || node.isGeneralization) { this.mindMap.on('mousemove', e => {
return if (this.mindMap.opt.readonly) {
} return
if (e.which !== 1 || node.isRoot) { }
return if (!this.isMousedown) {
} return
e.preventDefault() }
// 计算鼠标按下的位置距离节点左上角的距离 e.preventDefault()
this.drawTransform = this.mindMap.draw.transform() let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
let { scaleX, scaleY, translateX, translateY } = this.drawTransform this.mouseMoveX = x
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY) this.mouseMoveY = y
this.offsetX = x - (node.left * scaleX + translateX) if (
this.offsetY = y - (node.top * scaleY + translateY) Math.abs(x - this.mouseDownX) <= 10 &&
this.node = node Math.abs(y - this.mouseDownY) <= 10 &&
this.isMousedown = true !this.node.isDrag
this.mouseDownX = x ) {
this.mouseDownY = y return
}) }
this.mindMap.on('mousemove', e => { this.mindMap.renderer.clearAllActive()
if (this.mindMap.opt.readonly) { this.onMove(x, y)
return })
} this.onMouseup = this.onMouseup.bind(this)
if (!this.isMousedown) { this.mindMap.on('node_mouseup', this.onMouseup)
return this.mindMap.on('mouseup', this.onMouseup)
} }
e.preventDefault()
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY) // 鼠标松开事件
this.mouseMoveX = x onMouseup(e) {
this.mouseMoveY = y if (!this.isMousedown) {
if ( return
Math.abs(x - this.mouseDownX) <= 10 && }
Math.abs(y - this.mouseDownY) <= 10 && this.isMousedown = false
!this.node.isDrag let _nodeIsDrag = this.node.isDrag
) { this.node.isDrag = false
return this.node.show()
} this.removeCloneNode()
this.mindMap.renderer.clearAllActive() // 存在重叠子节点,则移动作为其子节点
this.onMove(x, y) if (this.overlapNode) {
}) this.mindMap.renderer.setNodeActive(this.overlapNode, false)
this.onMouseup = this.onMouseup.bind(this) this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
this.mindMap.on('node_mouseup', this.onMouseup) } else if (this.prevNode) {
this.mindMap.on('mouseup', this.onMouseup) // 存在前一个相邻节点,作为其下一个兄弟节点
} this.mindMap.renderer.setNodeActive(this.prevNode, false)
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
/** } else if (this.nextNode) {
* javascript comment // 存在下一个相邻节点,作为其前一个兄弟节点
* @Author: 王林25 this.mindMap.renderer.setNodeActive(this.nextNode, false)
* @Date: 2021-11-23 19:38:02 this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
* @Desc: 鼠标松开事件 } else if (_nodeIsDrag) {
*/ // 自定义位置
onMouseup(e) { let { x, y } = this.mindMap.toPos(
if (!this.isMousedown) { e.clientX - this.offsetX,
return e.clientY - this.offsetY
} )
this.isMousedown = false let { scaleX, scaleY, translateX, translateY } = this.drawTransform
let _nodeIsDrag = this.node.isDrag x = (x - translateX) / scaleX
this.node.isDrag = false y = (y - translateY) / scaleY
this.node.show() this.node.left = x
this.removeCloneNode() this.node.top = y
// 存在重叠子节点,则移动作为其子节点 this.node.customLeft = x
if (this.overlapNode) { this.node.customTop = y
this.mindMap.renderer.setNodeActive(this.overlapNode, false) this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y)
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode) this.mindMap.render()
} else if (this.prevNode) { }
// 存在前一个相邻节点,作为其下一个兄弟节点 this.reset()
this.mindMap.renderer.setNodeActive(this.prevNode, false) }
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
} else if (this.nextNode) { // 创建克隆节点
// 存在下一个相邻节点,作为其前一个兄弟节点 createCloneNode() {
this.mindMap.renderer.setNodeActive(this.nextNode, false) if (!this.clone) {
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode) // 节点
} else if (_nodeIsDrag) { this.clone = this.node.group.clone()
// 自定义位置 this.clone.opacity(0.5)
let { x, y } = this.mindMap.toPos( this.clone.css('z-index', 99999)
e.clientX - this.offsetX, this.node.isDrag = true
e.clientY - this.offsetY this.node.hide()
) // 连接线
let { scaleX, scaleY, translateX, translateY } = this.drawTransform this.line = this.draw.path()
x = (x - translateX) / scaleX this.line.opacity(0.5)
y = (y - translateY) / scaleY this.node.styleLine(this.line, this.node)
this.node.left = x // 同级位置占位符
this.node.top = y this.placeholder = this.draw.rect().fill({
this.node.customLeft = x color: this.node.style.merge('lineColor', true)
this.node.customTop = y })
this.mindMap.execCommand('SET_NODE_CUSTOM_POSITION', this.node, x, y) this.mindMap.draw.add(this.clone)
this.mindMap.render() }
} }
this.reset()
} // 移除克隆节点
removeCloneNode() {
/** if (!this.clone) {
* javascript comment return
* @Author: 王林25 }
* @Date: 2021-11-23 19:34:53 this.clone.remove()
* @Desc: 创建克隆节点 this.line.remove()
*/ this.placeholder.remove()
createCloneNode() { }
if (!this.clone) {
// 节点 // 拖动中
this.clone = this.node.group.clone() onMove(x, y) {
this.clone.opacity(0.5) if (!this.isMousedown) {
this.clone.css('z-index', 99999) return
this.node.isDrag = true }
this.node.hide() this.createCloneNode()
// 连接线 let { scaleX, scaleY, translateX, translateY } = this.drawTransform
this.line = this.draw.path() this.cloneNodeLeft = x - this.offsetX
this.line.opacity(0.5) this.cloneNodeTop = y - this.offsetY
this.node.styleLine(this.line, this.node) x = (this.cloneNodeLeft - translateX) / scaleX
// 同级位置占位符 y = (this.cloneNodeTop - translateY) / scaleY
this.placeholder = this.draw.rect().fill({ let t = this.clone.transform()
color: this.node.style.merge('lineColor', true) this.clone.translate(x - t.translateX, y - t.translateY)
}) // 连接线
this.mindMap.draw.add(this.clone) let parent = this.node.parent
} this.line.plot(
} this.quadraticCurvePath(
parent.left + parent.width / 2,
/** parent.top + parent.height / 2,
* javascript comment x + this.node.width / 2,
* @Author: 王林25 y + this.node.height / 2
* @Date: 2021-11-23 19:35:16 )
* @Desc: 移除克隆节点 )
*/ this.checkOverlapNode()
removeCloneNode() { }
if (!this.clone) {
return // 检测重叠节点
} checkOverlapNode() {
this.clone.remove() if (!this.drawTransform) {
this.line.remove() return
this.placeholder.remove() }
} let { scaleX, scaleY, translateX, translateY } = this.drawTransform
let checkRight = this.cloneNodeLeft + this.node.width * scaleX
/** let checkBottom = this.cloneNodeTop + this.node.height * scaleX
* javascript comment this.overlapNode = null
* @Author: 王林25 this.prevNode = null
* @Date: 2021-11-23 18:53:47 this.nextNode = null
* @Desc: 拖动中 this.placeholder.size(0, 0)
*/ bfsWalk(this.mindMap.renderer.root, node => {
onMove(x, y) { if (node.nodeData.data.isActive) {
if (!this.isMousedown) { this.mindMap.renderer.setNodeActive(node, false)
return }
} if (node === this.node || this.node.isParent(node)) {
this.createCloneNode() return
let { scaleX, scaleY, translateX, translateY } = this.drawTransform }
this.cloneNodeLeft = x - this.offsetX if (this.overlapNode || (this.prevNode && this.nextNode)) {
this.cloneNodeTop = y - this.offsetY return
x = (this.cloneNodeLeft - translateX) / scaleX }
y = (this.cloneNodeTop - translateY) / scaleY let { left, top, width, height } = node
let t = this.clone.transform() let _left = left
this.clone.translate(x - t.translateX, y - t.translateY) let _top = top
// 连接线 let _bottom = top + height
let parent = this.node.parent let right = (left + width) * scaleX + translateX
this.line.plot( let bottom = (top + height) * scaleY + translateY
this.quadraticCurvePath( left = left * scaleX + translateX
parent.left + parent.width / 2, top = top * scaleY + translateY
parent.top + parent.height / 2, // 检测是否重叠
x + this.node.width / 2, if (!this.overlapNode) {
y + this.node.height / 2 if (
) left <= checkRight &&
) right >= this.cloneNodeLeft &&
this.checkOverlapNode() top <= checkBottom &&
} bottom >= this.cloneNodeTop
) {
/** this.overlapNode = node
* @Author: 王林 }
* @Date: 2021-07-11 10:20:43 }
* @Desc: 检测重叠节点 // 检测兄弟节点位置
*/ if (!this.prevNode && !this.nextNode && !node.isRoot) {
checkOverlapNode() { // && this.node.isBrother(node)
if (!this.drawTransform) { if (left <= checkRight && right >= this.cloneNodeLeft) {
return if (this.cloneNodeTop > bottom && this.cloneNodeTop <= bottom + 10) {
} this.prevNode = node
let { scaleX, scaleY, translateX, translateY } = this.drawTransform this.placeholder.size(node.width, 10).move(_left, _bottom)
let checkRight = this.cloneNodeLeft + this.node.width * scaleX } else if (checkBottom < top && checkBottom >= top - 10) {
let checkBottom = this.cloneNodeTop + this.node.height * scaleX this.nextNode = node
this.overlapNode = null this.placeholder.size(node.width, 10).move(_left, _top - 10)
this.prevNode = null }
this.nextNode = null }
this.placeholder.size(0, 0) }
bfsWalk(this.mindMap.renderer.root, node => { })
if (node.nodeData.data.isActive) { if (this.overlapNode) {
this.mindMap.renderer.setNodeActive(node, false) this.mindMap.renderer.setNodeActive(this.overlapNode, true)
} }
if (node === this.node || this.node.isParent(node)) { }
return }
}
if (this.overlapNode || (this.prevNode && this.nextNode)) { export default Drag
return
}
let { left, top, width, height } = node
let _left = left
let _top = top
let _bottom = top + height
let right = (left + width) * scaleX + translateX
let bottom = (top + height) * scaleY + translateY
left = left * scaleX + translateX
top = top * scaleY + translateY
// 检测是否重叠
if (!this.overlapNode) {
if (
left <= checkRight &&
right >= this.cloneNodeLeft &&
top <= checkBottom &&
bottom >= this.cloneNodeTop
) {
this.overlapNode = node
}
}
// 检测兄弟节点位置
if (!this.prevNode && !this.nextNode && !node.isRoot) {
// && this.node.isBrother(node)
if (left <= checkRight && right >= this.cloneNodeLeft) {
if (this.cloneNodeTop > bottom && this.cloneNodeTop <= bottom + 10) {
this.prevNode = node
this.placeholder.size(node.width, 10).move(_left, _bottom)
} else if (checkBottom < top && checkBottom >= top - 10) {
this.nextNode = node
this.placeholder.size(node.width, 10).move(_left, _top - 10)
}
}
}
})
if (this.overlapNode) {
this.mindMap.renderer.setNodeActive(this.overlapNode, true)
}
}
}
export default Drag

View File

@ -1,18 +1,8 @@
import EventEmitter from 'eventemitter3' import EventEmitter from 'eventemitter3'
/** // 事件类
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:53:09
* @Desc: 事件类
*/
class Event extends EventEmitter { class Event extends EventEmitter {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:53:25
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
super() super()
this.opt = opt this.opt = opt
@ -34,12 +24,7 @@ class Event extends EventEmitter {
this.bind() this.bind()
} }
/** // 绑定函数上下文
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:52:24
* @Desc: 绑定函数上下文
*/
bindFn() { bindFn() {
this.onDrawClick = this.onDrawClick.bind(this) this.onDrawClick = this.onDrawClick.bind(this)
this.onMousedown = this.onMousedown.bind(this) this.onMousedown = this.onMousedown.bind(this)
@ -51,12 +36,7 @@ class Event extends EventEmitter {
this.onKeyup = this.onKeyup.bind(this) this.onKeyup = this.onKeyup.bind(this)
} }
/** // 绑定事件
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:53:43
* @Desc: 绑定事件
*/
bind() { bind() {
this.mindMap.svg.on('click', this.onDrawClick) this.mindMap.svg.on('click', this.onDrawClick)
this.mindMap.el.addEventListener('mousedown', this.onMousedown) this.mindMap.el.addEventListener('mousedown', this.onMousedown)
@ -73,12 +53,7 @@ class Event extends EventEmitter {
window.addEventListener('keyup', this.onKeyup) window.addEventListener('keyup', this.onKeyup)
} }
/** // 解绑事件
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:40:51
* @Desc: 解绑事件
*/
unbind() { unbind() {
this.mindMap.svg.off('click', this.onDrawClick) this.mindMap.svg.off('click', this.onDrawClick)
this.mindMap.el.removeEventListener('mousedown', this.onMousedown) this.mindMap.el.removeEventListener('mousedown', this.onMousedown)
@ -89,30 +64,17 @@ class Event extends EventEmitter {
window.removeEventListener('keyup', this.onKeyup) window.removeEventListener('keyup', this.onKeyup)
} }
/** // 画布的单击事件
* @Author: 王林
* @Date: 2021-04-24 13:19:39
* @Desc: 画布的单击事件
*/
onDrawClick(e) { onDrawClick(e) {
this.emit('draw_click', e) this.emit('draw_click', e)
} }
/** // svg画布的鼠标按下事件
* @Author: 王林
* @Date: 2021-07-16 13:37:30
* @Desc: svg画布的鼠标按下事件
*/
onSvgMousedown(e) { onSvgMousedown(e) {
this.emit('svg_mousedown', e) this.emit('svg_mousedown', e)
} }
/** // 鼠标按下事件
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:17:35
* @Desc: 鼠标按下事件
*/
onMousedown(e) { onMousedown(e) {
// e.preventDefault() // e.preventDefault()
// 鼠标左键 // 鼠标左键
@ -124,12 +86,7 @@ class Event extends EventEmitter {
this.emit('mousedown', e, this) this.emit('mousedown', e, this)
} }
/** // 鼠标移动事件
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:18:32
* @Desc: 鼠标移动事件
*/
onMousemove(e) { onMousemove(e) {
// e.preventDefault() // e.preventDefault()
this.mousemovePos.x = e.clientX this.mousemovePos.x = e.clientX
@ -142,23 +99,13 @@ class Event extends EventEmitter {
} }
} }
/** // 鼠标松开事件
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:18:57
* @Desc: 鼠标松开事件
*/
onMouseup(e) { onMouseup(e) {
this.isLeftMousedown = false this.isLeftMousedown = false
this.emit('mouseup', e, this) this.emit('mouseup', e, this)
} }
/** // 鼠标滚动
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:46:27
* @Desc: 鼠标滚动
*/
onMousewheel(e) { onMousewheel(e) {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
@ -171,22 +118,13 @@ class Event extends EventEmitter {
this.emit('mousewheel', e, dir, this) this.emit('mousewheel', e, dir, this)
} }
/** // 鼠标右键菜单事件
* @Author: 王林
* @Date: 2021-07-10 22:34:13
* @Desc: 鼠标右键菜单事件
*/
onContextmenu(e) { onContextmenu(e) {
e.preventDefault() e.preventDefault()
this.emit('contextmenu', e) this.emit('contextmenu', e)
} }
/** // 按键松开事件
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 11:12:11
* @Desc: 按键松开事件
*/
onKeyup(e) { onKeyup(e) {
this.emit('keyup', e) this.emit('keyup', e)
} }

View File

@ -3,27 +3,15 @@ import JsPDF from 'jspdf'
import { SVG } from '@svgdotjs/svg.js' import { SVG } from '@svgdotjs/svg.js'
const URL = window.URL || window.webkitURL || window const URL = window.URL || window.webkitURL || window
/** // 导出类
* @Author: 王林
* @Date: 2021-07-01 22:05:16
* @Desc: 导出类
*/
class Export { class Export {
/** // 构造函数
* @Author: 王林
* @Date: 2021-07-01 22:05:42
* @Desc: 构造函数
*/
constructor(opt) { constructor(opt) {
this.mindMap = opt.mindMap this.mindMap = opt.mindMap
this.exportPadding = this.mindMap.opt.exportPadding this.exportPadding = this.mindMap.opt.exportPadding
} }
/** // 导出
* @Author: 王林
* @Date: 2021-07-02 07:44:06
* @Desc: 导出
*/
async export(type, isDownload = true, name = '思维导图', ...args) { async export(type, isDownload = true, name = '思维导图', ...args) {
if (this[type]) { if (this[type]) {
let result = await this[type](name, ...args) let result = await this[type](name, ...args)
@ -36,11 +24,7 @@ class Export {
} }
} }
/** // 获取svg数据
* @Author: 王林
* @Date: 2021-07-04 14:57:40
* @Desc: 获取svg数据
*/
async getSvgData() { async getSvgData() {
let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap() let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap()
// 把图片的url转换成data:url类型否则导出会丢失图片 // 把图片的url转换成data:url类型否则导出会丢失图片
@ -57,11 +41,7 @@ class Export {
} }
} }
/** // svg转png
* @Author: 王林
* @Date: 2021-07-04 15:25:19
* @Desc: svg转png
*/
svgToPng(svgSrc) { svgToPng(svgSrc) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image() const img = new Image()
@ -99,11 +79,7 @@ class Export {
}) })
} }
/** // 在canvas上绘制思维导图背景
* @Author: 王林
* @Date: 2021-07-04 15:32:07
* @Desc: 在canvas上绘制思维导图背景
*/
drawBackgroundToCanvas(ctx, width, height) { drawBackgroundToCanvas(ctx, width, height) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let { let {
@ -139,10 +115,8 @@ class Export {
}) })
} }
// 导出为png
/** /**
* @Author: 王林
* @Date: 2021-07-01 22:09:51
* @Desc: 导出为png
* 方法1.把svg的图片都转化成data:url格式再转换 * 方法1.把svg的图片都转化成data:url格式再转换
* 方法2.把svg的图片提取出来再挨个绘制到canvas里最后一起转换 * 方法2.把svg的图片提取出来再挨个绘制到canvas里最后一起转换
*/ */
@ -160,12 +134,7 @@ class Export {
return imgDataUrl return imgDataUrl
} }
/** // 导出为pdf
* javascript comment
* @Author: 王林25
* @Date: 2022-08-08 19:23:08
* @Desc: 导出为pdf
*/
async pdf(name) { async pdf(name) {
let img = await this.png() let img = await this.png()
let pdf = new JsPDF('', 'pt', 'a4') let pdf = new JsPDF('', 'pt', 'a4')
@ -197,11 +166,7 @@ class Export {
image.src = img image.src = img
} }
/** // 在svg上绘制思维导图背景
* @Author: 王林
* @Date: 2021-07-04 15:32:07
* @Desc: 在svg上绘制思维导图背景
*/
drawBackgroundToSvg(svg) { drawBackgroundToSvg(svg) {
return new Promise(async resolve => { return new Promise(async resolve => {
let { let {
@ -223,11 +188,7 @@ class Export {
}) })
} }
/** // 导出为svg
* @Author: 王林
* @Date: 2021-07-04 14:54:07
* @Desc: 导出为svg
*/
async svg(name) { async svg(name) {
let { node } = await this.getSvgData() let { node } = await this.getSvgData()
node.first().before(SVG(`<title>${name}</title>`)) node.first().before(SVG(`<title>${name}</title>`))
@ -240,11 +201,7 @@ class Export {
return URL.createObjectURL(blob) return URL.createObjectURL(blob)
} }
/** // 导出为json
* @Author: 王林
* @Date: 2021-08-03 22:19:17
* @Desc: 导出为json
*/
json(name, withConfig = true) { json(name, withConfig = true) {
let data = this.mindMap.getData(withConfig) let data = this.mindMap.getData(withConfig)
let str = JSON.stringify(data) let str = JSON.stringify(data)
@ -252,11 +209,7 @@ class Export {
return URL.createObjectURL(blob) return URL.createObjectURL(blob)
} }
/** // 专有文件其实就是json文件
* @Author: 王林
* @Date: 2021-08-03 22:24:24
* @Desc: 专有文件其实就是json文件
*/
smm(name, withConfig) { smm(name, withConfig) {
return this.json(name, withConfig) return this.json(name, withConfig)
} }

View File

@ -1,15 +1,7 @@
import { keyMap } from './utils/keyMap' import { keyMap } from './utils/keyMap'
/** // 快捷按键、命令处理类
* @Author: 王林
* @Date: 2021-04-24 15:20:46
* @Desc: 快捷按键命令处理类
*/
export default class KeyCommand { export default class KeyCommand {
/** // 构造函数
* @Author: 王林
* @Date: 2021-04-24 15:21:32
* @Desc: 构造函数
*/
constructor(opt) { constructor(opt) {
this.opt = opt this.opt = opt
this.mindMap = opt.mindMap this.mindMap = opt.mindMap
@ -21,51 +13,29 @@ export default class KeyCommand {
this.bindEvent() this.bindEvent()
} }
/** // 暂停快捷键响应
* @Author: 王林
* @Date: 2022-08-14 08:57:55
* @Desc: 暂停快捷键响应
*/
pause() { pause() {
this.isPause = true this.isPause = true
} }
/** // 恢复快捷键响应
* @Author: 王林
* @Date: 2022-08-14 08:58:43
* @Desc: 恢复快捷键响应
*/
recovery() { recovery() {
this.isPause = false this.isPause = false
} }
/** // 保存当前注册的快捷键数据,然后清空快捷键数据
* javascript comment
* @Author: 王林25
* @Date: 2022-08-16 16:29:01
* @Desc: 保存当前注册的快捷键数据然后清空快捷键数据
*/
save() { save() {
this.shortcutMapCache = this.shortcutMap this.shortcutMapCache = this.shortcutMap
this.shortcutMap = {} this.shortcutMap = {}
} }
/** // 恢复保存的快捷键数据,然后清空缓存数据
* javascript comment
* @Author: 王林25
* @Date: 2022-08-16 16:29:38
* @Desc: 恢复保存的快捷键数据然后清空缓存数据
*/
restore() { restore() {
this.shortcutMap = this.shortcutMapCache this.shortcutMap = this.shortcutMapCache
this.shortcutMapCache = {} this.shortcutMapCache = {}
} }
/** // 绑定事件
* @Author: 王林
* @Date: 2021-04-24 15:23:22
* @Desc: 绑定事件
*/
bindEvent() { bindEvent() {
window.addEventListener('keydown', e => { window.addEventListener('keydown', e => {
if (this.isPause) { if (this.isPause) {
@ -83,11 +53,7 @@ export default class KeyCommand {
}) })
} }
/** // 检查键值是否符合
* @Author: 王林
* @Date: 2021-04-24 19:24:53
* @Desc: 检查键值是否符合
*/
checkKey(e, key) { checkKey(e, key) {
let o = this.getOriginEventCodeArr(e) let o = this.getOriginEventCodeArr(e)
let k = this.getKeyCodeArr(key) let k = this.getKeyCodeArr(key)
@ -107,11 +73,7 @@ export default class KeyCommand {
return true return true
} }
/** // 获取事件对象里的键值数组
* @Author: 王林
* @Date: 2021-04-24 19:15:19
* @Desc: 获取事件对象里的键值数组
*/
getOriginEventCodeArr(e) { getOriginEventCodeArr(e) {
let arr = [] let arr = []
if (e.ctrlKey || e.metaKey) { if (e.ctrlKey || e.metaKey) {
@ -129,11 +91,7 @@ export default class KeyCommand {
return arr return arr
} }
/** // 获取快捷键对应的键值数组
* @Author: 王林
* @Date: 2021-04-24 19:40:11
* @Desc: 获取快捷键对应的键值数组
*/
getKeyCodeArr(key) { getKeyCodeArr(key) {
let keyArr = key.split(/\s*\+\s*/) let keyArr = key.split(/\s*\+\s*/)
let arr = [] let arr = []
@ -143,10 +101,8 @@ export default class KeyCommand {
return arr return arr
} }
// 添加快捷键命令
/** /**
* @Author: 王林
* @Date: 2021-04-24 15:23:00
* @Desc: 添加快捷键命令
* Enter * Enter
* Tab | Insert * Tab | Insert
* Shift + a * Shift + a
@ -161,12 +117,7 @@ export default class KeyCommand {
}) })
} }
/** // 移除快捷键命令
* javascript comment
* @Author: 王林25
* @Date: 2021-07-27 14:06:16
* @Desc: 移除快捷键命令
*/
removeShortcut(key, fn) { removeShortcut(key, fn) {
key.split(/\s*\|\s*/).forEach(item => { key.split(/\s*\|\s*/).forEach(item => {
if (this.shortcutMap[item]) { if (this.shortcutMap[item]) {
@ -185,11 +136,7 @@ export default class KeyCommand {
}) })
} }
/** // 获取指定快捷键的处理函数
* @Author: 王林
* @Date: 2022-08-14 08:49:58
* @Desc: 获取指定快捷键的处理函数
*/
getShortcutFn(key) { getShortcutFn(key) {
let res = [] let res = []
key.split(/\s*\|\s*/).forEach(item => { key.split(/\s*\|\s*/).forEach(item => {

View File

@ -1,19 +1,9 @@
import { isKey } from './utils/keyMap' import { isKey } from './utils/keyMap'
import { bfsWalk } from './utils' import { bfsWalk } from './utils'
/** // 键盘导航类
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 11:06:50
* @Desc: 键盘导航类
*/
export default class KeyboardNavigation { export default class KeyboardNavigation {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 11:07:24
* @Desc: 构造函数
*/
constructor(opt) { constructor(opt) {
this.opt = opt this.opt = opt
this.mindMap = opt.mindMap this.mindMap = opt.mindMap
@ -21,12 +11,7 @@ export default class KeyboardNavigation {
this.mindMap.on('keyup', this.onKeyup) this.mindMap.on('keyup', this.onKeyup)
} }
/** // 处理按键事件
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 14:12:27
* @Desc: 处理按键事件
*/
onKeyup(e) { onKeyup(e) {
;['Left', 'Up', 'Right', 'Down'].forEach(dir => { ;['Left', 'Up', 'Right', 'Down'].forEach(dir => {
if (isKey(e, dir)) { if (isKey(e, dir)) {
@ -41,12 +26,7 @@ export default class KeyboardNavigation {
}) })
} }
/** // 聚焦到下一个节点
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 14:12:39
* @Desc: 聚焦到下一个节点
*/
focus(dir) { focus(dir) {
// 当前聚焦的节点 // 当前聚焦的节点
let currentActiveNode = this.mindMap.renderer.activeNodeList[0] let currentActiveNode = this.mindMap.renderer.activeNodeList[0]
@ -99,12 +79,7 @@ export default class KeyboardNavigation {
} }
} }
/** // 1.简单算法
* javascript comment
* @Author: 王林25
* @Date: 2022-12-12 16:22:54
* @Desc: 1.简单算法
*/
getFocusNodeBySimpleAlgorithm({ getFocusNodeBySimpleAlgorithm({
currentActiveNode, currentActiveNode,
currentActiveNodeRect, currentActiveNodeRect,
@ -143,12 +118,7 @@ export default class KeyboardNavigation {
}) })
} }
/** // 2.阴影算法
* javascript comment
* @Author: 王林25
* @Date: 2022-12-12 16:24:54
* @Desc: 2.阴影算法
*/
getFocusNodeByShadowAlgorithm({ getFocusNodeByShadowAlgorithm({
currentActiveNode, currentActiveNode,
currentActiveNodeRect, currentActiveNodeRect,
@ -187,12 +157,7 @@ export default class KeyboardNavigation {
}) })
} }
/** // 3.区域算法
* javascript comment
* @Author: 王林25
* @Date: 2022-12-13 16:15:36
* @Desc: 3.区域算法
*/
getFocusNodeByAreaAlgorithm({ getFocusNodeByAreaAlgorithm({
currentActiveNode, currentActiveNode,
currentActiveNodeRect, currentActiveNodeRect,
@ -229,12 +194,7 @@ export default class KeyboardNavigation {
}) })
} }
/** // 获取节点的位置信息
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 14:12:50
* @Desc: 获取节点的位置信息
*/
getNodeRect(node) { getNodeRect(node) {
let { scaleX, scaleY, translateX, translateY } = let { scaleX, scaleY, translateX, translateY } =
this.mindMap.draw.transform() this.mindMap.draw.transform()
@ -247,12 +207,7 @@ export default class KeyboardNavigation {
} }
} }
/** // 获取两个节点的距离
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 14:13:04
* @Desc: 获取两个节点的距离
*/
getDistance(node1Rect, node2Rect) { getDistance(node1Rect, node2Rect) {
let center1 = this.getCenter(node1Rect) let center1 = this.getCenter(node1Rect)
let center2 = this.getCenter(node2Rect) let center2 = this.getCenter(node2Rect)
@ -261,12 +216,7 @@ export default class KeyboardNavigation {
) )
} }
/** // 获取节点的中心点
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 14:13:11
* @Desc: 获取节点的中心点
*/
getCenter({ left, right, top, bottom }) { getCenter({ left, right, top, bottom }) {
return { return {
x: (left + right) / 2, x: (left + right) / 2,

View File

@ -1,11 +1,6 @@
// 小地图类 // 小地图类
class MiniMap { class MiniMap {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:00:45
* @Desc: 构造函数
*/
constructor(opt) { constructor(opt) {
this.mindMap = opt.mindMap this.mindMap = opt.mindMap
this.isMousedown = false this.isMousedown = false
@ -19,12 +14,7 @@ class MiniMap {
} }
} }
/** // 获取小地图相关数据
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:00:43
* @Desc: 获取小地图相关数据
*/
getMiniMap() { getMiniMap() {
const svg = this.mindMap.svg const svg = this.mindMap.svg
const draw = this.mindMap.draw const draw = this.mindMap.draw
@ -61,11 +51,8 @@ class MiniMap {
} }
} }
// 计算小地图的渲染数据
/** /**
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:05:51
* @Desc: 计算小地图的渲染数据
* boxWidth小地图容器的宽度 * boxWidth小地图容器的宽度
* boxHeight小地图容器的高度 * boxHeight小地图容器的高度
*/ */
@ -124,12 +111,7 @@ class MiniMap {
} }
} }
/** // 小地图鼠标按下事件
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:22:40
* @Desc: 小地图鼠标按下事件
*/
onMousedown(e) { onMousedown(e) {
this.isMousedown = true this.isMousedown = true
this.mousedownPos = { this.mousedownPos = {
@ -144,12 +126,7 @@ class MiniMap {
} }
} }
/** // 小地图鼠标移动事件
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:22:55
* @Desc: 小地图鼠标移动事件
*/
onMousemove(e, sensitivityNum = 5) { onMousemove(e, sensitivityNum = 5) {
if (!this.isMousedown) { if (!this.isMousedown) {
return return
@ -161,12 +138,7 @@ class MiniMap {
this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y) this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y)
} }
/** // 小地图鼠标松开事件
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:23:01
* @Desc: 小地图鼠标松开事件
*/
onMouseup() { onMouseup() {
this.isMousedown = false this.isMousedown = false
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,9 @@
import { bfsWalk, throttle } from './utils' import { bfsWalk, throttle } from './utils'
/** // 选择节点类
* @Author: 王林
* @Date: 2021-07-10 22:34:51
* @Desc: 选择节点类
*/
class Select { class Select {
/** // 构造函数
* @Author: 王林
* @Date: 2021-07-10 22:35:16
* @Desc: 构造函数
*/
constructor({ mindMap }) { constructor({ mindMap }) {
this.mindMap = mindMap this.mindMap = mindMap
this.rect = null this.rect = null
@ -23,11 +15,7 @@ class Select {
this.bindEvent() this.bindEvent()
} }
/** // 绑定事件
* @Author: 王林
* @Date: 2021-07-10 22:36:36
* @Desc: 绑定事件
*/
bindEvent() { bindEvent() {
this.checkInNodes = throttle(this.checkInNodes, 500, this) this.checkInNodes = throttle(this.checkInNodes, 500, this)
this.mindMap.on('mousedown', e => { this.mindMap.on('mousedown', e => {
@ -81,11 +69,7 @@ class Select {
}) })
} }
/** // 鼠标移动事件
* @Author: 王林
* @Date: 2021-07-13 07:55:49
* @Desc: 鼠标移动事件
*/
onMove(x, y) { onMove(x, y) {
// 绘制矩形 // 绘制矩形
this.rect.plot([ this.rect.plot([
@ -128,22 +112,14 @@ class Select {
} }
} }
/** // 开启自动移动
* @Author: 王林
* @Date: 2021-07-22 08:02:23
* @Desc: 开启自动移动
*/
startAutoMove(x, y) { startAutoMove(x, y) {
this.autoMoveTimer = setTimeout(() => { this.autoMoveTimer = setTimeout(() => {
this.onMove(x, y) this.onMove(x, y)
}, 20) }, 20)
} }
/** // 创建矩形
* @Author: 王林
* @Date: 2021-07-11 10:19:37
* @Desc: 创建矩形
*/
createRect(x, y) { createRect(x, y) {
this.rect = this.mindMap.svg this.rect = this.mindMap.svg
.polygon() .polygon()
@ -156,11 +132,7 @@ class Select {
.plot([[x, y]]) .plot([[x, y]])
} }
/** // 检测在选区里的节点
* @Author: 王林
* @Date: 2021-07-11 10:20:43
* @Desc: 检测在选区里的节点
*/
checkInNodes() { checkInNodes() {
let { scaleX, scaleY, translateX, translateY } = let { scaleX, scaleY, translateX, translateY } =
this.mindMap.draw.transform() this.mindMap.draw.transform()

View File

@ -1,18 +1,10 @@
/** // 节点形状类
* @Author: 王林
* @Date: 2022-08-22 21:32:50
* @Desc: 节点形状类
*/
export default class Shape { export default class Shape {
constructor(node) { constructor(node) {
this.node = node this.node = node
} }
/** // 形状需要的padding
* @Author: 王林
* @Date: 2022-08-17 22:32:32
* @Desc: 形状需要的padding
*/
getShapePadding(width, height, paddingX, paddingY) { getShapePadding(width, height, paddingX, paddingY) {
const shape = this.node.getShape() const shape = this.node.getShape()
const defaultPaddingX = 15 const defaultPaddingX = 15
@ -64,11 +56,7 @@ export default class Shape {
} }
} }
/** // 创建形状节点
* @Author: 王林
* @Date: 2022-08-17 22:22:53
* @Desc: 创建形状节点
*/
createShape() { createShape() {
const shape = this.node.getShape() const shape = this.node.getShape()
let { width, height } = this.node let { width, height } = this.node
@ -104,11 +92,7 @@ export default class Shape {
return node return node
} }
/** // 创建菱形
* @Author: 王林
* @Date: 2022-09-04 09:08:54
* @Desc: 创建菱形
*/
createDiamond() { createDiamond() {
let { width, height } = this.node let { width, height } = this.node
let halfWidth = width / 2 let halfWidth = width / 2
@ -129,11 +113,7 @@ export default class Shape {
`) `)
} }
/** // 创建平行四边形
* @Author: 王林
* @Date: 2022-09-03 16:14:12
* @Desc: 创建平行四边形
*/
createParallelogram() { createParallelogram() {
let { paddingX } = this.node.getPaddingVale() let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX paddingX = paddingX || this.node.shapePadding.paddingX
@ -146,11 +126,7 @@ export default class Shape {
`) `)
} }
/** // 创建圆角矩形
* @Author: 王林
* @Date: 2022-09-03 16:50:23
* @Desc: 创建圆角矩形
*/
createRoundedRectangle() { createRoundedRectangle() {
let { width, height } = this.node let { width, height } = this.node
let halfHeight = height / 2 let halfHeight = height / 2
@ -163,12 +139,7 @@ export default class Shape {
`) `)
} }
/** // 创建八角矩形
* javascript comment
* @Author: 王林
* @Date: 2022-09-12 16:14:08
* @Desc: 创建八角矩形
*/
createOctagonalRectangle() { createOctagonalRectangle() {
let w = 5 let w = 5
let { width, height } = this.node let { width, height } = this.node
@ -184,12 +155,7 @@ export default class Shape {
`) `)
} }
/** // 创建外三角矩形
* javascript comment
* @Author: 王林
* @Date: 2022-09-12 20:55:50
* @Desc: 创建外三角矩形
*/
createOuterTriangularRectangle() { createOuterTriangularRectangle() {
let { paddingX } = this.node.getPaddingVale() let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX paddingX = paddingX || this.node.shapePadding.paddingX
@ -204,12 +170,7 @@ export default class Shape {
`) `)
} }
/** // 创建内三角矩形
* javascript comment
* @Author: 王林
* @Date: 2022-09-12 20:59:37
* @Desc: 创建内三角矩形
*/
createInnerTriangularRectangle() { createInnerTriangularRectangle() {
let { paddingX } = this.node.getPaddingVale() let { paddingX } = this.node.getPaddingVale()
paddingX = paddingX || this.node.shapePadding.paddingX paddingX = paddingX || this.node.shapePadding.paddingX
@ -224,12 +185,7 @@ export default class Shape {
`) `)
} }
/** // 创建椭圆
* javascript comment
* @Author: 王林
* @Date: 2022-09-12 21:06:31
* @Desc: 创建椭圆
*/
createEllipse() { createEllipse() {
let { width, height } = this.node let { width, height } = this.node
let halfWidth = width / 2 let halfWidth = width / 2
@ -242,12 +198,7 @@ export default class Shape {
`) `)
} }
/** // 创建圆
* javascript comment
* @Author: 王林
* @Date: 2022-09-12 21:14:04
* @Desc: 创建圆
*/
createCircle() { createCircle() {
let { width, height } = this.node let { width, height } = this.node
let halfWidth = width / 2 let halfWidth = width / 2

View File

@ -1,238 +1,167 @@
import { tagColorList } from './utils/constant' import { tagColorList } from './utils/constant'
const rootProp = ['paddingX', 'paddingY'] const rootProp = ['paddingX', 'paddingY']
/** // 样式类
* @Author: 王林 class Style {
* @Date: 2021-04-11 10:09:08 // 设置背景样式
* @Desc: 样式类 static setBackgroundStyle(el, themeConfig) {
*/ let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig
class Style { el.style.backgroundColor = backgroundColor
/** if (backgroundImage) {
* @Author: 王林 el.style.backgroundImage = `url(${backgroundImage})`
* @Date: 2021-04-11 16:01:53 el.style.backgroundRepeat = backgroundRepeat
* @Desc: 设置背景样式 }
*/ }
static setBackgroundStyle(el, themeConfig) {
let { backgroundColor, backgroundImage, backgroundRepeat } = themeConfig // 构造函数
el.style.backgroundColor = backgroundColor constructor(ctx, themeConfig) {
if (backgroundImage) { this.ctx = ctx
el.style.backgroundImage = `url(${backgroundImage})` this.themeConfig = themeConfig
el.style.backgroundRepeat = backgroundRepeat }
}
} // 更新主题配置
updateThemeConfig(themeConfig) {
/** this.themeConfig = themeConfig
* @Author: 王林 }
* @Date: 2021-04-11 10:10:11
* @Desc: 构造函数 // 合并样式
*/ merge(prop, root, isActive) {
constructor(ctx, themeConfig) { // 三级及以下节点
this.ctx = ctx let defaultConfig = this.themeConfig.node
this.themeConfig = themeConfig if (root || rootProp.includes(prop)) {
} // 直接使用最外层样式
defaultConfig = this.themeConfig
/** } else if (this.ctx.isGeneralization) {
* @Author: 王林 // 概要节点
* @Date: 2021-07-12 07:40:14 defaultConfig = this.themeConfig.generalization
* @Desc: 更新主题配置 } else if (this.ctx.layerIndex === 0) {
*/ // 根节点
updateThemeConfig(themeConfig) { defaultConfig = this.themeConfig.root
this.themeConfig = themeConfig } else if (this.ctx.layerIndex === 1) {
} // 二级节点
defaultConfig = this.themeConfig.second
/** }
* @Author: 王林 // 激活状态
* @Date: 2021-04-11 12:02:55 if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
* @Desc: 合并样式 if (
*/ this.ctx.nodeData.data.activeStyle &&
merge(prop, root, isActive) { this.ctx.nodeData.data.activeStyle[prop] !== undefined
// 三级及以下节点 ) {
let defaultConfig = this.themeConfig.node return this.ctx.nodeData.data.activeStyle[prop]
if (root || rootProp.includes(prop)) { } else if (defaultConfig.active && defaultConfig.active[prop]) {
// 直接使用最外层样式 return defaultConfig.active[prop]
defaultConfig = this.themeConfig }
} else if (this.ctx.isGeneralization) { }
// 概要节点 // 优先使用节点本身的样式
defaultConfig = this.themeConfig.generalization return this.getSelfStyle(prop) !== undefined
} else if (this.ctx.layerIndex === 0) { ? this.getSelfStyle(prop)
// 根节点 : defaultConfig[prop]
defaultConfig = this.themeConfig.root }
} else if (this.ctx.layerIndex === 1) {
// 二级节点 // 获取某个样式值
defaultConfig = this.themeConfig.second getStyle(prop, root, isActive) {
} return this.merge(prop, root, isActive)
// 激活状态 }
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
if ( // 获取自身自定义样式
this.ctx.nodeData.data.activeStyle && getSelfStyle(prop) {
this.ctx.nodeData.data.activeStyle[prop] !== undefined return this.ctx.nodeData.data[prop]
) { }
return this.ctx.nodeData.data.activeStyle[prop]
} else if (defaultConfig.active && defaultConfig.active[prop]) { // 矩形
return defaultConfig.active[prop] rect(node) {
} this.shape(node)
} node.radius(this.merge('borderRadius'))
// 优先使用节点本身的样式 }
return this.getSelfStyle(prop) !== undefined
? this.getSelfStyle(prop) // 矩形外的其他形状
: defaultConfig[prop] shape(node) {
} node.fill({
color: this.merge('fillColor')
/** })
* javascript comment // 节点使用横线样式,不需要渲染非激活状态的边框样式
* @Author: 王林 if (
* @Date: 2022-09-12 21:55:57 !this.ctx.isRoot &&
* @Desc: 获取某个样式值 !this.ctx.isGeneralization &&
*/ this.themeConfig.nodeUseLineStyle &&
getStyle(prop, root, isActive) { !this.ctx.nodeData.data.isActive
return this.merge(prop, root, isActive) ) {
} return
}
/** node.stroke({
* javascript comment color: this.merge('borderColor'),
* @Author: flydreame width: this.merge('borderWidth'),
* @Date: 2022-09-17 12:09:39 dasharray: this.merge('borderDasharray')
* @Desc: 获取自身自定义样式 })
*/ }
getSelfStyle(prop) {
return this.ctx.nodeData.data[prop] // 文字
} text(node) {
node
/** .fill({
* @Author: 王林 color: this.merge('color')
* @Date: 2021-04-11 10:12:56 })
* @Desc: 矩形 .css({
*/ 'font-family': this.merge('fontFamily'),
rect(node) { 'font-size': this.merge('fontSize'),
this.shape(node) 'font-weight': this.merge('fontWeight'),
node.radius(this.merge('borderRadius')) 'font-style': this.merge('fontStyle'),
} 'text-decoration': this.merge('textDecoration')
})
/** }
* javascript comment
* @Author: 王林 // html文字节点
* @Date: 2022-09-12 15:04:28 domText(node, fontSizeScale = 1) {
* @Desc: 矩形外的其他形状 node.style.fontFamily = this.merge('fontFamily')
*/ node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px'
shape(node) { node.style.fontWeight = this.merge('fontWeight') || 'normal'
node.fill({ }
color: this.merge('fillColor')
}) // 标签文字
// 节点使用横线样式,不需要渲染非激活状态的边框样式 tagText(node, index) {
if ( node
!this.ctx.isRoot && .fill({
!this.ctx.isGeneralization && color: tagColorList[index].color
this.themeConfig.nodeUseLineStyle && })
!this.ctx.nodeData.data.isActive .css({
) { 'font-size': '12px'
return })
} }
node.stroke({
color: this.merge('borderColor'), // 标签矩形
width: this.merge('borderWidth'), tagRect(node, index) {
dasharray: this.merge('borderDasharray') node.fill({
}) color: tagColorList[index].background
} })
}
/**
* @Author: 王林 // 内置图标
* @Date: 2021-04-11 12:07:59 iconNode(node) {
* @Desc: 文字 node.attr({
*/ fill: this.merge('color')
text(node) { })
node }
.fill({
color: this.merge('color') // 连线
}) line(node, { width, color, dasharray } = {}) {
.css({ node.stroke({ width, color, dasharray }).fill({ color: 'none' })
'font-family': this.merge('fontFamily'), }
'font-size': this.merge('fontSize'),
'font-weight': this.merge('fontWeight'), // 概要连线
'font-style': this.merge('fontStyle'), generalizationLine(node) {
'text-decoration': this.merge('textDecoration') node
}) .stroke({
} width: this.merge('generalizationLineWidth', true),
color: this.merge('generalizationLineColor', true)
/** })
* @Author: 王林 .fill({ color: 'none' })
* @Date: 2021-04-13 08:14:34 }
* @Desc: html文字节点
*/ // 按钮
domText(node, fontSizeScale = 1) { iconBtn(node, fillNode) {
node.style.fontFamily = this.merge('fontFamily') node.fill({ color: '#808080' })
node.style.fontSize = this.merge('fontSize') * fontSizeScale + 'px' fillNode.fill({ color: '#fff' })
node.style.fontWeight = this.merge('fontWeight') || 'normal' }
} }
/** export default Style
* @Author: 王林
* @Date: 2021-06-20 20:02:18
* @Desc: 标签文字
*/
tagText(node, index) {
node
.fill({
color: tagColorList[index].color
})
.css({
'font-size': '12px'
})
}
/**
* @Author: 王林
* @Date: 2021-06-20 21:04:11
* @Desc: 标签矩形
*/
tagRect(node, index) {
node.fill({
color: tagColorList[index].background
})
}
/**
* @Author: 王林
* @Date: 2021-07-03 22:37:19
* @Desc: 内置图标
*/
iconNode(node) {
node.attr({
fill: this.merge('color')
})
}
/**
* @Author: 王林
* @Date: 2021-04-11 14:50:49
* @Desc: 连线
*/
line(node, { width, color, dasharray } = {}) {
node.stroke({ width, color, dasharray }).fill({ color: 'none' })
}
/**
* @Author: 王林
* @Date: 2022-07-30 16:19:03
* @Desc: 概要连线
*/
generalizationLine(node) {
node
.stroke({
width: this.merge('generalizationLineWidth', true),
color: this.merge('generalizationLineColor', true)
})
.fill({ color: 'none' })
}
/**
* @Author: 王林
* @Date: 2021-04-11 20:03:59
* @Desc: 按钮
*/
iconBtn(node, fillNode) {
node.fill({ color: '#808080' })
fillNode.fill({ color: '#fff' })
}
}
export default Style

View File

@ -1,18 +1,8 @@
import { getStrWithBrFromHtml } from './utils' import { getStrWithBrFromHtml } from './utils'
/** // 节点文字编辑类
* javascript comment
* @Author: 王林25
* @Date: 2021-06-19 11:11:28
* @Desc: 节点文字编辑类
*/
export default class TextEdit { export default class TextEdit {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2021-06-19 11:22:57
* @Desc: 构造函数
*/
constructor(renderer) { constructor(renderer) {
this.renderer = renderer this.renderer = renderer
this.mindMap = renderer.mindMap this.mindMap = renderer.mindMap
@ -23,11 +13,7 @@ export default class TextEdit {
this.bindEvent() this.bindEvent()
} }
/** // 事件
* @Author: 王林
* @Date: 2021-04-24 13:27:04
* @Desc: 事件
*/
bindEvent() { bindEvent() {
this.show = this.show.bind(this) this.show = this.show.bind(this)
// 节点双击事件 // 节点双击事件
@ -54,12 +40,7 @@ export default class TextEdit {
}) })
} }
/** // 注册临时快捷键
* javascript comment
* @Author: 王林25
* @Date: 2022-08-16 16:27:02
* @Desc: 注册临时快捷键
*/
registerTmpShortcut() { registerTmpShortcut() {
// 注册回车快捷键 // 注册回车快捷键
this.mindMap.keyCommand.addShortcut('Enter', () => { this.mindMap.keyCommand.addShortcut('Enter', () => {
@ -67,20 +48,12 @@ export default class TextEdit {
}) })
} }
/** // 显示文本编辑框
* @Author: 王林
* @Date: 2021-04-13 22:15:56
* @Desc: 显示文本编辑框
*/
show(node) { show(node) {
this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect()) this.showEditTextBox(node, node._textData.node.node.getBoundingClientRect())
} }
/** // 显示文本编辑框
* @Author: 王林
* @Date: 2021-04-13 22:13:02
* @Desc: 显示文本编辑框
*/
showEditTextBox(node, rect) { showEditTextBox(node, rect) {
this.mindMap.emit('before_show_text_edit') this.mindMap.emit('before_show_text_edit')
this.registerTmpShortcut() this.registerTmpShortcut()
@ -107,11 +80,7 @@ export default class TextEdit {
this.selectNodeText() this.selectNodeText()
} }
/** // 选中文本
* @Author: 王林
* @Date: 2021-08-02 23:13:50
* @Desc: 选中文本
*/
selectNodeText() { selectNodeText() {
let selection = window.getSelection() let selection = window.getSelection()
let range = document.createRange() let range = document.createRange()
@ -120,11 +89,7 @@ export default class TextEdit {
selection.addRange(range) selection.addRange(range)
} }
/** // 隐藏文本编辑框
* @Author: 王林
* @Date: 2021-04-24 13:48:16
* @Desc: 隐藏文本编辑框
*/
hideEditTextBox() { hideEditTextBox() {
if (!this.showTextEdit) { if (!this.showTextEdit) {
return return

View File

@ -1,16 +1,6 @@
/** // 视图操作类
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:45:24
* @Desc: 视图操作类
*/
class View { class View {
/** // 构造函数
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:45:40
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
this.opt = opt this.opt = opt
this.mindMap = this.opt.mindMap this.mindMap = this.opt.mindMap
@ -24,12 +14,7 @@ class View {
this.bind() this.bind()
} }
/** // 绑定
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 15:38:51
* @Desc: 绑定
*/
bind() { bind() {
// 快捷键 // 快捷键
this.mindMap.keyCommand.addShortcut('Control+=', () => { this.mindMap.keyCommand.addShortcut('Control+=', () => {
@ -80,12 +65,7 @@ class View {
}) })
} }
/** // 获取当前变换状态数据
* javascript comment
* @Author: 王林25
* @Date: 2021-11-22 18:30:24
* @Desc: 获取当前变换状态数据
*/
getTransformData() { getTransformData() {
return { return {
transform: this.mindMap.draw.transform(), transform: this.mindMap.draw.transform(),
@ -99,12 +79,7 @@ class View {
} }
} }
/** // 动态设置变换状态数据
* javascript comment
* @Author: 王林25
* @Date: 2021-11-22 19:54:17
* @Desc: 动态设置变换状态数据
*/
setTransformData(viewData) { setTransformData(viewData) {
if (viewData) { if (viewData) {
Object.keys(viewData.state).forEach(prop => { Object.keys(viewData.state).forEach(prop => {
@ -118,55 +93,31 @@ class View {
} }
} }
/** // 平移x方向
* javascript comment
* @Author: 王林25
* @Date: 2021-07-13 15:49:06
* @Desc: 平移x方向
*/
translateX(step) { translateX(step) {
this.x += step this.x += step
this.transform() this.transform()
} }
/** // 平移x方式到
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:03:53
* @Desc: 平移x方式到
*/
translateXTo(x) { translateXTo(x) {
this.x = x this.x = x
this.transform() this.transform()
} }
/** // 平移y方向
* javascript comment
* @Author: 王林25
* @Date: 2021-07-13 15:48:52
* @Desc: 平移y方向
*/
translateY(step) { translateY(step) {
this.y += step this.y += step
this.transform() this.transform()
} }
/** // 平移y方向到
* javascript comment
* @Author: 王林25
* @Date: 2022-10-10 14:04:10
* @Desc: 平移y方向到
*/
translateYTo(y) { translateYTo(y) {
this.y = y this.y = y
this.transform() this.transform()
} }
/** // 应用变换
* @Author: 王林
* @Date: 2021-07-04 17:13:14
* @Desc: 应用变换
*/
transform() { transform() {
this.mindMap.draw.transform({ this.mindMap.draw.transform({
scale: this.scale, scale: this.scale,
@ -176,11 +127,7 @@ class View {
this.mindMap.emit('view_data_change', this.getTransformData()) this.mindMap.emit('view_data_change', this.getTransformData())
} }
/** // 恢复
* @Author: 王林
* @Date: 2021-07-11 17:41:35
* @Desc: 恢复
*/
reset() { reset() {
this.scale = 1 this.scale = 1
this.x = 0 this.x = 0
@ -188,11 +135,7 @@ class View {
this.transform() this.transform()
} }
/** // 缩小
* @Author: 王林
* @Date: 2021-07-04 17:10:34
* @Desc: 缩小
*/
narrow() { narrow() {
if (this.scale - this.mindMap.opt.scaleRatio > 0.1) { if (this.scale - this.mindMap.opt.scaleRatio > 0.1) {
this.scale -= this.mindMap.opt.scaleRatio this.scale -= this.mindMap.opt.scaleRatio
@ -203,23 +146,14 @@ class View {
this.mindMap.emit('scale', this.scale) this.mindMap.emit('scale', this.scale)
} }
/** // 放大
* @Author: 王林
* @Date: 2021-07-04 17:10:41
* @Desc: 放大
*/
enlarge() { enlarge() {
this.scale += this.mindMap.opt.scaleRatio this.scale += this.mindMap.opt.scaleRatio
this.transform() this.transform()
this.mindMap.emit('scale', this.scale) this.mindMap.emit('scale', this.scale)
} }
/** // 设置缩放
* javascript comment
* @Author: 王林25
* @Date: 2022-12-09 16:31:59
* @Desc: 设置缩放
*/
setScale(scale) { setScale(scale) {
this.scale = scale this.scale = scale
this.transform() this.transform()

View File

@ -1,16 +1,8 @@
import Node from '../Node' import Node from '../Node'
/** // 布局基类
* @Author: 王林
* @Date: 2021-04-12 22:24:30
* @Desc: 布局基类
*/
class Base { class Base {
/** // 构造函数
* @Author: 王林
* @Date: 2021-04-12 22:25:16
* @Desc: 构造函数
*/
constructor(renderer) { constructor(renderer) {
// 渲染实例 // 渲染实例
this.renderer = renderer this.renderer = renderer
@ -22,45 +14,25 @@ class Base {
this.root = null this.root = null
} }
/** // 计算节点位置
* @Author: 王林
* @Date: 2021-04-12 22:39:50
* @Desc: 计算节点位置
*/
doLayout() { doLayout() {
throw new Error('【computed】方法为必要方法需要子类进行重写') throw new Error('【computed】方法为必要方法需要子类进行重写')
} }
/** // 连线
* @Author: 王林
* @Date: 2021-04-12 22:41:04
* @Desc: 连线
*/
renderLine() { renderLine() {
throw new Error('【renderLine】方法为必要方法需要子类进行重写') throw new Error('【renderLine】方法为必要方法需要子类进行重写')
} }
/** // 定位展开收缩按钮
* @Author: 王林
* @Date: 2021-04-12 22:42:08
* @Desc: 定位展开收缩按钮
*/
renderExpandBtn() { renderExpandBtn() {
throw new Error('【renderExpandBtn】方法为必要方法需要子类进行重写') throw new Error('【renderExpandBtn】方法为必要方法需要子类进行重写')
} }
/** // 概要节点
* @Author: 王林
* @Date: 2022-07-30 22:49:28
* @Desc: 概要节点
*/
renderGeneralization() {} renderGeneralization() {}
/** // 创建节点实例
* @Author: 王林
* @Date: 2021-07-10 21:30:54
* @Desc: 创建节点实例
*/
createNode(data, parent, isRoot, layerIndex) { createNode(data, parent, isRoot, layerIndex) {
// 创建节点 // 创建节点
let newNode = null let newNode = null
@ -98,22 +70,13 @@ class Base {
return newNode return newNode
} }
/** // 定位节点到画布中间
* @Author: 王林
* @Date: 2021-07-16 13:48:43
* @Desc: 定位节点到画布中间
*/
setNodeCenter(node) { setNodeCenter(node) {
node.left = (this.mindMap.width - node.width) / 2 node.left = (this.mindMap.width - node.width) / 2
node.top = (this.mindMap.height - node.height) / 2 node.top = (this.mindMap.height - node.height) / 2
} }
/** // 更新子节点属性
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 11:25:52
* @Desc: 更新子节点属性
*/
updateChildren(children, prop, offset) { updateChildren(children, prop, offset) {
children.forEach(item => { children.forEach(item => {
item[prop] += offset item[prop] += offset
@ -124,22 +87,14 @@ class Base {
}) })
} }
/** // 二次贝塞尔曲线
* @Author: 王林
* @Date: 2021-04-11 15:05:01
* @Desc: 二次贝塞尔曲线
*/
quadraticCurvePath(x1, y1, x2, y2) { quadraticCurvePath(x1, y1, x2, y2) {
let cx = x1 + (x2 - x1) * 0.2 let cx = x1 + (x2 - x1) * 0.2
let cy = y1 + (y2 - y1) * 0.8 let cy = y1 + (y2 - y1) * 0.8
return `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` return `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
} }
/** // 三次贝塞尔曲线
* @Author: 王林
* @Date: 2021-04-11 15:05:18
* @Desc: 三次贝塞尔曲线
*/
cubicBezierPath(x1, y1, x2, y2) { cubicBezierPath(x1, y1, x2, y2) {
let cx1 = x1 + (x2 - x1) / 2 let cx1 = x1 + (x2 - x1) / 2
let cy1 = y1 let cy1 = y1
@ -148,33 +103,21 @@ class Base {
return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}` return `M ${x1},${y1} C ${cx1},${cy1} ${cx2},${cy2} ${x2},${y2}`
} }
/** // 获取节点的marginX
* @Author: 王林
* @Date: 2021-06-27 19:00:07
* @Desc: 获取节点的marginX
*/
getMarginX(layerIndex) { getMarginX(layerIndex) {
return layerIndex === 1 return layerIndex === 1
? this.mindMap.themeConfig.second.marginX ? this.mindMap.themeConfig.second.marginX
: this.mindMap.themeConfig.node.marginX : this.mindMap.themeConfig.node.marginX
} }
/** // 获取节点的marginY
* @Author: 王林
* @Date: 2021-04-11 15:34:20
* @Desc: 获取节点的marginY
*/
getMarginY(layerIndex) { getMarginY(layerIndex) {
return layerIndex === 1 return layerIndex === 1
? this.mindMap.themeConfig.second.marginY ? this.mindMap.themeConfig.second.marginY
: this.mindMap.themeConfig.node.marginY : this.mindMap.themeConfig.node.marginY
} }
/** // 获取节点包括概要在内的宽度
* @Author: 王林
* @Date: 2022-07-31 20:53:12
* @Desc: 获取节点包括概要在内的宽度
*/
getNodeWidthWithGeneralization(node) { getNodeWidthWithGeneralization(node) {
return Math.max( return Math.max(
node.width, node.width,
@ -182,11 +125,7 @@ class Base {
) )
} }
/** // 获取节点包括概要在内的高度
* @Author: 王林
* @Date: 2022-07-31 20:53:12
* @Desc: 获取节点包括概要在内的高度
*/
getNodeHeightWithGeneralization(node) { getNodeHeightWithGeneralization(node) {
return Math.max( return Math.max(
node.height, node.height,
@ -194,10 +133,8 @@ class Base {
) )
} }
// 获取节点的边界值
/** /**
* @Author: 王林
* @Date: 2022-07-31 09:14:03
* @Desc: 获取节点的边界值
* dir生长方向h水平v垂直 * dir生长方向h水平v垂直
* isLeft是否向左生长 * isLeft是否向左生长
*/ */

View File

@ -1,441 +1,386 @@
import Base from './Base' import Base from './Base'
import { walk, asyncRun } from '../utils' import { walk, asyncRun } from '../utils'
/** // 目录组织图
* @Author: 王林 class CatalogOrganization extends Base {
* @Date: 2021-04-12 22:25:58 // 构造函数
* @Desc: 目录组织图 constructor(opt = {}) {
*/ super(opt)
class CatalogOrganization extends Base { }
/**
* @Author: 王林 // 布局
* @Date: 2021-04-12 22:26:31 doLayout(callback) {
* @Desc: 构造函数 let task = [
*/ () => {
constructor(opt = {}) { this.computedBaseValue()
super(opt) },
} () => {
this.computedLeftTopValue()
/** },
* javascript comment () => {
* @Author: 王林25 this.adjustLeftTopValue()
* @Date: 2021-04-06 14:04:20 },
* @Desc: 布局 () => {
*/ callback(this.root)
doLayout(callback) { }
let task = [ ]
() => { asyncRun(task)
this.computedBaseValue() }
},
() => { // 遍历数据计算节点的left、width、height
this.computedLeftTopValue() computedBaseValue() {
}, walk(
() => { this.renderer.renderTree,
this.adjustLeftTopValue() null,
}, (cur, parent, isRoot, layerIndex) => {
() => { let newNode = this.createNode(cur, parent, isRoot, layerIndex)
callback(this.root) // 根节点定位在画布中心位置
} if (isRoot) {
] this.setNodeCenter(newNode)
asyncRun(task) } else {
} // 非根节点
if (parent._node.isRoot) {
/** newNode.top =
* javascript comment parent._node.top +
* @Author: 王林25 parent._node.height +
* @Date: 2021-04-08 09:49:32 this.getMarginX(layerIndex)
* @Desc: 遍历数据计算节点的leftwidthheight }
*/ }
computedBaseValue() { if (!cur.data.expand) {
walk( return true
this.renderer.renderTree, }
null, },
(cur, parent, isRoot, layerIndex) => { (cur, parent, isRoot, layerIndex) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex) if (isRoot) {
// 根节点定位在画布中心位置 let len = cur.data.expand === false ? 0 : cur._node.children.length
if (isRoot) { cur._node.childrenAreaWidth = len
this.setNodeCenter(newNode) ? cur._node.children.reduce((h, item) => {
} else { return h + item.width
// 非根节点 }, 0) +
if (parent._node.isRoot) { (len + 1) * this.getMarginX(layerIndex + 1)
newNode.top = : 0
parent._node.top + }
parent._node.height + },
this.getMarginX(layerIndex) true,
} 0
} )
if (!cur.data.expand) { }
return true
} // 遍历节点树计算节点的left、top
}, computedLeftTopValue() {
(cur, parent, isRoot, layerIndex) => { walk(
if (isRoot) { this.root,
let len = cur.data.expand === false ? 0 : cur._node.children.length null,
cur._node.childrenAreaWidth = len (node, parent, isRoot, layerIndex) => {
? cur._node.children.reduce((h, item) => { if (
return h + item.width node.nodeData.data.expand &&
}, 0) + node.children &&
(len + 1) * this.getMarginX(layerIndex + 1) node.children.length
: 0 ) {
} let marginX = this.getMarginX(layerIndex + 1)
}, let marginY = this.getMarginY(layerIndex + 1)
true, if (isRoot) {
0 let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
) let totalLeft = left + marginX
} node.children.forEach(cur => {
cur.left = totalLeft
/** totalLeft += cur.width + marginX
* javascript comment })
* @Author: 王林25 } else {
* @Date: 2021-04-08 09:59:25 let totalTop = node.top + node.height + marginY + node.expandBtnSize
* @Desc: 遍历节点树计算节点的lefttop node.children.forEach(cur => {
*/ cur.left = node.left + node.width * 0.5
computedLeftTopValue() { cur.top = totalTop
walk( totalTop += cur.height + marginY + node.expandBtnSize
this.root, })
null, }
(node, parent, isRoot, layerIndex) => { }
if ( },
node.nodeData.data.expand && null,
node.children && true
node.children.length )
) { }
let marginX = this.getMarginX(layerIndex + 1)
let marginY = this.getMarginY(layerIndex + 1) // 调整节点left、top
if (isRoot) { adjustLeftTopValue() {
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 walk(
let totalLeft = left + marginX this.root,
node.children.forEach(cur => { null,
cur.left = totalLeft (node, parent, isRoot, layerIndex) => {
totalLeft += cur.width + marginX if (!node.nodeData.data.expand) {
}) return
} else { }
let totalTop = node.top + node.height + marginY + node.expandBtnSize // 调整left
node.children.forEach(cur => { if (parent && parent.isRoot) {
cur.left = node.left + node.width * 0.5 let areaWidth = this.getNodeAreaWidth(node)
cur.top = totalTop let difference = areaWidth - node.width
totalTop += cur.height + marginY + node.expandBtnSize if (difference > 0) {
}) this.updateBrothersLeft(node, difference / 2)
} }
} }
}, // 调整top
null, let len = node.children.length
true if (parent && !parent.isRoot && len > 0) {
) let marginY = this.getMarginY(layerIndex + 1)
} let totalHeight =
node.children.reduce((h, item) => {
/** return h + item.height
* javascript comment }, 0) +
* @Author: 王林25 (len + 1) * marginY +
* @Date: 2021-04-08 10:04:05 len * node.expandBtnSize
* @Desc: 调整节点lefttop this.updateBrothersTop(node, totalHeight)
*/ }
adjustLeftTopValue() { },
walk( null,
this.root, true
null, )
(node, parent, isRoot, layerIndex) => { }
if (!node.nodeData.data.expand) {
return // 递归计算节点的宽度
} getNodeAreaWidth(node) {
// 调整left let widthArr = []
if (parent && parent.isRoot) { let loop = (node, width) => {
let areaWidth = this.getNodeAreaWidth(node) if (node.children.length) {
let difference = areaWidth - node.width width += node.width / 2
if (difference > 0) { node.children.forEach(item => {
this.updateBrothersLeft(node, difference / 2) loop(item, width)
} })
} } else {
// 调整top width += node.width
let len = node.children.length widthArr.push(width)
if (parent && !parent.isRoot && len > 0) { }
let marginY = this.getMarginY(layerIndex + 1) }
let totalHeight = loop(node, 0)
node.children.reduce((h, item) => { return Math.max(...widthArr)
return h + item.height }
}, 0) +
(len + 1) * marginY + // 调整兄弟节点的left
len * node.expandBtnSize updateBrothersLeft(node, addWidth) {
this.updateBrothersTop(node, totalHeight) if (node.parent) {
} let childrenList = node.parent.children
}, let index = childrenList.findIndex(item => {
null, return item === node
true })
) // 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称
} if (
(index === 0 || index === childrenList.length - 1) &&
/** childrenList.length > 1
* javascript comment ) {
* @Author: 王林25 let _offset = index === 0 ? -addWidth : addWidth
* @Date: 2021-04-12 18:55:03 node.left += _offset
* @Desc: 递归计算节点的宽度 if (
*/ node.children &&
getNodeAreaWidth(node) { node.children.length &&
let widthArr = [] !node.hasCustomPosition()
let loop = (node, width) => { ) {
if (node.children.length) { this.updateChildren(node.children, 'left', _offset)
width += node.width / 2 }
node.children.forEach(item => { }
loop(item, width) childrenList.forEach((item, _index) => {
}) if (item.hasCustomPosition()) {
} else { // 适配自定义位置
width += node.width return
widthArr.push(width) }
} let _offset = 0
} if (_index < index) {
loop(node, 0) // 左边的节点往左移
return Math.max(...widthArr) _offset = -addWidth
} } else if (_index > index) {
// 右边的节点往右移
/** _offset = addWidth
* javascript comment }
* @Author: 王林25 item.left += _offset
* @Date: 2021-07-13 11:12:51 // 同步更新子节点的位置
* @Desc: 调整兄弟节点的left if (item.children && item.children.length) {
*/ this.updateChildren(item.children, 'left', _offset)
updateBrothersLeft(node, addWidth) { }
if (node.parent) { })
let childrenList = node.parent.children // 更新父节点的位置
let index = childrenList.findIndex(item => { this.updateBrothersLeft(node.parent, addWidth)
return item === node }
}) }
// 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称
if ( // 调整兄弟节点的top
(index === 0 || index === childrenList.length - 1) && updateBrothersTop(node, addHeight) {
childrenList.length > 1 if (node.parent && !node.parent.isRoot) {
) { let childrenList = node.parent.children
let _offset = index === 0 ? -addWidth : addWidth let index = childrenList.findIndex(item => {
node.left += _offset return item === node
if ( })
node.children && childrenList.forEach((item, _index) => {
node.children.length && if (item.hasCustomPosition()) {
!node.hasCustomPosition() // 适配自定义位置
) { return
this.updateChildren(node.children, 'left', _offset) }
} let _offset = 0
} // 下面的节点往下移
childrenList.forEach((item, _index) => { if (_index > index) {
if (item.hasCustomPosition()) { _offset = addHeight
// 适配自定义位置 }
return item.top += _offset
} // 同步更新子节点的位置
let _offset = 0 if (item.children && item.children.length) {
if (_index < index) { this.updateChildren(item.children, 'top', _offset)
// 左边的节点往左移 }
_offset = -addWidth })
} else if (_index > index) { // 更新父节点的位置
// 右边的节点往右移 this.updateBrothersTop(node.parent, addHeight)
_offset = addWidth }
} }
item.left += _offset
// 同步更新子节点的位置 // 绘制连线,连接该节点到其子节点
if (item.children && item.children.length) { renderLine(node, lines, style) {
this.updateChildren(item.children, 'left', _offset) if (node.children.length <= 0) {
} return []
}) }
// 更新父节点的位置 let { left, top, width, height, expandBtnSize } = node
this.updateBrothersLeft(node.parent, addWidth) let len = node.children.length
} let marginX = this.getMarginX(node.layerIndex + 1)
} if (node.isRoot) {
// 根节点
/** let x1 = left + width / 2
* javascript comment let y1 = top + height
* @Author: 王林25 let s1 = marginX * 0.7
* @Date: 2021-04-07 14:26:03 let minx = Infinity
* @Desc: 调整兄弟节点的top let maxx = -Infinity
*/ node.children.forEach((item, index) => {
updateBrothersTop(node, addHeight) { let x2 = item.left + item.width / 2
if (node.parent && !node.parent.isRoot) { let y2 = item.top
let childrenList = node.parent.children if (x2 < minx) {
let index = childrenList.findIndex(item => { minx = x2
return item === node }
}) if (x2 > maxx) {
childrenList.forEach((item, _index) => { maxx = x2
if (item.hasCustomPosition()) { }
// 适配自定义位置 // 节点使用横线风格,需要额外渲染横线
return let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
} ? ` L ${item.left},${y2} L ${item.left + item.width},${y2}`
let _offset = 0 : ''
// 下面的节点往下移 let path =
if (_index > index) { `M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` +
_offset = addHeight nodeUseLineStylePath
} // 竖线
item.top += _offset lines[index].plot(path)
// 同步更新子节点的位置 style && style(lines[index], item)
if (item.children && item.children.length) { })
this.updateChildren(item.children, 'top', _offset) minx = Math.min(minx, x1)
} maxx = Math.max(maxx, x1)
}) // 父节点的竖线
// 更新父节点的位置 let line1 = this.draw.path()
this.updateBrothersTop(node.parent, addHeight) node.style.line(line1)
} line1.plot(`M ${x1},${y1} L ${x1},${y1 + s1}`)
} node._lines.push(line1)
style && style(line1, node)
/** // 水平线
* @Author: 王林 if (len > 0) {
* @Date: 2021-04-11 14:42:48 let lin2 = this.draw.path()
* @Desc: 绘制连线连接该节点到其子节点 node.style.line(lin2)
*/ lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`)
renderLine(node, lines, style) { node._lines.push(lin2)
if (node.children.length <= 0) { style && style(lin2, node)
return [] }
} } else {
let { left, top, width, height, expandBtnSize } = node // 非根节点
let len = node.children.length let y1 = top + height
let marginX = this.getMarginX(node.layerIndex + 1) let maxy = -Infinity
if (node.isRoot) { let x2 = node.left + node.width * 0.3
// 根节点 node.children.forEach((item, index) => {
let x1 = left + width / 2 // 为了适配自定义位置,下面做了各种位置的兼容
let y1 = top + height let y2 = item.top + item.height / 2
let s1 = marginX * 0.7 if (y2 > maxy) {
let minx = Infinity maxy = y2
let maxx = -Infinity }
node.children.forEach((item, index) => { // 水平线
let x2 = item.left + item.width / 2 let path = ''
let y2 = item.top let _left = item.left
if (x2 < minx) { let _isLeft = item.left + item.width < x2
minx = x2 let _isXCenter = false
} if (_isLeft) {
if (x2 > maxx) { // 水平位置在父节点左边
maxx = x2 _left = item.left + item.width
} } else if (item.left < x2 && item.left + item.width > x2) {
// 节点使用横线风格,需要额外渲染横线 // 水平位置在父节点之间
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle _isXCenter = true
? ` L ${item.left},${y2} L ${item.left + item.width},${y2}` y2 = item.top
: '' maxy = y2
let path = }
`M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` + if (y2 > top && y2 < y1) {
nodeUseLineStylePath // 自定义位置的情况:垂直位置节点在父节点之间
// 竖线 path = `M ${
lines[index].plot(path) _isLeft ? node.left : node.left + node.width
style && style(lines[index], item) },${y2} L ${_left},${y2}`
}) } else if (y2 < y1) {
minx = Math.min(minx, x1) // 自定义位置的情况:垂直位置节点在父节点上面
maxx = Math.max(maxx, x1) if (_isXCenter) {
// 父节点的竖线 y2 = item.top + item.height
let line1 = this.draw.path() _left = x2
node.style.line(line1) }
line1.plot(`M ${x1},${y1} L ${x1},${y1 + s1}`) path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}`
node._lines.push(line1) } else {
style && style(line1, node) if (_isXCenter) {
// 水平线 _left = x2
if (len > 0) { }
let lin2 = this.draw.path() path = `M ${x2},${y2} L ${_left},${y2}`
node.style.line(lin2) }
lin2.plot(`M ${minx},${y1 + s1} L ${maxx},${y1 + s1}`) // 节点使用横线风格,需要额外渲染横线
node._lines.push(lin2) let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
style && style(lin2, node) ? ` L ${_left},${y2 - item.height / 2} L ${_left},${
} y2 + item.height / 2
} else { }`
// 非根节点 : ''
let y1 = top + height path += nodeUseLineStylePath
let maxy = -Infinity lines[index].plot(path)
let x2 = node.left + node.width * 0.3 style && style(lines[index], item)
node.children.forEach((item, index) => { })
// 为了适配自定义位置,下面做了各种位置的兼容 // 竖线
let y2 = item.top + item.height / 2 if (len > 0) {
if (y2 > maxy) { let lin2 = this.draw.path()
maxy = y2 expandBtnSize = len > 0 ? expandBtnSize : 0
} node.style.line(lin2)
// 水平线 if (maxy < y1 + expandBtnSize) {
let path = '' lin2.hide()
let _left = item.left } else {
let _isLeft = item.left + item.width < x2 lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`)
let _isXCenter = false lin2.show()
if (_isLeft) { }
// 水平位置在父节点左边 node._lines.push(lin2)
_left = item.left + item.width style && style(lin2, node)
} else if (item.left < x2 && item.left + item.width > x2) { }
// 水平位置在父节点之间 }
_isXCenter = true }
y2 = item.top
maxy = y2 // 渲染按钮
} renderExpandBtn(node, btn) {
if (y2 > top && y2 < y1) { let { width, height, expandBtnSize, isRoot } = node
// 自定义位置的情况:垂直位置节点在父节点之间 if (!isRoot) {
path = `M ${ let { translateX, translateY } = btn.transform()
_isLeft ? node.left : node.left + node.width btn.translate(
},${y2} L ${_left},${y2}` width * 0.3 - expandBtnSize / 2 - translateX,
} else if (y2 < y1) { height + expandBtnSize / 2 - translateY
// 自定义位置的情况:垂直位置节点在父节点上面 )
if (_isXCenter) { }
y2 = item.top + item.height }
_left = x2
} // 创建概要节点
path = `M ${x2},${top} L ${x2},${y2} L ${_left},${y2}` renderGeneralization(node, gLine, gNode) {
} else { let {
if (_isXCenter) { top,
_left = x2 bottom,
} right,
path = `M ${x2},${y2} L ${_left},${y2}` generalizationLineMargin,
} generalizationNodeMargin
// 节点使用横线风格,需要额外渲染横线 } = this.getNodeBoundaries(node, 'h')
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle let x1 = right + generalizationLineMargin
? ` L ${_left},${y2 - item.height / 2} L ${_left},${ let y1 = top
y2 + item.height / 2 let x2 = right + generalizationLineMargin
}` let y2 = bottom
: '' let cx = x1 + 20
path += nodeUseLineStylePath let cy = y1 + (y2 - y1) / 2
lines[index].plot(path) let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
style && style(lines[index], item) gLine.plot(path)
}) gNode.left = right + generalizationNodeMargin
// 竖线 gNode.top = top + (bottom - top - gNode.height) / 2
if (len > 0) { }
let lin2 = this.draw.path() }
expandBtnSize = len > 0 ? expandBtnSize : 0
node.style.line(lin2) export default CatalogOrganization
if (maxy < y1 + expandBtnSize) {
lin2.hide()
} else {
lin2.plot(`M ${x2},${y1 + expandBtnSize} L ${x2},${maxy}`)
lin2.show()
}
node._lines.push(lin2)
style && style(lin2, node)
}
}
}
/**
* @Author: 王林
* @Date: 2021-04-11 19:54:26
* @Desc: 渲染按钮
*/
renderExpandBtn(node, btn) {
let { width, height, expandBtnSize, isRoot } = node
if (!isRoot) {
let { translateX, translateY } = btn.transform()
btn.translate(
width * 0.3 - expandBtnSize / 2 - translateX,
height + expandBtnSize / 2 - translateY
)
}
}
/**
* @Author: 王林
* @Date: 2022-07-30 08:30:35
* @Desc: 创建概要节点
*/
renderGeneralization(node, gLine, gNode) {
let {
top,
bottom,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'h')
let x1 = right + generalizationLineMargin
let y1 = top
let x2 = right + generalizationLineMargin
let y2 = bottom
let cx = x1 + 20
let cy = y1 + (y2 - y1) / 2
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
gLine.plot(path)
gNode.left = right + generalizationNodeMargin
gNode.top = top + (bottom - top - gNode.height) / 2
}
}
export default CatalogOrganization

View File

@ -1,327 +1,267 @@
import Base from './Base' import Base from './Base'
import { walk, asyncRun } from '../utils' import { walk, asyncRun } from '../utils'
/** // 逻辑结构图
* @Author: 王林 class LogicalStructure extends Base {
* @Date: 2021-04-12 22:25:58 // 构造函数
* @Desc: 逻辑结构图 constructor(opt = {}) {
*/ super(opt)
class LogicalStructure extends Base { }
/**
* @Author: 王林 // 布局
* @Date: 2021-04-12 22:26:31 doLayout(callback) {
* @Desc: 构造函数 let task = [
*/ () => {
constructor(opt = {}) { this.computedBaseValue()
super(opt) },
} () => {
this.computedTopValue()
/** },
* javascript comment () => {
* @Author: 王林25 this.adjustTopValue()
* @Date: 2021-04-06 14:04:20 },
* @Desc: 布局 () => {
*/ callback(this.root)
doLayout(callback) { }
let task = [ ]
() => { asyncRun(task)
this.computedBaseValue() }
},
() => { // 遍历数据计算节点的left、width、height
this.computedTopValue() computedBaseValue() {
}, walk(
() => { this.renderer.renderTree,
this.adjustTopValue() null,
}, (cur, parent, isRoot, layerIndex) => {
() => { let newNode = this.createNode(cur, parent, isRoot, layerIndex)
callback(this.root) // 根节点定位在画布中心位置
} if (isRoot) {
] this.setNodeCenter(newNode)
asyncRun(task) } else {
} // 非根节点
// 定位到父节点右侧
/** newNode.left =
* javascript comment parent._node.left + parent._node.width + this.getMarginX(layerIndex)
* @Author: 王林25 }
* @Date: 2021-04-08 09:49:32 if (!cur.data.expand) {
* @Desc: 遍历数据计算节点的leftwidthheight return true
*/ }
computedBaseValue() { },
walk( (cur, parent, isRoot, layerIndex) => {
this.renderer.renderTree, // 返回时计算节点的areaHeight也就是子节点所占的高度之和包括外边距
null, let len = cur.data.expand === false ? 0 : cur._node.children.length
(cur, parent, isRoot, layerIndex) => { cur._node.childrenAreaHeight = len
let newNode = this.createNode(cur, parent, isRoot, layerIndex) ? cur._node.children.reduce((h, item) => {
// 根节点定位在画布中心位置 return h + item.height
if (isRoot) { }, 0) +
this.setNodeCenter(newNode) (len + 1) * this.getMarginY(layerIndex + 1)
} else { : 0
// 非根节点 },
// 定位到父节点右侧 true,
newNode.left = 0
parent._node.left + parent._node.width + this.getMarginX(layerIndex) )
} }
if (!cur.data.expand) {
return true // 遍历节点树计算节点的top
} computedTopValue() {
}, walk(
(cur, parent, isRoot, layerIndex) => { this.root,
// 返回时计算节点的areaHeight也就是子节点所占的高度之和包括外边距 null,
let len = cur.data.expand === false ? 0 : cur._node.children.length (node, parent, isRoot, layerIndex) => {
cur._node.childrenAreaHeight = len if (
? cur._node.children.reduce((h, item) => { node.nodeData.data.expand &&
return h + item.height node.children &&
}, 0) + node.children.length
(len + 1) * this.getMarginY(layerIndex + 1) ) {
: 0 let marginY = this.getMarginY(layerIndex + 1)
}, // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
true, let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
0 let totalTop = top + marginY
) node.children.forEach(cur => {
} cur.top = totalTop
totalTop += cur.height + marginY
/** })
* javascript comment }
* @Author: 王林25 },
* @Date: 2021-04-08 09:59:25 null,
* @Desc: 遍历节点树计算节点的top true
*/ )
computedTopValue() { }
walk(
this.root, // 调整节点top
null, adjustTopValue() {
(node, parent, isRoot, layerIndex) => { walk(
if ( this.root,
node.nodeData.data.expand && null,
node.children && (node, parent, isRoot, layerIndex) => {
node.children.length if (!node.nodeData.data.expand) {
) { return
let marginY = this.getMarginY(layerIndex + 1) }
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2 let difference =
let totalTop = top + marginY node.childrenAreaHeight -
node.children.forEach(cur => { this.getMarginY(layerIndex + 1) * 2 -
cur.top = totalTop node.height
totalTop += cur.height + marginY if (difference > 0) {
}) this.updateBrothers(node, difference / 2)
} }
}, },
null, null,
true true
) )
} }
/** // 更新兄弟节点的top
* javascript comment updateBrothers(node, addHeight) {
* @Author: 王林25 if (node.parent) {
* @Date: 2021-04-08 10:04:05 let childrenList = node.parent.children
* @Desc: 调整节点top let index = childrenList.findIndex(item => {
*/ return item === node
adjustTopValue() { })
walk( childrenList.forEach((item, _index) => {
this.root, if (item === node || item.hasCustomPosition()) {
null, // 适配自定义位置
(node, parent, isRoot, layerIndex) => { return
if (!node.nodeData.data.expand) { }
return let _offset = 0
} // 上面的节点往上移
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 if (_index < index) {
let difference = _offset = -addHeight
node.childrenAreaHeight - } else if (_index > index) {
this.getMarginY(layerIndex + 1) * 2 - // 下面的节点往下移
node.height _offset = addHeight
if (difference > 0) { }
this.updateBrothers(node, difference / 2) item.top += _offset
} // 同步更新子节点的位置
}, if (item.children && item.children.length) {
null, this.updateChildren(item.children, 'top', _offset)
true }
) })
} // 更新父节点的位置
this.updateBrothers(node.parent, addHeight)
/** }
* javascript comment }
* @Author: 王林25
* @Date: 2021-04-07 14:26:03 // 绘制连线,连接该节点到其子节点
* @Desc: 更新兄弟节点的top renderLine(node, lines, style, lineStyle) {
*/ if (lineStyle === 'curve') {
updateBrothers(node, addHeight) { this.renderLineCurve(node, lines, style)
if (node.parent) { } else if (lineStyle === 'direct') {
let childrenList = node.parent.children this.renderLineDirect(node, lines, style)
let index = childrenList.findIndex(item => { } else {
return item === node this.renderLineStraight(node, lines, style)
}) }
childrenList.forEach((item, _index) => { }
if (item === node || item.hasCustomPosition()) {
// 适配自定义位置 // 直线风格连线
return renderLineStraight(node, lines, style) {
} if (node.children.length <= 0) {
let _offset = 0 return []
// 上面的节点往上移 }
if (_index < index) { let { left, top, width, height, expandBtnSize } = node
_offset = -addHeight let marginX = this.getMarginX(node.layerIndex + 1)
} else if (_index > index) { let s1 = (marginX - expandBtnSize) * 0.6
// 下面的节点往下移 node.children.forEach((item, index) => {
_offset = addHeight let x1 =
} node.layerIndex === 0 ? left + width : left + width + expandBtnSize
item.top += _offset let y1 = top + height / 2
// 同步更新子节点的位置 let x2 = item.left
if (item.children && item.children.length) { let y2 = item.top + item.height / 2
this.updateChildren(item.children, 'top', _offset) // 节点使用横线风格,需要额外渲染横线
} let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
}) ? item.width
// 更新父节点的位置 : 0
this.updateBrothers(node.parent, addHeight) let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${
} x2 + nodeUseLineStyleOffset
} },${y2}`
lines[index].plot(path)
/** style && style(lines[index], item)
* @Author: 王林 })
* @Date: 2021-04-11 14:42:48 }
* @Desc: 绘制连线连接该节点到其子节点
*/ // 直连风格
renderLine(node, lines, style, lineStyle) { renderLineDirect(node, lines, style) {
if (lineStyle === 'curve') { if (node.children.length <= 0) {
this.renderLineCurve(node, lines, style) return []
} else if (lineStyle === 'direct') { }
this.renderLineDirect(node, lines, style) let { left, top, width, height, expandBtnSize } = node
} else { node.children.forEach((item, index) => {
this.renderLineStraight(node, lines, style) let x1 =
} node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
} let y1 = top + height / 2
let x2 = item.left
/** let y2 = item.top + item.height / 2
* javascript comment // 节点使用横线风格,需要额外渲染横线
* @Author: 王林25 let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
* @Date: 2022-09-30 14:17:30 ? ` L ${item.left + item.width},${y2}`
* @Desc: 直线风格连线 : ''
*/ let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
renderLineStraight(node, lines, style) { lines[index].plot(path)
if (node.children.length <= 0) { style && style(lines[index], item)
return [] })
} }
let { left, top, width, height, expandBtnSize } = node
let marginX = this.getMarginX(node.layerIndex + 1) // 曲线风格连线
let s1 = (marginX - expandBtnSize) * 0.6 renderLineCurve(node, lines, style) {
node.children.forEach((item, index) => { if (node.children.length <= 0) {
let x1 = return []
node.layerIndex === 0 ? left + width : left + width + expandBtnSize }
let y1 = top + height / 2 let { left, top, width, height, expandBtnSize } = node
let x2 = item.left node.children.forEach((item, index) => {
let y2 = item.top + item.height / 2 let x1 =
// 节点使用横线风格,需要额外渲染横线 node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle let y1 = top + height / 2
? item.width let x2 = item.left
: 0 let y2 = item.top + item.height / 2
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${ let path = ''
x2 + nodeUseLineStyleOffset // 节点使用横线风格,需要额外渲染横线
},${y2}` let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
lines[index].plot(path) ? ` L ${item.left + item.width},${y2}`
style && style(lines[index], item) : ''
}) if (node.isRoot) {
} path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
} else {
/** path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
* javascript comment }
* @Author: 王林25 lines[index].plot(path)
* @Date: 2022-09-30 14:34:41 style && style(lines[index], item)
* @Desc: 直连风格 })
*/ }
renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { // 渲染按钮
return [] renderExpandBtn(node, btn) {
} let { width, height } = node
let { left, top, width, height, expandBtnSize } = node let { translateX, translateY } = btn.transform()
node.children.forEach((item, index) => { // 节点使用横线风格,需要调整展开收起按钮位置
let x1 = let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize ? height / 2
let y1 = top + height / 2 : 0
let x2 = item.left btn.translate(
let y2 = item.top + item.height / 2 width - translateX,
// 节点使用横线风格,需要额外渲染横线 height / 2 - translateY + nodeUseLineStyleOffset
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle )
? ` L ${item.left + item.width},${y2}` }
: ''
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath // 创建概要节点
lines[index].plot(path) renderGeneralization(node, gLine, gNode) {
style && style(lines[index], item) let {
}) top,
} bottom,
right,
/** generalizationLineMargin,
* javascript comment generalizationNodeMargin
* @Author: 王林25 } = this.getNodeBoundaries(node, 'h')
* @Date: 2022-09-30 14:17:43 let x1 = right + generalizationLineMargin
* @Desc: 曲线风格连线 let y1 = top
*/ let x2 = right + generalizationLineMargin
renderLineCurve(node, lines, style) { let y2 = bottom
if (node.children.length <= 0) { let cx = x1 + 20
return [] let cy = y1 + (y2 - y1) / 2
} let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
let { left, top, width, height, expandBtnSize } = node gLine.plot(path)
node.children.forEach((item, index) => { gNode.left = right + generalizationNodeMargin
let x1 = gNode.top = top + (bottom - top - gNode.height) / 2
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize }
let y1 = top + height / 2 }
let x2 = item.left
let y2 = item.top + item.height / 2 export default LogicalStructure
let path = ''
// 节点使用横线风格,需要额外渲染横线
let nodeUseLineStylePath = this.mindMap.themeConfig.nodeUseLineStyle
? ` L ${item.left + item.width},${y2}`
: ''
if (node.isRoot) {
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
} else {
path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath
}
lines[index].plot(path)
style && style(lines[index], item)
})
}
/**
* @Author: 王林
* @Date: 2021-04-11 19:54:26
* @Desc: 渲染按钮
*/
renderExpandBtn(node, btn) {
let { width, height } = node
let { translateX, translateY } = btn.transform()
// 节点使用横线风格,需要调整展开收起按钮位置
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
? height / 2
: 0
btn.translate(
width - translateX,
height / 2 - translateY + nodeUseLineStyleOffset
)
}
/**
* @Author: 王林
* @Date: 2022-07-30 08:30:35
* @Desc: 创建概要节点
*/
renderGeneralization(node, gLine, gNode) {
let {
top,
bottom,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'h')
let x1 = right + generalizationLineMargin
let y1 = top
let x2 = right + generalizationLineMargin
let y2 = bottom
let cx = x1 + 20
let cy = y1 + (y2 - y1) / 2
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
gLine.plot(path)
gNode.left = right + generalizationNodeMargin
gNode.top = top + (bottom - top - gNode.height) / 2
}
}
export default LogicalStructure

View File

@ -1,28 +1,17 @@
import Base from './Base' import Base from './Base'
import { walk, asyncRun } from '../utils' import { walk, asyncRun } from '../utils'
/** // 思维导图
* @Author: 王林
* @Date: 2021-04-12 22:25:58
* @Desc: 思维导图
* 在逻辑结构图的基础上增加一个变量来记录生长方向向左还是向右同时在计算left的时候根据方向来计算调整top时只考虑同方向的节点即可
*/
class MindMap extends Base { class MindMap extends Base {
/** // 构造函数
* @Author: 王林 // 在逻辑结构图的基础上增加一个变量来记录生长方向向左还是向右同时在计算left的时候根据方向来计算、调整top时只考虑同方向的节点即可
* @Date: 2021-04-12 22:26:31
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
super(opt) super(opt)
} }
/** // 布局
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 14:04:20
* @Desc: 布局
*/
doLayout(callback) { doLayout(callback) {
let task = [ let task = [
() => { () => {
@ -41,12 +30,8 @@ class MindMap extends Base {
asyncRun(task) asyncRun(task)
} }
/** // 遍历数据计算节点的left、width、height
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 09:49:32
* @Desc: 遍历数据计算节点的leftwidthheight
*/
computedBaseValue() { computedBaseValue() {
walk( walk(
this.renderer.renderTree, this.renderer.renderTree,
@ -110,12 +95,8 @@ class MindMap extends Base {
) )
} }
/** // 遍历节点树计算节点的top
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 09:59:25
* @Desc: 遍历节点树计算节点的top
*/
computedTopValue() { computedTopValue() {
walk( walk(
this.root, this.root,
@ -147,12 +128,8 @@ class MindMap extends Base {
) )
} }
/** // 调整节点top
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 10:04:05
* @Desc: 调整节点top
*/
adjustTopValue() { adjustTopValue() {
walk( walk(
this.root, this.root,
@ -174,12 +151,8 @@ class MindMap extends Base {
) )
} }
/** // 更新兄弟节点的top
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:26:03
* @Desc: 更新兄弟节点的top
*/
updateBrothers(node, leftAddHeight, rightAddHeight) { updateBrothers(node, leftAddHeight, rightAddHeight) {
if (node.parent) { if (node.parent) {
// 过滤出和自己同方向的节点 // 过滤出和自己同方向的节点
@ -214,11 +187,8 @@ class MindMap extends Base {
} }
} }
/** // 绘制连线,连接该节点到其子节点
* @Author: 王林
* @Date: 2021-04-11 14:42:48
* @Desc: 绘制连线连接该节点到其子节点
*/
renderLine(node, lines, style, lineStyle) { renderLine(node, lines, style, lineStyle) {
if (lineStyle === 'curve') { if (lineStyle === 'curve') {
this.renderLineCurve(node, lines, style) this.renderLineCurve(node, lines, style)
@ -229,12 +199,8 @@ class MindMap extends Base {
} }
} }
/** // 直线风格连线
* javascript comment
* @Author: 王林25
* @Date: 2022-09-30 14:10:47
* @Desc: 直线风格连线
*/
renderLineStraight(node, lines, style) { renderLineStraight(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return [] return []
@ -268,12 +234,8 @@ class MindMap extends Base {
}) })
} }
/** // 直连风格
* javascript comment
* @Author: 王林25
* @Date: 2022-09-30 14:34:41
* @Desc: 直连风格
*/
renderLineDirect(node, lines, style) { renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return [] return []
@ -304,12 +266,8 @@ class MindMap extends Base {
}) })
} }
/** // 曲线风格连线
* javascript comment
* @Author: 王林25
* @Date: 2022-09-30 14:10:56
* @Desc: 曲线风格连线
*/
renderLineCurve(node, lines, style) { renderLineCurve(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return [] return []
@ -345,11 +303,8 @@ class MindMap extends Base {
}) })
} }
/** // 渲染按钮
* @Author: 王林
* @Date: 2021-04-11 19:54:26
* @Desc: 渲染按钮
*/
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { width, height, expandBtnSize } = node let { width, height, expandBtnSize } = node
let { translateX, translateY } = btn.transform() let { translateX, translateY } = btn.transform()
@ -362,11 +317,8 @@ class MindMap extends Base {
btn.translate(x, y) btn.translate(x, y)
} }
/** // 创建概要节点
* @Author: 王林
* @Date: 2022-07-30 08:30:35
* @Desc: 创建概要节点
*/
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let isLeft = node.dir === 'left' let isLeft = node.dir === 'left'
let { let {

View File

@ -1,28 +1,17 @@
import Base from './Base' import Base from './Base'
import { walk, asyncRun } from '../utils' import { walk, asyncRun } from '../utils'
/** // 组织结构图
* @Author: 王林 // 和逻辑结构图基本一样只是方向变成向下生长所以先计算节点的top后计算节点的left、最后调整节点的left即可
* @Date: 2021-04-12 22:25:58
* @Desc: 组织结构图
* 和逻辑结构图基本一样只是方向变成向下生长所以先计算节点的top后计算节点的left最后调整节点的left即可
*/
class OrganizationStructure extends Base { class OrganizationStructure extends Base {
/** // 构造函数
* @Author: 王林
* @Date: 2021-04-12 22:26:31
* @Desc: 构造函数
*/
constructor(opt = {}) { constructor(opt = {}) {
super(opt) super(opt)
} }
/** // 布局
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 14:04:20
* @Desc: 布局
*/
doLayout(callback) { doLayout(callback) {
let task = [ let task = [
() => { () => {
@ -41,12 +30,8 @@ class OrganizationStructure extends Base {
asyncRun(task) asyncRun(task)
} }
/** // 遍历数据计算节点的left、width、height
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 09:49:32
* @Desc: 遍历数据计算节点的leftwidthheight
*/
computedBaseValue() { computedBaseValue() {
walk( walk(
this.renderer.renderTree, this.renderer.renderTree,
@ -81,12 +66,8 @@ class OrganizationStructure extends Base {
) )
} }
/** // 遍历节点树计算节点的left
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 09:59:25
* @Desc: 遍历节点树计算节点的left
*/
computedLeftValue() { computedLeftValue() {
walk( walk(
this.root, this.root,
@ -112,12 +93,8 @@ class OrganizationStructure extends Base {
) )
} }
/** // 调整节点left
* javascript comment
* @Author: 王林25
* @Date: 2021-04-08 10:04:05
* @Desc: 调整节点left
*/
adjustLeftValue() { adjustLeftValue() {
walk( walk(
this.root, this.root,
@ -140,12 +117,8 @@ class OrganizationStructure extends Base {
) )
} }
/** // 更新兄弟节点的left
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 14:26:03
* @Desc: 更新兄弟节点的left
*/
updateBrothers(node, addWidth) { updateBrothers(node, addWidth) {
if (node.parent) { if (node.parent) {
let childrenList = node.parent.children let childrenList = node.parent.children
@ -176,11 +149,8 @@ class OrganizationStructure extends Base {
} }
} }
/** // 绘制连线,连接该节点到其子节点
* @Author: 王林
* @Date: 2021-04-11 14:42:48
* @Desc: 绘制连线连接该节点到其子节点
*/
renderLine(node, lines, style, lineStyle) { renderLine(node, lines, style, lineStyle) {
if (lineStyle === 'direct') { if (lineStyle === 'direct') {
this.renderLineDirect(node, lines, style) this.renderLineDirect(node, lines, style)
@ -189,12 +159,8 @@ class OrganizationStructure extends Base {
} }
} }
/** // 直连风格
* javascript comment
* @Author: 王林25
* @Date: 2022-09-30 14:34:41
* @Desc: 直连风格
*/
renderLineDirect(node, lines, style) { renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return [] return []
@ -215,12 +181,8 @@ class OrganizationStructure extends Base {
}) })
} }
/** // 直线风格连线
* javascript comment
* @Author: 王林25
* @Date: 2022-09-30 14:39:07
* @Desc: 直线风格连线
*/
renderLineStraight(node, lines, style) { renderLineStraight(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return [] return []
@ -269,11 +231,8 @@ class OrganizationStructure extends Base {
} }
} }
/** // 渲染按钮
* @Author: 王林
* @Date: 2021-04-11 19:54:26
* @Desc: 渲染按钮
*/
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { width, height, expandBtnSize } = node let { width, height, expandBtnSize } = node
let { translateX, translateY } = btn.transform() let { translateX, translateY } = btn.transform()
@ -283,11 +242,8 @@ class OrganizationStructure extends Base {
) )
} }
/** // 创建概要节点
* @Author: 王林
* @Date: 2022-07-30 08:30:35
* @Desc: 创建概要节点
*/
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let { let {
bottom, bottom,

View File

@ -1,12 +1,7 @@
import JSZip from 'jszip' import JSZip from 'jszip'
import xmlConvert from 'xml-js' import xmlConvert from 'xml-js'
/** // 解析.xmind文件
* javascript comment
* @Author: 王林25
* @Date: 2022-09-21 14:07:47
* @Desc: 解析.xmind文件
*/
const parseXmindFile = file => { const parseXmindFile = file => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
JSZip.loadAsync(file).then( JSZip.loadAsync(file).then(
@ -37,12 +32,7 @@ const parseXmindFile = file => {
}) })
} }
/** // 转换xmind数据
* javascript comment
* @Author: 王林25
* @Date: 2022-09-21 18:57:25
* @Desc: 转换xmind数据
*/
const transformXmind = content => { const transformXmind = content => {
let data = JSON.parse(content)[0] let data = JSON.parse(content)[0]
let nodeTree = data.rootTopic let nodeTree = data.rootTopic
@ -82,12 +72,7 @@ const transformXmind = content => {
return newTree return newTree
} }
/** // 转换旧版xmind数据xmind8
* javascript comment
* @Author: 王林25
* @Date: 2022-09-23 15:51:51
* @Desc: 转换旧版xmind数据xmind8
*/
const transformOldXmind = content => { const transformOldXmind = content => {
let data = JSON.parse(content) let data = JSON.parse(content)
let elements = data.elements let elements = data.elements

View File

@ -1,15 +1,7 @@
/** // 展开按钮
* @Author: 王林
* @Date: 2021-04-11 19:46:10
* @Desc: 展开按钮
*/
const open = `<svg t="1618141562310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13476" width="200" height="200"><path d="M475.136 327.168v147.968h-147.968v74.24h147.968v147.968h74.24v-147.968h147.968v-74.24h-147.968v-147.968h-74.24z m36.864-222.208c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13477"></path></svg>` const open = `<svg t="1618141562310" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13476" width="200" height="200"><path d="M475.136 327.168v147.968h-147.968v74.24h147.968v147.968h74.24v-147.968h147.968v-74.24h-147.968v-147.968h-74.24z m36.864-222.208c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13477"></path></svg>`
/** // 收缩按钮
* @Author: 王林
* @Date: 2021-04-11 19:46:23
* @Desc: 收缩按钮
*/
const close = `<svg t="1618141589243" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13611" width="200" height="200"><path d="M512 105.472c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13612"></path><path d="M252.928 474.624h518.144v74.24h-518.144z" p-id="13613"></path></svg>` const close = `<svg t="1618141589243" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="13611" width="200" height="200"><path d="M512 105.472c225.28 0 407.04 181.76 407.04 407.04s-181.76 407.04-407.04 407.04-407.04-181.76-407.04-407.04 181.76-407.04 407.04-407.04z m0-74.24c-265.216 0-480.768 215.552-480.768 480.768s215.552 480.768 480.768 480.768 480.768-215.552 480.768-480.768-215.552-480.768-480.768-480.768z" p-id="13612"></path><path d="M252.928 474.624h518.144v74.24h-518.144z" p-id="13613"></path></svg>`
export default { export default {

View File

@ -278,11 +278,7 @@ export const nodeIconList = [
} }
] ]
/** // 获取nodeIconList icon内容
* @Author: 王林
* @Date: 2021-06-23 22:36:56
* @Desc: 获取nodeIconList icon内容
*/
const getNodeIconListIcon = name => { const getNodeIconListIcon = name => {
let arr = name.split('_') let arr = name.split('_')
let typeData = nodeIconList.find(item => { let typeData = nodeIconList.find(item => {

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 天空蓝
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 天空蓝
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(115, 161, 191)', lineColor: 'rgb(115, 161, 191)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 脑残粉
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 脑残粉
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(191, 115, 148)', lineColor: 'rgb(191, 115, 148)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 脑图经典
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 脑图经典
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: '#fff', lineColor: '#fff',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 经典2
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 经典2
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(51, 51, 51)', lineColor: 'rgb(51, 51, 51)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 经典3
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 经典3
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(94, 202, 110)', lineColor: 'rgb(94, 202, 110)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 经典4
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 经典4
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(30, 53, 86)', lineColor: 'rgb(30, 53, 86)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 经典蓝
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 经典蓝
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(51, 51, 51)', lineColor: 'rgb(51, 51, 51)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 经典绿
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 经典绿
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(123, 199, 120)', lineColor: 'rgb(123, 199, 120)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 暗色
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 暗色
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(17, 68, 23)', lineColor: 'rgb(17, 68, 23)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 暗色2
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 暗色2
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(75, 81, 78)', lineColor: 'rgb(75, 81, 78)',

View File

@ -1,146 +1,142 @@
/** // 默认主题
* @Author: 王林 export default {
* @Date: 2021-04-11 10:19:55 // 节点内边距
* @Desc: 默认主题 paddingX: 15,
*/ paddingY: 5,
export default { // 图片显示的最大宽度
// 节点内边距 imgMaxWidth: 100,
paddingX: 15, // 图片显示的最大高度
paddingY: 5, imgMaxHeight: 100,
// 图片显示的最大宽度 // icon的大小
imgMaxWidth: 100, iconSize: 20,
// 图片显示的最大高度 // 连线的粗细
imgMaxHeight: 100, lineWidth: 1,
// icon的大小 // 连线的颜色
iconSize: 20, lineColor: '#549688',
// 连线的粗细 // 连线样式
lineWidth: 1, lineDasharray: 'none',
// 连线的颜色 // 连线风格
lineColor: '#549688', lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线curve、直线straight、直连direct
// 连线样式 // 概要连线的粗细
lineDasharray: 'none', generalizationLineWidth: 1,
// 连线风格 // 概要连线的颜色
lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线curve、直线straight、直连direct generalizationLineColor: '#549688',
// 概要连线的粗细 // 概要曲线距节点的距离
generalizationLineWidth: 1, generalizationLineMargin: 0,
// 概要连线的颜色 // 概要节点距节点的距离
generalizationLineColor: '#549688', generalizationNodeMargin: 20,
// 概要曲线距节点的距离 // 背景颜色
generalizationLineMargin: 0, backgroundColor: '#fafafa',
// 概要节点距节点的距离 // 背景图片
generalizationNodeMargin: 20, backgroundImage: 'none',
// 背景颜色 // 背景重复
backgroundColor: '#fafafa', backgroundRepeat: 'no-repeat',
// 背景图片 // 节点使用横线样式
backgroundImage: 'none', nodeUseLineStyle: false,
// 背景重复 // 根节点样式
backgroundRepeat: 'no-repeat', root: {
// 节点使用横线样式 shape: 'rectangle',
nodeUseLineStyle: false, fillColor: '#549688',
// 根节点样式 fontFamily: '微软雅黑, Microsoft YaHei',
root: { color: '#fff',
shape: 'rectangle', fontSize: 16,
fillColor: '#549688', fontWeight: 'bold',
fontFamily: '微软雅黑, Microsoft YaHei', fontStyle: 'normal',
color: '#fff', lineHeight: 1.5,
fontSize: 16, borderColor: 'transparent',
fontWeight: 'bold', borderWidth: 0,
fontStyle: 'normal', borderDasharray: 'none',
lineHeight: 1.5, borderRadius: 5,
borderColor: 'transparent', textDecoration: 'none',
borderWidth: 0, active: {
borderDasharray: 'none', borderColor: 'rgb(57, 80, 96)',
borderRadius: 5, borderWidth: 3,
textDecoration: 'none', borderDasharray: 'none'
active: { }
borderColor: 'rgb(57, 80, 96)', },
borderWidth: 3, // 二级节点样式
borderDasharray: 'none' second: {
} shape: 'rectangle',
}, marginX: 100,
// 二级节点样式 marginY: 40,
second: { fillColor: '#fff',
shape: 'rectangle', fontFamily: '微软雅黑, Microsoft YaHei',
marginX: 100, color: '#565656',
marginY: 40, fontSize: 16,
fillColor: '#fff', fontWeight: 'noraml',
fontFamily: '微软雅黑, Microsoft YaHei', fontStyle: 'normal',
color: '#565656', lineHeight: 1.5,
fontSize: 16, borderColor: '#549688',
fontWeight: 'noraml', borderWidth: 1,
fontStyle: 'normal', borderDasharray: 'none',
lineHeight: 1.5, borderRadius: 5,
borderColor: '#549688', textDecoration: 'none',
borderWidth: 1, active: {
borderDasharray: 'none', borderColor: 'rgb(57, 80, 96)',
borderRadius: 5, borderWidth: 3,
textDecoration: 'none', borderDasharray: 'none'
active: { }
borderColor: 'rgb(57, 80, 96)', },
borderWidth: 3, // 三级及以下节点样式
borderDasharray: 'none' node: {
} shape: 'rectangle',
}, marginX: 50,
// 三级及以下节点样式 marginY: 0,
node: { fillColor: 'transparent',
shape: 'rectangle', fontFamily: '微软雅黑, Microsoft YaHei',
marginX: 50, color: '#6a6d6c',
marginY: 0, fontSize: 14,
fillColor: 'transparent', fontWeight: 'noraml',
fontFamily: '微软雅黑, Microsoft YaHei', fontStyle: 'normal',
color: '#6a6d6c', lineHeight: 1.5,
fontSize: 14, borderColor: 'transparent',
fontWeight: 'noraml', borderWidth: 0,
fontStyle: 'normal', borderRadius: 5,
lineHeight: 1.5, borderDasharray: 'none',
borderColor: 'transparent', textDecoration: 'none',
borderWidth: 0, active: {
borderRadius: 5, borderColor: 'rgb(57, 80, 96)',
borderDasharray: 'none', borderWidth: 3,
textDecoration: 'none', borderDasharray: 'none'
active: { }
borderColor: 'rgb(57, 80, 96)', },
borderWidth: 3, // 概要节点样式
borderDasharray: 'none' generalization: {
} shape: 'rectangle',
}, marginX: 100,
// 概要节点样式 marginY: 40,
generalization: { fillColor: '#fff',
shape: 'rectangle', fontFamily: '微软雅黑, Microsoft YaHei',
marginX: 100, color: '#565656',
marginY: 40, fontSize: 16,
fillColor: '#fff', fontWeight: 'noraml',
fontFamily: '微软雅黑, Microsoft YaHei', fontStyle: 'normal',
color: '#565656', lineHeight: 1.5,
fontSize: 16, borderColor: '#549688',
fontWeight: 'noraml', borderWidth: 1,
fontStyle: 'normal', borderDasharray: 'none',
lineHeight: 1.5, borderRadius: 5,
borderColor: '#549688', textDecoration: 'none',
borderWidth: 1, active: {
borderDasharray: 'none', borderColor: 'rgb(57, 80, 96)',
borderRadius: 5, borderWidth: 3,
textDecoration: 'none', borderDasharray: 'none'
active: { }
borderColor: 'rgb(57, 80, 96)', }
borderWidth: 3, }
borderDasharray: 'none'
} // 支持激活样式的属性
} // 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
} export const supportActiveStyle = [
'fillColor',
// 支持激活样式的属性 'color',
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小 'fontWeight',
export const supportActiveStyle = [ 'fontStyle',
'fillColor', 'borderColor',
'color', 'borderWidth',
'fontWeight', 'borderDasharray',
'fontStyle', 'borderRadius',
'borderColor', 'textDecoration'
'borderWidth', ]
'borderDasharray',
'borderRadius', export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']
'textDecoration'
]
export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 泥土黄
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 泥土黄
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(191, 147, 115)', lineColor: 'rgb(191, 147, 115)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 清新绿
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 清新绿
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: '#333', lineColor: '#333',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 清新红
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 清新红
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(191, 115, 115)', lineColor: 'rgb(191, 115, 115)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 金色vip
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 金色vip
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(51, 56, 62)', lineColor: 'rgb(51, 56, 62)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 绿叶
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 绿叶
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(40, 193, 84)', lineColor: 'rgb(40, 193, 84)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 小黄人
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 小黄人
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(51, 51, 51)', lineColor: 'rgb(51, 51, 51)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 薄荷
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 薄荷
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(104, 204, 202)', lineColor: 'rgb(104, 204, 202)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 粉红葡萄
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 粉红葡萄
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(166, 101, 106)', lineColor: 'rgb(166, 101, 106)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 浪漫紫
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 浪漫紫
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(123, 115, 191)', lineColor: 'rgb(123, 115, 191)',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 天清绿
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 天清绿
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: '#fff', lineColor: '#fff',

View File

@ -1,11 +1,7 @@
import defaultTheme from './default' import defaultTheme from './default'
import merge from 'deepmerge' import merge from 'deepmerge'
/** // 活力橙
* @Author: 王林
* @Date: 2021-04-11 15:22:18
* @Desc: 活力橙
*/
export default merge(defaultTheme, { export default merge(defaultTheme, {
// 连线的颜色 // 连线的颜色
lineColor: 'rgb(254, 146, 0)', lineColor: 'rgb(254, 146, 0)',

View File

@ -1,8 +1,4 @@
/** // 标签颜色列表
* @Author: 王林
* @Date: 2021-06-24 21:42:07
* @Desc: 标签颜色列表
*/
export const tagColorList = [ export const tagColorList = [
{ {
color: 'rgb(77, 65, 0)', color: 'rgb(77, 65, 0)',
@ -26,12 +22,7 @@ export const tagColorList = [
} }
] ]
/** // 布局结构列表
* javascript comment
* @Author: 王林25
* @Date: 2021-07-13 15:56:28
* @Desc: 布局结构列表
*/
export const layoutList = [ export const layoutList = [
{ {
name: '逻辑结构图', name: '逻辑结构图',
@ -61,11 +52,7 @@ export const layoutValueList = [
'organizationStructure' 'organizationStructure'
] ]
/** // 主题列表
* @Author: 王林
* @Date: 2021-06-24 22:58:42
* @Desc: 主题列表
*/
export const themeList = [ export const themeList = [
{ {
name: '默认', name: '默认',

View File

@ -1,9 +1,4 @@
/** // 深度优先遍历树
* javascript comment
* @Author: 王林25
* @Date: 2021-04-06 14:13:17
* @Desc: 深度优先遍历树
*/
export const walk = ( export const walk = (
root, root,
parent, parent,
@ -34,12 +29,7 @@ export const walk = (
afterCallback && afterCallback(root, parent, isRoot, layerIndex, index) afterCallback && afterCallback(root, parent, isRoot, layerIndex, index)
} }
/** // 广度优先遍历树
* javascript comment
* @Author: 王林25
* @Date: 2021-04-07 18:47:20
* @Desc: 广度优先遍历树
*/
export const bfsWalk = (root, callback) => { export const bfsWalk = (root, callback) => {
callback(root) callback(root)
let stack = [root] let stack = [root]
@ -60,12 +50,7 @@ export const bfsWalk = (root, callback) => {
} }
} }
/** // 缩放图片尺寸
* javascript comment
* @Author: 王林25
* @Date: 2021-04-09 10:44:54
* @Desc: 缩放图片尺寸
*/
export const resizeImgSize = (width, height, maxWidth, maxHeight) => { export const resizeImgSize = (width, height, maxWidth, maxHeight) => {
let nRatio = width / height let nRatio = width / height
let arr = [] let arr = []
@ -98,12 +83,7 @@ export const resizeImgSize = (width, height, maxWidth, maxHeight) => {
return arr return arr
} }
/** // 缩放图片
* javascript comment
* @Author: 王林25
* @Date: 2021-04-09 10:18:42
* @Desc: 缩放图片
*/
export const resizeImg = (imgUrl, maxWidth, maxHeight) => { export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let img = new Image() let img = new Image()
@ -123,11 +103,7 @@ export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
}) })
} }
/** // 从头html结构字符串里获取带换行符的字符串
* @Author: 王林
* @Date: 2021-05-04 12:26:56
* @Desc: 从头html结构字符串里获取带换行符的字符串
*/
export const getStrWithBrFromHtml = str => { export const getStrWithBrFromHtml = str => {
str = str.replace(/<br>/gim, '\n') str = str.replace(/<br>/gim, '\n')
let el = document.createElement('div') let el = document.createElement('div')
@ -136,11 +112,7 @@ export const getStrWithBrFromHtml = str => {
return str return str
} }
/** // 极简的深拷贝
* @Author: 王林
* @Date: 2021-05-04 14:45:39
* @Desc: 极简的深拷贝
*/
export const simpleDeepClone = data => { export const simpleDeepClone = data => {
try { try {
return JSON.parse(JSON.stringify(data)) return JSON.parse(JSON.stringify(data))
@ -149,11 +121,7 @@ export const simpleDeepClone = data => {
} }
} }
/** // 复制渲染树数据
* @Author: 王林
* @Date: 2021-05-04 14:40:11
* @Desc: 复制渲染树数据
*/
export const copyRenderTree = (tree, root) => { export const copyRenderTree = (tree, root) => {
tree.data = simpleDeepClone(root.data) tree.data = simpleDeepClone(root.data)
tree.children = [] tree.children = []
@ -165,11 +133,7 @@ export const copyRenderTree = (tree, root) => {
return tree return tree
} }
/** // 复制节点树数据
* @Author: 王林
* @Date: 2021-05-04 14:40:11
* @Desc: 复制节点树数据
*/
export const copyNodeTree = (tree, root, removeActiveState = false) => { export const copyNodeTree = (tree, root, removeActiveState = false) => {
tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data) tree.data = simpleDeepClone(root.nodeData ? root.nodeData.data : root.data)
if (removeActiveState) { if (removeActiveState) {
@ -192,11 +156,7 @@ export const copyNodeTree = (tree, root, removeActiveState = false) => {
return tree return tree
} }
/** // 图片转成dataURL
* @Author: 王林
* @Date: 2021-07-04 09:08:43
* @Desc: 图片转成dataURL
*/
export const imgToDataUrl = src => { export const imgToDataUrl = src => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const img = new Image() const img = new Image()
@ -222,11 +182,7 @@ export const imgToDataUrl = src => {
}) })
} }
/** // 下载文件
* @Author: 王林
* @Date: 2021-07-04 16:20:06
* @Desc: 下载文件
*/
export const downloadFile = (file, fileName) => { export const downloadFile = (file, fileName) => {
let a = document.createElement('a') let a = document.createElement('a')
a.href = file a.href = file
@ -234,11 +190,7 @@ export const downloadFile = (file, fileName) => {
a.click() a.click()
} }
/** // 节流函数
* @Author: 王林
* @Date: 2021-07-11 10:36:47
* @Desc: 节流函数
*/
export const throttle = (fn, time = 300, ctx) => { export const throttle = (fn, time = 300, ctx) => {
let timer = null let timer = null
return () => { return () => {
@ -252,12 +204,7 @@ export const throttle = (fn, time = 300, ctx) => {
} }
} }
/** // 异步执行任务队列
* javascript comment
* @Author: 王林25
* @Date: 2021-07-12 10:27:36
* @Desc: 异步执行任务队列
*/
export const asyncRun = (taskList, callback = () => {}) => { export const asyncRun = (taskList, callback = () => {}) => {
let index = 0 let index = 0
let len = taskList.length let len = taskList.length