Feat:新增向左逻辑结构图

This commit is contained in:
街角小林 2024-07-02 11:46:03 +08:00
parent c23a16e65a
commit b45674cf8f
4 changed files with 99 additions and 26 deletions

View File

@ -174,6 +174,7 @@ export const CONSTANTS = {
}, },
LAYOUT: { LAYOUT: {
LOGICAL_STRUCTURE: 'logicalStructure', LOGICAL_STRUCTURE: 'logicalStructure',
LOGICAL_STRUCTURE_LEFT: 'logicalStructureLeft',
MIND_MAP: 'mindMap', MIND_MAP: 'mindMap',
ORGANIZATION_STRUCTURE: 'organizationStructure', ORGANIZATION_STRUCTURE: 'organizationStructure',
CATALOG_ORGANIZATION: 'catalogOrganization', CATALOG_ORGANIZATION: 'catalogOrganization',
@ -251,6 +252,10 @@ export const layoutList = [
name: '逻辑结构图', name: '逻辑结构图',
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE
}, },
{
name: '向左逻辑结构图',
value: CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT
},
{ {
name: '思维导图', name: '思维导图',
value: CONSTANTS.LAYOUT.MIND_MAP value: CONSTANTS.LAYOUT.MIND_MAP
@ -282,6 +287,7 @@ export const layoutList = [
] ]
export const layoutValueList = [ export const layoutValueList = [
CONSTANTS.LAYOUT.LOGICAL_STRUCTURE, CONSTANTS.LAYOUT.LOGICAL_STRUCTURE,
CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT,
CONSTANTS.LAYOUT.MIND_MAP, CONSTANTS.LAYOUT.MIND_MAP,
CONSTANTS.LAYOUT.CATALOG_ORGANIZATION, CONSTANTS.LAYOUT.CATALOG_ORGANIZATION,
CONSTANTS.LAYOUT.ORGANIZATION_STRUCTURE, CONSTANTS.LAYOUT.ORGANIZATION_STRUCTURE,

View File

@ -42,6 +42,8 @@ import { Polygon } from '@svgdotjs/svg.js'
const layouts = { const layouts = {
// 逻辑结构图 // 逻辑结构图
[CONSTANTS.LAYOUT.LOGICAL_STRUCTURE]: LogicalStructure, [CONSTANTS.LAYOUT.LOGICAL_STRUCTURE]: LogicalStructure,
// 向左逻辑结构图
[CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT]: LogicalStructure,
// 思维导图 // 思维导图
[CONSTANTS.LAYOUT.MIND_MAP]: MindMap, [CONSTANTS.LAYOUT.MIND_MAP]: MindMap,
// 目录组织图 // 目录组织图

View File

@ -1,11 +1,13 @@
import Base from './Base' import Base from './Base'
import { walk, asyncRun, getNodeIndexInNodeList } from '../utils' import { walk, asyncRun, getNodeIndexInNodeList } from '../utils'
import { CONSTANTS } from '../constants/constant'
// 逻辑结构图 // 逻辑结构图
class LogicalStructure extends Base { class LogicalStructure extends Base {
// 构造函数 // 构造函数
constructor(opt = {}) { constructor(opt = {}, layout) {
super(opt) super(opt)
this.isUseLeft = layout === CONSTANTS.LAYOUT.LOGICAL_STRUCTURE_LEFT
} }
// 布局 // 布局
@ -40,8 +42,15 @@ class LogicalStructure extends Base {
} else { } else {
// 非根节点 // 非根节点
// 定位到父节点右侧 // 定位到父节点右侧
newNode.left = if (this.isUseLeft) {
parent._node.left + parent._node.width + this.getMarginX(layerIndex) newNode.left =
parent._node.left - newNode.width - this.getMarginX(layerIndex)
} else {
newNode.left =
parent._node.left +
parent._node.width +
this.getMarginX(layerIndex)
}
} }
if (!cur.data.expand) { if (!cur.data.expand) {
return true return true
@ -167,15 +176,24 @@ class LogicalStructure extends Base {
} }
let marginX = this.getMarginX(node.layerIndex + 1) let marginX = this.getMarginX(node.layerIndex + 1)
let s1 = (marginX - expandBtnSize) * 0.6 let s1 = (marginX - expandBtnSize) * 0.6
if (this.isUseLeft) {
s1 *= -1
}
let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle let nodeUseLineStyle = this.mindMap.themeConfig.nodeUseLineStyle
node.children.forEach((item, index) => { node.children.forEach((item, index) => {
let x1 = let x1
node.layerIndex === 0 ? left + width : left + width + expandBtnSize if (this.isUseLeft) {
x1 = node.layerIndex === 0 ? left : left - expandBtnSize
} else {
x1 = node.layerIndex === 0 ? left + width : left + width + expandBtnSize
}
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = this.isUseLeft ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
// 节点使用横线风格,需要额外渲染横线 // 节点使用横线风格,需要额外渲染横线
let nodeUseLineStyleOffset = nodeUseLineStyle ? item.width : 0 let nodeUseLineStyleOffset = nodeUseLineStyle
? item.width * (this.isUseLeft ? -1 : 1)
: 0
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1 y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2 y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
let path = this.createFoldLine([ let path = this.createFoldLine([
@ -202,15 +220,17 @@ class LogicalStructure extends Base {
if (node.layerIndex === 0) { if (node.layerIndex === 0) {
expandBtnSize = 0 expandBtnSize = 0
} }
let x1 = left + width + expandBtnSize let x1 = this.isUseLeft
? left - expandBtnSize
: left + width + expandBtnSize
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = this.isUseLeft ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1 y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2 y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
// 节点使用横线风格,需要额外渲染横线 // 节点使用横线风格,需要额外渲染横线
let nodeUseLineStylePath = nodeUseLineStyle let nodeUseLineStylePath = nodeUseLineStyle
? ` L ${item.left + item.width},${y2}` ? ` L ${this.isUseLeft ? item.left : item.left + item.width},${y2}`
: '' : ''
let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath
this.setLineStyle(style, lines[index], path, item) this.setLineStyle(style, lines[index], path, item)
@ -235,20 +255,33 @@ class LogicalStructure extends Base {
if (node.layerIndex === 0) { if (node.layerIndex === 0) {
expandBtnSize = 0 expandBtnSize = 0
} }
let x1 = let x1
node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve if (this.isUseLeft) {
? left + width / 2 x1 =
: left + width + expandBtnSize node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve
? left + width / 2
: left - expandBtnSize
} else {
x1 =
node.layerIndex === 0 && !rootLineStartPositionKeepSameInCurve
? left + width / 2
: left + width + expandBtnSize
}
let y1 = top + height / 2 let y1 = top + height / 2
let x2 = item.left let x2 = this.isUseLeft ? item.left + item.width : item.left
let y2 = item.top + item.height / 2 let y2 = item.top + item.height / 2
let path = '' let path = ''
y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1 y1 = nodeUseLineStyle && !node.isRoot ? y1 + height / 2 : y1
y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2 y2 = nodeUseLineStyle ? y2 + item.height / 2 : y2
// 节点使用横线风格,需要额外渲染横线 // 节点使用横线风格,需要额外渲染横线
let nodeUseLineStylePath = nodeUseLineStyle let nodeUseLineStylePath
? ` L ${item.left + item.width},${y2}` if (this.isUseLeft) {
: '' nodeUseLineStylePath = nodeUseLineStyle ? ` L ${item.left},${y2}` : ''
} else {
nodeUseLineStylePath = nodeUseLineStyle
? ` L ${item.left + item.width},${y2}`
: ''
}
if (node.isRoot && !rootLineKeepSameInCurve) { if (node.isRoot && !rootLineKeepSameInCurve) {
path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath path = this.quadraticCurvePath(x1, y1, x2, y2) + nodeUseLineStylePath
} else { } else {
@ -260,14 +293,17 @@ class LogicalStructure extends Base {
// 渲染按钮 // 渲染按钮
renderExpandBtn(node, btn) { renderExpandBtn(node, btn) {
let { width, height } = node let { width, height, expandBtnSize, layerIndex } = node
if (layerIndex === 0) {
expandBtnSize = 0
}
let { translateX, translateY } = btn.transform() let { translateX, translateY } = btn.transform()
// 节点使用横线风格,需要调整展开收起按钮位置 // 节点使用横线风格,需要调整展开收起按钮位置
let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle let nodeUseLineStyleOffset = this.mindMap.themeConfig.nodeUseLineStyle
? height / 2 ? height / 2
: 0 : 0
// 位置没有变化则返回 // 位置没有变化则返回
let _x = width let _x = this.isUseLeft ? 0 - expandBtnSize : width
let _y = height / 2 + nodeUseLineStyleOffset let _y = height / 2 + nodeUseLineStyleOffset
if (_x === translateX && _y === translateY) { if (_x === translateX && _y === translateY) {
return return
@ -279,29 +315,42 @@ class LogicalStructure extends Base {
renderGeneralization(list) { renderGeneralization(list) {
list.forEach(item => { list.forEach(item => {
let { let {
left,
top, top,
bottom, bottom,
right, right,
generalizationLineMargin, generalizationLineMargin,
generalizationNodeMargin generalizationNodeMargin
} = this.getNodeGeneralizationRenderBoundaries(item, 'h') } = this.getNodeGeneralizationRenderBoundaries(item, 'h')
let x1 = right + generalizationLineMargin let x = this.isUseLeft
? left - generalizationLineMargin
: right + generalizationLineMargin
let x1 = x
let y1 = top let y1 = top
let x2 = right + generalizationLineMargin let x2 = x
let y2 = bottom let y2 = bottom
let cx = x1 + 20 let cx = x1 + (this.isUseLeft ? -20 : 20)
let cy = y1 + (y2 - y1) / 2 let cy = y1 + (y2 - y1) / 2
let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}`
item.generalizationLine.plot(path) item.generalizationLine.plot(path)
item.generalizationNode.left = right + generalizationNodeMargin item.generalizationNode.left =
x +
(this.isUseLeft
? -generalizationNodeMargin
: generalizationNodeMargin) -
(this.isUseLeft ? item.generalizationNode.width : 0)
item.generalizationNode.top = item.generalizationNode.top =
top + (bottom - top - item.generalizationNode.height) / 2 top + (bottom - top - item.generalizationNode.height) / 2
}) })
} }
// 渲染展开收起按钮的隐藏占位元素 // 渲染展开收起按钮的隐藏占位元素
renderExpandBtnRect(rect, expandBtnSize, width, height, node) { renderExpandBtnRect(rect, expandBtnSize, width, height) {
rect.size(expandBtnSize, height).x(width).y(0) if (this.isUseLeft) {
rect.size(expandBtnSize, height).x(-expandBtnSize).y(0)
} else {
rect.size(expandBtnSize, height).x(width).y(0)
}
} }
} }

View File

@ -397,6 +397,7 @@ class Drag extends Base {
} }
const { const {
LOGICAL_STRUCTURE, LOGICAL_STRUCTURE,
LOGICAL_STRUCTURE_LEFT,
MIND_MAP, MIND_MAP,
ORGANIZATION_STRUCTURE, ORGANIZATION_STRUCTURE,
CATALOG_ORGANIZATION, CATALOG_ORGANIZATION,
@ -420,6 +421,7 @@ class Drag extends Base {
} }
switch (this.mindMap.opt.layout) { switch (this.mindMap.opt.layout) {
case LOGICAL_STRUCTURE: case LOGICAL_STRUCTURE:
case LOGICAL_STRUCTURE_LEFT:
this.handleLogicalStructure(node) this.handleLogicalStructure(node)
break break
case MIND_MAP: case MIND_MAP:
@ -457,6 +459,7 @@ class Drag extends Base {
handleOverlapNode() { handleOverlapNode() {
const { const {
LOGICAL_STRUCTURE, LOGICAL_STRUCTURE,
LOGICAL_STRUCTURE_LEFT,
MIND_MAP, MIND_MAP,
ORGANIZATION_STRUCTURE, ORGANIZATION_STRUCTURE,
CATALOG_ORGANIZATION, CATALOG_ORGANIZATION,
@ -491,6 +494,10 @@ class Drag extends Base {
: lastNodeRect.originLeft : lastNodeRect.originLeft
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
break break
case LOGICAL_STRUCTURE_LEFT:
x = lastNodeRect.originRight - this.placeholderWidth
y = lastNodeRect.originBottom + this.minOffset - halfPlaceholderHeight
break
case ORGANIZATION_STRUCTURE: case ORGANIZATION_STRUCTURE:
rotate = true rotate = true
x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight x = lastNodeRect.originRight + this.minOffset - halfPlaceholderHeight
@ -603,6 +610,12 @@ class Drag extends Base {
nodeRect.originTop + nodeRect.originTop +
(nodeRect.originHeight - this.placeholderHeight) / 2 (nodeRect.originHeight - this.placeholderHeight) / 2
break break
case LOGICAL_STRUCTURE_LEFT:
x = nodeRect.originLeft - this.placeholderWidth - marginX
y =
nodeRect.originTop +
(nodeRect.originHeight - this.placeholderHeight) / 2
break
case ORGANIZATION_STRUCTURE: case ORGANIZATION_STRUCTURE:
rotate = true rotate = true
x = x =
@ -683,6 +696,7 @@ class Drag extends Base {
getNewChildNodeDir(node) { getNewChildNodeDir(node) {
const { const {
LOGICAL_STRUCTURE, LOGICAL_STRUCTURE,
LOGICAL_STRUCTURE_LEFT,
MIND_MAP, MIND_MAP,
TIMELINE2, TIMELINE2,
VERTICAL_TIMELINE, VERTICAL_TIMELINE,
@ -691,6 +705,8 @@ class Drag extends Base {
switch (this.mindMap.opt.layout) { switch (this.mindMap.opt.layout) {
case LOGICAL_STRUCTURE: case LOGICAL_STRUCTURE:
return CONSTANTS.LAYOUT_GROW_DIR.RIGHT return CONSTANTS.LAYOUT_GROW_DIR.RIGHT
case LOGICAL_STRUCTURE_LEFT:
return CONSTANTS.LAYOUT_GROW_DIR.LEFT
case MIND_MAP: case MIND_MAP:
case TIMELINE2: case TIMELINE2:
case VERTICAL_TIMELINE: case VERTICAL_TIMELINE: