From 668a3673b4191a8226a8acd281e2d87e76ea746b Mon Sep 17 00:00:00 2001 From: yvonneyx Date: Tue, 3 Sep 2024 11:08:41 +0800 Subject: [PATCH] feat: drag-canvas supports range --- packages/g6/src/behaviors/drag-canvas.ts | 47 ++++++++++++++++++++-- packages/g6/src/behaviors/scroll-canvas.ts | 20 ++++----- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/packages/g6/src/behaviors/drag-canvas.ts b/packages/g6/src/behaviors/drag-canvas.ts index 4b13e88444d..c4fbd79cc7c 100644 --- a/packages/g6/src/behaviors/drag-canvas.ts +++ b/packages/g6/src/behaviors/drag-canvas.ts @@ -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'; @@ -41,6 +43,13 @@ export interface DragCanvasOptions extends BaseBehaviorOptions { * @defaultValue `'both'` */ direction?: 'x' | 'y' | 'both'; + /** + * 可拖拽的视口范围,默认最多可拖拽一屏。可以分别设置上、右、下、左四个方向的范围,每个方向的范围在 [0, Infinity] 之间 + * + * 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; /** * 触发拖拽的方式,默认使用指针按下拖拽 * @@ -80,6 +89,7 @@ export class DragCanvas extends BaseBehavior { }, sensitivity: 10, direction: 'both', + range: 1, }; private shortcut: Shortcut; @@ -169,16 +179,45 @@ export class DragCanvas extends BaseBehavior { * @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) { diff --git a/packages/g6/src/behaviors/scroll-canvas.ts b/packages/g6/src/behaviors/scroll-canvas.ts index e4fde6afa69..88741c816a9 100644 --- a/packages/g6/src/behaviors/scroll-canvas.ts +++ b/packages/g6/src/behaviors/scroll-canvas.ts @@ -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'; @@ -48,9 +46,9 @@ export interface ScrollCanvasOptions extends BaseBehaviorOptions { */ direction?: 'x' | 'y'; /** - * 可滚动的视口范围,默认最多可以滚动一屏的位置。可以分别设置上右下左,单个方向范围在 [0, Infinity] 之间 + * 可滚动的视口范围,默认最多可滚动一屏。可以分别设置上、右、下、左四个方向的范围,每个方向的范围在 [0, Infinity] 之间 * - * 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] + * 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; @@ -86,7 +84,7 @@ export class ScrollCanvas extends BaseBehavior { enable: true, sensitivity: 1, preventDefault: true, - range: 1, + range: 0.5, }; private shortcut: Shortcut; @@ -166,21 +164,17 @@ export class ScrollCanvas extends BaseBehavior { 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;