UNPKG

@matthewgapp/solidjs-flow

Version:

React Flow - A highly customizable React library for building node-based editors and interactive flow charts.

139 lines (117 loc) 4.2 kB
import { pointToRendererPoint, getViewportForBounds, fitView, type XYPosition, rendererPointToPoint, } from '@xyflow/system'; import { useStoreApi, useStore } from './useStore'; import type { ViewportHelperFunctions, SolidFlowState } from '../types'; const selector = (s: SolidFlowState) => () => !!s.panZoom.get(); /** * Hook for getting viewport helper functions. * * @internal * @returns viewport helper functions */ const useViewportHelper = (): ViewportHelperFunctions => { const store = useStoreApi(); const panZoomInitialized = useStore(selector); const viewportHelperFunctions = (): ViewportHelperFunctions => { return { zoomIn: (options) => store.panZoom.get()?.scaleBy(1.2, { duration: options?.duration }), zoomOut: (options) => store.panZoom.get()?.scaleBy(1 / 1.2, { duration: options?.duration }), zoomTo: (zoomLevel, options) => store.panZoom.get()?.scaleTo(zoomLevel, { duration: options?.duration }), getZoom: () => store.transform.get()[2], setViewport: (viewport, options) => { const { panZoom } = store; const [tX, tY, tZoom] = store.transform.get(); panZoom.get()?.setViewport( { x: viewport.x ?? tX, y: viewport.y ?? tY, zoom: viewport.zoom ?? tZoom, }, { duration: options?.duration } ); }, getViewport: () => { const [x, y, zoom] = store.transform.get(); return { x, y, zoom }; }, fitView: (options) => { const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store; const panZoomValue = panZoom.get(); return panZoomValue ? fitView( { nodeLookup, width: width.get(), height: height.get(), nodeOrigin: nodeOrigin.get(), minZoom: minZoom.get(), maxZoom: maxZoom.get(), panZoom: panZoomValue, }, options ) : false; }, setCenter: (x, y, options) => { const { width, height, maxZoom, panZoom } = store; const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : maxZoom.get(); const centerX = width.get() / 2 - x * nextZoom; const centerY = height.get() / 2 - y * nextZoom; panZoom.get()?.setViewport( { x: centerX, y: centerY, zoom: nextZoom, }, { duration: options?.duration } ); }, fitBounds: (bounds, options) => { const { width, height, minZoom, maxZoom, panZoom } = store; const viewport = getViewportForBounds( bounds, width.get(), height.get(), minZoom.get(), maxZoom.get(), options?.padding ?? 0.1 ); panZoom.get()?.setViewport(viewport, { duration: options?.duration }); }, screenToFlowPosition: (clientPosition: XYPosition, options: { snapToGrid: boolean } = { snapToGrid: true }) => { const { transform, snapGrid } = store; const domNode = store.domNode.get(); if (!domNode) { return clientPosition; } const { x: domX, y: domY } = domNode.getBoundingClientRect(); const correctedPosition = { x: clientPosition.x - domX, y: clientPosition.y - domY, }; return pointToRendererPoint(correctedPosition, transform.get(), options.snapToGrid, snapGrid.get()); }, flowToScreenPosition: (flowPosition: XYPosition) => { const { transform } = store; const domNode = store.domNode.get(); if (!domNode) { return flowPosition; } const { x: domX, y: domY } = domNode.getBoundingClientRect(); const rendererPosition = rendererPointToPoint(flowPosition, transform.get()); return { x: rendererPosition.x + domX, y: rendererPosition.y + domY, }; }, viewportInitialized: panZoomInitialized, }; }; return viewportHelperFunctions(); }; export default useViewportHelper;