diff --git a/packages/interactive-minimap/src/MiniMap.tsx b/packages/interactive-minimap/src/MiniMap.tsx index d8c8e77e..57444d62 100644 --- a/packages/interactive-minimap/src/MiniMap.tsx +++ b/packages/interactive-minimap/src/MiniMap.tsx @@ -5,7 +5,7 @@ import shallow from 'zustand/shallow'; import { zoom, D3ZoomEvent, zoomIdentity } from 'd3-zoom'; import { select, pointer } from 'd3-selection'; -import { useStore, getRectOfNodes, ReactFlowState, Rect, Panel, getBoundsOfRects, useStoreApi } from '@reactflow/core'; +import { useStore, getRectOfNodes, Panel, getBoundsOfRects, useStoreApi, ReactFlowState, Rect } from '@reactflow/core'; import MiniMapNode from './MiniMapNode'; import { MiniMapProps, GetMiniMapNodeAttribute } from './types'; @@ -29,8 +29,6 @@ const selector = (s: ReactFlowState) => { viewBB, boundingRect: nodes.length > 0 ? getBoundsOfRects(getRectOfNodes(nodes), viewBB) : viewBB, rfId: s.rfId, - width: s.width, - height: s.height, }; }; @@ -52,7 +50,7 @@ function MiniMap({ }: MiniMapProps) { const store = useStoreApi(); const svg = useRef(null); - const { boundingRect, viewBB, nodes, rfId, width: w, height: h } = useStore(selector, shallow); + const { boundingRect, viewBB, nodes, rfId } = useStore(selector, shallow); const elementWidth = (style?.width as number) ?? defaultWidth; const elementHeight = (style?.height as number) ?? defaultHeight; const nodeColorFunc = getAttrFunction(nodeColor); @@ -72,7 +70,7 @@ function MiniMap({ const labelledBy = `${ARIA_LABEL_KEY}-${rfId}`; const viewScaleRef = useRef(0); - viewScaleRef.current = Math.max(w / elementWidth, h / elementHeight); + viewScaleRef.current = viewScale; const onSvgClick = (event: MouseEvent) => { const rfCoord = pointer(event); @@ -106,14 +104,12 @@ function MiniMap({ return; } - let nextTransform = null; - const position = { x: transform[0] - event.sourceEvent.movementX * viewScaleRef.current * transform[2], y: transform[1] - event.sourceEvent.movementY * viewScaleRef.current * transform[2], }; - nextTransform = zoomIdentity.translate(position.x, position.y).scale(transform[2]); + const nextTransform = zoomIdentity.translate(position.x, position.y).scale(transform[2]); d3Zoom.transform(d3Selection, nextTransform); }); diff --git a/packages/interactive-minimap/src/MiniMapDrag.tsx b/packages/interactive-minimap/src/MiniMapDrag.tsx deleted file mode 100644 index e5a7927e..00000000 --- a/packages/interactive-minimap/src/MiniMapDrag.tsx +++ /dev/null @@ -1,187 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { memo, useEffect, useRef } from 'react'; -import cc from 'classcat'; -import shallow from 'zustand/shallow'; -import { zoom, D3ZoomEvent, zoomIdentity } from 'd3-zoom'; -import { select } from 'd3-selection'; -import { - useStore, - getRectOfNodes, - ReactFlowState, - Rect, - Panel, - getBoundsOfRects, - useStoreApi, - useReactFlow, - XYPosition, -} from '@reactflow/core'; - -import MiniMapNode from './MiniMapNode'; -import { MiniMapProps, GetMiniMapNodeAttribute } from './types'; - -declare const window: any; - -const defaultWidth = 200; -const defaultHeight = 150; - -const selector = (s: ReactFlowState) => { - const nodes = Array.from(s.nodeInternals.values()); - const viewBB: Rect = { - x: -s.transform[0] / s.transform[2], - y: -s.transform[1] / s.transform[2], - width: s.width / s.transform[2], - height: s.height / s.transform[2], - }; - - return { - nodes: nodes.filter((node) => !node.hidden && node.width && node.height), - viewBB, - boundingRect: nodes.length > 0 ? getBoundsOfRects(getRectOfNodes(nodes), viewBB) : viewBB, - rfId: s.rfId, - }; -}; - -const getAttrFunction = (func: any): GetMiniMapNodeAttribute => (func instanceof Function ? func : () => func); - -const ARIA_LABEL_KEY = 'react-flow__minimap-desc'; - -function MiniMap({ - style, - className, - nodeStrokeColor = '#555', - nodeColor = '#fff', - nodeClassName = '', - nodeBorderRadius = 5, - nodeStrokeWidth = 2, - maskColor = 'rgb(240, 242, 243, 0.7)', - position = 'bottom-right', -}: MiniMapProps) { - const store = useStoreApi(); - const svg = useRef(null); - const initialized = useRef(false); - const { boundingRect, viewBB, nodes, rfId } = useStore(selector, shallow); - const elementWidth = (style?.width as number) ?? defaultWidth; - const elementHeight = (style?.height as number) ?? defaultHeight; - const nodeColorFunc = getAttrFunction(nodeColor); - const nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor); - const nodeClassNameFunc = getAttrFunction(nodeClassName); - const scaledWidth = boundingRect.width / elementWidth; - const scaledHeight = boundingRect.height / elementHeight; - const viewScale = Math.max(scaledWidth, scaledHeight); - const viewWidth = viewScale * elementWidth; - const viewHeight = viewScale * elementHeight; - const offset = 5 * viewScale; - const x = boundingRect.x - (viewWidth - boundingRect.width) / 2 - offset; - const y = boundingRect.y - (viewHeight - boundingRect.height) / 2 - offset; - const width = viewWidth + offset * 2; - const height = viewHeight + offset * 2; - const shapeRendering = typeof window === 'undefined' || !!window.chrome ? 'crispEdges' : 'geometricPrecision'; - const labelledBy = `${ARIA_LABEL_KEY}-${rfId}`; - const { setCenter } = useReactFlow(); - const startTransform = useRef({ x: 0, y: 0 }); - const viewScaleRef = useRef(0); - const viewScaleWRef = useRef(0); - const viewScaleHRef = useRef(0); - - viewScaleRef.current = viewScale; - viewScaleWRef.current = scaledWidth; - viewScaleHRef.current = scaledHeight; - - useEffect(() => { - if (!initialized.current && svg.current) { - const bounds = svg.current.getBoundingClientRect() || { left: 0, top: 0 }; - - const selection = select(svg.current as Element); - - const zoomHandler = zoom() - .on('start', (event: D3ZoomEvent) => { - const { transform } = store.getState(); - - const px = (event.sourceEvent.clientX - bounds.left) * viewScaleRef.current; - const py = (event.sourceEvent.clientY - bounds.top) * viewScaleRef.current; - - startTransform.current = { - x: px - transform[0] / transform[2], - y: py - transform[1] / transform[2], - }; - }) - .on('zoom.wheel', (event: D3ZoomEvent) => { - const { transform, d3Selection, d3Zoom } = store.getState(); - - if (event.sourceEvent.type !== 'wheel' || !d3Selection || !d3Zoom) { - return; - } - - const pinchDelta = - -event.sourceEvent.deltaY * - (event.sourceEvent.deltaMode === 1 ? 0.05 : event.sourceEvent.deltaMode ? 1 : 0.002) * - 10; - const zoom = transform[2] * Math.pow(2, pinchDelta); - d3Zoom.scaleTo(d3Selection, zoom, [startTransform.current.x, startTransform.current.y]); - }) - .on('zoom', (event: D3ZoomEvent) => { - if (event.sourceEvent.type !== 'mousemove') { - return; - } - - const { transform, d3Selection, d3Zoom } = store.getState(); - const px = (event.sourceEvent.clientX - bounds.left) * viewScaleRef.current; - const py = (event.sourceEvent.clientY - bounds.top) * viewScaleRef.current; - - const position = { - x: (px - startTransform.current.x) * transform[2], - y: (py - startTransform.current.y) * transform[2], - }; - - const nextTransform = zoomIdentity.translate(position.x, position.y).scale(transform[2]); - d3Zoom!.transform(d3Selection!, nextTransform); - }); - selection.call(zoomHandler); - initialized.current = true; - } - }, [setCenter]); - - return ( - - - React Flow mini map - {nodes.map((node) => { - return ( - - ); - })} - - - - ); -} - -MiniMap.displayName = 'MiniMap'; - -export default memo(MiniMap);