Skip to content

Commit

Permalink
feat(edgeless): support updating dragging area when viewport updates (t…
Browse files Browse the repository at this point in the history
  • Loading branch information
donteatfriedrice authored Sep 22, 2023
1 parent c956087 commit c91d8d4
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { PointerEventState } from '@blocksuite/block-std';
import { assertExists, noop } from '@blocksuite/global/utils';
import { assertExists, DisposableGroup, noop } from '@blocksuite/global/utils';

import { getBlockClipboardInfo } from '../../../__internal__/clipboard/index.js';
import {
Expand Down Expand Up @@ -63,6 +63,7 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
dragType = DefaultModeDragType.None;

private _dragStartPos: IVec = [0, 0];
private _dragLastPos: IVec = [0, 0];
private _dragStartModelCoord: IVec = [0, 0];
private _dragLastModelCoord: IVec = [0, 0];
private _lastMoveDelta: IVec = [0, 0];
Expand All @@ -74,6 +75,8 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
private _toBeMoved: Selectable[] = [];
private _frames = new Set<FrameElement>();
private _autoPanTimer: number | null = null;
private _dragging = false;
private _draggingAreaDisposables: DisposableGroup | null = null;

override get draggingArea() {
if (this.dragType === DefaultModeDragType.Selecting) {
Expand Down Expand Up @@ -377,11 +380,16 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
});
}

private _updateSelectingState = (e: PointerEventState) => {
private _updateSelectingState = () => {
const { surface } = this._edgeless;
const { viewport } = surface;
const startX = this._dragStartModelCoord[0];
const startY = this._dragStartModelCoord[1];
const [curX, curY] = surface.toModelCoord(e.x, e.y);
// Should convert the last drag position to model coordinate
const [curX, curY] = viewport.toModelCoord(
this._dragLastPos[0],
this._dragLastPos[1]
);
const x = Math.min(startX, curX);
const y = Math.min(startY, curY);

Expand All @@ -399,6 +407,7 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
false
);

// Record the last model coordinate for dragging area updating
this._dragLastModelCoord = [curX, curY];
this._forceUpdateSelection(this.dragType, true);
this._edgeless.slots.draggingAreaUpdated.emit();
Expand All @@ -416,18 +425,28 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
}
};

private _startAutoPanning = (delta: IVec, e: PointerEventState) => {
private _clearDraggingAreaDisposable = () => {
if (this._draggingAreaDisposables) {
this._draggingAreaDisposables.dispose();
this._draggingAreaDisposables = null;
}
};

private _startAutoPanning = (delta: IVec) => {
this._panViewport(delta);
this._stopAutoPanning();

this._autoPanTimer = window.setInterval(() => {
this._panViewport(delta);
this._updateSelectingState(e);
this._updateSelectingState();
}, 30);
};

private _clearSelectingState = () => {
this._stopAutoPanning();
this._clearDraggingAreaDisposable();
this._dragging = false;
this._dragLastPos = [0, 0];
this._dragStartModelCoord = [0, 0];
this._dragLastModelCoord = [0, 0];
this._edgeless.slots.draggingAreaUpdated.emit();
Expand Down Expand Up @@ -461,7 +480,9 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
initializeDragState(e: PointerEventState, dragType: DefaultModeDragType) {
const { x, y } = e;
this.dragType = dragType;
this._dragging = true;
this._dragStartPos = [x, y];
this._dragLastPos = [x, y];
const [startX, startY] = this._surface.toModelCoord(x, y);
this._dragStartModelCoord = [startX, startY];
this._dragLastModelCoord = [startX, startY];
Expand All @@ -471,6 +492,25 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
this._selectedBounds = this._toBeMoved.map(element =>
Bound.deserialize(element.xywh)
);

// If the drag type is selecting, set up the dragging area disposable group
// If the viewport updates when dragging, should update the dragging area and selection
if (this.dragType === DefaultModeDragType.Selecting) {
this._clearDraggingAreaDisposable();

this._draggingAreaDisposables = new DisposableGroup();
this._draggingAreaDisposables.add(
this._edgeless.slots.viewportUpdated.on(() => {
if (
this.dragType === DefaultModeDragType.Selecting &&
this._dragging &&
!this._autoPanTimer
) {
this._updateSelectingState();
}
})
);
}
}

onContainerDragMove(e: PointerEventState) {
Expand All @@ -479,10 +519,12 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
const zoom = viewport.zoom;
switch (this.dragType) {
case DefaultModeDragType.Selecting: {
this._updateSelectingState(e);
// Record the last drag pointer position for auto panning and view port updating
this._dragLastPos = [e.x, e.y];
this._updateSelectingState();
const moveDelta = calPanDelta(viewport, e);
if (moveDelta) {
this._startAutoPanning(moveDelta, e);
this._startAutoPanning(moveDelta);
} else {
this._stopAutoPanning();
}
Expand Down Expand Up @@ -554,6 +596,7 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
}
const { surface } = this._edgeless;
this._dragStartPos = [0, 0];
this._dragLastPos = [0, 0];
this._selectedBounds = [];
this._lastMoveDelta = [0, 0];
surface.snap.cleanupAlignables();
Expand Down Expand Up @@ -582,6 +625,8 @@ export class DefaultToolController extends EdgelessToolController<DefaultTool> {
}

beforeModeSwitch() {
this._stopAutoPanning();
this._clearDraggingAreaDisposable();
noop();
}

Expand Down
47 changes: 47 additions & 0 deletions tests/edgeless/selection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,3 +314,50 @@ test('should auto panning when selection rectangle reaches viewport edges', asyn
expect(selectedRect).toBeVisible();
await page.waitForTimeout(300);
});

test('should also update dragging area when viewport changes', async ({
page,
}) => {
await enterPlaygroundRoom(page);
await initEmptyEdgelessState(page);

await switchEditorMode(page);
await actions.zoomResetByKeyboard(page);

// Panning to the top
await page.mouse.click(400, 600);
await setEdgelessTool(page, 'pan');
await dragBetweenCoords(
page,
{
x: 400,
y: 600,
},
{
x: 400,
y: 100,
}
);
await setEdgelessTool(page, 'default');
await page.mouse.click(200, 300);

const selectedRectClass = '.affine-edgeless-selected-rect';
let selectedRect = await page.locator(selectedRectClass);
expect(selectedRect).toBeHidden();
// set up initial dragging area
await page.mouse.move(200, 300);
await page.mouse.down();
await page.mouse.move(600, 200, { steps: 20 });
await page.waitForTimeout(300);

// wheel the viewport to the top
await page.mouse.wheel(0, -300);
await page.waitForTimeout(300);
await page.mouse.up();

// Expect to select the empty note
selectedRect = await page.locator(selectedRectClass);
await page.waitForTimeout(300);
expect(selectedRect).toBeVisible();
await page.waitForTimeout(300);
});

0 comments on commit c91d8d4

Please sign in to comment.