Feat:支持自定义节点内容
This commit is contained in:
parent
1749705694
commit
749a4d0e81
@ -11,127 +11,7 @@ import { layoutValueList, CONSTANTS } from './src/constants/constant'
|
|||||||
import { SVG } from '@svgdotjs/svg.js'
|
import { SVG } from '@svgdotjs/svg.js'
|
||||||
import { simpleDeepClone } from './src/utils'
|
import { simpleDeepClone } from './src/utils'
|
||||||
import defaultTheme, { checkIsNodeSizeIndependenceConfig } from './src/themes/default'
|
import defaultTheme, { checkIsNodeSizeIndependenceConfig } from './src/themes/default'
|
||||||
|
import { defaultOpt } from './src/constants/defaultOptions'
|
||||||
// 默认选项配置
|
|
||||||
const defaultOpt = {
|
|
||||||
// 是否只读
|
|
||||||
readonly: false,
|
|
||||||
// 布局
|
|
||||||
layout: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
|
|
||||||
// 如果结构为鱼骨图,那么可以通过该选项控制倾斜角度
|
|
||||||
fishboneDeg: 45,
|
|
||||||
// 主题
|
|
||||||
theme: 'default', // 内置主题:default(默认主题)
|
|
||||||
// 主题配置,会和所选择的主题进行合并
|
|
||||||
themeConfig: {},
|
|
||||||
// 放大缩小的增量比例
|
|
||||||
scaleRatio: 0.1,
|
|
||||||
// 最多显示几个标签
|
|
||||||
maxTag: 5,
|
|
||||||
// 导出图片时的内边距
|
|
||||||
exportPadding: 20,
|
|
||||||
// 展开收缩按钮尺寸
|
|
||||||
expandBtnSize: 20,
|
|
||||||
// 节点里图片和文字的间距
|
|
||||||
imgTextMargin: 5,
|
|
||||||
// 节点里各种文字信息的间距,如图标和文字的间距
|
|
||||||
textContentMargin: 2,
|
|
||||||
// 多选节点时鼠标移动到边缘时的画布移动偏移量
|
|
||||||
selectTranslateStep: 3,
|
|
||||||
// 多选节点时鼠标移动距边缘多少距离时开始偏移
|
|
||||||
selectTranslateLimit: 20,
|
|
||||||
// 自定义节点备注内容显示
|
|
||||||
customNoteContentShow: null,
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
show(){},
|
|
||||||
hide(){}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// 是否开启节点自由拖拽
|
|
||||||
enableFreeDrag: false,
|
|
||||||
// 水印配置
|
|
||||||
watermarkConfig: {
|
|
||||||
text: '',
|
|
||||||
lineSpacing: 100,
|
|
||||||
textSpacing: 100,
|
|
||||||
angle: 30,
|
|
||||||
textStyle: {
|
|
||||||
color: '#999',
|
|
||||||
opacity: 0.5,
|
|
||||||
fontSize: 14
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 达到该宽度文本自动换行
|
|
||||||
textAutoWrapWidth: 500,
|
|
||||||
// 自定义鼠标滚轮事件处理
|
|
||||||
// 可以传一个函数,回调参数为事件对象
|
|
||||||
customHandleMousewheel: null,
|
|
||||||
// 鼠标滚动的行为,如果customHandleMousewheel传了自定义函数,这个属性不生效
|
|
||||||
mousewheelAction: CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM,// zoom(放大缩小)、move(上下移动)
|
|
||||||
// 当mousewheelAction设为move时,可以通过该属性控制鼠标滚动一下视图移动的步长,单位px
|
|
||||||
mousewheelMoveStep: 100,
|
|
||||||
// 默认插入的二级节点的文字
|
|
||||||
defaultInsertSecondLevelNodeText: '二级节点',
|
|
||||||
// 默认插入的二级以下节点的文字
|
|
||||||
defaultInsertBelowSecondLevelNodeText: '分支主题',
|
|
||||||
// 展开收起按钮的颜色
|
|
||||||
expandBtnStyle: {
|
|
||||||
color: '#808080',
|
|
||||||
fill: '#fff'
|
|
||||||
},
|
|
||||||
// 自定义展开收起按钮的图标
|
|
||||||
expandBtnIcon: {
|
|
||||||
open: '',// svg字符串
|
|
||||||
close: ''
|
|
||||||
},
|
|
||||||
// 是否只有当鼠标在画布内才响应快捷键事件
|
|
||||||
enableShortcutOnlyWhenMouseInSvg: true,
|
|
||||||
// 是否开启节点动画过渡
|
|
||||||
enableNodeTransitionMove: true,
|
|
||||||
// 如果开启节点动画过渡,可以通过该属性设置过渡的时间,单位ms
|
|
||||||
nodeTransitionMoveDuration: 300,
|
|
||||||
// 初始根节点的位置
|
|
||||||
initRootNodePosition: null,
|
|
||||||
// 导出png、svg、pdf时的图形内边距
|
|
||||||
exportPaddingX: 10,
|
|
||||||
exportPaddingY: 10,
|
|
||||||
// 节点文本编辑框的z-index
|
|
||||||
nodeTextEditZIndex: 3000,
|
|
||||||
// 节点备注浮层的z-index
|
|
||||||
nodeNoteTooltipZIndex: 3000,
|
|
||||||
// 是否在点击了画布外的区域时结束节点文本的编辑状态
|
|
||||||
isEndNodeTextEditOnClickOuter: true,
|
|
||||||
// 最大历史记录数
|
|
||||||
maxHistoryCount: 1000,
|
|
||||||
// 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示
|
|
||||||
alwaysShowExpandBtn: false,
|
|
||||||
// 扩展节点可插入的图标
|
|
||||||
iconList: [
|
|
||||||
// {
|
|
||||||
// name: '',// 分组名称
|
|
||||||
// type: '',// 分组的值
|
|
||||||
// list: [// 分组下的图标列表
|
|
||||||
// {
|
|
||||||
// name: '',// 图标名称
|
|
||||||
// icon:''// 图标,可以传svg或图片
|
|
||||||
// }
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
],
|
|
||||||
// 节点最大缓存数量
|
|
||||||
maxNodeCacheCount: 1000,
|
|
||||||
// 关联线默认文字
|
|
||||||
defaultAssociativeLineText: '关联',
|
|
||||||
// 思维导图适应画布大小时的内边距
|
|
||||||
fitPadding: 50,
|
|
||||||
// 是否开启按住ctrl键多选节点功能
|
|
||||||
enableCtrlKeyNodeSelection: true,
|
|
||||||
// 设置为左键多选节点,右键拖动画布
|
|
||||||
useLeftKeySelectionRightKeyDrag: false,
|
|
||||||
// 节点即将进入编辑前的回调方法,如果该方法返回true以外的值,那么将取消编辑,函数可以返回一个值,或一个Promise,回调参数为节点实例
|
|
||||||
beforeTextEdit: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// 思维导图
|
// 思维导图
|
||||||
class MindMap {
|
class MindMap {
|
||||||
|
|||||||
126
simple-mind-map/src/constants/defaultOptions.js
Normal file
126
simple-mind-map/src/constants/defaultOptions.js
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import { CONSTANTS } from './constant'
|
||||||
|
|
||||||
|
// 默认选项配置
|
||||||
|
export const defaultOpt = {
|
||||||
|
// 是否只读
|
||||||
|
readonly: false,
|
||||||
|
// 布局
|
||||||
|
layout: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
|
||||||
|
// 如果结构为鱼骨图,那么可以通过该选项控制倾斜角度
|
||||||
|
fishboneDeg: 45,
|
||||||
|
// 主题
|
||||||
|
theme: 'default', // 内置主题:default(默认主题)
|
||||||
|
// 主题配置,会和所选择的主题进行合并
|
||||||
|
themeConfig: {},
|
||||||
|
// 放大缩小的增量比例
|
||||||
|
scaleRatio: 0.1,
|
||||||
|
// 最多显示几个标签
|
||||||
|
maxTag: 5,
|
||||||
|
// 导出图片时的内边距
|
||||||
|
exportPadding: 20,
|
||||||
|
// 展开收缩按钮尺寸
|
||||||
|
expandBtnSize: 20,
|
||||||
|
// 节点里图片和文字的间距
|
||||||
|
imgTextMargin: 5,
|
||||||
|
// 节点里各种文字信息的间距,如图标和文字的间距
|
||||||
|
textContentMargin: 2,
|
||||||
|
// 多选节点时鼠标移动到边缘时的画布移动偏移量
|
||||||
|
selectTranslateStep: 3,
|
||||||
|
// 多选节点时鼠标移动距边缘多少距离时开始偏移
|
||||||
|
selectTranslateLimit: 20,
|
||||||
|
// 自定义节点备注内容显示
|
||||||
|
customNoteContentShow: null,
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
show(){},
|
||||||
|
hide(){}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// 是否开启节点自由拖拽
|
||||||
|
enableFreeDrag: false,
|
||||||
|
// 水印配置
|
||||||
|
watermarkConfig: {
|
||||||
|
text: '',
|
||||||
|
lineSpacing: 100,
|
||||||
|
textSpacing: 100,
|
||||||
|
angle: 30,
|
||||||
|
textStyle: {
|
||||||
|
color: '#999',
|
||||||
|
opacity: 0.5,
|
||||||
|
fontSize: 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 达到该宽度文本自动换行
|
||||||
|
textAutoWrapWidth: 500,
|
||||||
|
// 自定义鼠标滚轮事件处理
|
||||||
|
// 可以传一个函数,回调参数为事件对象
|
||||||
|
customHandleMousewheel: null,
|
||||||
|
// 鼠标滚动的行为,如果customHandleMousewheel传了自定义函数,这个属性不生效
|
||||||
|
mousewheelAction: CONSTANTS.MOUSE_WHEEL_ACTION.ZOOM, // zoom(放大缩小)、move(上下移动)
|
||||||
|
// 当mousewheelAction设为move时,可以通过该属性控制鼠标滚动一下视图移动的步长,单位px
|
||||||
|
mousewheelMoveStep: 100,
|
||||||
|
// 默认插入的二级节点的文字
|
||||||
|
defaultInsertSecondLevelNodeText: '二级节点',
|
||||||
|
// 默认插入的二级以下节点的文字
|
||||||
|
defaultInsertBelowSecondLevelNodeText: '分支主题',
|
||||||
|
// 展开收起按钮的颜色
|
||||||
|
expandBtnStyle: {
|
||||||
|
color: '#808080',
|
||||||
|
fill: '#fff'
|
||||||
|
},
|
||||||
|
// 自定义展开收起按钮的图标
|
||||||
|
expandBtnIcon: {
|
||||||
|
open: '', // svg字符串
|
||||||
|
close: ''
|
||||||
|
},
|
||||||
|
// 是否只有当鼠标在画布内才响应快捷键事件
|
||||||
|
enableShortcutOnlyWhenMouseInSvg: true,
|
||||||
|
// 是否开启节点动画过渡
|
||||||
|
enableNodeTransitionMove: true,
|
||||||
|
// 如果开启节点动画过渡,可以通过该属性设置过渡的时间,单位ms
|
||||||
|
nodeTransitionMoveDuration: 300,
|
||||||
|
// 初始根节点的位置
|
||||||
|
initRootNodePosition: null,
|
||||||
|
// 导出png、svg、pdf时的图形内边距
|
||||||
|
exportPaddingX: 10,
|
||||||
|
exportPaddingY: 10,
|
||||||
|
// 节点文本编辑框的z-index
|
||||||
|
nodeTextEditZIndex: 3000,
|
||||||
|
// 节点备注浮层的z-index
|
||||||
|
nodeNoteTooltipZIndex: 3000,
|
||||||
|
// 是否在点击了画布外的区域时结束节点文本的编辑状态
|
||||||
|
isEndNodeTextEditOnClickOuter: true,
|
||||||
|
// 最大历史记录数
|
||||||
|
maxHistoryCount: 1000,
|
||||||
|
// 是否一直显示节点的展开收起按钮,默认为鼠标移上去和激活时才显示
|
||||||
|
alwaysShowExpandBtn: false,
|
||||||
|
// 扩展节点可插入的图标
|
||||||
|
iconList: [
|
||||||
|
// {
|
||||||
|
// name: '',// 分组名称
|
||||||
|
// type: '',// 分组的值
|
||||||
|
// list: [// 分组下的图标列表
|
||||||
|
// {
|
||||||
|
// name: '',// 图标名称
|
||||||
|
// icon:''// 图标,可以传svg或图片
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
],
|
||||||
|
// 节点最大缓存数量
|
||||||
|
maxNodeCacheCount: 1000,
|
||||||
|
// 关联线默认文字
|
||||||
|
defaultAssociativeLineText: '关联',
|
||||||
|
// 思维导图适应画布大小时的内边距
|
||||||
|
fitPadding: 50,
|
||||||
|
// 是否开启按住ctrl键多选节点功能
|
||||||
|
enableCtrlKeyNodeSelection: true,
|
||||||
|
// 设置为左键多选节点,右键拖动画布
|
||||||
|
useLeftKeySelectionRightKeyDrag: false,
|
||||||
|
// 节点即将进入编辑前的回调方法,如果该方法返回true以外的值,那么将取消编辑,函数可以返回一个值,或一个Promise,回调参数为节点实例
|
||||||
|
beforeTextEdit: null,
|
||||||
|
// 是否开启自定义节点内容
|
||||||
|
isUseCustomNodeContent: false,
|
||||||
|
// 自定义返回节点内容的方法
|
||||||
|
customCreateNodeContent: null
|
||||||
|
}
|
||||||
@ -66,10 +66,15 @@ export default class TextEdit {
|
|||||||
|
|
||||||
// 显示文本编辑框
|
// 显示文本编辑框
|
||||||
async show(node) {
|
async show(node) {
|
||||||
if (typeof this.mindMap.opt.beforeTextEdit === 'function') {
|
// 使用了自定义节点内容那么不响应编辑事件
|
||||||
|
if (node.isUseCustomNodeContent()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let { beforeTextEdit } = this.mindMap.opt
|
||||||
|
if (typeof beforeTextEdit === 'function') {
|
||||||
let isShow = false
|
let isShow = false
|
||||||
try {
|
try {
|
||||||
isShow = await this.mindMap.opt.beforeTextEdit(node)
|
isShow = await beforeTextEdit(node)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
isShow = false
|
isShow = false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import Style from './Style'
|
import Style from './Style'
|
||||||
import Shape from './Shape'
|
import Shape from './Shape'
|
||||||
import { asyncRun } from '../../../utils'
|
import { asyncRun, nodeToHTML } from '../../../utils'
|
||||||
import { G, Rect } from '@svgdotjs/svg.js'
|
import { G, Rect, ForeignObject, SVG } from '@svgdotjs/svg.js'
|
||||||
import nodeGeneralizationMethods from './nodeGeneralization'
|
import nodeGeneralizationMethods from './nodeGeneralization'
|
||||||
import nodeExpandBtnMethods from './nodeExpandBtn'
|
import nodeExpandBtnMethods from './nodeExpandBtn'
|
||||||
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
||||||
@ -59,6 +59,7 @@ class Node {
|
|||||||
this.group = null
|
this.group = null
|
||||||
this.shapeNode = null // 节点形状节点
|
this.shapeNode = null // 节点形状节点
|
||||||
// 节点内容对象
|
// 节点内容对象
|
||||||
|
this._customNodeContent = null
|
||||||
this._imgData = null
|
this._imgData = null
|
||||||
this._iconData = null
|
this._iconData = null
|
||||||
this._textData = null
|
this._textData = null
|
||||||
@ -154,6 +155,13 @@ class Node {
|
|||||||
|
|
||||||
// 创建节点的各个内容对象数据
|
// 创建节点的各个内容对象数据
|
||||||
createNodeData() {
|
createNodeData() {
|
||||||
|
// 自定义节点内容
|
||||||
|
let { isUseCustomNodeContent, customCreateNodeContent } = this.mindMap.opt
|
||||||
|
if (isUseCustomNodeContent && customCreateNodeContent) {
|
||||||
|
this._customNodeContent = customCreateNodeContent(this)
|
||||||
|
}
|
||||||
|
// 如果没有返回内容,那么还是使用内置的节点内容
|
||||||
|
if (this._customNodeContent) return
|
||||||
this._imgData = this.createImgNode()
|
this._imgData = this.createImgNode()
|
||||||
this._iconData = this.createIconNode()
|
this._iconData = this.createIconNode()
|
||||||
this._textData = this.createTextNode()
|
this._textData = this.createTextNode()
|
||||||
@ -176,6 +184,14 @@ class Node {
|
|||||||
|
|
||||||
// 计算节点尺寸信息
|
// 计算节点尺寸信息
|
||||||
getNodeRect() {
|
getNodeRect() {
|
||||||
|
// 自定义节点内容
|
||||||
|
if (this.isUseCustomNodeContent()) {
|
||||||
|
let rect = this.measureCustomNodeContentSize(this._customNodeContent)
|
||||||
|
return {
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height
|
||||||
|
}
|
||||||
|
}
|
||||||
// 宽高
|
// 宽高
|
||||||
let imgContentWidth = 0
|
let imgContentWidth = 0
|
||||||
let imgContentHeight = 0
|
let imgContentHeight = 0
|
||||||
@ -266,6 +282,15 @@ class Node {
|
|||||||
if (this.isGeneralization && this.generalizationBelongNode) {
|
if (this.isGeneralization && this.generalizationBelongNode) {
|
||||||
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
this.group.addClass('generalization_' + this.generalizationBelongNode.uid)
|
||||||
}
|
}
|
||||||
|
// 如果存在自定义节点内容,那么使用自定义节点内容
|
||||||
|
if (this.isUseCustomNodeContent()) {
|
||||||
|
let foreignObject = new ForeignObject()
|
||||||
|
foreignObject.width(width)
|
||||||
|
foreignObject.height(height)
|
||||||
|
foreignObject.add(SVG(this._customNodeContent))
|
||||||
|
this.group.add(foreignObject)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 图片节点
|
// 图片节点
|
||||||
let imgHeight = 0
|
let imgHeight = 0
|
||||||
if (this._imgData) {
|
if (this._imgData) {
|
||||||
|
|||||||
@ -280,6 +280,32 @@ function createNoteNode() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 测量自定义节点内容元素的宽高
|
||||||
|
let warpEl = null
|
||||||
|
function measureCustomNodeContentSize (content) {
|
||||||
|
if (!warpEl) {
|
||||||
|
warpEl = document.createElement('div')
|
||||||
|
warpEl.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
left: -99999px;
|
||||||
|
top: -99999px;
|
||||||
|
`
|
||||||
|
this.mindMap.el.appendChild(warpEl)
|
||||||
|
}
|
||||||
|
warpEl.innerHTML = ''
|
||||||
|
warpEl.appendChild(content)
|
||||||
|
let rect = warpEl.getBoundingClientRect()
|
||||||
|
return {
|
||||||
|
width: rect.width,
|
||||||
|
height: rect.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 是否使用的是自定义节点内容
|
||||||
|
function isUseCustomNodeContent() {
|
||||||
|
return !!this._customNodeContent
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
createImgNode,
|
createImgNode,
|
||||||
getImgShowSize,
|
getImgShowSize,
|
||||||
@ -288,5 +314,7 @@ export default {
|
|||||||
createTextNode,
|
createTextNode,
|
||||||
createHyperlinkNode,
|
createHyperlinkNode,
|
||||||
createTagNode,
|
createTagNode,
|
||||||
createNoteNode
|
createNoteNode,
|
||||||
|
measureCustomNodeContentSize,
|
||||||
|
isUseCustomNodeContent
|
||||||
}
|
}
|
||||||
@ -357,3 +357,14 @@ export const readBlob = (blob) => {
|
|||||||
reader.readAsDataURL(blob)
|
reader.readAsDataURL(blob)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将dom节点转换成html字符串
|
||||||
|
let nodeToHTMLWrapEl = null
|
||||||
|
export const nodeToHTML = (node) => {
|
||||||
|
if (!nodeToHTMLWrapEl) {
|
||||||
|
nodeToHTMLWrapEl = document.createElement('div')
|
||||||
|
}
|
||||||
|
nodeToHTMLWrapEl.innerHTML = ''
|
||||||
|
nodeToHTMLWrapEl.appendChild(node)
|
||||||
|
return nodeToHTMLWrapEl.innerHTML
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user