C内核流量计算方法优化,前端文件名称读取优化
This commit is contained in:
1 parent
5d5a2e1843
commit
808c484f5b
94 files changed
+20163
-4418
No files matched your search
@@ -272,7 +272,7 @@ test("复制块保留内部连接,同时未连接端口仍参与待放置吸
|
||||
await expect(targetPort).toHaveAttribute("data-connected", "true");
|
||||
});
|
||||
|
||||
test("正交连接线可拖动内部线段,且无连接交叉点显示跨线桥", async ({
|
||||
test("选中正交连接线不显示拐点,仍可拖动线段、撤销并保存跨线桥路由", async ({
|
||||
page,
|
||||
}) => {
|
||||
const project = {
|
||||
@@ -342,6 +342,7 @@ test("正交连接线可拖动内部线段,且无连接交叉点显示跨线
|
||||
.locator(".react-flow__edge-interaction")
|
||||
.dispatchEvent("click");
|
||||
await expect(horizontalEdge).toHaveClass(/selected|editor-edge-selected/);
|
||||
await expect(horizontalEdge.locator("circle")).toHaveCount(0);
|
||||
const horizontalSegment = horizontalEdge
|
||||
.locator(".manual-edge-segment-handle.horizontal")
|
||||
.first();
|
||||
@@ -404,125 +405,21 @@ test("正交连接线可拖动内部线段,且无连接交叉点显示跨线
|
||||
pathBeforeVerticalDrag ?? "",
|
||||
);
|
||||
|
||||
const cornerHandle = horizontalEdge.locator(
|
||||
'.manual-edge-corner-handle[data-corner-index="2"]',
|
||||
);
|
||||
await expect(cornerHandle).toHaveCount(1);
|
||||
const cornerBefore = await cornerHandle.evaluate(
|
||||
(circle: SVGCircleElement) => ({
|
||||
flowX: circle.cx.baseVal.value,
|
||||
flowY: circle.cy.baseVal.value,
|
||||
screen: (() => {
|
||||
const matrix = circle.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取连接线拐点坐标");
|
||||
}
|
||||
const point = new DOMPoint(
|
||||
circle.cx.baseVal.value,
|
||||
circle.cy.baseVal.value,
|
||||
).matrixTransform(matrix);
|
||||
return { x: point.x, y: point.y };
|
||||
})(),
|
||||
}),
|
||||
);
|
||||
const pathBeforeCornerDrag = await horizontalPath.getAttribute("d");
|
||||
await page.mouse.move(cornerBefore.screen.x, cornerBefore.screen.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(
|
||||
cornerBefore.screen.x + 32,
|
||||
cornerBefore.screen.y + 24,
|
||||
{ steps: 6 },
|
||||
);
|
||||
await page.mouse.up();
|
||||
await expect(horizontalPath).not.toHaveAttribute(
|
||||
"d",
|
||||
pathBeforeCornerDrag ?? "",
|
||||
);
|
||||
const cornerAfter = await cornerHandle.evaluate(
|
||||
(circle: SVGCircleElement) => ({
|
||||
flowX: circle.cx.baseVal.value,
|
||||
flowY: circle.cy.baseVal.value,
|
||||
}),
|
||||
);
|
||||
expect(Math.abs(cornerAfter.flowX - cornerBefore.flowX)).toBeGreaterThan(1);
|
||||
expect(Math.abs(cornerAfter.flowY - cornerBefore.flowY)).toBeGreaterThan(1);
|
||||
|
||||
const pathAfterSegmentDrags = await horizontalPath.getAttribute("d");
|
||||
await expect(horizontalEdge.locator("circle")).toHaveCount(0);
|
||||
await page.keyboard.press("Control+z");
|
||||
await expect(horizontalPath).toHaveAttribute(
|
||||
"d",
|
||||
pathBeforeCornerDrag ?? "",
|
||||
pathBeforeVerticalDrag ?? "",
|
||||
);
|
||||
await horizontalEdge
|
||||
.locator(".react-flow__edge-interaction")
|
||||
.dispatchEvent("click");
|
||||
await expect(horizontalEdge).toHaveClass(/selected|editor-edge-selected/);
|
||||
|
||||
const boundaryCorner = horizontalEdge.locator(
|
||||
'.manual-edge-corner-handle[data-corner-index="1"]',
|
||||
);
|
||||
await expect(boundaryCorner).toHaveCount(1);
|
||||
const boundaryStart = await boundaryCorner.evaluate(
|
||||
(circle: SVGCircleElement) => {
|
||||
const matrix = circle.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取端点相邻拐点坐标");
|
||||
}
|
||||
const point = new DOMPoint(
|
||||
circle.cx.baseVal.value,
|
||||
circle.cy.baseVal.value,
|
||||
).matrixTransform(matrix);
|
||||
return { x: point.x, y: point.y };
|
||||
},
|
||||
);
|
||||
const boundaryPathLocator = horizontalEdge.locator(".react-flow__edge-path");
|
||||
const boundaryPathBefore = await boundaryPathLocator.getAttribute("d");
|
||||
const boundaryTarget = {
|
||||
x: boundaryStart.x + 38,
|
||||
y: boundaryStart.y + 30,
|
||||
};
|
||||
await page.mouse.move(boundaryStart.x, boundaryStart.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(
|
||||
(boundaryStart.x + boundaryTarget.x) / 2,
|
||||
(boundaryStart.y + boundaryTarget.y) / 2,
|
||||
{ steps: 4 },
|
||||
);
|
||||
await page.mouse.move(boundaryTarget.x, boundaryTarget.y, { steps: 4 });
|
||||
await page.mouse.up();
|
||||
await expect(boundaryPathLocator).not.toHaveAttribute(
|
||||
await page.keyboard.press("Control+y");
|
||||
await expect(horizontalPath).toHaveAttribute(
|
||||
"d",
|
||||
boundaryPathBefore ?? "",
|
||||
pathAfterSegmentDrags ?? "",
|
||||
);
|
||||
await expect(boundaryPathLocator).toHaveAttribute("d", / Q /);
|
||||
|
||||
const cornerScreenPoints = await horizontalEdge
|
||||
.locator(".manual-edge-corner-handle")
|
||||
.evaluateAll((circles: SVGCircleElement[]) =>
|
||||
circles.map((circle) => {
|
||||
const matrix = circle.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取调整后的拐点坐标");
|
||||
}
|
||||
const point = new DOMPoint(
|
||||
circle.cx.baseVal.value,
|
||||
circle.cy.baseVal.value,
|
||||
).matrixTransform(matrix);
|
||||
return { x: point.x, y: point.y };
|
||||
}),
|
||||
);
|
||||
const closestCornerDistance = Math.min(
|
||||
...cornerScreenPoints.map((point) =>
|
||||
Math.hypot(point.x - boundaryTarget.x, point.y - boundaryTarget.y),
|
||||
),
|
||||
);
|
||||
expect(
|
||||
closestCornerDistance,
|
||||
JSON.stringify({ boundaryStart, boundaryTarget, cornerScreenPoints }),
|
||||
).toBeLessThan(3);
|
||||
|
||||
const boundaryPathAfter = await boundaryPathLocator.getAttribute("d");
|
||||
const linePoints = [
|
||||
...(boundaryPathAfter ?? "").matchAll(
|
||||
...(pathAfterSegmentDrags ?? "").matchAll(
|
||||
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
|
||||
),
|
||||
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
|
||||
@@ -623,110 +520,127 @@ test("缩小画布后连接线端点仍与端口图标边缘对齐", async ({ pa
|
||||
expect(alignment!.targetGapY).toBeLessThan(0.75);
|
||||
});
|
||||
|
||||
test("直线首次折弯后即使原手柄卸载,拖动仍连续且保持正交", async ({
|
||||
page,
|
||||
}) => {
|
||||
const project = {
|
||||
...structuredClone(wideProject),
|
||||
nodes: [
|
||||
projectNode("straight-source", 0, 260),
|
||||
projectNode("straight-target", 700, 260),
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
id: "straight-edge",
|
||||
source: "straight-source",
|
||||
target: "straight-target",
|
||||
sourceHandle: "port_b",
|
||||
targetHandle: "port_a",
|
||||
data: { isContactEdge: false },
|
||||
},
|
||||
],
|
||||
};
|
||||
await page.addInitScript((storedProject) => {
|
||||
window.localStorage.setItem(
|
||||
"system-simulation-flow:project:demo-system",
|
||||
JSON.stringify(storedProject),
|
||||
for (const route of [
|
||||
{ label: "直线", targetY: 260, targetRotation: 0, pointCount: 2 },
|
||||
{ label: "L 型连接线", targetY: 480, targetRotation: 90, pointCount: 3 },
|
||||
]) {
|
||||
test(`${route.label}可直接拖动线条,首次折弯后仍连续且保持正交`, async ({
|
||||
page,
|
||||
}) => {
|
||||
const project = {
|
||||
...structuredClone(wideProject),
|
||||
nodes: [
|
||||
projectNode("straight-source", 0, 260),
|
||||
{
|
||||
...projectNode("straight-target", 700, route.targetY),
|
||||
data: {
|
||||
...projectNode("straight-target", 700, route.targetY).data,
|
||||
rotation: route.targetRotation,
|
||||
},
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
id: "straight-edge",
|
||||
source: "straight-source",
|
||||
target: "straight-target",
|
||||
sourceHandle: "port_b",
|
||||
targetHandle: "port_a",
|
||||
data: { isContactEdge: false },
|
||||
},
|
||||
],
|
||||
};
|
||||
await page.addInitScript((storedProject) => {
|
||||
window.localStorage.setItem(
|
||||
"system-simulation-flow:project:demo-system",
|
||||
JSON.stringify(storedProject),
|
||||
);
|
||||
}, project);
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "加载工程", exact: true }).click();
|
||||
|
||||
const edge = page.locator(
|
||||
'.flow-canvas .react-flow__edge[data-id="straight-edge"]',
|
||||
);
|
||||
}, project);
|
||||
await page.goto("/");
|
||||
await page.getByRole("button", { name: "加载工程", exact: true }).click();
|
||||
|
||||
const edge = page.locator(
|
||||
'.flow-canvas .react-flow__edge[data-id="straight-edge"]',
|
||||
);
|
||||
const edgePath = edge.locator(".react-flow__edge-path");
|
||||
await edge.locator(".react-flow__edge-interaction").dispatchEvent("click");
|
||||
const routeHandle = edge.locator(".manual-edge-route-handle");
|
||||
await expect(routeHandle).toHaveCount(1);
|
||||
const dragStart = await routeHandle.evaluate((circle: SVGCircleElement) => {
|
||||
const matrix = circle.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取直线路由手柄坐标");
|
||||
}
|
||||
const point = new DOMPoint(
|
||||
circle.cx.baseVal.value,
|
||||
circle.cy.baseVal.value,
|
||||
).matrixTransform(matrix);
|
||||
return { x: point.x, y: point.y };
|
||||
});
|
||||
const pathBefore = await edgePath.getAttribute("d");
|
||||
await page.mouse.move(dragStart.x, dragStart.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(dragStart.x + 18, dragStart.y + 21, { steps: 4 });
|
||||
|
||||
await expect(routeHandle).toHaveCount(0);
|
||||
const verticalSegment = edge
|
||||
.locator(".manual-edge-segment-handle.vertical")
|
||||
.first();
|
||||
await expect(verticalSegment).toHaveCount(1);
|
||||
const segmentXAtHalfMove = await verticalSegment.evaluate(
|
||||
(line: SVGLineElement) => {
|
||||
const edgePath = edge.locator(".react-flow__edge-path");
|
||||
await edge.locator(".react-flow__edge-interaction").dispatchEvent("click");
|
||||
await expect(edge.locator("circle")).toHaveCount(0);
|
||||
const routeHandle = edge.locator(
|
||||
'.manual-edge-segment-handle[data-segment-index="0"]',
|
||||
);
|
||||
await expect(routeHandle).toHaveCount(1);
|
||||
await expect(routeHandle).toHaveCSS("pointer-events", "stroke");
|
||||
const dragStart = await routeHandle.evaluate((line: SVGLineElement) => {
|
||||
const matrix = line.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取首次折弯后的竖直线段坐标");
|
||||
throw new Error("无法获取待拖动连接线段坐标");
|
||||
}
|
||||
return new DOMPoint(
|
||||
line.x1.baseVal.value,
|
||||
line.y1.baseVal.value,
|
||||
).matrixTransform(matrix).x;
|
||||
},
|
||||
);
|
||||
const point = new DOMPoint(
|
||||
line.x1.baseVal.value * 0.75 + line.x2.baseVal.value * 0.25,
|
||||
line.y1.baseVal.value * 0.75 + line.y2.baseVal.value * 0.25,
|
||||
).matrixTransform(matrix);
|
||||
return { x: point.x, y: point.y };
|
||||
});
|
||||
const pathBefore = await edgePath.getAttribute("d");
|
||||
expect([...(pathBefore ?? "").matchAll(/[ML]\s/g)]).toHaveLength(route.pointCount);
|
||||
await page.mouse.move(dragStart.x, dragStart.y);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(dragStart.x + 18, dragStart.y + 21, { steps: 4 });
|
||||
|
||||
await page.mouse.move(dragStart.x + 36, dragStart.y + 42, { steps: 4 });
|
||||
const segmentXAtFullMove = await verticalSegment.evaluate(
|
||||
(line: SVGLineElement) => {
|
||||
const matrix = line.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取连续拖动后的竖直线段坐标");
|
||||
}
|
||||
return new DOMPoint(
|
||||
line.x1.baseVal.value,
|
||||
line.y1.baseVal.value,
|
||||
).matrixTransform(matrix).x;
|
||||
},
|
||||
);
|
||||
await page.mouse.up();
|
||||
expect(Math.abs(segmentXAtFullMove - segmentXAtHalfMove)).toBeGreaterThan(10);
|
||||
await expect(edgePath).not.toHaveAttribute("d", pathBefore ?? "");
|
||||
await expect(
|
||||
edge.locator(".manual-edge-segment-handle.horizontal").first(),
|
||||
).toHaveCount(1);
|
||||
await expect(routeHandle).toHaveCount(0);
|
||||
const verticalSegment = edge
|
||||
.locator(".manual-edge-segment-handle.vertical")
|
||||
.first();
|
||||
await expect(verticalSegment).toHaveCount(1);
|
||||
const segmentXAtHalfMove = await verticalSegment.evaluate(
|
||||
(line: SVGLineElement) => {
|
||||
const matrix = line.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取首次折弯后的竖直线段坐标");
|
||||
}
|
||||
return new DOMPoint(
|
||||
line.x1.baseVal.value,
|
||||
line.y1.baseVal.value,
|
||||
).matrixTransform(matrix).x;
|
||||
},
|
||||
);
|
||||
|
||||
const routeAfter = await edgePath.getAttribute("d");
|
||||
const routePoints = [
|
||||
...(routeAfter ?? "").matchAll(
|
||||
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
|
||||
),
|
||||
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
|
||||
routePoints.slice(1).forEach((point, index) => {
|
||||
const previous = routePoints[index];
|
||||
expect(
|
||||
Math.abs(point.x - previous.x) < 0.01 ||
|
||||
Math.abs(point.y - previous.y) < 0.01,
|
||||
).toBe(true);
|
||||
await page.mouse.move(dragStart.x + 36, dragStart.y + 42, { steps: 4 });
|
||||
const segmentXAtFullMove = await verticalSegment.evaluate(
|
||||
(line: SVGLineElement) => {
|
||||
const matrix = line.getScreenCTM();
|
||||
if (!matrix) {
|
||||
throw new Error("无法获取连续拖动后的竖直线段坐标");
|
||||
}
|
||||
return new DOMPoint(
|
||||
line.x1.baseVal.value,
|
||||
line.y1.baseVal.value,
|
||||
).matrixTransform(matrix).x;
|
||||
},
|
||||
);
|
||||
await page.mouse.up();
|
||||
expect(Math.abs(segmentXAtFullMove - segmentXAtHalfMove)).toBeGreaterThan(10);
|
||||
await expect(edgePath).not.toHaveAttribute("d", pathBefore ?? "");
|
||||
await expect(edge.locator("circle")).toHaveCount(0);
|
||||
await expect(
|
||||
edge.locator(".manual-edge-segment-handle.horizontal").first(),
|
||||
).toHaveCount(1);
|
||||
|
||||
const routeAfter = await edgePath.getAttribute("d");
|
||||
const routePoints = [
|
||||
...(routeAfter ?? "").matchAll(
|
||||
/[ML]\s+(-?\d+(?:\.\d+)?)\s+(-?\d+(?:\.\d+)?)/g,
|
||||
),
|
||||
].map((match) => ({ x: Number(match[1]), y: Number(match[2]) }));
|
||||
routePoints.slice(1).forEach((point, index) => {
|
||||
const previous = routePoints[index];
|
||||
expect(
|
||||
Math.abs(point.x - previous.x) < 0.01 ||
|
||||
Math.abs(point.y - previous.y) < 0.01,
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test("同一组件不同端口发出的线路在远端交叉时仍显示跨线桥", async ({
|
||||
page,
|
||||
|
||||
Reference in new issue
Block a user