Feat:节点增加鼠标滑过效果、节点激活效果重构、去除激活样式改变功能
This commit is contained in:
parent
b35dd282ec
commit
a24f7a73c8
@ -11,7 +11,8 @@ import {
|
|||||||
layoutValueList,
|
layoutValueList,
|
||||||
CONSTANTS,
|
CONSTANTS,
|
||||||
commonCaches,
|
commonCaches,
|
||||||
ERROR_TYPES
|
ERROR_TYPES,
|
||||||
|
cssContent
|
||||||
} from './src/constants/constant'
|
} from './src/constants/constant'
|
||||||
import { SVG } from '@svgdotjs/svg.js'
|
import { SVG } from '@svgdotjs/svg.js'
|
||||||
import { simpleDeepClone, getType } from './src/utils'
|
import { simpleDeepClone, getType } from './src/utils'
|
||||||
@ -37,6 +38,10 @@ class MindMap {
|
|||||||
this.height = this.elRect.height
|
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)
|
this.svg = SVG().addTo(this.el).size(this.width, this.height)
|
||||||
this.draw = this.svg.group()
|
this.draw = this.svg.group()
|
||||||
@ -101,6 +106,19 @@ class MindMap {
|
|||||||
return opt
|
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 = '') {
|
render(callback, source = '') {
|
||||||
this.batchExecution.push('render', () => {
|
this.batchExecution.push('render', () => {
|
||||||
@ -419,6 +437,7 @@ class MindMap {
|
|||||||
Style.removeBackgroundStyle(this.el)
|
Style.removeBackgroundStyle(this.el)
|
||||||
this.el.innerHTML = ''
|
this.el.innerHTML = ''
|
||||||
this.el = null
|
this.el = null
|
||||||
|
this.removeCss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -349,3 +349,23 @@ export const a4Size = {
|
|||||||
width: 592.28,
|
width: 592.28,
|
||||||
height: 841.89
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
@ -168,5 +168,7 @@ export const defaultOpt = {
|
|||||||
// 开启鼠标双击复位思维导图位置及缩放
|
// 开启鼠标双击复位思维导图位置及缩放
|
||||||
enableDblclickReset: true,
|
enableDblclickReset: true,
|
||||||
// 导出图片时canvas的缩放倍数,该配置会和window.devicePixelRatio值取最大值
|
// 导出图片时canvas的缩放倍数,该配置会和window.devicePixelRatio值取最大值
|
||||||
minExportImgCanvasScale: 2
|
minExportImgCanvasScale: 2,
|
||||||
|
// 节点鼠标hover和激活时显示的矩形边框颜色
|
||||||
|
hoverRectColor: 'rgb(94, 200, 248)'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -407,7 +407,7 @@ class Render {
|
|||||||
// 激活节点需要显示展开收起按钮
|
// 激活节点需要显示展开收起按钮
|
||||||
node.showExpandBtn()
|
node.showExpandBtn()
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
node.updateNodeShape()
|
node.updateNodeActive()
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1000,7 +1000,7 @@ class Render {
|
|||||||
} else {
|
} else {
|
||||||
node.hideExpandBtn()
|
node.hideExpandBtn()
|
||||||
}
|
}
|
||||||
node.updateNodeShape()
|
node.updateNodeActive()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置节点是否展开
|
// 设置节点是否展开
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Style from './Style'
|
import Style from './Style'
|
||||||
import Shape from './Shape'
|
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 nodeGeneralizationMethods from './nodeGeneralization'
|
||||||
import nodeExpandBtnMethods from './nodeExpandBtn'
|
import nodeExpandBtnMethods from './nodeExpandBtn'
|
||||||
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
import nodeCommandWrapsMethods from './nodeCommandWraps'
|
||||||
@ -58,6 +58,7 @@ class Node {
|
|||||||
// 节点内容的容器
|
// 节点内容的容器
|
||||||
this.group = null
|
this.group = null
|
||||||
this.shapeNode = null // 节点形状节点
|
this.shapeNode = null // 节点形状节点
|
||||||
|
this.hoverNode = null // 节点hover和激活的节点
|
||||||
// 节点内容对象
|
// 节点内容对象
|
||||||
this._customNodeContent = null
|
this._customNodeContent = null
|
||||||
this._imgData = null
|
this._imgData = null
|
||||||
@ -277,8 +278,8 @@ class Node {
|
|||||||
this.shapeNode = this.shapeInstance.createShape()
|
this.shapeNode = this.shapeInstance.createShape()
|
||||||
this.shapeNode.addClass('smm-node-shape')
|
this.shapeNode.addClass('smm-node-shape')
|
||||||
this.shapeNode.translate(halfBorderWidth, halfBorderWidth)
|
this.shapeNode.translate(halfBorderWidth, halfBorderWidth)
|
||||||
|
this.style.shape(this.shapeNode)
|
||||||
this.group.add(this.shapeNode)
|
this.group.add(this.shapeNode)
|
||||||
this.updateNodeShape()
|
|
||||||
// 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示
|
// 渲染一个隐藏的矩形区域,用来触发展开收起按钮的显示
|
||||||
this.renderExpandBtnPlaceholderRect()
|
this.renderExpandBtnPlaceholderRect()
|
||||||
// 概要节点添加一个带所属节点id的类名
|
// 概要节点添加一个带所属节点id的类名
|
||||||
@ -365,6 +366,11 @@ class Node {
|
|||||||
: 0)
|
: 0)
|
||||||
)
|
)
|
||||||
this.group.add(textContentNested)
|
this.group.add(textContentNested)
|
||||||
|
// 激活hover和激活边框
|
||||||
|
this.hoverNode = new Rect()
|
||||||
|
this.hoverNode.addClass('smm-hover-node')
|
||||||
|
this.style.hoverNode(this.hoverNode, width, height)
|
||||||
|
this.group.add(this.hoverNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 给节点绑定事件
|
// 给节点绑定事件
|
||||||
@ -467,10 +473,11 @@ class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新节点
|
// 更新节点
|
||||||
update(isLayout = false) {
|
update() {
|
||||||
if (!this.group) {
|
if (!this.group) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
this.updateNodeActive()
|
||||||
let { alwaysShowExpandBtn } = this.mindMap.opt
|
let { alwaysShowExpandBtn } = this.mindMap.opt
|
||||||
if (alwaysShowExpandBtn) {
|
if (alwaysShowExpandBtn) {
|
||||||
// 需要移除展开收缩按钮
|
// 需要移除展开收缩按钮
|
||||||
@ -543,13 +550,11 @@ class Node {
|
|||||||
return sizeChange
|
return sizeChange
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新节点形状样式
|
// 更新节点激活状态
|
||||||
updateNodeShape() {
|
updateNodeActive() {
|
||||||
if (!this.shapeNode) return
|
if (!this.group) return
|
||||||
const shape = this.getShape()
|
const isActive = this.nodeData.data.isActive
|
||||||
this.style[shape === CONSTANTS.SHAPE.RECTANGLE ? 'rect' : 'shape'](
|
this.group[isActive ? 'addClass' : 'removeClass']('active')
|
||||||
this.shapeNode
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归渲染
|
// 递归渲染
|
||||||
@ -557,9 +562,7 @@ class Node {
|
|||||||
// 节点
|
// 节点
|
||||||
// 重新渲染连线
|
// 重新渲染连线
|
||||||
this.renderLine()
|
this.renderLine()
|
||||||
let isLayout = false
|
|
||||||
if (!this.group) {
|
if (!this.group) {
|
||||||
isLayout = true
|
|
||||||
// 创建组
|
// 创建组
|
||||||
this.group = new G()
|
this.group = new G()
|
||||||
this.group.addClass('smm-node')
|
this.group.addClass('smm-node')
|
||||||
@ -569,7 +572,7 @@ class Node {
|
|||||||
this.bindGroupEvent()
|
this.bindGroupEvent()
|
||||||
this.draw.add(this.group)
|
this.draw.add(this.group)
|
||||||
this.layout()
|
this.layout()
|
||||||
this.update(isLayout)
|
this.update()
|
||||||
} else {
|
} else {
|
||||||
this.draw.add(this.group)
|
this.draw.add(this.group)
|
||||||
if (this.needLayout) {
|
if (this.needLayout) {
|
||||||
@ -803,8 +806,8 @@ class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取某个样式
|
// 获取某个样式
|
||||||
getStyle(prop, root, isActive) {
|
getStyle(prop, root) {
|
||||||
let v = this.style.merge(prop, root, isActive)
|
let v = this.style.merge(prop, root)
|
||||||
return v === undefined ? '' : v
|
return v === undefined ? '' : v
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -833,7 +836,7 @@ class Node {
|
|||||||
|
|
||||||
// 获取节点非节点状态的边框大小
|
// 获取节点非节点状态的边框大小
|
||||||
getBorderWidth() {
|
getBorderWidth() {
|
||||||
return this.style.merge('borderWidth', false, false) || 0
|
return this.style.merge('borderWidth', false) || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取数据
|
// 获取数据
|
||||||
|
|||||||
@ -69,7 +69,8 @@ export default class Shape {
|
|||||||
let node = null
|
let node = null
|
||||||
// 矩形
|
// 矩形
|
||||||
if (shape === CONSTANTS.SHAPE.RECTANGLE) {
|
if (shape === CONSTANTS.SHAPE.RECTANGLE) {
|
||||||
node = new Rect().size(width, height)
|
// node = new Rect().size(width, height)
|
||||||
|
node = this.createRect()
|
||||||
} else if (shape === CONSTANTS.SHAPE.DIAMOND) {
|
} else if (shape === CONSTANTS.SHAPE.DIAMOND) {
|
||||||
// 菱形
|
// 菱形
|
||||||
node = this.createDiamond()
|
node = this.createDiamond()
|
||||||
@ -98,6 +99,19 @@ export default class Shape {
|
|||||||
return node
|
return node
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 创建矩形TODO
|
||||||
|
createRect() {
|
||||||
|
let { width, height } = this.node
|
||||||
|
let borderRadius = this.node.style.merge('borderRadius')
|
||||||
|
return new Path().plot(`
|
||||||
|
M${0},0
|
||||||
|
L${width},0
|
||||||
|
L${width},${height}
|
||||||
|
L${0},${height}
|
||||||
|
L${0},${0}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|
||||||
// 创建菱形
|
// 创建菱形
|
||||||
createDiamond() {
|
createDiamond() {
|
||||||
let { width, height } = this.node
|
let { width, height } = this.node
|
||||||
|
|||||||
@ -42,7 +42,7 @@ class Style {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 合并样式
|
// 合并样式
|
||||||
merge(prop, root, isActive) {
|
merge(prop, root) {
|
||||||
let themeConfig = this.ctx.mindMap.themeConfig
|
let themeConfig = this.ctx.mindMap.themeConfig
|
||||||
// 三级及以下节点
|
// 三级及以下节点
|
||||||
let defaultConfig = themeConfig.node
|
let defaultConfig = themeConfig.node
|
||||||
@ -59,17 +59,6 @@ class Style {
|
|||||||
// 二级节点
|
// 二级节点
|
||||||
defaultConfig = themeConfig.second
|
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
|
return this.getSelfStyle(prop) !== undefined
|
||||||
? this.getSelfStyle(prop)
|
? this.getSelfStyle(prop)
|
||||||
@ -77,8 +66,8 @@ class Style {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取某个样式值
|
// 获取某个样式值
|
||||||
getStyle(prop, root, isActive) {
|
getStyle(prop, root) {
|
||||||
return this.merge(prop, root, isActive)
|
return this.merge(prop, root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取自身自定义样式
|
// 获取自身自定义样式
|
||||||
@ -220,6 +209,20 @@ class Style {
|
|||||||
})
|
})
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hover和激活节点
|
||||||
|
hoverNode(node, width, height) {
|
||||||
|
const { hoverRectColor } = this.ctx.mindMap.opt
|
||||||
|
node
|
||||||
|
.size(width + 0, height + 0)
|
||||||
|
.x(-0)
|
||||||
|
.y(-0)
|
||||||
|
.radius(5)
|
||||||
|
.fill('none')
|
||||||
|
.stroke({
|
||||||
|
color: hoverRectColor
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Style.cacheStyle = null
|
Style.cacheStyle = null
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user