package(utils): add fitView
This commit is contained in:
@@ -40,7 +40,8 @@
|
|||||||
"@types/d3": "^7.4.0",
|
"@types/d3": "^7.4.0",
|
||||||
"@types/d3-drag": "^3.0.1",
|
"@types/d3-drag": "^3.0.1",
|
||||||
"@types/d3-selection": "^3.0.3",
|
"@types/d3-selection": "^3.0.3",
|
||||||
"@types/d3-zoom": "^3.0.1"
|
"@types/d3-zoom": "^3.0.1",
|
||||||
|
"d3-zoom": "^3.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=17",
|
"react": ">=17",
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import type { Selection as D3Selection } from 'd3';
|
import type { Selection as D3Selection } from 'd3';
|
||||||
|
import { zoomIdentity } from 'd3-zoom';
|
||||||
|
|
||||||
import { boxToRect, clamp, devWarn, getBoundsOfBoxes, getOverlappingArea, rectToBox } from './utils';
|
import { boxToRect, clamp, devWarn, getBoundsOfBoxes, getOverlappingArea, rectToBox } from './utils';
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +14,8 @@ import {
|
|||||||
type Rect,
|
type Rect,
|
||||||
type NodeInternals,
|
type NodeInternals,
|
||||||
type NodeOrigin,
|
type NodeOrigin,
|
||||||
|
FitViewParams,
|
||||||
|
FitViewOptions,
|
||||||
} from '@reactflow/system';
|
} from '@reactflow/system';
|
||||||
|
|
||||||
export const isEdge = (element: Node | Connection | Edge): element is Edge =>
|
export const isEdge = (element: Node | Connection | Edge): element is Edge =>
|
||||||
@@ -285,3 +288,45 @@ export const getTransformForBounds = (
|
|||||||
export const getD3Transition = (selection: D3Selection<Element, unknown, null, undefined>, duration = 0) => {
|
export const getD3Transition = (selection: D3Selection<Element, unknown, null, undefined>, duration = 0) => {
|
||||||
return selection.transition().duration(duration);
|
return selection.transition().duration(duration);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function fitView(
|
||||||
|
{ nodes, width, height, d3Zoom, d3Selection, nodeOrigin, minZoom, maxZoom }: FitViewParams,
|
||||||
|
options: FitViewOptions = {}
|
||||||
|
) {
|
||||||
|
const filteredNodes = nodes.filter((n) => {
|
||||||
|
const isVisible = options.includeHiddenNodes ? n.width && n.height : !n.hidden;
|
||||||
|
|
||||||
|
if (options.nodes?.length) {
|
||||||
|
return isVisible && options.nodes.some((optionNode) => optionNode.id === n.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return isVisible;
|
||||||
|
});
|
||||||
|
|
||||||
|
const nodesInitialized = filteredNodes.every((n) => n.width && n.height);
|
||||||
|
|
||||||
|
if (nodes.length > 0 && nodesInitialized) {
|
||||||
|
const bounds = getRectOfNodes(nodes, nodeOrigin);
|
||||||
|
|
||||||
|
const [x, y, zoom] = getTransformForBounds(
|
||||||
|
bounds,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
options.minZoom ?? minZoom,
|
||||||
|
options.maxZoom ?? maxZoom,
|
||||||
|
options.padding ?? 0.1
|
||||||
|
);
|
||||||
|
|
||||||
|
const nextTransform = zoomIdentity.translate(x, y).scale(zoom);
|
||||||
|
|
||||||
|
if (typeof options.duration === 'number' && options.duration > 0) {
|
||||||
|
d3Zoom.transform(getD3Transition(d3Selection, options.duration), nextTransform);
|
||||||
|
} else {
|
||||||
|
d3Zoom.transform(d3Selection, nextTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user