diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx index 5f2010d3..88272045 100644 --- a/src/container/GraphView/index.tsx +++ b/src/container/GraphView/index.tsx @@ -188,6 +188,9 @@ const GraphView = ({ zoomOnScroll, zoomOnDoubleClick, paneMoveable, + defaultPosition, + defaultZoom, + translateExtent, }); useEffect(() => { @@ -205,16 +208,6 @@ const GraphView = ({ }); } - const initialTransform = { - x: defaultPosition[0], - y: defaultPosition[1], - k: defaultZoom, - }; - - if (initialTransform.x !== 0 || initialTransform.y !== 0 || initialTransform.k !== 1) { - setInitTransform(initialTransform); - } - isInitialised.current = true; } }, [d3Initialised, onLoad]); diff --git a/src/container/NodeRenderer/index.tsx b/src/container/NodeRenderer/index.tsx index 18674df8..bf99ac32 100644 --- a/src/container/NodeRenderer/index.tsx +++ b/src/container/NodeRenderer/index.tsx @@ -83,6 +83,7 @@ const NodeRenderer = ({ onlyRenderVisibleNodes = true, ...props }: NodeRendererP const nodesDraggable = useStoreState((s) => s.nodesDraggable); const nodesConnectable = useStoreState((s) => s.nodesConnectable); const elementsSelectable = useStoreState((s) => s.elementsSelectable); + const transformStyle = { transform: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`, }; diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index aee9fa52..63dba920 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -142,8 +142,8 @@ const ReactFlow = ({ onPaneScroll, onPaneContextMenu, }: ReactFlowProps) => { - const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), []); - const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), []); + const nodeTypesParsed = useMemo(() => createNodeTypes(nodeTypes), [nodeTypes]); + const edgeTypesParsed = useMemo(() => createEdgeTypes(edgeTypes), [edgeTypes]); const reactFlowClasses = cc(['react-flow', className]); return ( diff --git a/src/hooks/useD3Zoom.ts b/src/hooks/useD3Zoom.ts index 4fbbef6c..60d430c7 100644 --- a/src/hooks/useD3Zoom.ts +++ b/src/hooks/useD3Zoom.ts @@ -1,7 +1,7 @@ import { useEffect, useRef, MutableRefObject } from 'react'; import { useStoreState, useStoreActions } from '../store/hooks'; -import { FlowTransform } from '../types'; +import { FlowTransform, TranslateExtent } from '../types'; interface UseD3ZoomParams { zoomPane: MutableRefObject; @@ -9,6 +9,9 @@ interface UseD3ZoomParams { zoomOnScroll: boolean; zoomOnDoubleClick: boolean; paneMoveable: boolean; + defaultPosition: [number, number]; + defaultZoom: number; + translateExtent?: TranslateExtent; onMove?: (flowTransform?: FlowTransform) => void; onMoveStart?: (flowTransform?: FlowTransform) => void; onMoveEnd?: (flowTransform?: FlowTransform) => void; @@ -34,6 +37,9 @@ export default ({ zoomOnDoubleClick, selectionKeyPressed, paneMoveable, + defaultPosition, + defaultZoom, + translateExtent, }: UseD3ZoomParams): void => { const prevTransform = useRef({ x: 0, y: 0, zoom: 0 }); const d3Zoom = useStoreState((s) => s.d3Zoom); @@ -43,7 +49,7 @@ export default ({ useEffect(() => { if (zoomPane.current) { - initD3(zoomPane.current); + initD3({ zoomPane: zoomPane.current, defaultPosition, defaultZoom, translateExtent }); } }, []); diff --git a/src/store/index.ts b/src/store/index.ts index 85e08fba..1e3e743a 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -51,6 +51,12 @@ type SetSnapGrid = { snapGrid: [number, number]; }; +type InitD3 = { + zoomPane: Element; + defaultPosition: [number, number]; + defaultZoom: number; + translateExtent?: TranslateExtent; +}; export interface StoreModel { width: number; height: number; @@ -116,7 +122,7 @@ export interface StoreModel { updateSize: Action; - initD3: Action; + initD3: Action; setMinMaxZoom: Action; @@ -369,11 +375,21 @@ export const storeModel: StoreModel = { state.height = size.height || 500; }), - initD3: action((state, zoomPaneNode) => { - const d3ZoomInstance = zoom().scaleExtent([state.minZoom, state.maxZoom]).translateExtent(state.translateExtent); + initD3: action((state, { zoomPane, defaultPosition, defaultZoom, translateExtent }) => { + const currentTranslateExtent = typeof translateExtent !== 'undefined' ? translateExtent : state.translateExtent; + const d3ZoomInstance = zoom().scaleExtent([state.minZoom, state.maxZoom]).translateExtent(currentTranslateExtent); + const selection = select(zoomPane).call(d3ZoomInstance); - const selection = select(zoomPaneNode).call(d3ZoomInstance); + const clampedX = clamp(defaultPosition[0], currentTranslateExtent[0][0], currentTranslateExtent[1][0]); + const clampedY = clamp(defaultPosition[1], currentTranslateExtent[0][1], currentTranslateExtent[1][1]); + const clampedZoom = clamp(defaultZoom, state.minZoom, state.maxZoom); + const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom); + selection.property('__zoom', updatedTransform); + + state.transform[0] = clampedX; + state.transform[1] = clampedY; + state.transform[2] = clampedZoom; state.d3Zoom = d3ZoomInstance; state.d3Selection = selection; state.d3Initialised = true;