mirror of
https://github.com/wanglin2/mind-map.git
synced 2026-02-24 10:28:26 +08:00
Compare commits
87 Commits
0.6.17
...
0.7.1-fix.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
977799a3ac | ||
|
|
76ddecee50 | ||
|
|
0ab495a161 | ||
|
|
fefbcfbbee | ||
|
|
c77c7403da | ||
|
|
b0044bb5fa | ||
|
|
e61749c1b3 | ||
|
|
43216ed925 | ||
|
|
385873b6e8 | ||
|
|
5583642961 | ||
|
|
e063724ab6 | ||
|
|
19d4788489 | ||
|
|
1452fd2a28 | ||
|
|
c296b99d5a | ||
|
|
e9de1e675f | ||
|
|
b3e254c0ee | ||
|
|
bd3d470e40 | ||
|
|
21564445d6 | ||
|
|
e53d1b1948 | ||
|
|
c428f166a6 | ||
|
|
f19704ec41 | ||
|
|
d47f013f84 | ||
|
|
612d675a19 | ||
|
|
13f571e0b5 | ||
|
|
b09d408ab3 | ||
|
|
ea95ae2b5d | ||
|
|
2590e21807 | ||
|
|
fb41653d79 | ||
|
|
4c9c34a0ea | ||
|
|
0d5602b832 | ||
|
|
af87f84ce8 | ||
|
|
a96c16aa45 | ||
|
|
e29e1c26e5 | ||
|
|
fee38cbe8a | ||
|
|
58ca173234 | ||
|
|
aee10c6810 | ||
|
|
fe43be3451 | ||
|
|
21868c7f44 | ||
|
|
5585d2a4f7 | ||
|
|
1d04038609 | ||
|
|
305c5e9f70 | ||
|
|
4ac91003bb | ||
|
|
44410900aa | ||
|
|
239b369391 | ||
|
|
d9638fef98 | ||
|
|
ecb9482b82 | ||
|
|
cd5556aad5 | ||
|
|
063af62cf6 | ||
|
|
a4611d11a8 | ||
|
|
5d1f460a94 | ||
|
|
075e578bb4 | ||
|
|
32c17921ca | ||
|
|
7c470c9b88 | ||
|
|
e472b840f1 | ||
|
|
726460c812 | ||
|
|
7ccf796c34 | ||
|
|
c183306ab2 | ||
|
|
29bb27aa23 | ||
|
|
7f9d03c8af | ||
|
|
c3a0e09f6d | ||
|
|
1d497b2f13 | ||
|
|
f43a2ebdef | ||
|
|
4c3f3cb1ab | ||
|
|
a404a71ba2 | ||
|
|
6b4c118a2b | ||
|
|
1157257911 | ||
|
|
f2642c9d63 | ||
|
|
91bc0351b8 | ||
|
|
df2dc96ba5 | ||
|
|
3d86650f22 | ||
|
|
a31e93bacf | ||
|
|
a3362e44fe | ||
|
|
f7f234b4cb | ||
|
|
48f1de5c25 | ||
|
|
c533459da1 | ||
|
|
d99895b845 | ||
|
|
c65393d1bc | ||
|
|
5d133f74cf | ||
|
|
5997c98b8f | ||
|
|
217d66f692 | ||
|
|
d14d887c1a | ||
|
|
e36e238c2f | ||
|
|
1b0646af6d | ||
|
|
a24f7a73c8 | ||
|
|
b35dd282ec | ||
|
|
8c0c2c5bc4 | ||
|
|
3763cd0efc |
24
README.md
24
README.md
@@ -87,9 +87,7 @@ const mindMap = new MindMap({
|
||||
|
||||
# 微信交流群
|
||||
|
||||
<img src="./qrcode.jpg" style="width: 300px" />
|
||||
|
||||
如果已过期,可以微信添加`wanglinguanfang`拉你入群。
|
||||
群聊人数较多,无法通过二维码入群,可以微信添加`wanglinguanfang`拉你入群。
|
||||
|
||||
# 请作者喝杯咖啡
|
||||
|
||||
@@ -165,4 +163,24 @@ const mindMap = new MindMap({
|
||||
<img src="./web/src/assets/avatar/default.png" style="width: 50px;height: 50px;" />
|
||||
<span>Luke</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/布林.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>布林</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/南风.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>南风</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/蜉蝣撼大叔.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>蜉蝣撼大叔</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/乙.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>乙</span>
|
||||
</span>
|
||||
<span>
|
||||
<img src="./web/src/assets/avatar/敏.jpg" style="width: 50px;height: 50px;" />
|
||||
<span>敏</span>
|
||||
</span>
|
||||
</p>
|
||||
@@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1"><link rel="icon" href="dist/logo.ico"><title>思绪思维导图</title><script>// 自定义静态资源的路径
|
||||
window.externalPublicPath = './dist/'
|
||||
// 接管应用
|
||||
window.takeOverApp = false</script><link href="dist/css/chunk-vendors.css?3f27c97d35a340dfd1c0" rel="stylesheet"><link href="dist/css/app.css?3f27c97d35a340dfd1c0" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
window.takeOverApp = false</script><link href="dist/css/chunk-vendors.css?3d449dfd2d4c7693c086" rel="stylesheet"><link href="dist/css/app.css?3d449dfd2d4c7693c086" rel="stylesheet"></head><body><noscript><strong>We're sorry but thoughts doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script>const getDataFromBackend = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
@@ -66,4 +66,4 @@
|
||||
// 可以通过window.$bus.$on()来监听应用的一些事件
|
||||
// 实例化页面
|
||||
window.initApp()
|
||||
}</script><script src="dist/js/chunk-vendors.js?3f27c97d35a340dfd1c0"></script><script src="dist/js/app.js?3f27c97d35a340dfd1c0"></script></body></html>
|
||||
}</script><script src="dist/js/chunk-vendors.js?3d449dfd2d4c7693c086"></script><script src="dist/js/app.js?3d449dfd2d4c7693c086"></script></body></html>
|
||||
BIN
qrcode.jpg
BIN
qrcode.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 49 KiB |
@@ -13,6 +13,7 @@ import NodeImgAdjust from './src/plugins/NodeImgAdjust.js'
|
||||
import TouchEvent from './src/plugins/TouchEvent.js'
|
||||
import Search from './src/plugins/Search.js'
|
||||
import Painter from './src/plugins/Painter.js'
|
||||
import Scrollbar from './src/plugins/Scrollbar.js'
|
||||
import xmind from './src/parse/xmind.js'
|
||||
import markdown from './src/parse/markdown.js'
|
||||
import icons from './src/svg/icons.js'
|
||||
@@ -27,8 +28,7 @@ MindMap.constants = constants
|
||||
MindMap.themes = themes
|
||||
MindMap.defaultTheme = defaultTheme
|
||||
|
||||
MindMap
|
||||
.usePlugin(MiniMap)
|
||||
MindMap.usePlugin(MiniMap)
|
||||
.usePlugin(Watermark)
|
||||
.usePlugin(Drag)
|
||||
.usePlugin(KeyboardNavigation)
|
||||
@@ -42,5 +42,6 @@ MindMap
|
||||
.usePlugin(NodeImgAdjust)
|
||||
.usePlugin(Search)
|
||||
.usePlugin(Painter)
|
||||
.usePlugin(Scrollbar)
|
||||
|
||||
export default MindMap
|
||||
export default MindMap
|
||||
|
||||
14
simple-mind-map/index.d.ts
vendored
14
simple-mind-map/index.d.ts
vendored
@@ -1,14 +0,0 @@
|
||||
// declare module "simple-mind-map";
|
||||
declare module 'simple-mind-map'{
|
||||
class MindMap {
|
||||
constructor(opt:any);
|
||||
handleOpt(opt:any):void;
|
||||
render(callback:any, source:string):void;
|
||||
reRender(callback:any, source:string):void;
|
||||
resize():void;
|
||||
on(event:any, fn:any):void;
|
||||
setFullData(data:any):void;
|
||||
getData(withConfig:any):any;
|
||||
}
|
||||
export default MindMap;
|
||||
}
|
||||
@@ -11,10 +11,11 @@ import {
|
||||
layoutValueList,
|
||||
CONSTANTS,
|
||||
commonCaches,
|
||||
ERROR_TYPES
|
||||
ERROR_TYPES,
|
||||
cssContent
|
||||
} from './src/constants/constant'
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import { simpleDeepClone, getType } from './src/utils'
|
||||
import { simpleDeepClone, getType, getObjectChangedProps } from './src/utils'
|
||||
import defaultTheme, {
|
||||
checkIsNodeSizeIndependenceConfig
|
||||
} from './src/themes/default'
|
||||
@@ -23,6 +24,10 @@ import { defaultOpt } from './src/constants/defaultOptions'
|
||||
// 思维导图
|
||||
class MindMap {
|
||||
// 构造函数
|
||||
/**
|
||||
*
|
||||
* @param {defaultOpt} opt
|
||||
*/
|
||||
constructor(opt = {}) {
|
||||
// 合并选项
|
||||
this.opt = this.handleOpt(merge(defaultOpt, opt))
|
||||
@@ -35,7 +40,12 @@ class MindMap {
|
||||
// 画布宽高
|
||||
this.width = this.elRect.width
|
||||
this.height = this.elRect.height
|
||||
if (this.width <= 0 || this.height <= 0) throw new Error('容器元素el的宽高不能为0')
|
||||
if (this.width <= 0 || this.height <= 0)
|
||||
throw new Error('容器元素el的宽高不能为0')
|
||||
|
||||
// 添加css
|
||||
this.cssEl = null
|
||||
this.addCss()
|
||||
|
||||
// 画布
|
||||
this.svg = SVG().addTo(this.el).size(this.width, this.height)
|
||||
@@ -82,7 +92,7 @@ class MindMap {
|
||||
})
|
||||
|
||||
// 初始渲染
|
||||
this.render()
|
||||
this.render(this.opt.fit ? () => this.view.fit() : () => {})
|
||||
setTimeout(() => {
|
||||
this.command.addHistory()
|
||||
}, 0)
|
||||
@@ -101,6 +111,19 @@ class MindMap {
|
||||
return opt
|
||||
}
|
||||
|
||||
// 添加必要的css样式到页面
|
||||
addCss() {
|
||||
this.cssEl = document.createElement('style')
|
||||
this.cssEl.type = 'text/css'
|
||||
this.cssEl.innerHTML = cssContent
|
||||
document.head.appendChild(this.cssEl)
|
||||
}
|
||||
|
||||
// 移除css
|
||||
removeCss() {
|
||||
document.head.removeChild(this.cssEl)
|
||||
}
|
||||
|
||||
// 渲染,部分渲染
|
||||
render(callback, source = '') {
|
||||
this.batchExecution.push('render', () => {
|
||||
@@ -183,9 +206,11 @@ class MindMap {
|
||||
|
||||
// 设置主题配置
|
||||
setThemeConfig(config) {
|
||||
// 计算改变了的配置
|
||||
const changedConfig = getObjectChangedProps(this.themeConfig, config)
|
||||
this.opt.themeConfig = config
|
||||
// 检查改变的是否是节点大小无关的主题属性
|
||||
let res = checkIsNodeSizeIndependenceConfig(config)
|
||||
let res = checkIsNodeSizeIndependenceConfig(changedConfig)
|
||||
this.render(null, res ? '' : CONSTANTS.CHANGE_THEME)
|
||||
}
|
||||
|
||||
@@ -339,6 +364,8 @@ class MindMap {
|
||||
draw.translate(-rect.x + elRect.left, -rect.y + elRect.top)
|
||||
// 克隆一份数据
|
||||
let clone = svg.clone()
|
||||
// 添加必要的样式
|
||||
clone.add(SVG(`<style>${cssContent}</style>`))
|
||||
// 如果实际图形宽高超出了屏幕宽高,且存在水印的话需要重新绘制水印,否则会出现超出部分没有水印的问题
|
||||
if (
|
||||
(rect.width > origWidth || rect.height > origHeight) &&
|
||||
@@ -406,6 +433,9 @@ class MindMap {
|
||||
destroy() {
|
||||
// 移除插件
|
||||
;[...MindMap.pluginList].forEach(plugin => {
|
||||
if (this[plugin.instanceName].beforePluginDestroy) {
|
||||
this[plugin.instanceName].beforePluginDestroy()
|
||||
}
|
||||
this[plugin.instanceName] = null
|
||||
})
|
||||
// 解绑事件
|
||||
@@ -414,13 +444,16 @@ class MindMap {
|
||||
this.svg.remove()
|
||||
// 去除给容器元素设置的背景样式
|
||||
Style.removeBackgroundStyle(this.el)
|
||||
this.el.innerHTML = ''
|
||||
this.el = null
|
||||
this.removeCss()
|
||||
}
|
||||
}
|
||||
|
||||
// 插件列表
|
||||
MindMap.pluginList = []
|
||||
MindMap.usePlugin = (plugin, opt = {}) => {
|
||||
if (MindMap.hasPlugin(plugin) !== -1) return MindMap
|
||||
plugin.pluginOpt = opt
|
||||
MindMap.pluginList.push(plugin)
|
||||
return MindMap
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "simple-mind-map",
|
||||
"version": "0.6.17",
|
||||
"version": "0.7.1-fix.2",
|
||||
"description": "一个简单的web在线思维导图",
|
||||
"authors": [
|
||||
{
|
||||
@@ -12,6 +12,7 @@
|
||||
"url": "http://lxqnsys.com/"
|
||||
}
|
||||
],
|
||||
"types": "./types/index.d.ts",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -19,10 +20,11 @@
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint src/",
|
||||
"format": "prettier --write ."
|
||||
"format": "prettier --write .",
|
||||
"types": "npx -p typescript tsc index.js --declaration --allowJs --emitDeclarationOnly --outDir types --target es2017"
|
||||
},
|
||||
"module": "index.js",
|
||||
"__main": "./dist/simpleMindMap.umd.min.js",
|
||||
"main": "./dist/simpleMindMap.umd.min.js",
|
||||
"dependencies": {
|
||||
"@svgdotjs/svg.js": "^3.0.16",
|
||||
"deepmerge": "^1.5.2",
|
||||
@@ -31,6 +33,7 @@
|
||||
"jszip": "^3.10.1",
|
||||
"mdast-util-from-markdown": "^1.3.0",
|
||||
"quill": "^1.3.6",
|
||||
"tern": "^0.24.3",
|
||||
"uuid": "^9.0.0",
|
||||
"xml-js": "^1.6.11"
|
||||
},
|
||||
|
||||
@@ -17,7 +17,7 @@ const transform = dir => {
|
||||
}
|
||||
|
||||
const transformFile = file => {
|
||||
console.log(file);
|
||||
console.log(file)
|
||||
let content = fs.readFileSync(file, 'utf-8')
|
||||
countCodeLines(content)
|
||||
// transformComments(file, content)
|
||||
@@ -25,7 +25,7 @@ const transformFile = file => {
|
||||
|
||||
// 统计代码行数
|
||||
let totalLines = 0
|
||||
const countCodeLines = (content) => {
|
||||
const countCodeLines = content => {
|
||||
totalLines += content.split(/\n/).length
|
||||
}
|
||||
|
||||
@@ -43,4 +43,4 @@ const transformComments = (file, content) => {
|
||||
|
||||
transform(entryPath)
|
||||
transformFile(path.join(__dirname, '../index.js'))
|
||||
console.log(totalLines);
|
||||
console.log(totalLines)
|
||||
|
||||
@@ -249,6 +249,10 @@ export const CONSTANTS = {
|
||||
PASTE_TYPE: {
|
||||
CLIP_BOARD: 'clipBoard',
|
||||
CANVAS: 'canvas'
|
||||
},
|
||||
SCROLL_BAR_DIR: {
|
||||
VERTICAL: 'vertical',
|
||||
HORIZONTAL: 'horizontal'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,42 +261,42 @@ export const initRootNodePositionMap = {
|
||||
[CONSTANTS.INIT_ROOT_NODE_POSITION.TOP]: 0,
|
||||
[CONSTANTS.INIT_ROOT_NODE_POSITION.RIGHT]: 1,
|
||||
[CONSTANTS.INIT_ROOT_NODE_POSITION.BOTTOM]: 1,
|
||||
[CONSTANTS.INIT_ROOT_NODE_POSITION.CENTER]: 0.5,
|
||||
[CONSTANTS.INIT_ROOT_NODE_POSITION.CENTER]: 0.5
|
||||
}
|
||||
|
||||
// 布局结构列表
|
||||
export const layoutList = [
|
||||
{
|
||||
name: '逻辑结构图',
|
||||
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
|
||||
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE
|
||||
},
|
||||
{
|
||||
name: '思维导图',
|
||||
value: CONSTANTS.LAYOUT.MIND_MAP,
|
||||
value: CONSTANTS.LAYOUT.MIND_MAP
|
||||
},
|
||||
{
|
||||
name: '组织结构图',
|
||||
value: CONSTANTS.LAYOUT.ORGANIZATION_STRUCTURE,
|
||||
value: CONSTANTS.LAYOUT.ORGANIZATION_STRUCTURE
|
||||
},
|
||||
{
|
||||
name: '目录组织图',
|
||||
value: CONSTANTS.LAYOUT.CATALOG_ORGANIZATION,
|
||||
value: CONSTANTS.LAYOUT.CATALOG_ORGANIZATION
|
||||
},
|
||||
{
|
||||
name: '时间轴',
|
||||
value: CONSTANTS.LAYOUT.TIMELINE,
|
||||
value: CONSTANTS.LAYOUT.TIMELINE
|
||||
},
|
||||
{
|
||||
name: '时间轴2',
|
||||
value: CONSTANTS.LAYOUT.TIMELINE2,
|
||||
value: CONSTANTS.LAYOUT.TIMELINE2
|
||||
},
|
||||
{
|
||||
name: '竖向时间轴',
|
||||
value: CONSTANTS.LAYOUT.VERTICAL_TIMELINE,
|
||||
value: CONSTANTS.LAYOUT.VERTICAL_TIMELINE
|
||||
},
|
||||
{
|
||||
name: '鱼骨图',
|
||||
value: CONSTANTS.LAYOUT.FISHBONE,
|
||||
value: CONSTANTS.LAYOUT.FISHBONE
|
||||
}
|
||||
]
|
||||
export const layoutValueList = [
|
||||
@@ -325,7 +329,9 @@ export const nodeDataNoStylePropList = [
|
||||
'uid',
|
||||
'activeStyle',
|
||||
'associativeLineTargets',
|
||||
'associativeLineTargetControlOffsets'
|
||||
'associativeLineTargetControlOffsets',
|
||||
'associativeLinePoint',
|
||||
'associativeLineText'
|
||||
]
|
||||
|
||||
// 数据缓存
|
||||
@@ -342,4 +348,30 @@ export const ERROR_TYPES = {
|
||||
LOAD_CLIPBOARD_IMAGE_ERROR: 'load_clipboard_image_error',
|
||||
BEFORE_TEXT_EDIT_ERROR: 'before_text_edit_error',
|
||||
EXPORT_ERROR: 'export_error'
|
||||
}
|
||||
}
|
||||
|
||||
// a4纸的宽高
|
||||
export const a4Size = {
|
||||
width: 592.28,
|
||||
height: 841.89
|
||||
}
|
||||
|
||||
// css
|
||||
export const cssContent = `
|
||||
/* 鼠标hover和激活时渲染的矩形 */
|
||||
.smm-hover-node{
|
||||
display: none;
|
||||
opacity: 0.6;
|
||||
stroke-width: 1;
|
||||
}
|
||||
|
||||
.smm-node:hover .smm-hover-node{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.smm-node.active .smm-hover-node{
|
||||
display: block;
|
||||
opacity: 1;
|
||||
stroke-width: 2;
|
||||
}
|
||||
`
|
||||
|
||||
@@ -68,13 +68,21 @@ export const defaultOpt = {
|
||||
// 展开收起按钮的颜色
|
||||
expandBtnStyle: {
|
||||
color: '#808080',
|
||||
fill: '#fff'
|
||||
fill: '#fff',
|
||||
fontSize: 13,
|
||||
strokeColor: '#333333'
|
||||
},
|
||||
// 自定义展开收起按钮的图标
|
||||
expandBtnIcon: {
|
||||
open: '', // svg字符串
|
||||
close: ''
|
||||
},
|
||||
// 处理收起节点数量
|
||||
expandBtnNumHandler: num => {
|
||||
return num
|
||||
},
|
||||
// 是否显示带数量的收起按钮
|
||||
isShowExpandNum: true,
|
||||
// 是否只有当鼠标在画布内才响应快捷键事件
|
||||
enableShortcutOnlyWhenMouseInSvg: true,
|
||||
// 初始根节点的位置
|
||||
@@ -166,5 +174,19 @@ export const defaultOpt = {
|
||||
}
|
||||
`,
|
||||
// 开启鼠标双击复位思维导图位置及缩放
|
||||
enableDblclickReset: true
|
||||
enableDblclickReset: false,
|
||||
// 导出图片时canvas的缩放倍数,该配置会和window.devicePixelRatio值取最大值
|
||||
minExportImgCanvasScale: 2,
|
||||
// 节点鼠标hover和激活时显示的矩形边框的颜色
|
||||
hoverRectColor: 'rgb(94, 200, 248)',
|
||||
// 节点鼠标hover和激活时显示的矩形边框距节点内容的距离
|
||||
hoverRectPadding: 2,
|
||||
// 双击节点进入节点文本编辑时是否默认选中文本,默认只在创建新节点时会选中
|
||||
selectTextOnEnterEditText: false,
|
||||
// 删除节点后激活相邻节点
|
||||
deleteNodeActive: true,
|
||||
// 拖拽节点时鼠标移动到画布边缘是否开启画布自动移动
|
||||
autoMoveWhenMouseInEdgeOnDrag: true,
|
||||
// 是否首次加载fit view
|
||||
fit: false
|
||||
}
|
||||
|
||||
@@ -37,7 +37,11 @@ class Command {
|
||||
this.commands[name].forEach(fn => {
|
||||
fn(...args)
|
||||
})
|
||||
if (['BACK', 'FORWARD', 'SET_NODE_ACTIVE', 'CLEAR_ACTIVE_NODE'].includes(name)) {
|
||||
if (
|
||||
['BACK', 'FORWARD', 'SET_NODE_ACTIVE', 'CLEAR_ACTIVE_NODE'].includes(
|
||||
name
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.addHistory()
|
||||
@@ -78,7 +82,11 @@ class Command {
|
||||
}
|
||||
let data = this.getCopyData()
|
||||
// 此次数据和上次一样则不重复添加
|
||||
if (this.history.length > 0 && JSON.stringify(this.history[this.history.length - 1]) === JSON.stringify(data)) {
|
||||
if (
|
||||
this.history.length > 0 &&
|
||||
JSON.stringify(this.history[this.history.length - 1]) ===
|
||||
JSON.stringify(data)
|
||||
) {
|
||||
return
|
||||
}
|
||||
// 删除当前历史指针后面的数据
|
||||
@@ -123,7 +131,11 @@ class Command {
|
||||
let len = this.history.length
|
||||
if (this.activeHistoryIndex + step <= len - 1) {
|
||||
this.activeHistoryIndex += step
|
||||
this.mindMap.emit('back_forward', this.activeHistoryIndex, this.history.length)
|
||||
this.mindMap.emit(
|
||||
'back_forward',
|
||||
this.activeHistoryIndex,
|
||||
this.history.length
|
||||
)
|
||||
let data = simpleDeepClone(this.history[this.activeHistoryIndex])
|
||||
this.mindMap.emit('data_change', data)
|
||||
return data
|
||||
@@ -138,10 +150,10 @@ class Command {
|
||||
// 移除节点数据中的uid
|
||||
removeDataUid(data) {
|
||||
data = simpleDeepClone(data)
|
||||
let walk = (root) => {
|
||||
let walk = root => {
|
||||
delete root.data.uid
|
||||
if (root.children && root.children.length > 0) {
|
||||
root.children.forEach((item) => {
|
||||
root.children.forEach(item => {
|
||||
walk(item)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -46,13 +46,20 @@ export default class KeyCommand {
|
||||
if (this.mindMap.richText && this.mindMap.richText.showTextEdit) {
|
||||
return
|
||||
}
|
||||
if (this.mindMap.renderer.textEdit.showTextEdit || (this.mindMap.associativeLine && this.mindMap.associativeLine.showTextEdit)) {
|
||||
if (
|
||||
this.mindMap.renderer.textEdit.showTextEdit ||
|
||||
(this.mindMap.associativeLine &&
|
||||
this.mindMap.associativeLine.showTextEdit)
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.isInSvg = false
|
||||
})
|
||||
window.addEventListener('keydown', e => {
|
||||
if (this.isPause || (this.mindMap.opt.enableShortcutOnlyWhenMouseInSvg && !this.isInSvg)) {
|
||||
if (
|
||||
this.isPause ||
|
||||
(this.mindMap.opt.enableShortcutOnlyWhenMouseInSvg && !this.isInSvg)
|
||||
) {
|
||||
return
|
||||
}
|
||||
Object.keys(this.shortcutMap).forEach(key => {
|
||||
|
||||
@@ -113,7 +113,7 @@ class Event extends EventEmitter {
|
||||
this.isMiddleMousedown ||
|
||||
(useLeftKeySelectionRightKeyDrag
|
||||
? this.isRightMousedown
|
||||
: this.isLeftMousedown)
|
||||
: this.isLeftMousedown)
|
||||
) {
|
||||
e.preventDefault()
|
||||
this.emit('drag', e, this)
|
||||
|
||||
@@ -342,7 +342,7 @@ class Render {
|
||||
}
|
||||
})
|
||||
})
|
||||
this.mindMap.emit('node_active', null, this.activeNodeList)
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
}
|
||||
|
||||
// 清除当前激活的节点
|
||||
@@ -382,7 +382,7 @@ class Render {
|
||||
// 检索某个节点在激活列表里的索引
|
||||
findActiveNodeIndex(node) {
|
||||
return this.activeNodeList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ class Render {
|
||||
getNodeIndex(node) {
|
||||
return node.parent
|
||||
? node.parent.children.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
: 0
|
||||
}
|
||||
@@ -407,7 +407,7 @@ class Render {
|
||||
// 激活节点需要显示展开收起按钮
|
||||
node.showExpandBtn()
|
||||
setTimeout(() => {
|
||||
node.updateNodeShape()
|
||||
node.updateNodeActive()
|
||||
}, 0)
|
||||
}
|
||||
},
|
||||
@@ -416,6 +416,7 @@ class Render {
|
||||
0,
|
||||
0
|
||||
)
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
}
|
||||
|
||||
// 回退
|
||||
@@ -552,7 +553,7 @@ class Render {
|
||||
let parent = node.parent
|
||||
let childList = parent.children
|
||||
let index = childList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
if (index === -1 || index === 0) {
|
||||
return
|
||||
@@ -579,7 +580,7 @@ class Render {
|
||||
let parent = node.parent
|
||||
let childList = parent.children
|
||||
let index = childList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
if (index === -1 || index === childList.length - 1) {
|
||||
return
|
||||
@@ -751,7 +752,7 @@ class Render {
|
||||
let nodeParent = node.parent
|
||||
let nodeBorthers = nodeParent.children
|
||||
let nodeIndex = nodeBorthers.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
if (nodeIndex === -1) {
|
||||
return
|
||||
@@ -763,7 +764,7 @@ class Render {
|
||||
let existParent = exist.parent
|
||||
let existBorthers = existParent.children
|
||||
let existIndex = existBorthers.findIndex(item => {
|
||||
return item === exist
|
||||
return item.uid === exist.uid
|
||||
})
|
||||
if (existIndex === -1) {
|
||||
return
|
||||
@@ -790,7 +791,7 @@ class Render {
|
||||
let nodeParent = node.parent
|
||||
let nodeBorthers = nodeParent.children
|
||||
let nodeIndex = nodeBorthers.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
if (nodeIndex === -1) {
|
||||
return
|
||||
@@ -802,7 +803,7 @@ class Render {
|
||||
let existParent = exist.parent
|
||||
let existBorthers = existParent.children
|
||||
let existIndex = existBorthers.findIndex(item => {
|
||||
return item === exist
|
||||
return item.uid === exist.uid
|
||||
})
|
||||
if (existIndex === -1) {
|
||||
return
|
||||
@@ -823,6 +824,8 @@ class Render {
|
||||
if (this.activeNodeList.length <= 0 && appointNodes.length <= 0) {
|
||||
return
|
||||
}
|
||||
// 删除节点后需要激活的节点
|
||||
let needActiveNode = null
|
||||
let isAppointNodes = appointNodes.length > 0
|
||||
let list = isAppointNodes ? appointNodes : this.activeNodeList
|
||||
let root = list.find(node => {
|
||||
@@ -836,6 +839,28 @@ class Render {
|
||||
root.children = []
|
||||
root.nodeData.children = []
|
||||
} else {
|
||||
// 如果只选中了一个节点,删除后激活其兄弟节点或者父节点
|
||||
if (
|
||||
this.activeNodeList.length === 1 &&
|
||||
!this.activeNodeList[0].isGeneralization &&
|
||||
this.mindMap.opt.deleteNodeActive
|
||||
) {
|
||||
const node = this.activeNodeList[0]
|
||||
const broList = node.parent.children
|
||||
const nodeIndex = broList.findIndex(item => item.uid === node.uid)
|
||||
// 如果后面有兄弟节点
|
||||
if (nodeIndex < broList.length - 1) {
|
||||
needActiveNode = broList[nodeIndex + 1]
|
||||
} else {
|
||||
// 如果前面有兄弟节点
|
||||
if (nodeIndex > 0) {
|
||||
needActiveNode = broList[nodeIndex - 1]
|
||||
} else {
|
||||
// 没有兄弟节点
|
||||
needActiveNode = node.parent
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let node = list[i]
|
||||
if (isAppointNodes) list.splice(i, 1)
|
||||
@@ -854,7 +879,14 @@ class Render {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.mindMap.emit('node_active', null, this.activeNodeList)
|
||||
this.activeNodeList = []
|
||||
// 激活被删除节点的兄弟节点或父节点
|
||||
if (needActiveNode) {
|
||||
this.activeNodeList.push(needActiveNode)
|
||||
this.setNodeActive(needActiveNode, true)
|
||||
needActiveNode = null
|
||||
}
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
this.mindMap.render()
|
||||
}
|
||||
|
||||
@@ -886,7 +918,7 @@ class Render {
|
||||
let copyData = copyNodeTree({}, node, true)
|
||||
this.removeActiveNode(node)
|
||||
this.removeOneNode(node)
|
||||
this.mindMap.emit('node_active', null, this.activeNodeList)
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
this.mindMap.render()
|
||||
if (callback && typeof callback === 'function') {
|
||||
callback(copyData)
|
||||
@@ -901,7 +933,7 @@ class Render {
|
||||
// let copyData = copyNodeTree({}, node, false, true)
|
||||
this.removeActiveNode(node)
|
||||
this.removeOneNode(node)
|
||||
this.mindMap.emit('node_active', null, this.activeNodeList)
|
||||
this.mindMap.emit('node_active', null, [...this.activeNodeList])
|
||||
toNode.nodeData.children.push(node.nodeData)
|
||||
this.mindMap.render()
|
||||
if (toNode.isRoot) {
|
||||
@@ -921,19 +953,9 @@ class Render {
|
||||
}
|
||||
|
||||
// 设置节点样式
|
||||
setNodeStyle(node, prop, value, isActive) {
|
||||
let data = {}
|
||||
if (isActive) {
|
||||
data = {
|
||||
activeStyle: {
|
||||
...(node.nodeData.data.activeStyle || {}),
|
||||
[prop]: value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = {
|
||||
[prop]: value
|
||||
}
|
||||
setNodeStyle(node, prop, value) {
|
||||
let data = {
|
||||
[prop]: value
|
||||
}
|
||||
// 如果开启了富文本,则需要应用到富文本上
|
||||
if (this.mindMap.richText) {
|
||||
@@ -954,18 +976,8 @@ class Render {
|
||||
}
|
||||
|
||||
// 设置节点多个样式
|
||||
setNodeStyles(node, style, isActive) {
|
||||
let data = {}
|
||||
if (isActive) {
|
||||
data = {
|
||||
activeStyle: {
|
||||
...(node.nodeData.data.activeStyle || {}),
|
||||
...style
|
||||
}
|
||||
}
|
||||
} else {
|
||||
data = style
|
||||
}
|
||||
setNodeStyles(node, style) {
|
||||
let data = { ...style }
|
||||
// 如果开启了富文本,则需要应用到富文本上
|
||||
if (this.mindMap.richText) {
|
||||
let config = this.mindMap.richText.normalStyleToRichTextStyle(style)
|
||||
@@ -1000,7 +1012,7 @@ class Render {
|
||||
} else {
|
||||
node.hideExpandBtn()
|
||||
}
|
||||
node.updateNodeShape()
|
||||
node.updateNodeActive()
|
||||
}
|
||||
|
||||
// 设置节点是否展开
|
||||
@@ -1112,7 +1124,13 @@ class Render {
|
||||
|
||||
// 设置节点图片
|
||||
setNodeImage(node, data) {
|
||||
const { url, title, width, height, custom = false } = data || { url: '', title: '', width: 0, height: 0, custom: false }
|
||||
const {
|
||||
url,
|
||||
title,
|
||||
width,
|
||||
height,
|
||||
custom = false
|
||||
} = data || { url: '', title: '', width: 0, height: 0, custom: false }
|
||||
this.setNodeDataRender(node, {
|
||||
image: url,
|
||||
imageTitle: title || '',
|
||||
|
||||
@@ -63,7 +63,7 @@ export default class TextEdit {
|
||||
const node = activeNodeList[0]
|
||||
// 当正在输入中文或英文或数字时,如果没有按下组合键,那么自动进入文本编辑模式
|
||||
if (node && this.checkIsAutoEnterTextEditKey(e)) {
|
||||
this.show(node)
|
||||
this.show(node, e, false, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -93,7 +93,8 @@ export default class TextEdit {
|
||||
|
||||
// 显示文本编辑框
|
||||
// isInserting:是否是刚创建的节点
|
||||
async show(node, e, isInserting = false) {
|
||||
// isFromKeyDown:是否是在按键事件进入的编辑
|
||||
async show(node, e, isInserting = false, isFromKeyDown = false) {
|
||||
// 使用了自定义节点内容那么不响应编辑事件
|
||||
if (node.isUseCustomNodeContent()) {
|
||||
return
|
||||
@@ -114,10 +115,10 @@ export default class TextEdit {
|
||||
this.mindMap.view.translateXY(offsetLeft, offsetTop)
|
||||
let rect = node._textData.node.node.getBoundingClientRect()
|
||||
if (this.mindMap.richText) {
|
||||
this.mindMap.richText.showEditText(node, rect, isInserting)
|
||||
this.mindMap.richText.showEditText(node, rect, isInserting, isFromKeyDown)
|
||||
return
|
||||
}
|
||||
this.showEditTextBox(node, rect, isInserting)
|
||||
this.showEditTextBox(node, rect, isInserting, isFromKeyDown)
|
||||
}
|
||||
|
||||
// 处理画布缩放
|
||||
@@ -135,8 +136,10 @@ export default class TextEdit {
|
||||
}
|
||||
|
||||
// 显示文本编辑框
|
||||
showEditTextBox(node, rect, isInserting) {
|
||||
showEditTextBox(node, rect, isInserting, isFromKeyDown) {
|
||||
if (this.showTextEdit) return
|
||||
const { nodeTextEditZIndex, textAutoWrapWidth, selectTextOnEnterEditText } =
|
||||
this.mindMap.opt
|
||||
this.mindMap.emit('before_show_text_edit')
|
||||
this.registerTmpShortcut()
|
||||
if (!this.textEditNode) {
|
||||
@@ -169,15 +172,14 @@ export default class TextEdit {
|
||||
)
|
||||
let isMultiLine = node._textData.node.attr('data-ismultiLine') === 'true'
|
||||
node.style.domText(this.textEditNode, scale, isMultiLine)
|
||||
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
||||
this.textEditNode.style.zIndex = nodeTextEditZIndex
|
||||
this.textEditNode.innerHTML = textLines.join('<br>')
|
||||
this.textEditNode.style.minWidth = rect.width + 10 + 'px'
|
||||
this.textEditNode.style.minHeight = rect.height + 6 + 'px'
|
||||
this.textEditNode.style.left = rect.left + 'px'
|
||||
this.textEditNode.style.top = rect.top + 'px'
|
||||
this.textEditNode.style.display = 'block'
|
||||
this.textEditNode.style.maxWidth =
|
||||
this.mindMap.opt.textAutoWrapWidth * scale + 'px'
|
||||
this.textEditNode.style.maxWidth = textAutoWrapWidth * scale + 'px'
|
||||
if (isMultiLine && lineHeight !== 1) {
|
||||
this.textEditNode.style.transform = `translateY(${
|
||||
-((lineHeight * fontSize - fontSize) / 2) * scale
|
||||
@@ -188,7 +190,7 @@ export default class TextEdit {
|
||||
// if (!this.cacheEditingText) {
|
||||
// this.selectNodeText()
|
||||
// }
|
||||
if (isInserting) {
|
||||
if (isInserting || (selectTextOnEnterEditText && !isFromKeyDown)) {
|
||||
this.selectNodeText()
|
||||
} else {
|
||||
this.focus()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Style from './Style'
|
||||
import Shape from './Shape'
|
||||
import { G, ForeignObject, SVG } from '@svgdotjs/svg.js'
|
||||
import { G, ForeignObject, SVG, Rect } from '@svgdotjs/svg.js'
|
||||
import nodeGeneralizationMethods from './nodeGeneralization'
|
||||
import nodeExpandBtnMethods from './nodeExpandBtn'
|
||||
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
||||
@@ -58,6 +58,7 @@ class Node {
|
||||
// 节点内容的容器
|
||||
this.group = null
|
||||
this.shapeNode = null // 节点形状节点
|
||||
this.hoverNode = null // 节点hover和激活的节点
|
||||
// 节点内容对象
|
||||
this._customNodeContent = null
|
||||
this._imgData = null
|
||||
@@ -269,6 +270,7 @@ class Node {
|
||||
layout() {
|
||||
// 清除之前的内容
|
||||
this.group.clear()
|
||||
const { hoverRectPadding } = this.mindMap.opt
|
||||
let { width, height, textContentItemMargin } = this
|
||||
let { paddingY } = this.getPaddingVale()
|
||||
const halfBorderWidth = this.getBorderWidth() / 2
|
||||
@@ -277,21 +279,32 @@ class Node {
|
||||
this.shapeNode = this.shapeInstance.createShape()
|
||||
this.shapeNode.addClass('smm-node-shape')
|
||||
this.shapeNode.translate(halfBorderWidth, halfBorderWidth)
|
||||
this.style.shape(this.shapeNode)
|
||||
this.group.add(this.shapeNode)
|
||||
this.updateNodeShape()
|
||||
// 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示
|
||||
this.renderExpandBtnPlaceholderRect()
|
||||
// 概要节点添加一个带所属节点id的类名
|
||||
if (this.isGeneralization && this.generalizationBelongNode) {
|
||||
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
||||
}
|
||||
// 激活hover和激活边框
|
||||
const addHoverNode = () => {
|
||||
this.hoverNode = new Rect()
|
||||
.size(width + hoverRectPadding * 2, height + hoverRectPadding * 2)
|
||||
.x(-hoverRectPadding)
|
||||
.y(-hoverRectPadding)
|
||||
this.hoverNode.addClass('smm-hover-node')
|
||||
this.style.hoverNode(this.hoverNode, width, height)
|
||||
this.group.add(this.hoverNode)
|
||||
}
|
||||
// 如果存在自定义节点内容,那么使用自定义节点内容
|
||||
if (this.isUseCustomNodeContent()) {
|
||||
let foreignObject = new ForeignObject()
|
||||
foreignObject.width(width)
|
||||
foreignObject.height(height)
|
||||
foreignObject.add(SVG(this._customNodeContent))
|
||||
foreignObject.add(this._customNodeContent)
|
||||
this.group.add(foreignObject)
|
||||
addHoverNode()
|
||||
return
|
||||
}
|
||||
// 图片节点
|
||||
@@ -365,6 +378,7 @@ class Node {
|
||||
: 0)
|
||||
)
|
||||
this.group.add(textContentNested)
|
||||
addHoverNode()
|
||||
}
|
||||
|
||||
// 给节点绑定事件
|
||||
@@ -380,14 +394,27 @@ class Node {
|
||||
this.active(e)
|
||||
})
|
||||
this.group.on('mousedown', e => {
|
||||
if (this.isRoot && e.which === 3 && !this.mindMap.opt.readonly) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
if (!this.isRoot && e.which !== 2 && !this.mindMap.opt.readonly) {
|
||||
e.stopPropagation()
|
||||
const {
|
||||
readonly,
|
||||
enableCtrlKeyNodeSelection,
|
||||
useLeftKeySelectionRightKeyDrag
|
||||
} = this.mindMap.opt
|
||||
// 只读模式不需要阻止冒泡
|
||||
if (!readonly) {
|
||||
if (this.isRoot) {
|
||||
// 根节点,右键拖拽画布模式下不需要阻止冒泡
|
||||
if (e.which === 3 && !useLeftKeySelectionRightKeyDrag) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
} else {
|
||||
// 非根节点,且按下的是非鼠标中键,需要阻止事件冒泡
|
||||
if (e.which !== 2) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
}
|
||||
// 多选和取消多选
|
||||
if (e.ctrlKey && this.mindMap.opt.enableCtrlKeyNodeSelection) {
|
||||
if (e.ctrlKey && enableCtrlKeyNodeSelection) {
|
||||
this.isMultipleChoice = true
|
||||
let isActive = this.nodeData.data.isActive
|
||||
if (!isActive)
|
||||
@@ -400,11 +427,9 @@ class Node {
|
||||
this.mindMap.renderer[isActive ? 'removeActiveNode' : 'addActiveNode'](
|
||||
this
|
||||
)
|
||||
this.mindMap.emit(
|
||||
'node_active',
|
||||
isActive ? null : this,
|
||||
this.mindMap.renderer.activeNodeList
|
||||
)
|
||||
this.mindMap.emit('node_active', isActive ? null : this, [
|
||||
...this.mindMap.renderer.activeNodeList
|
||||
])
|
||||
}
|
||||
this.mindMap.emit('node_mousedown', this, e)
|
||||
})
|
||||
@@ -435,13 +460,21 @@ class Node {
|
||||
})
|
||||
// 右键菜单事件
|
||||
this.group.on('contextmenu', e => {
|
||||
const { readonly, useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
|
||||
// 按住ctrl键点击鼠标左键不知为何触发的是contextmenu事件
|
||||
if (this.mindMap.opt.readonly || e.ctrlKey) {
|
||||
// || this.isGeneralization
|
||||
if (readonly || e.ctrlKey) {
|
||||
return
|
||||
}
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
// 如果是多选节点结束,那么不要触发右键菜单事件
|
||||
if (
|
||||
this.mindMap.select &&
|
||||
!useLeftKeySelectionRightKeyDrag &&
|
||||
this.mindMap.select.hasSelectRange()
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (this.nodeData.data.isActive) {
|
||||
this.renderer.clearActive()
|
||||
}
|
||||
@@ -463,14 +496,15 @@ class Node {
|
||||
this.renderer.clearActive()
|
||||
this.mindMap.execCommand('SET_NODE_ACTIVE', this, true)
|
||||
this.renderer.addActiveNode(this)
|
||||
this.mindMap.emit('node_active', this, this.renderer.activeNodeList)
|
||||
this.mindMap.emit('node_active', this, [...this.renderer.activeNodeList])
|
||||
}
|
||||
|
||||
// 更新节点
|
||||
update(isLayout = false) {
|
||||
update() {
|
||||
if (!this.group) {
|
||||
return
|
||||
}
|
||||
this.updateNodeActive()
|
||||
let { alwaysShowExpandBtn } = this.mindMap.opt
|
||||
if (alwaysShowExpandBtn) {
|
||||
// 需要移除展开收缩按钮
|
||||
@@ -543,13 +577,11 @@ class Node {
|
||||
return sizeChange
|
||||
}
|
||||
|
||||
// 更新节点形状样式
|
||||
updateNodeShape() {
|
||||
if (!this.shapeNode) return
|
||||
const shape = this.getShape()
|
||||
this.style[shape === CONSTANTS.SHAPE.RECTANGLE ? 'rect' : 'shape'](
|
||||
this.shapeNode
|
||||
)
|
||||
// 更新节点激活状态
|
||||
updateNodeActive() {
|
||||
if (!this.group) return
|
||||
const isActive = this.nodeData.data.isActive
|
||||
this.group[isActive ? 'addClass' : 'removeClass']('active')
|
||||
}
|
||||
|
||||
// 递归渲染
|
||||
@@ -557,9 +589,7 @@ class Node {
|
||||
// 节点
|
||||
// 重新渲染连线
|
||||
this.renderLine()
|
||||
let isLayout = false
|
||||
if (!this.group) {
|
||||
isLayout = true
|
||||
// 创建组
|
||||
this.group = new G()
|
||||
this.group.addClass('smm-node')
|
||||
@@ -569,7 +599,7 @@ class Node {
|
||||
this.bindGroupEvent()
|
||||
this.draw.add(this.group)
|
||||
this.layout()
|
||||
this.update(isLayout)
|
||||
this.update()
|
||||
} else {
|
||||
this.draw.add(this.group)
|
||||
if (this.needLayout) {
|
||||
@@ -770,12 +800,12 @@ class Node {
|
||||
|
||||
// 检测当前节点是否是某个节点的祖先节点
|
||||
isParent(node) {
|
||||
if (this === node) {
|
||||
if (this.uid === node.uid) {
|
||||
return false
|
||||
}
|
||||
let parent = node.parent
|
||||
while (parent) {
|
||||
if (this === parent) {
|
||||
if (this.uid === parent.uid) {
|
||||
return true
|
||||
}
|
||||
parent = parent.parent
|
||||
@@ -785,11 +815,11 @@ class Node {
|
||||
|
||||
// 检测当前节点是否是某个节点的兄弟节点
|
||||
isBrother(node) {
|
||||
if (!this.parent || this === node) {
|
||||
if (!this.parent || this.uid === node.uid) {
|
||||
return false
|
||||
}
|
||||
return this.parent.children.find(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
}
|
||||
|
||||
@@ -803,8 +833,8 @@ class Node {
|
||||
}
|
||||
|
||||
// 获取某个样式
|
||||
getStyle(prop, root, isActive) {
|
||||
let v = this.style.merge(prop, root, isActive)
|
||||
getStyle(prop, root) {
|
||||
let v = this.style.merge(prop, root)
|
||||
return v === undefined ? '' : v
|
||||
}
|
||||
|
||||
@@ -833,7 +863,7 @@ class Node {
|
||||
|
||||
// 获取节点非节点状态的边框大小
|
||||
getBorderWidth() {
|
||||
return this.style.merge('borderWidth', false, false) || 0
|
||||
return this.style.merge('borderWidth', false) || 0
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
|
||||
@@ -62,14 +62,10 @@ export default class Shape {
|
||||
// 创建形状节点
|
||||
createShape() {
|
||||
const shape = this.node.getShape()
|
||||
const borderWidth = this.node.getBorderWidth()
|
||||
let { width, height } = this.node
|
||||
width -= borderWidth
|
||||
height -= borderWidth
|
||||
let node = null
|
||||
// 矩形
|
||||
if (shape === CONSTANTS.SHAPE.RECTANGLE) {
|
||||
node = new Rect().size(width, height)
|
||||
node = this.createRect()
|
||||
} else if (shape === CONSTANTS.SHAPE.DIAMOND) {
|
||||
// 菱形
|
||||
node = this.createDiamond()
|
||||
@@ -98,9 +94,41 @@ export default class Shape {
|
||||
return node
|
||||
}
|
||||
|
||||
// 获取节点减去节点边框宽度、hover节点边框宽度后的尺寸
|
||||
getNodeSize() {
|
||||
const borderWidth = this.node.getBorderWidth()
|
||||
let { width, height } = this.node
|
||||
width -= borderWidth
|
||||
height -= borderWidth
|
||||
return {
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
|
||||
// 创建矩形
|
||||
createRect() {
|
||||
let { width, height } = this.getNodeSize()
|
||||
let borderRadius = this.node.style.merge('borderRadius')
|
||||
return new Path().plot(`
|
||||
M${borderRadius},0
|
||||
L${width - borderRadius},0
|
||||
C${width - borderRadius},0 ${width},${0} ${width},${borderRadius}
|
||||
L${width},${height - borderRadius}
|
||||
C${width},${height - borderRadius} ${width},${height} ${
|
||||
width - borderRadius
|
||||
},${height}
|
||||
L${borderRadius},${height}
|
||||
C${borderRadius},${height} ${0},${height} ${0},${height - borderRadius}
|
||||
L${0},${borderRadius}
|
||||
C${0},${borderRadius} ${0},${0} ${borderRadius},${0}
|
||||
Z
|
||||
`)
|
||||
}
|
||||
|
||||
// 创建菱形
|
||||
createDiamond() {
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
let halfWidth = width / 2
|
||||
let halfHeight = height / 2
|
||||
let topX = halfWidth
|
||||
@@ -123,7 +151,7 @@ export default class Shape {
|
||||
createParallelogram() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
return new Polygon().plot([
|
||||
[paddingX, 0],
|
||||
[width, 0],
|
||||
@@ -134,7 +162,7 @@ export default class Shape {
|
||||
|
||||
// 创建圆角矩形
|
||||
createRoundedRectangle() {
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
let halfHeight = height / 2
|
||||
return new Path().plot(`
|
||||
M${halfHeight},0
|
||||
@@ -148,7 +176,7 @@ export default class Shape {
|
||||
// 创建八角矩形
|
||||
createOctagonalRectangle() {
|
||||
let w = 5
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
return new Polygon().plot([
|
||||
[0, w],
|
||||
[w, 0],
|
||||
@@ -165,7 +193,7 @@ export default class Shape {
|
||||
createOuterTriangularRectangle() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
return new Polygon().plot([
|
||||
[paddingX, 0],
|
||||
[width - paddingX, 0],
|
||||
@@ -180,7 +208,7 @@ export default class Shape {
|
||||
createInnerTriangularRectangle() {
|
||||
let { paddingX } = this.node.getPaddingVale()
|
||||
paddingX = paddingX || this.node.shapePadding.paddingX
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
return new Polygon().plot([
|
||||
[0, 0],
|
||||
[width, 0],
|
||||
@@ -193,7 +221,7 @@ export default class Shape {
|
||||
|
||||
// 创建椭圆
|
||||
createEllipse() {
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
let halfWidth = width / 2
|
||||
let halfHeight = height / 2
|
||||
return new Path().plot(`
|
||||
@@ -206,7 +234,7 @@ export default class Shape {
|
||||
|
||||
// 创建圆
|
||||
createCircle() {
|
||||
let { width, height } = this.node
|
||||
let { width, height } = this.getNodeSize()
|
||||
let halfWidth = width / 2
|
||||
let halfHeight = height / 2
|
||||
return new Path().plot(`
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { tagColorList, nodeDataNoStylePropList } from '../../../constants/constant'
|
||||
import { tagColorList } from '../../../constants/constant'
|
||||
import { checkIsNodeStyleDataKey } from '../../../utils/index'
|
||||
|
||||
const rootProp = ['paddingX', 'paddingY']
|
||||
const backgroundStyleProps = ['backgroundColor', 'backgroundImage', 'backgroundRepeat', 'backgroundPosition', 'backgroundSize']
|
||||
const backgroundStyleProps = [
|
||||
'backgroundColor',
|
||||
'backgroundImage',
|
||||
'backgroundRepeat',
|
||||
'backgroundPosition',
|
||||
'backgroundSize'
|
||||
]
|
||||
|
||||
// 样式类
|
||||
class Style {
|
||||
@@ -10,12 +18,18 @@ class Style {
|
||||
if (!Style.cacheStyle) {
|
||||
Style.cacheStyle = {}
|
||||
let style = window.getComputedStyle(el)
|
||||
backgroundStyleProps.forEach((prop) => {
|
||||
backgroundStyleProps.forEach(prop => {
|
||||
Style.cacheStyle[prop] = style[prop]
|
||||
})
|
||||
}
|
||||
// 设置新样式
|
||||
let { backgroundColor, backgroundImage, backgroundRepeat, backgroundPosition, backgroundSize } = themeConfig
|
||||
let {
|
||||
backgroundColor,
|
||||
backgroundImage,
|
||||
backgroundRepeat,
|
||||
backgroundPosition,
|
||||
backgroundSize
|
||||
} = themeConfig
|
||||
el.style.backgroundColor = backgroundColor
|
||||
if (backgroundImage && backgroundImage !== 'none') {
|
||||
el.style.backgroundImage = `url(${backgroundImage})`
|
||||
@@ -30,7 +44,7 @@ class Style {
|
||||
// 移除背景样式
|
||||
static removeBackgroundStyle(el) {
|
||||
if (!Style.cacheStyle) return
|
||||
backgroundStyleProps.forEach((prop) => {
|
||||
backgroundStyleProps.forEach(prop => {
|
||||
el.style[prop] = Style.cacheStyle[prop]
|
||||
})
|
||||
Style.cacheStyle = null
|
||||
@@ -42,7 +56,7 @@ class Style {
|
||||
}
|
||||
|
||||
// 合并样式
|
||||
merge(prop, root, isActive) {
|
||||
merge(prop, root) {
|
||||
let themeConfig = this.ctx.mindMap.themeConfig
|
||||
// 三级及以下节点
|
||||
let defaultConfig = themeConfig.node
|
||||
@@ -59,17 +73,6 @@ class Style {
|
||||
// 二级节点
|
||||
defaultConfig = themeConfig.second
|
||||
}
|
||||
// 激活状态
|
||||
if (isActive !== undefined ? isActive : this.ctx.nodeData.data.isActive) {
|
||||
if (
|
||||
this.ctx.nodeData.data.activeStyle &&
|
||||
this.ctx.nodeData.data.activeStyle[prop] !== undefined
|
||||
) {
|
||||
return this.ctx.nodeData.data.activeStyle[prop]
|
||||
} else if (defaultConfig.active && defaultConfig.active[prop]) {
|
||||
return defaultConfig.active[prop]
|
||||
}
|
||||
}
|
||||
// 优先使用节点本身的样式
|
||||
return this.getSelfStyle(prop) !== undefined
|
||||
? this.getSelfStyle(prop)
|
||||
@@ -77,8 +80,8 @@ class Style {
|
||||
}
|
||||
|
||||
// 获取某个样式值
|
||||
getStyle(prop, root, isActive) {
|
||||
return this.merge(prop, root, isActive)
|
||||
getStyle(prop, root) {
|
||||
return this.merge(prop, root)
|
||||
}
|
||||
|
||||
// 获取自身自定义样式
|
||||
@@ -142,10 +145,10 @@ class Style {
|
||||
|
||||
// 获取文本样式
|
||||
getTextFontStyle() {
|
||||
return {
|
||||
italic: this.merge('fontStyle') === 'italic',
|
||||
bold: this.merge('fontWeight'),
|
||||
fontSize: this.merge('fontSize'),
|
||||
return {
|
||||
italic: this.merge('fontStyle') === 'italic',
|
||||
bold: this.merge('fontWeight'),
|
||||
fontSize: this.merge('fontSize'),
|
||||
fontFamily: this.merge('fontFamily')
|
||||
}
|
||||
}
|
||||
@@ -201,25 +204,40 @@ class Style {
|
||||
|
||||
// 展开收起按钮
|
||||
iconBtn(node, node2, fillNode) {
|
||||
let { color, fill } = this.ctx.mindMap.opt.expandBtnStyle || {
|
||||
let { color, fill, fontSize, fontColor } = this.ctx.mindMap.opt
|
||||
.expandBtnStyle || {
|
||||
color: '#808080',
|
||||
fill: '#fff'
|
||||
fill: '#fff',
|
||||
fontSize: 12,
|
||||
strokeColor: '#333333',
|
||||
fontColor: '#333333'
|
||||
}
|
||||
node.fill({ color: color })
|
||||
node2.fill({ color: color })
|
||||
fillNode.fill({ color: fill })
|
||||
if (this.ctx.mindMap.opt.isShowExpandNum) {
|
||||
node.attr({ 'font-size': fontSize, 'font-color': fontColor })
|
||||
}
|
||||
}
|
||||
|
||||
// 是否设置了自定义的样式
|
||||
hasCustomStyle() {
|
||||
let res = false
|
||||
Object.keys(this.ctx.nodeData.data).forEach((item) => {
|
||||
if (!nodeDataNoStylePropList.includes(item)) {
|
||||
Object.keys(this.ctx.nodeData.data).forEach(item => {
|
||||
if (checkIsNodeStyleDataKey(item)) {
|
||||
res = true
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// hover和激活节点
|
||||
hoverNode(node) {
|
||||
const { hoverRectColor } = this.ctx.mindMap.opt
|
||||
node.radius(5).fill('none').stroke({
|
||||
color: hoverRectColor
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Style.cacheStyle = null
|
||||
|
||||
@@ -39,13 +39,13 @@ function setShape(shape) {
|
||||
}
|
||||
|
||||
// 修改某个样式
|
||||
function setStyle(prop, value, isActive) {
|
||||
this.mindMap.execCommand('SET_NODE_STYLE', this, prop, value, isActive)
|
||||
function setStyle(prop, value) {
|
||||
this.mindMap.execCommand('SET_NODE_STYLE', this, prop, value)
|
||||
}
|
||||
|
||||
// 修改多个样式
|
||||
function setStyles(style, isActive) {
|
||||
this.mindMap.execCommand('SET_NODE_STYLES', this, style, isActive)
|
||||
function setStyles(style) {
|
||||
this.mindMap.execCommand('SET_NODE_STYLES', this, style)
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -160,12 +160,8 @@ function createTextNode() {
|
||||
return this.createRichTextNode()
|
||||
}
|
||||
let g = new G()
|
||||
let fontSize = this.getStyle('fontSize', false, this.nodeData.data.isActive)
|
||||
let lineHeight = this.getStyle(
|
||||
'lineHeight',
|
||||
false,
|
||||
this.nodeData.data.isActive
|
||||
)
|
||||
let fontSize = this.getStyle('fontSize', false)
|
||||
let lineHeight = this.getStyle('lineHeight', false)
|
||||
// 文本超长自动换行
|
||||
let textStyle = this.style.getTextFontStyle()
|
||||
let textArr = this.nodeData.data.text.split(/\n/gim)
|
||||
|
||||
@@ -6,13 +6,27 @@ function createExpandNodeContent() {
|
||||
if (this._openExpandNode) {
|
||||
return
|
||||
}
|
||||
let { open, close } = this.mindMap.opt.expandBtnIcon || {}
|
||||
// 展开的节点
|
||||
this._openExpandNode = SVG(open || btnsSvg.open).size(
|
||||
this.expandBtnSize,
|
||||
this.expandBtnSize
|
||||
)
|
||||
this._openExpandNode.x(0).y(-this.expandBtnSize / 2)
|
||||
let { close, open } = this.mindMap.opt.expandBtnIcon || {}
|
||||
// 根据配置判断是否显示数量按钮
|
||||
if (this.mindMap.opt.isShowExpandNum) {
|
||||
// 展开的节点
|
||||
this._openExpandNode = SVG()
|
||||
.text()
|
||||
.size(this.expandBtnSize, this.expandBtnSize)
|
||||
// 文本垂直居中
|
||||
this._openExpandNode.attr({
|
||||
'text-anchor': 'middle',
|
||||
'dominant-baseline': 'middle',
|
||||
x: this.expandBtnSize / 2,
|
||||
y: 2
|
||||
})
|
||||
} else {
|
||||
this._openExpandNode = SVG(open || btnsSvg.open).size(
|
||||
this.expandBtnSize,
|
||||
this.expandBtnSize
|
||||
)
|
||||
this._openExpandNode.x(0).y(-this.expandBtnSize / 2)
|
||||
}
|
||||
// 收起的节点
|
||||
this._closeExpandNode = SVG(close || btnsSvg.close).size(
|
||||
this.expandBtnSize,
|
||||
@@ -22,6 +36,7 @@ function createExpandNodeContent() {
|
||||
// 填充节点
|
||||
this._fillExpandNode = new Circle().size(this.expandBtnSize)
|
||||
this._fillExpandNode.x(0).y(-this.expandBtnSize / 2)
|
||||
|
||||
// 设置样式
|
||||
this.style.iconBtn(
|
||||
this._openExpandNode,
|
||||
@@ -29,7 +44,12 @@ function createExpandNodeContent() {
|
||||
this._fillExpandNode
|
||||
)
|
||||
}
|
||||
|
||||
function sumNode(data = []) {
|
||||
return data.reduce(
|
||||
(total, cur) => total + this.sumNode(cur.children || []),
|
||||
data.length
|
||||
)
|
||||
}
|
||||
// 创建或更新展开收缩按钮内容
|
||||
function updateExpandBtnNode() {
|
||||
let { expand } = this.nodeData.data
|
||||
@@ -47,7 +67,27 @@ function updateExpandBtnNode() {
|
||||
node = this._closeExpandNode
|
||||
this._lastExpandBtnType = true
|
||||
}
|
||||
if (this._expandBtn) this._expandBtn.add(this._fillExpandNode).add(node)
|
||||
|
||||
if (this._expandBtn) {
|
||||
// 如果是收起按钮加上边框
|
||||
let { isShowExpandNum, expandBtnStyle, expandBtnNumHandler } =
|
||||
this.mindMap.opt
|
||||
if (isShowExpandNum) {
|
||||
if (!expand) {
|
||||
// 数字按钮添加边框
|
||||
this._fillExpandNode.stroke({
|
||||
color: expandBtnStyle.strokeColor
|
||||
})
|
||||
// 计算子节点数量
|
||||
let count = this.sumNode(this.nodeData.children)
|
||||
count = expandBtnNumHandler(count)
|
||||
node.text(count)
|
||||
} else {
|
||||
this._fillExpandNode.stroke('none')
|
||||
}
|
||||
}
|
||||
this._expandBtn.add(this._fillExpandNode).add(node)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新展开收缩按钮位置
|
||||
@@ -138,5 +178,6 @@ export default {
|
||||
renderExpandBtn,
|
||||
removeExpandBtn,
|
||||
showExpandBtn,
|
||||
hideExpandBtn
|
||||
hideExpandBtn,
|
||||
sumNode
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import Node from './Node'
|
||||
import { createUid } from '../../../utils/index'
|
||||
|
||||
// 检查是否存在概要
|
||||
function checkHasGeneralization () {
|
||||
function checkHasGeneralization() {
|
||||
return !!this.nodeData.data.generalization
|
||||
}
|
||||
|
||||
// 创建概要节点
|
||||
function createGeneralizationNode () {
|
||||
function createGeneralizationNode() {
|
||||
if (this.isGeneralization || !this.checkHasGeneralization()) {
|
||||
return
|
||||
}
|
||||
@@ -35,14 +35,14 @@ function createGeneralizationNode () {
|
||||
}
|
||||
|
||||
// 更新概要节点
|
||||
function updateGeneralization () {
|
||||
function updateGeneralization() {
|
||||
if (this.isGeneralization) return
|
||||
this.removeGeneralization()
|
||||
this.createGeneralizationNode()
|
||||
}
|
||||
|
||||
// 渲染概要节点
|
||||
function renderGeneralization () {
|
||||
function renderGeneralization() {
|
||||
if (this.isGeneralization) return
|
||||
if (!this.checkHasGeneralization()) {
|
||||
this.removeGeneralization()
|
||||
@@ -65,7 +65,7 @@ function renderGeneralization () {
|
||||
}
|
||||
|
||||
// 删除概要节点
|
||||
function removeGeneralization () {
|
||||
function removeGeneralization() {
|
||||
if (this.isGeneralization) return
|
||||
if (this._generalizationLine) {
|
||||
this._generalizationLine.remove()
|
||||
@@ -86,7 +86,7 @@ function removeGeneralization () {
|
||||
}
|
||||
|
||||
// 隐藏概要节点
|
||||
function hideGeneralization () {
|
||||
function hideGeneralization() {
|
||||
if (this.isGeneralization) return
|
||||
if (this._generalizationLine) {
|
||||
this._generalizationLine.hide()
|
||||
@@ -97,7 +97,7 @@ function hideGeneralization () {
|
||||
}
|
||||
|
||||
// 显示概要节点
|
||||
function showGeneralization () {
|
||||
function showGeneralization() {
|
||||
if (this.isGeneralization) return
|
||||
if (this._generalizationLine) {
|
||||
this._generalizationLine.show()
|
||||
@@ -108,11 +108,11 @@ function showGeneralization () {
|
||||
}
|
||||
|
||||
export default {
|
||||
checkHasGeneralization,
|
||||
createGeneralizationNode,
|
||||
updateGeneralization,
|
||||
renderGeneralization,
|
||||
removeGeneralization,
|
||||
hideGeneralization,
|
||||
showGeneralization
|
||||
}
|
||||
checkHasGeneralization,
|
||||
createGeneralizationNode,
|
||||
updateGeneralization,
|
||||
renderGeneralization,
|
||||
removeGeneralization,
|
||||
hideGeneralization,
|
||||
showGeneralization
|
||||
}
|
||||
|
||||
@@ -79,7 +79,10 @@ class View {
|
||||
// 鼠标滚轮事件控制缩放
|
||||
if (mousewheelAction === CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM) {
|
||||
if (disableMouseWheelZoom) return
|
||||
const { x: clientX, y: clientY } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
const { x: clientX, y: clientY } = this.mindMap.toPos(
|
||||
e.clientX,
|
||||
e.clientY
|
||||
)
|
||||
let cx = mouseScaleCenterUseMousePosition ? clientX : undefined
|
||||
let cy = mouseScaleCenterUseMousePosition ? clientY : undefined
|
||||
switch (dir) {
|
||||
@@ -171,7 +174,6 @@ class View {
|
||||
|
||||
// 平移x方式到
|
||||
translateXTo(x) {
|
||||
if (x === 0) return
|
||||
this.x = x
|
||||
this.transform()
|
||||
}
|
||||
@@ -185,7 +187,6 @@ class View {
|
||||
|
||||
// 平移y方向到
|
||||
translateYTo(y) {
|
||||
if (y === 0) return
|
||||
this.y = y
|
||||
this.transform()
|
||||
}
|
||||
|
||||
@@ -46,7 +46,10 @@ class Base {
|
||||
|
||||
// 检查当前来源是否需要重新计算节点大小
|
||||
checkIsNeedResizeSources() {
|
||||
return [CONSTANTS.CHANGE_THEME, CONSTANTS.TRANSFORM_TO_NORMAL_NODE].includes(this.renderer.renderSource)
|
||||
return [
|
||||
CONSTANTS.CHANGE_THEME,
|
||||
CONSTANTS.TRANSFORM_TO_NORMAL_NODE
|
||||
].includes(this.renderer.renderSource)
|
||||
}
|
||||
|
||||
// 层级类型改变
|
||||
@@ -70,7 +73,10 @@ class Base {
|
||||
// 数据上保存了节点引用,那么直接复用节点
|
||||
if (data && data._node && !this.renderer.reRender) {
|
||||
newNode = data._node
|
||||
let isLayerTypeChange = this.checkIsLayerTypeChange(newNode.layerIndex, layerIndex)
|
||||
let isLayerTypeChange = this.checkIsLayerTypeChange(
|
||||
newNode.layerIndex,
|
||||
layerIndex
|
||||
)
|
||||
newNode.reset()
|
||||
newNode.layerIndex = layerIndex
|
||||
this.cacheNode(data._node.uid, newNode)
|
||||
@@ -85,7 +91,10 @@ class Base {
|
||||
newNode = this.lru.get(data.data.uid)
|
||||
// 保存该节点上一次的数据
|
||||
let lastData = JSON.stringify(newNode.nodeData.data)
|
||||
let isLayerTypeChange = this.checkIsLayerTypeChange(newNode.layerIndex, layerIndex)
|
||||
let isLayerTypeChange = this.checkIsLayerTypeChange(
|
||||
newNode.layerIndex,
|
||||
layerIndex
|
||||
)
|
||||
newNode.reset()
|
||||
newNode.nodeData = newNode.handleData(data || {})
|
||||
newNode.layerIndex = layerIndex
|
||||
@@ -139,7 +148,7 @@ class Base {
|
||||
} else if (initRootNodePositionMap[value] !== undefined) {
|
||||
return size * initRootNodePositionMap[value]
|
||||
} else if (/^\d\d*%$/.test(value)) {
|
||||
return Number.parseFloat(value) / 100 * size
|
||||
return (Number.parseFloat(value) / 100) * size
|
||||
} else {
|
||||
return (size - nodeSize) / 2
|
||||
}
|
||||
@@ -148,12 +157,24 @@ class Base {
|
||||
// 定位节点到画布中间
|
||||
setNodeCenter(node) {
|
||||
let { initRootNodePosition } = this.mindMap.opt
|
||||
let { CENTER }= CONSTANTS.INIT_ROOT_NODE_POSITION
|
||||
if (!initRootNodePosition || !Array.isArray(initRootNodePosition) || initRootNodePosition.length < 2) {
|
||||
let { CENTER } = CONSTANTS.INIT_ROOT_NODE_POSITION
|
||||
if (
|
||||
!initRootNodePosition ||
|
||||
!Array.isArray(initRootNodePosition) ||
|
||||
initRootNodePosition.length < 2
|
||||
) {
|
||||
initRootNodePosition = [CENTER, CENTER]
|
||||
}
|
||||
node.left = this.formatPosition(initRootNodePosition[0], this.mindMap.width, node.width)
|
||||
node.top = this.formatPosition(initRootNodePosition[1], this.mindMap.height, node.height)
|
||||
node.left = this.formatPosition(
|
||||
initRootNodePosition[0],
|
||||
this.mindMap.width,
|
||||
node.width
|
||||
)
|
||||
node.top = this.formatPosition(
|
||||
initRootNodePosition[1],
|
||||
this.mindMap.height,
|
||||
node.height
|
||||
)
|
||||
}
|
||||
|
||||
// 更新子节点属性
|
||||
@@ -170,7 +191,7 @@ class Base {
|
||||
// 更新子节点多个属性
|
||||
updateChildrenPro(children, props) {
|
||||
children.forEach(item => {
|
||||
Object.keys(props).forEach((prop) => {
|
||||
Object.keys(props).forEach(prop => {
|
||||
item[prop] += props[prop]
|
||||
})
|
||||
if (item.children && item.children.length && !item.hasCustomPosition()) {
|
||||
@@ -181,9 +202,13 @@ class Base {
|
||||
}
|
||||
|
||||
// 递归计算节点的宽度
|
||||
getNodeAreaWidth(node) {
|
||||
getNodeAreaWidth(node, withGeneralization = false) {
|
||||
let widthArr = []
|
||||
let totalGeneralizationNodeWidth = 0
|
||||
let loop = (node, width) => {
|
||||
if (withGeneralization && node.checkHasGeneralization()) {
|
||||
totalGeneralizationNodeWidth += node._generalizationNodeWidth
|
||||
}
|
||||
if (node.children.length) {
|
||||
width += node.width / 2
|
||||
node.children.forEach(item => {
|
||||
@@ -195,7 +220,7 @@ class Base {
|
||||
}
|
||||
}
|
||||
loop(node, 0)
|
||||
return Math.max(...widthArr)
|
||||
return Math.max(...widthArr) + totalGeneralizationNodeWidth
|
||||
}
|
||||
|
||||
// 二次贝塞尔曲线
|
||||
@@ -216,16 +241,22 @@ class Base {
|
||||
|
||||
// 获取节点的marginX
|
||||
getMarginX(layerIndex) {
|
||||
const { themeConfig, opt } = this.mindMap
|
||||
const { second, node } = themeConfig
|
||||
const hoverRectPadding = opt.hoverRectPadding * 2
|
||||
return layerIndex === 1
|
||||
? this.mindMap.themeConfig.second.marginX
|
||||
: this.mindMap.themeConfig.node.marginX
|
||||
? second.marginX + hoverRectPadding
|
||||
: node.marginX + hoverRectPadding
|
||||
}
|
||||
|
||||
// 获取节点的marginY
|
||||
getMarginY(layerIndex) {
|
||||
const { themeConfig, opt } = this.mindMap
|
||||
const { second, node } = themeConfig
|
||||
const hoverRectPadding = opt.hoverRectPadding * 2
|
||||
return layerIndex === 1
|
||||
? this.mindMap.themeConfig.second.marginY
|
||||
: this.mindMap.themeConfig.node.marginY
|
||||
? second.marginY + hoverRectPadding
|
||||
: node.marginY + hoverRectPadding
|
||||
}
|
||||
|
||||
// 获取节点包括概要在内的宽度
|
||||
|
||||
@@ -87,11 +87,18 @@ class CatalogOrganization extends Base {
|
||||
totalLeft += cur.width + marginX
|
||||
})
|
||||
} else {
|
||||
let totalTop = node.top + node.height + marginY + (this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
let totalTop =
|
||||
node.top +
|
||||
this.getNodeHeightWithGeneralization(node) +
|
||||
marginY +
|
||||
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
node.children.forEach(cur => {
|
||||
cur.left = node.left + node.width * 0.5
|
||||
cur.top = totalTop
|
||||
totalTop += cur.height + marginY + (this.getNodeActChildrenLength(cur) > 0 ? cur.expandBtnSize : 0)
|
||||
totalTop +=
|
||||
this.getNodeHeightWithGeneralization(cur) +
|
||||
marginY +
|
||||
(this.getNodeActChildrenLength(cur) > 0 ? cur.expandBtnSize : 0)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -112,7 +119,7 @@ class CatalogOrganization extends Base {
|
||||
}
|
||||
// 调整left
|
||||
if (parent && parent.isRoot) {
|
||||
let areaWidth = this.getNodeAreaWidth(node)
|
||||
let areaWidth = this.getNodeAreaWidth(node, true)
|
||||
let difference = areaWidth - node.width
|
||||
if (difference > 0) {
|
||||
this.updateBrothersLeft(node, difference)
|
||||
@@ -124,7 +131,13 @@ class CatalogOrganization extends Base {
|
||||
let marginY = this.getMarginY(layerIndex + 1)
|
||||
let totalHeight =
|
||||
node.children.reduce((h, item) => {
|
||||
return h + item.height + (this.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
return (
|
||||
h +
|
||||
this.getNodeHeightWithGeneralization(item) +
|
||||
(this.getNodeActChildrenLength(item) > 0
|
||||
? item.expandBtnSize
|
||||
: 0)
|
||||
)
|
||||
}, 0) +
|
||||
len * marginY
|
||||
this.updateBrothersTop(node, totalHeight)
|
||||
@@ -134,7 +147,7 @@ class CatalogOrganization extends Base {
|
||||
if (isRoot) {
|
||||
let { right, left } = this.getNodeBoundaries(node, 'h')
|
||||
let childrenWidth = right - left
|
||||
let offset = (node.left - left) - (childrenWidth - node.width) / 2
|
||||
let offset = node.left - left - (childrenWidth - node.width) / 2
|
||||
this.updateChildren(node.children, 'left', offset)
|
||||
}
|
||||
},
|
||||
@@ -147,7 +160,7 @@ class CatalogOrganization extends Base {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition() || _index <= index) {
|
||||
@@ -170,7 +183,7 @@ class CatalogOrganization extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
|
||||
@@ -56,10 +56,11 @@ class Fishbone extends Base {
|
||||
}
|
||||
// 计算二级节点的top值
|
||||
if (parent._node.isRoot) {
|
||||
let marginY = this.getMarginY(layerIndex)
|
||||
if (this.checkIsTop(newNode)) {
|
||||
newNode.top = parent._node.top - newNode.height
|
||||
newNode.top = parent._node.top - newNode.height - marginY
|
||||
} else {
|
||||
newNode.top = parent._node.top + parent._node.height
|
||||
newNode.top = parent._node.top + parent._node.height + marginY
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,15 +81,16 @@ class Fishbone extends Base {
|
||||
null,
|
||||
(node, parent, isRoot, layerIndex) => {
|
||||
if (node.isRoot) {
|
||||
let topTotalLeft = node.left + node.width + node.height
|
||||
let bottomTotalLeft = node.left + node.width + node.height
|
||||
let marginX = this.getMarginX(layerIndex + 1)
|
||||
let topTotalLeft = node.left + node.width + node.height + marginX
|
||||
let bottomTotalLeft = node.left + node.width + node.height + marginX
|
||||
node.children.forEach(item => {
|
||||
if (this.checkIsTop(item)) {
|
||||
item.left = topTotalLeft
|
||||
topTotalLeft += item.width
|
||||
topTotalLeft += item.width + marginX
|
||||
} else {
|
||||
item.left = bottomTotalLeft + 20
|
||||
bottomTotalLeft += item.width
|
||||
bottomTotalLeft += item.width + marginX
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -154,9 +156,11 @@ class Fishbone extends Base {
|
||||
getNodeAreaHeight(node) {
|
||||
let totalHeight = 0
|
||||
let loop = node => {
|
||||
let marginY = this.getMarginY(node.layerIndex)
|
||||
totalHeight +=
|
||||
node.height +
|
||||
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
(this.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0) +
|
||||
marginY
|
||||
if (node.children.length) {
|
||||
node.children.forEach(item => {
|
||||
loop(item)
|
||||
@@ -190,7 +194,7 @@ class Fishbone extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
@@ -244,8 +248,9 @@ class Fishbone extends Base {
|
||||
maxx = item.left
|
||||
}
|
||||
// 水平线段到二级节点的连线
|
||||
let marginY = this.getMarginY(item.layerIndex)
|
||||
let nodeLineX = item.left
|
||||
let offset = node.height / 2
|
||||
let offset = node.height / 2 + marginY
|
||||
let offsetX = offset / Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
let line = this.draw.path()
|
||||
if (this.checkIsTop(item)) {
|
||||
@@ -267,7 +272,7 @@ class Fishbone extends Base {
|
||||
})
|
||||
// 从根节点出发的水平线
|
||||
let nodeHalfTop = node.top + node.height / 2
|
||||
let offset = node.height / 2
|
||||
let offset = node.height / 2 + this.getMarginY(node.layerIndex + 1)
|
||||
let line = this.draw.path()
|
||||
line.plot(
|
||||
`M ${node.left + node.width},${nodeHalfTop} L ${
|
||||
|
||||
@@ -170,7 +170,8 @@ class Fishbone extends Base {
|
||||
item.top += _top
|
||||
// 调整left
|
||||
let offsetLeft =
|
||||
(totalHeight2 + nodeTotalHeight) / Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
(totalHeight2 + nodeTotalHeight) /
|
||||
Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
item.left += offsetLeft
|
||||
totalHeight += offset
|
||||
totalHeight2 += nodeTotalHeight
|
||||
@@ -237,7 +238,7 @@ class Fishbone extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
@@ -312,7 +313,9 @@ class Fishbone extends Base {
|
||||
if (node.parent && node.parent.isRoot) {
|
||||
line.plot(
|
||||
`M ${x},${top + height} L ${x + lineLength},${
|
||||
top + height + Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
top +
|
||||
height +
|
||||
Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
}`
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -140,7 +140,8 @@ class Fishbone extends Base {
|
||||
node.top - (item.top - node.top) - nodeTotalHeight + node.height
|
||||
// 调整left
|
||||
let offsetLeft =
|
||||
(nodeTotalHeight + totalHeight) / Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
(nodeTotalHeight + totalHeight) /
|
||||
Math.tan(degToRad(this.mindMap.opt.fishboneDeg))
|
||||
item.left += offsetLeft
|
||||
totalHeight += nodeTotalHeight
|
||||
// 同步更新后代节点
|
||||
@@ -206,7 +207,7 @@ class Fishbone extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
@@ -285,14 +286,16 @@ class Fishbone extends Base {
|
||||
) {
|
||||
line.plot(
|
||||
`M ${x},${top} L ${x + lineLength},${
|
||||
top - Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
top -
|
||||
Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
}`
|
||||
)
|
||||
} else {
|
||||
if (node.parent && node.parent.isRoot) {
|
||||
line.plot(
|
||||
`M ${x},${top} L ${x + lineLength},${
|
||||
top - Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
top -
|
||||
Math.tan(degToRad(this.mindMap.opt.fishboneDeg)) * lineLength
|
||||
}`
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -56,6 +56,15 @@ class LogicalStructure extends Base {
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
// 如果存在概要,则和概要的高度取最大值
|
||||
let generalizationNodeHeight = cur._node.checkHasGeneralization()
|
||||
? cur._node._generalizationNodeHeight +
|
||||
this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
cur._node.childrenAreaHeight2 = Math.max(
|
||||
cur._node.childrenAreaHeight,
|
||||
generalizationNodeHeight
|
||||
)
|
||||
},
|
||||
true,
|
||||
0
|
||||
@@ -99,7 +108,7 @@ class LogicalStructure extends Base {
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaHeight -
|
||||
node.childrenAreaHeight2 -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.height
|
||||
if (difference > 0) {
|
||||
@@ -116,10 +125,10 @@ class LogicalStructure extends Base {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item === node || item.hasCustomPosition()) {
|
||||
if (item.uid === node.uid || item.hasCustomPosition()) {
|
||||
// 适配自定义位置
|
||||
return
|
||||
}
|
||||
|
||||
@@ -90,6 +90,20 @@ class MindMap extends Base {
|
||||
cur._node.rightChildrenAreaHeight =
|
||||
rightChildrenAreaHeight +
|
||||
(rightLen + 1) * this.getMarginY(layerIndex + 1)
|
||||
|
||||
// 如果存在概要,则和概要的高度取最大值
|
||||
let generalizationNodeHeight = cur._node.checkHasGeneralization()
|
||||
? cur._node._generalizationNodeHeight +
|
||||
this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
cur._node.leftChildrenAreaHeight2 = Math.max(
|
||||
cur._node.leftChildrenAreaHeight,
|
||||
generalizationNodeHeight
|
||||
)
|
||||
cur._node.rightChildrenAreaHeight2 = Math.max(
|
||||
cur._node.rightChildrenAreaHeight,
|
||||
generalizationNodeHeight
|
||||
)
|
||||
},
|
||||
true,
|
||||
0
|
||||
@@ -139,8 +153,8 @@ class MindMap extends Base {
|
||||
}
|
||||
// 判断子节点所占的高度之和是否大于该节点自身,大于则需要调整位置
|
||||
let base = this.getMarginY(layerIndex + 1) * 2 + node.height
|
||||
let leftDifference = node.leftChildrenAreaHeight - base
|
||||
let rightDifference = node.rightChildrenAreaHeight - base
|
||||
let leftDifference = node.leftChildrenAreaHeight2 - base
|
||||
let rightDifference = node.rightChildrenAreaHeight2 - base
|
||||
if (leftDifference > 0 || rightDifference > 0) {
|
||||
this.updateBrothers(node, leftDifference / 2, rightDifference / 2)
|
||||
}
|
||||
@@ -158,7 +172,7 @@ class MindMap extends Base {
|
||||
return item.dir === node.dir
|
||||
})
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
|
||||
@@ -57,6 +57,15 @@ class OrganizationStructure extends Base {
|
||||
}, 0) +
|
||||
(len + 1) * this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
|
||||
// 如果存在概要,则和概要的高度取最大值
|
||||
let generalizationNodeWidth = cur._node.checkHasGeneralization()
|
||||
? cur._node._generalizationNodeWidth + this.getMarginY(layerIndex + 1)
|
||||
: 0
|
||||
cur._node.childrenAreaWidth2 = Math.max(
|
||||
cur._node.childrenAreaWidth,
|
||||
generalizationNodeWidth
|
||||
)
|
||||
},
|
||||
true,
|
||||
0
|
||||
@@ -100,7 +109,7 @@ class OrganizationStructure extends Base {
|
||||
}
|
||||
// 判断子节点所占的宽度之和是否大于该节点自身,大于则需要调整位置
|
||||
let difference =
|
||||
node.childrenAreaWidth -
|
||||
node.childrenAreaWidth2 -
|
||||
this.getMarginY(layerIndex + 1) * 2 -
|
||||
node.width
|
||||
if (difference > 0) {
|
||||
@@ -117,7 +126,7 @@ class OrganizationStructure extends Base {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
|
||||
@@ -209,7 +209,7 @@ class Timeline extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
|
||||
@@ -156,13 +156,13 @@ class VerticalTimeline extends Base {
|
||||
if (node.parent) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
// 自定义节点位置
|
||||
if (item.hasCustomPosition()) return
|
||||
// 三级或三级以下节点自身位置不需要动
|
||||
if (!node.parent.isRoot && item === node) return
|
||||
if (!node.parent.isRoot && item.uid === node.uid) return
|
||||
let _offset = 0
|
||||
// 二级节点上面的兄弟节点不需要移动,自身需要往下移动
|
||||
if (node.parent.isRoot) {
|
||||
@@ -202,7 +202,7 @@ class VerticalTimeline extends Base {
|
||||
if (node.parent && !node.parent.isRoot) {
|
||||
let childrenList = node.parent.children
|
||||
let index = childrenList.findIndex(item => {
|
||||
return item === node
|
||||
return item.uid === node.uid
|
||||
})
|
||||
childrenList.forEach((item, _index) => {
|
||||
if (item.hasCustomPosition()) {
|
||||
|
||||
@@ -47,30 +47,35 @@ export default {
|
||||
computedLeftTopValue({ layerIndex, node, ctx }) {
|
||||
if (layerIndex >= 1 && node.children) {
|
||||
// 遍历三级及以下节点的子节点
|
||||
let marginY = ctx.getMarginY(layerIndex + 1)
|
||||
let startLeft = node.left + node.width * ctx.childIndent
|
||||
let totalTop =
|
||||
node.top +
|
||||
node.height +
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0) +
|
||||
marginY
|
||||
node.children.forEach(item => {
|
||||
item.left = startLeft
|
||||
item.top += totalTop
|
||||
totalTop +=
|
||||
item.height +
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0) +
|
||||
marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
adjustLeftTopValueBefore({ node, parent, ctx }) {
|
||||
adjustLeftTopValueBefore({ node, parent, ctx, layerIndex }) {
|
||||
// 调整top
|
||||
let len = node.children.length
|
||||
let marginY = ctx.getMarginY(layerIndex + 1)
|
||||
// 调整三级及以下节点的top
|
||||
if (parent && !parent.isRoot && len > 0) {
|
||||
let totalHeight = node.children.reduce((h, item) => {
|
||||
return (
|
||||
h +
|
||||
item.height +
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0) +
|
||||
marginY
|
||||
)
|
||||
}, 0)
|
||||
ctx.updateBrothersTop(node, totalHeight)
|
||||
@@ -80,7 +85,8 @@ export default {
|
||||
// 将二级节点的子节点移到上方
|
||||
if (parent && parent.isRoot) {
|
||||
// 遍历二级节点的子节点
|
||||
let totalHeight = node.expandBtnSize
|
||||
let marginY = ctx.getMarginY(node.layerIndex + 1)
|
||||
let totalHeight = node.expandBtnSize + marginY
|
||||
node.children.forEach(item => {
|
||||
// 调整top
|
||||
let nodeTotalHeight = ctx.getNodeAreaHeight(item)
|
||||
@@ -89,7 +95,11 @@ export default {
|
||||
item.top =
|
||||
node.top - (item.top - node.top) - nodeTotalHeight + node.height
|
||||
// 调整left
|
||||
item.left = node.left + node.width * ctx.indent + (nodeTotalHeight + totalHeight) / Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg))
|
||||
item.left =
|
||||
node.left +
|
||||
node.width * ctx.indent +
|
||||
(nodeTotalHeight + totalHeight) /
|
||||
Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg))
|
||||
totalHeight += nodeTotalHeight
|
||||
// 同步更新后代节点
|
||||
ctx.updateChildrenPro(item.children, {
|
||||
@@ -126,7 +136,9 @@ export default {
|
||||
if (node.parent && node.parent.isRoot) {
|
||||
line.plot(
|
||||
`M ${x},${top + height} L ${x + lineLength},${
|
||||
top + height + Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg)) * lineLength
|
||||
top +
|
||||
height +
|
||||
Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg)) * lineLength
|
||||
}`
|
||||
)
|
||||
} else {
|
||||
@@ -134,13 +146,15 @@ export default {
|
||||
}
|
||||
},
|
||||
computedLeftTopValue({ layerIndex, node, ctx }) {
|
||||
let marginY = ctx.getMarginY(layerIndex + 1)
|
||||
if (layerIndex === 1 && node.children) {
|
||||
// 遍历二级节点的子节点
|
||||
let startLeft = node.left + node.width * ctx.childIndent
|
||||
let totalTop =
|
||||
node.top +
|
||||
node.height +
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0) +
|
||||
marginY
|
||||
|
||||
node.children.forEach(item => {
|
||||
item.left = startLeft
|
||||
@@ -149,7 +163,8 @@ export default {
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
totalTop +=
|
||||
item.height +
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0) +
|
||||
marginY
|
||||
})
|
||||
}
|
||||
if (layerIndex > 1 && node.children) {
|
||||
@@ -157,25 +172,29 @@ export default {
|
||||
let startLeft = node.left + node.width * ctx.childIndent
|
||||
let totalTop =
|
||||
node.top -
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(node) > 0 ? node.expandBtnSize : 0) -
|
||||
marginY
|
||||
node.children.forEach(item => {
|
||||
item.left = startLeft
|
||||
item.top = totalTop - item.height
|
||||
totalTop -=
|
||||
item.height +
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0) +
|
||||
marginY
|
||||
})
|
||||
}
|
||||
},
|
||||
adjustLeftTopValueBefore({ node, ctx, layerIndex }) {
|
||||
// 调整top
|
||||
let marginY = ctx.getMarginY(layerIndex + 1)
|
||||
let len = node.children.length
|
||||
if (layerIndex > 2 && len > 0) {
|
||||
let totalHeight = node.children.reduce((h, item) => {
|
||||
return (
|
||||
h +
|
||||
item.height +
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0)
|
||||
(ctx.getNodeActChildrenLength(item) > 0 ? item.expandBtnSize : 0) +
|
||||
marginY
|
||||
)
|
||||
}, 0)
|
||||
ctx.updateBrothersTop(node, -totalHeight)
|
||||
@@ -185,23 +204,28 @@ export default {
|
||||
// 将二级节点的子节点移到上方
|
||||
if (parent && parent.isRoot) {
|
||||
// 遍历二级节点的子节点
|
||||
let marginY = ctx.getMarginY(node.layerIndex + 1)
|
||||
let totalHeight = 0
|
||||
let totalHeight2 = node.expandBtnSize
|
||||
node.children.forEach(item => {
|
||||
// 调整top
|
||||
let hasChildren = ctx.getNodeActChildrenLength(item) > 0
|
||||
let nodeTotalHeight = ctx.getNodeAreaHeight(item)
|
||||
let offset =
|
||||
hasChildren > 0
|
||||
? nodeTotalHeight -
|
||||
item.height -
|
||||
(hasChildren ? item.expandBtnSize : 0)
|
||||
: 0
|
||||
let offset = hasChildren
|
||||
? nodeTotalHeight -
|
||||
item.height -
|
||||
(hasChildren ? item.expandBtnSize : 0)
|
||||
: 0
|
||||
offset -= hasChildren ? marginY : 0
|
||||
let _top = totalHeight + offset
|
||||
let _left = item.left
|
||||
item.top += _top
|
||||
// 调整left
|
||||
item.left = node.left + node.width * ctx.indent + (nodeTotalHeight + totalHeight2) / Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg))
|
||||
item.left =
|
||||
node.left +
|
||||
node.width * ctx.indent +
|
||||
(nodeTotalHeight + totalHeight2) /
|
||||
Math.tan(degToRad(ctx.mindMap.opt.fishboneDeg))
|
||||
totalHeight += offset
|
||||
totalHeight2 += nodeTotalHeight
|
||||
// 同步更新后代节点
|
||||
|
||||
@@ -50,4 +50,4 @@ export const transformToMarkdown = root => {
|
||||
true
|
||||
)
|
||||
return content
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
getTextFromHtml,
|
||||
imgToDataUrl,
|
||||
parseDataUrl,
|
||||
getImageSize
|
||||
getImageSize,
|
||||
isUndef
|
||||
} from '../utils/index'
|
||||
|
||||
// 解析.xmind文件
|
||||
@@ -49,7 +50,7 @@ const transformXmind = async (content, files) => {
|
||||
let walk = async (node, newNode) => {
|
||||
newNode.data = {
|
||||
// 节点内容
|
||||
text: node.title
|
||||
text: isUndef(node.title) ? '' : node.title
|
||||
}
|
||||
// 节点备注
|
||||
if (node.notes) {
|
||||
@@ -146,9 +147,10 @@ const transformOldXmind = content => {
|
||||
let walk = (node, newNode) => {
|
||||
let nodeElements = node.elements
|
||||
let nodeTitle = getItemByName(nodeElements, 'title')
|
||||
nodeTitle = nodeTitle && nodeTitle.elements && nodeTitle.elements[0].text
|
||||
newNode.data = {
|
||||
// 节点内容
|
||||
text: nodeTitle && nodeTitle.elements && nodeTitle.elements[0].text
|
||||
text: isUndef(nodeTitle) ? '' : nodeTitle
|
||||
}
|
||||
try {
|
||||
// 节点备注
|
||||
@@ -189,7 +191,7 @@ const transformOldXmind = content => {
|
||||
if (_children && _children.elements && _children.elements.length > 0) {
|
||||
_children.elements.forEach(item => {
|
||||
if (item.name === 'topics') {
|
||||
(item.elements || []).forEach(item2 => {
|
||||
;(item.elements || []).forEach(item2 => {
|
||||
let newChild = {}
|
||||
newNode.children.push(newChild)
|
||||
walk(item2, newChild)
|
||||
@@ -215,6 +217,7 @@ const transformToXmind = async (data, name) => {
|
||||
let waitLoadImageList = []
|
||||
let walk = async (node, newNode, isRoot) => {
|
||||
let newData = {
|
||||
id: node.data.uid,
|
||||
structureClass: 'org.xmind.ui.logic.right',
|
||||
title: getTextFromHtml(node.data.text), // 节点文本
|
||||
children: {
|
||||
@@ -242,20 +245,20 @@ const transformToXmind = async (data, name) => {
|
||||
}
|
||||
// 图片
|
||||
if (node.data.image) {
|
||||
// 处理异步逻辑
|
||||
let resolve = null
|
||||
let promise = new Promise(_resolve => {
|
||||
resolve = _resolve
|
||||
})
|
||||
waitLoadImageList.push(promise)
|
||||
try {
|
||||
// 处理异步逻辑
|
||||
let resolve = null
|
||||
let promise = new Promise(_resolve => {
|
||||
resolve = _resolve
|
||||
})
|
||||
waitLoadImageList.push(promise)
|
||||
let imgName = ''
|
||||
let imgData = node.data.image
|
||||
// 网络图片要先转换成data:url
|
||||
if (/^https?:\/\//.test(node.data.image)) {
|
||||
// base64之外的其他图片要先转换成data:url
|
||||
if (!/^data:/.test(node.data.image)) {
|
||||
imgData = await imgToDataUrl(node.data.image)
|
||||
}
|
||||
// 从data:url中解析出图片类型和base64
|
||||
// 从data:url中解析出图片类型和ase64
|
||||
let dataUrlRes = parseDataUrl(imgData)
|
||||
imgName = 'image_' + imageList.length + '.' + dataUrlRes.type
|
||||
imageList.push({
|
||||
|
||||
@@ -99,13 +99,34 @@ class AssociativeLine {
|
||||
// 创建箭头
|
||||
createMarker() {
|
||||
return this.draw.marker(20, 20, add => {
|
||||
add.ref(2, 5)
|
||||
add.ref(12, 5)
|
||||
add.size(10, 10)
|
||||
add.attr('orient', 'auto-start-reverse')
|
||||
this.markerPath = add.path('M0,0 L2,5 L0,10 L10,5 Z')
|
||||
})
|
||||
}
|
||||
|
||||
// 判断关联线坐标是否变更,有变更则使用变化后的坐标,无则默认坐标
|
||||
updateAllLinesPos(node, toNode, associativeLinePoint) {
|
||||
associativeLinePoint = associativeLinePoint || {}
|
||||
let [startPoint, endPoint] = computeNodePoints(node, toNode)
|
||||
let nodeRange = 0
|
||||
let nodeDir = ''
|
||||
let toNodeRange = 0
|
||||
let toNodeDir = ''
|
||||
if (associativeLinePoint.startPoint) {
|
||||
nodeRange = associativeLinePoint.startPoint.range || 0
|
||||
nodeDir = associativeLinePoint.startPoint.dir || 'right'
|
||||
startPoint = getNodePoint(node, nodeDir, nodeRange)
|
||||
}
|
||||
if (associativeLinePoint.endPoint) {
|
||||
toNodeRange = associativeLinePoint.endPoint.range || 0
|
||||
toNodeDir = associativeLinePoint.endPoint.dir || 'right'
|
||||
endPoint = getNodePoint(toNode, toNodeDir, toNodeRange)
|
||||
}
|
||||
return [startPoint, endPoint]
|
||||
}
|
||||
|
||||
// 渲染所有连线
|
||||
renderAllLines() {
|
||||
// 先移除
|
||||
@@ -137,10 +158,17 @@ class AssociativeLine {
|
||||
0
|
||||
)
|
||||
nodeToIds.forEach((ids, node) => {
|
||||
ids.forEach(id => {
|
||||
ids.forEach((id, index) => {
|
||||
let toNode = idToNode.get(id)
|
||||
if (!node || !toNode) return
|
||||
let [startPoint, endPoint] = computeNodePoints(node, toNode)
|
||||
const associativeLinePoint = (node.nodeData.data.associativeLinePoint ||
|
||||
[])[index]
|
||||
// 切换结构和布局,都会更新坐标
|
||||
const [startPoint, endPoint] = this.updateAllLinesPos(
|
||||
node,
|
||||
toNode,
|
||||
associativeLinePoint
|
||||
)
|
||||
this.drawLine(startPoint, endPoint, node, toNode)
|
||||
})
|
||||
})
|
||||
@@ -183,11 +211,28 @@ class AssociativeLine {
|
||||
.fill({ color: 'none' })
|
||||
clickPath.plot(pathStr)
|
||||
// 文字
|
||||
let text = this.createText({ path, clickPath, node, toNode, startPoint, endPoint, controlPoints })
|
||||
let text = this.createText({
|
||||
path,
|
||||
clickPath,
|
||||
node,
|
||||
toNode,
|
||||
startPoint,
|
||||
endPoint,
|
||||
controlPoints
|
||||
})
|
||||
// 点击事件
|
||||
clickPath.click(e => {
|
||||
e.stopPropagation()
|
||||
this.setActiveLine({ path, clickPath, text, node, toNode, startPoint, endPoint, controlPoints })
|
||||
this.setActiveLine({
|
||||
path,
|
||||
clickPath,
|
||||
text,
|
||||
node,
|
||||
toNode,
|
||||
startPoint,
|
||||
endPoint,
|
||||
controlPoints
|
||||
})
|
||||
})
|
||||
// 渲染关联线文字
|
||||
this.renderText(this.getText(node, toNode), path, text)
|
||||
@@ -195,10 +240,17 @@ class AssociativeLine {
|
||||
}
|
||||
|
||||
// 激活某根关联线
|
||||
setActiveLine({ path, clickPath, text, node, toNode, startPoint, endPoint, controlPoints }) {
|
||||
let {
|
||||
associativeLineActiveColor
|
||||
} = this.mindMap.themeConfig
|
||||
setActiveLine({
|
||||
path,
|
||||
clickPath,
|
||||
text,
|
||||
node,
|
||||
toNode,
|
||||
startPoint,
|
||||
endPoint,
|
||||
controlPoints
|
||||
}) {
|
||||
let { associativeLineActiveColor } = this.mindMap.themeConfig
|
||||
// 如果当前存在激活节点,那么取消激活节点
|
||||
if (this.mindMap.renderer.activeNodeList.length > 0) {
|
||||
this.clearActiveNodes()
|
||||
@@ -287,6 +339,22 @@ class AssociativeLine {
|
||||
}
|
||||
}
|
||||
|
||||
// 计算节点偏移位置
|
||||
getNodePos(node) {
|
||||
const { scaleX, scaleY, translateX, translateY } =
|
||||
this.mindMap.draw.transform()
|
||||
const { left, top, width, height } = node
|
||||
let translateLeft = left * scaleX + translateX
|
||||
let translateTop = top * scaleY + translateY
|
||||
return {
|
||||
left,
|
||||
top,
|
||||
translateLeft,
|
||||
translateTop,
|
||||
width,
|
||||
height
|
||||
}
|
||||
}
|
||||
// 检测当前移动到的目标节点
|
||||
checkOverlapNode(x, y) {
|
||||
this.overlapNode = null
|
||||
@@ -294,7 +362,7 @@ class AssociativeLine {
|
||||
if (node.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(node, false)
|
||||
}
|
||||
if (node === this.creatingStartNode || this.overlapNode) {
|
||||
if (node.uid === this.creatingStartNode.uid || this.overlapNode) {
|
||||
return
|
||||
}
|
||||
let { left, top, width, height } = node
|
||||
@@ -311,7 +379,7 @@ class AssociativeLine {
|
||||
|
||||
// 完成创建连接线
|
||||
completeCreateLine(node) {
|
||||
if (this.creatingStartNode === node) return
|
||||
if (this.creatingStartNode.uid === node.uid) return
|
||||
this.addLine(this.creatingStartNode, node)
|
||||
if (this.overlapNode && this.overlapNode.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(this.overlapNode, false)
|
||||
@@ -336,6 +404,11 @@ class AssociativeLine {
|
||||
}
|
||||
// 将目标节点id保存起来
|
||||
let list = fromNode.nodeData.data.associativeLineTargets || []
|
||||
// 连线节点是否存在相同的id,存在则阻止添加关联线
|
||||
const sameLine = list.some(item => item === id)
|
||||
if (sameLine) {
|
||||
return
|
||||
}
|
||||
list.push(id)
|
||||
// 保存控制点
|
||||
let [startPoint, endPoint] = computeNodePoints(fromNode, toNode)
|
||||
@@ -358,9 +431,13 @@ class AssociativeLine {
|
||||
y: controlPoints[1].y - endPoint.y
|
||||
}
|
||||
]
|
||||
let associativeLinePoint = fromNode.nodeData.data.associativeLinePoint || []
|
||||
// 记录关联的起始|结束坐标
|
||||
associativeLinePoint[list.length - 1] = { startPoint, endPoint }
|
||||
this.mindMap.execCommand('SET_NODE_DATA', fromNode, {
|
||||
associativeLineTargets: list,
|
||||
associativeLineTargetControlOffsets: offsetList
|
||||
associativeLineTargetControlOffsets: offsetList,
|
||||
associativeLinePoint
|
||||
})
|
||||
}
|
||||
|
||||
@@ -369,13 +446,18 @@ class AssociativeLine {
|
||||
if (!this.activeLine) return
|
||||
let [, , , node, toNode] = this.activeLine
|
||||
this.removeControls()
|
||||
let { associativeLineTargets, associativeLineTargetControlOffsets, associativeLineText } =
|
||||
node.nodeData.data
|
||||
let {
|
||||
associativeLineTargets,
|
||||
associativeLinePoint,
|
||||
associativeLineTargetControlOffsets,
|
||||
associativeLineText
|
||||
} = node.nodeData.data
|
||||
associativeLinePoint = associativeLinePoint || []
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
// 更新关联线文本数据
|
||||
let newAssociativeLineText = {}
|
||||
if (associativeLineText) {
|
||||
Object.keys(associativeLineText).forEach((item) => {
|
||||
Object.keys(associativeLineText).forEach(item => {
|
||||
if (item !== toNode.nodeData.data.id) {
|
||||
newAssociativeLineText[item] = associativeLineText[item]
|
||||
}
|
||||
@@ -386,6 +468,10 @@ class AssociativeLine {
|
||||
associativeLineTargets: associativeLineTargets.filter((_, index) => {
|
||||
return index !== targetIndex
|
||||
}),
|
||||
// 连接线坐标
|
||||
associativeLinePoint: associativeLinePoint.filter((_, index) => {
|
||||
return index !== targetIndex
|
||||
}),
|
||||
// 偏移量
|
||||
associativeLineTargetControlOffsets: associativeLineTargetControlOffsets
|
||||
? associativeLineTargetControlOffsets.filter((_, index) => {
|
||||
|
||||
@@ -13,6 +13,8 @@ class Drag extends Base {
|
||||
|
||||
// 复位
|
||||
reset() {
|
||||
// 当前画布节点列表
|
||||
this.nodeList = []
|
||||
// 当前拖拽节点
|
||||
this.node = null
|
||||
// 当前重叠节点
|
||||
@@ -68,6 +70,7 @@ class Drag extends Base {
|
||||
this.isMousedown = true
|
||||
this.mouseDownX = x
|
||||
this.mouseDownY = y
|
||||
this.nodeTreeToList()
|
||||
})
|
||||
this.mindMap.on('mousemove', e => {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
@@ -89,7 +92,7 @@ class Drag extends Base {
|
||||
return
|
||||
}
|
||||
this.mindMap.renderer.clearAllActive()
|
||||
this.onMove(x, y)
|
||||
this.onMove(x, y, e)
|
||||
})
|
||||
this.onMouseup = this.onMouseup.bind(this)
|
||||
this.mindMap.on('node_mouseup', this.onMouseup)
|
||||
@@ -106,7 +109,9 @@ class Drag extends Base {
|
||||
this.node.isDrag = false
|
||||
this.node.show()
|
||||
this.removeCloneNode()
|
||||
let overlapNodeUid = this.overlapNode ? this.overlapNode.nodeData.data.uid : ''
|
||||
let overlapNodeUid = this.overlapNode
|
||||
? this.overlapNode.nodeData.data.uid
|
||||
: ''
|
||||
let prevNodeUid = this.prevNode ? this.prevNode.nodeData.data.uid : ''
|
||||
let nextNodeUid = this.nextNode ? this.nextNode.nodeData.data.uid : ''
|
||||
// 存在重叠子节点,则移动作为其子节点
|
||||
@@ -177,7 +182,7 @@ class Drag extends Base {
|
||||
}
|
||||
|
||||
// 拖动中
|
||||
onMove(x, y) {
|
||||
onMove(x, y, e) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
@@ -200,6 +205,12 @@ class Drag extends Base {
|
||||
)
|
||||
)
|
||||
this.checkOverlapNode()
|
||||
// 如果注册了多选节点插件,那么复用它的边缘自动移动画布功能
|
||||
if (this.mindMap.opt.autoMoveWhenMouseInEdgeOnDrag && this.mindMap.select) {
|
||||
this.drawTransform = this.mindMap.draw.transform()
|
||||
this.mindMap.select.clearAutoMoveTimer()
|
||||
this.mindMap.select.onMove(e.clientX, e.clientY)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测重叠节点
|
||||
@@ -207,90 +218,47 @@ class Drag extends Base {
|
||||
if (!this.drawTransform || !this.placeholder) {
|
||||
return
|
||||
}
|
||||
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
|
||||
let x = this.mouseMoveX
|
||||
let y = this.mouseMoveY
|
||||
this.overlapNode = null
|
||||
this.prevNode = null
|
||||
this.nextNode = null
|
||||
this.placeholder.size(0, 0)
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
this.nodeList.forEach(node => {
|
||||
if (node.nodeData.data.isActive) {
|
||||
this.mindMap.renderer.setNodeActive(node, false)
|
||||
}
|
||||
if (node === this.node || this.node.isParent(node)) {
|
||||
if (node.uid === this.node.uid || this.node.isParent(node)) {
|
||||
return
|
||||
}
|
||||
if (this.overlapNode || (this.prevNode && this.nextNode)) {
|
||||
return
|
||||
}
|
||||
let nodeRect = this.getNodeRect(node)
|
||||
let oneFourthHeight = nodeRect.height / 4
|
||||
// 前一个和后一个节点
|
||||
let checkList = node.parent ? node.parent.children.filter((item) => {
|
||||
return item !== this.node
|
||||
}) : []
|
||||
let index = checkList.findIndex((item) => {
|
||||
return item === node
|
||||
})
|
||||
let prevBrother = null
|
||||
let nextBrother = null
|
||||
if (index !== -1) {
|
||||
if (index - 1 >= 0) {
|
||||
prevBrother = checkList[index - 1]
|
||||
}
|
||||
if (index + 1 <= checkList.length - 1) {
|
||||
nextBrother = checkList[index + 1]
|
||||
}
|
||||
}
|
||||
// 和前一个兄弟节点的距离
|
||||
let prevBrotherOffset = 0
|
||||
if (prevBrother) {
|
||||
let prevNodeRect = this.getNodeRect(prevBrother)
|
||||
prevBrotherOffset = nodeRect.top - prevNodeRect.bottom
|
||||
// 间距小于10就当它不存在
|
||||
prevBrotherOffset = prevBrotherOffset >= this.minOffset ? prevBrotherOffset / 2 : 0
|
||||
} else {
|
||||
// 没有前一个兄弟节点,那么假设和前一个节点的距离为20
|
||||
prevBrotherOffset = this.minOffset
|
||||
}
|
||||
// 和后一个兄弟节点的距离
|
||||
let nextBrotherOffset = 0
|
||||
if (nextBrother) {
|
||||
let nextNodeRect = this.getNodeRect(nextBrother)
|
||||
nextBrotherOffset = nextNodeRect.top - nodeRect.bottom
|
||||
nextBrotherOffset = nextBrotherOffset >= this.minOffset ? nextBrotherOffset / 2 : 0
|
||||
} else {
|
||||
nextBrotherOffset = this.minOffset
|
||||
}
|
||||
if (nodeRect.left <= x && nodeRect.right >= x) {
|
||||
// 检测兄弟节点位置
|
||||
if (!this.overlapNode && !this.prevNode && !this.nextNode && !node.isRoot) {
|
||||
let checkIsPrevNode = nextBrotherOffset > 0 ? // 距离下一个兄弟节点的距离大于0
|
||||
y > nodeRect.bottom && y <= (nodeRect.bottom + nextBrotherOffset) : // 那么在当前节点外底部判断
|
||||
y >= nodeRect.bottom - oneFourthHeight && y <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
|
||||
let checkIsNextNode = prevBrotherOffset > 0 ? // 距离上一个兄弟节点的距离大于0
|
||||
y < nodeRect.top && y >= (nodeRect.top - prevBrotherOffset) : // 那么在当前节点外底部判断
|
||||
y >= nodeRect.top && y <= nodeRect.top + oneFourthHeight
|
||||
if (checkIsPrevNode) {
|
||||
this.prevNode = node
|
||||
let size = nextBrotherOffset > 0 ? Math.min(nextBrotherOffset, nodeDragPlaceholderMaxSize) : 5
|
||||
this.placeholder.size(node.width, size).move(nodeRect.originLeft, nodeRect.originBottom)
|
||||
} else if (checkIsNextNode) {
|
||||
this.nextNode = node
|
||||
let size = prevBrotherOffset > 0 ? Math.min(prevBrotherOffset, nodeDragPlaceholderMaxSize) : 5
|
||||
this.placeholder.size(node.width, size).move(nodeRect.originLeft, nodeRect.originTop - size)
|
||||
}
|
||||
}
|
||||
// 检测是否重叠
|
||||
if (!this.overlapNode && !this.prevNode && !this.nextNode) {
|
||||
if (
|
||||
nodeRect.top + (prevBrotherOffset > 0 ? 0 : oneFourthHeight) <= y &&
|
||||
nodeRect.bottom - (nextBrotherOffset > 0 ? 0 : oneFourthHeight) >= y
|
||||
) {
|
||||
this.overlapNode = node
|
||||
}
|
||||
}
|
||||
switch (this.mindMap.opt.layout) {
|
||||
case 'logicalStructure':
|
||||
this.handleLogicalStructure(node)
|
||||
break
|
||||
case 'mindMap':
|
||||
this.handleMindMap(node)
|
||||
break
|
||||
case 'organizationStructure':
|
||||
this.handleOrganizationStructure(node)
|
||||
break
|
||||
case 'catalogOrganization':
|
||||
this.handleCatalogOrganization(node)
|
||||
break
|
||||
case 'timeline':
|
||||
this.handleTimeLine(node)
|
||||
break
|
||||
case 'timeline2':
|
||||
this.handleTimeLine2(node)
|
||||
break
|
||||
case 'verticalTimeline':
|
||||
this.handleLogicalStructure(node)
|
||||
break
|
||||
case 'fishbone':
|
||||
this.handleFishbone(node)
|
||||
break
|
||||
default:
|
||||
this.handleLogicalStructure(node)
|
||||
}
|
||||
})
|
||||
if (this.overlapNode) {
|
||||
@@ -298,6 +266,299 @@ class Drag extends Base {
|
||||
}
|
||||
}
|
||||
|
||||
// 垂直方向比较
|
||||
// isReverse:是否反向
|
||||
handleVerticalCheck(node, checkList, isReverse = false) {
|
||||
let x = this.mouseMoveX
|
||||
let y = this.mouseMoveY
|
||||
let nodeRect = this.getNodeRect(node)
|
||||
if (isReverse) {
|
||||
checkList = checkList.reverse()
|
||||
}
|
||||
let oneFourthHeight = nodeRect.height / 4
|
||||
let { prevBrotherOffset, nextBrotherOffset } =
|
||||
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'v')
|
||||
if (nodeRect.left <= x && nodeRect.right >= x) {
|
||||
// 检测兄弟节点位置
|
||||
if (
|
||||
!this.overlapNode &&
|
||||
!this.prevNode &&
|
||||
!this.nextNode &&
|
||||
!node.isRoot
|
||||
) {
|
||||
let checkIsPrevNode =
|
||||
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
|
||||
? y > nodeRect.bottom && y <= nodeRect.bottom + nextBrotherOffset // 那么在当前节点外底部判断
|
||||
: y >= nodeRect.bottom - oneFourthHeight && y <= nodeRect.bottom // 否则在当前节点内底部1/4区间判断
|
||||
let checkIsNextNode =
|
||||
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
|
||||
? y < nodeRect.top && y >= nodeRect.top - prevBrotherOffset // 那么在当前节点外底部判断
|
||||
: y >= nodeRect.top && y <= nodeRect.top + oneFourthHeight
|
||||
if (checkIsPrevNode) {
|
||||
if (isReverse) {
|
||||
this.nextNode = node
|
||||
} else {
|
||||
this.prevNode = node
|
||||
}
|
||||
let size = this.formatPlaceholderSize(nextBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
node.width,
|
||||
size,
|
||||
nodeRect.originLeft,
|
||||
nodeRect.originBottom
|
||||
)
|
||||
} else if (checkIsNextNode) {
|
||||
if (isReverse) {
|
||||
this.prevNode = node
|
||||
} else {
|
||||
this.nextNode = node
|
||||
}
|
||||
let size = this.formatPlaceholderSize(prevBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
node.width,
|
||||
size,
|
||||
nodeRect.originLeft,
|
||||
nodeRect.originTop - size
|
||||
)
|
||||
}
|
||||
}
|
||||
// 检测是否重叠
|
||||
this.checkIsOverlap({
|
||||
node,
|
||||
dir: 'v',
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset,
|
||||
size: oneFourthHeight,
|
||||
pos: y,
|
||||
nodeRect
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 水平方向比较
|
||||
handleHorizontalCheck(node, checkList) {
|
||||
let x = this.mouseMoveX
|
||||
let y = this.mouseMoveY
|
||||
let nodeRect = this.getNodeRect(node)
|
||||
let oneFourthWidth = nodeRect.width / 4
|
||||
let { prevBrotherOffset, nextBrotherOffset } =
|
||||
this.getNodeDistanceToSiblingNode(checkList, node, nodeRect, 'h')
|
||||
if (nodeRect.top <= y && nodeRect.bottom >= y) {
|
||||
// 检测兄弟节点位置
|
||||
if (
|
||||
!this.overlapNode &&
|
||||
!this.prevNode &&
|
||||
!this.nextNode &&
|
||||
!node.isRoot
|
||||
) {
|
||||
let checkIsPrevNode =
|
||||
nextBrotherOffset > 0 // 距离下一个兄弟节点的距离大于0
|
||||
? x < nodeRect.right + nextBrotherOffset && x >= nodeRect.right // 那么在当前节点外底部判断
|
||||
: x <= nodeRect.right && x >= nodeRect.right - oneFourthWidth // 否则在当前节点内底部1/4区间判断
|
||||
let checkIsNextNode =
|
||||
prevBrotherOffset > 0 // 距离上一个兄弟节点的距离大于0
|
||||
? x > nodeRect.left - prevBrotherOffset && x <= nodeRect.left // 那么在当前节点外底部判断
|
||||
: x <= nodeRect.left + oneFourthWidth && x >= nodeRect.left
|
||||
if (checkIsPrevNode) {
|
||||
this.prevNode = node
|
||||
let size = this.formatPlaceholderSize(nextBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
size,
|
||||
node.height,
|
||||
nodeRect.originRight,
|
||||
nodeRect.originTop
|
||||
)
|
||||
} else if (checkIsNextNode) {
|
||||
this.nextNode = node
|
||||
let size = this.formatPlaceholderSize(prevBrotherOffset)
|
||||
this.setPlaceholderRect(
|
||||
size,
|
||||
node.height,
|
||||
nodeRect.originLeft - size,
|
||||
nodeRect.originTop
|
||||
)
|
||||
}
|
||||
}
|
||||
// 检测是否重叠
|
||||
this.checkIsOverlap({
|
||||
node,
|
||||
dir: 'h',
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset,
|
||||
size: oneFourthWidth,
|
||||
pos: x,
|
||||
nodeRect
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 获取节点距前一个和后一个节点的距离
|
||||
getNodeDistanceToSiblingNode(checkList, node, nodeRect, dir) {
|
||||
let dir1 = dir === 'v' ? 'top' : 'left'
|
||||
let dir2 = dir === 'v' ? 'bottom' : 'right'
|
||||
let index = checkList.findIndex(item => {
|
||||
return item.uid === node.uid
|
||||
})
|
||||
let prevBrother = null
|
||||
let nextBrother = null
|
||||
if (index !== -1) {
|
||||
if (index - 1 >= 0) {
|
||||
prevBrother = checkList[index - 1]
|
||||
}
|
||||
if (index + 1 <= checkList.length - 1) {
|
||||
nextBrother = checkList[index + 1]
|
||||
}
|
||||
}
|
||||
// 和前一个兄弟节点的距离
|
||||
let prevBrotherOffset = 0
|
||||
if (prevBrother) {
|
||||
let prevNodeRect = this.getNodeRect(prevBrother)
|
||||
prevBrotherOffset = nodeRect[dir1] - prevNodeRect[dir2]
|
||||
// 间距小于10就当它不存在
|
||||
prevBrotherOffset =
|
||||
prevBrotherOffset >= this.minOffset ? prevBrotherOffset / 2 : 0
|
||||
} else {
|
||||
// 没有前一个兄弟节点,那么假设和前一个节点的距离为20
|
||||
prevBrotherOffset = this.minOffset
|
||||
}
|
||||
// 和后一个兄弟节点的距离
|
||||
let nextBrotherOffset = 0
|
||||
if (nextBrother) {
|
||||
let nextNodeRect = this.getNodeRect(nextBrother)
|
||||
nextBrotherOffset = nextNodeRect[dir1] - nodeRect[dir2]
|
||||
nextBrotherOffset =
|
||||
nextBrotherOffset >= this.minOffset ? nextBrotherOffset / 2 : 0
|
||||
} else {
|
||||
nextBrotherOffset = this.minOffset
|
||||
}
|
||||
return {
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset
|
||||
}
|
||||
}
|
||||
|
||||
// 处理提示元素的大小
|
||||
formatPlaceholderSize(size) {
|
||||
const { nodeDragPlaceholderMaxSize } = this.mindMap.opt
|
||||
return size > 0 ? Math.min(size, nodeDragPlaceholderMaxSize) : 5
|
||||
}
|
||||
|
||||
// 设置提示元素的大小和位置
|
||||
setPlaceholderRect(w, h, x, y) {
|
||||
this.placeholder.size(w, h).move(x, y)
|
||||
}
|
||||
|
||||
// 检测是否重叠
|
||||
checkIsOverlap({
|
||||
node,
|
||||
dir,
|
||||
prevBrotherOffset,
|
||||
nextBrotherOffset,
|
||||
size,
|
||||
pos,
|
||||
nodeRect
|
||||
}) {
|
||||
let dir1 = dir === 'v' ? 'top' : 'left'
|
||||
let dir2 = dir === 'v' ? 'bottom' : 'right'
|
||||
if (!this.overlapNode && !this.prevNode && !this.nextNode) {
|
||||
if (
|
||||
nodeRect[dir1] + (prevBrotherOffset > 0 ? 0 : size) <= pos &&
|
||||
nodeRect[dir2] - (nextBrotherOffset > 0 ? 0 : size) >= pos
|
||||
) {
|
||||
this.overlapNode = node
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理逻辑结构图
|
||||
handleLogicalStructure(node) {
|
||||
const checkList = this.commonGetNodeCheckList(node)
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
|
||||
// 处理思维导图
|
||||
handleMindMap(node) {
|
||||
const checkList = node.parent
|
||||
? node.parent.children.filter(item => {
|
||||
let sameDir = true
|
||||
if (node.layerIndex === 1) {
|
||||
sameDir = item.dir === node.dir
|
||||
}
|
||||
return item !== this.node && sameDir
|
||||
})
|
||||
: []
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
|
||||
// 处理组织结构图
|
||||
handleOrganizationStructure(node) {
|
||||
const checkList = this.commonGetNodeCheckList(node)
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
}
|
||||
|
||||
// 处理目录组织图
|
||||
handleCatalogOrganization(node) {
|
||||
const checkList = this.commonGetNodeCheckList(node)
|
||||
if (node.layerIndex === 1) {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理时间轴
|
||||
handleTimeLine(node) {
|
||||
let checkList = this.commonGetNodeCheckList(node)
|
||||
if (node.layerIndex === 1) {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理时间轴2
|
||||
handleTimeLine2(node) {
|
||||
let checkList = this.commonGetNodeCheckList(node)
|
||||
if (node.layerIndex === 1) {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
|
||||
if (node.dir === 'top' && node.layerIndex === 2) {
|
||||
this.handleVerticalCheck(node, checkList, true)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理鱼骨图
|
||||
handleFishbone(node) {
|
||||
let checkList = node.parent
|
||||
? node.parent.children.filter(item => {
|
||||
return item !== this.node && item.layerIndex > 1
|
||||
})
|
||||
: []
|
||||
if (node.layerIndex === 1) {
|
||||
this.handleHorizontalCheck(node, checkList)
|
||||
} else {
|
||||
// 处于上方的三级节点需要特殊处理,因为节点排列方向反向了
|
||||
if (node.dir === 'top' && node.layerIndex === 2) {
|
||||
this.handleVerticalCheck(node, checkList, true)
|
||||
} else {
|
||||
this.handleVerticalCheck(node, checkList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取节点的兄弟节点列表通用方法
|
||||
commonGetNodeCheckList(node) {
|
||||
return node.parent
|
||||
? node.parent.children.filter(item => {
|
||||
return item !== this.node
|
||||
})
|
||||
: []
|
||||
}
|
||||
|
||||
// 计算节点的位置尺寸信息
|
||||
getNodeRect(node) {
|
||||
let { scaleX, scaleY, translateX, translateY } = this.drawTransform
|
||||
@@ -305,6 +566,7 @@ class Drag extends Base {
|
||||
let originLeft = left
|
||||
let originTop = top
|
||||
let originBottom = top + height
|
||||
let originRight = left + width
|
||||
let right = (left + width) * scaleX + translateX
|
||||
let bottom = (top + height) * scaleY + translateY
|
||||
left = left * scaleX + translateX
|
||||
@@ -318,9 +580,24 @@ class Drag extends Base {
|
||||
bottom,
|
||||
originLeft,
|
||||
originTop,
|
||||
originBottom
|
||||
originBottom,
|
||||
originRight
|
||||
}
|
||||
}
|
||||
|
||||
// 节点由树转换成数组,从子节点到根节点
|
||||
nodeTreeToList() {
|
||||
const list = []
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (!list[node.layerIndex]) {
|
||||
list[node.layerIndex] = []
|
||||
}
|
||||
list[node.layerIndex].push(node)
|
||||
})
|
||||
this.nodeList = list.reduceRight((res, cur) => {
|
||||
return [...res, ...cur]
|
||||
}, [])
|
||||
}
|
||||
}
|
||||
|
||||
Drag.instanceName = 'drag'
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { SVG } from '@svgdotjs/svg.js'
|
||||
import drawBackgroundImageToCanvas from '../utils/simulateCSSBackgroundInCanvas'
|
||||
import { transformToMarkdown } from '../parse/toMarkdown'
|
||||
import { a4Size } from '../constants/constant'
|
||||
|
||||
// 导出插件
|
||||
class Export {
|
||||
@@ -57,45 +58,51 @@ class Export {
|
||||
}
|
||||
|
||||
// svg转png
|
||||
svgToPng(svgSrc, transparent, rotateWhenWidthLongerThenHeight = false) {
|
||||
svgToPng(
|
||||
svgSrc,
|
||||
transparent,
|
||||
checkRotate = () => {
|
||||
return false
|
||||
}
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
|
||||
img.setAttribute('crossOrigin', 'anonymous')
|
||||
img.onload = async () => {
|
||||
try {
|
||||
let canvas = document.createElement('canvas')
|
||||
const canvas = document.createElement('canvas')
|
||||
const dpr = Math.max(
|
||||
window.devicePixelRatio,
|
||||
this.mindMap.opt.minExportImgCanvasScale
|
||||
)
|
||||
const imgWidth = img.width
|
||||
const imgHeight = img.height
|
||||
// 如果宽比高长,那么旋转90度
|
||||
let needRotate =
|
||||
rotateWhenWidthLongerThenHeight && img.width / img.height > 1
|
||||
const needRotate = checkRotate(imgWidth, imgHeight)
|
||||
if (needRotate) {
|
||||
canvas.width = img.height
|
||||
canvas.height = img.width
|
||||
canvas.width = imgHeight * dpr
|
||||
canvas.height = imgWidth * dpr
|
||||
canvas.style.width = imgHeight + 'px'
|
||||
canvas.style.height = imgWidth + 'px'
|
||||
} else {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
canvas.width = imgWidth * dpr
|
||||
canvas.height = imgHeight * dpr
|
||||
canvas.style.width = imgWidth + 'px'
|
||||
canvas.style.height = imgHeight + 'px'
|
||||
}
|
||||
let ctx = canvas.getContext('2d')
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx.scale(dpr, dpr)
|
||||
if (needRotate) {
|
||||
ctx.rotate(0.5 * Math.PI)
|
||||
ctx.translate(0, -img.height)
|
||||
ctx.translate(0, -imgHeight)
|
||||
}
|
||||
// 绘制背景
|
||||
if (!transparent) {
|
||||
await this.drawBackgroundToCanvas(ctx, img.width, img.height)
|
||||
await this.drawBackgroundToCanvas(ctx, imgWidth, imgHeight)
|
||||
}
|
||||
// 图片绘制到canvas里
|
||||
ctx.drawImage(
|
||||
img,
|
||||
0,
|
||||
0,
|
||||
img.width,
|
||||
img.height,
|
||||
0,
|
||||
0,
|
||||
img.width,
|
||||
img.height
|
||||
)
|
||||
ctx.drawImage(img, 0, 0, imgWidth, imgHeight)
|
||||
resolve(canvas.toDataURL())
|
||||
} catch (error) {
|
||||
reject(error)
|
||||
@@ -179,7 +186,7 @@ class Export {
|
||||
* 方法1.把svg的图片都转化成data:url格式,再转换
|
||||
* 方法2.把svg的图片提取出来再挨个绘制到canvas里,最后一起转换
|
||||
*/
|
||||
async png(name, transparent = false, rotateWhenWidthLongerThenHeight) {
|
||||
async png(name, transparent = false, checkRotate) {
|
||||
let { node, str } = await this.getSvgData()
|
||||
str = removeHTMLEntities(str)
|
||||
// 如果开启了富文本,则使用htmltocanvas转换为图片
|
||||
@@ -187,7 +194,9 @@ class Export {
|
||||
// 覆盖html默认的样式
|
||||
let foreignObjectList = node.find('foreignObject')
|
||||
if (foreignObjectList.length > 0) {
|
||||
foreignObjectList[0].add(SVG(`<style>${ this.mindMap.opt.resetCss }</style>`))
|
||||
foreignObjectList[0].add(
|
||||
SVG(`<style>${this.mindMap.opt.resetCss}</style>`)
|
||||
)
|
||||
}
|
||||
str = node.svg()
|
||||
// 使用其他库(html2canvas、dom-to-image-more等)来完成导出
|
||||
@@ -195,7 +204,7 @@ class Export {
|
||||
// let imgDataUrl = await this.svgToPng(
|
||||
// res,
|
||||
// transparent,
|
||||
// rotateWhenWidthLongerThenHeight
|
||||
// checkRotate
|
||||
// )
|
||||
// return imgDataUrl
|
||||
}
|
||||
@@ -206,11 +215,7 @@ class Export {
|
||||
// 转换成data:url数据
|
||||
let svgUrl = await readBlob(blob)
|
||||
// 绘制到canvas上
|
||||
let res = await this.svgToPng(
|
||||
svgUrl,
|
||||
transparent,
|
||||
rotateWhenWidthLongerThenHeight
|
||||
)
|
||||
let res = await this.svgToPng(svgUrl, transparent, checkRotate)
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -219,7 +224,10 @@ class Export {
|
||||
if (!this.mindMap.doExportPDF) {
|
||||
throw new Error('请注册ExportPDF插件')
|
||||
}
|
||||
let img = await this.png('', false, true)
|
||||
let img = await this.png('', false, (width, height) => {
|
||||
if (width <= a4Size.width && height && a4Size.height) return false
|
||||
return width / height > 1
|
||||
})
|
||||
this.mindMap.doExportPDF.pdf(name, img, useMultiPageExport)
|
||||
}
|
||||
|
||||
@@ -242,7 +250,9 @@ class Export {
|
||||
if (this.mindMap.richText) {
|
||||
let foreignObjectList = node.find('foreignObject')
|
||||
if (foreignObjectList.length > 0) {
|
||||
foreignObjectList[0].add(SVG(`<style>${ this.mindMap.opt.resetCss }</style>`))
|
||||
foreignObjectList[0].add(
|
||||
SVG(`<style>${this.mindMap.opt.resetCss}</style>`)
|
||||
)
|
||||
}
|
||||
}
|
||||
node.first().before(SVG(`<title>${name}</title>`))
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import JsPDF from 'jspdf'
|
||||
import { a4Size } from '../constants/constant'
|
||||
|
||||
// 导出PDF插件,需要通过Export插件使用
|
||||
class ExportPDF {
|
||||
@@ -19,29 +20,34 @@ class ExportPDF {
|
||||
// 单页导出
|
||||
onePageExport(name, img) {
|
||||
let pdf = new JsPDF('', 'pt', 'a4')
|
||||
let a4Width = 595
|
||||
let a4Height = 841
|
||||
let a4Ratio = a4Width / a4Height
|
||||
let a4Ratio = a4Size.width / a4Size.height
|
||||
let image = new Image()
|
||||
image.onload = () => {
|
||||
let imageWidth = image.width
|
||||
let imageHeight = image.height
|
||||
let imageRatio = imageWidth / imageHeight
|
||||
let w, h
|
||||
if (imageWidth <= a4Width && imageHeight <= a4Height) {
|
||||
if (imageWidth <= a4Size.width && imageHeight <= a4Size.height) {
|
||||
// 使用图片原始宽高
|
||||
w = imageWidth
|
||||
h = imageHeight
|
||||
} else if (a4Ratio > imageRatio) {
|
||||
// 以a4Height为高度,缩放图片宽度
|
||||
w = imageRatio * a4Height
|
||||
h = a4Height
|
||||
w = imageRatio * a4Size.height
|
||||
h = a4Size.height
|
||||
} else {
|
||||
// 以a4Width为宽度,缩放图片高度
|
||||
w = a4Width
|
||||
h = a4Width / imageRatio
|
||||
w = a4Size.width
|
||||
h = a4Size.width / imageRatio
|
||||
}
|
||||
pdf.addImage(img, 'PNG', (a4Width - w) / 2, (a4Height - h) / 2, w, h)
|
||||
pdf.addImage(
|
||||
img,
|
||||
'PNG',
|
||||
(a4Size.width - w) / 2,
|
||||
(a4Size.height - h) / 2,
|
||||
w,
|
||||
h
|
||||
)
|
||||
pdf.save(name)
|
||||
}
|
||||
image.src = img
|
||||
@@ -50,20 +56,18 @@ class ExportPDF {
|
||||
// 多页导出
|
||||
multiPageExport(name, img) {
|
||||
let image = new Image()
|
||||
const a4Width = 592.28
|
||||
const a4Height = 841.89
|
||||
image.onload = () => {
|
||||
let imageWidth = image.width
|
||||
let imageHeight = image.height
|
||||
// 一页pdf显示高度
|
||||
let pageHeight = (imageWidth / a4Width) * a4Height
|
||||
let pageHeight = (imageWidth / a4Size.width) * a4Size.height
|
||||
// 未生成pdf的高度
|
||||
let leftHeight = imageHeight
|
||||
// 偏移
|
||||
let position = 0
|
||||
// a4纸的尺寸[595.28,841.89],图片在pdf中图片的宽高
|
||||
let imgWidth = a4Width
|
||||
let imgHeight = (a4Width / imageWidth) * imageHeight
|
||||
let imgWidth = a4Size.width
|
||||
let imgHeight = (a4Size.width / imageWidth) * imageHeight
|
||||
let pdf = new JsPDF('', 'pt', 'a4')
|
||||
// 有两个高度需要区分,一个是图片的实际高度,和生成pdf的页面高度(841.89)
|
||||
// 当内容未超过pdf一页显示的范围,无需分页
|
||||
@@ -71,8 +75,8 @@ class ExportPDF {
|
||||
pdf.addImage(
|
||||
img,
|
||||
'PNG',
|
||||
(a4Width - imgWidth) / 2,
|
||||
(a4Height - imgHeight) / 2,
|
||||
(a4Size.width - imgWidth) / 2,
|
||||
(a4Size.height - imgHeight) / 2,
|
||||
imgWidth,
|
||||
imgHeight
|
||||
)
|
||||
@@ -81,7 +85,7 @@ class ExportPDF {
|
||||
while (leftHeight > 0) {
|
||||
pdf.addImage(img, 'PNG', 0, position, imgWidth, imgHeight)
|
||||
leftHeight -= pageHeight
|
||||
position -= a4Height
|
||||
position -= a4Size.height
|
||||
// 避免添加空白页
|
||||
if (leftHeight > 0) {
|
||||
pdf.addPage()
|
||||
|
||||
@@ -94,7 +94,7 @@ class KeyboardNavigation {
|
||||
// 遍历节点树
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
// 跳过当前聚焦的节点
|
||||
if (node === currentActiveNode) return
|
||||
if (node.uid === currentActiveNode.uid) return
|
||||
// 当前遍历到的节点的位置信息
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
@@ -131,7 +131,7 @@ class KeyboardNavigation {
|
||||
checkNodeDis
|
||||
}) {
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node === currentActiveNode) return
|
||||
if (node.uid === currentActiveNode.uid) return
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
let match = false
|
||||
@@ -173,7 +173,7 @@ class KeyboardNavigation {
|
||||
let cX = (currentActiveNodeRect.right + currentActiveNodeRect.left) / 2
|
||||
let cY = (currentActiveNodeRect.bottom + currentActiveNodeRect.top) / 2
|
||||
bfsWalk(this.mindMap.renderer.root, node => {
|
||||
if (node === currentActiveNode) return
|
||||
if (node.uid === currentActiveNode.uid) return
|
||||
let rect = this.getNodeRect(node)
|
||||
let { left, top, right, bottom } = rect
|
||||
// 遍历到的节点的中心点
|
||||
@@ -232,4 +232,4 @@ class KeyboardNavigation {
|
||||
|
||||
KeyboardNavigation.instanceName = 'keyboardNavigation'
|
||||
|
||||
export default KeyboardNavigation
|
||||
export default KeyboardNavigation
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { isWhite, isTransparent, getVisibleColorFromTheme } from '../utils/index'
|
||||
import {
|
||||
isWhite,
|
||||
isTransparent,
|
||||
getVisibleColorFromTheme
|
||||
} from '../utils/index'
|
||||
|
||||
// 小地图插件
|
||||
class MiniMap {
|
||||
@@ -78,7 +82,7 @@ class MiniMap {
|
||||
viewBoxStyle.left = miniMapBoxLeft + actWidth
|
||||
}
|
||||
|
||||
Object.keys(viewBoxStyle).forEach((key) => {
|
||||
Object.keys(viewBoxStyle).forEach(key => {
|
||||
viewBoxStyle[key] = viewBoxStyle[key] + 'px'
|
||||
})
|
||||
|
||||
@@ -106,7 +110,7 @@ class MiniMap {
|
||||
}
|
||||
let children = svg.children()
|
||||
if (children && children.length > 0) {
|
||||
children.forEach((node) => {
|
||||
children.forEach(node => {
|
||||
this.removeNodeContent(node)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class NodeImgAdjust {
|
||||
// 如果当前正在拖动调整中那么直接返回
|
||||
if (this.isMousedown || this.isAdjusted || this.mindMap.opt.readonly) return
|
||||
// 如果在当前节点内移动,以及自定义元素已经是显示状态,那么直接返回
|
||||
if (this.node === node && this.isShowHandleEl) return
|
||||
if (this.node && this.node.uid === node.uid && this.isShowHandleEl) return
|
||||
// 更新当前节点信息
|
||||
this.node = node
|
||||
this.img = img
|
||||
@@ -263,6 +263,11 @@ class NodeImgAdjust {
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
NodeImgAdjust.instanceName = 'nodeImgAdjust'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { nodeDataNoStylePropList } from '../constants/constant'
|
||||
import { checkIsNodeStyleDataKey } from '../utils/index'
|
||||
|
||||
// 格式刷插件
|
||||
class Painter {
|
||||
@@ -49,13 +49,13 @@ class Painter {
|
||||
!this.isInPainter ||
|
||||
!this.painterNode ||
|
||||
!node ||
|
||||
node === this.painterNode
|
||||
node.uid === this.painterNode.uid
|
||||
)
|
||||
return
|
||||
const style = {}
|
||||
const painterNodeData = this.painterNode.nodeData.data
|
||||
Object.keys(painterNodeData).forEach(key => {
|
||||
if (!nodeDataNoStylePropList.includes(key)) {
|
||||
if (checkIsNodeStyleDataKey(key)) {
|
||||
style[key] = painterNodeData[key]
|
||||
}
|
||||
})
|
||||
@@ -69,6 +69,11 @@ class Painter {
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
Painter.instanceName = 'painter'
|
||||
|
||||
@@ -152,7 +152,7 @@ class RichText {
|
||||
}
|
||||
|
||||
// 显示文本编辑控件
|
||||
showEditText(node, rect, isInserting) {
|
||||
showEditText(node, rect, isInserting, isFromKeyDown) {
|
||||
if (this.showTextEdit) {
|
||||
return
|
||||
}
|
||||
@@ -160,7 +160,8 @@ class RichText {
|
||||
richTextEditFakeInPlace,
|
||||
customInnerElsAppendTo,
|
||||
nodeTextEditZIndex,
|
||||
textAutoWrapWidth
|
||||
textAutoWrapWidth,
|
||||
selectTextOnEnterEditText
|
||||
} = this.mindMap.opt
|
||||
this.node = node
|
||||
this.isInserting = isInserting
|
||||
@@ -246,8 +247,11 @@ class RichText {
|
||||
this.initQuillEditor()
|
||||
document.querySelector('.ql-editor').style.minHeight = originHeight + 'px'
|
||||
this.showTextEdit = true
|
||||
// 如果是刚创建的节点,那么默认全选,否则普通激活不全选
|
||||
this.focus(isInserting ? 0 : null)
|
||||
// 如果是刚创建的节点,那么默认全选,否则普通激活不全选,除非selectTextOnEnterEditText配置为true
|
||||
// 在selectTextOnEnterEditText时,如果是在keydown事件进入的节点编辑,也不需要全选
|
||||
this.focus(
|
||||
isInserting || (selectTextOnEnterEditText && !isFromKeyDown) ? 0 : null
|
||||
)
|
||||
if (!node.nodeData.data.richText) {
|
||||
// 如果是非富文本的情况,需要手动应用文本样式
|
||||
this.setTextStyleIfNotRichText(node)
|
||||
@@ -371,7 +375,7 @@ class RichText {
|
||||
}
|
||||
})
|
||||
// 拦截粘贴,只允许粘贴纯文本
|
||||
this.quill.clipboard.addMatcher(Node.TEXT_NODE, (node) => {
|
||||
this.quill.clipboard.addMatcher(Node.TEXT_NODE, node => {
|
||||
let style = this.getPasteTextStyle()
|
||||
return new Delta().insert(node.data, style)
|
||||
})
|
||||
@@ -631,6 +635,11 @@ class RichText {
|
||||
this.transformAllNodesToNormalNode()
|
||||
document.head.removeChild(this.styleEl)
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
document.head.removeChild(this.styleEl)
|
||||
}
|
||||
}
|
||||
|
||||
RichText.instanceName = 'richText'
|
||||
|
||||
258
simple-mind-map/src/plugins/Scrollbar.js
Normal file
258
simple-mind-map/src/plugins/Scrollbar.js
Normal file
@@ -0,0 +1,258 @@
|
||||
import { throttle } from '../utils/index'
|
||||
import { CONSTANTS } from '../constants/constant'
|
||||
|
||||
// 滚动条插件
|
||||
class Scrollbar {
|
||||
// 构造函数
|
||||
constructor(opt) {
|
||||
this.mindMap = opt.mindMap
|
||||
this.scrollbarWrapSize = {
|
||||
width: 0, // 水平滚动条的容器宽度
|
||||
height: 0 // 垂直滚动条的容器高度
|
||||
}
|
||||
// 思维导图实际高度
|
||||
this.chartHeight = 0
|
||||
this.chartWidth = 0
|
||||
this.reset()
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
// 复位数据
|
||||
reset() {
|
||||
// 当前拖拽的滚动条类型
|
||||
this.currentScrollType = ''
|
||||
this.isMousedown = false
|
||||
this.mousedownPos = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
// 鼠标按下时,滚动条位置
|
||||
this.mousedownScrollbarPos = 0
|
||||
}
|
||||
|
||||
// 绑定事件
|
||||
bindEvent() {
|
||||
this.onMousemove = this.onMousemove.bind(this)
|
||||
this.onMouseup = this.onMouseup.bind(this)
|
||||
this.updateScrollbar = this.updateScrollbar.bind(this)
|
||||
this.updateScrollbar = throttle(this.updateScrollbar, 16, this) // 加个节流
|
||||
this.mindMap.on('mousemove', this.onMousemove)
|
||||
this.mindMap.on('mouseup', this.onMouseup)
|
||||
this.mindMap.on('node_tree_render_end', this.updateScrollbar)
|
||||
this.mindMap.on('view_data_change', this.updateScrollbar)
|
||||
}
|
||||
|
||||
// 解绑事件
|
||||
unBindEvent() {
|
||||
this.mindMap.off('mousemove', this.onMousemove)
|
||||
this.mindMap.off('mouseup', this.onMouseup)
|
||||
this.mindMap.off('node_tree_render_end', this.updateScrollbar)
|
||||
this.mindMap.off('view_data_change', this.updateScrollbar)
|
||||
}
|
||||
|
||||
// 渲染后、数据改变需要更新滚动条
|
||||
updateScrollbar() {
|
||||
// 当前正在拖拽滚动条时不需要更新
|
||||
if (this.isMousedown) return
|
||||
const res = this.calculationScrollbar()
|
||||
this.emitEvent(res)
|
||||
}
|
||||
|
||||
// 发送滚动条改变事件
|
||||
emitEvent(data) {
|
||||
this.mindMap.emit('scrollbar_change', data)
|
||||
}
|
||||
|
||||
// 设置滚动条容器的大小,指滚动条容器的大小,对于水平滚动条,即宽度,对于垂直滚动条,即高度
|
||||
setScrollBarWrapSize(width, height) {
|
||||
this.scrollbarWrapSize.width = width
|
||||
this.scrollbarWrapSize.height = height
|
||||
}
|
||||
|
||||
// 计算滚动条大小和位置
|
||||
calculationScrollbar() {
|
||||
const rect = this.mindMap.draw.rbox()
|
||||
// 减去画布距离浏览器窗口左上角的距离
|
||||
const elRect = this.mindMap.elRect
|
||||
rect.x -= elRect.left
|
||||
rect.y -= elRect.top
|
||||
|
||||
// 垂直滚动条
|
||||
const canvasHeight = this.mindMap.height // 画布高度
|
||||
const paddingY = canvasHeight / 2 // 首尾允许超出的距离,默认为高度的一半
|
||||
const chartHeight = rect.height + paddingY * 2 // 思维导图高度
|
||||
this.chartHeight = chartHeight
|
||||
const chartTop = rect.y - paddingY // 思维导图顶部距画布顶部的距离
|
||||
const height = Math.min((canvasHeight / chartHeight) * 100, 100) // 滚动条高度 = 画布高度 / 思维导图高度
|
||||
let top = (-chartTop / chartHeight) * 100 // 滚动条距离 = 思维导图顶部距画布顶部的距离 / 思维导图高度
|
||||
// 判断是否到达边界
|
||||
if (top < 0) {
|
||||
top = 0
|
||||
}
|
||||
if (top > 100 - height) {
|
||||
top = 100 - height
|
||||
}
|
||||
|
||||
// 水平滚动条
|
||||
const canvasWidth = this.mindMap.width
|
||||
const paddingX = canvasWidth / 2
|
||||
const chartWidth = rect.width + paddingX * 2
|
||||
this.chartWidth = chartWidth
|
||||
const chartLeft = rect.x - paddingX
|
||||
const width = Math.min((canvasWidth / chartWidth) * 100, 100)
|
||||
let left = (-chartLeft / chartWidth) * 100
|
||||
if (left < 0) {
|
||||
left = 0
|
||||
}
|
||||
if (left > 100 - width) {
|
||||
left = 100 - width
|
||||
}
|
||||
|
||||
const res = {
|
||||
// 垂直滚动条
|
||||
vertical: {
|
||||
top,
|
||||
height
|
||||
},
|
||||
// 水平滚动条
|
||||
horizontal: {
|
||||
left,
|
||||
width
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// 滚动条鼠标按下事件处理函数
|
||||
onMousedown(e, type) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
this.currentScrollType = type
|
||||
this.isMousedown = true
|
||||
this.mousedownPos = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
}
|
||||
// 保存滚动条当前的位置
|
||||
const styles = window.getComputedStyle(e.target)
|
||||
if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
|
||||
this.mousedownScrollbarPos = Number.parseFloat(styles.top)
|
||||
} else {
|
||||
this.mousedownScrollbarPos = Number.parseFloat(styles.left)
|
||||
}
|
||||
}
|
||||
|
||||
// 鼠标移动事件处理函数
|
||||
onMousemove(e) {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
if (this.currentScrollType === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
|
||||
const oy = e.clientY - this.mousedownPos.y + this.mousedownScrollbarPos
|
||||
this.updateMindMapView(CONSTANTS.SCROLL_BAR_DIR.VERTICAL, oy)
|
||||
} else {
|
||||
const ox = e.clientX - this.mousedownPos.x + this.mousedownScrollbarPos
|
||||
this.updateMindMapView(CONSTANTS.SCROLL_BAR_DIR.HORIZONTAL, ox)
|
||||
}
|
||||
}
|
||||
|
||||
// 鼠标松开事件处理函数
|
||||
onMouseup() {
|
||||
this.isMousedown = false
|
||||
this.reset()
|
||||
}
|
||||
|
||||
// 更新视图
|
||||
updateMindMapView(type, offset) {
|
||||
const scrollbarData = this.calculationScrollbar()
|
||||
const t = this.mindMap.draw.transform()
|
||||
const drawRect = this.mindMap.draw.rbox()
|
||||
const rootRect = this.mindMap.renderer.root.group.rbox()
|
||||
if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
|
||||
// 滚动条新位置
|
||||
let oy = offset
|
||||
// 判断是否达到首尾
|
||||
if (oy <= 0) {
|
||||
oy = 0
|
||||
}
|
||||
let max =
|
||||
((100 - scrollbarData.vertical.height) / 100) *
|
||||
this.scrollbarWrapSize.height
|
||||
if (oy >= max) {
|
||||
oy = max
|
||||
}
|
||||
// 转换成百分比
|
||||
const oyPercentage = (oy / this.scrollbarWrapSize.height) * 100
|
||||
// 转换成相对于图形高度的距离
|
||||
const oyPx = (-oyPercentage / 100) * this.chartHeight
|
||||
// 节点中心点到图形最上方的距离
|
||||
const yOffset = rootRect.y - drawRect.y
|
||||
// 内边距
|
||||
const paddingY = this.mindMap.height / 2
|
||||
// 图形新位置
|
||||
let chartTop = oyPx + yOffset - paddingY * t.scaleY + paddingY
|
||||
this.mindMap.view.translateYTo(chartTop)
|
||||
this.emitEvent({
|
||||
horizontal: scrollbarData.horizontal,
|
||||
vertical: {
|
||||
top: oyPercentage,
|
||||
height: scrollbarData.vertical.height
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 滚动条新位置
|
||||
let ox = offset
|
||||
// 判断是否达到首尾
|
||||
if (ox <= 0) {
|
||||
ox = 0
|
||||
}
|
||||
let max =
|
||||
((100 - scrollbarData.horizontal.width) / 100) *
|
||||
this.scrollbarWrapSize.width
|
||||
if (ox >= max) {
|
||||
ox = max
|
||||
}
|
||||
// 转换成百分比
|
||||
const oxPercentage = (ox / this.scrollbarWrapSize.width) * 100
|
||||
// 转换成相对于图形高度的距离
|
||||
const oxPx = (-oxPercentage / 100) * this.chartWidth
|
||||
// 节点中心点到图形最左边的距离
|
||||
const xOffset = rootRect.x - drawRect.x
|
||||
// 内边距
|
||||
const paddingX = this.mindMap.width / 2
|
||||
// 图形新位置
|
||||
let chartLeft = oxPx + xOffset - paddingX * t.scaleX + paddingX
|
||||
this.mindMap.view.translateXTo(chartLeft)
|
||||
this.emitEvent({
|
||||
vertical: scrollbarData.vertical,
|
||||
horizontal: {
|
||||
left: oxPercentage,
|
||||
width: scrollbarData.horizontal.width
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条的点击事件
|
||||
onClick(e, type) {
|
||||
let offset = 0
|
||||
if (type === CONSTANTS.SCROLL_BAR_DIR.VERTICAL) {
|
||||
offset = e.clientY - e.currentTarget.getBoundingClientRect().top
|
||||
} else {
|
||||
offset = e.clientX - e.currentTarget.getBoundingClientRect().left
|
||||
}
|
||||
this.updateMindMapView(type, offset)
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
Scrollbar.instanceName = 'scrollbar'
|
||||
|
||||
export default Scrollbar
|
||||
@@ -1,4 +1,9 @@
|
||||
import { bfsWalk, getTextFromHtml, isUndef, replaceHtmlText } from '../utils/index'
|
||||
import {
|
||||
bfsWalk,
|
||||
getTextFromHtml,
|
||||
isUndef,
|
||||
replaceHtmlText
|
||||
} from '../utils/index'
|
||||
|
||||
// 搜索插件
|
||||
class Search {
|
||||
|
||||
@@ -11,6 +11,8 @@ class Select {
|
||||
this.mouseDownY = 0
|
||||
this.mouseMoveX = 0
|
||||
this.mouseMoveY = 0
|
||||
this.isSelecting = false
|
||||
this.cacheActiveList = []
|
||||
this.bindEvent()
|
||||
}
|
||||
|
||||
@@ -30,6 +32,7 @@ class Select {
|
||||
}
|
||||
e.preventDefault()
|
||||
this.isMousedown = true
|
||||
this.cacheActiveList = [...this.mindMap.renderer.activeNodeList]
|
||||
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
this.mouseDownX = x
|
||||
this.mouseDownY = y
|
||||
@@ -51,8 +54,40 @@ class Select {
|
||||
) {
|
||||
return
|
||||
}
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
this.onMove(x, y)
|
||||
this.clearAutoMoveTimer()
|
||||
this.onMove(
|
||||
e.clientX,
|
||||
e.clientY,
|
||||
() => {
|
||||
this.isSelecting = true
|
||||
// 绘制矩形
|
||||
this.rect.plot([
|
||||
[this.mouseDownX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseMoveY],
|
||||
[this.mouseDownX, this.mouseMoveY]
|
||||
])
|
||||
this.checkInNodes()
|
||||
},
|
||||
(dir, step) => {
|
||||
switch (dir) {
|
||||
case 'left':
|
||||
this.mouseDownX += step
|
||||
break
|
||||
case 'top':
|
||||
this.mouseDownY += step
|
||||
break
|
||||
case 'right':
|
||||
this.mouseDownX -= step
|
||||
break
|
||||
case 'bottom':
|
||||
this.mouseDownY -= step
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
this.mindMap.on('mouseup', () => {
|
||||
if (this.mindMap.opt.readonly) {
|
||||
@@ -61,68 +96,92 @@ class Select {
|
||||
if (!this.isMousedown) {
|
||||
return
|
||||
}
|
||||
this.mindMap.emit(
|
||||
'node_active',
|
||||
null,
|
||||
this.mindMap.renderer.activeNodeList
|
||||
)
|
||||
this.checkTriggerNodeActiveEvent()
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
this.isMousedown = false
|
||||
this.cacheActiveList = []
|
||||
if (this.rect) this.rect.remove()
|
||||
this.rect = null
|
||||
setTimeout(() => {
|
||||
this.isSelecting = false
|
||||
}, 0)
|
||||
})
|
||||
}
|
||||
|
||||
// 如果激活节点改变了,那么触发事件
|
||||
checkTriggerNodeActiveEvent() {
|
||||
let isNumChange =
|
||||
this.cacheActiveList.length !==
|
||||
this.mindMap.renderer.activeNodeList.length
|
||||
let isNodeChange = false
|
||||
if (!isNumChange) {
|
||||
for (let i = 0; i < this.cacheActiveList.length; i++) {
|
||||
let cur = this.cacheActiveList[i]
|
||||
if (
|
||||
!this.mindMap.renderer.activeNodeList.find(item => {
|
||||
return item.nodeData.data.uid === cur.nodeData.data.uid
|
||||
})
|
||||
) {
|
||||
isNodeChange = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isNumChange || isNodeChange) {
|
||||
this.mindMap.emit('node_active', null, [
|
||||
...this.mindMap.renderer.activeNodeList
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
// 鼠标移动事件
|
||||
onMove(x, y) {
|
||||
// 绘制矩形
|
||||
this.rect.plot([
|
||||
[this.mouseDownX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseDownY],
|
||||
[this.mouseMoveX, this.mouseMoveY],
|
||||
[this.mouseDownX, this.mouseMoveY]
|
||||
])
|
||||
this.checkInNodes()
|
||||
onMove(x, y, callback = () => {}, handle = () => {}) {
|
||||
callback()
|
||||
// 检测边缘移动
|
||||
let step = this.mindMap.opt.selectTranslateStep
|
||||
let limit = this.mindMap.opt.selectTranslateLimit
|
||||
let count = 0
|
||||
// 左边缘
|
||||
if (x <= this.mindMap.elRect.left + limit) {
|
||||
this.mouseDownX += step
|
||||
handle('left', step)
|
||||
this.mindMap.view.translateX(step)
|
||||
count++
|
||||
}
|
||||
// 右边缘
|
||||
if (x >= this.mindMap.elRect.right - limit) {
|
||||
this.mouseDownX -= step
|
||||
handle('right', step)
|
||||
this.mindMap.view.translateX(-step)
|
||||
count++
|
||||
}
|
||||
// 上边缘
|
||||
if (y <= this.mindMap.elRect.top + limit) {
|
||||
this.mouseDownY += step
|
||||
handle('top', step)
|
||||
this.mindMap.view.translateY(step)
|
||||
count++
|
||||
}
|
||||
// 下边缘
|
||||
if (y >= this.mindMap.elRect.bottom - limit) {
|
||||
this.mouseDownY -= step
|
||||
handle('bottom', step)
|
||||
this.mindMap.view.translateY(-step)
|
||||
count++
|
||||
}
|
||||
if (count > 0) {
|
||||
this.startAutoMove(x, y)
|
||||
this.startAutoMove(x, y, callback, handle)
|
||||
}
|
||||
}
|
||||
|
||||
// 开启自动移动
|
||||
startAutoMove(x, y) {
|
||||
startAutoMove(x, y, callback, handle) {
|
||||
this.autoMoveTimer = setTimeout(() => {
|
||||
this.onMove(x, y)
|
||||
this.onMove(x, y, callback, handle)
|
||||
}, 20)
|
||||
}
|
||||
|
||||
// 清除自动移动定时器
|
||||
clearAutoMoveTimer() {
|
||||
clearTimeout(this.autoMoveTimer)
|
||||
}
|
||||
|
||||
// 创建矩形
|
||||
createRect(x, y) {
|
||||
this.rect = this.mindMap.svg
|
||||
@@ -172,6 +231,11 @@ class Select {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 是否存在选区
|
||||
hasSelectRange() {
|
||||
return this.isSelecting
|
||||
}
|
||||
}
|
||||
|
||||
Select.instanceName = 'select'
|
||||
|
||||
@@ -148,6 +148,11 @@ class TouchEvent {
|
||||
beforePluginRemove() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
|
||||
// 插件被卸载前做的事情
|
||||
beforePluginDestroy() {
|
||||
this.unBindEvent()
|
||||
}
|
||||
}
|
||||
|
||||
TouchEvent.instanceName = 'touchEvent'
|
||||
|
||||
@@ -109,7 +109,10 @@ class Watermark {
|
||||
|
||||
// 更新水印
|
||||
updateWatermark(config) {
|
||||
this.mindMap.opt.watermarkConfig = merge(this.mindMap.opt.watermarkConfig, config)
|
||||
this.mindMap.opt.watermarkConfig = merge(
|
||||
this.mindMap.opt.watermarkConfig,
|
||||
config
|
||||
)
|
||||
this.handleConfig(config)
|
||||
this.draw()
|
||||
}
|
||||
@@ -117,4 +120,4 @@ class Watermark {
|
||||
|
||||
Watermark.instanceName = 'watermark'
|
||||
|
||||
export default Watermark
|
||||
export default Watermark
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
getAssociativeLineTargetIndex,
|
||||
joinCubicBezierPath,
|
||||
computeNodePoints,
|
||||
getNodePoint,
|
||||
getDefaultControlPointOffsets
|
||||
} from './associativeLineUtils'
|
||||
|
||||
@@ -61,15 +61,22 @@ function onControlPointMousemove(e) {
|
||||
}
|
||||
// 更新当前拖拽的控制点的位置
|
||||
this[this.mousedownControlPointKey].x(x - radius).y(y - radius)
|
||||
let [path, clickPath, text, node, toNode] = this.activeLine
|
||||
let [startPoint, endPoint] = computeNodePoints(node, toNode)
|
||||
let [, , , node, toNode] = this.activeLine
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
let { associativeLinePoint, associativeLineTargetControlOffsets } =
|
||||
node.nodeData.data
|
||||
associativeLinePoint = associativeLinePoint || []
|
||||
const nodePos = this.getNodePos(node)
|
||||
const toNodePos = this.getNodePos(toNode)
|
||||
let [startPoint, endPoint] = this.updateAllLinesPos(
|
||||
node,
|
||||
toNode,
|
||||
associativeLinePoint[targetIndex]
|
||||
)
|
||||
this.controlPointMousemoveState.startPoint = startPoint
|
||||
this.controlPointMousemoveState.endPoint = endPoint
|
||||
let targetIndex = getAssociativeLineTargetIndex(node, toNode)
|
||||
this.controlPointMousemoveState.targetIndex = targetIndex
|
||||
let offsets = []
|
||||
let associativeLineTargetControlOffsets =
|
||||
node.nodeData.data.associativeLineTargetControlOffsets
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsets = getDefaultControlPointOffsets(startPoint, endPoint)
|
||||
@@ -78,8 +85,14 @@ function onControlPointMousemove(e) {
|
||||
}
|
||||
let point1 = null
|
||||
let point2 = null
|
||||
const { x: clientX, y: clientY } = this.mindMap.toPos(e.clientX, e.clientY)
|
||||
const _e = {
|
||||
clientX,
|
||||
clientY
|
||||
}
|
||||
// 拖拽的是控制点1
|
||||
if (this.mousedownControlPointKey === 'controlPoint1') {
|
||||
startPoint = getNodePoint(nodePos, '', 0, _e)
|
||||
point1 = {
|
||||
x,
|
||||
y
|
||||
@@ -88,10 +101,15 @@ function onControlPointMousemove(e) {
|
||||
x: endPoint.x + offsets[1].x,
|
||||
y: endPoint.y + offsets[1].y
|
||||
}
|
||||
// 更新控制点1的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
if (startPoint) {
|
||||
// 保存更新后的坐标
|
||||
this.controlPointMousemoveState.startPoint = startPoint
|
||||
// 更新控制点1的连线
|
||||
this.controlLine1.plot(startPoint.x, startPoint.y, point1.x, point1.y)
|
||||
}
|
||||
} else {
|
||||
// 拖拽的是控制点2
|
||||
endPoint = getNodePoint(toNodePos, '', 0, _e)
|
||||
point1 = {
|
||||
x: startPoint.x + offsets[0].x,
|
||||
y: startPoint.y + offsets[0].y
|
||||
@@ -100,18 +118,39 @@ function onControlPointMousemove(e) {
|
||||
x,
|
||||
y
|
||||
}
|
||||
// 更新控制点2的连线
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
if (endPoint) {
|
||||
// 保存更新后结束节点的坐标
|
||||
this.controlPointMousemoveState.endPoint = endPoint
|
||||
// 更新控制点2的连线
|
||||
this.controlLine2.plot(endPoint.x, endPoint.y, point2.x, point2.y)
|
||||
}
|
||||
}
|
||||
this.updataAassociativeLine(
|
||||
startPoint,
|
||||
endPoint,
|
||||
point1,
|
||||
point2,
|
||||
this.activeLine
|
||||
)
|
||||
}
|
||||
|
||||
function updataAassociativeLine(
|
||||
startPoint,
|
||||
endPoint,
|
||||
point1,
|
||||
point2,
|
||||
activeLine
|
||||
) {
|
||||
const [path, clickPath, text] = activeLine
|
||||
// 更新关联线
|
||||
let pathStr = joinCubicBezierPath(startPoint, endPoint, point1, point2)
|
||||
const pathStr = joinCubicBezierPath(startPoint, endPoint, point1, point2)
|
||||
path.plot(pathStr)
|
||||
clickPath.plot(pathStr)
|
||||
this.updateTextPos(path, text)
|
||||
this.updateTextEditBoxPos(text)
|
||||
}
|
||||
|
||||
// 控制点的鼠标移动事件
|
||||
// 控制点的鼠标松开事件
|
||||
function onControlPointMouseup(e) {
|
||||
if (!this.isControlPointMousedown) return
|
||||
e.stopPropagation()
|
||||
@@ -120,8 +159,15 @@ function onControlPointMouseup(e) {
|
||||
this.controlPointMousemoveState
|
||||
let [, , , node] = this.activeLine
|
||||
let offsetList = []
|
||||
let associativeLineTargetControlOffsets =
|
||||
node.nodeData.data.associativeLineTargetControlOffsets
|
||||
let { associativeLinePoint, associativeLineTargetControlOffsets } =
|
||||
node.nodeData.data
|
||||
if (!associativeLinePoint) {
|
||||
associativeLinePoint = []
|
||||
}
|
||||
associativeLinePoint[targetIndex] = associativeLinePoint[targetIndex] || {
|
||||
startPoint,
|
||||
endPoint
|
||||
}
|
||||
if (!associativeLineTargetControlOffsets) {
|
||||
// 兼容0.4.5版本,没有associativeLineTargetControlOffsets的情况
|
||||
offsetList[targetIndex] = getDefaultControlPointOffsets(
|
||||
@@ -140,6 +186,7 @@ function onControlPointMouseup(e) {
|
||||
y: pos.y - startPoint.y
|
||||
}
|
||||
offset2 = offsetList[targetIndex][1]
|
||||
associativeLinePoint[targetIndex].startPoint = startPoint
|
||||
} else {
|
||||
// 更新控制点2数据
|
||||
offset1 = offsetList[targetIndex][0]
|
||||
@@ -147,10 +194,12 @@ function onControlPointMouseup(e) {
|
||||
x: pos.x - endPoint.x,
|
||||
y: pos.y - endPoint.y
|
||||
}
|
||||
associativeLinePoint[targetIndex].endPoint = endPoint
|
||||
}
|
||||
offsetList[targetIndex] = [offset1, offset2]
|
||||
this.mindMap.execCommand('SET_NODE_DATA', node, {
|
||||
associativeLineTargetControlOffsets: offsetList
|
||||
associativeLineTargetControlOffsets: offsetList,
|
||||
associativeLinePoint
|
||||
})
|
||||
// 这里要加个setTimeout0是因为draw_click事件比mouseup事件触发的晚,所以重置isControlPointMousedown需要等draw_click事件触发完以后
|
||||
setTimeout(() => {
|
||||
@@ -237,5 +286,6 @@ export default {
|
||||
renderControls,
|
||||
removeControls,
|
||||
hideControls,
|
||||
showControls
|
||||
showControls,
|
||||
updataAassociativeLine
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ function showEditTextBox(g) {
|
||||
this.mindMap.keyCommand.addShortcut('Enter', () => {
|
||||
this.hideEditTextBox()
|
||||
})
|
||||
|
||||
|
||||
if (!this.textEditNode) {
|
||||
this.textEditNode = document.createElement('div')
|
||||
this.textEditNode.style.cssText = `position:fixed;box-sizing: border-box;background-color:#fff;box-shadow: 0 0 20px rgba(0,0,0,.5);padding: 3px 5px;margin-left: -5px;margin-top: -3px;outline: none; word-break: break-all;`
|
||||
@@ -62,7 +62,8 @@ function showEditTextBox(g) {
|
||||
).split(/\n/gim)
|
||||
this.textEditNode.style.fontFamily = associativeLineTextFontFamily
|
||||
this.textEditNode.style.fontSize = associativeLineTextFontSize * scale + 'px'
|
||||
this.textEditNode.style.lineHeight = textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
||||
this.textEditNode.style.lineHeight =
|
||||
textLines.length > 1 ? associativeLineTextLineHeight : 'normal'
|
||||
this.textEditNode.style.zIndex = this.mindMap.opt.nodeTextEditZIndex
|
||||
this.textEditNode.innerHTML = textLines.join('<br>')
|
||||
this.textEditNode.style.display = 'block'
|
||||
@@ -78,10 +79,12 @@ function onScale() {
|
||||
// 更新文本编辑框位置
|
||||
function updateTextEditBoxPos(g) {
|
||||
let rect = g.node.getBoundingClientRect()
|
||||
this.textEditNode.style.minWidth = rect.width + 10 + 'px'
|
||||
this.textEditNode.style.minHeight = rect.height + 6 + 'px'
|
||||
this.textEditNode.style.left = rect.left + 'px'
|
||||
this.textEditNode.style.top = rect.top + 'px'
|
||||
if (this.textEditNode) {
|
||||
this.textEditNode.style.minWidth = `${rect.width + 10}px`
|
||||
this.textEditNode.style.minHeight = `${rect.height + 6}px`
|
||||
this.textEditNode.style.left = `${rect.left}px`
|
||||
this.textEditNode.style.top = `${rect.top}px`
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏文本编辑框
|
||||
|
||||
@@ -54,28 +54,136 @@ export const cubicBezierPath = (x1, y1, x2, y2) => {
|
||||
)
|
||||
}
|
||||
|
||||
export const calcPoint = (node, e) => {
|
||||
const { left, top, translateLeft, translateTop, width, height } = node
|
||||
const clientX = e.clientX
|
||||
const clientY = e.clientY
|
||||
// 中心点的坐标
|
||||
const centerX = translateLeft + width / 2
|
||||
const centerY = translateTop + height / 2
|
||||
const translateCenterX = left + width / 2
|
||||
const translateCenterY = top + height / 2
|
||||
const theta = Math.atan(height / width)
|
||||
// 矩形左上角坐标
|
||||
const deltaX = clientX - centerX
|
||||
const deltaY = centerY - clientY
|
||||
// 方向值
|
||||
const direction = Math.atan2(deltaY, deltaX)
|
||||
// 默认坐标
|
||||
let x = left + width
|
||||
let y = top + height
|
||||
if (direction < theta && direction >= -theta) {
|
||||
// 右边
|
||||
// 正切值 = 对边/邻边,对边 = 正切值*邻边
|
||||
const range = direction * (width / 2)
|
||||
if (direction < theta && direction >= 0) {
|
||||
// 中心点上边
|
||||
y = translateCenterY - range
|
||||
} else if (direction >= -theta && direction < 0) {
|
||||
// 中心点下方
|
||||
y = translateCenterY - range
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
dir: 'right',
|
||||
range
|
||||
}
|
||||
} else if (direction >= theta && direction < Math.PI - theta) {
|
||||
// 上边
|
||||
y = top
|
||||
let range = 0
|
||||
if (direction < Math.PI / 2 - theta && direction >= theta) {
|
||||
// 正切值 = 对边/邻边,邻边 = 对边/正切值
|
||||
const side = height / 2 / direction
|
||||
range = -side
|
||||
// 中心点右侧
|
||||
x = translateCenterX + side
|
||||
} else if (
|
||||
direction >= Math.PI / 2 - theta &&
|
||||
direction < Math.PI - theta
|
||||
) {
|
||||
// 中心点左侧
|
||||
const tanValue = (centerX - clientX) / (centerY - clientY)
|
||||
const side = (height / 2) * tanValue
|
||||
range = side
|
||||
x = translateCenterX - side
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
dir: 'top',
|
||||
range
|
||||
}
|
||||
} else if (direction < -theta && direction >= theta - Math.PI) {
|
||||
// 下边
|
||||
let range = 0
|
||||
if (direction >= theta - Math.PI / 2 && direction < -theta) {
|
||||
// 中心点右侧
|
||||
// 正切值 = 对边/邻边,邻边 = 对边/正切值
|
||||
const side = height / 2 / direction
|
||||
range = side
|
||||
x = translateCenterX - side
|
||||
} else if (
|
||||
direction < theta - Math.PI / 2 &&
|
||||
direction >= theta - Math.PI
|
||||
) {
|
||||
// 中心点左侧
|
||||
const tanValue = (centerX - clientX) / (centerY - clientY)
|
||||
const side = (height / 2) * tanValue
|
||||
range = -side
|
||||
x = translateCenterX + side
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
dir: 'bottom',
|
||||
range
|
||||
}
|
||||
}
|
||||
// 左边
|
||||
x = left
|
||||
const tanValue = (centerY - clientY) / (centerX - clientX)
|
||||
const range = tanValue * (width / 2)
|
||||
if (direction >= -Math.PI && direction < theta - Math.PI) {
|
||||
// 中心点右侧
|
||||
y = translateCenterY - range
|
||||
} else if (direction < Math.PI && direction >= Math.PI - theta) {
|
||||
// 中心点左侧
|
||||
y = translateCenterY - range
|
||||
}
|
||||
return {
|
||||
x,
|
||||
y,
|
||||
dir: 'left',
|
||||
range
|
||||
}
|
||||
}
|
||||
// 获取节点的连接点
|
||||
export const getNodePoint = (node, dir = 'right') => {
|
||||
export const getNodePoint = (node, dir = 'right', range = 0, e = null) => {
|
||||
let { left, top, width, height } = node
|
||||
if (e) {
|
||||
return calcPoint(node, e)
|
||||
}
|
||||
switch (dir) {
|
||||
case 'left':
|
||||
return {
|
||||
x: left,
|
||||
y: top + height / 2
|
||||
y: top + height / 2 - range
|
||||
}
|
||||
case 'right':
|
||||
return {
|
||||
x: left + width,
|
||||
y: top + height / 2
|
||||
y: top + height / 2 - range
|
||||
}
|
||||
case 'top':
|
||||
return {
|
||||
x: left + width / 2,
|
||||
x: left + width / 2 - range,
|
||||
y: top
|
||||
}
|
||||
case 'bottom':
|
||||
return {
|
||||
x: left + width / 2,
|
||||
x: left + width / 2 - range,
|
||||
y: top + height
|
||||
}
|
||||
default:
|
||||
@@ -111,8 +219,8 @@ export const computeNodePoints = (fromNode, toNode) => {
|
||||
toDir = 'bottom'
|
||||
} else if (offsetY > 0 && -offsetY < offsetX && offsetY > offsetX) {
|
||||
// down
|
||||
fromDir = 'bottom'
|
||||
toDir = 'top'
|
||||
fromDir = 'right'
|
||||
toDir = 'right'
|
||||
}
|
||||
return [getNodePoint(fromNode, fromDir), getNodePoint(toNode, toDir)]
|
||||
}
|
||||
@@ -179,4 +287,4 @@ export const getDefaultControlPointOffsets = (startPoint, endPoint) => {
|
||||
y: controlPoints[1].y - endPoint.y
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '#e68112',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,18 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: '#8c5416',
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#e68112'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#8c5416',
|
||||
active: {
|
||||
borderColor: '#b0bc47'
|
||||
}
|
||||
color: '#8c5416'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -49,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: '#ffd683',
|
||||
borderColor: '#b0bc47',
|
||||
borderWidth: 2,
|
||||
color: '#8c5416',
|
||||
active: {
|
||||
borderColor: '#e68112'
|
||||
}
|
||||
color: '#8c5416'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '#94c143',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#749336',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,18 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: '#749336',
|
||||
borderColor: '#aec668',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#749336',
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
color: '#749336'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -49,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: '#cee498',
|
||||
borderColor: '#aec668',
|
||||
borderWidth: 2,
|
||||
color: '#749336',
|
||||
active: {
|
||||
borderColor: '#749336'
|
||||
}
|
||||
color: '#749336'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(111, 61, 6)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#fff',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,18 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(225, 201, 158)',
|
||||
borderColor: 'rgb(245, 224, 191)',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 208, 124)'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(231, 203, 155)',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 208, 124)'
|
||||
}
|
||||
color: 'rgb(231, 203, 155)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -49,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(56, 45, 34)',
|
||||
borderColor: 'rgb(104, 84, 61)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(242, 216, 176)',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 208, 124)'
|
||||
}
|
||||
color: 'rgb(242, 216, 176)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: 'rgb(254, 199, 13)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,19 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(0, 0, 0)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(36, 179, 96)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(204, 204, 204)',
|
||||
active: {
|
||||
borderColor: 'rgb(254, 199, 13)'
|
||||
}
|
||||
color: 'rgb(204, 204, 204)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -50,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(27, 31, 34)',
|
||||
borderColor: 'rgb(255, 119, 34)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(204, 204, 204)',
|
||||
active: {
|
||||
borderColor: 'rgb(36, 179, 96)'
|
||||
}
|
||||
color: 'rgb(204, 204, 204)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,10 +13,7 @@ export default merge(defaultTheme, {
|
||||
generalizationLineColor: '#333',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(115, 161, 191)',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)'
|
||||
}
|
||||
fillColor: 'rgb(115, 161, 191)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -24,26 +21,17 @@ export default merge(defaultTheme, {
|
||||
color: '#333',
|
||||
borderColor: 'rgb(115, 161, 191)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,10 +13,7 @@ export default merge(defaultTheme, {
|
||||
generalizationLineColor: '#333',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(191, 115, 148)',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 74)'
|
||||
}
|
||||
fillColor: 'rgb(191, 115, 148)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -24,26 +21,17 @@ export default merge(defaultTheme, {
|
||||
color: '#333',
|
||||
borderColor: 'rgb(191, 115, 148)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 74)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 74)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 74)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,16 +18,13 @@ export default merge(defaultTheme, {
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDowQzg5QTQ0NDhENzgxMUUzOENGREE4QTg0RDgzRTZDNyIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDowQzg5QTQ0NThENzgxMUUzOENGREE4QTg0RDgzRTZDNyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkMwOEQ1NDRGOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkMwOEQ1NDUwOEQ3NzExRTM4Q0ZEQThBODREODNFNkM3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+e9P33AAAACVJREFUeNpisXJ0YUACTAyoAMr/+eM7EGGRZ4FQ7BycEAZAgAEAHbEGtkoQm/wAAAAASUVORK5CYII=',
|
||||
// 背景重复
|
||||
backgroundRepeat: 'repeat',
|
||||
backgroundSize: 'auto',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(233, 223, 152)',
|
||||
color: '#333',
|
||||
fontSize: 24,
|
||||
borderRadius: 21,
|
||||
active: {
|
||||
fillColor: 'rgb(254, 219, 0)',
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
borderRadius: 21
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -35,30 +32,18 @@ export default merge(defaultTheme, {
|
||||
borderColor: 'transparent',
|
||||
color: '#333',
|
||||
fontSize: 16,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
fillColor: 'rgb(254, 219, 0)',
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
active: {
|
||||
fillColor: 'rgb(254, 219, 0)',
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'transparent',
|
||||
color: '#333',
|
||||
active: {
|
||||
fillColor: 'rgb(254, 219, 0)',
|
||||
borderColor: 'transparent'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,10 +18,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(18, 187, 55)',
|
||||
color: '#fff',
|
||||
fontSize: 24,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
borderColor: 'rgb(51, 51, 51)'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,27 +26,18 @@ export default merge(defaultTheme, {
|
||||
borderColor: 'transparent',
|
||||
color: '#1a1a1a',
|
||||
fontSize: 18,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
borderColor: 'rgb(51, 51, 51)'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#1a1a1a',
|
||||
active: {
|
||||
borderColor: 'rgb(51, 51, 51)'
|
||||
}
|
||||
color: '#1a1a1a'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'rgb(51, 51, 51)',
|
||||
borderWidth: 2,
|
||||
color: '#1a1a1a',
|
||||
active: {
|
||||
borderColor: 'rgb(18, 187, 55)'
|
||||
}
|
||||
color: '#1a1a1a'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -20,10 +20,7 @@ export default merge(defaultTheme, {
|
||||
fontSize: 24,
|
||||
borderRadius: 10,
|
||||
borderColor: 'rgb(249, 199, 84)',
|
||||
borderWidth: 1,
|
||||
active: {
|
||||
borderColor: 'rgb(94, 202, 110)'
|
||||
}
|
||||
borderWidth: 1
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -32,27 +29,18 @@ export default merge(defaultTheme, {
|
||||
borderWidth: 1,
|
||||
color: '#1a1a1a',
|
||||
fontSize: 18,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
borderColor: 'rgb(94, 202, 110)'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#1a1a1a',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 202, 110)'
|
||||
}
|
||||
color: '#1a1a1a'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#1a1a1a',
|
||||
color: '#1a1a1a',
|
||||
borderWidth: 2,
|
||||
active: {
|
||||
borderColor: 'rgb(94, 202, 110)'
|
||||
}
|
||||
borderWidth: 2
|
||||
}
|
||||
})
|
||||
|
||||
@@ -20,10 +20,7 @@ export default merge(defaultTheme, {
|
||||
fontSize: 24,
|
||||
borderRadius: 10,
|
||||
borderColor: 'rgb(189, 197, 201)',
|
||||
borderWidth: 2,
|
||||
active: {
|
||||
borderColor: 'rgb(169, 218, 218)'
|
||||
}
|
||||
borderWidth: 2
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -32,10 +29,7 @@ export default merge(defaultTheme, {
|
||||
borderWidth: 2,
|
||||
color: '#fff',
|
||||
fontSize: 18,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
borderColor: 'rgb(56, 123, 233)'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
@@ -43,19 +37,13 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(30, 53, 86)',
|
||||
borderColor: 'rgb(30, 53, 86)',
|
||||
borderWidth: 1,
|
||||
marginY: 20,
|
||||
active: {
|
||||
borderColor: 'rgb(169, 218, 218)'
|
||||
}
|
||||
marginY: 20
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'rgb(56, 123, 233)',
|
||||
borderColor: 'rgb(56, 123, 233)',
|
||||
color: '#fff',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(169, 218, 218)'
|
||||
}
|
||||
borderWidth: 0
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,10 +16,7 @@ export default merge(defaultTheme, {
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(255, 255, 255)',
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -27,26 +24,17 @@ export default merge(defaultTheme, {
|
||||
color: '#222',
|
||||
borderColor: 'rgb(255, 255, 255)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'rgb(51, 51, 51)',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -14,10 +14,7 @@ export default merge(defaultTheme, {
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(253, 244, 217)',
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -25,27 +22,18 @@ export default merge(defaultTheme, {
|
||||
color: '#222',
|
||||
borderColor: 'rgb(242, 200, 104)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'rgb(123, 199, 120)',
|
||||
borderColor: 'transparent',
|
||||
borderWidth: 2,
|
||||
color: '#fff',
|
||||
active: {
|
||||
borderColor: 'rgb(94, 199, 248)'
|
||||
}
|
||||
color: '#fff'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,11 +16,7 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: 'rgb(173, 123, 91)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -28,18 +24,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(125, 86, 42)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(173, 123, 91)'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(96, 71, 47)',
|
||||
active: {
|
||||
borderColor: 'rgb(173, 123, 91)'
|
||||
}
|
||||
color: 'rgb(96, 71, 47)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -47,9 +37,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(255, 249, 239)',
|
||||
borderColor: 'rgb(173, 123, 91)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(122, 83, 44)',
|
||||
active: {
|
||||
borderColor: 'rgb(202, 117, 79)'
|
||||
}
|
||||
color: 'rgb(122, 83, 44)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,11 +16,7 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: 'rgb(173, 91, 12)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -28,18 +24,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(50, 113, 96)',
|
||||
borderColor: 'rgb(113, 195, 169)',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(173, 91, 12)'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(10, 59, 43)',
|
||||
active: {
|
||||
borderColor: 'rgb(173, 91, 12)'
|
||||
}
|
||||
color: 'rgb(10, 59, 43)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -47,9 +37,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(246, 238, 211)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
color: 'rgb(173, 91, 12)',
|
||||
active: {
|
||||
borderColor: 'rgb(113, 195, 169)'
|
||||
}
|
||||
color: 'rgb(173, 91, 12)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,10 +18,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(28, 178, 43)',
|
||||
color: '#fff',
|
||||
fontSize: 24,
|
||||
borderRadius: 10,
|
||||
active: {
|
||||
borderColor: 'rgb(17, 68, 23)'
|
||||
}
|
||||
borderRadius: 10
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,26 +26,17 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(147,148,149)',
|
||||
fontSize: 18,
|
||||
borderRadius: 10,
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(17, 68, 23)'
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(147, 148, 149)',
|
||||
active: {
|
||||
borderColor: 'rgb(17, 68, 23)'
|
||||
}
|
||||
color: 'rgb(147, 148, 149)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'transparent',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(17, 68, 23)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,11 +17,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(36, 179, 96)',
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(254, 199, 13)',
|
||||
borderWidth: 3
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,28 +25,18 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(0, 0, 0)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(36, 179, 96)',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: 'rgb(204, 204, 204)',
|
||||
active: {
|
||||
borderColor: 'rgb(254, 199, 13)'
|
||||
}
|
||||
color: 'rgb(204, 204, 204)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'transparent',
|
||||
borderColor: 'rgb(255, 119, 34)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(204, 204, 204)',
|
||||
active: {
|
||||
borderColor: 'rgb(254, 199, 13)'
|
||||
}
|
||||
color: 'rgb(204, 204, 204)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -70,12 +70,7 @@ export default {
|
||||
borderWidth: 0,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
textDecoration: 'none'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -93,12 +88,7 @@ export default {
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
textDecoration: 'none'
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
@@ -116,12 +106,7 @@ export default {
|
||||
borderWidth: 0,
|
||||
borderRadius: 5,
|
||||
borderDasharray: 'none',
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
textDecoration: 'none'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -139,12 +124,7 @@ export default {
|
||||
borderWidth: 1,
|
||||
borderDasharray: 'none',
|
||||
borderRadius: 5,
|
||||
textDecoration: 'none',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
textDecoration: 'none'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,14 +158,17 @@ const nodeSizeIndependenceList = [
|
||||
'backgroundImage',
|
||||
'backgroundRepeat',
|
||||
'backgroundPosition',
|
||||
'backgroundSize'
|
||||
'backgroundSize',
|
||||
'rootLineKeepSameInCurve'
|
||||
]
|
||||
export const checkIsNodeSizeIndependenceConfig = (config) => {
|
||||
export const checkIsNodeSizeIndependenceConfig = config => {
|
||||
let keys = Object.keys(config)
|
||||
for(let i = 0; i < keys.length; i++) {
|
||||
if (!nodeSizeIndependenceList.find((item) => {
|
||||
return item === keys[i]
|
||||
})) {
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (
|
||||
!nodeSizeIndependenceList.find(item => {
|
||||
return item === keys[i]
|
||||
})
|
||||
) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,10 +13,7 @@ export default merge(defaultTheme, {
|
||||
generalizationLineColor: '#333',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(191, 147, 115)',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 73, 57)'
|
||||
}
|
||||
fillColor: 'rgb(191, 147, 115)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -24,26 +21,17 @@ export default merge(defaultTheme, {
|
||||
color: '#333',
|
||||
borderColor: 'rgb(191, 147, 115)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(96, 73, 57)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 73, 57)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 73, 57)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -26,11 +26,6 @@ export default merge(defaultTheme, {
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(57, 80, 96)',
|
||||
borderWidth: 3,
|
||||
borderDasharray: 'none'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,10 +13,7 @@ export default merge(defaultTheme, {
|
||||
generalizationLineColor: '#333',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(191, 115, 115)',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 57)'
|
||||
}
|
||||
fillColor: 'rgb(191, 115, 115)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -24,26 +21,17 @@ export default merge(defaultTheme, {
|
||||
color: '#333',
|
||||
borderColor: 'rgb(191, 115, 115)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 57)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 57)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(96, 57, 57)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,11 +17,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(51, 56, 62)',
|
||||
color: 'rgb(247, 208, 160)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(247, 208, 160)',
|
||||
borderWidth: 3
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,27 +25,17 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(81, 58, 42)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(51, 56, 62)',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(0, 192, 184)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'rgb(127, 93, 64)',
|
||||
borderColor: 'transparent',
|
||||
color: 'rgb(255, 214, 175)',
|
||||
active: {
|
||||
borderColor: 'rgb(51, 56, 62)'
|
||||
}
|
||||
color: 'rgb(255, 214, 175)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,11 +17,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(25, 193, 73)',
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: '#222',
|
||||
borderWidth: 3
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,28 +25,18 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(69, 149, 96)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(25, 193, 73)',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(25, 193, 73)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'rgb(251, 158, 0)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(51, 51, 51)',
|
||||
active: {
|
||||
borderColor: 'rgb(25, 193, 73)'
|
||||
}
|
||||
color: 'rgb(51, 51, 51)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(255, 255, 255)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 119, 34)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,19 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(209, 210, 210)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 119, 34)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(204, 204, 204)',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 119, 34)'
|
||||
}
|
||||
color: 'rgb(204, 204, 204)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -50,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(255, 119, 34)',
|
||||
borderColor: '',
|
||||
borderWidth: 2,
|
||||
color: '#fff',
|
||||
active: {
|
||||
borderColor: 'rgb(23, 153, 243)'
|
||||
}
|
||||
color: '#fff'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,10 +16,7 @@ export default merge(defaultTheme, {
|
||||
root: {
|
||||
fillColor: 'rgb(55, 165, 255)',
|
||||
borderColor: 'rgb(51, 51, 51)',
|
||||
borderWidth: 3,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 160, 36)'
|
||||
}
|
||||
borderWidth: 3
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -27,26 +24,17 @@ export default merge(defaultTheme, {
|
||||
color: '#222',
|
||||
borderColor: 'rgb(51, 51, 51)',
|
||||
borderWidth: 3,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(55, 165, 255)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(55, 165, 255)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
borderColor: '#222',
|
||||
borderWidth: 3,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(55, 165, 255)'
|
||||
}
|
||||
color: '#222'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,11 +16,7 @@ export default merge(defaultTheme, {
|
||||
root: {
|
||||
fillColor: 'rgb(0, 192, 184)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 160, 36)',
|
||||
borderWidth: 3
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -28,26 +24,17 @@ export default merge(defaultTheme, {
|
||||
color: '#222',
|
||||
borderColor: 'rgb(184, 235, 233)',
|
||||
borderWidth: 2,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(0, 192, 184)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(0, 192, 184)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'rgb(90, 206, 241)',
|
||||
borderColor: 'transparent',
|
||||
color: '#fff',
|
||||
active: {
|
||||
borderColor: 'rgb(0, 192, 184)'
|
||||
}
|
||||
color: '#fff'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: '#110501',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#a9a4a9',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,18 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: '#a9a4a9',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#110501'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: '#a9a4a9',
|
||||
active: {
|
||||
borderColor: '#ff6811'
|
||||
}
|
||||
color: '#a9a4a9'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -49,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: '',
|
||||
borderColor: '#ff6811',
|
||||
borderWidth: 2,
|
||||
color: '#a9a4a9',
|
||||
active: {
|
||||
borderColor: '#110501'
|
||||
}
|
||||
color: '#a9a4a9'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,11 +16,7 @@ export default merge(defaultTheme, {
|
||||
root: {
|
||||
fillColor: 'rgb(139, 109, 225)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(243, 104, 138)',
|
||||
borderWidth: 2
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -28,28 +24,17 @@ export default merge(defaultTheme, {
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(139, 109, 225)',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(139, 109, 225)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'transparent',
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(139, 109, 225)',
|
||||
borderWidth: 2
|
||||
}
|
||||
color: '#222'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -18,11 +18,7 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(255, 233, 157)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 233, 157)',
|
||||
borderWidth: 3
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -30,18 +26,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(211, 58, 21)',
|
||||
borderColor: 'rgb(222, 101, 85)',
|
||||
borderWidth: 2,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 233, 157)'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(144, 71, 43)',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 233, 157)'
|
||||
}
|
||||
color: 'rgb(144, 71, 43)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -49,9 +39,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(255, 247, 211)',
|
||||
borderColor: 'rgb(255, 202, 162)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(187, 101, 69)',
|
||||
active: {
|
||||
borderColor: 'rgb(222, 101, 85)'
|
||||
}
|
||||
color: 'rgb(187, 101, 69)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -13,10 +13,7 @@ export default merge(defaultTheme, {
|
||||
generalizationLineColor: '#333',
|
||||
// 根节点样式
|
||||
root: {
|
||||
fillColor: 'rgb(123, 115, 191)',
|
||||
active: {
|
||||
borderColor: 'rgb(61, 57, 96)'
|
||||
}
|
||||
fillColor: 'rgb(123, 115, 191)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -24,26 +21,17 @@ export default merge(defaultTheme, {
|
||||
color: '#333',
|
||||
borderColor: 'rgb(123, 115, 191)',
|
||||
borderWidth: 1,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(61, 57, 96)'
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(61, 57, 96)'
|
||||
}
|
||||
color: '#333'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: '#333',
|
||||
color: '#333',
|
||||
active: {
|
||||
borderColor: 'rgb(61, 57, 96)'
|
||||
}
|
||||
color: '#333'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -16,10 +16,7 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(34, 34, 34)',
|
||||
borderColor: 'rgb(34, 34, 34)',
|
||||
borderWidth: 3,
|
||||
fontSize: 24,
|
||||
active: {
|
||||
borderColor: '#a13600'
|
||||
}
|
||||
fontSize: 24
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -27,18 +24,12 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(34, 34, 34)',
|
||||
borderColor: 'rgb(34, 34, 34)',
|
||||
borderWidth: 3,
|
||||
fontSize: 18,
|
||||
active: {
|
||||
borderColor: '#a13600'
|
||||
}
|
||||
fontSize: 18
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 14,
|
||||
color: 'rgb(34, 34, 34)',
|
||||
active: {
|
||||
borderColor: '#a13600'
|
||||
}
|
||||
color: 'rgb(34, 34, 34)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
@@ -46,9 +37,6 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'transparent',
|
||||
borderColor: 'rgb(34, 34, 34)',
|
||||
borderWidth: 2,
|
||||
color: 'rgb(34, 34, 34)',
|
||||
active: {
|
||||
borderColor: '#a13600'
|
||||
}
|
||||
color: 'rgb(34, 34, 34)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,11 +17,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
color: 'rgb(65, 89, 158)',
|
||||
active: {
|
||||
borderColor: 'rgb(251, 227, 188)',
|
||||
borderWidth: 3
|
||||
}
|
||||
color: 'rgb(65, 89, 158)'
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,27 +25,17 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(65, 89, 158)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: 'rgb(65, 89, 158)',
|
||||
active: {
|
||||
borderColor: 'rgb(251, 227, 188)'
|
||||
}
|
||||
color: 'rgb(65, 89, 158)'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: '#fff',
|
||||
borderColor: 'transparent',
|
||||
color: 'rgb(65, 89, 158)',
|
||||
active: {
|
||||
borderColor: 'rgb(251, 227, 188)'
|
||||
}
|
||||
color: 'rgb(65, 89, 158)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -17,11 +17,7 @@ export default merge(defaultTheme, {
|
||||
fillColor: 'rgb(255, 112, 52)',
|
||||
color: '#fff',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
active: {
|
||||
borderColor: 'rgb(51, 51, 51)',
|
||||
borderWidth: 3
|
||||
}
|
||||
borderWidth: 0
|
||||
},
|
||||
// 二级节点样式
|
||||
second: {
|
||||
@@ -29,27 +25,17 @@ export default merge(defaultTheme, {
|
||||
color: 'rgb(51, 51, 51)',
|
||||
borderColor: '',
|
||||
borderWidth: 0,
|
||||
fontSize: 14,
|
||||
active: {
|
||||
borderColor: 'rgb(255, 112, 52)',
|
||||
borderWidth: 2
|
||||
}
|
||||
fontSize: 14
|
||||
},
|
||||
// 三级及以下节点样式
|
||||
node: {
|
||||
fontSize: 12,
|
||||
color: '#222',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 112, 52)'
|
||||
}
|
||||
color: '#222'
|
||||
},
|
||||
// 概要节点样式
|
||||
generalization: {
|
||||
fillColor: 'rgb(255, 222, 69)',
|
||||
borderColor: 'transparent',
|
||||
color: 'rgb(51, 51, 51)',
|
||||
active: {
|
||||
borderColor: 'rgb(255, 112, 52)'
|
||||
}
|
||||
color: 'rgb(51, 51, 51)'
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
// LRU缓存类
|
||||
export default class CRU {
|
||||
constructor(max) {
|
||||
this.max = max || 1000
|
||||
this.size = 0
|
||||
this.pool = new Map()
|
||||
}
|
||||
export default class Lru {
|
||||
constructor(max) {
|
||||
this.max = max || 1000
|
||||
this.size = 0
|
||||
this.pool = new Map()
|
||||
}
|
||||
|
||||
add(key, value) {
|
||||
// 如果该key是否已经存在,则先删除
|
||||
this.delete(key)
|
||||
this.pool.set(key, value)
|
||||
this.size++
|
||||
// 如果数量超出最大值,则删除最早的
|
||||
if (this.size > this.max) {
|
||||
let keys = this.pool.keys()
|
||||
let last = keys.next()
|
||||
this.delete(last.value)
|
||||
}
|
||||
|
||||
add(key, value) {
|
||||
// 如果该key是否已经存在,则先删除
|
||||
this.delete(key)
|
||||
this.pool.set(key, value)
|
||||
this.size++
|
||||
// 如果数量超出最大值,则删除最早的
|
||||
if (this.size > this.max) {
|
||||
let keys = this.pool.keys()
|
||||
let last = keys.next()
|
||||
this.delete(last.value)
|
||||
}
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
if (this.pool.has(key)) {
|
||||
this.pool.delete(key)
|
||||
this.size--
|
||||
}
|
||||
delete(key) {
|
||||
if (this.pool.has(key)) {
|
||||
this.pool.delete(key)
|
||||
this.size--
|
||||
}
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this.pool.has(key)
|
||||
}
|
||||
has(key) {
|
||||
return this.pool.has(key)
|
||||
}
|
||||
|
||||
get(key) {
|
||||
if (this.pool.has(key)) {
|
||||
return this.pool.get(key)
|
||||
}
|
||||
get(key) {
|
||||
if (this.pool.has(key)) {
|
||||
return this.pool.get(key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { nodeDataNoStylePropList } from '../constants/constant'
|
||||
|
||||
// 深度优先遍历树
|
||||
export const walk = (
|
||||
@@ -632,3 +633,39 @@ export const isMobile = () => {
|
||||
navigator.userAgent
|
||||
)
|
||||
}
|
||||
|
||||
// 获取对象改变了的的属性
|
||||
export const getObjectChangedProps = (oldObject, newObject) => {
|
||||
const res = {}
|
||||
Object.keys(newObject).forEach(prop => {
|
||||
const oldVal = oldObject[prop]
|
||||
const newVal = newObject[prop]
|
||||
if (getType(oldVal) !== getType(newVal)) {
|
||||
res[prop] = newVal
|
||||
return
|
||||
}
|
||||
if (getType(oldVal) === 'Object') {
|
||||
if (JSON.stringify(oldVal) !== JSON.stringify(newVal)) {
|
||||
res[prop] = newVal
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (oldVal !== newVal) {
|
||||
res[prop] = newVal
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
return res
|
||||
}
|
||||
|
||||
// 判断一个字段是否是节点数据中的样式字段
|
||||
export const checkIsNodeStyleDataKey = key => {
|
||||
// 用户自定义字段
|
||||
if (/^_/.test(key)) return false
|
||||
// 不在节点非样式字段列表里,那么就是样式字段
|
||||
if (!nodeDataNoStylePropList.includes(key)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -351,4 +351,4 @@ const drawBackgroundImageToCanvas = (
|
||||
}
|
||||
}
|
||||
|
||||
export default drawBackgroundImageToCanvas
|
||||
export default drawBackgroundImageToCanvas
|
||||
|
||||
166
simple-mind-map/types/index.d.ts
vendored
Normal file
166
simple-mind-map/types/index.d.ts
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
export default MindMap
|
||||
declare class MindMap {
|
||||
/**
|
||||
*
|
||||
* @param {defaultOpt} opt
|
||||
*/
|
||||
constructor(opt?: {
|
||||
readonly: boolean
|
||||
layout: string
|
||||
fishboneDeg: number
|
||||
theme: string
|
||||
themeConfig: {}
|
||||
scaleRatio: number
|
||||
mouseScaleCenterUseMousePosition: boolean
|
||||
maxTag: number
|
||||
expandBtnSize: number
|
||||
imgTextMargin: number
|
||||
textContentMargin: number
|
||||
selectTranslateStep: number
|
||||
selectTranslateLimit: number
|
||||
customNoteContentShow: any
|
||||
enableFreeDrag: boolean
|
||||
watermarkConfig: {
|
||||
text: string
|
||||
lineSpacing: number
|
||||
textSpacing: number
|
||||
angle: number
|
||||
textStyle: {
|
||||
color: string
|
||||
opacity: number
|
||||
fontSize: number
|
||||
}
|
||||
}
|
||||
textAutoWrapWidth: number
|
||||
customHandleMousewheel: any
|
||||
mousewheelAction: string
|
||||
mousewheelMoveStep: number
|
||||
mousewheelZoomActionReverse: boolean
|
||||
defaultInsertSecondLevelNodeText: string
|
||||
defaultInsertBelowSecondLevelNodeText: string
|
||||
expandBtnStyle: {
|
||||
color: string
|
||||
fill: string
|
||||
fontSize: number
|
||||
strokeColor: string
|
||||
}
|
||||
expandBtnIcon: {
|
||||
open: string
|
||||
close: string
|
||||
}
|
||||
expandBtnNumHandler: (num: any) => any
|
||||
isShowExpandNum: boolean
|
||||
enableShortcutOnlyWhenMouseInSvg: boolean
|
||||
initRootNodePosition: any
|
||||
exportPaddingX: number
|
||||
exportPaddingY: number
|
||||
nodeTextEditZIndex: number
|
||||
nodeNoteTooltipZIndex: number
|
||||
isEndNodeTextEditOnClickOuter: boolean
|
||||
maxHistoryCount: number
|
||||
alwaysShowExpandBtn: boolean
|
||||
iconList: any[]
|
||||
maxNodeCacheCount: number
|
||||
defaultAssociativeLineText: string
|
||||
fitPadding: number
|
||||
enableCtrlKeyNodeSelection: boolean
|
||||
useLeftKeySelectionRightKeyDrag: boolean
|
||||
beforeTextEdit: any
|
||||
isUseCustomNodeContent: boolean
|
||||
customCreateNodeContent: any
|
||||
customInnerElsAppendTo: any
|
||||
nodeDragPlaceholderMaxSize: number
|
||||
enableAutoEnterTextEditWhenKeydown: boolean
|
||||
richTextEditFakeInPlace: boolean
|
||||
customHandleClipboardText: any
|
||||
disableMouseWheelZoom: boolean
|
||||
errorHandler: (code: any, error: any) => void
|
||||
resetCss: string
|
||||
enableDblclickReset: boolean
|
||||
minExportImgCanvasScale: number
|
||||
hoverRectColor: string
|
||||
hoverRectPadding: number
|
||||
selectTextOnEnterEditText: boolean
|
||||
deleteNodeActive: boolean
|
||||
autoMoveWhenMouseInEdgeOnDrag: boolean
|
||||
})
|
||||
opt: any
|
||||
el: any
|
||||
elRect: any
|
||||
width: any
|
||||
height: any
|
||||
cssEl: HTMLStyleElement
|
||||
svg: any
|
||||
draw: any
|
||||
event: Event
|
||||
keyCommand: KeyCommand
|
||||
command: Command
|
||||
renderer: Render
|
||||
view: View
|
||||
batchExecution: BatchExecution
|
||||
handleOpt(opt: any): any
|
||||
addCss(): void
|
||||
removeCss(): void
|
||||
render(callback: any, source?: string): void
|
||||
reRender(callback: any, source?: string): void
|
||||
resize(): void
|
||||
on(event: any, fn: any): void
|
||||
emit(event: any, ...args: any[]): void
|
||||
off(event: any, fn: any): void
|
||||
initCache(): void
|
||||
initTheme(): void
|
||||
themeConfig: any
|
||||
setTheme(theme: any): void
|
||||
getTheme(): any
|
||||
setThemeConfig(config: any): void
|
||||
getCustomThemeConfig(): any
|
||||
getThemeConfig(prop: any): any
|
||||
getConfig(prop: any): any
|
||||
updateConfig(opt?: {}): void
|
||||
getLayout(): any
|
||||
setLayout(layout: any): void
|
||||
execCommand(...args: any[]): void
|
||||
setData(data: any): void
|
||||
setFullData(data: any): void
|
||||
getData(withConfig: any): any
|
||||
export(...args: any[]): Promise<any>
|
||||
toPos(
|
||||
x: any,
|
||||
y: any
|
||||
): {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
setMode(mode: any): void
|
||||
getSvgData({
|
||||
paddingX,
|
||||
paddingY
|
||||
}?: {
|
||||
paddingX?: number
|
||||
paddingY?: number
|
||||
}): {
|
||||
svg: any
|
||||
svgHTML: any
|
||||
rect: any
|
||||
origWidth: any
|
||||
origHeight: any
|
||||
scaleX: any
|
||||
scaleY: any
|
||||
}
|
||||
addPlugin(plugin: any, opt: any): void
|
||||
removePlugin(plugin: any): void
|
||||
initPlugin(plugin: any): void
|
||||
destroy(): void
|
||||
}
|
||||
declare namespace MindMap {
|
||||
let pluginList: any[]
|
||||
function usePlugin(plugin: any, opt?: {}): typeof MindMap
|
||||
function hasPlugin(plugin: any): number
|
||||
function defineTheme(name: any, config?: {}): Error
|
||||
}
|
||||
import Event from './src/core/event/Event'
|
||||
import KeyCommand from './src/core/command/KeyCommand'
|
||||
import Command from './src/core/command/Command'
|
||||
import Render from './src/core/render/Render'
|
||||
import View from './src/core/view/View'
|
||||
import BatchExecution from './src/utils/BatchExecution'
|
||||
113
simple-mind-map/types/src/constants/constant.d.ts
vendored
Normal file
113
simple-mind-map/types/src/constants/constant.d.ts
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
export const tagColorList: {
|
||||
color: string
|
||||
background: string
|
||||
}[]
|
||||
export const themeList: {
|
||||
name: string
|
||||
value: string
|
||||
dark: boolean
|
||||
}[]
|
||||
export namespace CONSTANTS {
|
||||
let CHANGE_THEME: string
|
||||
let CHANGE_LAYOUT: string
|
||||
let SET_DATA: string
|
||||
let TRANSFORM_TO_NORMAL_NODE: string
|
||||
namespace MODE {
|
||||
let READONLY: string
|
||||
let EDIT: string
|
||||
}
|
||||
namespace LAYOUT {
|
||||
let LOGICAL_STRUCTURE: string
|
||||
let MIND_MAP: string
|
||||
let ORGANIZATION_STRUCTURE: string
|
||||
let CATALOG_ORGANIZATION: string
|
||||
let TIMELINE: string
|
||||
let TIMELINE2: string
|
||||
let FISHBONE: string
|
||||
let VERTICAL_TIMELINE: string
|
||||
}
|
||||
namespace DIR {
|
||||
let UP: string
|
||||
let LEFT: string
|
||||
let DOWN: string
|
||||
let RIGHT: string
|
||||
}
|
||||
namespace KEY_DIR {
|
||||
let LEFT_1: string
|
||||
export { LEFT_1 as LEFT }
|
||||
let UP_1: string
|
||||
export { UP_1 as UP }
|
||||
let RIGHT_1: string
|
||||
export { RIGHT_1 as RIGHT }
|
||||
let DOWN_1: string
|
||||
export { DOWN_1 as DOWN }
|
||||
}
|
||||
namespace SHAPE {
|
||||
let RECTANGLE: string
|
||||
let DIAMOND: string
|
||||
let PARALLELOGRAM: string
|
||||
let ROUNDED_RECTANGLE: string
|
||||
let OCTAGONAL_RECTANGLE: string
|
||||
let OUTER_TRIANGULAR_RECTANGLE: string
|
||||
let INNER_TRIANGULAR_RECTANGLE: string
|
||||
let ELLIPSE: string
|
||||
let CIRCLE: string
|
||||
}
|
||||
namespace MOUSE_WHEEL_ACTION {
|
||||
let ZOOM: string
|
||||
let MOVE: string
|
||||
}
|
||||
namespace INIT_ROOT_NODE_POSITION {
|
||||
let LEFT_2: string
|
||||
export { LEFT_2 as LEFT }
|
||||
export let TOP: string
|
||||
let RIGHT_2: string
|
||||
export { RIGHT_2 as RIGHT }
|
||||
export let BOTTOM: string
|
||||
export let CENTER: string
|
||||
}
|
||||
namespace LAYOUT_GROW_DIR {
|
||||
let LEFT_3: string
|
||||
export { LEFT_3 as LEFT }
|
||||
let TOP_1: string
|
||||
export { TOP_1 as TOP }
|
||||
let RIGHT_3: string
|
||||
export { RIGHT_3 as RIGHT }
|
||||
let BOTTOM_1: string
|
||||
export { BOTTOM_1 as BOTTOM }
|
||||
}
|
||||
namespace PASTE_TYPE {
|
||||
let CLIP_BOARD: string
|
||||
let CANVAS: string
|
||||
}
|
||||
namespace SCROLL_BAR_DIR {
|
||||
let VERTICAL: string
|
||||
let HORIZONTAL: string
|
||||
}
|
||||
}
|
||||
export const initRootNodePositionMap: {
|
||||
[x: string]: number
|
||||
}
|
||||
export const layoutList: {
|
||||
name: string
|
||||
value: string
|
||||
}[]
|
||||
export const layoutValueList: string[]
|
||||
export const nodeDataNoStylePropList: string[]
|
||||
export namespace commonCaches {
|
||||
let measureCustomNodeContentSizeEl: any
|
||||
let measureRichtextNodeTextSizeEl: any
|
||||
}
|
||||
export namespace ERROR_TYPES {
|
||||
let READ_CLIPBOARD_ERROR: string
|
||||
let PARSE_PASTE_DATA_ERROR: string
|
||||
let CUSTOM_HANDLE_CLIPBOARD_TEXT_ERROR: string
|
||||
let LOAD_CLIPBOARD_IMAGE_ERROR: string
|
||||
let BEFORE_TEXT_EDIT_ERROR: string
|
||||
let EXPORT_ERROR: string
|
||||
}
|
||||
export namespace a4Size {
|
||||
let width: number
|
||||
let height: number
|
||||
}
|
||||
export const cssContent: '\n /* 鼠标hover和激活时渲染的矩形 */\n .smm-hover-node{\n display: none;\n opacity: 0.6;\n stroke-width: 1;\n }\n\n .smm-node:hover .smm-hover-node{\n display: block;\n }\n\n .smm-node.active .smm-hover-node{\n display: block;\n opacity: 1;\n stroke-width: 2;\n }\n'
|
||||
82
simple-mind-map/types/src/constants/defaultOptions.d.ts
vendored
Normal file
82
simple-mind-map/types/src/constants/defaultOptions.d.ts
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
export namespace defaultOpt {
|
||||
let readonly: boolean
|
||||
let layout: string
|
||||
let fishboneDeg: number
|
||||
let theme: string
|
||||
let themeConfig: {}
|
||||
let scaleRatio: number
|
||||
let mouseScaleCenterUseMousePosition: boolean
|
||||
let maxTag: number
|
||||
let expandBtnSize: number
|
||||
let imgTextMargin: number
|
||||
let textContentMargin: number
|
||||
let selectTranslateStep: number
|
||||
let selectTranslateLimit: number
|
||||
let customNoteContentShow: any
|
||||
let enableFreeDrag: boolean
|
||||
namespace watermarkConfig {
|
||||
let text: string
|
||||
let lineSpacing: number
|
||||
let textSpacing: number
|
||||
let angle: number
|
||||
namespace textStyle {
|
||||
let color: string
|
||||
let opacity: number
|
||||
let fontSize: number
|
||||
}
|
||||
}
|
||||
let textAutoWrapWidth: number
|
||||
let customHandleMousewheel: any
|
||||
let mousewheelAction: string
|
||||
let mousewheelMoveStep: number
|
||||
let mousewheelZoomActionReverse: boolean
|
||||
let defaultInsertSecondLevelNodeText: string
|
||||
let defaultInsertBelowSecondLevelNodeText: string
|
||||
namespace expandBtnStyle {
|
||||
let color_1: string
|
||||
export { color_1 as color }
|
||||
export let fill: string
|
||||
let fontSize_1: number
|
||||
export { fontSize_1 as fontSize }
|
||||
export let strokeColor: string
|
||||
}
|
||||
namespace expandBtnIcon {
|
||||
let open: string
|
||||
let close: string
|
||||
}
|
||||
function expandBtnNumHandler(num: any): any
|
||||
let isShowExpandNum: boolean
|
||||
let enableShortcutOnlyWhenMouseInSvg: boolean
|
||||
let initRootNodePosition: any
|
||||
let exportPaddingX: number
|
||||
let exportPaddingY: number
|
||||
let nodeTextEditZIndex: number
|
||||
let nodeNoteTooltipZIndex: number
|
||||
let isEndNodeTextEditOnClickOuter: boolean
|
||||
let maxHistoryCount: number
|
||||
let alwaysShowExpandBtn: boolean
|
||||
let iconList: any[]
|
||||
let maxNodeCacheCount: number
|
||||
let defaultAssociativeLineText: string
|
||||
let fitPadding: number
|
||||
let enableCtrlKeyNodeSelection: boolean
|
||||
let useLeftKeySelectionRightKeyDrag: boolean
|
||||
let beforeTextEdit: any
|
||||
let isUseCustomNodeContent: boolean
|
||||
let customCreateNodeContent: any
|
||||
let customInnerElsAppendTo: any
|
||||
let nodeDragPlaceholderMaxSize: number
|
||||
let enableAutoEnterTextEditWhenKeydown: boolean
|
||||
let richTextEditFakeInPlace: boolean
|
||||
let customHandleClipboardText: any
|
||||
let disableMouseWheelZoom: boolean
|
||||
function errorHandler(code: any, error: any): void
|
||||
let resetCss: string
|
||||
let enableDblclickReset: boolean
|
||||
let minExportImgCanvasScale: number
|
||||
let hoverRectColor: string
|
||||
let hoverRectPadding: number
|
||||
let selectTextOnEnterEditText: boolean
|
||||
let deleteNodeActive: boolean
|
||||
let autoMoveWhenMouseInEdgeOnDrag: boolean
|
||||
}
|
||||
19
simple-mind-map/types/src/core/command/Command.d.ts
vendored
Normal file
19
simple-mind-map/types/src/core/command/Command.d.ts
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
export default Command
|
||||
declare class Command {
|
||||
constructor(opt?: {})
|
||||
opt: {}
|
||||
mindMap: any
|
||||
commands: {}
|
||||
history: any[]
|
||||
activeHistoryIndex: number
|
||||
addHistory(): void
|
||||
clearHistory(): void
|
||||
registerShortcutKeys(): void
|
||||
exec(name: any, ...args: any[]): void
|
||||
add(name: any, fn: any): void
|
||||
remove(name: any, fn: any): void
|
||||
back(step?: number): any
|
||||
forward(step?: number): any
|
||||
getCopyData(): any
|
||||
removeDataUid(data: any): any
|
||||
}
|
||||
26
simple-mind-map/types/src/core/command/KeyCommand.d.ts
vendored
Normal file
26
simple-mind-map/types/src/core/command/KeyCommand.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
export default class KeyCommand {
|
||||
constructor(opt: any)
|
||||
opt: any
|
||||
mindMap: any
|
||||
shortcutMap: {}
|
||||
shortcutMapCache: {}
|
||||
isPause: boolean
|
||||
isInSvg: boolean
|
||||
pause(): void
|
||||
recovery(): void
|
||||
save(): void
|
||||
restore(): void
|
||||
bindEvent(): void
|
||||
checkKey(e: any, key: any): boolean
|
||||
getOriginEventCodeArr(e: any): any[]
|
||||
hasCombinationKey(e: any): any
|
||||
getKeyCodeArr(key: any): any[]
|
||||
/**
|
||||
* Enter
|
||||
* Tab | Insert
|
||||
* Shift + a
|
||||
*/
|
||||
addShortcut(key: any, fn: any): void
|
||||
removeShortcut(key: any, fn: any): void
|
||||
getShortcutFn(key: any): any[]
|
||||
}
|
||||
42
simple-mind-map/types/src/core/command/keyMap.d.ts
vendored
Normal file
42
simple-mind-map/types/src/core/command/keyMap.d.ts
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
export const keyMap: {
|
||||
Backspace: number
|
||||
Tab: number
|
||||
Enter: number
|
||||
Shift: number
|
||||
Control: number
|
||||
Alt: number
|
||||
CapsLock: number
|
||||
Esc: number
|
||||
Spacebar: number
|
||||
PageUp: number
|
||||
PageDown: number
|
||||
End: number
|
||||
Home: number
|
||||
Insert: number
|
||||
Left: number
|
||||
Up: number
|
||||
Right: number
|
||||
Down: number
|
||||
Del: number
|
||||
NumLock: number
|
||||
Cmd: number
|
||||
CmdFF: number
|
||||
F1: number
|
||||
F2: number
|
||||
F3: number
|
||||
F4: number
|
||||
F5: number
|
||||
F6: number
|
||||
F7: number
|
||||
F8: number
|
||||
F9: number
|
||||
F10: number
|
||||
F11: number
|
||||
F12: number
|
||||
'`': number
|
||||
'=': number
|
||||
'-': number
|
||||
'/': number
|
||||
'.': number
|
||||
}
|
||||
export function isKey(e: any, key: any): boolean
|
||||
35
simple-mind-map/types/src/core/event/Event.d.ts
vendored
Normal file
35
simple-mind-map/types/src/core/event/Event.d.ts
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
export default Event
|
||||
declare class Event {
|
||||
constructor(opt?: {})
|
||||
opt: {}
|
||||
mindMap: any
|
||||
isLeftMousedown: boolean
|
||||
isRightMousedown: boolean
|
||||
isMiddleMousedown: boolean
|
||||
mousedownPos: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
mousemovePos: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
mousemoveOffset: {
|
||||
x: number
|
||||
y: number
|
||||
}
|
||||
bindFn(): void
|
||||
onBodyClick(e: any): void
|
||||
onDrawClick(e: any): void
|
||||
onMousedown(e: any): void
|
||||
onMousemove(e: any): void
|
||||
onMouseup(e: any): void
|
||||
onMousewheel(e: any): void
|
||||
onContextmenu(e: any): void
|
||||
onSvgMousedown(e: any): void
|
||||
onKeyup(e: any): void
|
||||
onMouseenter(e: any): void
|
||||
onMouseleave(e: any): void
|
||||
bind(): void
|
||||
unbind(): void
|
||||
}
|
||||
107
simple-mind-map/types/src/core/render/Render.d.ts
vendored
Normal file
107
simple-mind-map/types/src/core/render/Render.d.ts
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
export default Render
|
||||
declare class Render {
|
||||
constructor(opt?: {})
|
||||
opt: {}
|
||||
mindMap: any
|
||||
themeConfig: any
|
||||
draw: any
|
||||
renderTree: any
|
||||
reRender: boolean
|
||||
isRendering: boolean
|
||||
hasWaitRendering: boolean
|
||||
nodeCache: {}
|
||||
lastNodeCache: {}
|
||||
renderSource: string
|
||||
activeNodeList: any[]
|
||||
root: any
|
||||
textEdit: TextEdit
|
||||
lastBeingCopyData: any
|
||||
beingCopyData: any
|
||||
beingPasteText: string
|
||||
beingPasteImgSize: number
|
||||
currentBeingPasteType: string
|
||||
setLayout(): void
|
||||
layout:
|
||||
| MindMap
|
||||
| CatalogOrganization
|
||||
| OrganizationStructure
|
||||
| Timeline
|
||||
| VerticalTimeline
|
||||
bindEvent(): void
|
||||
registerCommands(): void
|
||||
selectAll(): void
|
||||
back(step: any): void
|
||||
forward(step: any): void
|
||||
insertNode(
|
||||
openEdit?: boolean,
|
||||
appointNodes?: any[],
|
||||
appointData?: any,
|
||||
appointChildren?: any[]
|
||||
): void
|
||||
insertChildNode(
|
||||
openEdit?: boolean,
|
||||
appointNodes?: any[],
|
||||
appointData?: any,
|
||||
appointChildren?: any[]
|
||||
): void
|
||||
upNode(): void
|
||||
downNode(): void
|
||||
insertAfter(node: any, exist: any): void
|
||||
insertBefore(node: any, exist: any): void
|
||||
moveNodeTo(node: any, toNode: any): void
|
||||
removeNode(appointNodes?: any[]): void
|
||||
pasteNode(data: any): void
|
||||
cutNode(callback: any): any
|
||||
setNodeStyle(node: any, prop: any, value: any): void
|
||||
setNodeStyles(node: any, style: any): void
|
||||
setNodeActive(node: any, active: any): void
|
||||
clearAllActive(): void
|
||||
setNodeExpand(node: any, expand: any): void
|
||||
expandAllNode(): void
|
||||
unexpandAllNode(): void
|
||||
expandToLevel(level: any): void
|
||||
setNodeData(node: any, data: any): void
|
||||
setNodeText(node: any, text: any, richText: any, resetRichText: any): void
|
||||
setNodeImage(node: any, data: any): void
|
||||
setNodeIcon(node: any, icons: any): void
|
||||
setNodeHyperlink(node: any, link: any, title?: string): void
|
||||
setNodeNote(node: any, note: any): void
|
||||
setNodeTag(node: any, tag: any): void
|
||||
addGeneralization(data: any): void
|
||||
removeGeneralization(): void
|
||||
setNodeCustomPosition(node: any, left?: any, top?: any): void
|
||||
resetLayout(): void
|
||||
setNodeShape(node: any, shape: any): void
|
||||
goTargetNode(node: any, callback?: () => void): void
|
||||
registerShortcutKeys(): void
|
||||
insertNodeWrap: () => void
|
||||
toggleActiveExpand(): void
|
||||
removeNodeWrap: () => void
|
||||
copy(): void
|
||||
cut(): void
|
||||
startTextEdit(): void
|
||||
endTextEdit(): void
|
||||
render(callback: () => void, source: any): void
|
||||
clearActive(): void
|
||||
addActiveNode(node: any): void
|
||||
removeActiveNode(node: any): void
|
||||
findActiveNodeIndex(node: any): number
|
||||
getNodeIndex(node: any): any
|
||||
formatAppointNodes(appointNodes: any): any[]
|
||||
setCoptyDataToClipboard(data: any): void
|
||||
paste(): void
|
||||
onPaste(): Promise<void>
|
||||
removeOneNode(node: any): void
|
||||
copyNode(): any
|
||||
toggleNodeExpand(node: any): void
|
||||
setNodeDataRender(node: any, data: any, notRender?: boolean): void
|
||||
moveNodeToCenter(node: any): void
|
||||
expandToNodeUid(uid: any, callback?: () => void): void
|
||||
findNodeByUid(uid: any): any
|
||||
}
|
||||
import TextEdit from './TextEdit'
|
||||
import MindMap from '../../layouts/MindMap'
|
||||
import CatalogOrganization from '../../layouts/CatalogOrganization'
|
||||
import OrganizationStructure from '../../layouts/OrganizationStructure'
|
||||
import Timeline from '../../layouts/Timeline'
|
||||
import VerticalTimeline from '../../layouts/VerticalTimeline'
|
||||
29
simple-mind-map/types/src/core/render/TextEdit.d.ts
vendored
Normal file
29
simple-mind-map/types/src/core/render/TextEdit.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
export default class TextEdit {
|
||||
constructor(renderer: any)
|
||||
renderer: any
|
||||
mindMap: any
|
||||
currentNode: any
|
||||
textEditNode: HTMLDivElement
|
||||
showTextEdit: boolean
|
||||
cacheEditingText: string
|
||||
bindEvent(): void
|
||||
show(
|
||||
node: any,
|
||||
e: any,
|
||||
isInserting?: boolean,
|
||||
isFromKeyDown?: boolean
|
||||
): Promise<void>
|
||||
onScale(): void
|
||||
checkIsAutoEnterTextEditKey(e: any): boolean
|
||||
registerTmpShortcut(): void
|
||||
showEditTextBox(
|
||||
node: any,
|
||||
rect: any,
|
||||
isInserting: any,
|
||||
isFromKeyDown: any
|
||||
): void
|
||||
focus(): void
|
||||
selectNodeText(): void
|
||||
getEditText(): any
|
||||
hideEditTextBox(): any
|
||||
}
|
||||
116
simple-mind-map/types/src/core/render/node/Node.d.ts
vendored
Normal file
116
simple-mind-map/types/src/core/render/node/Node.d.ts
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
export default Node
|
||||
declare class Node {
|
||||
constructor(opt?: {})
|
||||
nodeData: any
|
||||
uid: any
|
||||
mindMap: any
|
||||
renderer: any
|
||||
draw: any
|
||||
style: Style
|
||||
shapeInstance: Shape
|
||||
shapePadding: {
|
||||
paddingX: number
|
||||
paddingY: number
|
||||
}
|
||||
isRoot: any
|
||||
isGeneralization: any
|
||||
generalizationBelongNode: any
|
||||
layerIndex: any
|
||||
width: any
|
||||
height: any
|
||||
_left: any
|
||||
_top: any
|
||||
customLeft: any
|
||||
customTop: any
|
||||
isDrag: boolean
|
||||
parent: any
|
||||
children: any
|
||||
group: any
|
||||
shapeNode: any
|
||||
hoverNode: any
|
||||
_customNodeContent: any
|
||||
_imgData: any
|
||||
_iconData: any
|
||||
_textData: any
|
||||
_hyperlinkData: any
|
||||
_tagData: any
|
||||
_noteData: any
|
||||
noteEl: any
|
||||
_expandBtn: any
|
||||
_lastExpandBtnType: any
|
||||
_showExpandBtn: boolean
|
||||
_openExpandNode: any
|
||||
_closeExpandNode: any
|
||||
_fillExpandNode: any
|
||||
_lines: any[]
|
||||
_generalizationLine: any
|
||||
_generalizationNode: any
|
||||
_unVisibleRectRegionNode: any
|
||||
_isMouseenter: boolean
|
||||
_rectInfo: {
|
||||
imgContentWidth: number
|
||||
imgContentHeight: number
|
||||
textContentWidth: number
|
||||
textContentHeight: number
|
||||
}
|
||||
_generalizationNodeWidth: number
|
||||
_generalizationNodeHeight: number
|
||||
textContentItemMargin: any
|
||||
blockContentMargin: any
|
||||
expandBtnSize: any
|
||||
isMultipleChoice: boolean
|
||||
needLayout: boolean
|
||||
isHide: boolean
|
||||
set left(arg: any)
|
||||
get left(): any
|
||||
set top(arg: any)
|
||||
get top(): any
|
||||
reset(): void
|
||||
handleData(data: any): any
|
||||
createNodeData(): void
|
||||
getSize(): boolean
|
||||
getNodeRect(): {
|
||||
width: any
|
||||
height: any
|
||||
}
|
||||
layout(): void
|
||||
bindGroupEvent(): void
|
||||
active(e: any): void
|
||||
update(): void
|
||||
getNodePosInClient(
|
||||
_left: any,
|
||||
_top: any
|
||||
): {
|
||||
left: any
|
||||
top: any
|
||||
}
|
||||
reRender(): boolean
|
||||
updateNodeActive(): void
|
||||
render(callback?: () => void): void
|
||||
remove(): void
|
||||
destroy(): void
|
||||
hide(): void
|
||||
show(): void
|
||||
renderLine(deep?: boolean): void
|
||||
getShape(): any
|
||||
hasCustomPosition(): boolean
|
||||
ancestorHasCustomPosition(): boolean
|
||||
addChildren(node: any): void
|
||||
styleLine(line: any, node: any): void
|
||||
removeLine(): void
|
||||
isParent(node: any): boolean
|
||||
isBrother(node: any): any
|
||||
getPaddingVale(): {
|
||||
paddingX: any
|
||||
paddingY: any
|
||||
}
|
||||
getStyle(prop: any, root: any): any
|
||||
getSelfStyle(prop: any): any
|
||||
getParentSelfStyle(prop: any): any
|
||||
getSelfInhertStyle(prop: any): any
|
||||
getBorderWidth(): any
|
||||
getData(key: any): any
|
||||
hasCustomStyle(): boolean
|
||||
}
|
||||
import Style from './Style'
|
||||
import Shape from './Shape'
|
||||
28
simple-mind-map/types/src/core/render/node/Shape.d.ts
vendored
Normal file
28
simple-mind-map/types/src/core/render/node/Shape.d.ts
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
export default class Shape {
|
||||
constructor(node: any)
|
||||
node: any
|
||||
getShapePadding(
|
||||
width: any,
|
||||
height: any,
|
||||
paddingX: any,
|
||||
paddingY: any
|
||||
): {
|
||||
paddingX: number
|
||||
paddingY: number
|
||||
}
|
||||
createShape(): any
|
||||
getNodeSize(): {
|
||||
width: any
|
||||
height: any
|
||||
}
|
||||
createRect(): any
|
||||
createDiamond(): any
|
||||
createParallelogram(): any
|
||||
createRoundedRectangle(): any
|
||||
createOctagonalRectangle(): any
|
||||
createOuterTriangularRectangle(): any
|
||||
createInnerTriangularRectangle(): any
|
||||
createEllipse(): any
|
||||
createCircle(): any
|
||||
}
|
||||
export const shapeList: string[]
|
||||
43
simple-mind-map/types/src/core/render/node/Style.d.ts
vendored
Normal file
43
simple-mind-map/types/src/core/render/node/Style.d.ts
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
export default Style
|
||||
declare class Style {
|
||||
static setBackgroundStyle(el: any, themeConfig: any): void
|
||||
static removeBackgroundStyle(el: any): void
|
||||
constructor(ctx: any)
|
||||
ctx: any
|
||||
merge(prop: any, root: any): any
|
||||
getStyle(prop: any, root: any): any
|
||||
getSelfStyle(prop: any): any
|
||||
rect(node: any): void
|
||||
shape(node: any): void
|
||||
text(node: any): void
|
||||
createStyleText(): string
|
||||
getTextFontStyle(): {
|
||||
italic: boolean
|
||||
bold: any
|
||||
fontSize: any
|
||||
fontFamily: any
|
||||
}
|
||||
domText(node: any, fontSizeScale: number, isMultiLine: any): void
|
||||
tagText(node: any, index: any): void
|
||||
tagRect(node: any, index: any): void
|
||||
iconNode(node: any): void
|
||||
line(
|
||||
node: any,
|
||||
{
|
||||
width,
|
||||
color,
|
||||
dasharray
|
||||
}?: {
|
||||
width: any
|
||||
color: any
|
||||
dasharray: any
|
||||
}
|
||||
): void
|
||||
generalizationLine(node: any): void
|
||||
iconBtn(node: any, node2: any, fillNode: any): void
|
||||
hasCustomStyle(): boolean
|
||||
hoverNode(node: any): void
|
||||
}
|
||||
declare namespace Style {
|
||||
let cacheStyle: any
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user