Merge branch 'feature' of https://github.com/wanglin2/mind-map into feature

This commit is contained in:
街角小林 2025-02-11 17:31:01 +08:00
commit aa41d23505
9 changed files with 79 additions and 9 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@ node_modules
.DS_Store .DS_Store
dist_electron dist_electron
simple-mind-map/dist simple-mind-map/dist
simple-mind-map/types simple-mind-map/types
utools/dist

View File

@ -20,7 +20,8 @@ import {
isUndef, isUndef,
handleGetSvgDataExtraContent, handleGetSvgDataExtraContent,
getNodeTreeBoundingRect, getNodeTreeBoundingRect,
mergeTheme mergeTheme,
createUidForAppointNodes
} from './src/utils' } from './src/utils'
import defaultTheme, { import defaultTheme, {
checkIsNodeSizeIndependenceConfig checkIsNodeSizeIndependenceConfig
@ -149,6 +150,8 @@ class MindMap {
if (data.data && !data.data.expand) { if (data.data && !data.data.expand) {
data.data.expand = true data.data.expand = true
} }
// 给没有uid的节点添加uid
createUidForAppointNodes([data], false, null, true)
return data return data
} }
@ -395,6 +398,7 @@ class MindMap {
// 更新画布数据,如果新的数据是在当前画布节点数据基础上增删改查后形成的,那么可以使用该方法来更新画布数据 // 更新画布数据,如果新的数据是在当前画布节点数据基础上增删改查后形成的,那么可以使用该方法来更新画布数据
updateData(data) { updateData(data) {
data = this.handleData(data)
this.emit('before_update_data', data) this.emit('before_update_data', data)
this.renderer.setData(data) this.renderer.setData(data)
this.render() this.render()
@ -583,7 +587,7 @@ class MindMap {
this.watermark.isInExport = false this.watermark.isInExport = false
} }
// 添加必要的样式 // 添加必要的样式
[this.joinCss(), ...cssTextList].forEach(s => { ;[this.joinCss(), ...cssTextList].forEach(s => {
clone.add(SVG(`<style>${s}</style>`)) clone.add(SVG(`<style>${s}</style>`))
}) })
// 附加内容 // 附加内容

View File

@ -302,6 +302,25 @@ export const defaultOpt = {
}, },
// 自定义快捷创建子节点按钮的点击操作, // 自定义快捷创建子节点按钮的点击操作,
customQuickCreateChildBtnClick: null, customQuickCreateChildBtnClick: null,
// 添加自定义的节点内容
// 可传递一个对象,格式如下:
/*
{
// 返回要添加的DOM元素详细
create: (node) => {
return {
el, // DOM节点
width: 20, // 宽高
height: 20
}
},
// 处理生成的@svgdotjs/svg.js库的ForeignObject节点实例可以设置其在节点内的位置
handle: ({ content, element, node }) => {
}
}
*/
addCustomContentToNode: null,
// 【Select插件】 // 【Select插件】
// 多选节点时鼠标移动到边缘时的画布移动偏移量 // 多选节点时鼠标移动到边缘时的画布移动偏移量

View File

@ -99,6 +99,7 @@ class MindMapNode {
this._generalizationList = [] this._generalizationList = []
this._unVisibleRectRegionNode = null this._unVisibleRectRegionNode = null
this._isMouseenter = false this._isMouseenter = false
this._customContentAddToNodeAdd = null
// 尺寸信息 // 尺寸信息
this._rectInfo = { this._rectInfo = {
textContentWidth: 0, textContentWidth: 0,
@ -216,7 +217,8 @@ class MindMapNode {
isUseCustomNodeContent, isUseCustomNodeContent,
customCreateNodeContent, customCreateNodeContent,
createNodePrefixContent, createNodePrefixContent,
createNodePostfixContent createNodePostfixContent,
addCustomContentToNode
} = this.mindMap.opt } = this.mindMap.opt
// 需要创建的内容类型 // 需要创建的内容类型
const typeList = [ const typeList = [
@ -289,6 +291,15 @@ class MindMapNode {
addXmlns(this._postfixData.el) addXmlns(this._postfixData.el)
} }
} }
if (
addCustomContentToNode &&
typeof addCustomContentToNode.create === 'function'
) {
this._customContentAddToNodeAdd = addCustomContentToNode.create(this)
if (this._customContentAddToNodeAdd && this._customContentAddToNodeAdd.el) {
addXmlns(this._customContentAddToNodeAdd.el)
}
}
} }
// 计算节点的宽高 // 计算节点的宽高

View File

@ -177,7 +177,8 @@ function layout() {
const { const {
hoverRectPadding, hoverRectPadding,
openRealtimeRenderOnNodeTextEdit, openRealtimeRenderOnNodeTextEdit,
textContentMargin textContentMargin,
addCustomContentToNode
} = this.mindMap.opt } = this.mindMap.opt
// 避免编辑过程中展开收起按钮闪烁的问题 // 避免编辑过程中展开收起按钮闪烁的问题
if (openRealtimeRenderOnNodeTextEdit && this._expandBtn) { if (openRealtimeRenderOnNodeTextEdit && this._expandBtn) {
@ -428,6 +429,22 @@ function layout() {
} }
textContentNested.translate(translateX, translateY) textContentNested.translate(translateX, translateY)
addHoverNode() addHoverNode()
if (this._customContentAddToNodeAdd && this._customContentAddToNodeAdd.el) {
const foreignObject = createForeignObjectNode(
this._customContentAddToNodeAdd
)
this.group.add(foreignObject)
if (
addCustomContentToNode &&
typeof addCustomContentToNode.handle === 'function'
) {
addCustomContentToNode.handle({
content: this._customContentAddToNodeAdd,
element: foreignObject,
node: this
})
}
}
this.mindMap.emit('node_layout_end', this) this.mindMap.emit('node_layout_end', this)
} }

View File

@ -2,13 +2,14 @@ import btnsSvg from '../../../svg/btns'
import { SVG, Circle, G } from '@svgdotjs/svg.js' import { SVG, Circle, G } from '@svgdotjs/svg.js'
function initQuickCreateChildBtn() { function initQuickCreateChildBtn() {
if (this.isGeneralization) return
this._quickCreateChildBtn = null this._quickCreateChildBtn = null
this._showQuickCreateChildBtn = false this._showQuickCreateChildBtn = false
} }
// 显示按钮 // 显示按钮
function showQuickCreateChildBtn() { function showQuickCreateChildBtn() {
if (this.getChildrenLength() > 0) return if (this.isGeneralization || this.getChildrenLength() > 0) return
// 创建按钮 // 创建按钮
if (this._quickCreateChildBtn) { if (this._quickCreateChildBtn) {
this.group.add(this._quickCreateChildBtn) this.group.add(this._quickCreateChildBtn)
@ -63,6 +64,7 @@ function showQuickCreateChildBtn() {
// 移除按钮 // 移除按钮
function removeQuickCreateChildBtn() { function removeQuickCreateChildBtn() {
if (this.isGeneralization) return
if (this._quickCreateChildBtn && this._showQuickCreateChildBtn) { if (this._quickCreateChildBtn && this._showQuickCreateChildBtn) {
this._quickCreateChildBtn.remove() this._quickCreateChildBtn.remove()
this._showQuickCreateChildBtn = false this._showQuickCreateChildBtn = false
@ -71,6 +73,7 @@ function removeQuickCreateChildBtn() {
// 隐藏按钮 // 隐藏按钮
function hideQuickCreateChildBtn() { function hideQuickCreateChildBtn() {
if (this.isGeneralization) return
const { isActive } = this.getData() const { isActive } = this.getData()
if (!isActive) { if (!isActive) {
this.removeQuickCreateChildBtn() this.removeQuickCreateChildBtn()

View File

@ -182,6 +182,10 @@ class Search {
const uid = this.isNodeInstance(currentNode) const uid = this.isNodeInstance(currentNode)
? currentNode.getData('uid') ? currentNode.getData('uid')
: currentNode.data.uid : currentNode.data.uid
if (!uid) {
callback()
return
}
const targetNode = this.mindMap.renderer.findNodeByUid(uid) const targetNode = this.mindMap.renderer.findNodeByUid(uid)
this.mindMap.execCommand('GO_TARGET_NODE', uid, node => { this.mindMap.execCommand('GO_TARGET_NODE', uid, node => {
if (!this.isNodeInstance(currentNode)) { if (!this.isNodeInstance(currentNode)) {

View File

@ -508,7 +508,7 @@ export const loadImage = imgFile => {
// 移除字符串中的html实体 // 移除字符串中的html实体
export const removeHTMLEntities = str => { export const removeHTMLEntities = str => {
[['&nbsp;', '&#160;']].forEach(item => { ;[['&nbsp;', '&#160;']].forEach(item => {
str = str.replace(new RegExp(item[0], 'g'), item[1]) str = str.replace(new RegExp(item[0], 'g'), item[1])
}) })
return str return str
@ -1002,7 +1002,8 @@ export const addDataToAppointNodes = (appointNodes, data = {}) => {
export const createUidForAppointNodes = ( export const createUidForAppointNodes = (
appointNodes, appointNodes,
createNewId = false, createNewId = false,
handle = null handle = null,
handleGeneralization = false
) => { ) => {
const walk = list => { const walk = list => {
list.forEach(node => { list.forEach(node => {
@ -1012,6 +1013,14 @@ export const createUidForAppointNodes = (
if (createNewId || isUndef(node.data.uid)) { if (createNewId || isUndef(node.data.uid)) {
node.data.uid = createUid() node.data.uid = createUid()
} }
if (handleGeneralization) {
const generalizationList = formatGetNodeGeneralization(node.data)
generalizationList.forEach(gNode => {
if (createNewId || isUndef(gNode.uid)) {
gNode.uid = createUid()
}
})
}
handle && handle(node) handle && handle(node)
if (node.children && node.children.length > 0) { if (node.children && node.children.length > 0) {
walk(node.children) walk(node.children)
@ -1060,7 +1069,7 @@ export const generateColorByContent = str => {
// html转义 // html转义
export const htmlEscape = str => { export const htmlEscape = str => {
[ ;[
['&', '&amp;'], ['&', '&amp;'],
['<', '&lt;'], ['<', '&lt;'],
['>', '&gt;'] ['>', '&gt;']

View File

@ -125,6 +125,7 @@ export default {
) )
this.mindMap.keyCommand.addShortcut('Control+f', this.showSearch) this.mindMap.keyCommand.addShortcut('Control+f', this.showSearch)
window.addEventListener('resize', this.setSearchResultListHeight) window.addEventListener('resize', this.setSearchResultListHeight)
this.$bus.$on('setData', this.close)
}, },
mounted() { mounted() {
this.setSearchResultListHeight() this.setSearchResultListHeight()
@ -141,6 +142,7 @@ export default {
) )
this.mindMap.keyCommand.removeShortcut('Control+f', this.showSearch) this.mindMap.keyCommand.removeShortcut('Control+f', this.showSearch)
window.removeEventListener('resize', this.setSearchResultListHeight) window.removeEventListener('resize', this.setSearchResultListHeight)
this.$bus.$off('setData', this.close)
}, },
methods: { methods: {
isUndef, isUndef,