Skip to content

Commit

Permalink
feat: drag-canvas supports range
Browse files Browse the repository at this point in the history
  • Loading branch information
yvonneyx committed Sep 3, 2024
1 parent 59b369c commit 668a367
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 17 deletions.
47 changes: 43 additions & 4 deletions packages/g6/src/behaviors/drag-canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import type { Cursor } from '@antv/g';
import { debounce, isObject } from '@antv/util';
import { CommonEvent } from '../constants';
import type { RuntimeContext } from '../runtime/types';
import type { IKeyboardEvent, IPointerEvent, Vector2, ViewportAnimationEffectTiming } from '../types';
import type { IKeyboardEvent, IPointerEvent, Padding, Vector2, ViewportAnimationEffectTiming } from '../types';
import { getExpandedBBox, getPointBBox, isPointInBBox } from '../utils/bbox';
import { parsePadding } from '../utils/padding';
import type { ShortcutKey } from '../utils/shortcut';
import { Shortcut } from '../utils/shortcut';
import { multiply } from '../utils/vector';
import { multiply, subtract } from '../utils/vector';
import type { BaseBehaviorOptions } from './base-behavior';
import { BaseBehavior } from './base-behavior';

Expand Down Expand Up @@ -41,6 +43,13 @@ export interface DragCanvasOptions extends BaseBehaviorOptions {
* @defaultValue `'both'`
*/
direction?: 'x' | 'y' | 'both';
/**
* <zh/> 可拖拽的视口范围,默认最多可拖拽一屏。可以分别设置上、右、下、左四个方向的范围,每个方向的范围在 [0, Infinity] 之间
*
* <en/> The draggable viewport range allows you to drag up to one screen by default. You can set the range for each direction (top, right, bottom, left) individually, with each direction's range between [0, Infinity]
* @defaultValue 1
*/
range?: Padding;
/**
* <zh/> 触发拖拽的方式,默认使用指针按下拖拽
*
Expand Down Expand Up @@ -80,6 +89,7 @@ export class DragCanvas extends BaseBehavior<DragCanvasOptions> {
},
sensitivity: 10,
direction: 'both',
range: 1,
};

private shortcut: Shortcut;
Expand Down Expand Up @@ -169,16 +179,45 @@ export class DragCanvas extends BaseBehavior<DragCanvasOptions> {
* @internal
*/
protected async translate(offset: Vector2, animation?: ViewportAnimationEffectTiming) {
let [dx, dy] = offset;
offset = this.clampByDirection(offset);
offset = this.clampByRange(offset);

await this.context.graph.translateBy(offset, animation);
}

private clampByDirection([dx, dy]: Vector2): Vector2 {
const { direction } = this.options;
if (direction === 'x') {
dy = 0;
} else if (direction === 'y') {
dx = 0;
}
return [dx, dy];
}

await this.context.graph.translateBy([dx, dy], animation);
private clampByRange([dx, dy]: Vector2): Vector2 {
const { viewport, canvas } = this.context;

const [canvasWidth, canvasHeight] = canvas.getSize();
const [top, right, bottom, left] = parsePadding(this.options.range);
const range = [canvasHeight * top, canvasWidth * right, canvasHeight * bottom, canvasWidth * left];
const draggableArea = getExpandedBBox(getPointBBox(viewport!.getCanvasCenter()), range);

const nextViewportCenter = subtract(viewport!.getViewportCenter(), [dx, dy, 0]);
if (!isPointInBBox(nextViewportCenter, draggableArea)) {
const {
min: [minX, minY],
max: [maxX, maxY],
} = draggableArea;

if ((nextViewportCenter[0] < minX && dx > 0) || (nextViewportCenter[0] > maxX && dx < 0)) {
dx = 0;
}
if ((nextViewportCenter[1] < minY && dy > 0) || (nextViewportCenter[1] > maxY && dy < 0)) {
dy = 0;
}
}
return [dx, dy];
}

private validate(event: IPointerEvent | IKeyboardEvent) {
Expand Down
20 changes: 7 additions & 13 deletions packages/g6/src/behaviors/scroll-canvas.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import type { Tuple3Number } from '@antv/g';
import { AABB } from '@antv/g';
import { isFunction, isObject } from '@antv/util';
import { CommonEvent } from '../constants';
import type { RuntimeContext } from '../runtime/types';
import type { IKeyboardEvent, Padding, Point } from '../types';
import { getExpandedBBox, isPointInBBox } from '../utils/bbox';
import { getExpandedBBox, getPointBBox, isPointInBBox } from '../utils/bbox';
import { parsePadding } from '../utils/padding';
import { Shortcut, ShortcutKey } from '../utils/shortcut';
import { multiply, subtract } from '../utils/vector';
Expand Down Expand Up @@ -48,9 +46,9 @@ export interface ScrollCanvasOptions extends BaseBehaviorOptions {
*/
direction?: 'x' | 'y';
/**
* <zh/> 可滚动的视口范围,默认最多可以滚动一屏的位置。可以分别设置上右下左,单个方向范围在 [0, Infinity] 之间
* <zh/> 可滚动的视口范围,默认最多可滚动一屏。可以分别设置上、右、下、左四个方向的范围,每个方向的范围在 [0, Infinity] 之间
*
* <en/> The range of the scrollable viewport, by default, you can scroll to the position of one screen at most. The four directions can be set separately, and the range of a single direction is between [0, Infinity]
* <en/> The scrollable viewport range allows you to scroll up to one screen by default. You can set the range for each direction (top, right, bottom, left) individually, with each direction's range between [0, Infinity]
* @defaultValue 1
*/
range?: Padding;
Expand Down Expand Up @@ -86,7 +84,7 @@ export class ScrollCanvas extends BaseBehavior<ScrollCanvasOptions> {
enable: true,
sensitivity: 1,
preventDefault: true,
range: 1,
range: 0.5,
};

private shortcut: Shortcut;
Expand Down Expand Up @@ -166,21 +164,17 @@ export class ScrollCanvas extends BaseBehavior<ScrollCanvasOptions> {
private clampByRange([dx, dy]: Point) {
const { viewport, canvas } = this.context;

const canvasCenter = [...viewport!.getCanvasCenter(), 0] as Tuple3Number;
const bbox = new AABB();
bbox.setMinMax(canvasCenter, canvasCenter);

const [canvasWidth, canvasHeight] = canvas.getSize();
const [top, right, bottom, left] = parsePadding(this.options.range);
const range = [canvasHeight * top, canvasWidth * right, canvasHeight * bottom, canvasWidth * left];
const area = getExpandedBBox(bbox, range);
const scrollableArea = getExpandedBBox(getPointBBox(viewport!.getCanvasCenter()), range);

const nextViewportCenter = subtract(viewport!.getViewportCenter(), [dx, dy, 0]);
if (!isPointInBBox(nextViewportCenter, area)) {
if (!isPointInBBox(nextViewportCenter, scrollableArea)) {
const {
min: [minX, minY],
max: [maxX, maxY],
} = area;
} = scrollableArea;

if ((nextViewportCenter[0] < minX && dx > 0) || (nextViewportCenter[0] > maxX && dx < 0)) {
dx = 0;
Expand Down

0 comments on commit 668a367

Please sign in to comment.