refactor(fitView): use same fitView function for viewport helper and initial prop

This commit is contained in:
Christopher Möller
2022-01-27 13:00:03 +01:00
parent 0244c93cb9
commit af52bab2a5
40 changed files with 169 additions and 184 deletions
@@ -1,19 +1,18 @@
import { useEffect, useRef } from 'react';
import useReactFlow from './useReactFlow';
import { OnPaneReady } from '../types';
import { OnInit } from '../types';
function useOnPaneReadyHandler(onPaneReady: OnPaneReady<any> | undefined) {
function useOnInitHandler(onInit: OnInit<any> | undefined) {
const ReactFlowInstance = useReactFlow();
const isInitialized = useRef<boolean>(false);
useEffect(() => {
if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onPaneReady) {
onPaneReady(ReactFlowInstance);
if (!isInitialized.current && ReactFlowInstance.viewportInitialized && onInit) {
setTimeout(() => onInit(ReactFlowInstance), 1);
isInitialized.current = true;
}
}, [onPaneReady, ReactFlowInstance]);
}, [onInit, ReactFlowInstance.viewportInitialized]);
}
export default useOnPaneReadyHandler;
export default useOnInitHandler;
+12 -46
View File
@@ -1,11 +1,11 @@
import { useMemo } from 'react';
import { zoomIdentity } from 'd3-zoom';
import shallow from 'zustand/shallow';
import { Selection as D3Selection } from 'd3';
import { useStoreApi, useStore } from '../store';
import { getRectOfNodeInternals, pointToRendererPoint, getTransformForBounds } from '../utils/graph';
import { FitViewParams, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
import { pointToRendererPoint, getTransformForBounds, getD3Transition } from '../utils/graph';
import { FitViewOptions, Viewport, ViewportHelperFunctions, ReactFlowState, Rect, XYPosition } from '../types';
import { fitView as fitViewStore } from '../store/utils';
const DEFAULT_PADDING = 0.1;
@@ -16,7 +16,7 @@ const initialViewportHelper: ViewportHelperFunctions = {
getZoom: () => 1,
setViewport: (_: Viewport) => {},
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
fitView: (_: FitViewParams = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
fitView: (_: FitViewOptions = { padding: DEFAULT_PADDING, includeHiddenNodes: false }) => {},
setCenter: (_: number, __: number) => {},
fitBounds: (_: Rect) => {},
project: (position: XYPosition) => position,
@@ -28,10 +28,6 @@ const selector = (s: ReactFlowState) => ({
d3Selection: s.d3Selection,
});
const getTransition = (selection: D3Selection<Element, unknown, null, undefined>, duration: number = 0) => {
return selection.transition().duration(duration);
};
const useViewportHelper = (): ViewportHelperFunctions => {
const store = useStoreApi();
const { d3Zoom, d3Selection } = useStore(selector, shallow);
@@ -39,45 +35,22 @@ const useViewportHelper = (): ViewportHelperFunctions => {
const viewportHelperFunctions = useMemo<ViewportHelperFunctions>(() => {
if (d3Selection && d3Zoom) {
return {
zoomIn: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1.2),
zoomOut: (options) => d3Zoom.scaleBy(getTransition(d3Selection, options?.duration), 1 / 1.2),
zoomTo: (zoomLevel, options) => d3Zoom.scaleTo(getTransition(d3Selection, options?.duration), zoomLevel),
zoomIn: (options) => d3Zoom.scaleBy(getD3Transition(d3Selection, options?.duration), 1.2),
zoomOut: (options) => d3Zoom.scaleBy(getD3Transition(d3Selection, options?.duration), 1 / 1.2),
zoomTo: (zoomLevel, options) => d3Zoom.scaleTo(getD3Transition(d3Selection, options?.duration), zoomLevel),
getZoom: () => {
const [, , zoom] = store.getState().transform;
return zoom;
},
setViewport: (transform, options) => {
const nextTransform = zoomIdentity.translate(transform.x, transform.y).scale(transform.zoom);
d3Zoom.transform(getTransition(d3Selection, options?.duration), nextTransform);
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), nextTransform);
},
getViewport: () => {
const [x, y, zoom] = store.getState().transform;
return { x, y, zoom };
},
fitView: (options) => {
const { nodeInternals, width, height, minZoom, maxZoom } = store.getState();
// @TODO: work with nodeInternals instead of converting it to an array
const nodes = Array.from(nodeInternals).map(([_, node]) => node);
if (!nodes.length) {
return;
}
const bounds = getRectOfNodeInternals(
options?.includeHiddenNodes ? nodes : nodes.filter((node) => !node.hidden)
);
const [x, y, zoom] = getTransformForBounds(
bounds,
width,
height,
options?.minZoom ?? minZoom,
options?.maxZoom ?? maxZoom,
options?.padding ?? DEFAULT_PADDING
);
const transform = zoomIdentity.translate(x, y).scale(zoom);
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
},
fitView: (options) => fitViewStore(store.getState, options),
setCenter: (x, y, options) => {
const { width, height, maxZoom } = store.getState();
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom;
@@ -85,21 +58,14 @@ const useViewportHelper = (): ViewportHelperFunctions => {
const centerY = height / 2 - y * nextZoom;
const transform = zoomIdentity.translate(centerX, centerY).scale(nextZoom);
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), transform);
},
fitBounds: (bounds, options) => {
const { width, height, minZoom, maxZoom } = store.getState();
const [x, y, zoom] = getTransformForBounds(
bounds,
width,
height,
minZoom,
maxZoom,
options?.padding ?? DEFAULT_PADDING
);
const [x, y, zoom] = getTransformForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? 0.1);
const transform = zoomIdentity.translate(x, y).scale(zoom);
d3Zoom.transform(getTransition(d3Selection, options?.duration), transform);
d3Zoom.transform(getD3Transition(d3Selection, options?.duration), transform);
},
project: (position: XYPosition) => {
const { transform, snapToGrid, snapGrid } = store.getState();