增加eslint校验、prettier格式化

This commit is contained in:
wanglin2 2022-10-19 16:33:09 +08:00
parent 0aeee0ff28
commit f663f8d60a
94 changed files with 11347 additions and 10732 deletions

View File

@ -0,0 +1,17 @@
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"overrides": [
],
"parserOptions": {
"parser": 'babel-eslint',
"ecmaVersion": 12,
"sourceType": "module",
"allowImportExportEverywhere": true
},
"rules": {
}
}

View File

@ -0,0 +1,10 @@
src/assets
*/.DS_Store
dist
example
node_modules
*.json
*.md
.eslintrc.js
.prettierignore
.prettierrc

View File

@ -0,0 +1,5 @@
semi: false
singleQuote: true
printWidth: 80
trailingComma: 'none'
arrowParens: 'avoid'

View File

@ -10,15 +10,11 @@ import BatchExecution from './src/BatchExecution'
import Export from './src/Export' import Export from './src/Export'
import Select from './src/Select' import Select from './src/Select'
import Drag from './src/Drag' import Drag from './src/Drag'
import MiniMap from './src/MiniMap'; import MiniMap from './src/MiniMap'
import { import { layoutValueList } from './src/utils/constant'
layoutValueList import { SVG } from '@svgdotjs/svg.js'
} from './src/utils/constant'
import {
SVG
} from '@svgdotjs/svg.js'
import xmind from './src/parse/xmind' import xmind from './src/parse/xmind'
import { simpleDeepClone } from './src/utils'; import { simpleDeepClone } from './src/utils'
// 默认选项配置 // 默认选项配置
const defaultOpt = { const defaultOpt = {

View File

@ -17,7 +17,10 @@
"type": "git", "type": "git",
"url": "https://github.com/wanglin2/mind-map" "url": "https://github.com/wanglin2/mind-map"
}, },
"scripts": {}, "scripts": {
"lint": "eslint src/",
"format": "prettier --write ."
},
"module": "index.js", "module": "index.js",
"main": "./dist/simpleMindMap.umd.min.js", "main": "./dist/simpleMindMap.umd.min.js",
"dependencies": { "dependencies": {
@ -35,5 +38,9 @@
"mind-map", "mind-map",
"mindMap", "mindMap",
"MindMap" "MindMap"
] ],
"devDependencies": {
"eslint": "^8.25.0",
"prettier": "^2.7.1"
}
} }

View File

@ -22,17 +22,17 @@ const nextTick = function (fn, ctx) {
counter = (counter + 1) % 2 // counter会在0和1两者循环变化 counter = (counter + 1) % 2 // counter会在0和1两者循环变化
textNode.data = counter // 节点变化会触发回调handle textNode.data = counter // 节点变化会触发回调handle
} }
} else {// 否则使用定时器 } else {
// 否则使用定时器
timerFunc = setTimeout timerFunc = setTimeout
} }
return function (cb, ctx) { return function () {
if (pending) return if (pending) return
pending = true pending = true
timerFunc(handle, 0) timerFunc(handle, 0)
} }
} }
/** /**
* @Author: 王林 * @Author: 王林
* @Date: 2021-06-26 22:40:52 * @Date: 2021-06-26 22:40:52
@ -57,7 +57,7 @@ class BatchExecution {
*/ */
push(name, fn) { push(name, fn) {
if (this.has[name]) { if (this.has[name]) {
return; return
} }
this.has[name] = true this.has[name] = true
this.queue.push({ this.queue.push({

View File

@ -1,4 +1,4 @@
import { copyRenderTree, simpleDeepClone } from './utils'; import { copyRenderTree, simpleDeepClone } from './utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -53,11 +53,11 @@ class Command {
*/ */
exec(name, ...args) { exec(name, ...args) {
if (this.commands[name]) { if (this.commands[name]) {
this.commands[name].forEach((fn) => { this.commands[name].forEach(fn => {
fn(...args) fn(...args)
}) })
if (name === 'BACK' || name === 'FORWARD') { if (name === 'BACK' || name === 'FORWARD') {
return; return
} }
this.addHistory() this.addHistory()
} }
@ -89,8 +89,8 @@ class Command {
this.commands[name] = [] this.commands[name] = []
delete this.commands[name] delete this.commands[name]
} else { } else {
let index = this.commands[name].find((item) => { let index = this.commands[name].find(item => {
return item === fn; return item === fn
}) })
if (index !== -1) { if (index !== -1) {
this.commands[name].splice(index, 1) this.commands[name].splice(index, 1)
@ -108,7 +108,11 @@ class Command {
this.history.push(simpleDeepClone(data)) this.history.push(simpleDeepClone(data))
this.activeHistoryIndex = this.history.length - 1 this.activeHistoryIndex = this.history.length - 1
this.mindMap.emit('data_change', data) this.mindMap.emit('data_change', data)
this.mindMap.emit('back_forward', this.activeHistoryIndex, this.history.length) this.mindMap.emit(
'back_forward',
this.activeHistoryIndex,
this.history.length
)
} }
/** /**
@ -119,8 +123,12 @@ class Command {
back(step = 1) { back(step = 1) {
if (this.activeHistoryIndex - step >= 0) { if (this.activeHistoryIndex - step >= 0) {
this.activeHistoryIndex -= step this.activeHistoryIndex -= step
this.mindMap.emit('back_forward', this.activeHistoryIndex, this.history.length) this.mindMap.emit(
return simpleDeepClone(this.history[this.activeHistoryIndex]); 'back_forward',
this.activeHistoryIndex,
this.history.length
)
return simpleDeepClone(this.history[this.activeHistoryIndex])
} }
} }
@ -134,8 +142,8 @@ class Command {
let len = this.history.length let len = this.history.length
if (this.activeHistoryIndex + step <= len - 1) { if (this.activeHistoryIndex + step <= len - 1) {
this.activeHistoryIndex += step this.activeHistoryIndex += step
this.mindMap.emit('back_forward', this.activeHistoryIndex,) this.mindMap.emit('back_forward', this.activeHistoryIndex)
return simpleDeepClone(this.history[this.activeHistoryIndex]); return simpleDeepClone(this.history[this.activeHistoryIndex])
} }
} }

View File

@ -1,7 +1,4 @@
import { import { bfsWalk, throttle } from './utils'
bfsWalk,
throttle
} from './utils'
import Base from './layouts/Base' import Base from './layouts/Base'
/** /**
@ -16,9 +13,7 @@ class Drag extends Base {
* @Date: 2021-07-10 22:35:16 * @Date: 2021-07-10 22:35:16
* @Desc: 构造函数 * @Desc: 构造函数
*/ */
constructor({ constructor({ mindMap }) {
mindMap
}) {
super(mindMap.renderer) super(mindMap.renderer)
this.mindMap = mindMap this.mindMap = mindMap
this.reset() this.reset()
@ -80,25 +75,17 @@ class Drag extends Base {
e.preventDefault() e.preventDefault()
// 计算鼠标按下的位置距离节点左上角的距离 // 计算鼠标按下的位置距离节点左上角的距离
this.drawTransform = this.mindMap.draw.transform() this.drawTransform = this.mindMap.draw.transform()
let { let { scaleX, scaleY, translateX, translateY } = this.drawTransform
scaleX,
scaleY,
translateX,
translateY
} = this.drawTransform
this.offsetX = e.clientX - (node.left * scaleX + translateX) this.offsetX = e.clientX - (node.left * scaleX + translateX)
this.offsetY = e.clientY - (node.top * scaleY + translateY) this.offsetY = e.clientY - (node.top * scaleY + translateY)
// //
this.node = node this.node = node
this.isMousedown = true this.isMousedown = true
let { let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
x,
y
} = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseDownX = x this.mouseDownX = x
this.mouseDownY = y this.mouseDownY = y
}) })
this.mindMap.on('mousemove', (e) => { this.mindMap.on('mousemove', e => {
if (this.mindMap.opt.readonly) { if (this.mindMap.opt.readonly) {
return return
} }
@ -106,13 +93,14 @@ class Drag extends Base {
return return
} }
e.preventDefault() e.preventDefault()
let { let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
x,
y
} = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x this.mouseMoveX = x
this.mouseMoveY = y this.mouseMoveY = y
if ((Math.abs(x - this.mouseDownX) <= 10 && Math.abs(y - this.mouseDownY) <= 10) && !this.node.isDrag) { if (
Math.abs(x - this.mouseDownX) <= 10 &&
Math.abs(y - this.mouseDownY) <= 10 &&
!this.node.isDrag
) {
return return
} }
this.mindMap.renderer.clearAllActive() this.mindMap.renderer.clearAllActive()
@ -131,7 +119,7 @@ class Drag extends Base {
*/ */
onMouseup(e) { onMouseup(e) {
if (!this.isMousedown) { if (!this.isMousedown) {
return; return
} }
this.isMousedown = false this.isMousedown = false
let _nodeIsDrag = this.node.isDrag let _nodeIsDrag = this.node.isDrag
@ -142,24 +130,21 @@ class Drag extends Base {
if (this.overlapNode) { if (this.overlapNode) {
this.mindMap.renderer.setNodeActive(this.overlapNode, false) this.mindMap.renderer.setNodeActive(this.overlapNode, false)
this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode) this.mindMap.execCommand('MOVE_NODE_TO', this.node, this.overlapNode)
} else if (this.prevNode) { // 存在前一个相邻节点,作为其下一个兄弟节点 } else if (this.prevNode) {
// 存在前一个相邻节点,作为其下一个兄弟节点
this.mindMap.renderer.setNodeActive(this.prevNode, false) this.mindMap.renderer.setNodeActive(this.prevNode, false)
this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode) this.mindMap.execCommand('INSERT_AFTER', this.node, this.prevNode)
} else if (this.nextNode) { // 存在下一个相邻节点,作为其前一个兄弟节点 } else if (this.nextNode) {
// 存在下一个相邻节点,作为其前一个兄弟节点
this.mindMap.renderer.setNodeActive(this.nextNode, false) this.mindMap.renderer.setNodeActive(this.nextNode, false)
this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode) this.mindMap.execCommand('INSERT_BEFORE', this.node, this.nextNode)
} else if (_nodeIsDrag) { } else if (_nodeIsDrag) {
// 自定义位置 // 自定义位置
let { let { x, y } = this.mindMap.toPos(
x, e.clientX - this.offsetX,
y e.clientY - this.offsetY
} = this.mindMap.toPos(e.clientX - this.offsetX, e.clientY - this.offsetY) )
let { let { scaleX, scaleY, translateX, translateY } = this.drawTransform
scaleX,
scaleY,
translateX,
translateY
} = this.drawTransform
x = (x - translateX) / scaleX x = (x - translateX) / scaleX
y = (y - translateY) / scaleY y = (y - translateY) / scaleY
this.node.left = x this.node.left = x
@ -221,15 +206,10 @@ class Drag extends Base {
*/ */
onMove(x, y) { onMove(x, y) {
if (!this.isMousedown) { if (!this.isMousedown) {
return; return
} }
this.createCloneNode() this.createCloneNode()
let { let { scaleX, scaleY, translateX, translateY } = this.drawTransform
scaleX,
scaleY,
translateX,
translateY
} = this.drawTransform
this.cloneNodeLeft = x - this.offsetX this.cloneNodeLeft = x - this.offsetX
this.cloneNodeTop = y - this.offsetY this.cloneNodeTop = y - this.offsetY
x = (this.cloneNodeLeft - translateX) / scaleX x = (this.cloneNodeLeft - translateX) / scaleX
@ -238,7 +218,14 @@ class Drag extends Base {
this.clone.translate(x - t.translateX, y - t.translateY) this.clone.translate(x - t.translateX, y - t.translateY)
// 连接线 // 连接线
let parent = this.node.parent let parent = this.node.parent
this.line.plot(this.quadraticCurvePath(parent.left + parent.width / 2, parent.top + parent.height / 2, x + this.node.width / 2, y + this.node.height / 2)) this.line.plot(
this.quadraticCurvePath(
parent.left + parent.width / 2,
parent.top + parent.height / 2,
x + this.node.width / 2,
y + this.node.height / 2
)
)
this.checkOverlapNode() this.checkOverlapNode()
} }
@ -251,34 +238,24 @@ class Drag extends Base {
if (!this.drawTransform) { if (!this.drawTransform) {
return return
} }
let { let { scaleX, scaleY, translateX, translateY } = this.drawTransform
scaleX,
scaleY,
translateX,
translateY
} = this.drawTransform
let checkRight = this.cloneNodeLeft + this.node.width * scaleX let checkRight = this.cloneNodeLeft + this.node.width * scaleX
let checkBottom = this.cloneNodeTop + this.node.height * scaleX let checkBottom = this.cloneNodeTop + this.node.height * scaleX
this.overlapNode = null this.overlapNode = null
this.prevNode = null this.prevNode = null
this.nextNode = null this.nextNode = null
this.placeholder.size(0, 0) this.placeholder.size(0, 0)
bfsWalk(this.mindMap.renderer.root, (node) => { bfsWalk(this.mindMap.renderer.root, node => {
if (node.nodeData.data.isActive) { if (node.nodeData.data.isActive) {
this.mindMap.renderer.setNodeActive(node, false) this.mindMap.renderer.setNodeActive(node, false)
} }
if (node === this.node || this.node.isParent(node)) { if (node === this.node || this.node.isParent(node)) {
return return
} }
if (this.overlapNode || this.prevNode && this.nextNode) { if (this.overlapNode || (this.prevNode && this.nextNode)) {
return return
} }
let { let { left, top, width, height } = node
left,
top,
width,
height
} = node
let _left = left let _left = left
let _top = top let _top = top
let _bottom = top + height let _bottom = top + height
@ -289,8 +266,10 @@ class Drag extends Base {
// 检测是否重叠 // 检测是否重叠
if (!this.overlapNode) { if (!this.overlapNode) {
if ( if (
left <= checkRight && right >= this.cloneNodeLeft && left <= checkRight &&
top <= checkBottom && bottom >= this.cloneNodeTop right >= this.cloneNodeLeft &&
top <= checkBottom &&
bottom >= this.cloneNodeTop
) { ) {
this.overlapNode = node this.overlapNode = node
} }

View File

@ -63,7 +63,7 @@ class Event extends EventEmitter {
window.addEventListener('mousemove', this.onMousemove) window.addEventListener('mousemove', this.onMousemove)
window.addEventListener('mouseup', this.onMouseup) window.addEventListener('mouseup', this.onMouseup)
// 兼容火狐浏览器 // 兼容火狐浏览器
if(window.navigator.userAgent.toLowerCase().indexOf("firefox") != -1){ if (window.navigator.userAgent.toLowerCase().indexOf('firefox') != -1) {
this.mindMap.el.addEventListener('DOMMouseScroll', this.onMousewheel) this.mindMap.el.addEventListener('DOMMouseScroll', this.onMousewheel)
} else { } else {
this.mindMap.el.addEventListener('mousewheel', this.onMousewheel) this.mindMap.el.addEventListener('mousewheel', this.onMousewheel)

View File

@ -1,8 +1,6 @@
import { imgToDataUrl, downloadFile } from './utils' import { imgToDataUrl, downloadFile } from './utils'
import JsPDF from 'jspdf' import JsPDF from 'jspdf'
import { import { SVG } from '@svgdotjs/svg.js'
SVG,
} from '@svgdotjs/svg.js'
const URL = window.URL || window.webkitURL || window const URL = window.URL || window.webkitURL || window
/** /**
@ -47,7 +45,7 @@ class Export {
let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap() let { svg, svgHTML } = this.mindMap.miniMap.getMiniMap()
// 把图片的url转换成data:url类型否则导出会丢失图片 // 把图片的url转换成data:url类型否则导出会丢失图片
let imageList = svg.find('image') let imageList = svg.find('image')
let task = imageList.map(async (item) => { let task = imageList.map(async item => {
let imgUlr = item.attr('href') || item.attr('xlink:href') let imgUlr = item.attr('href') || item.attr('xlink:href')
let imgData = await imgToDataUrl(imgUlr) let imgData = await imgToDataUrl(imgUlr)
item.attr('href', imgData) item.attr('href', imgData)
@ -78,13 +76,23 @@ class Export {
// 绘制背景 // 绘制背景
await this.drawBackgroundToCanvas(ctx, canvas.width, canvas.height) await this.drawBackgroundToCanvas(ctx, canvas.width, canvas.height)
// 图片绘制到canvas里 // 图片绘制到canvas里
ctx.drawImage(img, 0, 0, img.width, img.height, this.exportPadding, this.exportPadding, img.width, img.height) ctx.drawImage(
img,
0,
0,
img.width,
img.height,
this.exportPadding,
this.exportPadding,
img.width,
img.height
)
resolve(canvas.toDataURL()) resolve(canvas.toDataURL())
} catch (error) { } catch (error) {
reject(error) reject(error)
} }
} }
img.onerror = (e) => { img.onerror = e => {
reject(e) reject(e)
} }
img.src = svgSrc img.src = svgSrc
@ -97,8 +105,12 @@ class Export {
* @Desc: 在canvas上绘制思维导图背景 * @Desc: 在canvas上绘制思维导图背景
*/ */
drawBackgroundToCanvas(ctx, width, height) { drawBackgroundToCanvas(ctx, width, height) {
return new Promise((resolve, rejct) => { return new Promise((resolve, reject) => {
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig let {
backgroundColor = '#fff',
backgroundImage,
backgroundRepeat = 'repeat'
} = this.mindMap.themeConfig
// 背景颜色 // 背景颜色
ctx.save() ctx.save()
ctx.rect(0, 0, width, height) ctx.rect(0, 0, width, height)
@ -118,8 +130,8 @@ class Export {
ctx.restore() ctx.restore()
resolve() resolve()
} }
img.onerror = (e) => { img.onerror = e => {
rejct(e) reject(e)
} }
} else { } else {
resolve() resolve()
@ -191,8 +203,12 @@ class Export {
* @Desc: 在svg上绘制思维导图背景 * @Desc: 在svg上绘制思维导图背景
*/ */
drawBackgroundToSvg(svg) { drawBackgroundToSvg(svg) {
return new Promise(async (resolve, rejct) => { return new Promise(async resolve => {
let { backgroundColor = '#fff', backgroundImage, backgroundRepeat = "repeat" } = this.mindMap.themeConfig let {
backgroundColor = '#fff',
backgroundImage,
backgroundRepeat = 'repeat'
} = this.mindMap.themeConfig
// 背景颜色 // 背景颜色
svg.css('background-color', backgroundColor) svg.css('background-color', backgroundColor)
// 背景图片 // 背景图片
@ -242,7 +258,7 @@ class Export {
* @Desc: 专有文件其实就是json文件 * @Desc: 专有文件其实就是json文件
*/ */
smm(name, withConfig) { smm(name, withConfig) {
return this.json(name, withConfig); return this.json(name, withConfig)
} }
} }

View File

@ -1,4 +1,4 @@
import { keyMap } from './utils/keyMap'; import { keyMap } from './utils/keyMap'
/** /**
* @Author: 王林 * @Author: 王林
* @Date: 2021-04-24 15:20:46 * @Date: 2021-04-24 15:20:46
@ -67,15 +67,15 @@ export default class KeyCommand {
* @Desc: 绑定事件 * @Desc: 绑定事件
*/ */
bindEvent() { bindEvent() {
window.addEventListener('keydown', (e) => { window.addEventListener('keydown', e => {
if (this.isPause) { if (this.isPause) {
return return
} }
Object.keys(this.shortcutMap).forEach((key) => { Object.keys(this.shortcutMap).forEach(key => {
if (this.checkKey(e, key)) { if (this.checkKey(e, key)) {
e.stopPropagation() e.stopPropagation()
e.preventDefault() e.preventDefault()
this.shortcutMap[key].forEach((fn) => { this.shortcutMap[key].forEach(fn => {
fn() fn()
}) })
} }
@ -95,8 +95,8 @@ export default class KeyCommand {
return false return false
} }
for (let i = 0; i < o.length; i++) { for (let i = 0; i < o.length; i++) {
let index = k.findIndex((item) => { let index = k.findIndex(item => {
return item === o[i]; return item === o[i]
}) })
if (index === -1) { if (index === -1) {
return false return false
@ -137,7 +137,7 @@ export default class KeyCommand {
getKeyCodeArr(key) { getKeyCodeArr(key) {
let keyArr = key.split(/\s*\+\s*/) let keyArr = key.split(/\s*\+\s*/)
let arr = [] let arr = []
keyArr.forEach((item) => { keyArr.forEach(item => {
arr.push(keyMap[item]) arr.push(keyMap[item])
}) })
return arr return arr
@ -152,7 +152,7 @@ export default class KeyCommand {
* Shift + a * Shift + a
*/ */
addShortcut(key, fn) { addShortcut(key, fn) {
key.split(/\s*\|\s*/).forEach((item) => { key.split(/\s*\|\s*/).forEach(item => {
if (this.shortcutMap[item]) { if (this.shortcutMap[item]) {
this.shortcutMap[item].push(fn) this.shortcutMap[item].push(fn)
} else { } else {
@ -168,10 +168,10 @@ export default class KeyCommand {
* @Desc: 移除快捷键命令 * @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]) {
if (fn) { if (fn) {
let index = this.shortcutMap[item].findIndex((f) => { let index = this.shortcutMap[item].findIndex(f => {
return f === fn return f === fn
}) })
if (index !== -1) { if (index !== -1) {
@ -192,7 +192,7 @@ export default class KeyCommand {
*/ */
getShortcutFn(key) { getShortcutFn(key) {
let res = [] let res = []
key.split(/\s*\|\s*/).forEach((item) => { key.split(/\s*\|\s*/).forEach(item => {
res = this.shortcutMap[item] || [] res = this.shortcutMap[item] || []
}) })
return res return res

View File

@ -7,16 +7,16 @@ class MiniMap {
* @Desc: 构造函数 * @Desc: 构造函数
*/ */
constructor(opt) { constructor(opt) {
this.mindMap = opt.mindMap; this.mindMap = opt.mindMap
this.isMousedown = false; this.isMousedown = false
this.mousedownPos = { this.mousedownPos = {
x: 0, x: 0,
y: 0, y: 0
}; }
this.startViewPos = { this.startViewPos = {
x: 0, x: 0,
y: 0, y: 0
}; }
} }
/** /**
@ -26,39 +26,39 @@ class MiniMap {
* @Desc: 获取小地图相关数据 * @Desc: 获取小地图相关数据
*/ */
getMiniMap() { getMiniMap() {
const svg = this.mindMap.svg; const svg = this.mindMap.svg
const draw = this.mindMap.draw; const draw = this.mindMap.draw
// 保存原始信息 // 保存原始信息
const origWidth = svg.width(); const origWidth = svg.width()
const origHeight = svg.height(); const origHeight = svg.height()
const origTransform = draw.transform(); const origTransform = draw.transform()
const elRect = this.mindMap.el.getBoundingClientRect(); const elRect = this.mindMap.el.getBoundingClientRect()
// 去除放大缩小的变换效果 // 去除放大缩小的变换效果
draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY); draw.scale(1 / origTransform.scaleX, 1 / origTransform.scaleY)
// 获取变换后的位置尺寸信息其实是getBoundingClientRect方法的包装方法 // 获取变换后的位置尺寸信息其实是getBoundingClientRect方法的包装方法
const rect = draw.rbox(); const rect = draw.rbox()
// 将svg设置为实际内容的宽高 // 将svg设置为实际内容的宽高
svg.size(rect.width, rect.height); svg.size(rect.width, rect.height)
// 把实际内容变换 // 把实际内容变换
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top); draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
// 克隆一份数据 // 克隆一份数据
const clone = svg.clone(); const clone = svg.clone()
// 恢复原先的大小和变换信息 // 恢复原先的大小和变换信息
svg.size(origWidth, origHeight); svg.size(origWidth, origHeight)
draw.transform(origTransform); draw.transform(origTransform)
return { return {
svg: clone, // 思维导图图形的整体svg元素包括svg画布容器、g实际的思维导图组 svg: clone, // 思维导图图形的整体svg元素包括svg画布容器、g实际的思维导图组
svgHTML: clone.svg(), // svg字符串 svgHTML: clone.svg(), // svg字符串
rect: { rect: {
...rect, // 思维导图图形未缩放时的位置尺寸等信息 ...rect, // 思维导图图形未缩放时的位置尺寸等信息
ratio: rect.width / rect.height, // 思维导图图形的宽高比 ratio: rect.width / rect.height // 思维导图图形的宽高比
}, },
origWidth, // 画布宽度 origWidth, // 画布宽度
origHeight, // 画布高度 origHeight, // 画布高度
scaleX: origTransform.scaleX, // 思维导图图形的水平缩放值 scaleX: origTransform.scaleX, // 思维导图图形的水平缩放值
scaleY: origTransform.scaleY, // 思维导图图形的垂直缩放值 scaleY: origTransform.scaleY // 思维导图图形的垂直缩放值
}; }
} }
/** /**
@ -71,57 +71,57 @@ class MiniMap {
*/ */
calculationMiniMap(boxWidth, boxHeight) { calculationMiniMap(boxWidth, boxHeight) {
let { svgHTML, rect, origWidth, origHeight, scaleX, scaleY } = let { svgHTML, rect, origWidth, origHeight, scaleX, scaleY } =
this.getMiniMap(); this.getMiniMap()
// 计算数据 // 计算数据
let boxRatio = boxWidth / boxHeight; let boxRatio = boxWidth / boxHeight
let actWidth = 0; let actWidth = 0
let actHeight = 0; let actHeight = 0
if (boxRatio > rect.ratio) { if (boxRatio > rect.ratio) {
// 高度以box为准缩放宽度 // 高度以box为准缩放宽度
actHeight = boxHeight; actHeight = boxHeight
actWidth = rect.ratio * actHeight; actWidth = rect.ratio * actHeight
} else { } else {
// 宽度以box为准缩放高度 // 宽度以box为准缩放高度
actWidth = boxWidth; actWidth = boxWidth
actHeight = actWidth / rect.ratio; actHeight = actWidth / rect.ratio
} }
// svg图形的缩放及位置 // svg图形的缩放及位置
let miniMapBoxScale = actWidth / rect.width; let miniMapBoxScale = actWidth / rect.width
let miniMapBoxLeft = (boxWidth - actWidth) / 2; let miniMapBoxLeft = (boxWidth - actWidth) / 2
let miniMapBoxTop = (boxHeight - actHeight) / 2; let miniMapBoxTop = (boxHeight - actHeight) / 2
// 视口框大小及位置 // 视口框大小及位置
let _rectX = rect.x - (rect.width * scaleX - rect.width) / 2; let _rectX = rect.x - (rect.width * scaleX - rect.width) / 2
let _rectX2 = rect.x2 + (rect.width * scaleX - rect.width) / 2; let _rectX2 = rect.x2 + (rect.width * scaleX - rect.width) / 2
let _rectY = rect.y - (rect.height * scaleY - rect.height) / 2; let _rectY = rect.y - (rect.height * scaleY - rect.height) / 2
let _rectY2 = rect.y2 + (rect.height * scaleY - rect.height) / 2; let _rectY2 = rect.y2 + (rect.height * scaleY - rect.height) / 2
let _rectWidth = rect.width * scaleX; let _rectWidth = rect.width * scaleX
let _rectHeight = rect.height * scaleY; let _rectHeight = rect.height * scaleY
let viewBoxStyle = { let viewBoxStyle = {
left: 0, left: 0,
top: 0, top: 0,
right: 0, right: 0,
bottom: 0, bottom: 0
}; }
viewBoxStyle.left = viewBoxStyle.left =
Math.max(0, (-_rectX / _rectWidth) * actWidth) + miniMapBoxLeft + "px"; Math.max(0, (-_rectX / _rectWidth) * actWidth) + miniMapBoxLeft + 'px'
viewBoxStyle.right = viewBoxStyle.right =
Math.max(0, ((_rectX2 - origWidth) / _rectWidth) * actWidth) + Math.max(0, ((_rectX2 - origWidth) / _rectWidth) * actWidth) +
miniMapBoxLeft + miniMapBoxLeft +
"px"; 'px'
viewBoxStyle.top = viewBoxStyle.top =
Math.max(0, (-_rectY / _rectHeight) * actHeight) + miniMapBoxTop + "px"; Math.max(0, (-_rectY / _rectHeight) * actHeight) + miniMapBoxTop + 'px'
viewBoxStyle.bottom = viewBoxStyle.bottom =
Math.max(0, ((_rectY2 - origHeight) / _rectHeight) * actHeight) + Math.max(0, ((_rectY2 - origHeight) / _rectHeight) * actHeight) +
miniMapBoxTop + miniMapBoxTop +
"px"; 'px'
return { return {
svgHTML, // 小地图html svgHTML, // 小地图html
viewBoxStyle, // 视图框的位置信息 viewBoxStyle, // 视图框的位置信息
miniMapBoxScale, // 视图框的缩放值 miniMapBoxScale, // 视图框的缩放值
miniMapBoxLeft, // 视图框的left值 miniMapBoxLeft, // 视图框的left值
miniMapBoxTop, // 视图框的top值 miniMapBoxTop // 视图框的top值
}; }
} }
/** /**
@ -131,17 +131,17 @@ class MiniMap {
* @Desc: 小地图鼠标按下事件 * @Desc: 小地图鼠标按下事件
*/ */
onMousedown(e) { onMousedown(e) {
this.isMousedown = true; this.isMousedown = true
this.mousedownPos = { this.mousedownPos = {
x: e.clientX, x: e.clientX,
y: e.clientY, y: e.clientY
}; }
// 保存视图当前的偏移量 // 保存视图当前的偏移量
let transformData = this.mindMap.view.getTransformData(); let transformData = this.mindMap.view.getTransformData()
this.startViewPos = { this.startViewPos = {
x: transformData.state.x, x: transformData.state.x,
y: transformData.state.y, y: transformData.state.y
}; }
} }
/** /**
@ -152,13 +152,13 @@ class MiniMap {
*/ */
onMousemove(e, sensitivityNum = 5) { onMousemove(e, sensitivityNum = 5) {
if (!this.isMousedown) { if (!this.isMousedown) {
return; return
} }
let ox = e.clientX - this.mousedownPos.x; let ox = e.clientX - this.mousedownPos.x
let oy = e.clientY - this.mousedownPos.y; let oy = e.clientY - this.mousedownPos.y
// 在视图最初偏移量上累加更新量 // 在视图最初偏移量上累加更新量
this.mindMap.view.translateXTo(ox * sensitivityNum + this.startViewPos.x); this.mindMap.view.translateXTo(ox * sensitivityNum + this.startViewPos.x)
this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y); this.mindMap.view.translateYTo(oy * sensitivityNum + this.startViewPos.y)
} }
/** /**
@ -168,8 +168,8 @@ class MiniMap {
* @Desc: 小地图鼠标松开事件 * @Desc: 小地图鼠标松开事件
*/ */
onMouseup() { onMouseup() {
this.isMousedown = false; this.isMousedown = false
} }
} }
export default MiniMap; export default MiniMap

View File

@ -1,18 +1,7 @@
import Style from './Style' import Style from './Style'
import Shape from './Shape' import Shape from './Shape'
import { import { resizeImgSize, asyncRun } from './utils'
resizeImgSize, import { Image, SVG, Circle, A, G, Rect, Text } from '@svgdotjs/svg.js'
asyncRun
} from './utils'
import {
Image,
SVG,
Circle,
A,
G,
Rect,
Text
} from '@svgdotjs/svg.js'
import btnsSvg from './svg/btns' import btnsSvg from './svg/btns'
import iconsSvg from './svg/icons' import iconsSvg from './svg/icons'
@ -53,7 +42,8 @@ class Node {
// 是否是根节点 // 是否是根节点
this.isRoot = opt.isRoot === undefined ? false : opt.isRoot this.isRoot = opt.isRoot === undefined ? false : opt.isRoot
// 是否是概要节点 // 是否是概要节点
this.isGeneralization = opt.isGeneralization === undefined ? false : opt.isGeneralization this.isGeneralization =
opt.isGeneralization === undefined ? false : opt.isGeneralization
this.generalizationBelongNode = null this.generalizationBelongNode = null
// 节点层级 // 节点层级
this.layerIndex = opt.layerIndex === undefined ? 0 : opt.layerIndex this.layerIndex = opt.layerIndex === undefined ? 0 : opt.layerIndex
@ -231,7 +221,13 @@ class Node {
this._expandBtn.off(['mouseover', 'mouseout', 'click']) this._expandBtn.off(['mouseover', 'mouseout', 'click'])
} }
if (this.group) { if (this.group) {
this.group.off(['click', 'dblclick', 'contextmenu', 'mousedown', 'mouseup']) this.group.off([
'click',
'dblclick',
'contextmenu',
'mousedown',
'mouseup'
])
} }
} }
@ -242,7 +238,14 @@ class Node {
*/ */
removeAllNode() { removeAllNode() {
// 节点内的内容 // 节点内的内容
;[this._imgData, this._iconData, this._textData, this._hyperlinkData, this._tagData, this._noteData].forEach((item) => { ;[
this._imgData,
this._iconData,
this._textData,
this._hyperlinkData,
this._tagData,
this._noteData
].forEach(item => {
if (item && item.node) item.node.remove() if (item && item.node) item.node.remove()
}) })
this._imgData = null this._imgData = null
@ -275,10 +278,7 @@ class Node {
getSize() { getSize() {
this.removeAllNode() this.removeAllNode()
this.createNodeData() this.createNodeData()
let { let { width, height } = this.getNodeRect()
width,
height
} = this.getNodeRect()
// 判断节点尺寸是否有变化 // 判断节点尺寸是否有变化
let changed = this.width !== width || this.height !== height let changed = this.width !== width || this.height !== height
this.width = width this.width = width
@ -307,7 +307,7 @@ class Node {
if (this._iconData.length > 0) { if (this._iconData.length > 0) {
textContentWidth += this._iconData.reduce((sum, cur) => { textContentWidth += this._iconData.reduce((sum, cur) => {
textContentHeight = Math.max(textContentHeight, cur.height) textContentHeight = Math.max(textContentHeight, cur.height)
return sum += cur.width + this.textContentItemMargin return (sum += cur.width + this.textContentItemMargin)
}, 0) }, 0)
} }
// 文字 // 文字
@ -318,13 +318,16 @@ class Node {
// 超链接 // 超链接
if (this._hyperlinkData) { if (this._hyperlinkData) {
textContentWidth += this._hyperlinkData.width textContentWidth += this._hyperlinkData.width
textContentHeight = Math.max(textContentHeight, this._hyperlinkData.height) textContentHeight = Math.max(
textContentHeight,
this._hyperlinkData.height
)
} }
// 标签 // 标签
if (this._tagData.length > 0) { if (this._tagData.length > 0) {
textContentWidth += this._tagData.reduce((sum, cur) => { textContentWidth += this._tagData.reduce((sum, cur) => {
textContentHeight = Math.max(textContentHeight, cur.height) textContentHeight = Math.max(textContentHeight, cur.height)
return sum += cur.width + this.textContentItemMargin return (sum += cur.width + this.textContentItemMargin)
}, 0) }, 0)
} }
// 备注 // 备注
@ -336,13 +339,17 @@ class Node {
this._rectInfo.textContentWidth = textContentWidth this._rectInfo.textContentWidth = textContentWidth
this._rectInfo.textContentHeight = textContentHeight this._rectInfo.textContentHeight = textContentHeight
// 间距 // 间距
let margin = imgContentHeight > 0 && textContentHeight > 0 ? this.blockContentMargin : 0 let margin =
imgContentHeight > 0 && textContentHeight > 0
? this.blockContentMargin
: 0
let { paddingX, paddingY } = this.getPaddingVale() let { paddingX, paddingY } = this.getPaddingVale()
// 纯内容宽高 // 纯内容宽高
let _width = Math.max(imgContentWidth, textContentWidth) let _width = Math.max(imgContentWidth, textContentWidth)
let _height = imgContentHeight + textContentHeight let _height = imgContentHeight + textContentHeight
// 计算节点形状需要的附加内边距 // 计算节点形状需要的附加内边距
let { paddingX: shapePaddingX, paddingY: shapePaddingY } = this.shapeInstance.getShapePadding(_width, _height, paddingX, paddingY) let { paddingX: shapePaddingX, paddingY: shapePaddingY } =
this.shapeInstance.getShapePadding(_width, _height, paddingX, paddingY)
this.shapePadding.paddingX = shapePaddingX this.shapePadding.paddingX = shapePaddingX
this.shapePadding.paddingY = shapePaddingY this.shapePadding.paddingY = shapePaddingY
return { return {
@ -367,7 +374,7 @@ class Node {
if (this.nodeData.data.imageTitle) { if (this.nodeData.data.imageTitle) {
node.attr('title', this.nodeData.data.imageTitle) node.attr('title', this.nodeData.data.imageTitle)
} }
node.on('dblclick', (e) => { node.on('dblclick', e => {
this.mindMap.emit('node_img_dblclick', this, e) this.mindMap.emit('node_img_dblclick', this, e)
}) })
return { return {
@ -384,7 +391,12 @@ class Node {
* @Desc: 获取图片显示宽高 * @Desc: 获取图片显示宽高
*/ */
getImgShowSize() { getImgShowSize() {
return resizeImgSize(this.nodeData.data.imageSize.width, this.nodeData.data.imageSize.height, this.themeConfig.imgMaxWidth, this.themeConfig.imgMaxHeight) return resizeImgSize(
this.nodeData.data.imageSize.width,
this.nodeData.data.imageSize.height,
this.themeConfig.imgMaxWidth,
this.themeConfig.imgMaxHeight
)
} }
/** /**
@ -399,7 +411,7 @@ class Node {
return [] return []
} }
let iconSize = this.themeConfig.iconSize let iconSize = this.themeConfig.iconSize
return _data.icon.map((item) => { return _data.icon.map(item => {
return { return {
node: SVG(iconsSvg.getNodeIconListIcon(item)).size(iconSize, iconSize), node: SVG(iconsSvg.getNodeIconListIcon(item)).size(iconSize, iconSize),
width: iconSize, width: iconSize,
@ -416,18 +428,23 @@ class Node {
*/ */
createTextNode() { createTextNode() {
let g = new G() let g = new G()
let fontSize = this.getStyle('fontSize', this.isRoot, this.nodeData.data.isActive) let fontSize = this.getStyle(
let lineHeight = this.getStyle('lineHeight', this.isRoot, this.nodeData.data.isActive) 'fontSize',
this.nodeData.data.text.split(/\n/img).forEach((item, index) => { this.isRoot,
this.nodeData.data.isActive
)
let lineHeight = this.getStyle(
'lineHeight',
this.isRoot,
this.nodeData.data.isActive
)
this.nodeData.data.text.split(/\n/gim).forEach((item, index) => {
let node = new Text().text(item) let node = new Text().text(item)
this.style.text(node) this.style.text(node)
node.y(fontSize * lineHeight * index) node.y(fontSize * lineHeight * index)
g.add(node) g.add(node)
}) })
let { let { width, height } = g.bbox()
width,
height
} = g.bbox()
return { return {
node: g, node: g,
width, width,
@ -449,7 +466,7 @@ class Node {
let node = new SVG() let node = new SVG()
// 超链接节点 // 超链接节点
let a = new A().to(hyperlink).target('_blank') let a = new A().to(hyperlink).target('_blank')
a.node.addEventListener('click', (e) => { a.node.addEventListener('click', e => {
e.stopPropagation() e.stopPropagation()
}) })
if (hyperlinkTitle) { if (hyperlinkTitle) {
@ -485,10 +502,7 @@ class Node {
// 标签文本 // 标签文本
let text = new Text().text(item).x(8).cy(10) let text = new Text().text(item).x(8).cy(10)
this.style.tagText(text, index) this.style.tagText(text, index)
let { let { width } = text.bbox()
width,
height
} = text.bbox()
// 标签矩形 // 标签矩形
let rect = new Rect().size(width + 16, 20) let rect = new Rect().size(width + 16, 20)
this.style.tagRect(rect, index) this.style.tagRect(rect, index)
@ -542,7 +556,11 @@ class Node {
this.noteEl.style.top = top + iconSize + 'px' this.noteEl.style.top = top + iconSize + 'px'
this.noteEl.style.display = 'block' this.noteEl.style.display = 'block'
} else { } else {
this.mindMap.opt.customNoteContentShow.show(this.nodeData.data.note, left, top + iconSize) this.mindMap.opt.customNoteContentShow.show(
this.nodeData.data.note,
left,
top + iconSize
)
} }
}) })
node.on('mouseout', () => { node.on('mouseout', () => {
@ -576,11 +594,7 @@ class Node {
* @Desc: 定位节点内容 * @Desc: 定位节点内容
*/ */
layout() { layout() {
let { let { width, textContentItemMargin } = this
width,
height,
textContentItemMargin
} = this
let { paddingY } = this.getPaddingVale() let { paddingY } = this.getPaddingVale()
paddingY += this.shapePadding.paddingY paddingY += this.shapePadding.paddingY
// 创建组 // 创建组
@ -593,7 +607,9 @@ class Node {
this.update(true) this.update(true)
// 节点形状 // 节点形状
const shape = this.getShape() const shape = this.getShape()
this.style[shape === 'rectangle' ? 'rect' : 'shape'](this.shapeInstance.createShape()) this.style[shape === 'rectangle' ? 'rect' : 'shape'](
this.shapeInstance.createShape()
)
// 图片节点 // 图片节点
let imgHeight = 0 let imgHeight = 0
if (this._imgData) { if (this._imgData) {
@ -608,8 +624,10 @@ class Node {
let iconNested = new G() let iconNested = new G()
if (this._iconData && this._iconData.length > 0) { if (this._iconData && this._iconData.length > 0) {
let iconLeft = 0 let iconLeft = 0
this._iconData.forEach((item) => { this._iconData.forEach(item => {
item.node.x(textContentOffsetX + iconLeft).y((this._rectInfo.textContentHeight - item.height) / 2) item.node
.x(textContentOffsetX + iconLeft)
.y((this._rectInfo.textContentHeight - item.height) / 2)
iconNested.add(item.node) iconNested.add(item.node)
iconLeft += item.width + textContentItemMargin iconLeft += item.width + textContentItemMargin
}) })
@ -624,7 +642,9 @@ class Node {
} }
// 超链接 // 超链接
if (this._hyperlinkData) { if (this._hyperlinkData) {
this._hyperlinkData.node.x(textContentOffsetX).y((this._rectInfo.textContentHeight - this._hyperlinkData.height) / 2) this._hyperlinkData.node
.x(textContentOffsetX)
.y((this._rectInfo.textContentHeight - this._hyperlinkData.height) / 2)
textContentNested.add(this._hyperlinkData.node) textContentNested.add(this._hyperlinkData.node)
textContentOffsetX += this._hyperlinkData.width + textContentItemMargin textContentOffsetX += this._hyperlinkData.width + textContentItemMargin
} }
@ -632,8 +652,10 @@ class Node {
let tagNested = new G() let tagNested = new G()
if (this._tagData && this._tagData.length > 0) { if (this._tagData && this._tagData.length > 0) {
let tagLeft = 0 let tagLeft = 0
this._tagData.forEach((item) => { this._tagData.forEach(item => {
item.node.x(textContentOffsetX + tagLeft).y((this._rectInfo.textContentHeight - item.height) / 2) item.node
.x(textContentOffsetX + tagLeft)
.y((this._rectInfo.textContentHeight - item.height) / 2)
tagNested.add(item.node) tagNested.add(item.node)
tagLeft += item.width + textContentItemMargin tagLeft += item.width + textContentItemMargin
}) })
@ -642,31 +664,37 @@ class Node {
} }
// 备注 // 备注
if (this._noteData) { if (this._noteData) {
this._noteData.node.x(textContentOffsetX).y((this._rectInfo.textContentHeight - this._noteData.height) / 2) this._noteData.node
.x(textContentOffsetX)
.y((this._rectInfo.textContentHeight - this._noteData.height) / 2)
textContentNested.add(this._noteData.node) textContentNested.add(this._noteData.node)
textContentOffsetX += this._noteData.width textContentOffsetX += this._noteData.width
} }
// 文字内容整体 // 文字内容整体
textContentNested.translate( textContentNested.translate(
width / 2 - textContentNested.bbox().width / 2, width / 2 - textContentNested.bbox().width / 2,
imgHeight + paddingY + (imgHeight > 0 && this._rectInfo.textContentHeight > 0 ? this.blockContentMargin : 0) imgHeight +
paddingY +
(imgHeight > 0 && this._rectInfo.textContentHeight > 0
? this.blockContentMargin
: 0)
) )
this.group.add(textContentNested) this.group.add(textContentNested)
// 单击事件,选中节点 // 单击事件,选中节点
this.group.on('click', (e) => { this.group.on('click', e => {
this.mindMap.emit('node_click', this, e) this.mindMap.emit('node_click', this, e)
this.active(e) this.active(e)
}) })
this.group.on('mousedown', (e) => { this.group.on('mousedown', e => {
e.stopPropagation() e.stopPropagation()
this.mindMap.emit('node_mousedown', this, e) this.mindMap.emit('node_mousedown', this, e)
}) })
this.group.on('mouseup', (e) => { this.group.on('mouseup', e => {
e.stopPropagation() e.stopPropagation()
this.mindMap.emit('node_mouseup', this, e) this.mindMap.emit('node_mouseup', this, e)
}) })
// 双击事件 // 双击事件
this.group.on('dblclick', (e) => { this.group.on('dblclick', e => {
if (this.mindMap.opt.readonly) { if (this.mindMap.opt.readonly) {
return return
} }
@ -674,7 +702,7 @@ class Node {
this.mindMap.emit('node_dblclick', this, e) this.mindMap.emit('node_dblclick', this, e)
}) })
// 右键菜单事件 // 右键菜单事件
this.group.on('contextmenu', (e) => { this.group.on('contextmenu', e => {
if (this.mindMap.opt.readonly || this.isGeneralization) { if (this.mindMap.opt.readonly || this.isGeneralization) {
return return
} }
@ -734,7 +762,8 @@ class Node {
// 需要移除展开收缩按钮 // 需要移除展开收缩按钮
if (this._expandBtn && this.nodeData.children.length <= 0) { if (this._expandBtn && this.nodeData.children.length <= 0) {
this.removeExpandBtn() this.removeExpandBtn()
} else if (!this._expandBtn && this.nodeData.children.length > 0) {// 需要添加展开收缩按钮 } else if (!this._expandBtn && this.nodeData.children.length > 0) {
// 需要添加展开收缩按钮
this.renderExpandBtn() this.renderExpandBtn()
} else { } else {
this.updateExpandBtnPos() this.updateExpandBtnPos()
@ -742,7 +771,9 @@ class Node {
this.renderGeneralization() this.renderGeneralization()
let t = this.group.transform() let t = this.group.transform()
if (!layout) { if (!layout) {
this.group.animate(300).translate(this.left - t.translateX, this.top - t.translateY) this.group
.animate(300)
.translate(this.left - t.translateX, this.top - t.translateY)
} else { } else {
this.group.translate(this.left - t.translateX, this.top - t.translateY) this.group.translate(this.left - t.translateX, this.top - t.translateY)
} }
@ -765,9 +796,14 @@ class Node {
this.update() this.update()
} }
// 子节点 // 子节点
if (this.children && this.children.length && this.nodeData.data.expand !== false) { if (
this.children &&
this.children.length &&
this.nodeData.data.expand !== false
) {
let index = 0 let index = 0
asyncRun(this.children.map((item) => { asyncRun(
this.children.map(item => {
return () => { return () => {
item.render(() => { item.render(() => {
index++ index++
@ -776,7 +812,8 @@ class Node {
} }
}) })
} }
})) })
)
} else { } else {
callback() callback()
} }
@ -800,11 +837,13 @@ class Node {
this.removeLine() this.removeLine()
// 子节点 // 子节点
if (this.children && this.children.length) { if (this.children && this.children.length) {
asyncRun(this.children.map((item) => { asyncRun(
this.children.map(item => {
return () => { return () => {
item.remove() item.remove()
} }
})) })
)
} }
} }
@ -823,11 +862,13 @@ class Node {
} }
// 子节点 // 子节点
if (this.children && this.children.length) { if (this.children && this.children.length) {
asyncRun(this.children.map((item) => { asyncRun(
this.children.map(item => {
return () => { return () => {
item.hide() item.hide()
} }
})) })
)
} }
} }
@ -839,7 +880,7 @@ class Node {
*/ */
show() { show() {
if (!this.group) { if (!this.group) {
return; return
} }
this.group.show() this.group.show()
this.showGeneralization() this.showGeneralization()
@ -849,11 +890,13 @@ class Node {
} }
// 子节点 // 子节点
if (this.children && this.children.length) { if (this.children && this.children.length) {
asyncRun(this.children.map((item) => { asyncRun(
this.children.map(item => {
return () => { return () => {
item.show() item.show()
} }
})) })
)
} }
} }
@ -874,19 +917,24 @@ class Node {
}) })
} else if (childrenLen < this._lines.length) { } else if (childrenLen < this._lines.length) {
// 删除多余的线 // 删除多余的线
this._lines.slice(childrenLen).forEach((line) => { this._lines.slice(childrenLen).forEach(line => {
line.remove() line.remove()
}) })
this._lines = this._lines.slice(0, childrenLen) this._lines = this._lines.slice(0, childrenLen)
} }
// 画线 // 画线
this.renderer.layout.renderLine(this, this._lines, (line, node) => { this.renderer.layout.renderLine(
this,
this._lines,
(line, node) => {
// 添加样式 // 添加样式
this.styleLine(line, node) this.styleLine(line, node)
}, this.style.getStyle('lineStyle', true)) },
this.style.getStyle('lineStyle', true)
)
// 子级的连线也需要更新 // 子级的连线也需要更新
if (deep && this.children && this.children.length > 0) { if (deep && this.children && this.children.length > 0) {
this.children.forEach((item) => { this.children.forEach(item => {
item.renderLine(deep) item.renderLine(deep)
}) })
} }
@ -899,13 +947,17 @@ class Node {
* @Desc: 设置连线样式 * @Desc: 设置连线样式
*/ */
styleLine(line, node) { styleLine(line, node) {
let width = node.getSelfInhertStyle('lineWidth') || node.getStyle('lineWidth', true) let width =
let color = node.getSelfInhertStyle('lineColor') || node.getStyle('lineColor', true) node.getSelfInhertStyle('lineWidth') || node.getStyle('lineWidth', true)
let dasharray = node.getSelfInhertStyle('lineDasharray') || node.getStyle('lineDasharray', true) let color =
node.getSelfInhertStyle('lineColor') || node.getStyle('lineColor', true)
let dasharray =
node.getSelfInhertStyle('lineDasharray') ||
node.getStyle('lineDasharray', true)
this.style.line(line, { this.style.line(line, {
width, width,
color, color,
dasharray, dasharray
}) })
} }
@ -915,7 +967,7 @@ class Node {
* @Desc: 移除连线 * @Desc: 移除连线
*/ */
removeLine() { removeLine() {
this._lines.forEach((line) => { this._lines.forEach(line => {
line.remove() line.remove()
}) })
this._lines = [] this._lines = []
@ -994,7 +1046,11 @@ class Node {
return return
} }
this.createGeneralizationNode() this.createGeneralizationNode()
this.renderer.layout.renderGeneralization(this, this._generalizationLine, this._generalizationNode) this.renderer.layout.renderGeneralization(
this,
this._generalizationLine,
this._generalizationNode
)
this.style.generalizationLine(this._generalizationLine) this.style.generalizationLine(this._generalizationLine)
this._generalizationNode.render() this._generalizationNode.render()
} }
@ -1017,7 +1073,9 @@ class Node {
} }
// hack修复当激活一个节点时创建概要然后立即激活创建的概要节点后会重复创建概要节点并且无法删除的问题 // hack修复当激活一个节点时创建概要然后立即激活创建的概要节点后会重复创建概要节点并且无法删除的问题
if (this.generalizationBelongNode) { if (this.generalizationBelongNode) {
this.draw.find('.generalization_' + this.generalizationBelongNode.uid).remove() this.draw
.find('.generalization_' + this.generalizationBelongNode.uid)
.remove()
} }
} }
@ -1093,27 +1151,35 @@ class Node {
* @Desc: 展开收缩按钮 * @Desc: 展开收缩按钮
*/ */
renderExpandBtn() { renderExpandBtn() {
if (!this.nodeData.children || this.nodeData.children.length <= 0 || this.isRoot) { if (
!this.nodeData.children ||
this.nodeData.children.length <= 0 ||
this.isRoot
) {
return return
} }
this._expandBtn = new G() this._expandBtn = new G()
this.updateExpandBtnNode() this.updateExpandBtnNode()
this._expandBtn.on('mouseover', (e) => { this._expandBtn.on('mouseover', e => {
e.stopPropagation() e.stopPropagation()
this._expandBtn.css({ this._expandBtn.css({
cursor: 'pointer' cursor: 'pointer'
}) })
}) })
this._expandBtn.on('mouseout', (e) => { this._expandBtn.on('mouseout', e => {
e.stopPropagation() e.stopPropagation()
this._expandBtn.css({ this._expandBtn.css({
cursor: 'auto' cursor: 'auto'
}) })
}) })
this._expandBtn.on('click', (e) => { this._expandBtn.on('click', e => {
e.stopPropagation() e.stopPropagation()
// 展开收缩 // 展开收缩
this.mindMap.execCommand('SET_NODE_EXPAND', this, !this.nodeData.data.expand) this.mindMap.execCommand(
'SET_NODE_EXPAND',
this,
!this.nodeData.data.expand
)
this.mindMap.emit('expand_btn_click', this) this.mindMap.emit('expand_btn_click', this)
}) })
this.group.add(this._expandBtn) this.group.add(this._expandBtn)
@ -1134,7 +1200,6 @@ class Node {
} }
} }
/** /**
* javascript comment * javascript comment
* @Author: 王林25 * @Author: 王林25
@ -1165,7 +1230,7 @@ class Node {
if (!this.parent || this === node) { if (!this.parent || this === node) {
return false return false
} }
return this.parent.children.find((item) => { return this.parent.children.find(item => {
return item === node return item === node
}) })
} }
@ -1210,7 +1275,9 @@ class Node {
*/ */
getParentSelfStyle(prop) { getParentSelfStyle(prop) {
if (this.parent) { if (this.parent) {
return this.parent.getSelfStyle(prop) || this.parent.getParentSelfStyle(prop) return (
this.parent.getSelfStyle(prop) || this.parent.getParentSelfStyle(prop)
)
} }
return null return null
} }
@ -1222,8 +1289,10 @@ class Node {
* @Desc: 获取自身可继承的自定义样式 * @Desc: 获取自身可继承的自定义样式
*/ */
getSelfInhertStyle(prop) { getSelfInhertStyle(prop) {
return this.getSelfStyle(prop) // 自身 return (
|| this.getParentSelfStyle(prop) // 父级 this.getSelfStyle(prop) || // 自身
this.getParentSelfStyle(prop)
) // 父级
} }
/** /**

View File

@ -65,7 +65,11 @@ class Render {
* @Desc: 设置布局结构 * @Desc: 设置布局结构
*/ */
setLayout() { setLayout() {
this.layout = new (layouts[this.mindMap.opt.layout] ? layouts[this.mindMap.opt.layout] : layouts.logicalStructure)(this) this.layout = new (
layouts[this.mindMap.opt.layout]
? layouts[this.mindMap.opt.layout]
: layouts.logicalStructure
)(this)
} }
/** /**
@ -176,7 +180,10 @@ class Render {
this.mindMap.command.add('REMOVE_GENERALIZATION', this.removeGeneralization) this.mindMap.command.add('REMOVE_GENERALIZATION', this.removeGeneralization)
// 设置节点自定义位置 // 设置节点自定义位置
this.setNodeCustomPosition = this.setNodeCustomPosition.bind(this) this.setNodeCustomPosition = this.setNodeCustomPosition.bind(this)
this.mindMap.command.add('SET_NODE_CUSTOM_POSITION', this.setNodeCustomPosition) this.mindMap.command.add(
'SET_NODE_CUSTOM_POSITION',
this.setNodeCustomPosition
)
// 一键整理布局 // 一键整理布局
this.resetLayout = this.resetLayout.bind(this) this.resetLayout = this.resetLayout.bind(this)
this.mindMap.command.add('RESET_LAYOUT', this.resetLayout) this.mindMap.command.add('RESET_LAYOUT', this.resetLayout)
@ -269,7 +276,7 @@ class Render {
if (this.reRender) { if (this.reRender) {
this.clearActive() this.clearActive()
} }
this.layout.doLayout((root) => { this.layout.doLayout(root => {
this.root = root this.root = root
this.root.render(() => { this.root.render(() => {
this.mindMap.emit('node_tree_render_end') this.mindMap.emit('node_tree_render_end')
@ -284,7 +291,7 @@ class Render {
* @Desc: 清除当前激活的节点 * @Desc: 清除当前激活的节点
*/ */
clearActive() { clearActive() {
this.activeNodeList.forEach((item) => { this.activeNodeList.forEach(item => {
this.setNodeActive(item, false) this.setNodeActive(item, false)
}) })
this.activeNodeList = [] this.activeNodeList = []
@ -334,7 +341,7 @@ class Render {
* @Desc: 检索某个节点在激活列表里的索引 * @Desc: 检索某个节点在激活列表里的索引
*/ */
findActiveNodeIndex(node) { findActiveNodeIndex(node) {
return this.activeNodeList.findIndex((item) => { return this.activeNodeList.findIndex(item => {
return item === node return item === node
}) })
} }
@ -345,9 +352,11 @@ class Render {
* @Desc: 获取节点在同级里的索引位置 * @Desc: 获取节点在同级里的索引位置
*/ */
getNodeIndex(node) { getNodeIndex(node) {
return node.parent ? node.parent.children.findIndex((item) => { return node.parent
? node.parent.children.findIndex(item => {
return item === node return item === node
}) : 0 })
: 0
} }
/** /**
@ -356,15 +365,23 @@ class Render {
* @Desc: 全选 * @Desc: 全选
*/ */
selectAll() { selectAll() {
walk(this.root, null, (node) => { walk(
this.root,
null,
node => {
if (!node.nodeData.data.isActive) { if (!node.nodeData.data.isActive) {
node.nodeData.data.isActive = true node.nodeData.data.isActive = true
this.addActiveNode(node) this.addActiveNode(node)
setTimeout(() => { setTimeout(() => {
node.renderNode() node.renderNode()
}, 0); }, 0)
} }
}, null, true, 0, 0) },
null,
true,
0,
0
)
} }
/** /**
@ -415,12 +432,12 @@ class Render {
} }
let index = this.getNodeIndex(first) let index = this.getNodeIndex(first)
first.parent.nodeData.children.splice(index + 1, 0, { first.parent.nodeData.children.splice(index + 1, 0, {
"inserting": true, inserting: true,
"data": { data: {
"text": text, text: text,
"expand": true expand: true
}, },
"children": [] children: []
}) })
this.mindMap.render() this.mindMap.render()
} }
@ -435,18 +452,18 @@ class Render {
if (this.activeNodeList.length <= 0) { if (this.activeNodeList.length <= 0) {
return return
} }
this.activeNodeList.forEach((node, index) => { this.activeNodeList.forEach(node => {
if (!node.nodeData.children) { if (!node.nodeData.children) {
node.nodeData.children = [] node.nodeData.children = []
} }
let text = node.isRoot ? '二级节点' : '分支主题' let text = node.isRoot ? '二级节点' : '分支主题'
node.nodeData.children.push({ node.nodeData.children.push({
"inserting": true, inserting: true,
"data": { data: {
"text": text, text: text,
"expand": true expand: true
}, },
"children": [] children: []
}) })
// 插入子节点时自动展开子节点 // 插入子节点时自动展开子节点
node.nodeData.data.expand = true node.nodeData.data.expand = true
@ -475,7 +492,7 @@ class Render {
} }
let parent = node.parent let parent = node.parent
let childList = parent.children let childList = parent.children
let index = childList.findIndex((item) => { let index = childList.findIndex(item => {
return item === node return item === node
}) })
if (index === -1 || index === 0) { if (index === -1 || index === 0) {
@ -506,7 +523,7 @@ class Render {
} }
let parent = node.parent let parent = node.parent
let childList = parent.children let childList = parent.children
let index = childList.findIndex((item) => { let index = childList.findIndex(item => {
return item === node return item === node
}) })
if (index === -1 || index === childList.length - 1) { if (index === -1 || index === childList.length - 1) {
@ -535,14 +552,14 @@ class Render {
let parent = node.parent let parent = node.parent
let childList = parent.children let childList = parent.children
// 要移动节点的索引 // 要移动节点的索引
let index = childList.findIndex((item) => { let index = childList.findIndex(item => {
return item === node return item === node
}) })
if (index === -1) { if (index === -1) {
return return
} }
// 目标节点的索引 // 目标节点的索引
let existIndex = childList.findIndex((item) => { let existIndex = childList.findIndex(item => {
return item === exist return item === exist
}) })
if (existIndex === -1) { if (existIndex === -1) {
@ -551,8 +568,6 @@ class Render {
// 当前节点在目标节点前面 // 当前节点在目标节点前面
if (index < existIndex) { if (index < existIndex) {
existIndex = existIndex - 1 existIndex = existIndex - 1
} else {
existIndex = existIndex
} }
// 节点实例 // 节点实例
childList.splice(index, 1) childList.splice(index, 1)
@ -576,14 +591,14 @@ class Render {
let parent = node.parent let parent = node.parent
let childList = parent.children let childList = parent.children
// 要移动节点的索引 // 要移动节点的索引
let index = childList.findIndex((item) => { let index = childList.findIndex(item => {
return item === node return item === node
}) })
if (index === -1) { if (index === -1) {
return return
} }
// 目标节点的索引 // 目标节点的索引
let existIndex = childList.findIndex((item) => { let existIndex = childList.findIndex(item => {
return item === exist return item === exist
}) })
if (existIndex === -1) { if (existIndex === -1) {
@ -591,7 +606,7 @@ class Render {
} }
// 当前节点在目标节点前面 // 当前节点在目标节点前面
if (index < existIndex) { if (index < existIndex) {
existIndex = existIndex // do nothing
} else { } else {
existIndex = existIndex + 1 existIndex = existIndex + 1
} }
@ -624,7 +639,7 @@ class Render {
this.removeActiveNode(node) this.removeActiveNode(node)
i-- i--
} else if (node.isRoot) { } else if (node.isRoot) {
node.children.forEach((child) => { node.children.forEach(child => {
child.remove() child.remove()
}) })
node.children = [] node.children = []
@ -715,7 +730,7 @@ class Render {
if (this.activeNodeList.length <= 0) { if (this.activeNodeList.length <= 0) {
return return
} }
this.activeNodeList.forEach((item) => { this.activeNodeList.forEach(item => {
item.nodeData.children.push(simpleDeepClone(data)) item.nodeData.children.push(simpleDeepClone(data))
}) })
this.mindMap.render() this.mindMap.render()
@ -743,7 +758,7 @@ class Render {
this.setNodeDataRender(node, data) this.setNodeDataRender(node, data)
// 更新了连线的样式 // 更新了连线的样式
if (lineStyleProps.includes(prop)) { if (lineStyleProps.includes(prop)) {
(node.parent || node).renderLine(true) ;(node.parent || node).renderLine(true)
} }
} }
@ -768,14 +783,16 @@ class Render {
this.setNodeData(node, { this.setNodeData(node, {
expand expand
}) })
if (expand) { // 展开 if (expand) {
node.children.forEach((item) => { // 展开
node.children.forEach(item => {
item.render() item.render()
}) })
node.renderLine() node.renderLine()
node.updateExpandBtnNode() node.updateExpandBtnNode()
} else { // 收缩 } else {
node.children.forEach((item) => { // 收缩
node.children.forEach(item => {
item.remove() item.remove()
}) })
node.removeLine() node.removeLine()
@ -790,11 +807,19 @@ class Render {
* @Desc: 展开所有 * @Desc: 展开所有
*/ */
expandAllNode() { expandAllNode() {
walk(this.renderTree, null, (node) => { walk(
this.renderTree,
null,
node => {
if (!node.data.expand) { if (!node.data.expand) {
node.data.expand = true node.data.expand = true
} }
}, null, true, 0, 0) },
null,
true,
0,
0
)
this.mindMap.reRender() this.mindMap.reRender()
} }
@ -804,12 +829,20 @@ class Render {
* @Desc: 收起所有 * @Desc: 收起所有
*/ */
unexpandAllNode() { unexpandAllNode() {
walk(this.renderTree, null, (node, parent, isRoot) => { walk(
this.renderTree,
null,
(node, parent, isRoot) => {
node._node = null node._node = null
if (!isRoot) { if (!isRoot) {
node.data.expand = false node.data.expand = false
} }
}, null, true, 0, 0) },
null,
true,
0,
0
)
this.mindMap.reRender() this.mindMap.reRender()
} }
@ -820,10 +853,18 @@ class Render {
* @Desc: 展开到指定层级 * @Desc: 展开到指定层级
*/ */
expandToLevel(level) { expandToLevel(level) {
walk(this.renderTree, null, (node, parent, isRoot, layerIndex) => { walk(
this.renderTree,
null,
(node, parent, isRoot, layerIndex) => {
node._node = null node._node = null
node.data.expand = layerIndex < level node.data.expand = layerIndex < level
}, null, true, 0, 0) },
null,
true,
0,
0
)
this.mindMap.reRender() this.mindMap.reRender()
} }
@ -833,7 +874,7 @@ class Render {
* @Desc: 切换激活节点的展开状态 * @Desc: 切换激活节点的展开状态
*/ */
toggleActiveExpand() { toggleActiveExpand() {
this.activeNodeList.forEach((node) => { this.activeNodeList.forEach(node => {
if (node.nodeData.children.length <= 0) { if (node.nodeData.children.length <= 0) {
return return
} }
@ -847,7 +888,11 @@ class Render {
* @Desc: 切换节点展开状态 * @Desc: 切换节点展开状态
*/ */
toggleNodeExpand(node) { toggleNodeExpand(node) {
this.mindMap.execCommand('SET_NODE_EXPAND', node, !node.nodeData.data.expand) this.mindMap.execCommand(
'SET_NODE_EXPAND',
node,
!node.nodeData.data.expand
)
} }
/** /**
@ -866,19 +911,14 @@ class Render {
* @Date: 2021-07-10 08:37:40 * @Date: 2021-07-10 08:37:40
* @Desc: 设置节点图片 * @Desc: 设置节点图片
*/ */
setNodeImage(node, { setNodeImage(node, { url, title, width, height }) {
url,
title,
width,
height
}) {
this.setNodeDataRender(node, { this.setNodeDataRender(node, {
image: url, image: url,
imageTitle: title || '', imageTitle: title || '',
imageSize: { imageSize: {
width, width,
height, height
}, }
}) })
} }
@ -901,7 +941,7 @@ class Render {
setNodeHyperlink(node, link, title = '') { setNodeHyperlink(node, link, title = '') {
this.setNodeDataRender(node, { this.setNodeDataRender(node, {
hyperlink: link, hyperlink: link,
hyperlinkTitle: title, hyperlinkTitle: title
}) })
} }
@ -936,7 +976,7 @@ class Render {
if (this.activeNodeList.length <= 0) { if (this.activeNodeList.length <= 0) {
return return
} }
this.activeNodeList.forEach((node) => { this.activeNodeList.forEach(node => {
if (node.nodeData.data.generalization || node.isRoot) { if (node.nodeData.data.generalization || node.isRoot) {
return return
} }
@ -959,7 +999,7 @@ class Render {
if (this.activeNodeList.length <= 0) { if (this.activeNodeList.length <= 0) {
return return
} }
this.activeNodeList.forEach((node) => { this.activeNodeList.forEach(node => {
if (!node.nodeData.data.generalization) { if (!node.nodeData.data.generalization) {
return return
} }
@ -979,7 +1019,7 @@ class Render {
*/ */
setNodeCustomPosition(node, left = undefined, top = undefined) { setNodeCustomPosition(node, left = undefined, top = undefined) {
let nodeList = [node] || this.activeNodeList let nodeList = [node] || this.activeNodeList
nodeList.forEach((item) => { nodeList.forEach(item => {
this.setNodeData(item, { this.setNodeData(item, {
customLeft: left, customLeft: left,
customTop: top customTop: top
@ -994,7 +1034,10 @@ class Render {
* @Desc: 一键整理布局即去除自定义位置 * @Desc: 一键整理布局即去除自定义位置
*/ */
resetLayout() { resetLayout() {
walk(this.root, null, (node) => { walk(
this.root,
null,
node => {
node.customLeft = undefined node.customLeft = undefined
node.customTop = undefined node.customTop = undefined
this.setNodeData(node, { this.setNodeData(node, {
@ -1002,7 +1045,12 @@ class Render {
customTop: undefined customTop: undefined
}) })
this.mindMap.render() this.mindMap.render()
}, null, true, 0, 0) },
null,
true,
0,
0
)
} }
/** /**
@ -1016,7 +1064,7 @@ class Render {
return return
} }
let nodeList = [node] || this.activeNodeList let nodeList = [node] || this.activeNodeList
nodeList.forEach((item) => { nodeList.forEach(item => {
this.setNodeStyle(item, 'shape', shape) this.setNodeStyle(item, 'shape', shape)
}) })
} }
@ -1027,7 +1075,7 @@ class Render {
* @Desc: 更新节点数据 * @Desc: 更新节点数据
*/ */
setNodeData(node, data) { setNodeData(node, data) {
Object.keys(data).forEach((key) => { Object.keys(data).forEach(key => {
node.nodeData.data[key] = data[key] node.nodeData.data[key] = data[key]
}) })
} }

View File

@ -30,7 +30,7 @@ class Select {
*/ */
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 => {
if (this.mindMap.opt.readonly) { if (this.mindMap.opt.readonly) {
return return
} }
@ -43,7 +43,7 @@ class Select {
this.mouseDownY = y this.mouseDownY = y
this.createRect(x, y) this.createRect(x, y)
}) })
this.mindMap.on('mousemove', (e) => { this.mindMap.on('mousemove', e => {
if (this.mindMap.opt.readonly) { if (this.mindMap.opt.readonly) {
return return
} }
@ -53,20 +53,27 @@ class Select {
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY) let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
this.mouseMoveX = x this.mouseMoveX = x
this.mouseMoveY = y this.mouseMoveY = y
if (Math.abs(x - this.mouseDownX) <= 10 && Math.abs(y - this.mouseDownY) <= 10) { if (
Math.abs(x - this.mouseDownX) <= 10 &&
Math.abs(y - this.mouseDownY) <= 10
) {
return return
} }
clearTimeout(this.autoMoveTimer) clearTimeout(this.autoMoveTimer)
this.onMove(x, y) this.onMove(x, y)
}) })
this.mindMap.on('mouseup', (e) => { this.mindMap.on('mouseup', () => {
if (this.mindMap.opt.readonly) { if (this.mindMap.opt.readonly) {
return return
} }
if (!this.isMousedown) { if (!this.isMousedown) {
return; return
} }
this.mindMap.emit('node_active', null, this.mindMap.renderer.activeNodeList) this.mindMap.emit(
'node_active',
null,
this.mindMap.renderer.activeNodeList
)
clearTimeout(this.autoMoveTimer) clearTimeout(this.autoMoveTimer)
this.isMousedown = false this.isMousedown = false
if (this.rect) this.rect.remove() if (this.rect) this.rect.remove()
@ -129,7 +136,7 @@ class Select {
startAutoMove(x, y) { startAutoMove(x, y) {
this.autoMoveTimer = setTimeout(() => { this.autoMoveTimer = setTimeout(() => {
this.onMove(x, y) this.onMove(x, y)
}, 20); }, 20)
} }
/** /**
@ -138,11 +145,15 @@ class Select {
* @Desc: 创建矩形 * @Desc: 创建矩形
*/ */
createRect(x, y) { createRect(x, y) {
this.rect = this.mindMap.svg.polygon().stroke({ this.rect = this.mindMap.svg
.polygon()
.stroke({
color: '#0984e3' color: '#0984e3'
}).fill({ })
.fill({
color: 'rgba(9,132,227,0.3)' color: 'rgba(9,132,227,0.3)'
}).plot([[x, y]]) })
.plot([[x, y]])
} }
/** /**
@ -151,26 +162,22 @@ class Select {
* @Desc: 检测在选区里的节点 * @Desc: 检测在选区里的节点
*/ */
checkInNodes() { checkInNodes() {
let { scaleX, scaleY, translateX, translateY } = this.mindMap.draw.transform() let { scaleX, scaleY, translateX, translateY } =
this.mindMap.draw.transform()
let minx = Math.min(this.mouseDownX, this.mouseMoveX) let minx = Math.min(this.mouseDownX, this.mouseMoveX)
let miny = Math.min(this.mouseDownY, this.mouseMoveY) let miny = Math.min(this.mouseDownY, this.mouseMoveY)
let maxx = Math.max(this.mouseDownX, this.mouseMoveX) let maxx = Math.max(this.mouseDownX, this.mouseMoveX)
let maxy = Math.max(this.mouseDownY, this.mouseMoveY) let maxy = Math.max(this.mouseDownY, this.mouseMoveY)
bfsWalk(this.mindMap.renderer.root, (node) => { bfsWalk(this.mindMap.renderer.root, node => {
let { left, top, width, height } = node let { left, top, width, height } = node
let right = (left + width) * scaleX + translateX let right = (left + width) * scaleX + translateX
let bottom = (top + height) * scaleY + translateY let bottom = (top + height) * scaleY + translateY
left = left * scaleX + translateX left = left * scaleX + translateX
top = top * scaleY + translateY top = top * scaleY + translateY
if ( if (left >= minx && right <= maxx && top >= miny && bottom <= maxy) {
left >= minx &&
right <= maxx &&
top >= miny &&
bottom <= maxy
) {
this.mindMap.batchExecution.push('activeNode' + node.uid, () => { this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
if (node.nodeData.data.isActive) { if (node.nodeData.data.isActive) {
return ; return
} }
this.mindMap.renderer.setNodeActive(node, true) this.mindMap.renderer.setNodeActive(node, true)
this.mindMap.renderer.addActiveNode(node) this.mindMap.renderer.addActiveNode(node)
@ -178,7 +185,7 @@ class Select {
} else if (node.nodeData.data.isActive) { } else if (node.nodeData.data.isActive) {
this.mindMap.batchExecution.push('activeNode' + node.uid, () => { this.mindMap.batchExecution.push('activeNode' + node.uid, () => {
if (!node.nodeData.data.isActive) { if (!node.nodeData.data.isActive) {
return ; return
} }
this.mindMap.renderer.setNodeActive(node, false) this.mindMap.renderer.setNodeActive(node, false)
this.mindMap.renderer.removeActiveNode(node) this.mindMap.renderer.removeActiveNode(node)

View File

@ -54,7 +54,7 @@
case 'circle': case 'circle':
return { return {
paddingX: actHeight > actWidth ? actOffset / 2 : 0, paddingX: actHeight > actWidth ? actOffset / 2 : 0,
paddingY: actHeight < actWidth ? actOffset / 2 : 0, paddingY: actHeight < actWidth ? actOffset / 2 : 0
} }
default: default:
return { return {
@ -262,4 +262,14 @@
} }
// 形状列表 // 形状列表
export const shapeList = ['rectangle', 'diamond', 'parallelogram', 'roundedRectangle', 'octagonalRectangle', 'outerTriangularRectangle', 'innerTriangularRectangle', 'ellipse', 'circle'] export const shapeList = [
'rectangle',
'diamond',
'parallelogram',
'roundedRectangle',
'octagonalRectangle',
'outerTriangularRectangle',
'innerTriangularRectangle',
'ellipse',
'circle'
]

View File

@ -1,4 +1,4 @@
import { tagColorList } from './utils/constant'; import { tagColorList } from './utils/constant'
const rootProp = ['paddingX', 'paddingY'] const rootProp = ['paddingX', 'paddingY']
/** /**
@ -48,25 +48,34 @@ class Style {
merge(prop, root, isActive) { merge(prop, root, isActive) {
// 三级及以下节点 // 三级及以下节点
let defaultConfig = this.themeConfig.node let defaultConfig = this.themeConfig.node
if (root || rootProp.includes(prop)) {// 直接使用最外层样式 if (root || rootProp.includes(prop)) {
// 直接使用最外层样式
defaultConfig = this.themeConfig defaultConfig = this.themeConfig
} else if (this.ctx.isGeneralization) {// 概要节点 } else if (this.ctx.isGeneralization) {
// 概要节点
defaultConfig = this.themeConfig.generalization defaultConfig = this.themeConfig.generalization
} else if (this.ctx.layerIndex === 0) {// 根节点 } else if (this.ctx.layerIndex === 0) {
// 根节点
defaultConfig = this.themeConfig.root defaultConfig = this.themeConfig.root
} else if (this.ctx.layerIndex === 1) {// 二级节点 } else if (this.ctx.layerIndex === 1) {
// 二级节点
defaultConfig = this.themeConfig.second defaultConfig = this.themeConfig.second
} }
// 激活状态 // 激活状态
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) { if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
if (this.ctx.nodeData.data.activeStyle && this.ctx.nodeData.data.activeStyle[prop] !== undefined) { if (
return this.ctx.nodeData.data.activeStyle[prop]; this.ctx.nodeData.data.activeStyle &&
this.ctx.nodeData.data.activeStyle[prop] !== undefined
) {
return this.ctx.nodeData.data.activeStyle[prop]
} else if (defaultConfig.active && defaultConfig.active[prop]) { } else if (defaultConfig.active && defaultConfig.active[prop]) {
return defaultConfig.active[prop] return defaultConfig.active[prop]
} }
} }
// 优先使用节点本身的样式 // 优先使用节点本身的样式
return this.getSelfStyle(prop) !== undefined ? this.getSelfStyle(prop) : defaultConfig[prop] return this.getSelfStyle(prop) !== undefined
? this.getSelfStyle(prop)
: defaultConfig[prop]
} }
/** /**
@ -106,9 +115,11 @@ class Style {
* @Desc: 矩形外的其他形状 * @Desc: 矩形外的其他形状
*/ */
shape(node) { shape(node) {
node.fill({ node
.fill({
color: this.merge('fillColor') color: this.merge('fillColor')
}).stroke({ })
.stroke({
color: this.merge('borderColor'), color: this.merge('borderColor'),
width: this.merge('borderWidth'), width: this.merge('borderWidth'),
dasharray: this.merge('borderDasharray') dasharray: this.merge('borderDasharray')
@ -121,9 +132,11 @@ class Style {
* @Desc: 文字 * @Desc: 文字
*/ */
text(node) { text(node) {
node.fill({ node
.fill({
color: this.merge('color') color: this.merge('color')
}).css({ })
.css({
'font-family': this.merge('fontFamily'), 'font-family': this.merge('fontFamily'),
'font-size': this.merge('fontSize'), 'font-size': this.merge('fontSize'),
'font-weight': this.merge('fontWeight'), 'font-weight': this.merge('fontWeight'),
@ -149,9 +162,11 @@ class Style {
* @Desc: 标签文字 * @Desc: 标签文字
*/ */
tagText(node, index) { tagText(node, index) {
node.fill({ node
.fill({
color: tagColorList[index].color color: tagColorList[index].color
}).css({ })
.css({
'font-size': '12px' 'font-size': '12px'
}) })
} }
@ -193,7 +208,12 @@ class Style {
* @Desc: 概要连线 * @Desc: 概要连线
*/ */
generalizationLine(node) { generalizationLine(node) {
node.stroke({ width: this.merge('generalizationLineWidth', true), color: this.merge('generalizationLineColor', true) }).fill({ color: 'none' }) node
.stroke({
width: this.merge('generalizationLineWidth', true),
color: this.merge('generalizationLineColor', true)
})
.fill({ color: 'none' })
} }
/** /**

View File

@ -1,6 +1,4 @@
import { import { getStrWithBrFromHtml } from './utils'
getStrWithBrFromHtml
} from './utils'
/** /**
* javascript comment * javascript comment
@ -93,7 +91,9 @@ export default class TextEdit {
document.body.appendChild(this.textEditNode) document.body.appendChild(this.textEditNode)
} }
node.style.domText(this.textEditNode, this.mindMap.view.scale) node.style.domText(this.textEditNode, this.mindMap.view.scale)
this.textEditNode.innerHTML = node.nodeData.data.text.split(/\n/img).join('<br>') this.textEditNode.innerHTML = node.nodeData.data.text
.split(/\n/gim)
.join('<br>')
this.textEditNode.style.minWidth = rect.width + 10 + 'px' this.textEditNode.style.minWidth = rect.width + 10 + 'px'
this.textEditNode.style.minHeight = rect.height + 6 + 'px' this.textEditNode.style.minHeight = rect.height + 6 + 'px'
this.textEditNode.style.left = rect.left + 'px' this.textEditNode.style.left = rect.left + 'px'
@ -126,7 +126,7 @@ export default class TextEdit {
if (!this.showTextEdit) { if (!this.showTextEdit) {
return return
} }
this.renderer.activeNodeList.forEach((node) => { this.renderer.activeNodeList.forEach(node => {
let str = getStrWithBrFromHtml(this.textEditNode.innerHTML) let str = getStrWithBrFromHtml(this.textEditNode.innerHTML)
this.mindMap.execCommand('SET_NODE_TEXT', node, str) this.mindMap.execCommand('SET_NODE_TEXT', node, str)
if (node.isGeneralization) { if (node.isGeneralization) {
@ -135,7 +135,11 @@ export default class TextEdit {
} }
this.mindMap.render() this.mindMap.render()
}) })
this.mindMap.emit('hide_text_edit', this.textEditNode, this.renderer.activeNodeList) this.mindMap.emit(
'hide_text_edit',
this.textEditNode,
this.renderer.activeNodeList
)
this.textEditNode.style.display = 'none' this.textEditNode.style.display = 'none'
this.textEditNode.innerHTML = '' this.textEditNode.innerHTML = ''
this.textEditNode.style.fontFamily = 'inherit' this.textEditNode.style.fontFamily = 'inherit'

View File

@ -73,7 +73,8 @@ class View {
// // 放大 // // 放大
if (dir === 'down') { if (dir === 'down') {
this.enlarge() this.enlarge()
} else { // 缩小 } else {
// 缩小
this.narrow() this.narrow()
} }
}) })
@ -106,7 +107,7 @@ class View {
*/ */
setTransformData(viewData) { setTransformData(viewData) {
if (viewData) { if (viewData) {
Object.keys(viewData.state).forEach((prop) => { Object.keys(viewData.state).forEach(prop => {
this[prop] = viewData.state[prop] this[prop] = viewData.state[prop]
}) })
this.mindMap.draw.transform({ this.mindMap.draw.transform({
@ -170,7 +171,7 @@ class View {
this.mindMap.draw.transform({ this.mindMap.draw.transform({
scale: this.scale, scale: this.scale,
// origin: 'center center', // origin: 'center center',
translate: [this.x, this.y], translate: [this.x, this.y]
}) })
this.mindMap.emit('view_data_change', this.getTransformData()) this.mindMap.emit('view_data_change', this.getTransformData())
} }

View File

@ -1,7 +1,4 @@
import Node from '../Node' import Node from '../Node'
import {
walk,
} from '../utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -72,7 +69,8 @@ class Base {
newNode = data._node newNode = data._node
newNode.reset() newNode.reset()
newNode.layerIndex = layerIndex newNode.layerIndex = layerIndex
} else {// 创建新节点 } else {
// 创建新节点
newNode = new Node({ newNode = new Node({
data, data,
uid: this.mindMap.uid++, uid: this.mindMap.uid++,
@ -97,7 +95,7 @@ class Base {
newNode.parent = parent._node newNode.parent = parent._node
parent._node.addChildren(newNode) parent._node.addChildren(newNode)
} }
return newNode; return newNode
} }
/** /**
@ -117,9 +115,10 @@ class Base {
* @Desc: 更新子节点属性 * @Desc: 更新子节点属性
*/ */
updateChildren(children, prop, offset) { updateChildren(children, prop, offset) {
children.forEach((item) => { children.forEach(item => {
item[prop] += offset item[prop] += offset
if (item.children && item.children.length && !item.hasCustomPosition()) {// 适配自定义位置 if (item.children && item.children.length && !item.hasCustomPosition()) {
// 适配自定义位置
this.updateChildren(item.children, prop, offset) this.updateChildren(item.children, prop, offset)
} }
}) })
@ -155,7 +154,9 @@ class Base {
* @Desc: 获取节点的marginX * @Desc: 获取节点的marginX
*/ */
getMarginX(layerIndex) { getMarginX(layerIndex) {
return layerIndex === 1 ? this.mindMap.themeConfig.second.marginX : this.mindMap.themeConfig.node.marginX; return layerIndex === 1
? this.mindMap.themeConfig.second.marginX
: this.mindMap.themeConfig.node.marginX
} }
/** /**
@ -164,7 +165,9 @@ class Base {
* @Desc: 获取节点的marginY * @Desc: 获取节点的marginY
*/ */
getMarginY(layerIndex) { getMarginY(layerIndex) {
return layerIndex === 1 ? this.mindMap.themeConfig.second.marginY : this.mindMap.themeConfig.node.marginY; return layerIndex === 1
? this.mindMap.themeConfig.second.marginY
: this.mindMap.themeConfig.node.marginY
} }
/** /**
@ -173,7 +176,10 @@ class Base {
* @Desc: 获取节点包括概要在内的宽度 * @Desc: 获取节点包括概要在内的宽度
*/ */
getNodeWidthWithGeneralization(node) { getNodeWidthWithGeneralization(node) {
return Math.max(node.width, node.checkHasGeneralization() ? node._generalizationNodeWidth : 0) return Math.max(
node.width,
node.checkHasGeneralization() ? node._generalizationNodeWidth : 0
)
} }
/** /**
@ -182,7 +188,10 @@ class Base {
* @Desc: 获取节点包括概要在内的高度 * @Desc: 获取节点包括概要在内的高度
*/ */
getNodeHeightWithGeneralization(node) { getNodeHeightWithGeneralization(node) {
return Math.max(node.height, node.checkHasGeneralization() ? node._generalizationNodeHeight : 0) return Math.max(
node.height,
node.checkHasGeneralization() ? node._generalizationNodeHeight : 0
)
} }
/** /**
@ -192,20 +201,27 @@ class Base {
* dir生长方向h水平v垂直 * dir生长方向h水平v垂直
* isLeft是否向左生长 * isLeft是否向左生长
*/ */
getNodeBoundaries(node, dir, isLeft) { getNodeBoundaries(node, dir) {
let { generalizationLineMargin, generalizationNodeMargin } = this.mindMap.themeConfig let { generalizationLineMargin, generalizationNodeMargin } =
let walk = (root) => { this.mindMap.themeConfig
let walk = root => {
let _left = Infinity let _left = Infinity
let _right = -Infinity let _right = -Infinity
let _top = Infinity let _top = Infinity
let _bottom = -Infinity let _bottom = -Infinity
if (root.children && root.children.length > 0) { if (root.children && root.children.length > 0) {
root.children.forEach((child) => { root.children.forEach(child => {
let { left, right, top, bottom } = walk(child) let { left, right, top, bottom } = walk(child)
// 概要内容的宽度 // 概要内容的宽度
let generalizationWidth = child.checkHasGeneralization() && child.nodeData.data.expand ? child._generalizationNodeWidth + generalizationNodeMargin : 0 let generalizationWidth =
child.checkHasGeneralization() && child.nodeData.data.expand
? child._generalizationNodeWidth + generalizationNodeMargin
: 0
// 概要内容的高度 // 概要内容的高度
let generalizationHeight = child.checkHasGeneralization() && child.nodeData.data.expand ? child._generalizationNodeHeight + generalizationNodeMargin : 0 let generalizationHeight =
child.checkHasGeneralization() && child.nodeData.data.expand
? child._generalizationNodeHeight + generalizationNodeMargin
: 0
if (left - (dir === 'h' ? generalizationWidth : 0) < _left) { if (left - (dir === 'h' ? generalizationWidth : 0) < _left) {
_left = left - (dir === 'h' ? generalizationWidth : 0) _left = left - (dir === 'h' ? generalizationWidth : 0)
} }
@ -241,7 +257,7 @@ class Base {
bottom, bottom,
generalizationLineMargin, generalizationLineMargin,
generalizationNodeMargin generalizationNodeMargin
}; }
} }
} }

View File

@ -1,8 +1,5 @@
import Base from './Base'; import Base from './Base'
import { import { walk, asyncRun } from '../utils'
walk,
asyncRun
} from '../utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -26,15 +23,20 @@ class CatalogOrganization extends Base {
* @Desc: 布局 * @Desc: 布局
*/ */
doLayout(callback) { doLayout(callback) {
let task = [() => { let task = [
() => {
this.computedBaseValue() this.computedBaseValue()
}, () => { },
() => {
this.computedLeftTopValue() this.computedLeftTopValue()
}, () => { },
() => {
this.adjustLeftTopValue() this.adjustLeftTopValue()
}, () => { },
() => {
callback(this.root) callback(this.root)
}] }
]
asyncRun(task) asyncRun(task)
} }
@ -45,7 +47,10 @@ class CatalogOrganization extends Base {
* @Desc: 遍历数据计算节点的leftwidthheight * @Desc: 遍历数据计算节点的leftwidthheight
*/ */
computedBaseValue() { computedBaseValue() {
walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex) => { walk(
this.renderer.renderTree,
null,
(cur, parent, isRoot, layerIndex) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex) let newNode = this.createNode(cur, parent, isRoot, layerIndex)
// 根节点定位在画布中心位置 // 根节点定位在画布中心位置
if (isRoot) { if (isRoot) {
@ -53,20 +58,30 @@ class CatalogOrganization extends Base {
} else { } else {
// 非根节点 // 非根节点
if (parent._node.isRoot) { if (parent._node.isRoot) {
newNode.top = parent._node.top + parent._node.height + this.getMarginX(layerIndex) newNode.top =
parent._node.top +
parent._node.height +
this.getMarginX(layerIndex)
} }
} }
if (!cur.data.expand) { if (!cur.data.expand) {
return true; return true
} }
}, (cur, parent, isRoot, layerIndex) => { },
(cur, parent, isRoot, layerIndex) => {
if (isRoot) { if (isRoot) {
let len = cur.data.expand === false ? 0 : cur._node.children.length let len = cur.data.expand === false ? 0 : cur._node.children.length
cur._node.childrenAreaWidth = len ? cur._node.children.reduce((h, item) => { cur._node.childrenAreaWidth = len
? cur._node.children.reduce((h, item) => {
return h + item.width return h + item.width
}, 0) + (len + 1) * this.getMarginX(layerIndex + 1) : 0 }, 0) +
(len + 1) * this.getMarginX(layerIndex + 1)
: 0
} }
}, true, 0) },
true,
0
)
} }
/** /**
@ -76,27 +91,37 @@ class CatalogOrganization extends Base {
* @Desc: 遍历节点树计算节点的lefttop * @Desc: 遍历节点树计算节点的lefttop
*/ */
computedLeftTopValue() { computedLeftTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
if (node.nodeData.data.expand && node.children && node.children.length) { this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.nodeData.data.expand &&
node.children &&
node.children.length
) {
let marginX = this.getMarginX(layerIndex + 1) let marginX = this.getMarginX(layerIndex + 1)
let marginY = this.getMarginY(layerIndex + 1) let marginY = this.getMarginY(layerIndex + 1)
if (isRoot) { if (isRoot) {
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
let totalLeft = left + marginX let totalLeft = left + marginX
node.children.forEach((cur) => { node.children.forEach(cur => {
cur.left = totalLeft cur.left = totalLeft
totalLeft += cur.width + marginX totalLeft += cur.width + marginX
}) })
} else { } else {
let totalTop = node.top + node.height + marginY + node.expandBtnSize let totalTop = node.top + node.height + marginY + node.expandBtnSize
node.children.forEach((cur) => { node.children.forEach(cur => {
cur.left = node.left + node.width * 0.5 cur.left = node.left + node.width * 0.5
cur.top = totalTop cur.top = totalTop
totalTop += cur.height + marginY + node.expandBtnSize totalTop += cur.height + marginY + node.expandBtnSize
}) })
} }
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -106,9 +131,12 @@ class CatalogOrganization extends Base {
* @Desc: 调整节点lefttop * @Desc: 调整节点lefttop
*/ */
adjustLeftTopValue() { adjustLeftTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (!node.nodeData.data.expand) { if (!node.nodeData.data.expand) {
return; return
} }
// 调整left // 调整left
if (parent && parent.isRoot) { if (parent && parent.isRoot) {
@ -122,12 +150,18 @@ class CatalogOrganization extends Base {
let len = node.children.length let len = node.children.length
if (parent && !parent.isRoot && len > 0) { if (parent && !parent.isRoot && len > 0) {
let marginY = this.getMarginY(layerIndex + 1) let marginY = this.getMarginY(layerIndex + 1)
let totalHeight = node.children.reduce((h, item) => { let totalHeight =
node.children.reduce((h, item) => {
return h + item.height return h + item.height
}, 0) + (len + 1) * marginY + len * node.expandBtnSize }, 0) +
(len + 1) * marginY +
len * node.expandBtnSize
this.updateBrothersTop(node, totalHeight) this.updateBrothersTop(node, totalHeight)
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -141,7 +175,7 @@ class CatalogOrganization extends Base {
let loop = (node, width) => { let loop = (node, width) => {
if (node.children.length) { if (node.children.length) {
width += node.width / 2 width += node.width / 2
node.children.forEach((item) => { node.children.forEach(item => {
loop(item, width) loop(item, width)
}) })
} else { } else {
@ -162,25 +196,35 @@ class CatalogOrganization extends Base {
updateBrothersLeft(node, addWidth) { updateBrothersLeft(node, addWidth) {
if (node.parent) { if (node.parent) {
let childrenList = node.parent.children let childrenList = node.parent.children
let index = childrenList.findIndex((item) => { let index = childrenList.findIndex(item => {
return item === node return item === node
}) })
// 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称 // 存在大于一个节点时,第一个或最后一个节点自身也需要移动,否则两边不对称
if ((index === 0 || index === childrenList.length - 1) && childrenList.length > 1) { if (
(index === 0 || index === childrenList.length - 1) &&
childrenList.length > 1
) {
let _offset = index === 0 ? -addWidth : addWidth let _offset = index === 0 ? -addWidth : addWidth
node.left += _offset node.left += _offset
if (node.children && node.children.length && !node.hasCustomPosition()) { if (
node.children &&
node.children.length &&
!node.hasCustomPosition()
) {
this.updateChildren(node.children, 'left', _offset) this.updateChildren(node.children, 'left', _offset)
} }
} }
childrenList.forEach((item, _index) => { childrenList.forEach((item, _index) => {
if (item.hasCustomPosition()) {// 适配自定义位置 if (item.hasCustomPosition()) {
// 适配自定义位置
return return
} }
let _offset = 0 let _offset = 0
if (_index < index) { // 左边的节点往左移 if (_index < index) {
// 左边的节点往左移
_offset = -addWidth _offset = -addWidth
} else if (_index > index) { // 右边的节点往右移 } else if (_index > index) {
// 右边的节点往右移
_offset = addWidth _offset = addWidth
} }
item.left += _offset item.left += _offset
@ -203,11 +247,12 @@ class CatalogOrganization extends Base {
updateBrothersTop(node, addHeight) { updateBrothersTop(node, addHeight) {
if (node.parent && !node.parent.isRoot) { if (node.parent && !node.parent.isRoot) {
let childrenList = node.parent.children let childrenList = node.parent.children
let index = childrenList.findIndex((item) => { let index = childrenList.findIndex(item => {
return item === node return item === node
}) })
childrenList.forEach((item, _index) => { childrenList.forEach((item, _index) => {
if (item.hasCustomPosition()) {// 适配自定义位置 if (item.hasCustomPosition()) {
// 适配自定义位置
return return
} }
let _offset = 0 let _offset = 0
@ -233,15 +278,9 @@ class CatalogOrganization extends Base {
*/ */
renderLine(node, lines, style) { renderLine(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
let len = node.children.length let len = node.children.length
let marginX = this.getMarginX(node.layerIndex + 1) let marginX = this.getMarginX(node.layerIndex + 1)
if (node.isRoot) { if (node.isRoot) {
@ -260,7 +299,9 @@ class CatalogOrganization extends Base {
if (x2 > maxx) { if (x2 > maxx) {
maxx = x2 maxx = x2
} }
let path = `M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` let path = `M ${x2},${y1 + s1} L ${x2},${
y1 + s1 > y2 ? y2 + item.height : y2
}`
// 竖线 // 竖线
lines[index].plot(path) lines[index].plot(path)
style && style(lines[index], item) style && style(lines[index], item)
@ -308,7 +349,9 @@ class CatalogOrganization extends Base {
} }
if (y2 > top && y2 < y1) { if (y2 > top && y2 < y1) {
// 自定义位置的情况:垂直位置节点在父节点之间 // 自定义位置的情况:垂直位置节点在父节点之间
path = `M ${_isLeft ? node.left : node.left + node.width},${y2} L ${_left},${y2}` path = `M ${
_isLeft ? node.left : node.left + node.width
},${y2} L ${_left},${y2}`
} else if (y2 < y1) { } else if (y2 < y1) {
// 自定义位置的情况:垂直位置节点在父节点上面 // 自定义位置的情况:垂直位置节点在父节点上面
if (_isXCenter) { if (_isXCenter) {
@ -348,18 +391,13 @@ class CatalogOrganization extends Base {
* @Desc: 渲染按钮 * @Desc: 渲染按钮
*/ */
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { let { width, height, expandBtnSize, isRoot } = node
width,
height,
expandBtnSize,
isRoot
} = node
if (!isRoot) { if (!isRoot) {
let { let { translateX, translateY } = btn.transform()
translateX, btn.translate(
translateY width * 0.3 - expandBtnSize / 2 - translateX,
} = btn.transform() height + expandBtnSize / 2 - translateY
btn.translate(width * 0.3 - expandBtnSize / 2 - translateX, height + expandBtnSize / 2 - translateY) )
} }
} }
@ -369,7 +407,13 @@ class CatalogOrganization extends Base {
* @Desc: 创建概要节点 * @Desc: 创建概要节点
*/ */
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let { top, bottom, right, generalizationLineMargin, generalizationNodeMargin } = this.getNodeBoundaries(node, 'h') let {
top,
bottom,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'h')
let x1 = right + generalizationLineMargin let x1 = right + generalizationLineMargin
let y1 = top let y1 = top
let x2 = right + generalizationLineMargin let x2 = right + generalizationLineMargin

View File

@ -1,8 +1,5 @@
import Base from './Base'; import Base from './Base'
import { import { walk, asyncRun } from '../utils'
walk,
asyncRun
} from '../utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -26,15 +23,20 @@ class LogicalStructure extends Base {
* @Desc: 布局 * @Desc: 布局
*/ */
doLayout(callback) { doLayout(callback) {
let task = [() => { let task = [
() => {
this.computedBaseValue() this.computedBaseValue()
}, () => { },
() => {
this.computedTopValue() this.computedTopValue()
}, () => { },
() => {
this.adjustTopValue() this.adjustTopValue()
}, () => { },
() => {
callback(this.root) callback(this.root)
}] }
]
asyncRun(task) asyncRun(task)
} }
@ -45,7 +47,10 @@ class LogicalStructure extends Base {
* @Desc: 遍历数据计算节点的leftwidthheight * @Desc: 遍历数据计算节点的leftwidthheight
*/ */
computedBaseValue() { computedBaseValue() {
walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex) => { walk(
this.renderer.renderTree,
null,
(cur, parent, isRoot, layerIndex) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex) let newNode = this.createNode(cur, parent, isRoot, layerIndex)
// 根节点定位在画布中心位置 // 根节点定位在画布中心位置
if (isRoot) { if (isRoot) {
@ -53,18 +58,26 @@ class LogicalStructure extends Base {
} else { } else {
// 非根节点 // 非根节点
// 定位到父节点右侧 // 定位到父节点右侧
newNode.left = parent._node.left + parent._node.width + this.getMarginX(layerIndex) newNode.left =
parent._node.left + parent._node.width + this.getMarginX(layerIndex)
} }
if (!cur.data.expand) { if (!cur.data.expand) {
return true; return true
} }
}, (cur, parent, isRoot, layerIndex) => { },
(cur, parent, isRoot, layerIndex) => {
// 返回时计算节点的areaHeight也就是子节点所占的高度之和包括外边距 // 返回时计算节点的areaHeight也就是子节点所占的高度之和包括外边距
let len = cur.data.expand === false ? 0 : cur._node.children.length let len = cur.data.expand === false ? 0 : cur._node.children.length
cur._node.childrenAreaHeight = len ? cur._node.children.reduce((h, item) => { cur._node.childrenAreaHeight = len
? cur._node.children.reduce((h, item) => {
return h + item.height return h + item.height
}, 0) + (len + 1) * this.getMarginY(layerIndex + 1) : 0 }, 0) +
}, true, 0) (len + 1) * this.getMarginY(layerIndex + 1)
: 0
},
true,
0
)
} }
/** /**
@ -74,18 +87,28 @@ class LogicalStructure extends Base {
* @Desc: 遍历节点树计算节点的top * @Desc: 遍历节点树计算节点的top
*/ */
computedTopValue() { computedTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
if (node.nodeData.data.expand && node.children && node.children.length) { this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.nodeData.data.expand &&
node.children &&
node.children.length
) {
let marginY = this.getMarginY(layerIndex + 1) let marginY = this.getMarginY(layerIndex + 1)
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
let top = node.top + node.height / 2 - node.childrenAreaHeight / 2 let top = node.top + node.height / 2 - node.childrenAreaHeight / 2
let totalTop = top + marginY let totalTop = top + marginY
node.children.forEach((cur) => { node.children.forEach(cur => {
cur.top = totalTop cur.top = totalTop
totalTop += cur.height + marginY totalTop += cur.height + marginY
}) })
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -95,16 +118,25 @@ class LogicalStructure extends Base {
* @Desc: 调整节点top * @Desc: 调整节点top
*/ */
adjustTopValue() { adjustTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (!node.nodeData.data.expand) { if (!node.nodeData.data.expand) {
return; return
} }
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
let difference = node.childrenAreaHeight - this.getMarginY(layerIndex + 1) * 2 - node.height let difference =
node.childrenAreaHeight -
this.getMarginY(layerIndex + 1) * 2 -
node.height
if (difference > 0) { if (difference > 0) {
this.updateBrothers(node, difference / 2) this.updateBrothers(node, difference / 2)
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -116,18 +148,20 @@ class LogicalStructure extends Base {
updateBrothers(node, addHeight) { updateBrothers(node, addHeight) {
if (node.parent) { if (node.parent) {
let childrenList = node.parent.children let childrenList = node.parent.children
let index = childrenList.findIndex((item) => { let index = childrenList.findIndex(item => {
return item === node return item === node
}) })
childrenList.forEach((item, _index) => { childrenList.forEach((item, _index) => {
if (item === node || item.hasCustomPosition()) {// 适配自定义位置 if (item === node || item.hasCustomPosition()) {
// 适配自定义位置
return return
} }
let _offset = 0 let _offset = 0
// 上面的节点往上移 // 上面的节点往上移
if (_index < index) { if (_index < index) {
_offset = -addHeight _offset = -addHeight
} else if (_index > index) { // 下面的节点往下移 } else if (_index > index) {
// 下面的节点往下移
_offset = addHeight _offset = addHeight
} }
item.top += _offset item.top += _offset
@ -164,23 +198,20 @@ class LogicalStructure extends Base {
*/ */
renderLineStraight(node, lines, style) { renderLineStraight(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
let marginX = this.getMarginX(node.layerIndex + 1) let marginX = this.getMarginX(node.layerIndex + 1)
let s1 = (marginX - expandBtnSize) * 0.6 let s1 = (marginX - expandBtnSize) * 0.6
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width : left + width + expandBtnSize let x1 =
node.layerIndex === 0 ? left + width : left + width + expandBtnSize
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${x2},${y2}` let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${
x1 + s1
},${y2} L ${x2},${y2}`
lines[index].plot(path) lines[index].plot(path)
style && style(lines[index], item) style && style(lines[index], item)
}) })
@ -194,17 +225,12 @@ class LogicalStructure extends Base {
*/ */
renderLineDirect(node, lines, style) { renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize let x1 =
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
@ -222,17 +248,12 @@ class LogicalStructure extends Base {
*/ */
renderLineCurve(node, lines, style) { renderLineCurve(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize let x1 =
node.layerIndex === 0 ? left + width / 2 : left + width + expandBtnSize
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
@ -253,14 +274,8 @@ class LogicalStructure extends Base {
* @Desc: 渲染按钮 * @Desc: 渲染按钮
*/ */
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { let { width, height } = node
width, let { translateX, translateY } = btn.transform()
height
} = node
let {
translateX,
translateY
} = btn.transform()
btn.translate(width - translateX, height / 2 - translateY) btn.translate(width - translateX, height / 2 - translateY)
} }
@ -270,7 +285,13 @@ class LogicalStructure extends Base {
* @Desc: 创建概要节点 * @Desc: 创建概要节点
*/ */
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let { top, bottom, right, generalizationLineMargin, generalizationNodeMargin } = this.getNodeBoundaries(node, 'h') let {
top,
bottom,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'h')
let x1 = right + generalizationLineMargin let x1 = right + generalizationLineMargin
let y1 = top let y1 = top
let x2 = right + generalizationLineMargin let x2 = right + generalizationLineMargin

View File

@ -1,8 +1,5 @@
import Base from './Base'; import Base from './Base'
import { import { walk, asyncRun } from '../utils'
walk,
asyncRun
} from '../utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -27,15 +24,20 @@ class MindMap extends Base {
* @Desc: 布局 * @Desc: 布局
*/ */
doLayout(callback) { doLayout(callback) {
let task = [() => { let task = [
() => {
this.computedBaseValue() this.computedBaseValue()
}, () => { },
() => {
this.computedTopValue() this.computedTopValue()
}, () => { },
() => {
this.adjustTopValue() this.adjustTopValue()
}, () => { },
() => {
callback(this.root) callback(this.root)
}] }
]
asyncRun(task) asyncRun(task)
} }
@ -46,7 +48,10 @@ class MindMap extends Base {
* @Desc: 遍历数据计算节点的leftwidthheight * @Desc: 遍历数据计算节点的leftwidthheight
*/ */
computedBaseValue() { computedBaseValue() {
walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex, index) => { walk(
this.renderer.renderTree,
null,
(cur, parent, isRoot, layerIndex, index) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex) let newNode = this.createNode(cur, parent, isRoot, layerIndex)
// 根节点定位在画布中心位置 // 根节点定位在画布中心位置
if (isRoot) { if (isRoot) {
@ -56,16 +61,23 @@ class MindMap extends Base {
// 三级及以下节点以上级为准 // 三级及以下节点以上级为准
if (parent._node.dir) { if (parent._node.dir) {
newNode.dir = parent._node.dir newNode.dir = parent._node.dir
} else { // 节点生长方向 } else {
// 节点生长方向
newNode.dir = index % 2 === 0 ? 'right' : 'left' newNode.dir = index % 2 === 0 ? 'right' : 'left'
} }
// 根据生长方向定位到父节点的左侧或右侧 // 根据生长方向定位到父节点的左侧或右侧
newNode.left = newNode.dir === 'right' ? parent._node.left + parent._node.width + this.getMarginX(layerIndex) : parent._node.left - this.getMarginX(layerIndex) - newNode.width newNode.left =
newNode.dir === 'right'
? parent._node.left +
parent._node.width +
this.getMarginX(layerIndex)
: parent._node.left - this.getMarginX(layerIndex) - newNode.width
} }
if (!cur.data.expand) { if (!cur.data.expand) {
return true; return true
} }
}, (cur, parent, isRoot, layerIndex) => { },
(cur, parent, isRoot, layerIndex) => {
// 返回时计算节点的leftChildrenAreaHeight和rightChildrenAreaHeight也就是左侧和右侧子节点所占的高度之和包括外边距 // 返回时计算节点的leftChildrenAreaHeight和rightChildrenAreaHeight也就是左侧和右侧子节点所占的高度之和包括外边距
if (!cur.data.expand) { if (!cur.data.expand) {
cur._node.leftChildrenAreaHeight = 0 cur._node.leftChildrenAreaHeight = 0
@ -77,7 +89,7 @@ class MindMap extends Base {
let rightLen = 0 let rightLen = 0
let leftChildrenAreaHeight = 0 let leftChildrenAreaHeight = 0
let rightChildrenAreaHeight = 0 let rightChildrenAreaHeight = 0
cur._node.children.forEach((item) => { cur._node.children.forEach(item => {
if (item.dir === 'left') { if (item.dir === 'left') {
leftLen++ leftLen++
leftChildrenAreaHeight += item.height leftChildrenAreaHeight += item.height
@ -86,9 +98,16 @@ class MindMap extends Base {
rightChildrenAreaHeight += item.height rightChildrenAreaHeight += item.height
} }
}) })
cur._node.leftChildrenAreaHeight = leftChildrenAreaHeight + (leftLen + 1) * this.getMarginY(layerIndex + 1) cur._node.leftChildrenAreaHeight =
cur._node.rightChildrenAreaHeight = rightChildrenAreaHeight + (rightLen + 1) * this.getMarginY(layerIndex + 1) leftChildrenAreaHeight +
}, true, 0) (leftLen + 1) * this.getMarginY(layerIndex + 1)
cur._node.rightChildrenAreaHeight =
rightChildrenAreaHeight +
(rightLen + 1) * this.getMarginY(layerIndex + 1)
},
true,
0
)
} }
/** /**
@ -98,14 +117,21 @@ class MindMap extends Base {
* @Desc: 遍历节点树计算节点的top * @Desc: 遍历节点树计算节点的top
*/ */
computedTopValue() { computedTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
if (node.nodeData.data.expand && node.children && node.children.length) { this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.nodeData.data.expand &&
node.children &&
node.children.length
) {
let marginY = this.getMarginY(layerIndex + 1) let marginY = this.getMarginY(layerIndex + 1)
let baseTop = node.top + node.height / 2 + marginY let baseTop = node.top + node.height / 2 + marginY
// 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半
let leftTotalTop = baseTop - node.leftChildrenAreaHeight / 2 let leftTotalTop = baseTop - node.leftChildrenAreaHeight / 2
let rightTotalTop = baseTop - node.rightChildrenAreaHeight / 2 let rightTotalTop = baseTop - node.rightChildrenAreaHeight / 2
node.children.forEach((cur) => { node.children.forEach(cur => {
if (cur.dir === 'left') { if (cur.dir === 'left') {
cur.top = leftTotalTop cur.top = leftTotalTop
leftTotalTop += cur.height + marginY leftTotalTop += cur.height + marginY
@ -115,7 +141,10 @@ class MindMap extends Base {
} }
}) })
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -125,9 +154,12 @@ class MindMap extends Base {
* @Desc: 调整节点top * @Desc: 调整节点top
*/ */
adjustTopValue() { adjustTopValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (!node.nodeData.data.expand) { if (!node.nodeData.data.expand) {
return; return
} }
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置 // 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
let base = this.getMarginY(layerIndex + 1) * 2 + node.height let base = this.getMarginY(layerIndex + 1) * 2 + node.height
@ -136,7 +168,10 @@ class MindMap extends Base {
if (leftDifference > 0 || rightDifference > 0) { if (leftDifference > 0 || rightDifference > 0) {
this.updateBrothers(node, leftDifference / 2, rightDifference / 2) this.updateBrothers(node, leftDifference / 2, rightDifference / 2)
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -148,14 +183,15 @@ class MindMap extends Base {
updateBrothers(node, leftAddHeight, rightAddHeight) { updateBrothers(node, leftAddHeight, rightAddHeight) {
if (node.parent) { if (node.parent) {
// 过滤出和自己同方向的节点 // 过滤出和自己同方向的节点
let childrenList = node.parent.children.filter((item) => { let childrenList = node.parent.children.filter(item => {
return item.dir === node.dir return item.dir === node.dir
}) })
let index = childrenList.findIndex((item) => { let index = childrenList.findIndex(item => {
return item === node return item === node
}) })
childrenList.forEach((item, _index) => { childrenList.forEach((item, _index) => {
if (item.hasCustomPosition()) {// 适配自定义位置 if (item.hasCustomPosition()) {
// 适配自定义位置
return return
} }
let _offset = 0 let _offset = 0
@ -163,7 +199,8 @@ class MindMap extends Base {
// 上面的节点往上移 // 上面的节点往上移
if (_index < index) { if (_index < index) {
_offset = -addHeight _offset = -addHeight
} else if (_index > index) { // 下面的节点往下移 } else if (_index > index) {
// 下面的节点往下移
_offset = addHeight _offset = addHeight
} }
item.top += _offset item.top += _offset
@ -200,15 +237,9 @@ class MindMap extends Base {
*/ */
renderLineStraight(node, lines, style) { renderLineStraight(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
let marginX = this.getMarginX(node.layerIndex + 1) let marginX = this.getMarginX(node.layerIndex + 1)
let s1 = (marginX - expandBtnSize) * 0.6 let s1 = (marginX - expandBtnSize) * 0.6
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
@ -224,7 +255,9 @@ class MindMap extends Base {
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.dir === 'left' ? item.left + item.width : item.left let x2 = item.dir === 'left' ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${x2},${y2}` let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${
x1 + _s
},${y2} L ${x2},${y2}`
lines[index].plot(path) lines[index].plot(path)
style && style(lines[index], item) style && style(lines[index], item)
}) })
@ -238,17 +271,16 @@ class MindMap extends Base {
*/ */
renderLineDirect(node, lines, style) { renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width / 2 : item.dir === 'left' ? left - expandBtnSize : left + width + expandBtnSize let x1 =
node.layerIndex === 0
? left + width / 2
: item.dir === 'left'
? left - expandBtnSize
: left + width + expandBtnSize
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.dir === 'left' ? item.left + item.width : item.left let x2 = item.dir === 'left' ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
@ -266,17 +298,16 @@ class MindMap extends Base {
*/ */
renderLineCurve(node, lines, style) { renderLineCurve(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize } = node
left,
top,
width,
height,
expandBtnSize
} = node
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = node.layerIndex === 0 ? left + width / 2 : item.dir === 'left' ? left - expandBtnSize : left + width + 20 let x1 =
node.layerIndex === 0
? left + width / 2
: item.dir === 'left'
? left - expandBtnSize
: left + width + 20
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.dir === 'left' ? item.left + item.width : item.left let x2 = item.dir === 'left' ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
@ -297,15 +328,8 @@ class MindMap extends Base {
* @Desc: 渲染按钮 * @Desc: 渲染按钮
*/ */
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { let { width, height, expandBtnSize } = node
width, let { translateX, translateY } = btn.transform()
height,
expandBtnSize
} = node
let {
translateX,
translateY
} = btn.transform()
let x = (node.dir === 'left' ? 0 - expandBtnSize : width) - translateX let x = (node.dir === 'left' ? 0 - expandBtnSize : width) - translateX
let y = height / 2 - translateY let y = height / 2 - translateY
btn.translate(x, y) btn.translate(x, y)
@ -318,8 +342,17 @@ class MindMap extends Base {
*/ */
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let isLeft = node.dir === 'left' let isLeft = node.dir === 'left'
let { top, bottom, left, right, generalizationLineMargin, generalizationNodeMargin } = this.getNodeBoundaries(node, 'h', isLeft) let {
let x = isLeft ? left - generalizationLineMargin : right + generalizationLineMargin top,
bottom,
left,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'h', isLeft)
let x = isLeft
? left - generalizationLineMargin
: right + generalizationLineMargin
let x1 = x let x1 = x
let y1 = top let y1 = top
let x2 = x let x2 = x
@ -328,7 +361,10 @@ class MindMap extends Base {
let cy = y1 + (y2 - y1) / 2 let cy = y1 + (y2 - y1) / 2
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
gLine.plot(path) gLine.plot(path)
gNode.left = x + (isLeft ? -generalizationNodeMargin : generalizationNodeMargin) - (isLeft ? gNode.width : 0) gNode.left =
x +
(isLeft ? -generalizationNodeMargin : generalizationNodeMargin) -
(isLeft ? gNode.width : 0)
gNode.top = top + (bottom - top - gNode.height) / 2 gNode.top = top + (bottom - top - gNode.height) / 2
} }
} }

View File

@ -1,8 +1,5 @@
import Base from './Base'; import Base from './Base'
import { import { walk, asyncRun } from '../utils'
walk,
asyncRun
} from '../utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -27,15 +24,20 @@ class OrganizationStructure extends Base {
* @Desc: 布局 * @Desc: 布局
*/ */
doLayout(callback) { doLayout(callback) {
let task = [() => { let task = [
() => {
this.computedBaseValue() this.computedBaseValue()
}, () => { },
() => {
this.computedLeftValue() this.computedLeftValue()
}, () => { },
() => {
this.adjustLeftValue() this.adjustLeftValue()
}, () => { },
() => {
callback(this.root) callback(this.root)
}] }
]
asyncRun(task) asyncRun(task)
} }
@ -46,7 +48,10 @@ class OrganizationStructure extends Base {
* @Desc: 遍历数据计算节点的leftwidthheight * @Desc: 遍历数据计算节点的leftwidthheight
*/ */
computedBaseValue() { computedBaseValue() {
walk(this.renderer.renderTree, null, (cur, parent, isRoot, layerIndex) => { walk(
this.renderer.renderTree,
null,
(cur, parent, isRoot, layerIndex) => {
let newNode = this.createNode(cur, parent, isRoot, layerIndex) let newNode = this.createNode(cur, parent, isRoot, layerIndex)
// 根节点定位在画布中心位置 // 根节点定位在画布中心位置
if (isRoot) { if (isRoot) {
@ -54,18 +59,26 @@ class OrganizationStructure extends Base {
} else { } else {
// 非根节点 // 非根节点
// 定位到父节点下方 // 定位到父节点下方
newNode.top = parent._node.top + parent._node.height + this.getMarginX(layerIndex) newNode.top =
parent._node.top + parent._node.height + this.getMarginX(layerIndex)
} }
if (!cur.data.expand) { if (!cur.data.expand) {
return true; return true
} }
}, (cur, parent, isRoot, layerIndex) => { },
(cur, parent, isRoot, layerIndex) => {
// 返回时计算节点的areaWidth也就是子节点所占的宽度之和包括外边距 // 返回时计算节点的areaWidth也就是子节点所占的宽度之和包括外边距
let len = cur.data.expand === false ? 0 : cur._node.children.length let len = cur.data.expand === false ? 0 : cur._node.children.length
cur._node.childrenAreaWidth = len ? cur._node.children.reduce((h, item) => { cur._node.childrenAreaWidth = len
? cur._node.children.reduce((h, item) => {
return h + item.width return h + item.width
}, 0) + (len + 1) * this.getMarginY(layerIndex + 1) : 0 }, 0) +
}, true, 0) (len + 1) * this.getMarginY(layerIndex + 1)
: 0
},
true,
0
)
} }
/** /**
@ -75,18 +88,28 @@ class OrganizationStructure extends Base {
* @Desc: 遍历节点树计算节点的left * @Desc: 遍历节点树计算节点的left
*/ */
computedLeftValue() { computedLeftValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
if (node.nodeData.data.expand && node.children && node.children.length) { this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (
node.nodeData.data.expand &&
node.children &&
node.children.length
) {
let marginX = this.getMarginY(layerIndex + 1) let marginX = this.getMarginY(layerIndex + 1)
// 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半 // 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半
let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 let left = node.left + node.width / 2 - node.childrenAreaWidth / 2
let totalLeft = left + marginX let totalLeft = left + marginX
node.children.forEach((cur) => { node.children.forEach(cur => {
cur.left = totalLeft cur.left = totalLeft
totalLeft += cur.width + marginX totalLeft += cur.width + marginX
}) })
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -96,16 +119,25 @@ class OrganizationStructure extends Base {
* @Desc: 调整节点left * @Desc: 调整节点left
*/ */
adjustLeftValue() { adjustLeftValue() {
walk(this.root, null, (node, parent, isRoot, layerIndex) => { walk(
this.root,
null,
(node, parent, isRoot, layerIndex) => {
if (!node.nodeData.data.expand) { if (!node.nodeData.data.expand) {
return; return
} }
// 判断子节点所占的宽度之和是否大于该节点自身,大于则需要调整位置 // 判断子节点所占的宽度之和是否大于该节点自身,大于则需要调整位置
let difference = node.childrenAreaWidth - this.getMarginY(layerIndex + 1) * 2 - node.width let difference =
node.childrenAreaWidth -
this.getMarginY(layerIndex + 1) * 2 -
node.width
if (difference > 0) { if (difference > 0) {
this.updateBrothers(node, difference / 2) this.updateBrothers(node, difference / 2)
} }
}, null, true) },
null,
true
)
} }
/** /**
@ -117,18 +149,20 @@ class OrganizationStructure extends Base {
updateBrothers(node, addWidth) { updateBrothers(node, addWidth) {
if (node.parent) { if (node.parent) {
let childrenList = node.parent.children let childrenList = node.parent.children
let index = childrenList.findIndex((item) => { let index = childrenList.findIndex(item => {
return item === node return item === node
}) })
childrenList.forEach((item, _index) => { childrenList.forEach((item, _index) => {
if (item.hasCustomPosition()) {// 适配自定义位置 if (item.hasCustomPosition()) {
// 适配自定义位置
return return
} }
let _offset = 0 let _offset = 0
// 上面的节点往上移 // 上面的节点往上移
if (_index < index) { if (_index < index) {
_offset = -addWidth _offset = -addWidth
} else if (_index > index) { // 下面的节点往下移 } else if (_index > index) {
// 下面的节点往下移
_offset = addWidth _offset = addWidth
} }
item.left += _offset item.left += _offset
@ -163,14 +197,9 @@ class OrganizationStructure extends Base {
*/ */
renderLineDirect(node, lines, style) { renderLineDirect(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height } = node
left,
top,
width,
height,
} = node
let x1 = left + width / 2 let x1 = left + width / 2
let y1 = top + height let y1 = top + height
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
@ -190,16 +219,9 @@ class OrganizationStructure extends Base {
*/ */
renderLineStraight(node, lines, style) { renderLineStraight(node, lines, style) {
if (node.children.length <= 0) { if (node.children.length <= 0) {
return []; return []
} }
let { let { left, top, width, height, expandBtnSize, isRoot } = node
left,
top,
width,
height,
expandBtnSize,
isRoot
} = node
let x1 = left + width / 2 let x1 = left + width / 2
let y1 = top + height let y1 = top + height
let marginX = this.getMarginX(node.layerIndex + 1) let marginX = this.getMarginX(node.layerIndex + 1)
@ -245,16 +267,12 @@ class OrganizationStructure extends Base {
* @Desc: 渲染按钮 * @Desc: 渲染按钮
*/ */
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { let { width, height, expandBtnSize } = node
width, let { translateX, translateY } = btn.transform()
height, btn.translate(
expandBtnSize width / 2 - expandBtnSize / 2 - translateX,
} = node height + expandBtnSize / 2 - translateY
let { )
translateX,
translateY
} = btn.transform()
btn.translate(width / 2 - expandBtnSize / 2 - translateX, height + expandBtnSize / 2 - translateY)
} }
/** /**
@ -263,7 +281,13 @@ class OrganizationStructure extends Base {
* @Desc: 创建概要节点 * @Desc: 创建概要节点
*/ */
renderGeneralization(node, gLine, gNode) { renderGeneralization(node, gLine, gNode) {
let { bottom, left, right, generalizationLineMargin, generalizationNodeMargin } = this.getNodeBoundaries(node, 'v') let {
bottom,
left,
right,
generalizationLineMargin,
generalizationNodeMargin
} = this.getNodeBoundaries(node, 'v')
let x1 = left let x1 = left
let y1 = bottom + generalizationLineMargin let y1 = bottom + generalizationLineMargin
let x2 = right let x2 = right

View File

@ -1,5 +1,5 @@
import JSZip from "jszip"; import JSZip from 'jszip'
import xmlConvert from "xml-js"; import xmlConvert from 'xml-js'
/** /**
* javascript comment * javascript comment
@ -7,35 +7,35 @@ import xmlConvert from "xml-js";
* @Date: 2022-09-21 14:07:47 * @Date: 2022-09-21 14:07:47
* @Desc: 解析.xmind文件 * @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(
async (zip) => { async zip => {
try { try {
let content = ""; let content = ''
if (zip.files["content.json"]) { if (zip.files['content.json']) {
let json = await zip.files["content.json"].async("string"); let json = await zip.files['content.json'].async('string')
content = transformXmind(json); content = transformXmind(json)
} else if (zip.files["content.xml"]) { } else if (zip.files['content.xml']) {
let xml = await zip.files["content.xml"].async("string"); let xml = await zip.files['content.xml'].async('string')
let json = xmlConvert.xml2json(xml); let json = xmlConvert.xml2json(xml)
content = transformOldXmind(json); content = transformOldXmind(json)
} }
if (content) { if (content) {
resolve(content); resolve(content)
} else { } else {
reject(new Error("解析失败")); reject(new Error('解析失败'))
} }
} catch (error) { } catch (error) {
reject(error); reject(error)
} }
}, },
(e) => { e => {
reject(e); reject(e)
}
)
})
} }
);
});
};
/** /**
* javascript comment * javascript comment
@ -43,44 +43,44 @@ const parseXmindFile = (file) => {
* @Date: 2022-09-21 18:57:25 * @Date: 2022-09-21 18:57:25
* @Desc: 转换xmind数据 * @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
let newTree = {}; let newTree = {}
let walk = (node, newNode) => { let walk = (node, newNode) => {
newNode.data = { newNode.data = {
// 节点内容 // 节点内容
text: node.title, text: node.title
}; }
// 节点备注 // 节点备注
if (node.notes) { if (node.notes) {
newNode.data.note = (node.notes.realHTML || node.notes.plain).content; newNode.data.note = (node.notes.realHTML || node.notes.plain).content
} }
// 超链接 // 超链接
if (node.href && /^https?:\/\//.test(node.href)) { if (node.href && /^https?:\/\//.test(node.href)) {
newNode.data.hyperlink = node.href; newNode.data.hyperlink = node.href
} }
// 标签 // 标签
if (node.labels && node.labels.length > 0) { if (node.labels && node.labels.length > 0) {
newNode.data.tag = node.labels; newNode.data.tag = node.labels
} }
// 子节点 // 子节点
newNode.children = []; newNode.children = []
if ( if (
node.children && node.children &&
node.children.attached && node.children.attached &&
node.children.attached.length > 0 node.children.attached.length > 0
) { ) {
node.children.attached.forEach((item) => { node.children.attached.forEach(item => {
let newChild = {}; let newChild = {}
newNode.children.push(newChild); newNode.children.push(newChild)
walk(item, newChild); walk(item, newChild)
}); })
}
}
walk(nodeTree, newTree)
return newTree
} }
};
walk(nodeTree, newTree);
return newTree;
};
/** /**
* javascript comment * javascript comment
@ -88,86 +88,92 @@ const transformXmind = (content) => {
* @Date: 2022-09-23 15:51:51 * @Date: 2022-09-23 15:51:51
* @Desc: 转换旧版xmind数据xmind8 * @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
let root = null; let root = null
let getRoot = (arr) => { let getRoot = arr => {
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
if (!root && arr[i].name === "topic") { if (!root && arr[i].name === 'topic') {
root = arr[i]; root = arr[i]
return; return
} }
} }
arr.forEach((item) => { arr.forEach(item => {
getRoot(item.elements); getRoot(item.elements)
}); })
}; }
getRoot(elements); getRoot(elements)
let newTree = {}; let newTree = {}
let getItemByName = (arr, name) => { let getItemByName = (arr, name) => {
return arr.find((item) => { return arr.find(item => {
return item.name === name; return item.name === name
}); })
}; }
let walk = (node, newNode) => { let walk = (node, newNode) => {
let nodeElements = node.elements; let nodeElements = node.elements
newNode.data = { newNode.data = {
// 节点内容 // 节点内容
text: getItemByName(nodeElements, "title").elements[0].text, text: getItemByName(nodeElements, 'title').elements[0].text
}; }
try { try {
// 节点备注 // 节点备注
let notesElement = getItemByName(nodeElements, "notes"); let notesElement = getItemByName(nodeElements, 'notes')
if (notesElement) { if (notesElement) {
newNode.data.note = newNode.data.note =
notesElement.elements[0].elements[0].elements[0].text; notesElement.elements[0].elements[0].elements[0].text
}
} catch (error) {
console.log(error)
} }
} catch (error) {}
try { try {
// 超链接 // 超链接
if ( if (
node.attributes && node.attributes &&
node.attributes["xlink:href"] && node.attributes['xlink:href'] &&
/^https?:\/\//.test(node.attributes["xlink:href"]) /^https?:\/\//.test(node.attributes['xlink:href'])
) { ) {
newNode.data.hyperlink = node.attributes["xlink:href"]; newNode.data.hyperlink = node.attributes['xlink:href']
}
} catch (error) {
console.log(error)
} }
} catch (error) {}
try { try {
// 标签 // 标签
let labelsElement = getItemByName(nodeElements, "labels"); let labelsElement = getItemByName(nodeElements, 'labels')
if (labelsElement) { if (labelsElement) {
newNode.data.tag = labelsElement.elements.map((item) => { newNode.data.tag = labelsElement.elements.map(item => {
return item.elements[0].text; return item.elements[0].text
}); })
}
} catch (error) {
console.log(error)
} }
} catch (error) {}
// 子节点 // 子节点
newNode.children = []; newNode.children = []
let _children = getItemByName(nodeElements, "children"); let _children = getItemByName(nodeElements, 'children')
if (_children && _children.elements && _children.elements.length > 0) { if (_children && _children.elements && _children.elements.length > 0) {
_children.elements.forEach((item) => { _children.elements.forEach(item => {
if (item.name === "topics") { if (item.name === 'topics') {
item.elements.forEach((item2) => { item.elements.forEach(item2 => {
let newChild = {}; let newChild = {}
newNode.children.push(newChild); newNode.children.push(newChild)
walk(item2, newChild); walk(item2, newChild)
}); })
} else { } else {
let newChild = {}; let newChild = {}
newNode.children.push(newChild); newNode.children.push(newChild)
walk(item, newChild); walk(item, newChild)
} }
}); })
}
}
walk(root, newTree)
return newTree
} }
};
walk(root, newTree);
return newTree;
};
export default { export default {
parseXmindFile, parseXmindFile,
transformXmind, transformXmind,
transformOldXmind, transformOldXmind
}; }

View File

@ -1,8 +1,10 @@
// 超链接图标 // 超链接图标
const hyperlink = '<svg t="1624174958075" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7982" ><path d="M435.484444 251.733333v68.892445L295.822222 320.682667a168.504889 168.504889 0 0 0-2.844444 336.952889h142.506666v68.892444H295.822222a237.397333 237.397333 0 0 1 0-474.794667h139.662222z m248.945778 0a237.397333 237.397333 0 0 1 0 474.851556H544.654222v-69.006222l139.776 0.056889a168.504889 168.504889 0 0 0 2.844445-336.952889H544.597333V251.676444h139.776z m-25.827555 203.946667a34.474667 34.474667 0 0 1 0 68.892444H321.649778a34.474667 34.474667 0 0 1 0-68.892444h336.952889z" p-id="7983"></path></svg>' const hyperlink =
'<svg t="1624174958075" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7982" ><path d="M435.484444 251.733333v68.892445L295.822222 320.682667a168.504889 168.504889 0 0 0-2.844444 336.952889h142.506666v68.892444H295.822222a237.397333 237.397333 0 0 1 0-474.794667h139.662222z m248.945778 0a237.397333 237.397333 0 0 1 0 474.851556H544.654222v-69.006222l139.776 0.056889a168.504889 168.504889 0 0 0 2.844445-336.952889H544.597333V251.676444h139.776z m-25.827555 203.946667a34.474667 34.474667 0 0 1 0 68.892444H321.649778a34.474667 34.474667 0 0 1 0-68.892444h336.952889z" p-id="7983"></path></svg>'
// 备注图标 // 备注图标
const note = '<svg t="1624195132675" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792" ><path d="M152.768 985.984 152.768 49.856l434.56 0 66.816 0 234.048 267.392 0 66.816 0 601.92L152.768 985.984 152.768 985.984zM654.144 193.088l0 124.16 108.736 0L654.144 193.088 654.144 193.088zM821.312 384.064l-167.168 0L587.328 384.064 587.328 317.312 587.328 116.736 219.584 116.736 219.584 919.04l601.728 0L821.312 384.064 821.312 384.064zM386.688 517.888 319.808 517.888 319.808 450.944l66.816 0L386.624 517.888 386.688 517.888zM386.688 651.584 319.808 651.584 319.808 584.704l66.816 0L386.624 651.584 386.688 651.584zM386.688 785.344 319.808 785.344l0-66.88 66.816 0L386.624 785.344 386.688 785.344zM721.024 517.888 453.632 517.888 453.632 450.944l267.392 0L721.024 517.888 721.024 517.888zM654.144 651.584 453.632 651.584 453.632 584.704l200.512 0L654.144 651.584 654.144 651.584zM620.672 785.344l-167.04 0 0-66.88 167.04 0L620.672 785.344 620.672 785.344z" p-id="8793"></path></svg>' const note =
'<svg t="1624195132675" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8792" ><path d="M152.768 985.984 152.768 49.856l434.56 0 66.816 0 234.048 267.392 0 66.816 0 601.92L152.768 985.984 152.768 985.984zM654.144 193.088l0 124.16 108.736 0L654.144 193.088 654.144 193.088zM821.312 384.064l-167.168 0L587.328 384.064 587.328 317.312 587.328 116.736 219.584 116.736 219.584 919.04l601.728 0L821.312 384.064 821.312 384.064zM386.688 517.888 319.808 517.888 319.808 450.944l66.816 0L386.624 517.888 386.688 517.888zM386.688 651.584 319.808 651.584 319.808 584.704l66.816 0L386.624 651.584 386.688 651.584zM386.688 785.344 319.808 785.344l0-66.88 66.816 0L386.624 785.344 386.688 785.344zM721.024 517.888 453.632 517.888 453.632 450.944l267.392 0L721.024 517.888 721.024 517.888zM654.144 651.584 453.632 651.584 453.632 584.704l200.512 0L654.144 651.584 654.144 651.584zM620.672 785.344l-167.04 0 0-66.88 167.04 0L620.672 785.344 620.672 785.344z" p-id="8793"></path></svg>'
// 节点icon // 节点icon
export const nodeIconList = [ export const nodeIconList = [
@ -281,14 +283,14 @@ export const nodeIconList = [
* @Date: 2021-06-23 22:36:56 * @Date: 2021-06-23 22:36:56
* @Desc: 获取nodeIconList icon内容 * @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 => {
return item.type === arr[0]; return item.type === arr[0]
}) })
return typeData.list.find((item) => { return typeData.list.find(item => {
return item.name === arr[1] return item.name === arr[1]
}).icon; }).icon
} }
export default { export default {

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -18,7 +18,8 @@ export default merge(defaultTheme, {
// 背景颜色 // 背景颜色
backgroundColor: 'rgb(58, 65, 68)', backgroundColor: 'rgb(58, 65, 68)',
// 背景图片 // 背景图片
backgroundImage: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=', backgroundImage:
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=',
// 背景重复 // 背景重复
backgroundRepeat: 'repeat', backgroundRepeat: 'repeat',
// 根节点样式 // 根节点样式

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,7 +24,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: 'rgb(254, 199, 13)', borderColor: 'rgb(254, 199, 13)',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式

View File

@ -53,7 +53,7 @@ export default {
active: { active: {
borderColor: 'rgb(57, 80, 96)', borderColor: 'rgb(57, 80, 96)',
borderWidth: 3, borderWidth: 3,
borderDasharray: 'none', borderDasharray: 'none'
} }
}, },
// 二级节点样式 // 二级节点样式
@ -76,7 +76,7 @@ export default {
active: { active: {
borderColor: 'rgb(57, 80, 96)', borderColor: 'rgb(57, 80, 96)',
borderWidth: 3, borderWidth: 3,
borderDasharray: 'none', borderDasharray: 'none'
} }
}, },
// 三级及以下节点样式 // 三级及以下节点样式
@ -99,7 +99,7 @@ export default {
active: { active: {
borderColor: 'rgb(57, 80, 96)', borderColor: 'rgb(57, 80, 96)',
borderWidth: 3, borderWidth: 3,
borderDasharray: 'none', borderDasharray: 'none'
} }
}, },
// 概要节点样式 // 概要节点样式
@ -122,13 +122,23 @@ export default {
active: { active: {
borderColor: 'rgb(57, 80, 96)', borderColor: 'rgb(57, 80, 96)',
borderWidth: 3, borderWidth: 3,
borderDasharray: 'none', borderDasharray: 'none'
} }
} }
} }
// 支持激活样式的属性 // 支持激活样式的属性
// 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小 // 简单来说,会改变节点大小的都不支持在激活时设置,为了性能考虑,节点切换激活态时不会重新计算节点大小
export const supportActiveStyle = ['fillColor', 'color', 'fontWeight', 'fontStyle', 'borderColor', 'borderWidth', 'borderDasharray', 'borderRadius', 'textDecoration'] export const supportActiveStyle = [
'fillColor',
'color',
'fontWeight',
'fontStyle',
'borderColor',
'borderWidth',
'borderDasharray',
'borderRadius',
'textDecoration'
]
export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth'] export const lineStyleProps = ['lineColor', 'lineDasharray', 'lineWidth']

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -34,7 +34,7 @@ export default merge(defaultTheme, {
active: { active: {
borderColor: 'rgb(57, 80, 96)', borderColor: 'rgb(57, 80, 96)',
borderWidth: 3, borderWidth: 3,
borderDasharray: 'none', borderDasharray: 'none'
} }
} }
}) })

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,7 +24,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: 'rgb(247, 208, 160)', borderColor: 'rgb(247, 208, 160)',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,7 +24,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: '#222', borderColor: '#222',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式

View File

@ -8,8 +8,8 @@ import earthYellow from './earthYellow'
import classic from './classic' import classic from './classic'
import classic2 from './classic2' import classic2 from './classic2'
import classic3 from './classic3' import classic3 from './classic3'
import classic4 from './classic4'; import classic4 from './classic4'
import dark from './dark'; import dark from './dark'
import classicGreen from './classicGreen' import classicGreen from './classicGreen'
import classicBlue from './classicBlue' import classicBlue from './classicBlue'
import minions from './minions' import minions from './minions'

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -23,7 +23,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: 'rgb(255, 160, 36)', borderColor: 'rgb(255, 160, 36)',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -23,7 +23,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: 'rgb(243, 104, 138)', borderColor: 'rgb(243, 104, 138)',
borderWidth: 2, borderWidth: 2
} }
}, },
// 二级节点样式 // 二级节点样式
@ -35,7 +35,7 @@ export default merge(defaultTheme, {
fontSize: 14, fontSize: 14,
active: { active: {
borderColor: 'rgb(139, 109, 225)', borderColor: 'rgb(139, 109, 225)',
borderWidth: 2, borderWidth: 2
} }
}, },
// 三级及以下节点样式 // 三级及以下节点样式
@ -53,7 +53,7 @@ export default merge(defaultTheme, {
color: '#222', color: '#222',
active: { active: {
borderColor: 'rgb(139, 109, 225)', borderColor: 'rgb(139, 109, 225)',
borderWidth: 2, borderWidth: 2
} }
} }
}) })

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,7 +24,7 @@ export default merge(defaultTheme, {
color: 'rgb(65, 89, 158)', color: 'rgb(65, 89, 158)',
active: { active: {
borderColor: 'rgb(251, 227, 188)', borderColor: 'rgb(251, 227, 188)',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式
@ -36,7 +36,7 @@ export default merge(defaultTheme, {
fontSize: 14, fontSize: 14,
active: { active: {
borderColor: '#fff', borderColor: '#fff',
borderWidth: 2, borderWidth: 2
} }
}, },
// 三级及以下节点样式 // 三级及以下节点样式

View File

@ -1,5 +1,5 @@
import defaultTheme from './default'; import defaultTheme from './default'
import merge from 'deepmerge'; import merge from 'deepmerge'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,7 +24,7 @@ export default merge(defaultTheme, {
borderWidth: 0, borderWidth: 0,
active: { active: {
borderColor: 'rgb(51, 51, 51)', borderColor: 'rgb(51, 51, 51)',
borderWidth: 3, borderWidth: 3
} }
}, },
// 二级节点样式 // 二级节点样式

View File

@ -54,7 +54,12 @@ export const layoutList = [
img: require('../assets/catalogOrganization.jpg') img: require('../assets/catalogOrganization.jpg')
} }
] ]
export const layoutValueList = ['logicalStructure', 'mindMap', 'catalogOrganization', 'organizationStructure'] export const layoutValueList = [
'logicalStructure',
'mindMap',
'catalogOrganization',
'organizationStructure'
]
/** /**
* @Author: 王林 * @Author: 王林

View File

@ -4,7 +4,15 @@
* @Date: 2021-04-06 14:13:17 * @Date: 2021-04-06 14:13:17
* @Desc: 深度优先遍历树 * @Desc: 深度优先遍历树
*/ */
export const walk = (root, parent, beforeCallback, afterCallback, isRoot, layerIndex = 0, index = 0) => { export const walk = (
root,
parent,
beforeCallback,
afterCallback,
isRoot,
layerIndex = 0,
index = 0
) => {
let stop = false let stop = false
if (beforeCallback) { if (beforeCallback) {
stop = beforeCallback(root, parent, isRoot, layerIndex, index) stop = beforeCallback(root, parent, isRoot, layerIndex, index)
@ -12,7 +20,15 @@ export const walk = (root, parent, beforeCallback, afterCallback, isRoot, layerI
if (!stop && root.children && root.children.length > 0) { if (!stop && root.children && root.children.length > 0) {
let _layerIndex = layerIndex + 1 let _layerIndex = layerIndex + 1
root.children.forEach((node, nodeIndex) => { root.children.forEach((node, nodeIndex) => {
walk(node, root, beforeCallback, afterCallback, false, _layerIndex, nodeIndex) walk(
node,
root,
beforeCallback,
afterCallback,
false,
_layerIndex,
nodeIndex
)
}) })
} }
afterCallback && afterCallback(root, parent, isRoot, layerIndex, index) afterCallback && afterCallback(root, parent, isRoot, layerIndex, index)
@ -34,7 +50,7 @@ export const bfsWalk = (root, callback) => {
} }
let cur = stack.shift() let cur = stack.shift()
if (cur.children && cur.children.length) { if (cur.children && cur.children.length) {
cur.children.forEach((item) => { cur.children.forEach(item => {
stack.push(item) stack.push(item)
if (callback(item) === 'stop') { if (callback(item) === 'stop') {
isStop = true isStop = true
@ -58,9 +74,11 @@ export const resizeImgSize = (width, height, maxWidth, maxHeight) => {
arr = [width, height] arr = [width, height]
} else { } else {
let mRatio = maxWidth / maxHeight let mRatio = maxWidth / maxHeight
if (nRatio > mRatio) { // 固定高度 if (nRatio > mRatio) {
// 固定高度
arr = [nRatio * maxHeight, maxHeight] arr = [nRatio * maxHeight, maxHeight]
} else { // 固定宽度 } else {
// 固定宽度
arr = [maxWidth, maxWidth / nRatio] arr = [maxWidth, maxWidth / nRatio]
} }
} }
@ -91,10 +109,15 @@ export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
let img = new Image() let img = new Image()
img.src = imgUrl img.src = imgUrl
img.onload = () => { img.onload = () => {
let arr = resizeImgSize(img.naturalWidth, img.naturalHeight, maxWidth, maxHeight) let arr = resizeImgSize(
img.naturalWidth,
img.naturalHeight,
maxWidth,
maxHeight
)
resolve(arr) resolve(arr)
} }
img.onerror = (e) => { img.onerror = e => {
reject(e) reject(e)
} }
}) })
@ -105,12 +128,12 @@ export const resizeImg = (imgUrl, maxWidth, maxHeight) => {
* @Date: 2021-05-04 12:26:56 * @Date: 2021-05-04 12:26:56
* @Desc: 从头html结构字符串里获取带换行符的字符串 * @Desc: 从头html结构字符串里获取带换行符的字符串
*/ */
export const getStrWithBrFromHtml = (str) => { export const getStrWithBrFromHtml = str => {
str = str.replace(/<br>/img, '\n') str = str.replace(/<br>/gim, '\n')
let el = document.createElement('div') let el = document.createElement('div')
el.innerHTML = str el.innerHTML = str
str = el.textContent str = el.textContent
return str; return str
} }
/** /**
@ -118,7 +141,7 @@ export const getStrWithBrFromHtml = (str) => {
* @Date: 2021-05-04 14:45:39 * @Date: 2021-05-04 14:45:39
* @Desc: 极简的深拷贝 * @Desc: 极简的深拷贝
*/ */
export const simpleDeepClone = (data) => { export const simpleDeepClone = data => {
try { try {
return JSON.parse(JSON.stringify(data)) return JSON.parse(JSON.stringify(data))
} catch (error) { } catch (error) {
@ -139,7 +162,7 @@ export const copyRenderTree = (tree, root) => {
tree.children[index] = copyRenderTree({}, item) tree.children[index] = copyRenderTree({}, item)
}) })
} }
return tree; return tree
} }
/** /**
@ -157,12 +180,16 @@ export const copyNodeTree = (tree, root, removeActiveState = false) => {
root.children.forEach((item, index) => { root.children.forEach((item, index) => {
tree.children[index] = copyNodeTree({}, item, removeActiveState) tree.children[index] = copyNodeTree({}, item, removeActiveState)
}) })
} else if (root.nodeData && root.nodeData.children && root.nodeData.children.length > 0) { } else if (
root.nodeData &&
root.nodeData.children &&
root.nodeData.children.length > 0
) {
root.nodeData.children.forEach((item, index) => { root.nodeData.children.forEach((item, index) => {
tree.children[index] = copyNodeTree({}, item, removeActiveState) tree.children[index] = copyNodeTree({}, item, removeActiveState)
}) })
} }
return tree; return tree
} }
/** /**
@ -170,7 +197,7 @@ export const copyNodeTree = (tree, root, removeActiveState = false) => {
* @Date: 2021-07-04 09:08:43 * @Date: 2021-07-04 09:08:43
* @Desc: 图片转成dataURL * @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()
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片 // 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
@ -188,11 +215,11 @@ export const imgToDataUrl = (src) => {
reject(e) reject(e)
} }
} }
img.onerror = (e) => { img.onerror = e => {
reject(e) reject(e)
} }
img.src = src img.src = src
}); })
} }
/** /**
@ -221,8 +248,8 @@ export const throttle = (fn, time = 300, ctx) => {
timer = setTimeout(() => { timer = setTimeout(() => {
fn.call(ctx) fn.call(ctx)
timer = null timer = null
}, 300) }, time)
}; }
} }
/** /**

View File

@ -1,54 +1,54 @@
const map = { const map = {
'Backspace': 8, Backspace: 8,
'Tab': 9, Tab: 9,
'Enter': 13, Enter: 13,
'Shift': 16, Shift: 16,
'Control': 17, Control: 17,
'Alt': 18, Alt: 18,
'CapsLock': 20, CapsLock: 20,
'Esc': 27, Esc: 27,
'Spacebar': 32, Spacebar: 32,
'PageUp': 33, PageUp: 33,
'PageDown': 34, PageDown: 34,
'End': 35, End: 35,
'Home': 36, Home: 36,
'Insert': 45, Insert: 45,
'Left': 37, Left: 37,
'Up': 38, Up: 38,
'Right': 39, Right: 39,
'Down': 40, Down: 40,
'Del': 46, Del: 46,
'NumLock': 144, NumLock: 144,
'Cmd': 91, Cmd: 91,
'CmdFF': 224, CmdFF: 224,
'F1': 112, F1: 112,
'F2': 113, F2: 113,
'F3': 114, F3: 114,
'F4': 115, F4: 115,
'F5': 116, F5: 116,
'F6': 117, F6: 117,
'F7': 118, F7: 118,
'F8': 119, F8: 119,
'F9': 120, F9: 120,
'F10': 121, F10: 121,
'F11': 122, F11: 122,
'F12': 123, F12: 123,
'`': 192, '`': 192,
'=': 187, '=': 187,
'-': 189, '-': 189,
'/': 191, '/': 191,
'.': 190, '.': 190
} }
// 数字 // 数字

9
web/.prettierignore Normal file
View File

@ -0,0 +1,9 @@
src/assets
*/.DS_Store
node_modules
public
*.json
*.md
.eslintrc.js
.prettierignore
.prettierrc

5
web/.prettierrc Normal file
View File

@ -0,0 +1,5 @@
semi: false
singleQuote: true
printWidth: 80
trailingComma: 'none'
arrowParens: 'avoid'

View File

@ -6,7 +6,8 @@
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
"build": "vue-cli-service build && node ../copy.js", "build": "vue-cli-service build && node ../copy.js",
"lint": "vue-cli-service lint", "lint": "vue-cli-service lint",
"buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/index.js --dest ../simple-mind-map/dist" "buildLibrary": "vue-cli-service build --target lib --name simpleMindMap ../simple-mind-map/index.js --dest ../simple-mind-map/dist",
"format": "prettier --write src/**"
}, },
"dependencies": { "dependencies": {
"@toast-ui/editor": "^3.1.5", "@toast-ui/editor": "^3.1.5",
@ -26,6 +27,7 @@
"eslint-plugin-vue": "^6.2.2", "eslint-plugin-vue": "^6.2.2",
"less": "^3.12.2", "less": "^3.12.2",
"less-loader": "^7.1.0", "less-loader": "^7.1.0",
"prettier": "^1.19.1",
"vue-template-compiler": "^2.6.11", "vue-template-compiler": "^2.6.11",
"webpack": "^4.44.2" "webpack": "^4.44.2"
}, },

View File

@ -6,9 +6,9 @@
<script> <script>
export default { export default {
name: "App", name: 'App',
components: {}, components: {}
}; }
</script> </script>
<style> <style>

View File

@ -1,4 +1,4 @@
import exampleData from "simple-mind-map/example/exampleData" import exampleData from 'simple-mind-map/example/exampleData'
import { simpleDeepClone } from 'simple-mind-map/src/utils/index' import { simpleDeepClone } from 'simple-mind-map/src/utils/index'
import Vue from 'vue' import Vue from 'vue'
@ -18,7 +18,7 @@ const copyMindMapTreeData = (tree, root) => {
tree.children[index] = copyMindMapTreeData({}, item) tree.children[index] = copyMindMapTreeData({}, item)
}) })
} }
return tree; return tree
} }
/** /**
@ -44,7 +44,7 @@ export const getData = () => {
* @Date: 2021-08-01 10:14:28 * @Date: 2021-08-01 10:14:28
* @Desc: 存储思维导图数据 * @Desc: 存储思维导图数据
*/ */
export const storeData = (data) => { export const storeData = data => {
try { try {
let originData = getData() let originData = getData()
originData.root = copyMindMapTreeData({}, data) originData.root = copyMindMapTreeData({}, data)
@ -61,7 +61,7 @@ export const storeData = (data) => {
* @Date: 2021-08-01 10:24:56 * @Date: 2021-08-01 10:24:56
* @Desc: 存储思维导图配置数据 * @Desc: 存储思维导图配置数据
*/ */
export const storeConfig = (config) => { export const storeConfig = config => {
try { try {
let originData = getData() let originData = getData()
originData = { originData = {

View File

@ -1,15 +1,19 @@
/* Logo 字体 */ /* Logo 字体 */
@font-face { @font-face {
font-family: "iconfont logo"; font-family: 'iconfont logo';
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix')
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), format('embedded-opentype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834')
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); format('woff'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834')
format('truetype'),
url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont')
format('svg');
} }
.logo { .logo {
font-family: "iconfont logo"; font-family: 'iconfont logo';
font-size: 160px; font-size: 160px;
font-style: normal; font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@ -48,7 +52,6 @@
color: #666; color: #666;
} }
#tabs .active { #tabs .active {
border-bottom-color: #f00; border-bottom-color: #f00;
color: #222; color: #222;
@ -283,7 +286,7 @@
} }
.markdown > table th { .markdown > table th {
background: #F7F7F7; background: #f7f7f7;
} }
.markdown blockquote { .markdown blockquote {
@ -323,7 +326,6 @@
clear: both; clear: both;
} }
.hljs { .hljs {
display: block; display: block;
background: white; background: white;
@ -399,8 +401,8 @@ https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javasc
* Based on dabblet (http://dabblet.com) * Based on dabblet (http://dabblet.com)
* @author Lea Verou * @author Lea Verou
*/ */
code[class*="language-"], code[class*='language-'],
pre[class*="language-"] { pre[class*='language-'] {
color: black; color: black;
background: none; background: none;
text-shadow: 0 1px white; text-shadow: 0 1px white;
@ -422,46 +424,45 @@ pre[class*="language-"] {
hyphens: none; hyphens: none;
} }
pre[class*="language-"]::-moz-selection, pre[class*='language-']::-moz-selection,
pre[class*="language-"] ::-moz-selection, pre[class*='language-'] ::-moz-selection,
code[class*="language-"]::-moz-selection, code[class*='language-']::-moz-selection,
code[class*="language-"] ::-moz-selection { code[class*='language-'] ::-moz-selection {
text-shadow: none; text-shadow: none;
background: #b3d4fc; background: #b3d4fc;
} }
pre[class*="language-"]::selection, pre[class*='language-']::selection,
pre[class*="language-"] ::selection, pre[class*='language-'] ::selection,
code[class*="language-"]::selection, code[class*='language-']::selection,
code[class*="language-"] ::selection { code[class*='language-'] ::selection {
text-shadow: none; text-shadow: none;
background: #b3d4fc; background: #b3d4fc;
} }
@media print { @media print {
code[class*='language-'],
code[class*="language-"], pre[class*='language-'] {
pre[class*="language-"] {
text-shadow: none; text-shadow: none;
} }
} }
/* Code blocks */ /* Code blocks */
pre[class*="language-"] { pre[class*='language-'] {
padding: 1em; padding: 1em;
margin: .5em 0; margin: 0.5em 0;
overflow: auto; overflow: auto;
} }
:not(pre)>code[class*="language-"], :not(pre) > code[class*='language-'],
pre[class*="language-"] { pre[class*='language-'] {
background: #f5f2f0; background: #f5f2f0;
} }
/* Inline code */ /* Inline code */
:not(pre)>code[class*="language-"] { :not(pre) > code[class*='language-'] {
padding: .1em; padding: 0.1em;
border-radius: .3em; border-radius: 0.3em;
white-space: normal; white-space: normal;
} }
@ -477,7 +478,7 @@ pre[class*="language-"] {
} }
.namespace { .namespace {
opacity: .7; opacity: 0.7;
} }
.token.property, .token.property,
@ -505,7 +506,7 @@ pre[class*="language-"] {
.language-css .token.string, .language-css .token.string,
.style .token.string { .style .token.string {
color: #9a6e3a; color: #9a6e3a;
background: hsla(0, 0%, 100%, .5); background: hsla(0, 0%, 100%, 0.5);
} }
.token.atrule, .token.atrule,
@ -516,7 +517,7 @@ pre[class*="language-"] {
.token.function, .token.function,
.token.class-name { .token.class-name {
color: #DD4A68; color: #dd4a68;
} }
.token.regex, .token.regex,

View File

@ -3,11 +3,22 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>iconfont Demo</title> <title>iconfont Demo</title>
<link rel="shortcut icon" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg" type="image/x-icon"/> <link
<link rel="icon" type="image/svg+xml" href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"/> rel="shortcut icon"
<link rel="stylesheet" href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css"> href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"
<link rel="stylesheet" href="demo.css"> type="image/x-icon"
<link rel="stylesheet" href="iconfont.css"> />
<link
rel="icon"
type="image/svg+xml"
href="//img.alicdn.com/imgextra/i4/O1CN01Z5paLz1O0zuCC7osS_!!6000000001644-55-tps-83-82.svg"
/>
<link
rel="stylesheet"
href="https://g.alicdn.com/thx/cube/1.3.2/cube.min.css"
/>
<link rel="stylesheet" href="demo.css" />
<link rel="stylesheet" href="iconfont.css" />
<script src="iconfont.js"></script> <script src="iconfont.js"></script>
<!-- jQuery --> <!-- jQuery -->
<script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script> <script src="https://a1.alicdn.com/oss/uploads/2018/12/26/7bfddb60-08e8-11e9-9b04-53e73bb6408b.js"></script>
@ -28,7 +39,7 @@
margin-left: 0.5em; margin-left: 0.5em;
font-size: 22px; font-size: 22px;
color: #fff; color: #fff;
background: linear-gradient(-45deg, #3967FF, #B500FE); background: linear-gradient(-45deg, #3967ff, #b500fe);
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
} }
@ -36,10 +47,18 @@
</head> </head>
<body> <body>
<div class="main"> <div class="main">
<h1 class="logo"><a href="https://www.iconfont.cn/" title="iconfont 首页" target="_blank"> <h1 class="logo">
<img width="200" src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg"> <a
href="https://www.iconfont.cn/"
</a></h1> title="iconfont 首页"
target="_blank"
>
<img
width="200"
src="https://img.alicdn.com/imgextra/i3/O1CN01Mn65HV1FfSEzR6DKv_!!6000000000514-55-tps-228-59.svg"
/>
</a>
</h1>
<div class="nav-tabs"> <div class="nav-tabs">
<ul id="tabs" class="dib-box"> <ul id="tabs" class="dib-box">
<li class="dib active"><span>Unicode</span></li> <li class="dib active"><span>Unicode</span></li>
@ -47,13 +66,16 @@
<li class="dib"><span>Symbol</span></li> <li class="dib"><span>Symbol</span></li>
</ul> </ul>
<a href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2479351" target="_blank" class="nav-more">查看项目</a> <a
href="https://www.iconfont.cn/manage/index?manage_type=myprojects&projectId=2479351"
target="_blank"
class="nav-more"
>查看项目</a
>
</div> </div>
<div class="tab-container"> <div class="tab-container">
<div class="content unicode" style="display: block;"> <div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib"> <li class="dib">
<span class="icon iconfont">&#xe63e;</span> <span class="icon iconfont">&#xe63e;</span>
<div class="name">导出</div> <div class="name">导出</div>
@ -311,11 +333,10 @@
<div class="name">HTSCIT_展开2</div> <div class="name">HTSCIT_展开2</div>
<div class="code-name">&amp;#xe673;</div> <div class="code-name">&amp;#xe673;</div>
</li> </li>
</ul> </ul>
<div class="article markdown"> <div class="article markdown">
<h2 id="unicode-">Unicode 引用</h2> <h2 id="unicode-">Unicode 引用</h2>
<hr> <hr />
<p>Unicode 是字体在网页端最原始的应用方式,特点是:</p> <p>Unicode 是字体在网页端最原始的应用方式,特点是:</p>
<ul> <ul>
@ -323,10 +344,15 @@
<li>默认情况下不支持多色,直接添加多色图标会自动去色。</li> <li>默认情况下不支持多色,直接添加多色图标会自动去色。</li>
</ul> </ul>
<blockquote> <blockquote>
<p>注意:新版 iconfont 支持两种方式引用多色图标SVG symbol 引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)</p> <p>
注意:新版 iconfont 支持两种方式引用多色图标SVG symbol
引用方式和彩色字体图标模式。(使用彩色字体图标需要在「编辑项目」中开启「彩色」选项后并重新生成。)
</p>
</blockquote> </blockquote>
<p>Unicode 使用步骤如下:</p> <p>Unicode 使用步骤如下:</p>
<h3 id="-font-face">第一步:拷贝项目下面生成的 <code>@font-face</code></h3> <h3 id="-font-face">
第一步:拷贝项目下面生成的 <code>@font-face</code>
</h3>
<pre><code class="language-css" <pre><code class="language-css"
>@font-face { >@font-face {
font-family: 'iconfont'; font-family: 'iconfont';
@ -351,20 +377,21 @@
>&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt; >&lt;span class="iconfont"&gt;&amp;#x33;&lt;/span&gt;
</code></pre> </code></pre>
<blockquote> <blockquote>
<p>"iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p> <p>
"iconfont" 是你项目下的
font-family。可以通过编辑项目查看默认是 "iconfont"。
</p>
</blockquote> </blockquote>
</div> </div>
</div> </div>
<div class="content font-class"> <div class="content font-class">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib"> <li class="dib">
<span class="icon iconfont icondaochu1"></span> <span class="icon iconfont icondaochu1"></span>
<div class="name"> <div class="name">
导出 导出
</div> </div>
<div class="code-name">.icondaochu1 <div class="code-name">.icondaochu1</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -372,8 +399,7 @@
<div class="name"> <div class="name">
另存为 另存为
</div> </div>
<div class="code-name">.iconlingcunwei <div class="code-name">.iconlingcunwei</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -381,8 +407,7 @@
<div class="name"> <div class="name">
export export
</div> </div>
<div class="code-name">.iconexport <div class="code-name">.iconexport</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -390,8 +415,7 @@
<div class="name"> <div class="name">
打开 打开
</div> </div>
<div class="code-name">.icondakai <div class="code-name">.icondakai</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -399,8 +423,7 @@
<div class="name"> <div class="name">
新建 新建
</div> </div>
<div class="code-name">.iconxinjian <div class="code-name">.iconxinjian</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -408,8 +431,7 @@
<div class="name"> <div class="name">
剪切 剪切
</div> </div>
<div class="code-name">.iconjianqie <div class="code-name">.iconjianqie</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -417,8 +439,7 @@
<div class="name"> <div class="name">
整理 整理
</div> </div>
<div class="code-name">.iconzhengli <div class="code-name">.iconzhengli</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -426,8 +447,7 @@
<div class="name"> <div class="name">
复制 复制
</div> </div>
<div class="code-name">.iconfuzhi <div class="code-name">.iconfuzhi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -435,8 +455,7 @@
<div class="name"> <div class="name">
粘贴 粘贴
</div> </div>
<div class="code-name">.iconniantie <div class="code-name">.iconniantie</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -444,8 +463,7 @@
<div class="name"> <div class="name">
上移 上移
</div> </div>
<div class="code-name">.iconshangyi <div class="code-name">.iconshangyi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -453,8 +471,7 @@
<div class="name"> <div class="name">
下移 下移
</div> </div>
<div class="code-name">.iconxiayi <div class="code-name">.iconxiayi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -462,8 +479,7 @@
<div class="name"> <div class="name">
概括总览 概括总览
</div> </div>
<div class="code-name">.icongaikuozonglan <div class="code-name">.icongaikuozonglan</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -471,8 +487,7 @@
<div class="name"> <div class="name">
全选 全选
</div> </div>
<div class="code-name">.iconquanxuan <div class="code-name">.iconquanxuan</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -480,8 +495,7 @@
<div class="name"> <div class="name">
导入 导入
</div> </div>
<div class="code-name">.icondaoru <div class="code-name">.icondaoru</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -489,8 +503,7 @@
<div class="name"> <div class="name">
后退-实 后退-实
</div> </div>
<div class="code-name">.iconhoutui-shi <div class="code-name">.iconhoutui-shi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -498,8 +511,7 @@
<div class="name"> <div class="name">
前进 前进
</div> </div>
<div class="code-name">.iconqianjin1 <div class="code-name">.iconqianjin1</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -507,8 +519,7 @@
<div class="name"> <div class="name">
撤回 撤回
</div> </div>
<div class="code-name">.iconwithdraw <div class="code-name">.iconwithdraw</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -516,8 +527,7 @@
<div class="name"> <div class="name">
前进 前进
</div> </div>
<div class="code-name">.iconqianjin <div class="code-name">.iconqianjin</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -525,8 +535,7 @@
<div class="name"> <div class="name">
恢复默认 恢复默认
</div> </div>
<div class="code-name">.iconhuifumoren <div class="code-name">.iconhuifumoren</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -534,8 +543,7 @@
<div class="name"> <div class="name">
换行 换行
</div> </div>
<div class="code-name">.iconhuanhang <div class="code-name">.iconhuanhang</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -543,8 +551,7 @@
<div class="name"> <div class="name">
缩小 缩小
</div> </div>
<div class="code-name">.iconsuoxiao <div class="code-name">.iconsuoxiao</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -552,8 +559,7 @@
<div class="name"> <div class="name">
编辑 编辑
</div> </div>
<div class="code-name">.iconbianji <div class="code-name">.iconbianji</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -561,8 +567,7 @@
<div class="name"> <div class="name">
放大 放大
</div> </div>
<div class="code-name">.iconfangda <div class="code-name">.iconfangda</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -570,8 +575,7 @@
<div class="name"> <div class="name">
全屏 全屏
</div> </div>
<div class="code-name">.iconquanping1 <div class="code-name">.iconquanping1</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -579,8 +583,7 @@
<div class="name"> <div class="name">
定位 定位
</div> </div>
<div class="code-name">.icondingwei <div class="code-name">.icondingwei</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -588,8 +591,7 @@
<div class="name"> <div class="name">
导航 导航
</div> </div>
<div class="code-name">.icondaohang <div class="code-name">.icondaohang</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -597,8 +599,7 @@
<div class="name"> <div class="name">
键盘 键盘
</div> </div>
<div class="code-name">.iconjianpan <div class="code-name">.iconjianpan</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -606,8 +607,7 @@
<div class="name"> <div class="name">
全屏 全屏
</div> </div>
<div class="code-name">.iconquanping <div class="code-name">.iconquanping</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -615,8 +615,7 @@
<div class="name"> <div class="name">
导出 导出
</div> </div>
<div class="code-name">.icondaochu <div class="code-name">.icondaochu</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -624,8 +623,7 @@
<div class="name"> <div class="name">
标签 标签
</div> </div>
<div class="code-name">.iconbiaoqian <div class="code-name">.iconbiaoqian</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -633,8 +631,7 @@
<div class="name"> <div class="name">
流程-备注 流程-备注
</div> </div>
<div class="code-name">.iconflow-Mark <div class="code-name">.iconflow-Mark</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -642,8 +639,7 @@
<div class="name"> <div class="name">
超链接 超链接
</div> </div>
<div class="code-name">.iconchaolianjie <div class="code-name">.iconchaolianjie</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -651,8 +647,7 @@
<div class="name"> <div class="name">
主题 主题
</div> </div>
<div class="code-name">.iconjingzi <div class="code-name">.iconjingzi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -660,8 +655,7 @@
<div class="name"> <div class="name">
笑脸 笑脸
</div> </div>
<div class="code-name">.iconxiaolian <div class="code-name">.iconxiaolian</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -669,8 +663,7 @@
<div class="name"> <div class="name">
图 片 图 片
</div> </div>
<div class="code-name">.iconimage <div class="code-name">.iconimage</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -678,8 +671,7 @@
<div class="name"> <div class="name">
结构 结构
</div> </div>
<div class="code-name">.iconjiegou <div class="code-name">.iconjiegou</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -687,8 +679,7 @@
<div class="name"> <div class="name">
样式 样式
</div> </div>
<div class="code-name">.iconyangshi <div class="code-name">.iconyangshi</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -696,8 +687,7 @@
<div class="name"> <div class="name">
符号-大纲树 符号-大纲树
</div> </div>
<div class="code-name">.iconfuhao-dagangshu <div class="code-name">.iconfuhao-dagangshu</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -705,8 +695,7 @@
<div class="name"> <div class="name">
添加子节点 添加子节点
</div> </div>
<div class="code-name">.icontianjiazijiedian <div class="code-name">.icontianjiazijiedian</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -714,8 +703,7 @@
<div class="name"> <div class="name">
节点 节点
</div> </div>
<div class="code-name">.iconjiedian <div class="code-name">.iconjiedian</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -723,8 +711,7 @@
<div class="name"> <div class="name">
删 除 删 除
</div> </div>
<div class="code-name">.iconshanchu <div class="code-name">.iconshanchu</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -732,8 +719,7 @@
<div class="name"> <div class="name">
HTSCIT_展开 HTSCIT_展开
</div> </div>
<div class="code-name">.iconzhankai <div class="code-name">.iconzhankai</div>
</div>
</li> </li>
<li class="dib"> <li class="dib">
@ -741,37 +727,47 @@
<div class="name"> <div class="name">
HTSCIT_展开2 HTSCIT_展开2
</div> </div>
<div class="code-name">.iconzhankai1 <div class="code-name">.iconzhankai1</div>
</div>
</li> </li>
</ul> </ul>
<div class="article markdown"> <div class="article markdown">
<h2 id="font-class-">font-class 引用</h2> <h2 id="font-class-">font-class 引用</h2>
<hr> <hr />
<p>font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。</p> <p>
font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode
书写不直观,语意不明确的问题。
</p>
<p>与 Unicode 使用方式相比,具有如下特点:</p> <p>与 Unicode 使用方式相比,具有如下特点:</p>
<ul> <ul>
<li>相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。</li> <li>
<li>因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。</li> 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon
是什么。
</li>
<li>
因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class
里面的 Unicode 引用。
</li>
</ul> </ul>
<p>使用步骤如下:</p> <p>使用步骤如下:</p>
<h3 id="-fontclass-">第一步:引入项目下面生成的 fontclass 代码:</h3> <h3 id="-fontclass-">
第一步:引入项目下面生成的 fontclass 代码:
</h3>
<pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt; <pre><code class="language-html">&lt;link rel="stylesheet" href="./iconfont.css"&gt;
</code></pre> </code></pre>
<h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3> <h3 id="-">第二步:挑选相应图标并获取类名,应用于页面:</h3>
<pre><code class="language-html">&lt;span class="iconfont iconxxx"&gt;&lt;/span&gt; <pre><code class="language-html">&lt;span class="iconfont iconxxx"&gt;&lt;/span&gt;
</code></pre> </code></pre>
<blockquote> <blockquote>
<p>" <p>
iconfont" 是你项目下的 font-family。可以通过编辑项目查看默认是 "iconfont"。</p> " iconfont" 是你项目下的
font-family。可以通过编辑项目查看默认是 "iconfont"。
</p>
</blockquote> </blockquote>
</div> </div>
</div> </div>
<div class="content symbol"> <div class="content symbol">
<ul class="icon_lists dib-box"> <ul class="icon_lists dib-box">
<li class="dib"> <li class="dib">
<svg class="icon svg-icon" aria-hidden="true"> <svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icondaochu1"></use> <use xlink:href="#icondaochu1"></use>
@ -1115,17 +1111,24 @@
<div class="name">HTSCIT_展开2</div> <div class="name">HTSCIT_展开2</div>
<div class="code-name">#iconzhankai1</div> <div class="code-name">#iconzhankai1</div>
</li> </li>
</ul> </ul>
<div class="article markdown"> <div class="article markdown">
<h2 id="symbol-">Symbol 引用</h2> <h2 id="symbol-">Symbol 引用</h2>
<hr> <hr />
<p>这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a href="">文章</a> <p>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:</p> 这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇<a
href=""
>文章</a
>
这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:
</p>
<ul> <ul>
<li>支持多色图标了,不再受单色限制。</li> <li>支持多色图标了,不再受单色限制。</li>
<li>通过一些技巧,支持像字体那样,通过 <code>font-size</code>, <code>color</code> 来调整样式。</li> <li>
通过一些技巧,支持像字体那样,通过 <code>font-size</code>,
<code>color</code> 来调整样式。
</li>
<li>兼容性较差,支持 IE9+,及现代浏览器。</li> <li>兼容性较差,支持 IE9+,及现代浏览器。</li>
<li>浏览器渲染 SVG 的性能一般,还不如 png。</li> <li>浏览器渲染 SVG 的性能一般,还不如 png。</li>
</ul> </ul>
@ -1151,7 +1154,6 @@
</code></pre> </code></pre>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<script> <script>
@ -1168,7 +1170,10 @@
$('#tabs li').removeClass('active') $('#tabs li').removeClass('active')
$(this).addClass('active') $(this).addClass('active')
tabContent.hide().eq(index).fadeIn() tabContent
.hide()
.eq(index)
.fadeIn()
} }
}) })
}) })

View File

@ -1,12 +1,12 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 2479351 */ font-family: 'iconfont'; /* Project id 2479351 */
src: url('iconfont.woff2?t=1664005697217') format('woff2'), src: url('iconfont.woff2?t=1664005697217') format('woff2'),
url('iconfont.woff?t=1664005697217') format('woff'), url('iconfont.woff?t=1664005697217') format('woff'),
url('iconfont.ttf?t=1664005697217') format('truetype'); url('iconfont.ttf?t=1664005697217') format('truetype');
} }
.iconfont { .iconfont {
font-family: "iconfont" !important; font-family: 'iconfont' !important;
font-size: 16px; font-size: 16px;
font-style: normal; font-style: normal;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@ -14,174 +14,173 @@
} }
.icondaochu1:before { .icondaochu1:before {
content: "\e63e"; content: '\e63e';
} }
.iconlingcunwei:before { .iconlingcunwei:before {
content: "\e657"; content: '\e657';
} }
.iconexport:before { .iconexport:before {
content: "\e642"; content: '\e642';
} }
.icondakai:before { .icondakai:before {
content: "\ebdf"; content: '\ebdf';
} }
.iconxinjian:before { .iconxinjian:before {
content: "\e64e"; content: '\e64e';
} }
.iconjianqie:before { .iconjianqie:before {
content: "\e601"; content: '\e601';
} }
.iconzhengli:before { .iconzhengli:before {
content: "\e83b"; content: '\e83b';
} }
.iconfuzhi:before { .iconfuzhi:before {
content: "\e604"; content: '\e604';
} }
.iconniantie:before { .iconniantie:before {
content: "\e63f"; content: '\e63f';
} }
.iconshangyi:before { .iconshangyi:before {
content: "\e6be"; content: '\e6be';
} }
.iconxiayi:before { .iconxiayi:before {
content: "\e6bf"; content: '\e6bf';
} }
.icongaikuozonglan:before { .icongaikuozonglan:before {
content: "\e609"; content: '\e609';
} }
.iconquanxuan:before { .iconquanxuan:before {
content: "\f199"; content: '\f199';
} }
.icondaoru:before { .icondaoru:before {
content: "\e6a3"; content: '\e6a3';
} }
.iconhoutui-shi:before { .iconhoutui-shi:before {
content: "\e656"; content: '\e656';
} }
.iconqianjin1:before { .iconqianjin1:before {
content: "\e654"; content: '\e654';
} }
.iconwithdraw:before { .iconwithdraw:before {
content: "\e603"; content: '\e603';
} }
.iconqianjin:before { .iconqianjin:before {
content: "\e600"; content: '\e600';
} }
.iconhuifumoren:before { .iconhuifumoren:before {
content: "\e60e"; content: '\e60e';
} }
.iconhuanhang:before { .iconhuanhang:before {
content: "\e61e"; content: '\e61e';
} }
.iconsuoxiao:before { .iconsuoxiao:before {
content: "\ec13"; content: '\ec13';
} }
.iconbianji:before { .iconbianji:before {
content: "\e626"; content: '\e626';
} }
.iconfangda:before { .iconfangda:before {
content: "\e663"; content: '\e663';
} }
.iconquanping1:before { .iconquanping1:before {
content: "\e664"; content: '\e664';
} }
.icondingwei:before { .icondingwei:before {
content: "\e616"; content: '\e616';
} }
.icondaohang:before { .icondaohang:before {
content: "\e611"; content: '\e611';
} }
.iconjianpan:before { .iconjianpan:before {
content: "\e64d"; content: '\e64d';
} }
.iconquanping:before { .iconquanping:before {
content: "\e602"; content: '\e602';
} }
.icondaochu:before { .icondaochu:before {
content: "\e63d"; content: '\e63d';
} }
.iconbiaoqian:before { .iconbiaoqian:before {
content: "\e63c"; content: '\e63c';
} }
.iconflow-Mark:before { .iconflow-Mark:before {
content: "\e65b"; content: '\e65b';
} }
.iconchaolianjie:before { .iconchaolianjie:before {
content: "\e6f4"; content: '\e6f4';
} }
.iconjingzi:before { .iconjingzi:before {
content: "\e610"; content: '\e610';
} }
.iconxiaolian:before { .iconxiaolian:before {
content: "\e60f"; content: '\e60f';
} }
.iconimage:before { .iconimage:before {
content: "\e629"; content: '\e629';
} }
.iconjiegou:before { .iconjiegou:before {
content: "\e61d"; content: '\e61d';
} }
.iconyangshi:before { .iconyangshi:before {
content: "\e631"; content: '\e631';
} }
.iconfuhao-dagangshu:before { .iconfuhao-dagangshu:before {
content: "\e71f"; content: '\e71f';
} }
.icontianjiazijiedian:before { .icontianjiazijiedian:before {
content: "\e622"; content: '\e622';
} }
.iconjiedian:before { .iconjiedian:before {
content: "\e655"; content: '\e655';
} }
.iconshanchu:before { .iconshanchu:before {
content: "\e696"; content: '\e696';
} }
.iconzhankai:before { .iconzhankai:before {
content: "\e64c"; content: '\e64c';
} }
.iconzhankai1:before { .iconzhankai1:before {
content: "\e673"; content: '\e673';
} }

File diff suppressed because one or more lines are too long

View File

@ -30,21 +30,21 @@
<script> <script>
export default { export default {
name: "ImgUpload", name: 'ImgUpload',
model: { model: {
prop: "value", prop: 'value',
event: "change", event: 'change'
}, },
props: { props: {
value: { value: {
type: String, type: String,
default: "", default: ''
}, }
}, },
data() { data() {
return { return {
file: null, file: null
}; }
}, },
methods: { methods: {
/** /**
@ -53,8 +53,8 @@ export default {
* @Desc: 图片选择事件 * @Desc: 图片选择事件
*/ */
onImgUploadInputChange(e) { onImgUploadInputChange(e) {
let file = e.target.files[0]; let file = e.target.files[0]
this.selectImg(file); this.selectImg(file)
}, },
/** /**
@ -63,9 +63,9 @@ export default {
* @Desc: 拖动上传图片 * @Desc: 拖动上传图片
*/ */
onDrop(e) { onDrop(e) {
let dt = e.dataTransfer; let dt = e.dataTransfer
let file = dt.files && dt.files[0]; let file = dt.files && dt.files[0]
this.selectImg(file); this.selectImg(file)
}, },
/** /**
@ -74,12 +74,12 @@ export default {
* @Desc: 选择图片 * @Desc: 选择图片
*/ */
selectImg(file) { selectImg(file) {
this.file = file; this.file = file
let fr = new FileReader(); let fr = new FileReader()
fr.readAsDataURL(file); fr.readAsDataURL(file)
fr.onload = (e) => { fr.onload = e => {
this.$emit("change", e.target.result); this.$emit('change', e.target.result)
}; }
}, },
/** /**
@ -88,22 +88,22 @@ export default {
* @Desc: 获取图片大小 * @Desc: 获取图片大小
*/ */
getSize() { getSize() {
return new Promise((resolve, reject) => { return new Promise(resolve => {
let img = new Image(); let img = new Image()
img.src = this.value; img.src = this.value
img.onload = () => { img.onload = () => {
resolve({ resolve({
width: img.width, width: img.width,
height: img.height, height: img.height
}); })
}; }
img.onerror = (e) => { img.onerror = () => {
resolve({ resolve({
width: 0, width: 0,
height: 0, height: 0
}); })
}; }
}); })
}, },
/** /**
@ -112,13 +112,13 @@ export default {
* @Desc: 删除图片 * @Desc: 删除图片
*/ */
deleteImg() { deleteImg() {
this.$emit("change", ""); this.$emit('change', '')
this.file = null; this.file = null
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@import "./style.less"; @import './style.less';
</style> </style>

View File

@ -4,7 +4,7 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: rgba(255,255,255,.9); background-color: rgba(255, 255, 255, 0.9);
z-index: 1000; z-index: 1000;
.imgUploadPanel { .imgUploadPanel {
@ -20,7 +20,7 @@
margin-bottom: 15px; margin-bottom: 15px;
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
color: hsla(218,9%,51%,.8); color: hsla(218, 9%, 51%, 0.8);
} }
.closeBtn { .closeBtn {
@ -35,8 +35,8 @@
width: 100%; width: 100%;
height: 200px; height: 200px;
font-size: 20px; font-size: 20px;
color: rgba(51,51,51,.4); color: rgba(51, 51, 51, 0.4);
background-color: hsla(0,0%,87%,.6); background-color: hsla(0, 0%, 87%, 0.6);
border: none; border: none;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
@ -56,7 +56,7 @@
position: relative; position: relative;
width: 100%; width: 100%;
height: 200px; height: 200px;
background-color: hsla(0,0%,87%,.6); background-color: hsla(0, 0%, 87%, 0.6);
.previewBox { .previewBox {
width: 100%; width: 100%;

View File

@ -3,37 +3,48 @@ export const fontFamilyList = [
{ {
name: '宋体', name: '宋体',
value: '宋体, SimSun, Songti SC' value: '宋体, SimSun, Songti SC'
}, { },
{
name: '微软雅黑', name: '微软雅黑',
value: '微软雅黑, Microsoft YaHei' value: '微软雅黑, Microsoft YaHei'
}, { },
{
name: '楷体', name: '楷体',
value: '楷体, 楷体_GB2312, SimKai, STKaiti' value: '楷体, 楷体_GB2312, SimKai, STKaiti'
}, { },
{
name: '黑体', name: '黑体',
value: '黑体, SimHei, Heiti SC' value: '黑体, SimHei, Heiti SC'
}, { },
{
name: '隶书', name: '隶书',
value: '隶书, SimLi' value: '隶书, SimLi'
}, { },
{
name: 'Andale Mono', name: 'Andale Mono',
value: 'andale mono' value: 'andale mono'
}, { },
{
name: 'Arial', name: 'Arial',
value: 'arial, helvetica, sans-serif' value: 'arial, helvetica, sans-serif'
}, { },
{
name: 'arialBlack', name: 'arialBlack',
value: 'arial black, avant garde' value: 'arial black, avant garde'
}, { },
{
name: 'Comic Sans Ms', name: 'Comic Sans Ms',
value: 'comic sans ms' value: 'comic sans ms'
}, { },
{
name: 'Impact', name: 'Impact',
value: 'impact, chicago' value: 'impact, chicago'
}, { },
{
name: 'Times New Roman', name: 'Times New Roman',
value: 'times new roman' value: 'times new roman'
}, { },
{
name: 'Sans-Serif', name: 'Sans-Serif',
value: 'sans-serif' value: 'sans-serif'
}, },
@ -304,7 +315,7 @@ export const shortcutKeyList = [
icon: 'iconzhengli', icon: 'iconzhengli',
name: '一键整理布局', name: '一键整理布局',
value: 'Ctrl + L' value: 'Ctrl + L'
}, }
] ]
}, },
{ {

View File

@ -8,34 +8,34 @@
</template> </template>
<script> <script>
import Toolbar from "./components/Toolbar"; import Toolbar from './components/Toolbar'
import Edit from "./components/Edit"; import Edit from './components/Edit'
import { mapState, mapActions } from "vuex"; import { mapActions } from 'vuex'
export default { export default {
name: "Index", name: 'Index',
components: { components: {
Toolbar, Toolbar,
Edit, Edit
}, },
data() { data() {
return { return {
show: false, show: false
}; }
}, },
async created() { async created() {
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: "正在加载,请稍后...", text: '正在加载,请稍后...'
}); })
await this.getUserMindMapData(); await this.getUserMindMapData()
this.show = true; this.show = true
loading.close(); loading.close()
}, },
methods: { methods: {
...mapActions(["getUserMindMapData"]), ...mapActions(['getUserMindMapData'])
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -9,8 +9,8 @@
<Color <Color
:color="style.backgroundColor" :color="style.backgroundColor"
@change=" @change="
(color) => { color => {
update('backgroundColor', color); update('backgroundColor', color)
} }
" "
></Color> ></Color>
@ -20,8 +20,8 @@
class="imgUpload" class="imgUpload"
v-model="style.backgroundImage" v-model="style.backgroundImage"
@change=" @change="
(img) => { img => {
update('backgroundImage', img); update('backgroundImage', img)
} }
" "
></ImgUpload> ></ImgUpload>
@ -33,8 +33,8 @@
v-model="style.backgroundRepeat" v-model="style.backgroundRepeat"
placeholder="" placeholder=""
@change=" @change="
(value) => { value => {
update('backgroundRepeat', value); update('backgroundRepeat', value)
} }
" "
> >
@ -64,8 +64,8 @@
<Color <Color
:color="style.lineColor" :color="style.lineColor"
@change=" @change="
(color) => { color => {
update('lineColor', color); update('lineColor', color)
} }
" "
></Color> ></Color>
@ -79,8 +79,8 @@
v-model="style.lineWidth" v-model="style.lineWidth"
placeholder="" placeholder=""
@change=" @change="
(value) => { value => {
update('lineWidth', value); update('lineWidth', value)
} }
" "
> >
@ -103,8 +103,8 @@
v-model="style.lineStyle" v-model="style.lineStyle"
placeholder="" placeholder=""
@change=" @change="
(value) => { value => {
update('lineStyle', value); update('lineStyle', value)
} }
" "
> >
@ -132,8 +132,8 @@
<Color <Color
:color="style.generalizationLineColor" :color="style.generalizationLineColor"
@change=" @change="
(color) => { color => {
update('generalizationLineColor', color); update('generalizationLineColor', color)
} }
" "
></Color> ></Color>
@ -147,8 +147,8 @@
v-model="style.generalizationLineWidth" v-model="style.generalizationLineWidth"
placeholder="" placeholder=""
@change=" @change="
(value) => { value => {
update('generalizationLineWidth', value); update('generalizationLineWidth', value)
} }
" "
> >
@ -171,8 +171,8 @@
style="width: 200px" style="width: 200px"
v-model="style.paddingX" v-model="style.paddingX"
@change=" @change="
(value) => { value => {
update('paddingX', value); update('paddingX', value)
} }
" "
></el-slider> ></el-slider>
@ -185,8 +185,8 @@
style="width: 200px" style="width: 200px"
v-model="style.paddingY" v-model="style.paddingY"
@change=" @change="
(value) => { value => {
update('paddingY', value); update('paddingY', value)
} }
" "
></el-slider> ></el-slider>
@ -203,8 +203,8 @@
:min="10" :min="10"
:max="300" :max="300"
@change=" @change="
(value) => { value => {
update('imgMaxWidth', value); update('imgMaxWidth', value)
} }
" "
></el-slider> ></el-slider>
@ -219,8 +219,8 @@
:min="10" :min="10"
:max="300" :max="300"
@change=" @change="
(value) => { value => {
update('imgMaxHeight', value); update('imgMaxHeight', value)
} }
" "
></el-slider> ></el-slider>
@ -237,8 +237,8 @@
:min="12" :min="12"
:max="50" :max="50"
@change=" @change="
(value) => { value => {
update('iconSize', value); update('iconSize', value)
} }
" "
></el-slider> ></el-slider>
@ -262,8 +262,8 @@
style="width: 200px" style="width: 200px"
v-model="style.marginX" v-model="style.marginX"
@change=" @change="
(value) => { value => {
updateMargin('marginX', value); updateMargin('marginX', value)
} }
" "
></el-slider> ></el-slider>
@ -275,8 +275,8 @@
style="width: 200px" style="width: 200px"
v-model="style.marginY" v-model="style.marginY"
@change=" @change="
(value) => { value => {
updateMargin('marginY', value); updateMargin('marginY', value)
} }
" "
></el-slider> ></el-slider>
@ -287,15 +287,11 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
import Color from "./Color"; import Color from './Color'
import { import { lineWidthList, lineStyleList, backgroundRepeatList } from '@/config'
lineWidthList, import ImgUpload from '@/components/ImgUpload'
lineStyleList, import { storeConfig } from '@/api'
backgroundRepeatList
} from "@/config";
import ImgUpload from "@/components/ImgUpload";
import { storeConfig } from "@/api";
/** /**
* @Author: 王林 * @Author: 王林
@ -303,55 +299,55 @@ import { storeConfig } from "@/api";
* @Desc: 基础样式 * @Desc: 基础样式
*/ */
export default { export default {
name: "BaseStyle", name: 'BaseStyle',
components: { components: {
Sidebar, Sidebar,
Color, Color,
ImgUpload, ImgUpload
}, },
props: { props: {
data: { data: {
type: [Object, null], type: [Object, null],
default: null, default: null
}, },
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
lineWidthList, lineWidthList,
lineStyleList, lineStyleList,
backgroundRepeatList, backgroundRepeatList,
activeTab: "color", activeTab: 'color',
marginActiveTab: "second", marginActiveTab: 'second',
style: { style: {
backgroundColor: "", backgroundColor: '',
lineColor: "", lineColor: '',
lineWidth: "", lineWidth: '',
lineStyle: "", lineStyle: '',
generalizationLineWidth: "", generalizationLineWidth: '',
generalizationLineColor: "", generalizationLineColor: '',
paddingX: 0, paddingX: 0,
paddingY: 0, paddingY: 0,
imgMaxWidth: 0, imgMaxWidth: 0,
imgMaxHeight: 0, imgMaxHeight: 0,
iconSize: 0, iconSize: 0,
backgroundImage: "", backgroundImage: '',
backgroundRepeat: "no-repeat", backgroundRepeat: 'no-repeat',
marginX: 0, marginX: 0,
marginY: 0, marginY: 0
}, }
}; }
}, },
created() { created() {
this.$bus.$on("showBaseStyle", () => { this.$bus.$on('showBaseStyle', () => {
this.$refs.sidebar.show = false; this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.sidebar.show = true; this.$refs.sidebar.show = true
this.initStyle(); this.initStyle()
}); })
}); })
}, },
methods: { methods: {
/** /**
@ -360,27 +356,27 @@ export default {
* @Desc: 初始样式 * @Desc: 初始样式
*/ */
initStyle() { initStyle() {
[ ;[
"backgroundColor", 'backgroundColor',
"lineWidth", 'lineWidth',
"lineStyle", 'lineStyle',
"lineColor", 'lineColor',
"generalizationLineWidth", 'generalizationLineWidth',
"generalizationLineColor", 'generalizationLineColor',
"paddingX", 'paddingX',
"paddingY", 'paddingY',
"imgMaxWidth", 'imgMaxWidth',
"imgMaxHeight", 'imgMaxHeight',
"iconSize", 'iconSize',
"backgroundImage", 'backgroundImage',
"backgroundRepeat", 'backgroundRepeat'
].forEach((key) => { ].forEach(key => {
this.style[key] = this.mindMap.getThemeConfig(key); this.style[key] = this.mindMap.getThemeConfig(key)
if (key === "backgroundImage" && this.style[key] === "none") { if (key === 'backgroundImage' && this.style[key] === 'none') {
this.style[key] = ""; this.style[key] = ''
} }
}); })
this.initMarginStyle(); this.initMarginStyle()
}, },
/** /**
@ -389,10 +385,11 @@ export default {
* @Desc: margin初始值 * @Desc: margin初始值
*/ */
initMarginStyle() { initMarginStyle() {
["marginX", "marginY"].forEach((key) => { ;['marginX', 'marginY'].forEach(key => {
this.style[key] = this.style[key] = this.mindMap.getThemeConfig()[this.marginActiveTab][
this.mindMap.getThemeConfig()[this.marginActiveTab][key]; key
}); ]
})
}, },
/** /**
@ -401,19 +398,19 @@ export default {
* @Desc: 更新配置 * @Desc: 更新配置
*/ */
update(key, value) { update(key, value) {
if (key === "backgroundImage" && value === "none") { if (key === 'backgroundImage' && value === 'none') {
this.style[key] = ""; this.style[key] = ''
} else { } else {
this.style[key] = value; this.style[key] = value
} }
this.data.theme.config[key] = value; this.data.theme.config[key] = value
this.mindMap.setThemeConfig(this.data.theme.config); this.mindMap.setThemeConfig(this.data.theme.config)
storeConfig({ storeConfig({
theme: { theme: {
"template": this.mindMap.getTheme(), template: this.mindMap.getTheme(),
"config": this.data.theme.config config: this.data.theme.config
} }
}); })
}, },
/** /**
@ -422,15 +419,15 @@ export default {
* @Desc: 设置margin * @Desc: 设置margin
*/ */
updateMargin(type, value) { updateMargin(type, value) {
this.style[type] = value; this.style[type] = value
if (!this.data.theme.config[this.marginActiveTab]) { if (!this.data.theme.config[this.marginActiveTab]) {
this.data.theme.config[this.marginActiveTab] = {}; this.data.theme.config[this.marginActiveTab] = {}
}
this.data.theme.config[this.marginActiveTab][type] = value
this.mindMap.setThemeConfig(this.data.theme.config)
}
}
} }
this.data.theme.config[this.marginActiveTab][type] = value;
this.mindMap.setThemeConfig(this.data.theme.config);
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -21,7 +21,7 @@
</template> </template>
<script> <script>
import { colorList } from "@/config"; import { colorList } from '@/config'
/** /**
* @Author: 王林 * @Author: 王林
@ -29,26 +29,26 @@ import { colorList } from "@/config";
* @Desc: 颜色选择器 * @Desc: 颜色选择器
*/ */
export default { export default {
name: "Color", name: 'Color',
props: { props: {
color: { color: {
type: String, type: String,
default: "", default: ''
}, }
}, },
data() { data() {
return { return {
colorList, colorList,
selectColor: "", selectColor: ''
}; }
}, },
watch: { watch: {
color() { color() {
this.selectColor = this.color; this.selectColor = this.color
}, }
}, },
created() { created() {
this.selectColor = this.color; this.selectColor = this.color
}, },
methods: { methods: {
/** /**
@ -57,7 +57,7 @@ export default {
* @Desc: 点击预设颜色 * @Desc: 点击预设颜色
*/ */
clickColorItem(color) { clickColorItem(color) {
this.$emit("change", color); this.$emit('change', color)
}, },
/** /**
@ -66,10 +66,10 @@ export default {
* @Desc: 修改颜色 * @Desc: 修改颜色
*/ */
changeColor() { changeColor() {
this.$emit("change", this.selectColor); this.$emit('change', this.selectColor)
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -17,7 +17,11 @@
插入子级节点 插入子级节点
<span class="desc">Tab</span> <span class="desc">Tab</span>
</div> </div>
<div class="item" @click="exec('ADD_GENERALIZATION')" :class="{ disabled: insertNodeBtnDisabled }"> <div
class="item"
@click="exec('ADD_GENERALIZATION')"
:class="{ disabled: insertNodeBtnDisabled }"
>
插入概要 插入概要
<span class="desc">Ctrl + S</span> <span class="desc">Ctrl + S</span>
</div> </div>
@ -65,7 +69,14 @@
<div class="item"> <div class="item">
展开到 展开到
<div class="subItems listBox"> <div class="subItems listBox">
<div class="item" v-for="(item, index) in expandList" :key="item" @click="exec('UNEXPAND_TO_LEVEL', false, index + 1)">{{item}}</div> <div
class="item"
v-for="(item, index) in expandList"
:key="item"
@click="exec('UNEXPAND_TO_LEVEL', false, index + 1)"
>
{{ item }}
</div>
</div> </div>
</div> </div>
<div class="item" @click="exec('RESET_LAYOUT')"> <div class="item" @click="exec('RESET_LAYOUT')">
@ -83,11 +94,11 @@
* @Desc: 右键菜单 * @Desc: 右键菜单
*/ */
export default { export default {
name: "Contextmenu", name: 'Contextmenu',
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
@ -96,63 +107,70 @@ export default {
top: 0, top: 0,
node: null, node: null,
copyData: null, copyData: null,
type: "", type: '',
isMousedown: false, isMousedown: false,
mosuedownX: 0, mosuedownX: 0,
mosuedownY: 0, mosuedownY: 0,
expandList: ['一级主题', '二级主题', '三级主题', '四级主题', '五级主题', '六级主题'] expandList: [
}; '一级主题',
'二级主题',
'三级主题',
'四级主题',
'五级主题',
'六级主题'
]
}
}, },
computed: { computed: {
insertNodeBtnDisabled() { insertNodeBtnDisabled() {
return !this.node || this.node.isRoot; return !this.node || this.node.isRoot
}, },
upNodeBtnDisabled() { upNodeBtnDisabled() {
if (!this.node || this.node.isRoot) { if (!this.node || this.node.isRoot) {
return true; return true
} }
let isFirst = let isFirst =
this.node.parent.children.findIndex((item) => { this.node.parent.children.findIndex(item => {
return item === this.node; return item === this.node
}) === 0; }) === 0
return isFirst; return isFirst
}, },
downNodeBtnDisabled() { downNodeBtnDisabled() {
if (!this.node || this.node.isRoot) { if (!this.node || this.node.isRoot) {
return true; return true
} }
let children = this.node.parent.children; let children = this.node.parent.children
let isLast = let isLast =
children.findIndex((item) => { children.findIndex(item => {
return item === this.node; return item === this.node
}) === }) ===
children.length - 1; children.length - 1
return isLast; return isLast
}, }
}, },
created() { created() {
this.$bus.$on("node_contextmenu", this.show); this.$bus.$on('node_contextmenu', this.show)
this.$bus.$on("node_click", this.hide); this.$bus.$on('node_click', this.hide)
this.$bus.$on("draw_click", this.hide); this.$bus.$on('draw_click', this.hide)
this.$bus.$on("expand_btn_click", this.hide); this.$bus.$on('expand_btn_click', this.hide)
this.$bus.$on("svg_mousedown", this.onMousedown); this.$bus.$on('svg_mousedown', this.onMousedown)
this.$bus.$on("mouseup", this.onMouseup); this.$bus.$on('mouseup', this.onMouseup)
// //
this.mindMap.keyCommand.addShortcut('Control+c', this.copy); this.mindMap.keyCommand.addShortcut('Control+c', this.copy)
this.mindMap.keyCommand.addShortcut('Control+v', this.paste); this.mindMap.keyCommand.addShortcut('Control+v', this.paste)
this.mindMap.keyCommand.addShortcut('Control+x', this.cut); this.mindMap.keyCommand.addShortcut('Control+x', this.cut)
}, },
beforeDestroy() { beforeDestroy() {
this.$bus.$off("node_contextmenu", this.show); this.$bus.$off('node_contextmenu', this.show)
this.$bus.$off("node_click", this.hide); this.$bus.$off('node_click', this.hide)
this.$bus.$off("draw_click", this.hide); this.$bus.$off('draw_click', this.hide)
this.$bus.$off("expand_btn_click", this.hide); this.$bus.$off('expand_btn_click', this.hide)
this.$bus.$on("svg_mousedown", this.onMousedown); this.$bus.$on('svg_mousedown', this.onMousedown)
this.$bus.$on("mouseup", this.onMouseup); this.$bus.$on('mouseup', this.onMouseup)
// //
this.mindMap.keyCommand.removeShortcut('Control+c', this.copy); this.mindMap.keyCommand.removeShortcut('Control+c', this.copy)
this.mindMap.keyCommand.removeShortcut('Control+v', this.paste); this.mindMap.keyCommand.removeShortcut('Control+v', this.paste)
this.mindMap.keyCommand.removeShortcut('Control+x', this.cut); this.mindMap.keyCommand.removeShortcut('Control+x', this.cut)
}, },
methods: { methods: {
/** /**
@ -161,11 +179,11 @@ export default {
* @Desc: 节点右键显示 * @Desc: 节点右键显示
*/ */
show(e, node) { show(e, node) {
this.type = "node"; this.type = 'node'
this.left = e.clientX + 10; this.left = e.clientX + 10
this.top = e.clientY + 10; this.top = e.clientY + 10
this.isShow = true; this.isShow = true
this.node = node; this.node = node
}, },
/** /**
@ -175,11 +193,11 @@ export default {
*/ */
onMousedown(e) { onMousedown(e) {
if (e.which !== 3) { if (e.which !== 3) {
return; return
} }
this.mosuedownX = e.clientX this.mosuedownX = e.clientX
this.mosuedownY = e.clientY this.mosuedownY = e.clientY
this.isMousedown = true; this.isMousedown = true
}, },
/** /**
@ -189,12 +207,15 @@ export default {
*/ */
onMouseup(e) { onMouseup(e) {
if (!this.isMousedown) { if (!this.isMousedown) {
return; return
} }
this.isMousedown = false this.isMousedown = false
if (Math.abs(this.mosuedownX - e.clientX) > 3 || Math.abs(this.mosuedownY - e.clientY) > 3) { if (
Math.abs(this.mosuedownX - e.clientX) > 3 ||
Math.abs(this.mosuedownY - e.clientY) > 3
) {
this.hide() this.hide()
return; return
} }
this.show2(e) this.show2(e)
}, },
@ -205,10 +226,10 @@ export default {
* @Desc: 画布右键显示 * @Desc: 画布右键显示
*/ */
show2(e) { show2(e) {
this.type = "svg"; this.type = 'svg'
this.left = e.clientX + 10; this.left = e.clientX + 10
this.top = e.clientY + 10; this.top = e.clientY + 10
this.isShow = true; this.isShow = true
}, },
/** /**
@ -217,10 +238,10 @@ export default {
* @Desc: 隐藏 * @Desc: 隐藏
*/ */
hide() { hide() {
this.isShow = false; this.isShow = false
this.left = 0; this.left = 0
this.top = 0; this.top = 0
this.type = ""; this.type = ''
}, },
/** /**
@ -230,28 +251,28 @@ export default {
*/ */
exec(key, disabled, ...args) { exec(key, disabled, ...args) {
if (disabled) { if (disabled) {
return; return
} }
switch (key) { switch (key) {
case "COPY_NODE": case 'COPY_NODE':
this.copyData = this.mindMap.renderer.copyNode(); this.copyData = this.mindMap.renderer.copyNode()
break; break
case "CUT_NODE": case 'CUT_NODE':
this.$bus.$emit("execCommand", key, (copyData) => { this.$bus.$emit('execCommand', key, copyData => {
this.copyData = copyData; this.copyData = copyData
}); })
break; break
case "PASTE_NODE": case 'PASTE_NODE':
this.$bus.$emit("execCommand", key, this.copyData); this.$bus.$emit('execCommand', key, this.copyData)
break; break
case "RETURN_CENTER": case 'RETURN_CENTER':
this.mindMap.view.reset(); this.mindMap.view.reset()
break; break
default: default:
this.$bus.$emit("execCommand", key, ...args); this.$bus.$emit('execCommand', key, ...args)
break; break
} }
this.hide(); this.hide()
}, },
/** /**
@ -260,7 +281,7 @@ export default {
* @Desc: 复制 * @Desc: 复制
*/ */
copy() { copy() {
this.exec("COPY_NODE"); this.exec('COPY_NODE')
}, },
/** /**
@ -269,7 +290,7 @@ export default {
* @Desc: 粘贴 * @Desc: 粘贴
*/ */
paste() { paste() {
this.exec("PASTE_NODE"); this.exec('PASTE_NODE')
}, },
/** /**
@ -278,10 +299,10 @@ export default {
* @Desc: 剪切 * @Desc: 剪切
*/ */
cut() { cut() {
this.exec("CUT_NODE"); this.exec('CUT_NODE')
}
}
} }
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -18,20 +18,20 @@
* @Desc: 字数及节点数量统计 * @Desc: 字数及节点数量统计
*/ */
export default { export default {
name: "Count", name: 'Count',
props: {}, props: {},
data() { data() {
return { return {
words: 0, words: 0,
num: 0, num: 0
}; }
}, },
created() { created() {
this.$bus.$on("data_change", (data) => { this.$bus.$on('data_change', data => {
this.words = 0; this.words = 0
this.num = 0; this.num = 0
this.walk(data); this.walk(data)
}); })
}, },
methods: { methods: {
/** /**
@ -40,16 +40,16 @@ export default {
* @Desc: 遍历 * @Desc: 遍历
*/ */
walk(data) { walk(data) {
this.num++; this.num++
this.words += (String(data.data.text) || "").length; this.words += (String(data.data.text) || '').length
if (data.children && data.children.length > 0) { if (data.children && data.children.length > 0) {
data.children.forEach((item) => { data.children.forEach(item => {
this.walk(item); this.walk(item)
}); })
}
}
}
} }
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -68,11 +68,11 @@ export default {
this.$bus.$on('export', this.export) this.$bus.$on('export', this.export)
this.$bus.$on('setData', this.setData) this.$bus.$on('setData', this.setData)
this.$bus.$on('startTextEdit', () => { this.$bus.$on('startTextEdit', () => {
this.mindMap.renderer.startTextEdit(); this.mindMap.renderer.startTextEdit()
}); })
this.$bus.$on('endTextEdit', () => { this.$bus.$on('endTextEdit', () => {
this.mindMap.renderer.endTextEdit(); this.mindMap.renderer.endTextEdit()
}); })
if (this.openTest) { if (this.openTest) {
setTimeout(() => { setTimeout(() => {
this.test() this.test()
@ -88,7 +88,7 @@ export default {
test() { test() {
let nodeData = { let nodeData = {
data: { text: '根节点', expand: true, isActive: false }, data: { text: '根节点', expand: true, isActive: false },
children: [], children: []
} }
setTimeout(() => { setTimeout(() => {
nodeData.data.text = '理想青年实验室' nodeData.data.text = '理想青年实验室'
@ -97,25 +97,67 @@ export default {
setTimeout(() => { setTimeout(() => {
nodeData.children.push({ nodeData.children.push({
data: { text: '网站', expand: true, isActive: false }, data: { text: '网站', expand: true, isActive: false },
children: [], children: []
}) })
this.mindMap.setData(JSON.parse(JSON.stringify(nodeData))) this.mindMap.setData(JSON.parse(JSON.stringify(nodeData)))
setTimeout(() => { setTimeout(() => {
nodeData.children.push({ nodeData.children.push({
data: { text: '博客', expand: true, isActive: false }, data: { text: '博客', expand: true, isActive: false },
children: [], children: []
}) })
this.mindMap.setData(JSON.parse(JSON.stringify(nodeData))) this.mindMap.setData(JSON.parse(JSON.stringify(nodeData)))
setTimeout(() => { setTimeout(() => {
let viewData = {"transform":{"scaleX":1,"scaleY":1,"shear":0,"rotate":0,"translateX":179,"translateY":0,"originX":0,"originY":0,"a":1,"b":0,"c":0,"d":1,"e":179,"f":0},"state":{"scale":1,"x":179,"y":0,"sx":0,"sy":0}} let viewData = {
transform: {
scaleX: 1,
scaleY: 1,
shear: 0,
rotate: 0,
translateX: 179,
translateY: 0,
originX: 0,
originY: 0,
a: 1,
b: 0,
c: 0,
d: 1,
e: 179,
f: 0
},
state: { scale: 1, x: 179, y: 0, sx: 0, sy: 0 }
}
this.mindMap.view.setTransformData(viewData) this.mindMap.view.setTransformData(viewData)
setTimeout(() => { setTimeout(() => {
let viewData = {"transform":{"scaleX":1.6000000000000005,"scaleY":1.6000000000000005,"shear":0,"rotate":0,"translateX":-373.3000000000004,"translateY":-281.10000000000025,"originX":0,"originY":0,"a":1.6000000000000005,"b":0,"c":0,"d":1.6000000000000005,"e":-373.3000000000004,"f":-281.10000000000025},"state":{"scale":1.6000000000000005,"x":179,"y":0,"sx":0,"sy":0}} let viewData = {
transform: {
scaleX: 1.6000000000000005,
scaleY: 1.6000000000000005,
shear: 0,
rotate: 0,
translateX: -373.3000000000004,
translateY: -281.10000000000025,
originX: 0,
originY: 0,
a: 1.6000000000000005,
b: 0,
c: 0,
d: 1.6000000000000005,
e: -373.3000000000004,
f: -281.10000000000025
},
state: {
scale: 1.6000000000000005,
x: 179,
y: 0,
sx: 0,
sy: 0
}
}
this.mindMap.view.setTransformData(viewData) this.mindMap.view.setTransformData(viewData)
}, 1000); }, 1000)
}, 1000) }, 1000)
}, 1000) }, 1000)
}, 1000) }, 1000)
@ -141,12 +183,12 @@ export default {
if (this.openTest) { if (this.openTest) {
return return
} }
this.$bus.$on('data_change', (data) => { this.$bus.$on('data_change', data => {
storeData(data) storeData(data)
}) })
this.$bus.$on('view_data_change', (data) => { this.$bus.$on('view_data_change', data => {
storeConfig({ storeConfig({
view: data, view: data
}) })
}) })
}, },
@ -180,10 +222,10 @@ export default {
viewData: view, viewData: view,
customNoteContentShow: { customNoteContentShow: {
show: (content, left, top) => { show: (content, left, top) => {
this.$bus.$emit('showNoteContent', content, left, top); this.$bus.$emit('showNoteContent', content, left, top)
}, },
hide: () => { hide: () => {
this.$bus.$emit('hideNoteContent'); this.$bus.$emit('hideNoteContent')
} }
} }
}) })
@ -204,7 +246,7 @@ export default {
'mouseup', 'mouseup',
'mode_change', 'mode_change',
'node_tree_render_end' 'node_tree_render_end'
].forEach((event) => { ].forEach(event => {
this.mindMap.on(event, (...args) => { this.mindMap.on(event, (...args) => {
this.$bus.$emit(event, ...args) this.$bus.$emit(event, ...args)
}) })
@ -255,8 +297,8 @@ export default {
} catch (error) { } catch (error) {
console.log(error) console.log(error)
} }
}, }
}, }
} }
</script> </script>

View File

@ -8,8 +8,17 @@
<div> <div>
<div class="nameInputBox"> <div class="nameInputBox">
<span class="name">导出文件名称</span> <span class="name">导出文件名称</span>
<el-input style="width: 300px" v-model="fileName" size="mini"></el-input> <el-input
<el-checkbox v-show="['smm', 'json'].includes(exportType)" v-model="widthConfig" style="margin-left: 12px">是否包含主题结构等配置数据</el-checkbox> style="width: 300px"
v-model="fileName"
size="mini"
></el-input>
<el-checkbox
v-show="['smm', 'json'].includes(exportType)"
v-model="widthConfig"
style="margin-left: 12px"
>是否包含主题结构等配置数据</el-checkbox
>
</div> </div>
<el-radio-group v-model="exportType" size="mini"> <el-radio-group v-model="exportType" size="mini">
<el-radio-button label="smm">专有文件.smm</el-radio-button> <el-radio-button label="smm">专有文件.smm</el-radio-button>
@ -34,19 +43,19 @@
* @Desc: 导出 * @Desc: 导出
*/ */
export default { export default {
name: "Export", name: 'Export',
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
exportType: "smm", exportType: 'smm',
fileName: '思维导图', fileName: '思维导图',
widthConfig: true widthConfig: true
}; }
}, },
created() { created() {
this.$bus.$on("showExport", () => { this.$bus.$on('showExport', () => {
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -55,7 +64,7 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
}, },
/** /**
@ -64,15 +73,21 @@ export default {
* @Desc: 确定 * @Desc: 确定
*/ */
confirm() { confirm() {
this.$bus.$emit("export", this.exportType, true, this.fileName, this.widthConfig); this.$bus.$emit(
'export',
this.exportType,
true,
this.fileName,
this.widthConfig
)
this.$notify.info({ this.$notify.info({
title: '消息', title: '消息',
message: '如果没有触发下载,请检查是否被浏览器拦截了' message: '如果没有触发下载,请检查是否被浏览器拦截了'
}); })
this.cancel(); this.cancel()
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -7,7 +7,7 @@
</template> </template>
<script> <script>
import { fullscrrenEvent, fullScreen } from "@/utils"; import { fullscrrenEvent, fullScreen } from '@/utils'
/** /**
* @Author: 王林 * @Author: 王林
@ -15,27 +15,21 @@ import { fullscrrenEvent, fullScreen } from "@/utils";
* @Desc: 全屏 * @Desc: 全屏
*/ */
export default { export default {
name: "Fullscreen", name: 'Fullscreen',
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
},
},
data() {
return {};
},
watch: {
mindMap(val, oldVal) {
if (val && !oldVal) {
} }
}, },
data() {
return {}
}, },
created() { created() {
document[fullscrrenEvent] = (e) => { document[fullscrrenEvent] = () => {
setTimeout(() => { setTimeout(() => {
this.mindMap.resize(); this.mindMap.resize()
}, 1000); }, 1000)
}; }
}, },
methods: { methods: {
/** /**
@ -44,10 +38,10 @@ export default {
* @Desc: 准备全屏 * @Desc: 准备全屏
*/ */
toFullscreen() { toFullscreen() {
fullScreen(this.mindMap.el); fullScreen(this.mindMap.el)
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -1,6 +1,20 @@
<template> <template>
<el-dialog class="nodeDialog" title="导入" :visible.sync="dialogVisible" width="300px"> <el-dialog
<el-upload ref="upload" action="x" :file-list="fileList" :auto-upload="false" :multiple="false" :on-change="onChange" :limit="1" :on-exceed="onExceed"> class="nodeDialog"
title="导入"
:visible.sync="dialogVisible"
width="300px"
>
<el-upload
ref="upload"
action="x"
:file-list="fileList"
:auto-upload="false"
:multiple="false"
:on-change="onChange"
:limit="1"
:on-exceed="onExceed"
>
<el-button slot="trigger" size="small" type="primary">选取文件</el-button> <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
<div slot="tip" class="el-upload__tip">支持.smm.json.xmind文件</div> <div slot="tip" class="el-upload__tip">支持.smm.json.xmind文件</div>
</el-upload> </el-upload>
@ -20,24 +34,24 @@ import MindMap from 'simple-mind-map'
* @Desc: 导入 * @Desc: 导入
*/ */
export default { export default {
name: "Import", name: 'Import',
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
fileList: [], fileList: []
}; }
}, },
watch: { watch: {
dialogVisible(val, oldVal) { dialogVisible(val, oldVal) {
if (!val && oldVal) { if (!val && oldVal) {
this.fileList = []; this.fileList = []
}
} }
}, },
},
created() { created() {
this.$bus.$on("showImport", () => { this.$bus.$on('showImport', () => {
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -46,10 +60,10 @@ export default {
* @Desc: 文件选择 * @Desc: 文件选择
*/ */
onChange(file) { onChange(file) {
let reg = /\.(smm|xmind|json)$/; let reg = /\.(smm|xmind|json)$/
if (!reg.test(file.name)) { if (!reg.test(file.name)) {
this.$message.error("请选择.smm、.json、.xmind文件"); this.$message.error('请选择.smm、.json、.xmind文件')
this.fileList = []; this.fileList = []
} else { } else {
this.fileList.push(file) this.fileList.push(file)
} }
@ -61,7 +75,7 @@ export default {
* @Desc: 数量超出限制 * @Desc: 数量超出限制
*/ */
onExceed() { onExceed() {
this.$message.error("最多只能选择一个文件"); this.$message.error('最多只能选择一个文件')
}, },
/** /**
@ -70,7 +84,7 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
}, },
/** /**
@ -80,32 +94,32 @@ export default {
*/ */
confirm() { confirm() {
if (this.fileList.length <= 0) { if (this.fileList.length <= 0) {
return this.$message.error("请选择要导入的文件"); return this.$message.error('请选择要导入的文件')
} }
this.$store.commit('setIsHandleLocalFile', false); this.$store.commit('setIsHandleLocalFile', false)
let file = this.fileList[0]; let file = this.fileList[0]
if (/\.(smm|json)$/.test(file.name)) { if (/\.(smm|json)$/.test(file.name)) {
this.handleSmm(file) this.handleSmm(file)
} else if (/\.xmind$/.test(file.name)) { } else if (/\.xmind$/.test(file.name)) {
this.handleXmind(file) this.handleXmind(file)
} }
this.cancel(); this.cancel()
}, },
handleSmm(file) { handleSmm(file) {
let fileReader = new FileReader() let fileReader = new FileReader()
fileReader.readAsText(file.raw) fileReader.readAsText(file.raw)
fileReader.onload = (evt) => { fileReader.onload = evt => {
try { try {
let data = JSON.parse(evt.target.result) let data = JSON.parse(evt.target.result)
if (typeof data !== 'object') { if (typeof data !== 'object') {
throw new Error('文件内容有误') throw new Error('文件内容有误')
} }
this.$bus.$emit('setData', data) this.$bus.$emit('setData', data)
this.$message.success("导入成功"); this.$message.success('导入成功')
} catch (error) { } catch (error) {
console.log(error) console.log(error)
this.$message.error("文件解析失败"); this.$message.error('文件解析失败')
} }
} }
}, },
@ -114,16 +128,17 @@ export default {
try { try {
let data = await MindMap.xmind.parseXmindFile(file.raw) let data = await MindMap.xmind.parseXmindFile(file.raw)
this.$bus.$emit('setData', data) this.$bus.$emit('setData', data)
this.$message.success("导入成功"); this.$message.success('导入成功')
} catch (error) { } catch (error) {
console.log(error) console.log(error)
this.$message.error("文件解析失败"); this.$message.error('文件解析失败')
}
}
} }
} }
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.nodeDialog {} .nodeDialog {
}
</style> </style>

View File

@ -13,7 +13,7 @@
:style="{ :style="{
transform: `scale(${svgBoxScale})`, transform: `scale(${svgBoxScale})`,
left: svgBoxLeft + 'px', left: svgBoxLeft + 'px',
top: svgBoxTop + 'px', top: svgBoxTop + 'px'
}" }"
></div> ></div>
<div class="windowBox" :style="viewBoxStyle"></div> <div class="windowBox" :style="viewBoxStyle"></div>
@ -24,8 +24,8 @@
export default { export default {
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
@ -40,47 +40,47 @@ export default {
left: 0, left: 0,
top: 0, top: 0,
bottom: 0, bottom: 0,
right: 0, right: 0
}, }
}; }
}, },
mounted() { mounted() {
this.$bus.$on("toggle_mini_map", this.toggle_mini_map); this.$bus.$on('toggle_mini_map', this.toggle_mini_map)
this.$bus.$on("data_change", this.data_change); this.$bus.$on('data_change', this.data_change)
this.$bus.$on("view_data_change", this.data_change); this.$bus.$on('view_data_change', this.data_change)
this.$bus.$on("node_tree_render_end", this.data_change); this.$bus.$on('node_tree_render_end', this.data_change)
}, },
destroyed() { destroyed() {
this.$bus.$off("toggle_mini_map", this.toggle_mini_map); this.$bus.$off('toggle_mini_map', this.toggle_mini_map)
this.$bus.$off("data_change", this.data_change); this.$bus.$off('data_change', this.data_change)
this.$bus.$off("view_data_change", this.data_change); this.$bus.$off('view_data_change', this.data_change)
this.$bus.$off("node_tree_render_end", this.data_change); this.$bus.$off('node_tree_render_end', this.data_change)
}, },
methods: { methods: {
toggle_mini_map(show) { toggle_mini_map(show) {
this.showMiniMap = show; this.showMiniMap = show
this.$nextTick(() => { this.$nextTick(() => {
if (this.$refs.navigatorBox) { if (this.$refs.navigatorBox) {
this.init(); this.init()
} }
if (this.$refs.svgBox) { if (this.$refs.svgBox) {
this.drawMiniMap(); this.drawMiniMap()
} }
}); })
}, },
data_change() { data_change() {
if (!this.showMiniMap) { if (!this.showMiniMap) {
return; return
} }
clearTimeout(this.timer); clearTimeout(this.timer)
this.timer = setTimeout(() => { this.timer = setTimeout(() => {
this.drawMiniMap(); this.drawMiniMap()
}, 500); }, 500)
}, },
init() { init() {
let { width, height } = this.$refs.navigatorBox.getBoundingClientRect(); let { width, height } = this.$refs.navigatorBox.getBoundingClientRect()
this.boxWidth = width; this.boxWidth = width
this.boxHeight = height; this.boxHeight = height
}, },
drawMiniMap() { drawMiniMap() {
@ -89,32 +89,29 @@ export default {
viewBoxStyle, viewBoxStyle,
miniMapBoxScale, miniMapBoxScale,
miniMapBoxLeft, miniMapBoxLeft,
miniMapBoxTop, miniMapBoxTop
} = this.mindMap.miniMap.calculationMiniMap( } = this.mindMap.miniMap.calculationMiniMap(this.boxWidth, this.boxHeight)
this.boxWidth,
this.boxHeight
);
// //
this.$refs.svgBox.innerHTML = svgHTML; this.$refs.svgBox.innerHTML = svgHTML
this.viewBoxStyle = viewBoxStyle; this.viewBoxStyle = viewBoxStyle
this.svgBoxScale = miniMapBoxScale; this.svgBoxScale = miniMapBoxScale
this.svgBoxLeft = miniMapBoxLeft; this.svgBoxLeft = miniMapBoxLeft
this.svgBoxTop = miniMapBoxTop; this.svgBoxTop = miniMapBoxTop
}, },
onMousedown(e) { onMousedown(e) {
this.mindMap.miniMap.onMousedown(e); this.mindMap.miniMap.onMousedown(e)
}, },
onMousemove(e) { onMousemove(e) {
this.mindMap.miniMap.onMousemove(e); this.mindMap.miniMap.onMousemove(e)
}, },
onMouseup(e) { onMouseup(e) {
this.mindMap.miniMap.onMouseup(e); this.mindMap.miniMap.onMouseup(e)
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -1,7 +1,9 @@
<template> <template>
<div class="navigatorContainer"> <div class="navigatorContainer">
<div class="item"> <div class="item">
<el-checkbox v-model="openMiniMap" @change="toggleMiniMap">开启小地图</el-checkbox> <el-checkbox v-model="openMiniMap" @change="toggleMiniMap"
>开启小地图</el-checkbox
>
</div> </div>
<div class="item"> <div class="item">
<el-switch <el-switch
@ -22,8 +24,8 @@
</template> </template>
<script> <script>
import Scale from "./Scale"; import Scale from './Scale'
import Fullscreen from "./Fullscreen"; import Fullscreen from './Fullscreen'
/** /**
* @Author: 王林 * @Author: 王林
@ -31,15 +33,15 @@ import Fullscreen from "./Fullscreen";
* @Desc: 导航器工具栏 * @Desc: 导航器工具栏
*/ */
export default { export default {
name: "NavigatorToolbar", name: 'NavigatorToolbar',
components: { components: {
Scale, Scale,
Fullscreen, Fullscreen
}, },
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
@ -59,7 +61,7 @@ export default {
this.$bus.$emit('toggle_mini_map', show) this.$bus.$emit('toggle_mini_map', show)
} }
} }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -31,32 +31,32 @@
* @Desc: 节点超链接内容设置 * @Desc: 节点超链接内容设置
*/ */
export default { export default {
name: "NodeHyperlink", name: 'NodeHyperlink',
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
link: "", link: '',
linkTitle: "", linkTitle: '',
activeNodes: [], activeNodes: []
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.activeNodes.length > 0) { if (this.activeNodes.length > 0) {
let firstNode = this.activeNodes[0]; let firstNode = this.activeNodes[0]
this.link = firstNode.getData("hyperlink"); this.link = firstNode.getData('hyperlink')
this.linkTitle = firstNode.getData("hyperlinkTitle"); this.linkTitle = firstNode.getData('hyperlinkTitle')
} else { } else {
this.link = ""; this.link = ''
this.linkTitle = ""; this.linkTitle = ''
} }
}); })
this.$bus.$on("showNodeLink", () => { this.$bus.$on('showNodeLink', () => {
this.activeNodes[0].mindMap.keyCommand.pause(); this.activeNodes[0].mindMap.keyCommand.pause()
this.$bus.$emit('startTextEdit'); this.$bus.$emit('startTextEdit')
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -65,9 +65,9 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
this.activeNodes[0].mindMap.keyCommand.recovery(); this.activeNodes[0].mindMap.keyCommand.recovery()
this.$bus.$emit('endTextEdit'); this.$bus.$emit('endTextEdit')
}, },
/** /**
@ -76,13 +76,13 @@ export default {
* @Desc: 确定 * @Desc: 确定
*/ */
confirm() { confirm() {
this.activeNodes.forEach((node) => { this.activeNodes.forEach(node => {
node.setHyperlink(this.link, this.linkTitle); node.setHyperlink(this.link, this.linkTitle)
this.cancel(); this.cancel()
}); })
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -24,7 +24,7 @@
</template> </template>
<script> <script>
import { nodeIconList } from "simple-mind-map/src/svg/icons"; import { nodeIconList } from 'simple-mind-map/src/svg/icons'
/** /**
* @Author: 王林 * @Author: 王林
@ -32,28 +32,28 @@ import { nodeIconList } from "simple-mind-map/src/svg/icons";
* @Desc: 节点图标内容设置 * @Desc: 节点图标内容设置
*/ */
export default { export default {
name: "NodeIcon", name: 'NodeIcon',
data() { data() {
return { return {
nodeIconList, nodeIconList,
dialogVisible: false, dialogVisible: false,
iconList: [], iconList: [],
activeNodes: [], activeNodes: []
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.activeNodes.length > 0) { if (this.activeNodes.length > 0) {
let firstNode = this.activeNodes[0]; let firstNode = this.activeNodes[0]
this.iconList = firstNode.getData("icon") || []; this.iconList = firstNode.getData('icon') || []
} else { } else {
this.iconList = []; this.iconList = []
} }
}); })
this.$bus.$on("showNodeIcon", () => { this.$bus.$on('showNodeIcon', () => {
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -62,31 +62,31 @@ export default {
* @Desc: 设置icon * @Desc: 设置icon
*/ */
setIcon(type, name) { setIcon(type, name) {
let key = type + "_" + name; let key = type + '_' + name
let index = this.iconList.findIndex((item) => { let index = this.iconList.findIndex(item => {
return item === key; return item === key
}); })
// icon // icon
if (index !== -1) { if (index !== -1) {
this.iconList.splice(index, 1); this.iconList.splice(index, 1)
} else { } else {
let typeIndex = this.iconList.findIndex((item) => { let typeIndex = this.iconList.findIndex(item => {
return item.split("_")[0] === type; return item.split('_')[0] === type
}); })
// icon // icon
if (typeIndex !== -1) { if (typeIndex !== -1) {
this.iconList.splice(typeIndex, 1, key); this.iconList.splice(typeIndex, 1, key)
} else { } else {
// icon // icon
this.iconList.push(key); this.iconList.push(key)
}
}
this.activeNodes.forEach(node => {
node.setIcon([...this.iconList])
})
}
} }
} }
this.activeNodes.forEach((node) => {
node.setIcon([...this.iconList]);
});
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -128,7 +128,7 @@ export default {
width: 28px; width: 28px;
height: 28px; height: 28px;
border-radius: 50%; border-radius: 50%;
border: 2px solid #409EFF; border: 2px solid #409eff;
} }
} }
} }

View File

@ -18,7 +18,7 @@
</template> </template>
<script> <script>
import ImgUpload from "@/components/ImgUpload"; import ImgUpload from '@/components/ImgUpload'
/** /**
* @Author: 王林 * @Author: 王林
@ -26,33 +26,33 @@ import ImgUpload from "@/components/ImgUpload";
* @Desc: 节点图片内容设置 * @Desc: 节点图片内容设置
*/ */
export default { export default {
name: "NodeImage", name: 'NodeImage',
components: { components: {
ImgUpload, ImgUpload
}, },
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
img: "", img: '',
imgTitle: "", imgTitle: '',
activeNodes: null, activeNodes: null
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.activeNodes.length > 0) { if (this.activeNodes.length > 0) {
let firstNode = this.activeNodes[0]; let firstNode = this.activeNodes[0]
this.img = firstNode.getData("image"); this.img = firstNode.getData('image')
this.imgTitle = firstNode.getData("imageTitle"); this.imgTitle = firstNode.getData('imageTitle')
} else { } else {
this.img = ""; this.img = ''
this.imgTitle = ""; this.imgTitle = ''
} }
}); })
this.$bus.$on("showNodeImage", () => { this.$bus.$on('showNodeImage', () => {
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -61,7 +61,7 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
}, },
/** /**
@ -71,22 +71,22 @@ export default {
*/ */
async confirm() { async confirm() {
try { try {
let { width, height } = await this.$refs.ImgUpload.getSize(); let { width, height } = await this.$refs.ImgUpload.getSize()
this.activeNodes.forEach((node) => { this.activeNodes.forEach(node => {
node.setImage({ node.setImage({
url: this.img || "none", url: this.img || 'none',
title: this.imgTitle, title: this.imgTitle,
width, width,
height, height
}); })
}); })
this.cancel(); this.cancel()
} catch (error) { } catch (error) {
console.log(error); console.log(error)
}
}
}
} }
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -10,32 +10,32 @@ export default {
mindMap: { mindMap: {
type: Object, type: Object,
default() { default() {
return null; return null
}, }
}, }
}, },
data() { data() {
return { return {
images: [], images: []
}; }
}, },
mounted() { mounted() {
this.mindMap.on("node_img_dblclick", this.onNodeTmgDblclick); this.mindMap.on('node_img_dblclick', this.onNodeTmgDblclick)
}, },
beforeDestroy() { beforeDestroy() {
this.mindMap.off("node_img_dblclick", this.onNodeTmgDblclick); this.mindMap.off('node_img_dblclick', this.onNodeTmgDblclick)
}, },
methods: { methods: {
onNodeTmgDblclick(node, e) { onNodeTmgDblclick(node, e) {
e.stopPropagation(); e.stopPropagation()
e.preventDefault(); e.preventDefault()
this.images = [node.nodeData.data.image]; this.images = [node.nodeData.data.image]
this.$viewerApi({ this.$viewerApi({
images: this.images, images: this.images
}); })
}, }
}, }
}; }
</script> </script>
<style></style> <style></style>

View File

@ -22,8 +22,8 @@
</template> </template>
<script> <script>
import Editor from '@toast-ui/editor'; import Editor from '@toast-ui/editor'
import '@toast-ui/editor/dist/toastui-editor.css'; // Editor's Style import '@toast-ui/editor/dist/toastui-editor.css' // Editor's Style
/** /**
* @Author: 王林 * @Author: 王林
@ -31,32 +31,32 @@ import '@toast-ui/editor/dist/toastui-editor.css'; // Editor's Style
* @Desc: 节点备注内容设置 * @Desc: 节点备注内容设置
*/ */
export default { export default {
name: "NodeNote", name: 'NodeNote',
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
note: "", note: '',
activeNodes: [], activeNodes: [],
editor: null editor: null
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.activeNodes.length > 0) { if (this.activeNodes.length > 0) {
let firstNode = this.activeNodes[0]; let firstNode = this.activeNodes[0]
this.note = firstNode.getData("note"); this.note = firstNode.getData('note')
} else { } else {
this.note = ""; this.note = ''
} }
}); })
this.$bus.$on("showNodeNote", () => { this.$bus.$on('showNodeNote', () => {
this.$bus.$emit('startTextEdit'); this.$bus.$emit('startTextEdit')
this.dialogVisible = true; this.dialogVisible = true
this.$nextTick(() => { this.$nextTick(() => {
this.initEditor(); this.initEditor()
}); })
}); })
}, },
methods: { methods: {
/** /**
@ -71,9 +71,9 @@ export default {
height: '500px', height: '500px',
initialEditType: 'markdown', initialEditType: 'markdown',
previewStyle: 'vertical' previewStyle: 'vertical'
}); })
} }
this.editor.setMarkdown(this.note); this.editor.setMarkdown(this.note)
}, },
/** /**
@ -82,8 +82,8 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
this.$bus.$emit('endTextEdit'); this.$bus.$emit('endTextEdit')
}, },
/** /**
@ -92,14 +92,14 @@ export default {
* @Desc: 确定 * @Desc: 确定
*/ */
confirm() { confirm() {
this.note = this.editor.getMarkdown(); this.note = this.editor.getMarkdown()
this.activeNodes.forEach((node) => { this.activeNodes.forEach(node => {
node.setNote(this.note); node.setNote(this.note)
}); })
this.cancel(); this.cancel()
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -2,13 +2,17 @@
<div <div
class="noteContentViewer" class="noteContentViewer"
ref="noteContentViewer" ref="noteContentViewer"
:style="{ left: this.left + 'px', top: this.top + 'px', visibility: show ? 'visible' : 'hidden' }" :style="{
left: this.left + 'px',
top: this.top + 'px',
visibility: show ? 'visible' : 'hidden'
}"
></div> ></div>
</template> </template>
<script> <script>
import Viewer from '@toast-ui/editor/dist/toastui-editor-viewer'; import Viewer from '@toast-ui/editor/dist/toastui-editor-viewer'
import '@toast-ui/editor/dist/toastui-editor-viewer.css'; import '@toast-ui/editor/dist/toastui-editor-viewer.css'
/** /**
* @Author: 王林 * @Author: 王林
@ -16,28 +20,28 @@ import '@toast-ui/editor/dist/toastui-editor-viewer.css';
* @Desc: 节点备注内容显示 * @Desc: 节点备注内容显示
*/ */
export default { export default {
name: "NodeNoteContentShow", name: 'NodeNoteContentShow',
data() { data() {
return { return {
editor: null, editor: null,
show: false, show: false,
left: 0, left: 0,
top: 0, top: 0
}; }
}, },
created() { created() {
this.$bus.$on("showNoteContent", (content, left, top) => { this.$bus.$on('showNoteContent', (content, left, top) => {
this.editor.setMarkdown(content); this.editor.setMarkdown(content)
this.left = left; this.left = left
this.top = top; this.top = top
this.show = true; this.show = true
}); })
this.$bus.$on("hideNoteContent", () => { this.$bus.$on('hideNoteContent', () => {
this.show = false; this.show = false
}); })
}, },
mounted() { mounted() {
this.initEditor(); this.initEditor()
}, },
methods: { methods: {
/** /**
@ -49,11 +53,11 @@ export default {
if (!this.editor) { if (!this.editor) {
this.editor = new Viewer({ this.editor = new Viewer({
el: this.$refs.noteContentViewer el: this.$refs.noteContentViewer
}); })
}
}
}
} }
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -19,7 +19,7 @@
:key="index" :key="index"
:style="{ :style="{
backgroundColor: tagColorList[index].background, backgroundColor: tagColorList[index].background,
color: tagColorList[index].color, color: tagColorList[index].color
}" }"
> >
{{ item }} {{ item }}
@ -36,7 +36,7 @@
</template> </template>
<script> <script>
import { tagColorList } from "simple-mind-map/src/utils/constant"; import { tagColorList } from 'simple-mind-map/src/utils/constant'
/** /**
* @Author: 王林 * @Author: 王林
@ -44,32 +44,32 @@ import { tagColorList } from "simple-mind-map/src/utils/constant";
* @Desc: 节点标签内容设置 * @Desc: 节点标签内容设置
*/ */
export default { export default {
name: "NodeTag", name: 'NodeTag',
data() { data() {
return { return {
dialogVisible: false, dialogVisible: false,
tagColorList, tagColorList,
tagArr: [], tagArr: [],
tag: "", tag: '',
activeNodes: [], activeNodes: [],
max: 5, max: 5
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.activeNodes.length > 0) { if (this.activeNodes.length > 0) {
let firstNode = this.activeNodes[0]; let firstNode = this.activeNodes[0]
this.tagArr = firstNode.getData("tag") || []; this.tagArr = firstNode.getData('tag') || []
} else { } else {
this.tagArr = []; this.tagArr = []
this.tag = ""; this.tag = ''
} }
}); })
this.$bus.$on("showNodeTag", () => { this.$bus.$on('showNodeTag', () => {
this.$bus.$emit('startTextEdit'); this.$bus.$emit('startTextEdit')
this.dialogVisible = true; this.dialogVisible = true
}); })
}, },
methods: { methods: {
/** /**
@ -78,8 +78,8 @@ export default {
* @Desc: 添加 * @Desc: 添加
*/ */
add() { add() {
this.tagArr.push(this.tag); this.tagArr.push(this.tag)
this.tag = ""; this.tag = ''
}, },
/** /**
@ -88,7 +88,7 @@ export default {
* @Desc: 删除 * @Desc: 删除
*/ */
del(index) { del(index) {
this.tagArr.splice(index, 1); this.tagArr.splice(index, 1)
}, },
/** /**
@ -97,8 +97,8 @@ export default {
* @Desc: 取消 * @Desc: 取消
*/ */
cancel() { cancel() {
this.dialogVisible = false; this.dialogVisible = false
this.$bus.$emit('endTextEdit'); this.$bus.$emit('endTextEdit')
}, },
/** /**
@ -107,13 +107,13 @@ export default {
* @Desc: 确定 * @Desc: 确定
*/ */
confirm() { confirm() {
this.activeNodes.forEach((node) => { this.activeNodes.forEach(node => {
node.setTag(this.tagArr); node.setTag(this.tagArr)
}); })
this.cancel(); this.cancel()
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
/** /**
* @Author: 王林 * @Author: 王林
@ -13,33 +13,32 @@ import Sidebar from "./Sidebar";
* @Desc: 大纲内容 * @Desc: 大纲内容
*/ */
export default { export default {
name: "Outline", name: 'Outline',
components: { components: {
Sidebar, Sidebar
}, },
data() { data() {
return { return {
data: [], data: [],
defaultProps: { defaultProps: {
label(data) { label(data) {
return data.data.text; return data.data.text
}, }
}, }
}; }
}, },
created() { created() {
this.$bus.$on("data_change", (data) => { this.$bus.$on('data_change', data => {
this.data = [data]; this.data = [data]
}); })
this.$bus.$on("showOutline", () => { this.$bus.$on('showOutline', () => {
this.$refs.sidebar.show = false; this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.sidebar.show = true; this.$refs.sidebar.show = true
}); })
}); })
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped></style>
</style>

View File

@ -17,26 +17,26 @@
* @Desc: 放大缩小 * @Desc: 放大缩小
*/ */
export default { export default {
name: "Scale", name: 'Scale',
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
scaleNum: 100, scaleNum: 100
}; }
}, },
watch: { watch: {
mindMap(val, oldVal) { mindMap(val, oldVal) {
if (val && !oldVal) { if (val && !oldVal) {
this.mindMap.on("scale", (scale) => { this.mindMap.on('scale', scale => {
this.scaleNum = this.toPer(scale); this.scaleNum = this.toPer(scale)
}); })
this.scaleNum = this.toPer(this.mindMap.view.scale) this.scaleNum = this.toPer(this.mindMap.view.scale)
} }
}, }
}, },
methods: { methods: {
/** /**
@ -54,7 +54,7 @@ export default {
* @Desc: 缩小 * @Desc: 缩小
*/ */
narrow() { narrow() {
this.mindMap.view.narrow(); this.mindMap.view.narrow()
}, },
/** /**
@ -63,10 +63,10 @@ export default {
* @Desc: 放大 * @Desc: 放大
*/ */
enlarge() { enlarge() {
this.mindMap.view.enlarge(); this.mindMap.view.enlarge()
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -20,8 +20,8 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
import { shortcutKeyList } from "@/config"; import { shortcutKeyList } from '@/config'
/** /**
* @Author: 王林 * @Author: 王林
@ -29,24 +29,24 @@ import { shortcutKeyList } from "@/config";
* @Desc: 快捷键 * @Desc: 快捷键
*/ */
export default { export default {
name: "ShortcutKey", name: 'ShortcutKey',
components: { components: {
Sidebar, Sidebar
}, },
data() { data() {
return { return {
shortcutKeyList, shortcutKeyList
}; }
}, },
created() { created() {
this.$bus.$on("showShortcutKey", () => { this.$bus.$on('showShortcutKey', () => {
this.$refs.sidebar.show = false; this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.$refs.sidebar.show = true; this.$refs.sidebar.show = true
}); })
}); })
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -16,7 +16,7 @@
</template> </template>
<script> <script>
import { store } from "@/config"; import { store } from '@/config'
/** /**
* @Author: 王林 * @Author: 王林
@ -24,27 +24,27 @@ import { store } from "@/config";
* @Desc: 侧边栏容器 * @Desc: 侧边栏容器
*/ */
export default { export default {
name: "Sidebar", name: 'Sidebar',
props: { props: {
title: { title: {
type: String, type: String,
default: "", default: ''
}, }
}, },
data() { data() {
return { return {
show: false, show: false,
zIndex: 0, zIndex: 0
}; }
}, },
watch: { watch: {
show(val, oldVal) { show(val, oldVal) {
if (val && !oldVal) { if (val && !oldVal) {
this.zIndex = store.sidebarZIndex++; this.zIndex = store.sidebarZIndex++
}
}
}
} }
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -18,9 +18,9 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
import { layoutList } from "simple-mind-map/src/utils/constant"; import { layoutList } from 'simple-mind-map/src/utils/constant'
import { storeConfig } from "@/api"; import { storeConfig } from '@/api'
/** /**
* @Author: 王林 * @Author: 王林
@ -28,29 +28,29 @@ import { storeConfig } from "@/api";
* @Desc: 结构 * @Desc: 结构
*/ */
export default { export default {
name: "Structure", name: 'Structure',
components: { components: {
Sidebar, Sidebar
}, },
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
layoutList, layoutList,
layout: "", layout: ''
}; }
}, },
created() { created() {
this.$bus.$on("showStructure", () => { this.$bus.$on('showStructure', () => {
this.$refs.sidebar.show = false; this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.layout = this.mindMap.getLayout(); this.layout = this.mindMap.getLayout()
this.$refs.sidebar.show = true; this.$refs.sidebar.show = true
}); })
}); })
}, },
methods: { methods: {
/** /**
@ -59,14 +59,14 @@ export default {
* @Desc: 使用主题 * @Desc: 使用主题
*/ */
useLayout(layout) { useLayout(layout) {
this.layout = layout.value; this.layout = layout.value
this.mindMap.setLayout(layout.value); this.mindMap.setLayout(layout.value)
storeConfig({ storeConfig({
layout: layout.value, layout: layout.value
}); })
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -72,7 +72,11 @@
<div class="row"> <div class="row">
<div class="btnGroup"> <div class="btnGroup">
<el-tooltip content="颜色" placement="bottom"> <el-tooltip content="颜色" placement="bottom">
<div class="styleBtn" v-popover:popover :class="{ disabled: checkDisabled('color') }"> <div
class="styleBtn"
v-popover:popover
:class="{ disabled: checkDisabled('color') }"
>
A A
<span <span
class="colorShow" class="colorShow"
@ -83,7 +87,10 @@
<el-tooltip content="加粗" placement="bottom"> <el-tooltip content="加粗" placement="bottom">
<div <div
class="styleBtn" class="styleBtn"
:class="{ actived: style.fontWeight === 'bold', disabled: checkDisabled('fontWeight') }" :class="{
actived: style.fontWeight === 'bold',
disabled: checkDisabled('fontWeight')
}"
@click="toggleFontWeight" @click="toggleFontWeight"
> >
B B
@ -92,7 +99,10 @@
<el-tooltip content="斜体" placement="bottom"> <el-tooltip content="斜体" placement="bottom">
<div <div
class="styleBtn i" class="styleBtn i"
:class="{ actived: style.fontStyle === 'italic', disabled: checkDisabled('fontStyle') }" :class="{
actived: style.fontStyle === 'italic',
disabled: checkDisabled('fontStyle')
}"
@click="toggleFontStyle" @click="toggleFontStyle"
> >
I I
@ -109,10 +119,20 @@
</div> </div>
</el-tooltip> </el-tooltip>
</div> </div>
<el-popover ref="popover" placement="bottom" trigger="click" :disabled="checkDisabled('color')"> <el-popover
ref="popover"
placement="bottom"
trigger="click"
:disabled="checkDisabled('color')"
>
<Color :color="style.color" @change="changeFontColor"></Color> <Color :color="style.color" @change="changeFontColor"></Color>
</el-popover> </el-popover>
<el-popover ref="popover2" placement="bottom" trigger="click" :disabled="checkDisabled('textDecoration')"> <el-popover
ref="popover2"
placement="bottom"
trigger="click"
:disabled="checkDisabled('textDecoration')"
>
<el-radio-group <el-radio-group
size="mini" size="mini"
v-model="style.textDecoration" v-model="style.textDecoration"
@ -135,7 +155,12 @@
:style="{ width: '80px', backgroundColor: style.borderColor }" :style="{ width: '80px', backgroundColor: style.borderColor }"
:class="{ disabled: checkDisabled('borderColor') }" :class="{ disabled: checkDisabled('borderColor') }"
></span> ></span>
<el-popover ref="popover3" placement="bottom" trigger="click" :disabled="checkDisabled('borderColor')"> <el-popover
ref="popover3"
placement="bottom"
trigger="click"
:disabled="checkDisabled('borderColor')"
>
<Color <Color
:color="style.borderColor" :color="style.borderColor"
@change="changeBorderColor" @change="changeBorderColor"
@ -213,7 +238,12 @@
:style="{ backgroundColor: style.fillColor }" :style="{ backgroundColor: style.fillColor }"
:class="{ disabled: checkDisabled('fillColor') }" :class="{ disabled: checkDisabled('fillColor') }"
></span> ></span>
<el-popover ref="popover4" placement="bottom" trigger="click" :disabled="checkDisabled('fillColor')"> <el-popover
ref="popover4"
placement="bottom"
trigger="click"
:disabled="checkDisabled('fillColor')"
>
<Color :color="style.fillColor" @change="changeFillColor"></Color> <Color :color="style.fillColor" @change="changeFillColor"></Color>
</el-popover> </el-popover>
</div> </div>
@ -252,11 +282,13 @@
:style="{ width: '80px', backgroundColor: style.lineColor }" :style="{ width: '80px', backgroundColor: style.lineColor }"
:class="{ disabled: checkDisabled('lineColor') }" :class="{ disabled: checkDisabled('lineColor') }"
></span> ></span>
<el-popover ref="popover5" placement="bottom" trigger="click" :disabled="checkDisabled('lineColor')"> <el-popover
<Color ref="popover5"
:color="style.lineColor" placement="bottom"
@change="changeLineColor" trigger="click"
></Color> :disabled="checkDisabled('lineColor')"
>
<Color :color="style.lineColor" @change="changeLineColor"></Color>
</el-popover> </el-popover>
</div> </div>
<div class="rowItem"> <div class="rowItem">
@ -330,8 +362,8 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
import Color from "./Color"; import Color from './Color'
import { import {
fontFamilyList, fontFamilyList,
fontSizeList, fontSizeList,
@ -339,9 +371,9 @@ import {
borderDasharrayList, borderDasharrayList,
borderRadiusList, borderRadiusList,
lineHeightList, lineHeightList,
shapeList, shapeList
} from "@/config"; } from '@/config'
import { supportActiveStyle } from 'simple-mind-map/src/themes/default'; import { supportActiveStyle } from 'simple-mind-map/src/themes/default'
/** /**
* @Author: 王林 * @Author: 王林
@ -349,10 +381,10 @@ import { supportActiveStyle } from 'simple-mind-map/src/themes/default';
* @Desc: 节点样式设置 * @Desc: 节点样式设置
*/ */
export default { export default {
name: "Style", name: 'Style',
components: { components: {
Sidebar, Sidebar,
Color, Color
}, },
data() { data() {
return { return {
@ -365,39 +397,40 @@ export default {
borderRadiusList, borderRadiusList,
lineHeightList, lineHeightList,
activeNodes: [], activeNodes: [],
activeTab: "normal", activeTab: 'normal',
style: { style: {
shape: '', shape: '',
paddingX: 0, paddingX: 0,
paddingY: 0, paddingY: 0,
color: "", color: '',
fontFamily: "", fontFamily: '',
fontSize: "", fontSize: '',
lineHeight: "", lineHeight: '',
textDecoration: "", textDecoration: '',
fontWeight: "", fontWeight: '',
fontStyle: "", fontStyle: '',
borderWidth: "", borderWidth: '',
borderColor: "", borderColor: '',
fillColor: "", fillColor: '',
borderDasharray: "", borderDasharray: '',
borderRadius: "", borderRadius: '',
lineColor: "", lineColor: '',
lineDasharray: "", lineDasharray: '',
lineWidth: "", lineWidth: ''
}, }
}; }
}, },
created() { created() {
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
if (this.$refs.sidebar) this.$refs.sidebar.show = false; if (this.$refs.sidebar) this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.activeTab = "normal"; this.activeTab = 'normal'
this.activeNodes = args[1]; this.activeNodes = args[1]
if (this.$refs.sidebar) this.$refs.sidebar.show = this.activeNodes.length > 0; if (this.$refs.sidebar)
this.initNodeStyle(); this.$refs.sidebar.show = this.activeNodes.length > 0
}); this.initNodeStyle()
}); })
})
}, },
methods: { methods: {
/** /**
@ -406,7 +439,7 @@ export default {
* @Desc: tab切换 * @Desc: tab切换
*/ */
handleTabClick() { handleTabClick() {
this.initNodeStyle(); this.initNodeStyle()
}, },
/** /**
@ -415,7 +448,9 @@ export default {
* @Desc: 检查是否禁用 * @Desc: 检查是否禁用
*/ */
checkDisabled(prop) { checkDisabled(prop) {
return this.activeTab === 'active' && !this.supportActiveStyle.includes(prop) return (
this.activeTab === 'active' && !this.supportActiveStyle.includes(prop)
)
}, },
/** /**
@ -425,35 +460,35 @@ export default {
*/ */
initNodeStyle() { initNodeStyle() {
if (this.activeNodes.length <= 0) { if (this.activeNodes.length <= 0) {
this.activeTab = "normal"; this.activeTab = 'normal'
return; return
} }
[ ;[
"shape", 'shape',
"paddingX", 'paddingX',
"paddingY", 'paddingY',
"color", 'color',
"fontFamily", 'fontFamily',
"fontSize", 'fontSize',
"lineHeight", 'lineHeight',
"textDecoration", 'textDecoration',
"fontWeight", 'fontWeight',
"fontStyle", 'fontStyle',
"borderWidth", 'borderWidth',
"borderColor", 'borderColor',
"fillColor", 'fillColor',
"borderDasharray", 'borderDasharray',
"borderRadius", 'borderRadius',
"lineColor", 'lineColor',
"lineDasharray", 'lineDasharray',
"lineWidth", 'lineWidth'
].forEach((item) => { ].forEach(item => {
this.style[item] = this.activeNodes[0].getStyle( this.style[item] = this.activeNodes[0].getStyle(
item, item,
false, false,
this.activeTab === "active" this.activeTab === 'active'
); )
}); })
}, },
/** /**
@ -462,9 +497,9 @@ export default {
* @Desc: 修改样式 * @Desc: 修改样式
*/ */
update(prop) { update(prop) {
this.activeNodes.forEach((node) => { this.activeNodes.forEach(node => {
node.setStyle(prop, this.style[prop], this.activeTab === "active"); node.setStyle(prop, this.style[prop], this.activeTab === 'active')
}); })
}, },
/** /**
@ -473,12 +508,12 @@ export default {
* @Desc: 切换加粗样式 * @Desc: 切换加粗样式
*/ */
toggleFontWeight() { toggleFontWeight() {
if (this.style.fontWeight === "bold") { if (this.style.fontWeight === 'bold') {
this.style.fontWeight = "normal"; this.style.fontWeight = 'normal'
} else { } else {
this.style.fontWeight = "bold"; this.style.fontWeight = 'bold'
} }
this.update("fontWeight"); this.update('fontWeight')
}, },
/** /**
@ -487,12 +522,12 @@ export default {
* @Desc: 切换字体样式 * @Desc: 切换字体样式
*/ */
toggleFontStyle() { toggleFontStyle() {
if (this.style.fontStyle === "italic") { if (this.style.fontStyle === 'italic') {
this.style.fontStyle = "normal"; this.style.fontStyle = 'normal'
} else { } else {
this.style.fontStyle = "italic"; this.style.fontStyle = 'italic'
} }
this.update("fontStyle"); this.update('fontStyle')
}, },
/** /**
@ -501,8 +536,8 @@ export default {
* @Desc: 修改字体颜色 * @Desc: 修改字体颜色
*/ */
changeFontColor(color) { changeFontColor(color) {
this.style.color = color; this.style.color = color
this.update("color"); this.update('color')
}, },
/** /**
@ -511,8 +546,8 @@ export default {
* @Desc: 修改边框颜色 * @Desc: 修改边框颜色
*/ */
changeBorderColor(color) { changeBorderColor(color) {
this.style.borderColor = color; this.style.borderColor = color
this.update("borderColor"); this.update('borderColor')
}, },
/** /**
@ -521,8 +556,8 @@ export default {
* @Desc: 修改线条颜色 * @Desc: 修改线条颜色
*/ */
changeLineColor(color) { changeLineColor(color) {
this.style.lineColor = color; this.style.lineColor = color
this.update("lineColor"); this.update('lineColor')
}, },
/** /**
@ -531,11 +566,11 @@ export default {
* @Desc: 修改背景颜色 * @Desc: 修改背景颜色
*/ */
changeFillColor(color) { changeFillColor(color) {
this.style.fillColor = color; this.style.fillColor = color
this.update("fillColor"); this.update('fillColor')
}, }
}, }
}; }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
@ -598,9 +633,9 @@ export default {
cursor: pointer; cursor: pointer;
&.disabled { &.disabled {
background-color: #F5F7FA !important; background-color: #f5f7fa !important;
border-color: #E4E7ED !important; border-color: #e4e7ed !important;
color: #C0C4CC !important; color: #c0c4cc !important;
cursor: not-allowed !important; cursor: not-allowed !important;
} }
} }
@ -624,9 +659,9 @@ export default {
} }
&.disabled { &.disabled {
background-color: #F5F7FA !important; background-color: #f5f7fa !important;
border-color: #E4E7ED !important; border-color: #e4e7ed !important;
color: #C0C4CC !important; color: #c0c4cc !important;
cursor: not-allowed !important; cursor: not-allowed !important;
} }

View File

@ -18,9 +18,9 @@
</template> </template>
<script> <script>
import Sidebar from "./Sidebar"; import Sidebar from './Sidebar'
import { themeList } from "simple-mind-map/src/utils/constant"; import { themeList } from 'simple-mind-map/src/utils/constant'
import { storeConfig } from "@/api"; import { storeConfig } from '@/api'
/** /**
* @Author: 王林 * @Author: 王林
@ -28,29 +28,29 @@ import { storeConfig } from "@/api";
* @Desc: 主题 * @Desc: 主题
*/ */
export default { export default {
name: "Theme", name: 'Theme',
components: { components: {
Sidebar, Sidebar
}, },
props: { props: {
mindMap: { mindMap: {
type: Object, type: Object
}, }
}, },
data() { data() {
return { return {
themeList, themeList,
theme: "", theme: ''
}; }
}, },
created() { created() {
this.$bus.$on("showTheme", () => { this.$bus.$on('showTheme', () => {
this.$refs.sidebar.show = false; this.$refs.sidebar.show = false
this.$nextTick(() => { this.$nextTick(() => {
this.theme = this.mindMap.getTheme(); this.theme = this.mindMap.getTheme()
this.$refs.sidebar.show = true; this.$refs.sidebar.show = true
}); })
}); })
}, },
methods: { methods: {
/** /**
@ -59,17 +59,17 @@ export default {
* @Desc: 使用主题 * @Desc: 使用主题
*/ */
useTheme(theme) { useTheme(theme) {
this.theme = theme.value; this.theme = theme.value
this.mindMap.setTheme(theme.value); this.mindMap.setTheme(theme.value)
storeConfig({ storeConfig({
theme: { theme: {
"template": theme.value, template: theme.value,
"config": this.mindMap.getCustomThemeConfig() config: this.mindMap.getCustomThemeConfig()
}
})
}
}
} }
});
},
},
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -6,7 +6,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: readonly || backEnd, disabled: readonly || backEnd
}" }"
@click="$bus.$emit('execCommand', 'BACK')" @click="$bus.$emit('execCommand', 'BACK')"
> >
@ -16,7 +16,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: readonly || forwardEnd, disabled: readonly || forwardEnd
}" }"
@click="$bus.$emit('execCommand', 'FORWARD')" @click="$bus.$emit('execCommand', 'FORWARD')"
> >
@ -26,7 +26,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization, disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}" }"
@click="$bus.$emit('execCommand', 'INSERT_NODE')" @click="$bus.$emit('execCommand', 'INSERT_NODE')"
> >
@ -36,7 +36,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0 || hasGeneralization, disabled: activeNodes.length <= 0 || hasGeneralization
}" }"
@click="$bus.$emit('execCommand', 'INSERT_CHILD_NODE')" @click="$bus.$emit('execCommand', 'INSERT_CHILD_NODE')"
> >
@ -46,7 +46,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('execCommand', 'REMOVE_NODE')" @click="$bus.$emit('execCommand', 'REMOVE_NODE')"
> >
@ -56,7 +56,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('showNodeImage')" @click="$bus.$emit('showNodeImage')"
> >
@ -66,7 +66,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('showNodeIcon')" @click="$bus.$emit('showNodeIcon')"
> >
@ -76,7 +76,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('showNodeLink')" @click="$bus.$emit('showNodeLink')"
> >
@ -86,7 +86,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('showNodeNote')" @click="$bus.$emit('showNodeNote')"
> >
@ -96,7 +96,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0, disabled: activeNodes.length <= 0
}" }"
@click="$bus.$emit('showNodeTag')" @click="$bus.$emit('showNodeTag')"
> >
@ -106,7 +106,7 @@
<div <div
class="toolbarBtn" class="toolbarBtn"
:class="{ :class="{
disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization, disabled: activeNodes.length <= 0 || hasRoot || hasGeneralization
}" }"
@click="$bus.$emit('execCommand', 'ADD_GENERALIZATION')" @click="$bus.$emit('execCommand', 'ADD_GENERALIZATION')"
> >
@ -172,26 +172,26 @@
</template> </template>
<script> <script>
import NodeImage from "./NodeImage"; import NodeImage from './NodeImage'
import NodeHyperlink from "./NodeHyperlink"; import NodeHyperlink from './NodeHyperlink'
import NodeIcon from "./NodeIcon"; import NodeIcon from './NodeIcon'
import NodeNote from "./NodeNote"; import NodeNote from './NodeNote'
import NodeTag from "./NodeTag"; import NodeTag from './NodeTag'
import Export from "./Export"; import Export from './Export'
import Import from './Import'; import Import from './Import'
import { mapState } from 'vuex'; import { mapState } from 'vuex'
import { Notification } from 'element-ui'; import { Notification } from 'element-ui'
import exampleData from 'simple-mind-map/example/exampleData'; import exampleData from 'simple-mind-map/example/exampleData'
import { getData } from '../../../api'; import { getData } from '../../../api'
/** /**
* @Author: 王林 * @Author: 王林
* @Date: 2021-06-24 22:54:58 * @Date: 2021-06-24 22:54:58
* @Desc: 工具栏 * @Desc: 工具栏
*/ */
let fileHandle = null; let fileHandle = null
export default { export default {
name: "Toolbar", name: 'Toolbar',
components: { components: {
NodeImage, NodeImage,
NodeHyperlink, NodeHyperlink,
@ -208,46 +208,50 @@ export default {
forwardEnd: true, forwardEnd: true,
readonly: false, readonly: false,
isFullDataFile: false, isFullDataFile: false,
timer: null, timer: null
}; }
}, },
computed: { computed: {
...mapState(['isHandleLocalFile']), ...mapState(['isHandleLocalFile']),
hasRoot() { hasRoot() {
return this.activeNodes.findIndex((node) => { return (
return node.isRoot; this.activeNodes.findIndex(node => {
}) !== -1; return node.isRoot
}) !== -1
)
}, },
hasGeneralization() { hasGeneralization() {
return this.activeNodes.findIndex((node) => { return (
return node.isGeneralization; this.activeNodes.findIndex(node => {
}) !== -1;; return node.isGeneralization
}) !== -1
)
} }
}, },
watch: { watch: {
isHandleLocalFile(val) { isHandleLocalFile(val) {
if (!val) { if (!val) {
Notification.closeAll(); Notification.closeAll()
} }
} }
}, },
created() { created() {
this.$bus.$on("mode_change", (mode) => { this.$bus.$on('mode_change', mode => {
this.readonly = mode === 'readonly' this.readonly = mode === 'readonly'
}); })
this.$bus.$on("node_active", (...args) => { this.$bus.$on('node_active', (...args) => {
this.activeNodes = args[1]; this.activeNodes = args[1]
}); })
this.$bus.$on("back_forward", (index, len) => { this.$bus.$on('back_forward', (index, len) => {
this.backEnd = index <= 0 this.backEnd = index <= 0
this.forwardEnd = index >= len - 1 this.forwardEnd = index >= len - 1
}); })
this.$bus.$on("write_local_file", (content) => { this.$bus.$on('write_local_file', content => {
clearTimeout(this.timer); clearTimeout(this.timer)
this.timer = setTimeout(() => { this.timer = setTimeout(() => {
this.writeLocalFile(content); this.writeLocalFile(content)
}, 1000); }, 1000)
}); })
}, },
methods: { methods: {
/** /**
@ -264,26 +268,28 @@ export default {
accept: { accept: {
'application/json': ['.smm'] 'application/json': ['.smm']
} }
}, }
], ],
excludeAcceptAllOption: true, excludeAcceptAllOption: true,
multiple: false multiple: false
}); })
if (!_fileHandle) { if (!_fileHandle) {
return; return
} }
fileHandle = _fileHandle; fileHandle = _fileHandle
if (fileHandle.kind === 'directory') { if (fileHandle.kind === 'directory') {
this.$message.warning('请选择文件'); this.$message.warning('请选择文件')
return; return
} }
this.readFile(); this.readFile()
} catch (error) { } catch (error) {
console.log(error); console.log(error)
if (error.toString().includes('aborted')) { if (error.toString().includes('aborted')) {
return return
} }
this.$message.warning('你的浏览器可能不支持建议使用最新版本的Chrome浏览器'); this.$message.warning(
'你的浏览器可能不支持建议使用最新版本的Chrome浏览器'
)
} }
}, },
@ -293,20 +299,20 @@ export default {
* @Desc: 读取本地文件 * @Desc: 读取本地文件
*/ */
async readFile() { async readFile() {
let file = await fileHandle.getFile(); let file = await fileHandle.getFile()
let fileReader = new FileReader(); let fileReader = new FileReader()
fileReader.onload = async () => { fileReader.onload = async () => {
this.$store.commit('setIsHandleLocalFile', true); this.$store.commit('setIsHandleLocalFile', true)
this.setData(fileReader.result); this.setData(fileReader.result)
Notification.closeAll(); Notification.closeAll()
Notification({ Notification({
title: '提示', title: '提示',
message: `当前正在编辑你本机的【${file.name}】文件`, message: `当前正在编辑你本机的【${file.name}】文件`,
duration: 0, duration: 0,
showClose: false showClose: false
}); })
} }
fileReader.readAsText(file); fileReader.readAsText(file)
}, },
/** /**
@ -316,23 +322,23 @@ export default {
*/ */
setData(str) { setData(str) {
try { try {
let data = JSON.parse(str); let data = JSON.parse(str)
if (typeof data !== 'object') { if (typeof data !== 'object') {
throw new Error('文件内容有误'); throw new Error('文件内容有误')
} }
if (data.root) { if (data.root) {
this.isFullDataFile = true; this.isFullDataFile = true
} else { } else {
this.isFullDataFile = false; this.isFullDataFile = false
data = { data = {
...exampleData, ...exampleData,
root: data root: data
} }
} }
this.$bus.$emit('setData', data); this.$bus.$emit('setData', data)
} catch (error) { } catch (error) {
console.log(error) console.log(error)
this.$message.error("文件打开失败"); this.$message.error('文件打开失败')
} }
}, },
@ -343,15 +349,15 @@ export default {
*/ */
async writeLocalFile(content) { async writeLocalFile(content) {
if (!fileHandle || !this.isHandleLocalFile) { if (!fileHandle || !this.isHandleLocalFile) {
return; return
} }
if (!this.isFullDataFile) { if (!this.isFullDataFile) {
content = content.root; content = content.root
} }
let string = JSON.stringify(content); let string = JSON.stringify(content)
const writable = await fileHandle.createWritable(); const writable = await fileHandle.createWritable()
await writable.write(string); await writable.write(string)
await writable.close(); await writable.close()
}, },
/** /**
@ -360,7 +366,7 @@ export default {
* @Desc: 创建本地文件 * @Desc: 创建本地文件
*/ */
async createNewLocalFile() { async createNewLocalFile() {
await this.createLocalFile(exampleData); await this.createLocalFile(exampleData)
}, },
/** /**
@ -369,8 +375,8 @@ export default {
* @Desc: 另存为 * @Desc: 另存为
*/ */
async saveLocalFile() { async saveLocalFile() {
let data = getData(); let data = getData()
await this.createLocalFile(data); await this.createLocalFile(data)
}, },
/** /**
@ -381,37 +387,41 @@ export default {
async createLocalFile(content) { async createLocalFile(content) {
try { try {
let _fileHandle = await window.showSaveFilePicker({ let _fileHandle = await window.showSaveFilePicker({
types: [{ types: [
{
description: '', description: '',
accept: {'application/json': ['.smm']}, accept: { 'application/json': ['.smm'] }
}], }
],
suggestedName: '思维导图' suggestedName: '思维导图'
}); })
if (!_fileHandle) { if (!_fileHandle) {
return; return
} }
const loading = this.$loading({ const loading = this.$loading({
lock: true, lock: true,
text: '正在创建文件', text: '正在创建文件',
spinner: 'el-icon-loading', spinner: 'el-icon-loading',
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}); })
fileHandle = _fileHandle; fileHandle = _fileHandle
this.$store.commit('setIsHandleLocalFile', true); this.$store.commit('setIsHandleLocalFile', true)
this.isFullDataFile = true; this.isFullDataFile = true
await this.writeLocalFile(content); await this.writeLocalFile(content)
await this.readFile(); await this.readFile()
loading.close(); loading.close()
} catch (error) { } catch (error) {
console.log(error); console.log(error)
if (error.toString().includes('aborted')) { if (error.toString().includes('aborted')) {
return return
} }
this.$message.warning('你的浏览器可能不支持建议使用最新版本的Chrome浏览器'); this.$message.warning(
'你的浏览器可能不支持建议使用最新版本的Chrome浏览器'
)
}
}
} }
},
} }
};
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -4,9 +4,7 @@ import EditPage from '@/pages/Edit/Index'
Vue.use(VueRouter) Vue.use(VueRouter)
const routes = [ const routes = [{ path: '/', name: 'Edit', component: EditPage }]
{ path: '/', name: 'Edit', component: EditPage }
]
const router = new VueRouter({ const router = new VueRouter({
routes routes

View File

@ -1,6 +1,6 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import exampleData from 'simple-mind-map/example/exampleData'; import exampleData from 'simple-mind-map/example/exampleData'
Vue.use(Vuex) Vue.use(Vuex)
@ -37,9 +37,7 @@ const store = new Vuex.Store({
*/ */
getUserMindMapData(ctx) { getUserMindMapData(ctx) {
try { try {
let { let { data } = {
data
} = {
data: { data: {
data: { data: {
mindMapData: exampleData mindMapData: exampleData

View File

@ -5,13 +5,13 @@
*/ */
const getOnfullscreEnevt = () => { const getOnfullscreEnevt = () => {
if (document.documentElement.requestFullScreen) { if (document.documentElement.requestFullScreen) {
return 'onfullscreenchange'; return 'onfullscreenchange'
} else if (document.documentElement.webkitRequestFullScreen) { } else if (document.documentElement.webkitRequestFullScreen) {
return 'onwebkitfullscreenchange'; return 'onwebkitfullscreenchange'
} else if (document.documentElement.mozRequestFullScreen) { } else if (document.documentElement.mozRequestFullScreen) {
return 'onmozfullscreenchange'; return 'onmozfullscreenchange'
} else if (document.documentElement.msRequestFullscreen) { } else if (document.documentElement.msRequestFullscreen) {
return 'onmsfullscreenchange'; return 'onmsfullscreenchange'
} }
} }
@ -22,12 +22,12 @@ export const fullscrrenEvent = getOnfullscreEnevt()
* @Date: 2021-07-11 21:45:06 * @Date: 2021-07-11 21:45:06
* @Desc: 全屏 * @Desc: 全屏
*/ */
export const fullScreen = (element) => { export const fullScreen = element => {
if (element.requestFullScreen) { if (element.requestFullScreen) {
element.requestFullScreen(); element.requestFullScreen()
} else if (element.webkitRequestFullScreen) { } else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen(); element.webkitRequestFullScreen()
} else if (element.mozRequestFullScreen) { } else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen(); element.mozRequestFullScreen()
} }
} }