diff --git a/src/designs/structures/sequence-interaction.tsx b/src/designs/structures/sequence-interaction.tsx
index 14f537d5..9150200d 100644
--- a/src/designs/structures/sequence-interaction.tsx
+++ b/src/designs/structures/sequence-interaction.tsx
@@ -100,6 +100,7 @@ const DEFAULT_ITEM_HEIGHT = 50;
const FONT_SIZE = 14;
const ARROW_SIZE = 14;
const CORNER_RADIUS_NODE = 6;
+const LIFELINE_MASK_GAP = 2;
const LANE_PADDING = 60;
const BTN_HALF_SIZE = 12;
@@ -419,39 +420,6 @@ export const SequenceInteractionFlow: ComponentType<
const defsElements: JSXElement[] = [];
const btnElements: JSXElement[] = [];
- // 绘制生命线
- if (showLifeline) {
- lanes.forEach((_lane, laneIndex) => {
- const centerX = getLaneCenterX(laneIndex);
- const startY = padding + headerOffset;
- const endY = totalHeight - padding;
-
- decorElements.push(
- ,
- );
-
- // 绘制生命线末端箭头(实心)
- decorElements.push(
- ...createArrowElements(
- centerX,
- endY,
- Math.PI / 2,
- 'triangle',
- colorBorder,
- 1,
- 10,
- ),
- );
- });
- }
-
// 绘制泳道标题
if (showLaneHeader) {
lanes.forEach((lane, laneIndex) => {
@@ -523,19 +491,6 @@ export const SequenceInteractionFlow: ComponentType<
options,
);
- // 添加节点背景遮挡层,防止生命线虚线透过半透明节点显示
- // 只在节点中心放置窄条遮挡生命线,避免圆角处露出白色背景
- const maskStripWidth = lifelineWidth + 6;
- decorElements.push(
- ,
- );
-
// 构造类似 hierarchy-tree 的 _originalIndex
const originalIndex = [laneIndex, rowIndex];
// 附加到数据上,确保 Item 组件能正确识别
@@ -631,6 +586,97 @@ export const SequenceInteractionFlow: ComponentType<
);
});
+ // 绘制生命线(使用 mask 挖空节点区域,避免虚线穿透半透明节点)
+ if (showLifeline) {
+ // 预先按泳道分组节点,避免每条泳道都遍历全部节点
+ const nodeRectsByLane = new Map<
+ number,
+ { x: number; y: number; width: number; height: number }[]
+ >();
+ nodeLayoutById.forEach((layout) => {
+ let list = nodeRectsByLane.get(layout.laneIndex);
+ if (!list) {
+ list = [];
+ nodeRectsByLane.set(layout.laneIndex, list);
+ }
+ list.push({
+ x: layout.x,
+ y: layout.y,
+ width: layout.width,
+ height: layout.height,
+ });
+ });
+
+ lanes.forEach((_lane, laneIndex) => {
+ const centerX = getLaneCenterX(laneIndex);
+ const startY = padding + headerOffset;
+ const endY = totalHeight - padding;
+
+ const laneNodeRects = nodeRectsByLane.get(laneIndex) ?? [];
+
+ // 如果该泳道有节点,创建 mask 来挖空节点区域
+ let lifelineMaskAttr: string | undefined;
+ if (laneNodeRects.length > 0) {
+ const maskId = `lifeline-mask-${instanceId}-${laneIndex}`;
+ defsElements.push(
+
+ {/* 白色底:显示所有线条 */}
+
+ {/* 黑色块:在节点位置挖空生命线,上下各留 LIFELINE_MASK_GAP 间距 */}
+ {laneNodeRects.map((rect) => (
+
+ ))}
+ ,
+ );
+ lifelineMaskAttr = `url(#${maskId})`;
+ }
+
+ decorElements.push(
+ ,
+ );
+
+ // 绘制生命线末端箭头(实心)
+ decorElements.push(
+ ...createArrowElements(
+ centerX,
+ endY,
+ Math.PI / 2,
+ 'triangle',
+ colorBorder,
+ 1,
+ 10,
+ ),
+ );
+ });
+ }
+
// 添加新泳道按钮 (最右侧)
const lastLaneRightX = getLaneCenterX(lanes.length - 1) + laneWidth / 2;
const newLaneX =