From 80f8a357fe03966a6a446eaca0604706add7bc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A1=97=E8=A7=92=E5=B0=8F=E6=9E=97?= <1013335014@qq.com> Date: Tue, 26 Dec 2023 10:23:15 +0800 Subject: [PATCH] =?UTF-8?q?Feat=EF=BC=9A=E8=8A=82=E7=82=B9=E8=BF=9E?= =?UTF-8?q?=E7=BA=BF=E6=94=AF=E6=8C=81=E6=98=BE=E7=A4=BA=E7=AE=AD=E5=A4=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- simple-mind-map/src/core/render/node/Node.js | 42 ++++++++++++------- simple-mind-map/src/core/render/node/Style.js | 37 +++++++++++++++- simple-mind-map/src/layouts/Base.js | 6 +++ .../src/layouts/CatalogOrganization.js | 6 +-- simple-mind-map/src/layouts/Fishbone.js | 3 +- .../src/layouts/LogicalStructure.js | 9 ++-- simple-mind-map/src/layouts/MindMap.js | 18 +++----- .../src/layouts/OrganizationStructure.js | 16 +++---- simple-mind-map/src/layouts/Timeline.js | 6 +-- .../src/layouts/VerticalTimeline.js | 21 ++++------ simple-mind-map/src/themes/default.js | 5 ++- 11 files changed, 97 insertions(+), 72 deletions(-) diff --git a/simple-mind-map/src/core/render/node/Node.js b/simple-mind-map/src/core/render/node/Node.js index 1a9da053..af47745a 100644 --- a/simple-mind-map/src/core/render/node/Node.js +++ b/simple-mind-map/src/core/render/node/Node.js @@ -187,7 +187,10 @@ class Node { } // 如果没有返回内容,那么还是使用内置的节点内容 if (this._customNodeContent) { - this._customNodeContent.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml') + this._customNodeContent.setAttribute( + 'xmlns', + 'http://www.w3.org/1999/xhtml' + ) return } this._imgData = this.createImgNode() @@ -831,9 +834,9 @@ class Node { this.renderer.layout.renderLine( this, this._lines, - (line, node) => { + (...args) => { // 添加样式 - this.styleLine(line, node) + this.styleLine(...args) }, this.style.getStyle('lineStyle', true) ) @@ -888,19 +891,26 @@ class Node { } // 设置连线样式 - styleLine(line, node) { - let width = - node.getSelfInhertStyle('lineWidth') || node.getStyle('lineWidth', true) - let color = - node.getSelfInhertStyle('lineColor') || node.getStyle('lineColor', true) - let dasharray = - node.getSelfInhertStyle('lineDasharray') || - node.getStyle('lineDasharray', true) - this.style.line(line, { - width, - color, - dasharray - }) + styleLine(line, childNode, enableMarker) { + const width = + childNode.getSelfInhertStyle('lineWidth') || + childNode.getStyle('lineWidth', true) + const color = + childNode.getSelfInhertStyle('lineColor') || + childNode.getStyle('lineColor', true) + const dasharray = + childNode.getSelfInhertStyle('lineDasharray') || + childNode.getStyle('lineDasharray', true) + this.style.line( + line, + { + width, + color, + dasharray + }, + enableMarker, + childNode + ) } // 移除连线 diff --git a/simple-mind-map/src/core/render/node/Style.js b/simple-mind-map/src/core/render/node/Style.js index ecc190f7..0a36e433 100644 --- a/simple-mind-map/src/core/render/node/Style.js +++ b/simple-mind-map/src/core/render/node/Style.js @@ -55,6 +55,9 @@ class Style { // 构造函数 constructor(ctx) { this.ctx = ctx + // 箭头图标 + this._markerPath = null + this._marker = null } // 合并样式 @@ -190,8 +193,38 @@ class Style { } // 连线 - line(node, { width, color, dasharray } = {}) { - node.stroke({ width, color, dasharray }).fill({ color: 'none' }) + line(line, { width, color, dasharray } = {}, enableMarker, childNode) { + line.stroke({ color, dasharray, width }).fill({ color: 'none' }) + // 可以显示箭头 + if (enableMarker) { + const showMarker = this.merge('showLineMarker', true) + const childNodeStyle = childNode.style + // 显示箭头 + if (showMarker) { + // 创建子节点箭头标记 + childNodeStyle._marker = + childNodeStyle._marker || childNodeStyle.createMarker() + // 设置样式 + childNodeStyle._markerPath.stroke({ color }).fill({ color }) + line.marker('end', childNodeStyle._marker) + } else if (childNodeStyle._marker) { + // 不显示箭头,则删除该子节点的箭头标记 + line.attr('marker-end', '') + childNodeStyle._marker.remove() + childNodeStyle._marker = null + } + } + } + + // 创建箭头 + createMarker() { + return this.ctx.lineDraw.marker(20, 20, add => { + add.ref(8, 5) + add.size(20, 20) + add.attr('markerUnits', 'userSpaceOnUse') + add.attr('orient', 'auto-start-reverse') + this._markerPath = add.path('M0,0 L2,5 L0,10 L10,5 Z') + }) } // 概要连线 diff --git a/simple-mind-map/src/layouts/Base.js b/simple-mind-map/src/layouts/Base.js index 75aa24e0..c703c12e 100644 --- a/simple-mind-map/src/layouts/Base.js +++ b/simple-mind-map/src/layouts/Base.js @@ -443,6 +443,12 @@ class Base { getNodeActChildrenLength(node) { return node.nodeData.children && node.nodeData.children.length } + + // 设置连线样式 + setLineStyle(style, line, path, childNode) { + line.plot(path) + style && style(line, childNode, true) + } } export default Base diff --git a/simple-mind-map/src/layouts/CatalogOrganization.js b/simple-mind-map/src/layouts/CatalogOrganization.js index ce6e3cd8..2459a8c3 100644 --- a/simple-mind-map/src/layouts/CatalogOrganization.js +++ b/simple-mind-map/src/layouts/CatalogOrganization.js @@ -233,8 +233,7 @@ class CatalogOrganization extends Base { `M ${x2},${y1 + s1} L ${x2},${y1 + s1 > y2 ? y2 + item.height : y2}` + nodeUseLineStylePath // 竖线 - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) minx = Math.min(minx, x1) maxx = Math.max(maxx, x1) @@ -302,8 +301,7 @@ class CatalogOrganization extends Base { }` : '' path += nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) // 竖线 if (len > 0) { diff --git a/simple-mind-map/src/layouts/Fishbone.js b/simple-mind-map/src/layouts/Fishbone.js index 98f0b1fb..35505e13 100644 --- a/simple-mind-map/src/layouts/Fishbone.js +++ b/simple-mind-map/src/layouts/Fishbone.js @@ -300,8 +300,7 @@ class Fishbone extends Base { // 水平线 if (node.layerIndex > 1) { let path = `M ${x},${y} L ${item.left},${y}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) } }) // 斜线 diff --git a/simple-mind-map/src/layouts/LogicalStructure.js b/simple-mind-map/src/layouts/LogicalStructure.js index 572c4eb1..065402d2 100644 --- a/simple-mind-map/src/layouts/LogicalStructure.js +++ b/simple-mind-map/src/layouts/LogicalStructure.js @@ -181,8 +181,7 @@ class LogicalStructure extends Base { let path = `M ${x1},${y1} L ${x1 + s1},${y1} L ${x1 + s1},${y2} L ${ x2 + nodeUseLineStyleOffset },${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -209,8 +208,7 @@ class LogicalStructure extends Base { ? ` L ${item.left + item.width},${y2}` : '' let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -242,8 +240,7 @@ class LogicalStructure extends Base { } else { path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath } - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } diff --git a/simple-mind-map/src/layouts/MindMap.js b/simple-mind-map/src/layouts/MindMap.js index 3641933a..249f981d 100644 --- a/simple-mind-map/src/layouts/MindMap.js +++ b/simple-mind-map/src/layouts/MindMap.js @@ -116,11 +116,7 @@ class MindMap extends Base { this.root, null, (node, parent, isRoot, layerIndex) => { - if ( - node.getData('expand') && - node.children && - node.children.length - ) { + if (node.getData('expand') && node.children && node.children.length) { let marginY = this.getMarginY(layerIndex + 1) let baseTop = node.top + node.height / 2 + marginY // 第一个子节点的top值 = 该节点中心的top值 - 子节点的高度之和的一半 @@ -247,8 +243,7 @@ class MindMap extends Base { let path = `M ${x1},${y1} L ${x1 + _s},${y1} L ${x1 + _s},${y2} L ${ x2 + nodeUseLineStyleOffset },${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -287,8 +282,7 @@ class MindMap extends Base { } } let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -332,8 +326,7 @@ class MindMap extends Base { } else { path = this.cubicBezierPath(x1, y1, x2, y2) + nodeUseLineStylePath } - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -384,7 +377,8 @@ class MindMap extends Base { x + (isLeft ? -generalizationNodeMargin : generalizationNodeMargin) - (isLeft ? item.generalizationNode.width : 0) - item.generalizationNode.top = top + (bottom - top - item.generalizationNode.height) / 2 + item.generalizationNode.top = + top + (bottom - top - item.generalizationNode.height) / 2 }) } diff --git a/simple-mind-map/src/layouts/OrganizationStructure.js b/simple-mind-map/src/layouts/OrganizationStructure.js index 482c0781..74c4d1ce 100644 --- a/simple-mind-map/src/layouts/OrganizationStructure.js +++ b/simple-mind-map/src/layouts/OrganizationStructure.js @@ -78,11 +78,7 @@ class OrganizationStructure extends Base { this.root, null, (node, parent, isRoot, layerIndex) => { - if ( - node.getData('expand') && - node.children && - node.children.length - ) { + if (node.getData('expand') && node.children && node.children.length) { let marginX = this.getMarginY(layerIndex + 1) // 第一个子节点的left值 = 该节点中心的left值 - 子节点的宽度之和的一半 let left = node.left + node.width / 2 - node.childrenAreaWidth / 2 @@ -175,8 +171,7 @@ class OrganizationStructure extends Base { ? ` L ${item.left},${y2} L ${item.left + item.width},${y2}` : '' let path = `M ${x1},${y1} L ${x2},${y2}` + nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } @@ -210,8 +205,7 @@ class OrganizationStructure extends Base { ? ` L ${item.left},${y2} L ${item.left + item.width},${y2}` : '' let path = `M ${x2},${y1 + s1} L ${x2},${y2}` + nodeUseLineStylePath - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) minx = Math.min(x1, minx) maxx = Math.max(x1, maxx) @@ -261,9 +255,9 @@ class OrganizationStructure extends Base { let path = `M ${x1},${y1} Q ${cx},${cy} ${x2},${y2}` item.generalizationLine.plot(path) item.generalizationNode.top = bottom + generalizationNodeMargin - item.generalizationNode.left = left + (right - left - item.generalizationNode.width) / 2 + item.generalizationNode.left = + left + (right - left - item.generalizationNode.width) / 2 }) - } // 渲染展开收起按钮的隐藏占位元素 diff --git a/simple-mind-map/src/layouts/Timeline.js b/simple-mind-map/src/layouts/Timeline.js index d9d51c2e..030ef2dd 100644 --- a/simple-mind-map/src/layouts/Timeline.js +++ b/simple-mind-map/src/layouts/Timeline.js @@ -245,8 +245,7 @@ class Timeline extends Base { let x2 = item.left let y = node.top + node.height / 2 let path = `M ${x1},${y} L ${x2},${y}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) prevBother = item }) } else { @@ -264,8 +263,7 @@ class Timeline extends Base { } // 水平线 let path = `M ${x},${y} L ${item.left},${y}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) // 竖线 if (len > 0) { diff --git a/simple-mind-map/src/layouts/VerticalTimeline.js b/simple-mind-map/src/layouts/VerticalTimeline.js index 7f844fb0..e3352815 100644 --- a/simple-mind-map/src/layouts/VerticalTimeline.js +++ b/simple-mind-map/src/layouts/VerticalTimeline.js @@ -246,8 +246,7 @@ class VerticalTimeline extends Base { let y2 = item.top let x = node.left + node.width / 2 let path = `M ${x},${y1} L ${x},${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) prevBother = item }) } else { @@ -265,8 +264,7 @@ class VerticalTimeline extends Base { L ${nodeRight + offset},${nodeYCenter} L ${nodeRight + offset},${itemYCenter} L ${itemLeft},${itemYCenter}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } else { let nodeLeft = node.left @@ -281,8 +279,7 @@ class VerticalTimeline extends Base { L ${nodeLeft - offset},${nodeYCenter} L ${nodeLeft - offset},${itemYCenter} L ${itemRight},${itemYCenter}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) }) } } @@ -306,8 +303,7 @@ class VerticalTimeline extends Base { let y2 = item.top let x = node.left + node.width / 2 let path = `M ${x},${y1} L ${x},${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) prevBother = item }) } else { @@ -322,8 +318,7 @@ class VerticalTimeline extends Base { : item.left let y2 = item.top + item.height / 2 let path = `M ${x1},${y1} L ${x2},${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) } }) } @@ -346,8 +341,7 @@ class VerticalTimeline extends Base { let y2 = item.top let x = node.left + node.width / 2 let path = `M ${x},${y1} L ${x},${y2}` - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) prevBother = item }) } else { @@ -362,8 +356,7 @@ class VerticalTimeline extends Base { : item.left let y2 = item.top + item.height / 2 let path = this.cubicBezierPath(x1, y1, x2, y2) - lines[index].plot(path) - style && style(lines[index], item) + this.setLineStyle(style, lines[index], path, item) } }) } diff --git a/simple-mind-map/src/themes/default.js b/simple-mind-map/src/themes/default.js index 897a46d7..53185f22 100644 --- a/simple-mind-map/src/themes/default.js +++ b/simple-mind-map/src/themes/default.js @@ -20,6 +20,8 @@ export default { lineStyle: 'straight', // 针对logicalStructure、mindMap两种结构。曲线(curve)、直线(straight)、直连(direct) // 曲线连接时,根节点和其他节点的连接线样式保持统一,默认根节点为 ( 型,其他节点为 { 型,设为true后,都为 { 型 rootLineKeepSameInCurve: true, + // 连线尾部是否显示标记,目前只支持箭头 + showLineMarker: false, // 概要连线的粗细 generalizationLineWidth: 1, // 概要连线的颜色 @@ -159,7 +161,8 @@ const nodeSizeIndependenceList = [ 'backgroundRepeat', 'backgroundPosition', 'backgroundSize', - 'rootLineKeepSameInCurve' + 'rootLineKeepSameInCurve', + 'showLineMarker' ] export const checkIsNodeSizeIndependenceConfig = config => { let keys = Object.keys(config)