拉取最新代码

This commit is contained in:
panda 2024-09-27 20:34:55 +08:00
commit d0e46eb052
61 changed files with 333 additions and 184 deletions

View File

@ -103,7 +103,9 @@ const mindMap = new MindMap({
# 微信交流群
一群已满,可以扫描如下二维码进入二群,如已过期,可以微信添加`wanglinguanfang`拉你入群。思维导图相关问题皆可在群里提问,不必私聊作者。
一群已满,可以扫描如下二维码进入二群,如已过期,可以微信添加`wanglinguanfang`拉你入群。
大部分问题都可以通过文档解决,所以提问前请确保你已经阅读完了所有文档,文档里没有的可在群里提问,不必私聊作者。
<img src="./qrcode.jpg" style="width: 300px" />
@ -469,4 +471,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

@ -7,6 +7,8 @@ export const defaultOpt = {
el: null,
// 思维导图回显数据
data: null,
// 要恢复的视图数据一般通过mindMap.view.getTransformData()方法获取
viewData: null,
// 是否只读
readonly: false,
// 布局
@ -19,6 +21,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 +247,10 @@ export const defaultOpt = {
emptyTextMeasureHeightText: 'abc123我和你',
// 是否在进行节点文本编辑时实时更新节点大小和节点位置,开启后当节点数量比较多时可能会造成卡顿
openRealtimeRenderOnNodeTextEdit: false,
// 默认会给容器元素el绑定mousedown事件并且会阻止其默认事件这会带来一定问题比如你聚焦在思维导图外的其他输入框点击画布就不会触发其失焦可以通过该选项关闭阻止。关闭后也会带来一定问题比如鼠标框选节点时可能会选中节点文字看你如何取舍
mousedownEventPreventDefault: true,
// 在激活上粘贴用户剪贴板中的数据时,如果同时存在文本和图片,那么只粘贴文本,忽略图片
onlyPasteTextWhenHasImgAndText: true,
// 【Select插件】
// 多选节点时鼠标移动到边缘时的画布移动偏移量
@ -318,6 +334,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,7 +97,7 @@ class Render {
this.beingPasteText = ''
this.beingPasteImgSize = 0
this.currentBeingPasteType = ''
this.pasteData = { text: null, img: null}
this.pasteData = { text: null, img: null }
// 节点高亮框
this.highlightBoxNode = null
this.highlightBoxNodeStyle = null
@ -132,11 +132,6 @@ class Render {
}
}
// 解绑事件
unBindEvent() {
window.removeEventListener('paste', this.handlePaste)
}
// 绑定事件
bindEvent() {
// 画布点击事件清除当前激活节点列表
@ -168,13 +163,14 @@ class Render {
})
}
// 处理非https下的复制黏贴问题
if(!navigator.clipboard) {
this.handlePaste = this.handlePaste.bind(this)
window.addEventListener('paste', this.handlePaste)
this.mindMap.on('beforeDestroy', () => {
this.unBindEvent()
})
}
// 暂时不启用,因为给页面的其他输入框(比如节点文本编辑框)粘贴内容也会触发,冲突问题暂时没有想到好的解决方法,不可能要求所有输入框都阻止冒泡
// if (!navigator.clipboard) {
// this.handlePaste = this.handlePaste.bind(this)
// window.addEventListener('paste', this.handlePaste)
// this.mindMap.on('beforeDestroy', () => {
// window.removeEventListener('paste', this.handlePaste)
// })
// }
}
// 性能模式,懒加载节点
@ -419,7 +415,7 @@ class Render {
this.mindMap.keyCommand.addShortcut('Control+Down', () => {
this.mindMap.execCommand('DOWN_NODE')
})
// 复制节点
// 复制节点
this.mindMap.keyCommand.addShortcut('Control+c', () => {
this.copy()
})
@ -429,7 +425,7 @@ class Render {
})
// 粘贴节点
this.mindMap.keyCommand.addShortcut('Control+v', () => {
if(navigator.clipboard) this.paste()
if (navigator.clipboard) this.paste()
})
// 根节点居中显示
this.mindMap.keyCommand.addShortcut('Control+Enter', () => {
@ -1133,23 +1129,24 @@ class Render {
}
// 非https下复制黏贴获取内容方法
handlePaste(event){
const clipboardData = event.clipboardData || event.originalEvent.clipboardData || window.clipboardData
handlePaste(event) {
const { disabledClipboard } = this.mindMap.opt
if (disabledClipboard) return
const clipboardData =
event.clipboardData || event.originalEvent.clipboardData
const items = clipboardData.items
const clipboardType = items && items.length ? items[0].type : ''
const isImg = clipboardType.indexOf('image') > -1
const isText = clipboardType.indexOf('text') > -1
this.pasteData = { img: null, text: null}
// 复制的图片处理逻辑
if (isImg) {
for (let index in items) {
const item = items[index]
if (item.kind === 'file') this.pasteData.img = item.getAsFile()
let img = null
let text = ''
Array.from(items).forEach(item => {
if (item.type.indexOf('image') > -1) {
img = item.getAsFile()
}
}
// 复制的文本处理逻辑
if (isText) this.pasteData.text = clipboardData.getData('text')
if (item.type.indexOf('text') > -1) {
text = clipboardData.getData('text')
}
})
this.pasteData.img = img
this.pasteData.text = text
this.paste()
}
@ -1159,14 +1156,17 @@ class Render {
errorHandler,
handleIsSplitByWrapOnPasteCreateNewNode,
handleNodePasteImg,
disabledClipboard
disabledClipboard,
onlyPasteTextWhenHasImgAndText
} = this.mindMap.opt
// 读取剪贴板的文字和图片
let text = ''
let img = null
if (!disabledClipboard) {
try {
const res = navigator.clipboard ? await getDataFromClipboard() : this.pasteData
const res = navigator.clipboard
? await getDataFromClipboard()
: this.pasteData
text = res.text || ''
img = res.img || null
} catch (error) {
@ -1262,7 +1262,7 @@ class Render {
}
}
// 存在图片,则添加到当前激活节点
if (img) {
if (img && (!text || !onlyPasteTextWhenHasImgAndText)) {
try {
let imgData = null
// 自定义图片处理函数
@ -1600,7 +1600,7 @@ class Render {
this.setNodeDataRender(node, data)
// 更新了连线的样式
if (lineStyleProps.includes(prop)) {
(node.parent || node).renderLine(true)
;(node.parent || node).renderLine(true)
}
}
@ -1621,7 +1621,7 @@ class Render {
}
})
if (hasLineStyleProps) {
(node.parent || node).renderLine(true)
;(node.parent || node).renderLine(true)
}
}

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

@ -224,9 +224,15 @@ class Search {
replaceText = String(replaceText)
let currentNode = this.matchNodeList[this.currentIndex]
if (!currentNode) return
let text = this.getReplacedText(currentNode, this.searchText, replaceText)
// 如果当前搜索文本是替换文本的子串,那么该节点还是符合搜索结果的
const keep = replaceText.includes(this.searchText)
const text = this.getReplacedText(currentNode, this.searchText, replaceText)
this.notResetSearchText = true
currentNode.setText(text, currentNode.getData('richText'), true)
if (keep) {
this.updateMatchNodeList(this.matchNodeList)
return
}
const newList = this.matchNodeList.filter(node => {
return currentNode !== node
})
@ -249,6 +255,8 @@ class Search {
)
return
replaceText = String(replaceText)
// 如果当前搜索文本是替换文本的子串,那么该节点还是符合搜索结果的
const keep = replaceText.includes(this.searchText)
this.matchNodeList.forEach(node => {
const text = this.getReplacedText(node, this.searchText, replaceText)
if (this.isNodeInstance(node)) {
@ -267,7 +275,11 @@ class Search {
})
this.mindMap.render()
this.mindMap.command.addHistory()
this.endSearch()
if (keep) {
this.updateMatchNodeList(this.matchNodeList)
} else {
this.endSearch()
}
}
// 获取某个节点替换后的文本

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()