variable autoPanSpeed

This commit is contained in:
peterkogo
2024-07-04 16:33:45 +02:00
parent 0589b89d0e
commit 3f259e9662
10 changed files with 37 additions and 10 deletions
@@ -139,6 +139,7 @@ function HandleComponent(
isValidConnection: isValidConnection || currentStore.isValidConnection, isValidConnection: isValidConnection || currentStore.isValidConnection,
getTransform: () => store.getState().transform, getTransform: () => store.getState().transform,
getFromHandle: () => store.getState().connection.fromHandle, getFromHandle: () => store.getState().connection.fromHandle,
autoPanSpeed: currentStore.autoPanSpeed,
}); });
} }
@@ -66,6 +66,7 @@ const reactFlowFieldsToTrack = [
'nodeDragThreshold', 'nodeDragThreshold',
'onBeforeDelete', 'onBeforeDelete',
'debug', 'debug',
'autoPanSpeed',
] as const; ] as const;
type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number]; type ReactFlowFieldsToTrack = (typeof reactFlowFieldsToTrack)[number];
@@ -129,6 +129,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
disableKeyboardA11y = false, disableKeyboardA11y = false,
autoPanOnConnect, autoPanOnConnect,
autoPanOnNodeDrag, autoPanOnNodeDrag,
autoPanSpeed,
connectionRadius, connectionRadius,
isValidConnection, isValidConnection,
onError, onError,
@@ -269,6 +270,7 @@ function ReactFlow<NodeType extends Node = Node, EdgeType extends Edge = Edge>(
rfId={rfId} rfId={rfId}
autoPanOnConnect={autoPanOnConnect} autoPanOnConnect={autoPanOnConnect}
autoPanOnNodeDrag={autoPanOnNodeDrag} autoPanOnNodeDrag={autoPanOnNodeDrag}
autoPanSpeed={autoPanSpeed}
onError={onError} onError={onError}
connectionRadius={connectionRadius} connectionRadius={connectionRadius}
isValidConnection={isValidConnection} isValidConnection={isValidConnection}
+1
View File
@@ -112,6 +112,7 @@ const getInitialState = ({
ariaLiveMessage: '', ariaLiveMessage: '',
autoPanOnConnect: true, autoPanOnConnect: true,
autoPanOnNodeDrag: true, autoPanOnNodeDrag: true,
autoPanSpeed: 15,
connectionRadius: 20, connectionRadius: 20,
onError: devWarn, onError: devWarn,
isValidConnection: undefined, isValidConnection: undefined,
@@ -471,6 +471,10 @@ export interface ReactFlowProps<NodeType extends Node = Node, EdgeType extends E
* @default true * @default true
*/ */
autoPanOnConnect?: boolean; autoPanOnConnect?: boolean;
/** The speed at which the viewport pans while dragging a node or a selection box.
* @default 15
*/
autoPanSpeed?: number;
/** You can enable this prop to automatically pan the viewport while making a new connection. /** You can enable this prop to automatically pan the viewport while making a new connection.
* @default true * @default true
*/ */
+1
View File
@@ -139,6 +139,7 @@ export type ReactFlowStore<NodeType extends Node = Node, EdgeType extends Edge =
ariaLiveMessage: string; ariaLiveMessage: string;
autoPanOnConnect: boolean; autoPanOnConnect: boolean;
autoPanOnNodeDrag: boolean; autoPanOnNodeDrag: boolean;
autoPanSpeed: number;
connectionRadius: number; connectionRadius: number;
isValidConnection?: IsValidConnection<EdgeType>; isValidConnection?: IsValidConnection<EdgeType>;
+18 -6
View File
@@ -21,6 +21,10 @@ export const clampPosition = (position: XYPosition = { x: 0, y: 0 }, extent: Coo
y: clamp(position.y, extent[0][1], extent[1][1]), y: clamp(position.y, extent[0][1], extent[1][1]),
}); });
function easeInOutSine(x: number): number {
return -(Math.cos(Math.PI * x) - 1) / 2;
}
/** /**
* Calculates the velocity of panning when the mouse is close to the edge of the canvas * Calculates the velocity of panning when the mouse is close to the edge of the canvas
* @internal * @internal
@@ -29,19 +33,27 @@ export const clampPosition = (position: XYPosition = { x: 0, y: 0 }, extent: Coo
* @param max - Maximal position on canvas before panning starts * @param max - Maximal position on canvas before panning starts
* @returns - A number between 0 and 1 that represents the velocity of panning * @returns - A number between 0 and 1 that represents the velocity of panning
*/ */
const calcAutoPanVelocity = (value: number, min: number, max: number): number => { const calcAutoPanVelocity = (value: number, min: number, max: number, zoom: number): number => {
clamp(zoom, 0, 1);
if (value < min) { if (value < min) {
return clamp(Math.abs(value - min), 1, 50) / 50; return clamp(Math.abs(value - min), 1, min) / min;
} else if (value > max) { } else if (value > max) {
return -clamp(Math.abs(value - max), 1, 50) / 50; return -clamp(Math.abs(value - max), 1, min) / min;
} }
return 0; return 0;
}; };
export const calcAutoPan = (pos: XYPosition, bounds: Dimensions): number[] => { export const calcAutoPan = (
const xMovement = calcAutoPanVelocity(pos.x, 35, bounds.width - 35) * 20; pos: XYPosition,
const yMovement = calcAutoPanVelocity(pos.y, 35, bounds.height - 35) * 20; bounds: Dimensions,
transform: Transform,
speed: number = 15,
distance: number = 50
): number[] => {
const zoomFactor = clamp(transform[2] * 10, 0.01, 1);
const xMovement = calcAutoPanVelocity(pos.x, distance, bounds.width - distance, transform[2]) * speed * zoomFactor;
const yMovement = calcAutoPanVelocity(pos.y, distance, bounds.height - distance, transform[2]) * speed * zoomFactor;
return [xMovement, yMovement]; return [xMovement, yMovement];
}; };
+5 -3
View File
@@ -61,6 +61,7 @@ type StoreItems<OnNodeDrag> = {
onSelectionDrag?: OnSelectionDrag; onSelectionDrag?: OnSelectionDrag;
onSelectionDragStop?: OnSelectionDrag; onSelectionDragStop?: OnSelectionDrag;
updateNodePositions: UpdateNodePositions; updateNodePositions: UpdateNodePositions;
autoPanSpeed?: number;
}; };
export type XYDragParams<OnNodeDrag> = { export type XYDragParams<OnNodeDrag> = {
@@ -69,6 +70,7 @@ export type XYDragParams<OnNodeDrag> = {
onDrag?: OnDrag; onDrag?: OnDrag;
onDragStop?: OnDrag; onDragStop?: OnDrag;
onNodeMouseDown?: (id: string) => void; onNodeMouseDown?: (id: string) => void;
autoPanSpeed?: number;
}; };
export type XYDragInstance = { export type XYDragInstance = {
@@ -198,11 +200,11 @@ export function XYDrag<OnNodeDrag extends (e: any, nodes: any, node: any) => voi
return; return;
} }
const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds); const { transform, panBy, autoPanSpeed } = getStoreItems();
const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, transform, autoPanSpeed);
if (xMovement !== 0 || yMovement !== 0) { if (xMovement !== 0 || yMovement !== 0) {
const { transform, panBy } = getStoreItems();
lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2]; lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];
lastPos.y = (lastPos.y ?? 0) - yMovement / transform[2]; lastPos.y = (lastPos.y ?? 0) - yMovement / transform[2];
+3 -1
View File
@@ -44,6 +44,7 @@ function onPointerDown(
updateConnection, updateConnection,
getTransform, getTransform,
getFromHandle, getFromHandle,
autoPanSpeed,
}: OnPointerDownParams }: OnPointerDownParams
) { ) {
// when xyflow is used inside a shadow root we can't use document // when xyflow is used inside a shadow root we can't use document
@@ -78,7 +79,8 @@ function onPointerDown(
if (!autoPanOnConnect || !containerBounds) { if (!autoPanOnConnect || !containerBounds) {
return; return;
} }
const [x, y] = calcAutoPan(position, containerBounds); const transform = getTransform();
const [x, y] = calcAutoPan(position, containerBounds, transform, autoPanSpeed);
panBy({ x, y }); panBy({ x, y });
autoPanId = requestAnimationFrame(autoPan); autoPanId = requestAnimationFrame(autoPan);
+1
View File
@@ -35,6 +35,7 @@ export type OnPointerDownParams = {
onReconnectEnd?: (evt: MouseEvent | TouchEvent) => void; onReconnectEnd?: (evt: MouseEvent | TouchEvent) => void;
getTransform: () => Transform; getTransform: () => Transform;
getFromHandle: () => Handle | null; getFromHandle: () => Handle | null;
autoPanSpeed?: number;
}; };
export type IsValidParams = { export type IsValidParams = {