mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-06 11:59:51 +08:00
fix: align with only one element at a time (#10739)
### Changed - Align with only one element at a time - Mind map nodes cannot be alignment candidates
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
import { Overlay } from '@blocksuite/affine-block-surface';
|
import { Overlay } from '@blocksuite/affine-block-surface';
|
||||||
import { ConnectorElementModel } from '@blocksuite/affine-model';
|
import {
|
||||||
|
ConnectorElementModel,
|
||||||
|
MindmapElementModel,
|
||||||
|
} from '@blocksuite/affine-model';
|
||||||
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
import type { GfxModel } from '@blocksuite/block-std/gfx';
|
||||||
import { almostEqual, Bound, Point } from '@blocksuite/global/gfx';
|
import { almostEqual, Bound, Point } from '@blocksuite/global/gfx';
|
||||||
|
|
||||||
@@ -64,7 +67,13 @@ export class SnapManager extends Overlay {
|
|||||||
* corners, etc. It essentially represents the guidelines for the positioning
|
* corners, etc. It essentially represents the guidelines for the positioning
|
||||||
* and alignment within the individual graphic elements.
|
* and alignment within the individual graphic elements.
|
||||||
*/
|
*/
|
||||||
private _intraGraphicAlignLines: [Point, Point][] = [];
|
private _intraGraphicAlignLines: {
|
||||||
|
horizontal: [Point, Point][];
|
||||||
|
vertical: [Point, Point][];
|
||||||
|
} = {
|
||||||
|
horizontal: [],
|
||||||
|
vertical: [],
|
||||||
|
};
|
||||||
|
|
||||||
override clear() {
|
override clear() {
|
||||||
super.clear();
|
super.clear();
|
||||||
@@ -74,7 +83,10 @@ export class SnapManager extends Overlay {
|
|||||||
horizontal: [],
|
horizontal: [],
|
||||||
all: [],
|
all: [],
|
||||||
};
|
};
|
||||||
this._intraGraphicAlignLines = [];
|
this._intraGraphicAlignLines = {
|
||||||
|
horizontal: [],
|
||||||
|
vertical: [],
|
||||||
|
};
|
||||||
this._distributedAlignLines = [];
|
this._distributedAlignLines = [];
|
||||||
this._skippedElements.clear();
|
this._skippedElements.clear();
|
||||||
}
|
}
|
||||||
@@ -520,14 +532,12 @@ export class SnapManager extends Overlay {
|
|||||||
const top = Math.min(bound.minY + dy, other.minY);
|
const top = Math.min(bound.minY + dy, other.minY);
|
||||||
const down = Math.max(bound.maxY + dy, other.maxY);
|
const down = Math.max(bound.maxY + dy, other.maxY);
|
||||||
|
|
||||||
this._intraGraphicAlignLines.push(
|
this._intraGraphicAlignLines.horizontal = distanceIndices.map(
|
||||||
...distanceIndices.map(
|
idx =>
|
||||||
idx =>
|
[
|
||||||
[
|
new Point(alignXPosition[idx], top),
|
||||||
new Point(alignXPosition[idx], top),
|
new Point(alignXPosition[idx], down),
|
||||||
new Point(alignXPosition[idx], down),
|
] as [Point, Point]
|
||||||
] as [Point, Point]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,14 +577,12 @@ export class SnapManager extends Overlay {
|
|||||||
const left = Math.min(bound.minX + dx, other.minX);
|
const left = Math.min(bound.minX + dx, other.minX);
|
||||||
const right = Math.max(bound.maxX + dx, other.maxX);
|
const right = Math.max(bound.maxX + dx, other.maxX);
|
||||||
|
|
||||||
this._intraGraphicAlignLines.push(
|
this._intraGraphicAlignLines.vertical = alignPositionIndices.map(
|
||||||
...alignPositionIndices.map(
|
idx =>
|
||||||
idx =>
|
[
|
||||||
[
|
new Point(left, alignXPosition[idx]),
|
||||||
new Point(left, alignXPosition[idx]),
|
new Point(right, alignXPosition[idx]),
|
||||||
new Point(right, alignXPosition[idx]),
|
] as [Point, Point]
|
||||||
] as [Point, Point]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,18 +592,29 @@ export class SnapManager extends Overlay {
|
|||||||
|
|
||||||
const { viewport } = this.gfx;
|
const { viewport } = this.gfx;
|
||||||
|
|
||||||
this._intraGraphicAlignLines = [];
|
this._intraGraphicAlignLines = {
|
||||||
|
horizontal: [],
|
||||||
|
vertical: [],
|
||||||
|
};
|
||||||
this._distributedAlignLines = [];
|
this._distributedAlignLines = [];
|
||||||
this._updateAlignCandidates(bound);
|
this._updateAlignCandidates(bound);
|
||||||
|
|
||||||
for (const other of this._referenceBounds.all) {
|
for (const other of this._referenceBounds.all) {
|
||||||
const closestDistances = this._calculateClosestDistances(bound, other);
|
const closestDistances = this._calculateClosestDistances(bound, other);
|
||||||
|
|
||||||
if (closestDistances.horiz) {
|
if (
|
||||||
|
closestDistances.horiz &&
|
||||||
|
(!this._intraGraphicAlignLines.horizontal.length ||
|
||||||
|
Math.abs(closestDistances.horiz.distance) < Math.abs(rst.dx))
|
||||||
|
) {
|
||||||
this._updateXAlignPoint(rst, bound, other, closestDistances);
|
this._updateXAlignPoint(rst, bound, other, closestDistances);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (closestDistances.vert) {
|
if (
|
||||||
|
closestDistances.vert &&
|
||||||
|
(!this._intraGraphicAlignLines.vertical.length ||
|
||||||
|
Math.abs(closestDistances.vert.distance) < Math.abs(rst.dy))
|
||||||
|
) {
|
||||||
this._updateYAlignPoint(rst, bound, other, closestDistances);
|
this._updateYAlignPoint(rst, bound, other, closestDistances);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -616,7 +635,8 @@ export class SnapManager extends Overlay {
|
|||||||
|
|
||||||
override render(ctx: CanvasRenderingContext2D) {
|
override render(ctx: CanvasRenderingContext2D) {
|
||||||
if (
|
if (
|
||||||
this._intraGraphicAlignLines.length === 0 &&
|
this._intraGraphicAlignLines.vertical.length === 0 &&
|
||||||
|
this._intraGraphicAlignLines.horizontal.length === 0 &&
|
||||||
this._distributedAlignLines.length === 0
|
this._distributedAlignLines.length === 0
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
@@ -627,7 +647,10 @@ export class SnapManager extends Overlay {
|
|||||||
ctx.lineWidth = strokeWidth;
|
ctx.lineWidth = strokeWidth;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
this._intraGraphicAlignLines.forEach(line => {
|
[
|
||||||
|
...this._intraGraphicAlignLines.horizontal,
|
||||||
|
...this._intraGraphicAlignLines.vertical,
|
||||||
|
].forEach(line => {
|
||||||
let d = '';
|
let d = '';
|
||||||
if (line[0].x === line[1].x) {
|
if (line[0].x === line[1].x) {
|
||||||
const x = line[0].x;
|
const x = line[0].x;
|
||||||
@@ -666,6 +689,13 @@ export class SnapManager extends Overlay {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _isSkippedElement(element: GfxModel) {
|
||||||
|
return (
|
||||||
|
element instanceof ConnectorElementModel ||
|
||||||
|
element.group instanceof MindmapElementModel
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private _updateAlignCandidates(movingBound: Bound) {
|
private _updateAlignCandidates(movingBound: Bound) {
|
||||||
movingBound = movingBound.expand(ALIGN_THRESHOLD * this.gfx.viewport.zoom);
|
movingBound = movingBound.expand(ALIGN_THRESHOLD * this.gfx.viewport.zoom);
|
||||||
|
|
||||||
@@ -695,15 +725,13 @@ export class SnapManager extends Overlay {
|
|||||||
const allBounds: Bound[] = [];
|
const allBounds: Bound[] = [];
|
||||||
|
|
||||||
vertCandidates.forEach(candidate => {
|
vertCandidates.forEach(candidate => {
|
||||||
if (skipped.has(candidate) || candidate instanceof ConnectorElementModel)
|
if (skipped.has(candidate) || this._isSkippedElement(candidate)) return;
|
||||||
return;
|
|
||||||
verticalBounds.push(candidate.elementBound);
|
verticalBounds.push(candidate.elementBound);
|
||||||
allBounds.push(candidate.elementBound);
|
allBounds.push(candidate.elementBound);
|
||||||
});
|
});
|
||||||
|
|
||||||
horizCandidates.forEach(candidate => {
|
horizCandidates.forEach(candidate => {
|
||||||
if (skipped.has(candidate) || candidate instanceof ConnectorElementModel)
|
if (skipped.has(candidate) || this._isSkippedElement(candidate)) return;
|
||||||
return;
|
|
||||||
horizBounds.push(candidate.elementBound);
|
horizBounds.push(candidate.elementBound);
|
||||||
allBounds.push(candidate.elementBound);
|
allBounds.push(candidate.elementBound);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user