From 35daa95c229d768ac7030f799e50b5842baeef2e Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Mon, 6 Feb 2023 13:48:23 +0100 Subject: [PATCH] chore(core): cleanup useZoomPanHelper Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- .../core/src/composables/useZoomPanHelper.ts | 130 +++++++++--------- 1 file changed, 62 insertions(+), 68 deletions(-) diff --git a/packages/core/src/composables/useZoomPanHelper.ts b/packages/core/src/composables/useZoomPanHelper.ts index d8c566b6..f8bb80d9 100644 --- a/packages/core/src/composables/useZoomPanHelper.ts +++ b/packages/core/src/composables/useZoomPanHelper.ts @@ -1,36 +1,13 @@ import { zoomIdentity } from 'd3-zoom' -import type { D3Selection, Dimensions, Getters, GraphNode, ViewportFunctions } from '~/types' +import type { D3Selection, Dimensions, GraphNode, ViewportFunctions } from '~/types' const DEFAULT_PADDING = 0.1 -const transition = (selection: D3Selection, ms = 0) => selection.transition().duration(ms) - -const untilDimensions = async (dimensions: Dimensions, getNodes: Getters['getNodes']) => { - // if ssr we can't wait for dimensions, they'll never really exist - const window = useWindow() - if ('screen' in window) { - // wait until viewport dimensions has been established - await until(dimensions).toMatch(({ height, width }) => !isNaN(width) && width > 0 && !isNaN(height) && height > 0) - - // if initial nodes are present, wait until the node dimensions have been established - if (getNodes.length > 0) { - await until(getNodes).toMatch( - (nodes) => - !!nodes.filter(({ dimensions: { width, height } }) => !isNaN(width) && width > 0 && !isNaN(height) && height > 0) - .length, - ) - } - } - - return true -} - /** * @deprecated use {@link useVueFlow} instead (all viewport functions are also available in {@link useVueFlow}) */ export default (vueFlowId?: string): ViewportFunctions => { const { - onPaneReady, nodes, d3Zoom, d3Selection, @@ -42,51 +19,27 @@ export default (vueFlowId?: string): ViewportFunctions => { snapToGrid, snapGrid, getNodes, + onPaneReady, } = $(useVueFlow({ id: vueFlowId })) let hasDimensions = $ref(false) onPaneReady(() => (hasDimensions = true)) - const zoomTo: ViewportFunctions['zoomTo'] = async (zoomLevel, options) => { - if (!hasDimensions) await untilDimensions(dimensions, getNodes) - - if (d3Selection && d3Zoom) { - d3Zoom.scaleTo(transition(d3Selection, options?.duration), zoomLevel) - } - } - - const zoom = async (scale: number, duration?: number) => { - if (!hasDimensions) await untilDimensions(dimensions, getNodes) - - if (d3Selection && d3Zoom) { - d3Zoom.scaleBy(transition(d3Selection, duration), scale) - } - } - - const zoomIn: ViewportFunctions['zoomIn'] = async (options) => { - await zoom(1.2, options?.duration) - } - - const zoomOut: ViewportFunctions['zoomOut'] = async (options) => { - await zoom(1 / 1.2, options?.duration) - } - - const transformViewport = (x: number, y: number, zoom: number, duration?: number) => { - // enforce translate extent - const { x: clampedX, y: clampedY } = clampPosition({ x: -x, y: -y }, translateExtent) - - const nextTransform = zoomIdentity.translate(-clampedX, -clampedY).scale(zoom) - - if (d3Selection && d3Zoom) { - d3Zoom.transform(transition(d3Selection, duration), nextTransform) - } - } - return { - zoomIn, - zoomOut, - zoomTo, + zoomIn: async (options) => { + await zoom(1.2, options?.duration) + }, + zoomOut: async (options) => { + await zoom(1 / 1.2, options?.duration) + }, + zoomTo: async (zoomLevel, options) => { + if (!hasDimensions) await untilDimensions(dimensions, getNodes) + + if (d3Selection && d3Zoom) { + d3Zoom.scaleTo(transition(d3Selection, options?.duration), zoomLevel) + } + }, setTransform: async (transform, options) => { if (!hasDimensions) await untilDimensions(dimensions, getNodes) transformViewport(transform.x, transform.y, transform.zoom, options?.duration) @@ -105,15 +58,20 @@ export default (vueFlowId?: string): ViewportFunctions => { ) => { if (!hasDimensions) await untilDimensions(dimensions, getNodes) - if (!getNodes.length) return + if (!nodes.length) return - let nodeBounds: GraphNode[] = options.includeHiddenNodes ? nodes.filter((n) => n.width && n.height) : getNodes + const nodesToFit: GraphNode[] = (options.includeHiddenNodes ? nodes : getNodes).filter((node) => { + const initialized = node.initialized && node.dimensions.width && node.dimensions.height + let shouldInclude = true - if (options.nodes) { - nodeBounds = nodeBounds.filter((n) => options.nodes?.includes(n.id)) - } + if (options.nodes?.length) { + shouldInclude = options.nodes.includes(node.id) + } - const bounds = getRectOfNodes(nodeBounds) + return initialized && shouldInclude + }) + + const bounds = getRectOfNodes(nodesToFit) const { x, y, zoom } = getTransformForBounds( bounds, @@ -145,4 +103,40 @@ export default (vueFlowId?: string): ViewportFunctions => { }, project: (position) => pointToRendererPoint(position, viewport, snapToGrid, snapGrid), } + + async function zoom(scale: number, duration?: number) { + if (!hasDimensions) await untilDimensions(dimensions, getNodes) + + if (d3Selection && d3Zoom) { + d3Zoom.scaleBy(transition(d3Selection, duration), scale) + } + } + + function transformViewport(x: number, y: number, zoom: number, duration?: number) { + // enforce translate extent + const { x: clampedX, y: clampedY } = clampPosition({ x: -x, y: -y }, translateExtent) + + const nextTransform = zoomIdentity.translate(-clampedX, -clampedY).scale(zoom) + + if (d3Selection && d3Zoom) { + d3Zoom.transform(transition(d3Selection, duration), nextTransform) + } + } +} + +function transition(selection: D3Selection, ms = 0) { + return selection.transition().duration(ms) +} + +async function untilDimensions(dimensions: Dimensions, nodes: GraphNode[]) { + // if ssr we can't wait for dimensions, they'll never really exist + const window = useWindow() + if ('screen' in window) { + // if initial nodes are present, wait until the node dimensions have been established + if (nodes.length > 0) { + await until(nodes).toMatch((nodes) => !!nodes.filter((node) => node.initialized).length) + } + } + + return true }