mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-13 08:06:24 +08:00
fix: connector should remain the same when its target or source switch to other
shape type (#11369) Fixes [BS-1431](https://linear.app/affine-design/issue/BS-1431/改变-shape-形状后,connector-丢失)
This commit is contained in:
@@ -1319,27 +1319,31 @@ export class ConnectorPathGenerator extends PathGenerator {
|
||||
|
||||
if (source.id) {
|
||||
const startTangentVertical = Vec.rot(startPoint.tangent, -Math.PI / 2);
|
||||
startPoint.out = Vec.mul(
|
||||
startTangentVertical,
|
||||
Math.max(
|
||||
100,
|
||||
Math.abs(
|
||||
Vec.pry(Vec.sub(endPoint, startPoint), startTangentVertical)
|
||||
) / 3
|
||||
)
|
||||
);
|
||||
startPoint.out = isVecZero(startTangentVertical)
|
||||
? Vec.mul(Vec.per(Vec.normalize(Vec.sub(startPoint, endPoint))), 20)
|
||||
: Vec.mul(
|
||||
startTangentVertical,
|
||||
Math.max(
|
||||
100,
|
||||
Math.abs(
|
||||
Vec.pry(Vec.sub(endPoint, startPoint), startTangentVertical)
|
||||
) / 3
|
||||
)
|
||||
);
|
||||
}
|
||||
if (target.id) {
|
||||
const endTangentVertical = Vec.rot(endPoint.tangent, -Math.PI / 2);
|
||||
endPoint.in = Vec.mul(
|
||||
endTangentVertical,
|
||||
Math.max(
|
||||
100,
|
||||
Math.abs(
|
||||
Vec.pry(Vec.sub(startPoint, endPoint), endTangentVertical)
|
||||
) / 3
|
||||
)
|
||||
);
|
||||
endPoint.in = isVecZero(endTangentVertical)
|
||||
? Vec.mul(Vec.per(Vec.normalize(Vec.sub(endPoint, startPoint))), 20)
|
||||
: Vec.mul(
|
||||
endTangentVertical,
|
||||
Math.max(
|
||||
100,
|
||||
Math.abs(
|
||||
Vec.pry(Vec.sub(startPoint, endPoint), endTangentVertical)
|
||||
) / 3
|
||||
)
|
||||
);
|
||||
}
|
||||
return [startPoint, endPoint];
|
||||
} else {
|
||||
|
||||
@@ -141,7 +141,7 @@ export const shapeToolbarConfig = {
|
||||
|
||||
return renderMenu({
|
||||
icon: ShapeIcon(),
|
||||
label: 'Switch type',
|
||||
label: 'Switch shape type',
|
||||
items: ShapeComponentConfig.map(item => ({
|
||||
key: item.tooltip,
|
||||
value: item.name,
|
||||
|
||||
@@ -9,12 +9,17 @@ import {
|
||||
createShapeElement,
|
||||
dragBetweenViewCoords,
|
||||
edgelessCommonSetup as commonSetup,
|
||||
getConnectorPath,
|
||||
getConnectorPathWithInOut,
|
||||
pickColorAtPoints,
|
||||
rotateElementByHandle,
|
||||
selectElementInEdgeless,
|
||||
setEdgelessTool,
|
||||
Shape,
|
||||
toModelCoord,
|
||||
toViewCoord,
|
||||
triggerComponentToolbarAction,
|
||||
triggerShapeSwitch,
|
||||
} from '../../utils/actions/edgeless.js';
|
||||
import { pressBackspace, waitNextFrame } from '../../utils/actions/index.js';
|
||||
import {
|
||||
@@ -320,4 +325,56 @@ test.describe('quick connect', () => {
|
||||
await page.mouse.move(...point);
|
||||
await assertConnectorPath(page, [[50, 100], endpoint]);
|
||||
});
|
||||
|
||||
test('the triangle connectors should remain the same when switch to other shape', async ({
|
||||
page,
|
||||
}) => {
|
||||
await commonSetup(page);
|
||||
|
||||
const shape1Id = await createShapeElement(
|
||||
page,
|
||||
[0, 0],
|
||||
[100, 100],
|
||||
Shape.Triangle
|
||||
);
|
||||
const shape2Id = await createShapeElement(
|
||||
page,
|
||||
[200, 0],
|
||||
[300, 100],
|
||||
Shape.Triangle
|
||||
);
|
||||
|
||||
await setEdgelessTool(page, 'connector');
|
||||
await dragBetweenViewCoords(page, [60, 50], [240, 50]);
|
||||
|
||||
{
|
||||
const path = await getConnectorPath(page);
|
||||
// make sure the connector is created
|
||||
expect(path.length).toBeGreaterThan(0);
|
||||
}
|
||||
|
||||
// switch to other shape
|
||||
|
||||
await selectElementInEdgeless(page, [shape1Id]);
|
||||
await triggerShapeSwitch(page, 'Square');
|
||||
|
||||
await selectElementInEdgeless(page, [shape2Id]);
|
||||
await triggerShapeSwitch(page, 'Square');
|
||||
|
||||
await dragBetweenViewCoords(page, [50, 50], [0, 0]);
|
||||
|
||||
await dragBetweenViewCoords(page, [250, 50], [300, 50]);
|
||||
|
||||
{
|
||||
const path = await getConnectorPathWithInOut(page);
|
||||
expect(path.length).toBeGreaterThan(0);
|
||||
path.forEach(point => {
|
||||
[0, 1].forEach(i => {
|
||||
expect(point.in[i]).not.toBeNaN();
|
||||
expect(point.out[i]).not.toBeNaN();
|
||||
expect(point.point[i]).not.toBeNaN();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1082,6 +1082,19 @@ type Action =
|
||||
| 'autoArrange'
|
||||
| 'autoResize';
|
||||
|
||||
export async function triggerShapeSwitch(
|
||||
page: Page,
|
||||
type: 'Square' | 'Ellipse' | 'Diamond' | 'Triangle' | 'Rounded rectangle'
|
||||
) {
|
||||
const button = locatorComponentToolbar(page)
|
||||
.getByLabel('Switch shape type')
|
||||
.first();
|
||||
await button.click();
|
||||
|
||||
const shapeButton = locatorComponentToolbar(page).getByLabel(type);
|
||||
await shapeButton.click();
|
||||
}
|
||||
|
||||
export async function triggerComponentToolbarAction(
|
||||
page: Page,
|
||||
action: Action
|
||||
@@ -1598,6 +1611,31 @@ export async function getConnectorPath(page: Page, index = 0): Promise<IVec[]> {
|
||||
);
|
||||
}
|
||||
|
||||
export async function getConnectorPathWithInOut(
|
||||
page: Page,
|
||||
index = 0
|
||||
): Promise<
|
||||
{
|
||||
point: IVec;
|
||||
in: IVec;
|
||||
out: IVec;
|
||||
}[]
|
||||
> {
|
||||
return page.evaluate(
|
||||
([index]) => {
|
||||
const container = document.querySelector('affine-edgeless-root');
|
||||
if (!container) throw new Error('container not found');
|
||||
const connectors = container.service.crud.getElementsByType('connector');
|
||||
return connectors[index].absolutePath.map(path => ({
|
||||
point: [path[0], path[1]],
|
||||
in: path.in,
|
||||
out: path.out,
|
||||
}));
|
||||
},
|
||||
[index]
|
||||
);
|
||||
}
|
||||
|
||||
export async function getEdgelessElementBound(
|
||||
page: Page,
|
||||
elementId: string
|
||||
|
||||
Reference in New Issue
Block a user