Compare commits

..

23 Commits

Author SHA1 Message Date
街角小林
eff4cd0e77 打包0.11.2 2024-09-25 10:52:21 +08:00
街角小林
82c2d848a9 Feat:增加是否阻止mousedown事件默认事件的实例化选项 2024-09-25 10:31:39 +08:00
街角小林
0344599411 Fix:优化公式插件,适配创建多个实例的情况 2024-09-24 18:21:48 +08:00
街角小林
19fa0af6c0 Fix:修复创建多个思维导图实例时调用addPlugin添加同一个插件只有第一个实例会生效的问题 2024-09-24 17:55:52 +08:00
街角小林
bca1a073f7 Fix:修复创建多个思维导图实例时公式插件会多次扩展Quill的问题 2024-09-24 17:25:06 +08:00
街角小林
98fb23bf7c Feat:主题支持配置各个层级节点的内边距 2024-09-23 17:48:11 +08:00
街角小林
1c9c399b76 Feat:主题新增节点高亮框的圆角配置 2024-09-23 17:19:47 +08:00
wanglin2
bc43fedd87 Feat:新增自定义判断wheel事件是否来自触控板的实例化选项;优化代码 2024-09-21 19:54:43 +08:00
街角小林
156054ed93 Merge pull request #886 from Tarrency/feature-to-the-feature
feat: 配置平移步长和扩缩最值,解决触控板灵敏度问题
2024-09-21 15:24:58 +08:00
wangqi01
937f7d2969 fix: 限值平移步长比例生效只在鼠标/触控板滚动行为内 2024-09-20 18:03:18 +08:00
街角小林
e56a6d36cb Demo:优化节点图片添加了无法访问的图片的展示样式 2024-09-20 17:33:16 +08:00
街角小林
9f19061010 Fix:修复节点富文本编辑能粘贴图片的问题 2024-09-20 16:58:06 +08:00
街角小林
0d465f28f3 Feat:注释掉非https情况下的粘贴逻辑 2024-09-20 16:37:07 +08:00
街角小林
b4fdcd81b0 Fix:修复自定义主题节点渐变色方向无效的问题 2024-09-20 09:32:12 +08:00
Tarrency
38c0fe2e39 feat: 配置平移步长和扩缩最值,解决触控板灵敏度问题 2024-09-19 20:35:46 +08:00
街角小林
29ddbba9b9 Demo:新增一键展开某个节点所有下级节点的右键菜单 2024-09-19 19:52:34 +08:00
街角小林
9f9ed1e84f Fix:修复思维导图非常大的情况下导出图片失败的问题 2024-09-19 19:36:10 +08:00
街角小林
9ebc416167 Demo:修复右键菜单中的二级菜单会超出边界的问题 2024-09-19 18:19:57 +08:00
街角小林
5d49d985c0 优化代码 2024-09-19 18:14:52 +08:00
街角小林
c36338a794 Merge pull request #876 from BlackEyeBear/main
处理非https下navigator.clipboard方法无法获取,导致无法复制黏贴外部文本
2024-09-19 18:05:36 +08:00
wanglin2
c21ee4960e Fix:修复存在概要时切换主题会报错的问题 2024-09-18 21:52:11 +08:00
BlackEyeBear
5090f21b0e 处理非https下navigator.clipboard方法无法获取,导致无法复制黏贴外部文本 2024-09-16 22:08:55 +08:00
panda
3d9d172fa0 '处理非https下navigator.clipboard方法无法获取,导致无法复制黏贴外部文本' 2024-09-16 21:32:52 +08:00
60 changed files with 314 additions and 149 deletions

View File

@@ -469,4 +469,12 @@ const mindMap = new MindMap({
<img src="./web/src/assets/avatar/default.png" style="width: 50px;height: 50px;" />
<span>晏江</span>
</span>
<span>
<img src="./web/src/assets/avatar/default.png" style="width: 50px;height: 50px;" />
<span>Eric</span>
</span>
<span>
<img src="./web/src/assets/avatar/Joe.jpg" style="width: 50px;height: 50px;" />
<span>Joe</span>
</span>
</p>

File diff suppressed because one or more lines are too long

2
dist/js/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -9,7 +9,7 @@
})
} catch (error) {
console.log(error)
}</script><link href="dist/css/chunk-vendors.css?b396be756fa41f2b3cf9" rel="stylesheet"><link href="dist/css/app.css?b396be756fa41f2b3cf9" 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 = () => {
}</script><link href="dist/css/chunk-vendors.css?9c8ee1f3de5ddc8a450e" rel="stylesheet"><link href="dist/css/app.css?9c8ee1f3de5ddc8a450e" 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({
@@ -74,4 +74,4 @@
// 可以通过window.$bus.$on()来监听应用的一些事件
// 实例化页面
window.initApp()
}</script><script src="dist/js/chunk-vendors.js?b396be756fa41f2b3cf9"></script><script src="dist/js/app.js?b396be756fa41f2b3cf9"></script></body></html>
}</script><script src="dist/js/chunk-vendors.js?9c8ee1f3de5ddc8a450e"></script><script src="dist/js/app.js?9c8ee1f3de5ddc8a450e"></script></body></html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -31,7 +31,7 @@ MindMap.iconList = icons.nodeIconList
MindMap.constants = constants
MindMap.themes = themes
MindMap.defaultTheme = defaultTheme
MindMap.version = '0.11.1'
MindMap.version = '0.11.2'
MindMap.usePlugin(MiniMap)
.usePlugin(Watermark)

View File

@@ -19,7 +19,8 @@ import {
getObjectChangedProps,
isUndef,
handleGetSvgDataExtraContent,
getNodeTreeBoundingRect
getNodeTreeBoundingRect,
mergeTheme
} from './src/utils'
import defaultTheme, {
checkIsNodeSizeIndependenceConfig
@@ -34,6 +35,7 @@ class MindMap {
* @param {defaultOpt} opt
*/
constructor(opt = {}) {
MindMap.instanceCount++
// 合并选项
this.opt = this.handleOpt(merge(defaultOpt, opt))
// 预处理节点数据
@@ -252,7 +254,7 @@ class MindMap {
// 设置主题
initTheme() {
// 合并主题配置
this.themeConfig = merge(theme[this.opt.theme], this.opt.themeConfig)
this.themeConfig = mergeTheme(theme[this.opt.theme], this.opt.themeConfig)
// 设置背景样式
Style.setBackgroundStyle(this.el, this.themeConfig)
}
@@ -563,8 +565,8 @@ class MindMap {
let index = MindMap.hasPlugin(plugin)
if (index === -1) {
MindMap.usePlugin(plugin, opt)
this.initPlugin(plugin)
}
this.initPlugin(plugin)
}
// 移除插件
@@ -583,6 +585,7 @@ class MindMap {
// 实例化插件
initPlugin(plugin) {
if (this[plugin.instanceName]) return
this[plugin.instanceName] = new plugin({
mindMap: this,
pluginOpt: plugin.pluginOpt
@@ -616,6 +619,7 @@ class MindMap {
this.el.innerHTML = ''
this.el = null
this.removeCss()
MindMap.instanceCount--
}
}
@@ -632,13 +636,14 @@ MindMap.hasPlugin = plugin => {
return item === plugin
})
}
MindMap.instanceCount = 0
// 定义新主题
MindMap.defineTheme = (name, config = {}) => {
if (theme[name]) {
return new Error('该主题名称已存在')
}
theme[name] = merge(defaultTheme, config)
theme[name] = mergeTheme(defaultTheme, config)
}
export default MindMap

View File

@@ -1,6 +1,6 @@
{
"name": "simple-mind-map",
"version": "0.11.1",
"version": "0.11.2",
"description": "一个简单的web在线思维导图",
"authors": [
{

View File

@@ -19,6 +19,16 @@ export const defaultOpt = {
themeConfig: {},
// 放大缩小的增量比例
scaleRatio: 0.2,
// 平移的步长比例,只在鼠标滚轮和触控板触发的平移中应用
translateRatio: 1,
// 最小缩小值百分数最小为0该选项只会影响view.narrow方法影响的行为为Ctrl+-快捷键、鼠标滚轮及触控板不会影响其他方法比如view.setScale所以需要你自行限制大小
minZoomRatio: 20,
// 最大放大值,百分数,传-1代表不限制否则传0以上数字该选项只会影响view.enlarge方法
maxZoomRatio: 400,
// 自定义判断wheel事件是否来自电脑的触控板
// 默认是通过判断e.deltaY的值是否小于10显然这种方法是不准确的当鼠标滚动的很慢或者触摸移动的很快时判断就失效了如果你有更好的方法欢迎提交issue
// 如果你希望自己来判断那么传递一个函数接收一个参数e事件对象需要返回true或false代表是否是来自触控板
customCheckIsTouchPad: null,
// 鼠标缩放是否以鼠标当前位置为中心点,否则以画布中心点
mouseScaleCenterUseMousePosition: true,
// 最多显示几个标签
@@ -235,6 +245,8 @@ export const defaultOpt = {
emptyTextMeasureHeightText: 'abc123我和你',
// 是否在进行节点文本编辑时实时更新节点大小和节点位置,开启后当节点数量比较多时可能会造成卡顿
openRealtimeRenderOnNodeTextEdit: false,
// 默认会给容器元素el绑定mousedown事件并且会阻止其默认事件这会带来一定问题比如你聚焦在思维导图外的其他输入框点击画布就不会触发其失焦可以通过该选项关闭阻止。关闭后也会带来一定问题比如鼠标框选节点时可能会选中节点文字看你如何取舍
mousedownEventPreventDefault: true,
// 【Select插件】
// 多选节点时鼠标移动到边缘时的画布移动偏移量
@@ -318,6 +330,8 @@ export const defaultOpt = {
// 导出png、svg、pdf时会获取画布上的svg数据进行克隆然后通过该克隆的元素进行导出如果你想对该克隆元素做一些处理比如新增、替换、修改其中的一些元素那么可以通过该参数传递一个处理函数接收svg元素对象处理后需要返回原svg元素对象。
// 需要注意的是svg对象指的是@svgdotjs/svg.js库的元素对象所以你需要阅读该库的文档来操作该对象
handleBeingExportSvg: null,
// 导出图片或pdf都是通过canvas将svg绘制出来再导出所以如果思维导图特别大宽高可能会超出canvas支持的上限所以会进行缩放这个上限可以通过该参数设置代表canvas宽和高的最大宽度
maxCanvasSize: 16384,
// 【AssociativeLine插件】
// 关联线默认文字

View File

@@ -156,8 +156,14 @@ class Event extends EventEmitter {
// 判断是否是触控板
let isTouchPad = false
// mac、windows
if (e.wheelDeltaY === e.deltaY * -3 || Math.abs(e.wheelDeltaY) <= 10) {
isTouchPad = true
// if (e.wheelDeltaY === e.deltaY * -3 || Math.abs(e.wheelDeltaY) <= 10) {
// isTouchPad = true
// }
const { customCheckIsTouchPad } = this.mindMap.opt
if (typeof customCheckIsTouchPad === 'function') {
isTouchPad = customCheckIsTouchPad(e)
} else {
isTouchPad = Math.abs(e.deltaY) <= 10
}
this.emit('mousewheel', e, dirs, this, isTouchPad)
}

View File

@@ -97,6 +97,7 @@ class Render {
this.beingPasteText = ''
this.beingPasteImgSize = 0
this.currentBeingPasteType = ''
this.pasteData = { text: null, img: null }
// 节点高亮框
this.highlightBoxNode = null
this.highlightBoxNodeStyle = null
@@ -161,6 +162,15 @@ class Render {
})
})
}
// 处理非https下的复制黏贴问题
// 暂时不启用,因为给页面的其他输入框(比如节点文本编辑框)粘贴内容也会触发,冲突问题暂时没有想到好的解决方法,不可能要求所有输入框都阻止冒泡
// if (!navigator.clipboard) {
// this.handlePaste = this.handlePaste.bind(this)
// window.addEventListener('paste', this.handlePaste)
// this.mindMap.on('beforeDestroy', () => {
// window.removeEventListener('paste', this.handlePaste)
// })
// }
}
// 性能模式,懒加载节点
@@ -405,7 +415,7 @@ class Render {
this.mindMap.keyCommand.addShortcut('Control+Down', () => {
this.mindMap.execCommand('DOWN_NODE')
})
// 复制节点
// 复制节点
this.mindMap.keyCommand.addShortcut('Control+c', () => {
this.copy()
})
@@ -415,7 +425,7 @@ class Render {
})
// 粘贴节点
this.mindMap.keyCommand.addShortcut('Control+v', () => {
this.paste()
if (navigator.clipboard) this.paste()
})
// 根节点居中显示
this.mindMap.keyCommand.addShortcut('Control+Enter', () => {
@@ -1118,6 +1128,28 @@ class Render {
})
}
// 非https下复制黏贴获取内容方法
handlePaste(event) {
const { disabledClipboard } = this.mindMap.opt
if (disabledClipboard) return
const clipboardData =
event.clipboardData || event.originalEvent.clipboardData
const items = clipboardData.items
let img = null
let text = ''
Array.from(items).forEach(item => {
if (item.type.indexOf('image') > -1) {
img = item.getAsFile()
}
if (item.type.indexOf('text') > -1) {
text = clipboardData.getData('text')
}
})
this.pasteData.img = img
this.pasteData.text = text
this.paste()
}
// 粘贴
async paste() {
const {
@@ -1131,7 +1163,9 @@ class Render {
let img = null
if (!disabledClipboard) {
try {
const res = await getDataFromClipboard()
const res = navigator.clipboard
? await getDataFromClipboard()
: this.pasteData
text = res.text || ''
img = res.img || null
} catch (error) {

View File

@@ -1180,10 +1180,9 @@ class MindMapNode {
// 获取padding值
getPaddingVale() {
let { isActive } = this.getData()
return {
paddingX: this.getStyle('paddingX', true, isActive),
paddingY: this.getStyle('paddingY', true, isActive)
paddingX: this.getStyle('paddingX'),
paddingY: this.getStyle('paddingY')
}
}

View File

@@ -1,6 +1,5 @@
import { checkIsNodeStyleDataKey } from '../../../utils/index'
const rootProp = ['paddingX', 'paddingY']
const backgroundStyleProps = [
'backgroundColor',
'backgroundImage',
@@ -62,11 +61,10 @@ class Style {
// 合并样式
merge(prop, root) {
let themeConfig = this.ctx.mindMap.themeConfig
// 三级及以下节点
let defaultConfig = themeConfig.node
let defaultConfig = null
let useRoot = false
if (root || rootProp.includes(prop)) {
// 直接使用最外层样式
if (root) {
// 使用最外层样式
useRoot = true
defaultConfig = themeConfig
} else if (this.ctx.isGeneralization) {
@@ -78,12 +76,21 @@ class Style {
} else if (this.ctx.layerIndex === 1) {
// 二级节点
defaultConfig = themeConfig.second
} else {
// 三级及以下节点
defaultConfig = themeConfig.node
}
let value = ''
// 优先使用节点本身的样式
const value =
this.getSelfStyle(prop) !== undefined
? this.getSelfStyle(prop)
: defaultConfig[prop]
if (this.getSelfStyle(prop) !== undefined) {
value = this.getSelfStyle(prop)
} else if (defaultConfig[prop] !== undefined) {
// 否则使用对应层级的样式
value = defaultConfig[prop]
} else {
// 否则使用最外层样式
value = themeConfig[prop]
}
if (!useRoot) {
this.addToEffectiveStyles({
[prop]: value
@@ -348,8 +355,10 @@ class Style {
// hover和激活节点
hoverNode(node) {
const hoverRectColor = this.merge('hoverRectColor') || this.ctx.mindMap.opt.hoverRectColor
node.radius(5).fill('none').stroke({
const hoverRectColor =
this.merge('hoverRectColor') || this.ctx.mindMap.opt.hoverRectColor
const hoverRectRadius = this.merge('hoverRectRadius')
node.radius(hoverRectRadius).fill('none').stroke({
color: hoverRectColor
})
}

View File

@@ -30,8 +30,11 @@ class View {
})
// 拖动视图
this.mindMap.event.on('mousedown', e => {
if (this.mindMap.opt.isDisableDrag) return
e.preventDefault()
const { isDisableDrag, mousedownEventPreventDefault } = this.mindMap.opt
if (isDisableDrag) return
if (mousedownEventPreventDefault) {
e.preventDefault()
}
this.sx = this.x
this.sy = this.y
})
@@ -63,7 +66,8 @@ class View {
mouseScaleCenterUseMousePosition,
mousewheelMoveStep,
mousewheelZoomActionReverse,
disableMouseWheelZoom
disableMouseWheelZoom,
translateRatio
} = this.mindMap.opt
// 是否自定义鼠标滚轮事件
if (
@@ -138,7 +142,7 @@ class View {
if (dirs.includes(CONSTANTS.DIR.RIGHT)) {
mx = -stepX
}
this.translateXY(mx, my)
this.translateXY(mx * translateRatio, my * translateRatio)
}
})
this.mindMap.on('resize', () => {
@@ -246,8 +250,9 @@ class View {
// 缩小
narrow(cx, cy, isTouchPad) {
const scaleRatio = this.mindMap.opt.scaleRatio / (isTouchPad ? 5 : 1)
const scale = Math.max(this.scale - scaleRatio, 0.1)
let { scaleRatio, minZoomRatio } = this.mindMap.opt
scaleRatio = scaleRatio / (isTouchPad ? 5 : 1)
const scale = Math.max(this.scale - scaleRatio, minZoomRatio / 100)
this.scaleInCenter(scale, cx, cy)
this.transform()
this.emitEvent('scale')
@@ -255,8 +260,14 @@ class View {
// 放大
enlarge(cx, cy, isTouchPad) {
const scaleRatio = this.mindMap.opt.scaleRatio / (isTouchPad ? 5 : 1)
const scale = this.scale + scaleRatio
let { scaleRatio, maxZoomRatio } = this.mindMap.opt
scaleRatio = scaleRatio / (isTouchPad ? 5 : 1)
let scale = 0
if (maxZoomRatio === -1) {
scale = this.scale + scaleRatio
} else {
scale = Math.min(this.scale + scaleRatio, maxZoomRatio / 100)
}
this.scaleInCenter(scale, cx, cy)
this.transform()
this.emitEvent('scale')

View File

@@ -244,7 +244,9 @@ class Base {
isResizeSource ||
(newData && JSON.stringify(oldData) !== JSON.stringify(newData))
) {
gNode.nodeData.data = newData
if (newData) {
gNode.nodeData.data = newData
}
gNode.getSize()
gNode.needLayout = true
}

View File

@@ -129,6 +129,7 @@ class Export {
// svg转png
svgToPng(svgSrc, transparent, clipData = null) {
const { maxCanvasSize, minExportImgCanvasScale } = this.mindMap.opt
return new Promise((resolve, reject) => {
const img = new Image()
// 跨域图片需要添加这个属性,否则画布被污染了无法导出图片
@@ -136,10 +137,7 @@ class Export {
img.onload = async () => {
try {
const canvas = document.createElement('canvas')
const dpr = Math.max(
window.devicePixelRatio,
this.mindMap.opt.minExportImgCanvasScale
)
const dpr = Math.max(window.devicePixelRatio, minExportImgCanvasScale)
let imgWidth = img.width
let imgHeight = img.height
// 如果是裁减操作的话,那么需要手动添加内边距,及调整图片大小为实际的裁减区域的大小,不要忘了内边距哦
@@ -152,29 +150,40 @@ class Export {
imgHeight = clipData.height + paddingY * 2
}
// 检查是否超出canvas支持的像素上限
const maxSize = 16384 / dpr
const maxArea = maxSize * maxSize
if (imgWidth * imgHeight > maxArea) {
// canvas大小需要乘以dpr
let canvasWidth = imgWidth * dpr
let canvasHeight = imgHeight * dpr
if (canvasWidth > maxCanvasSize || canvasHeight > maxCanvasSize) {
let newWidth = null
let newHeight = null
if (imgWidth > maxSize) {
newWidth = maxArea / imgHeight
} else if (imgHeight > maxSize) {
newHeight = maxArea / imgWidth
if (canvasWidth > maxCanvasSize) {
// 如果宽度超出限制,那么调整为上限值
newWidth = maxCanvasSize
} else if (canvasHeight > maxCanvasSize) {
// 高度同理
newHeight = maxCanvasSize
}
const res = resizeImgSize(imgWidth, imgHeight, newWidth, newHeight)
imgWidth = res[0]
imgHeight = res[1]
// 计算缩放后的宽高
const res = resizeImgSize(
canvasWidth,
canvasHeight,
newWidth,
newHeight
)
canvasWidth = res[0]
canvasHeight = res[1]
}
canvas.width = imgWidth * dpr
canvas.height = imgHeight * dpr
canvas.style.width = imgWidth + 'px'
canvas.style.height = imgHeight + 'px'
canvas.width = canvasWidth
canvas.height = canvasHeight
const styleWidth = canvasWidth / dpr
const styleHeight = canvasHeight / dpr
canvas.style.width = styleWidth + 'px'
canvas.style.height = styleHeight + 'px'
const ctx = canvas.getContext('2d')
ctx.scale(dpr, dpr)
// 绘制背景
if (!transparent) {
await this.drawBackgroundToCanvas(ctx, imgWidth, imgHeight)
await this.drawBackgroundToCanvas(ctx, styleWidth, styleHeight)
}
// 图片绘制到canvas里
// 如果有裁减数据,那么需要进行裁减
@@ -191,7 +200,7 @@ class Export {
clipData.height
)
} else {
ctx.drawImage(img, 0, 0, imgWidth, imgHeight)
ctx.drawImage(img, 0, 0, styleWidth, styleHeight)
}
resolve(canvas.toDataURL())
} catch (error) {

View File

@@ -3,6 +3,9 @@ import Quill from 'quill'
import { getChromeVersion, htmlEscape } from '../utils/index'
import { getBaseStyleText, getFontStyleText } from './FormulaStyle'
let extended = false
const QuillFormula = Quill.import('formats/formula')
// 数学公式支持插件
// 该插件在富文本模式下可用
class Formula {
@@ -16,6 +19,18 @@ class Formula {
this.cssEl = null
this.addStyle()
this.extendQuill()
this.onDestroy = this.onDestroy.bind(this)
this.mindMap.on('beforeDestroy', this.onDestroy)
}
onDestroy() {
const instanceCount = Object.getPrototypeOf(this.mindMap).constructor
.instanceCount
// 如果思维导图实例数量变成0了那么就恢复成默认的
if (instanceCount <= 1) {
extended = false
Quill.register('formats/formula', QuillFormula, true)
}
}
init() {
@@ -50,7 +65,9 @@ class Formula {
// 修改formula格式工具
extendQuill() {
const QuillFormula = Quill.import('formats/formula')
if (extended) return
extended = true
const self = this
class CustomFormulaBlot extends QuillFormula {
@@ -168,11 +185,13 @@ class Formula {
// 插件被移除前做的事情
beforePluginRemove() {
this.removeStyle()
this.mindMap.off('beforeDestroy', this.onDestroy)
}
// 插件被卸载前做的事情
beforePluginDestroy() {
this.removeStyle()
this.mindMap.off('beforeDestroy', this.onDestroy)
}
}

View File

@@ -549,6 +549,20 @@ class RichText {
delta.ops = ops
return delta
})
// 拦截图片的粘贴
this.quill.root.addEventListener(
'paste',
e => {
if (
e.clipboardData &&
e.clipboardData.files &&
e.clipboardData.files.length
) {
e.preventDefault()
}
},
true
)
}
// 获取粘贴的文本的样式

View File

@@ -41,7 +41,8 @@ class Select {
// 鼠标按下
onMousedown(e) {
if (this.mindMap.opt.readonly) {
const { readonly, mousedownEventPreventDefault } = this.mindMap.opt
if (readonly) {
return
}
let { useLeftKeySelectionRightKeyDrag } = this.mindMap.opt
@@ -51,7 +52,9 @@ class Select {
) {
return
}
e.preventDefault()
if (mousedownEventPreventDefault) {
e.preventDefault()
}
this.isMousedown = true
this.cacheActiveList = [...this.mindMap.renderer.activeNodeList]
let { x, y } = this.mindMap.toPos(e.clientX, e.clientY)

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 秋天
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: '#fff2df',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 牛油果
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: '#e6f1de',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 黑金
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: 'rgb(18, 20, 20)',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 黑色幽默
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: 'rgb(27, 31, 34)',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 天空蓝
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(115, 161, 191)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 脑残粉
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(191, 115, 148)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 脑图经典
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: '#fff',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 经典2
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(51, 51, 51)',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 经典3
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(94, 202, 110)',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 经典4
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(30, 53, 86)',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 经典蓝
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(51, 51, 51)',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 经典绿
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(123, 199, 120)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 咖啡
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(173, 123, 91)',
lineWidth: 4,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 课程绿
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(113, 195, 169)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 暗色
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(17, 68, 23)',
// 连线的粗细

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 暗色2
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(75, 81, 78)',
lineWidth: 3,

View File

@@ -87,7 +87,11 @@ export default {
// 连线标记的位置start头部、end尾部该配置在showLineMarker配置为true时生效
lineMarkerDir: 'end',
// 节点鼠标hover和激活时显示的矩形边框的颜色主题里不设置默认会取hoverRectColor实例化选项的值
hoverRectColor: ''
hoverRectColor: '',
// 点鼠标hover和激活时显示的矩形边框的圆角大小
hoverRectRadius: 5
// paddingX: 15,
// paddingY: 5
},
// 二级节点样式
second: {
@@ -112,7 +116,10 @@ export default {
startDir: [0, 0],
endDir: [1, 0],
lineMarkerDir: 'end',
hoverRectColor: ''
hoverRectColor: '',
hoverRectRadius: 5
// paddingX: 15,
// paddingY: 5
},
// 三级及以下节点样式
node: {
@@ -137,7 +144,10 @@ export default {
startDir: [0, 0],
endDir: [1, 0],
lineMarkerDir: 'end',
hoverRectColor: ''
hoverRectColor: '',
hoverRectRadius: 5
// paddingX: 15,
// paddingY: 5
},
// 概要节点样式
generalization: {
@@ -161,7 +171,10 @@ export default {
endColor: '#fff',
startDir: [0, 0],
endDir: [1, 0],
hoverRectColor: ''
hoverRectColor: '',
hoverRectRadius: 5
// paddingX: 15,
// paddingY: 5
}
}
@@ -195,7 +208,8 @@ const nodeSizeIndependenceList = [
'endColor',
'startDir',
'endDir',
'hoverRectColor'
'hoverRectColor',
'hoverRectRadius'
]
export const checkIsNodeSizeIndependenceConfig = config => {
let keys = Object.keys(config)

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 泥土黄
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(191, 147, 115)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 清新绿
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: '#333',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 清新红
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(191, 115, 115)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 金色vip
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(51, 56, 62)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 绿叶
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(40, 193, 84)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 深夜办公室
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: 'rgb(32, 37, 49)',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 小黄人
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(51, 51, 51)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 薄荷
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(104, 204, 202)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 橙汁
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: '#070616',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 粉红葡萄
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(166, 101, 106)',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 红色精神
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 背景颜色
backgroundColor: 'rgb(255, 238, 228)',
// 连线的颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 浪漫紫
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(123, 115, 191)',
// 背景颜色

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 简约黑
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(34, 34, 34)',
lineWidth: 4,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 天清绿
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: '#fff',
lineWidth: 3,

View File

@@ -1,8 +1,8 @@
import defaultTheme from './default'
import merge from 'deepmerge'
import { mergeTheme } from '../utils'
// 活力橙
export default merge(defaultTheme, {
export default mergeTheme(defaultTheme, {
// 连线的颜色
lineColor: 'rgb(254, 146, 0)',
lineWidth: 3,

View File

@@ -5,6 +5,7 @@ import {
} from '../constants/constant'
import MersenneTwister from './mersenneTwister'
import { ForeignObject } from '@svgdotjs/svg.js'
import merge from 'deepmerge'
// 深度优先遍历树
export const walk = (
@@ -1610,3 +1611,12 @@ export const sortNodeList = nodeList => {
})
return nodeList
}
// 合并主题配置
export const mergeTheme = (dest, source) => {
return merge(dest, source, {
arrayMerge: (destinationArray, sourceArray) => {
return sourceArray
}
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -111,7 +111,8 @@ export default {
copyToPng: 'Png',
copySuccess: 'Copy success',
copyFail: 'Copy fail',
number: 'Number child nodes'
number: 'Number child nodes',
expandNodeChild: 'Expand all sub nodes'
},
count: {
words: 'Words',

View File

@@ -111,7 +111,8 @@ export default {
copyToPng: '图片',
copySuccess: '复制成功',
copyFail: '复制失败',
number: '编号其子节点'
number: '编号其子节点',
expandNodeChild: '展开所有下级节点'
},
count: {
words: '字数',

View File

@@ -111,7 +111,8 @@ export default {
copyToPng: '圖片',
copySuccess: '複製成功',
copyFail: '複製失敗',
number: '將其子節點編號'
number: '將其子節點編號',
expandNodeChild: '展開所有下級節點'
},
count: {
words: '字數',

View File

@@ -56,6 +56,9 @@
<span class="name">{{ $t('contextmenu.moveDownNode') }}</span>
<span class="desc">Ctrl + </span>
</div>
<div class="item" @click="exec('EXPAND_ALL')">
<span class="name">{{ $t('contextmenu.expandNodeChild') }}</span>
</div>
<div class="item" v-if="supportNumbers">
<span class="name">{{ $t('contextmenu.number') }}</span>
<span class="el-icon-arrow-right"></span>
@@ -344,12 +347,11 @@ export default {
// 计算右键菜单元素的显示位置
getShowPosition(x, y) {
this.subItemsShowLeft = false
const rect = this.$refs.contextmenuRef.getBoundingClientRect()
if (x + rect.width > window.innerWidth) {
x = x - rect.width - 20
this.subItemsShowLeft = true
}
this.subItemsShowLeft = x + rect.width + 150 > window.innerWidth
if (y + rect.height > window.innerHeight) {
y = window.innerHeight - rect.height - 10
}
@@ -462,6 +464,9 @@ export default {
this.node
)
break
case 'EXPAND_ALL':
this.$bus.$emit('execCommand', key, this.node.uid)
break
default:
this.$bus.$emit('execCommand', key, ...args)
break

View File

@@ -124,8 +124,8 @@ export default {
node.setImage({
url: img || 'none',
title: this.imgTitle,
width: res.width,
height: res.height
width: res.width || 100,
height: res.height || 100
})
})
this.cancel()