From a64abbeefdb5182a97072ed084e4ef759e103084 Mon Sep 17 00:00:00 2001 From: liuziqi Date: Thu, 21 Nov 2024 20:31:52 +0800 Subject: [PATCH 1/6] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8D=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E7=94=BB=E5=B8=83=E6=97=B6=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=90=B8=E9=99=84=E7=BD=91=E6=A0=BC=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E8=8A=82=E7=82=B9=E4=B8=8E=E8=BE=B9=E9=94=99?= =?UTF-8?q?=E4=BD=8D=E9=97=AE=E9=A2=98=20#1954?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/model/GraphModel.ts | 38 ++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/packages/core/src/model/GraphModel.ts b/packages/core/src/model/GraphModel.ts index 4e0ae1077..0a843efd7 100644 --- a/packages/core/src/model/GraphModel.ts +++ b/packages/core/src/model/GraphModel.ts @@ -1,4 +1,4 @@ -import { find, forEach, map, merge, isBoolean } from 'lodash-es' +import { find, forEach, map, merge, isBoolean, isEqual } from 'lodash-es' import { action, computed, observable } from 'mobx' import { BaseEdgeModel, @@ -439,6 +439,42 @@ export class GraphModel { throw new Error(`找不到${edge.type}对应的边。`) } const edgeModel = new Model(edge, this) + // 根据edgeModel中存储的数据找到当前画布上的起终锚点坐标 + // 判断当前起终锚点数据和Model中存储的起终点数据是否一致,不一致更新起终点信息 + const { + sourceNodeId, + targetNodeId, + sourceAnchorId, + targetAnchorId, + startPoint, + endPoint, + text, + textPosition, + } = edgeModel + const sourceNode = this.getNodeModelById(sourceNodeId) + const targetNode = this.getNodeModelById(targetNodeId) + const sourceAnchor = sourceNode?.anchors.find( + (anchor) => anchor.id === sourceAnchorId, + ) + const targetAnchor = targetNode?.anchors.find( + (anchor) => anchor.id === targetAnchorId, + ) + if (sourceAnchor && !isEqual(sourceAnchor, startPoint)) { + edgeModel.updateStartPoint(sourceAnchor) + } + if (targetAnchor && !isEqual(targetAnchor, endPoint)) { + edgeModel.updateEndPoint(targetAnchor) + } + // 而文本需要先算一下文本与默认文本位置之间的相对位置差 + // 再计算新路径的文本默认位置,加上相对位置差,得到调整后边的文本的位置 + if (text) { + const { x, y } = text + const { x: defaultX, y: defaultY } = textPosition + const deltaX = x - defaultX + const deltaY = y - defaultY + edgeModel.resetTextPosition() + edgeModel.moveText(deltaX, deltaY) + } this.edgeModelMap.set(edgeModel.id, edgeModel) this.elementsModelMap.set(edgeModel.id, edgeModel) From 38305c778c7621cb8a2ba5d78fc3c1afb38de81c Mon Sep 17 00:00:00 2001 From: Dymonelewis <120695700@qq.com> Date: Tue, 26 Nov 2024 11:54:39 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(core):=20line=20=E5=92=8C=20polyline?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0getPath=E6=96=B9=E6=B3=95=20#1929?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/algorithm/outline.ts | 2 +- packages/core/src/model/edge/LineEdgeModel.ts | 8 ++++++++ packages/core/src/model/edge/PolylineEdgeModel.ts | 15 ++++++++++++--- packages/core/src/view/overlay/OutlineOverlay.tsx | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/core/src/algorithm/outline.ts b/packages/core/src/algorithm/outline.ts index d55e5a9bf..0f8b15321 100644 --- a/packages/core/src/algorithm/outline.ts +++ b/packages/core/src/algorithm/outline.ts @@ -66,7 +66,7 @@ export const getEdgeOutline = ( edge: BaseEdgeModel, ): OutlineInfo | undefined => { if (edge.modelType === ModelType.LINE_EDGE) { - return getLineOutline(edge) + return getLineOutline(edge as LineEdgeModel) } if (edge.modelType === ModelType.POLYLINE_EDGE) { return getPolylineOutline(edge as PolylineEdgeModel) diff --git a/packages/core/src/model/edge/LineEdgeModel.ts b/packages/core/src/model/edge/LineEdgeModel.ts index 42c6c6fb2..2a2adae21 100644 --- a/packages/core/src/model/edge/LineEdgeModel.ts +++ b/packages/core/src/model/edge/LineEdgeModel.ts @@ -17,6 +17,14 @@ export class LineEdgeModel extends BaseEdgeModel { ...cloneDeep(customStyle), } } + initEdgeData(data: LogicFlow.EdgeConfig): void { + super.initEdgeData(data) + this.points = this.getPath([this.startPoint, this.endPoint]) + } + getPath(points: Point[]): string { + const [start, end] = points + return `M ${start.x} ${start.y} L ${end.x} ${end.y}` + } getTextPosition(): Point { return { x: (this.startPoint.x + this.endPoint.x) / 2, diff --git a/packages/core/src/model/edge/PolylineEdgeModel.ts b/packages/core/src/model/edge/PolylineEdgeModel.ts index 78b5ae22f..7533817d2 100644 --- a/packages/core/src/model/edge/PolylineEdgeModel.ts +++ b/packages/core/src/model/edge/PolylineEdgeModel.ts @@ -326,12 +326,21 @@ export class PolylineEdgeModel extends BaseEdgeModel { }) } + getPath(points: Point[]): string { + return points + .map((point, index) => { + if (!index) { + return `M ${point.x} ${point.y}` + } + return `L ${point.x} ${point.y}` + }) + .join(' ') + } + @action initPoints() { if (this.pointsList.length > 0) { - this.points = this.pointsList - .map((point) => `${point.x},${point.y}`) - .join(' ') + this.points = this.getPath(this.pointsList) } else { this.updatePoints() } diff --git a/packages/core/src/view/overlay/OutlineOverlay.tsx b/packages/core/src/view/overlay/OutlineOverlay.tsx index 97eabb7f6..cdaabe72f 100644 --- a/packages/core/src/view/overlay/OutlineOverlay.tsx +++ b/packages/core/src/view/overlay/OutlineOverlay.tsx @@ -82,7 +82,7 @@ export class OutlineOverlay extends Component { (hoverOutline && edge.isHovered) ) { if (edge.modelType === ModelType.LINE_EDGE) { - edgeOutline.push(this.getLineOutline(edge)) + edgeOutline.push(this.getLineOutline(edge as LineEdgeModel)) } else if (edge.modelType === ModelType.POLYLINE_EDGE) { edgeOutline.push(this.getPolylineOutline(edge as PolylineEdgeModel)) } else if (edge.modelType === ModelType.BEZIER_EDGE) { From e738ed88fb7d13684cd6df9a01bac5fffef239f5 Mon Sep 17 00:00:00 2001 From: Dymonelewis <120695700@qq.com> Date: Tue, 26 Nov 2024 12:42:20 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat(core):=20=E5=A2=9E=E5=8A=A0=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=92=8C=E8=BE=B9=E7=9A=84focus=E5=92=8Cblur=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E6=8A=A5=20#1917?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/constant/index.ts | 4 ++++ packages/core/src/view/edge/BaseEdge.tsx | 28 ++++++++++++++++++++++++ packages/core/src/view/node/BaseNode.tsx | 28 ++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/packages/core/src/constant/index.ts b/packages/core/src/constant/index.ts index 238b5e5c0..994e6afba 100644 --- a/packages/core/src/constant/index.ts +++ b/packages/core/src/constant/index.ts @@ -57,6 +57,8 @@ export enum EventType { NODE_CONTEXTMENU = 'node:contextmenu', NODE_ROTATE = 'node:rotate', NODE_RESIZE = 'node:resize', + NODE_FOCUS = 'node:focus', + NODE_BLUR = 'node:blur', // 节点 properties 变化事件 NODE_PROPERTIES_CHANGE = 'node:properties-change', @@ -67,6 +69,8 @@ export enum EventType { EDGE_DELETE = 'edge:delete', EDGE_CLICK = 'edge:click', EDGE_DBCLICK = 'edge:dbclick', + EDGE_FOCUS = 'edge:focus', + EDGE_BLUR = 'edge:blur', EDGE_MOUSEENTER = 'edge:mouseenter', EDGE_MOUSELEAVE = 'edge:mouseleave', diff --git a/packages/core/src/view/edge/BaseEdge.tsx b/packages/core/src/view/edge/BaseEdge.tsx index db878a6b6..444b63725 100644 --- a/packages/core/src/view/edge/BaseEdge.tsx +++ b/packages/core/src/view/edge/BaseEdge.tsx @@ -459,6 +459,32 @@ export abstract class BaseEdge

extends Component< this.toFront() } + handleFocus = (ev: any) => { + const { model, graphModel } = this.props + const position = graphModel.getPointByClient({ + x: ev.clientX, + y: ev.clientY, + }) + graphModel.eventCenter.emit(EventType.EDGE_FOCUS, { + data: model.getData(), + e: ev, + position, + }) + } + + handleBlur = (ev: any) => { + const { model, graphModel } = this.props + const position = graphModel.getPointByClient({ + x: ev.clientX, + y: ev.clientY, + }) + graphModel.eventCenter.emit(EventType.EDGE_BLUR, { + data: model.getData(), + e: ev, + position, + }) + } + /** * @overridable 支持重写, 此方法为获取边的形状,如果需要自定义边的形状,请重写此方法。 * @example https://docs.logic-flow.cn/docs/#/zh/guide/basic/edge?id=%e5%9f%ba%e4%ba%8e-react-%e7%bb%84%e4%bb%b6%e8%87%aa%e5%ae%9a%e4%b9%89%e8%be%b9 @@ -499,6 +525,8 @@ export abstract class BaseEdge

extends Component< onMouseOver={this.setHoverOn} onMouseEnter={this.setHoverOn} onMouseLeave={this.setHoverOff} + onFocus={this.handleFocus} + onBlur={this.handleBlur} > {this.getShape()} {this.getAppend()} diff --git a/packages/core/src/view/node/BaseNode.tsx b/packages/core/src/view/node/BaseNode.tsx index 787a6fb14..bfb4544ce 100644 --- a/packages/core/src/view/node/BaseNode.tsx +++ b/packages/core/src/view/node/BaseNode.tsx @@ -424,6 +424,32 @@ export abstract class BaseNode

extends Component< } } + handleFocus = (ev: any) => { + const { model, graphModel } = this.props + const position = graphModel.getPointByClient({ + x: ev.clientX, + y: ev.clientY, + }) + graphModel.eventCenter.emit(EventType.NODE_FOCUS, { + data: model.getData(), + e: ev, + position, + }) + } + + handleBlur = (ev: any) => { + const { model, graphModel } = this.props + const position = graphModel.getPointByClient({ + x: ev.clientX, + y: ev.clientY, + }) + graphModel.eventCenter.emit(EventType.NODE_BLUR, { + data: model.getData(), + e: ev, + position, + }) + } + // 因为自定义节点的时候,可能会基于hover状态自定义不同的样式。 setHoverOn = (ev: MouseEvent) => { const { model, graphModel } = this.props @@ -508,6 +534,8 @@ export abstract class BaseNode

extends Component< onMouseLeave={this.setHoverOff} onMouseOut={this.onMouseOut} onContextMenu={this.handleContextMenu} + onFocus={this.handleFocus} + onBlur={this.handleBlur} {...restAttributes} > {nodeShapeInner} From 4dd3d50933d7f0abe5e139d12c8cf26db084997c Mon Sep 17 00:00:00 2001 From: Dymonelewis <120695700@qq.com> Date: Tue, 26 Nov 2024 15:01:34 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix(core):=20=E8=8A=82=E7=82=B9=E5=92=8C?= =?UTF-8?q?=E8=BE=B9focus=E5=92=8Cblur=E4=BA=8B=E4=BB=B6=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BC=98=E5=8C=96:=E5=A4=84=E7=90=86=E6=B5=8F=E8=A7=88?= =?UTF-8?q?=E5=99=A8=E9=BB=98=E8=AE=A4focus=E6=A0=B7=E5=BC=8F=E9=97=AE?= =?UTF-8?q?=E9=A2=98&=E5=A2=9E=E5=8A=A0=E7=B1=BB=E5=9E=8B=E5=A3=B0?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/event/eventArgs.ts | 16 ++++++++++++++++ packages/core/src/style/index.less | 5 +++++ packages/core/src/style/raw.ts | 3 +++ packages/core/src/view/edge/BaseEdge.tsx | 16 ++-------------- packages/core/src/view/node/BaseNode.tsx | 16 ++-------------- 5 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/core/src/event/eventArgs.ts b/packages/core/src/event/eventArgs.ts index b13eb8545..775e3ca66 100644 --- a/packages/core/src/event/eventArgs.ts +++ b/packages/core/src/event/eventArgs.ts @@ -188,6 +188,14 @@ interface NodeEventArgs { */ properties: Record } + /** + * 节点获焦 + */ + 'node:focus': NodeEventArgsPick<'data'> + /** + * 节点失焦 + */ + 'node:blur': NodeEventArgsPick<'data'> } type EdgeEventArgsPick = Pick< @@ -259,6 +267,14 @@ interface EdgeEventArgs { oldEdge: EdgeData } } + /** + * 边获焦 + */ + 'edge:focus': EdgeEventArgsPick<'data'> + /** + * 边失焦 + */ + 'edge:blur': EdgeEventArgsPick<'data'> } /** diff --git a/packages/core/src/style/index.less b/packages/core/src/style/index.less index 6cbfb8cb4..a4555957a 100644 --- a/packages/core/src/style/index.less +++ b/packages/core/src/style/index.less @@ -19,6 +19,11 @@ cursor: move; } +// 在元素focus时浏览器会给元素outline设置一个5像素宽的默认样式,这里先全局禁用一下,后续再根据需要再做调整 +*:focus { + outline: none; +} + .lf-node-anchor { cursor: crosshair; } diff --git a/packages/core/src/style/raw.ts b/packages/core/src/style/raw.ts index b73733f07..11531c6e5 100644 --- a/packages/core/src/style/raw.ts +++ b/packages/core/src/style/raw.ts @@ -21,6 +21,9 @@ export const content = `.lf-graph { .lf-text-draggable { cursor: move; } +*:focus { + outline: none; +} .lf-node-anchor { cursor: crosshair; } diff --git a/packages/core/src/view/edge/BaseEdge.tsx b/packages/core/src/view/edge/BaseEdge.tsx index 444b63725..890f08707 100644 --- a/packages/core/src/view/edge/BaseEdge.tsx +++ b/packages/core/src/view/edge/BaseEdge.tsx @@ -459,29 +459,17 @@ export abstract class BaseEdge

extends Component< this.toFront() } - handleFocus = (ev: any) => { + handleFocus = () => { const { model, graphModel } = this.props - const position = graphModel.getPointByClient({ - x: ev.clientX, - y: ev.clientY, - }) graphModel.eventCenter.emit(EventType.EDGE_FOCUS, { data: model.getData(), - e: ev, - position, }) } - handleBlur = (ev: any) => { + handleBlur = () => { const { model, graphModel } = this.props - const position = graphModel.getPointByClient({ - x: ev.clientX, - y: ev.clientY, - }) graphModel.eventCenter.emit(EventType.EDGE_BLUR, { data: model.getData(), - e: ev, - position, }) } diff --git a/packages/core/src/view/node/BaseNode.tsx b/packages/core/src/view/node/BaseNode.tsx index bfb4544ce..b8aae02c6 100644 --- a/packages/core/src/view/node/BaseNode.tsx +++ b/packages/core/src/view/node/BaseNode.tsx @@ -424,29 +424,17 @@ export abstract class BaseNode

extends Component< } } - handleFocus = (ev: any) => { + handleFocus = () => { const { model, graphModel } = this.props - const position = graphModel.getPointByClient({ - x: ev.clientX, - y: ev.clientY, - }) graphModel.eventCenter.emit(EventType.NODE_FOCUS, { data: model.getData(), - e: ev, - position, }) } - handleBlur = (ev: any) => { + handleBlur = () => { const { model, graphModel } = this.props - const position = graphModel.getPointByClient({ - x: ev.clientX, - y: ev.clientY, - }) graphModel.eventCenter.emit(EventType.NODE_BLUR, { data: model.getData(), - e: ev, - position, }) } From 32d8e1cea83eb3835e9156d7833c8830084533dd Mon Sep 17 00:00:00 2001 From: Dymonelewis <120695700@qq.com> Date: Tue, 26 Nov 2024 15:02:58 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix(core):=20=E4=BF=AE=E5=A4=8Dpolyline=20p?= =?UTF-8?q?oints=E5=86=85=E5=AE=B9=E5=8F=98=E5=8C=96=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E7=9A=84=E6=97=A0=E6=B3=95=E8=A7=A3=E6=9E=90=E9=97=AE=E9=A2=98?= =?UTF-8?q?=20&=20=E4=BC=98=E5=8C=96=E5=88=9D=E5=A7=8B=E5=8C=96=E8=BE=B9?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E7=9B=B8=E5=85=B3=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/model/GraphModel.ts | 49 +++++++++++++------ .../core/src/model/edge/PolylineEdgeModel.ts | 9 +--- 2 files changed, 34 insertions(+), 24 deletions(-) diff --git a/packages/core/src/model/GraphModel.ts b/packages/core/src/model/GraphModel.ts index 0a843efd7..9a42a59dd 100644 --- a/packages/core/src/model/GraphModel.ts +++ b/packages/core/src/model/GraphModel.ts @@ -41,6 +41,7 @@ import Position = LogicFlow.Position import PointTuple = LogicFlow.PointTuple import GraphData = LogicFlow.GraphData import NodeConfig = LogicFlow.NodeConfig +import AnchorConfig = Model.AnchorConfig import BaseNodeModelCtor = LogicFlow.BaseNodeModelCtor import BaseEdgeModelCtor = LogicFlow.BaseEdgeModelCtor @@ -444,36 +445,52 @@ export class GraphModel { const { sourceNodeId, targetNodeId, - sourceAnchorId, - targetAnchorId, + sourceAnchorId = '', + targetAnchorId = '', startPoint, endPoint, text, textPosition, } = edgeModel + const updateAnchorPoint = ( + node: BaseNodeModel | undefined, + anchorId: string, + point: Position, + updatePoint: (anchor: AnchorConfig) => void, + ) => { + const anchor = node?.anchors.find((anchor) => anchor.id === anchorId) + if (anchor && !isEqual(anchor, point)) { + updatePoint(anchor) + } + } + const sourceNode = this.getNodeModelById(sourceNodeId) const targetNode = this.getNodeModelById(targetNodeId) - const sourceAnchor = sourceNode?.anchors.find( - (anchor) => anchor.id === sourceAnchorId, + + updateAnchorPoint( + sourceNode, + sourceAnchorId, + startPoint, + edgeModel.updateStartPoint.bind(edgeModel), ) - const targetAnchor = targetNode?.anchors.find( - (anchor) => anchor.id === targetAnchorId, + updateAnchorPoint( + targetNode, + targetAnchorId, + endPoint, + edgeModel.updateEndPoint.bind(edgeModel), ) - if (sourceAnchor && !isEqual(sourceAnchor, startPoint)) { - edgeModel.updateStartPoint(sourceAnchor) - } - if (targetAnchor && !isEqual(targetAnchor, endPoint)) { - edgeModel.updateEndPoint(targetAnchor) - } + // 而文本需要先算一下文本与默认文本位置之间的相对位置差 // 再计算新路径的文本默认位置,加上相对位置差,得到调整后边的文本的位置 if (text) { const { x, y } = text const { x: defaultX, y: defaultY } = textPosition - const deltaX = x - defaultX - const deltaY = y - defaultY - edgeModel.resetTextPosition() - edgeModel.moveText(deltaX, deltaY) + if (x && y && defaultX && defaultY) { + const deltaX = x - defaultX + const deltaY = y - defaultY + edgeModel.resetTextPosition() + edgeModel.moveText(deltaX, deltaY) + } } this.edgeModelMap.set(edgeModel.id, edgeModel) this.elementsModelMap.set(edgeModel.id, edgeModel) diff --git a/packages/core/src/model/edge/PolylineEdgeModel.ts b/packages/core/src/model/edge/PolylineEdgeModel.ts index 7533817d2..d55b5c085 100644 --- a/packages/core/src/model/edge/PolylineEdgeModel.ts +++ b/packages/core/src/model/edge/PolylineEdgeModel.ts @@ -327,14 +327,7 @@ export class PolylineEdgeModel extends BaseEdgeModel { } getPath(points: Point[]): string { - return points - .map((point, index) => { - if (!index) { - return `M ${point.x} ${point.y}` - } - return `L ${point.x} ${point.y}` - }) - .join(' ') + return points.map((point) => `${point.x},${point.y}`).join(' ') } @action From d16568249a1e5ad42090bf5fcfb3d6ff1deb62f6 Mon Sep 17 00:00:00 2001 From: Dymonelewis <120695700@qq.com> Date: Tue, 26 Nov 2024 15:06:16 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix(core):=20line=20getPath=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E6=95=B0=E6=8D=AE=E6=A0=BC=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/model/edge/LineEdgeModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/model/edge/LineEdgeModel.ts b/packages/core/src/model/edge/LineEdgeModel.ts index 2a2adae21..e6843c282 100644 --- a/packages/core/src/model/edge/LineEdgeModel.ts +++ b/packages/core/src/model/edge/LineEdgeModel.ts @@ -23,7 +23,7 @@ export class LineEdgeModel extends BaseEdgeModel { } getPath(points: Point[]): string { const [start, end] = points - return `M ${start.x} ${start.y} L ${end.x} ${end.y}` + return `${start.x},${start.y} ${end.x},${end.y}` } getTextPosition(): Point { return {