feat(viewpane): defer viewport functions until pane is ready

# What's changed?

* Allow vue flow id to be passed to `useZoomPanHelper` and defer viewport functions until pane is ready
* Remove warning for using viewport functions too early
This commit is contained in:
bcakmakoglu
2022-06-06 21:43:15 +02:00
committed by Braks
parent 8a570bea8b
commit 7dd79f6256
4 changed files with 65 additions and 36 deletions

View File

@@ -38,7 +38,7 @@ export class Storage {
const getters = useGetters(reactiveState)
const actions = useActions(reactiveState, getters)
const actions = useActions(reactiveState, getters, id)
const hooksOn = <any>{}
Object.entries(reactiveState.hooks).forEach(([n, h]) => {

View File

@@ -28,7 +28,7 @@ const untilDimensions = async (dimensions: Dimensions, getNodes: Getters['getNod
return true
}
export default (): ViewportFunctions => {
export default (vueFlowId?: string): ViewportFunctions => {
const {
onPaneReady,
nodes,
@@ -42,7 +42,7 @@ export default (): ViewportFunctions => {
snapToGrid,
snapGrid,
getNodes,
} = $(useVueFlow())
} = $(useVueFlow({ id: vueFlowId }))
let hasDimensions = $ref(false)

View File

@@ -1,12 +1,11 @@
<script lang="ts" setup>
import NodeRenderer from '../NodeRenderer/NodeRenderer.vue'
import EdgeRenderer from '../EdgeRenderer/EdgeRenderer.vue'
import { useVueFlow, useWindow, useZoomPanHelper } from '../../composables'
import { useVueFlow, useWindow } from '../../composables'
import type { Dimensions } from '../../types'
const { id, nodes, edges, viewport, snapToGrid, snapGrid, dimensions, setState, fitViewOnInit, emits } = $(useVueFlow())
// eslint-disable-next-line prefer-const
let { fitView, zoomIn, zoomOut, zoomTo, setTransform, setCenter, fitBounds, ...rest } = useVueFlow()
const { id, nodes, edges, viewport, snapToGrid, snapGrid, dimensions, setState, fitViewOnInit, emits, fitView, ...rest } =
useVueFlow()
const untilDimensions = async (dim: Dimensions) => {
// if ssr we can't wait for dimensions, they'll never really exist
@@ -23,26 +22,26 @@ let ready = $ref(false)
onMounted(async () => {
// wait until proper dimensions have been established, otherwise fitView will have wrong bounds when called at paneReady
await untilDimensions(dimensions)
// create new instance and set to state
const zoomPanHelper = useZoomPanHelper()
fitView = (params = { padding: 0.1 }) => {
zoomPanHelper.fitView(params)
}
zoomIn = zoomPanHelper.zoomIn
zoomOut = zoomPanHelper.zoomOut
zoomTo = zoomPanHelper.zoomTo
setTransform = zoomPanHelper.setTransform
setCenter = zoomPanHelper.setCenter
fitBounds = zoomPanHelper.fitBounds
await untilDimensions(dimensions.value)
// hide graph until dimensions are ready, so we don't have jumping graphs (ssr for example)
ready = true
fitViewOnInit && fitView()
emits.paneReady({ fitView, zoomIn, zoomOut, zoomTo, setTransform, setCenter, fitBounds, ...rest })
emits.paneReady({
id,
nodes,
edges,
viewport,
snapToGrid,
snapGrid,
dimensions,
setState,
fitViewOnInit,
fitView,
emits,
...rest,
})
})
</script>

View File

@@ -34,8 +34,9 @@ import {
pointToRendererPoint,
updateEdgeAction,
} from '~/utils'
import { useZoomPanHelper } from '~/composables'
export default (state: State, getters: ComputedGetters): Actions => {
export default (state: State, getters: ComputedGetters, id: string): Actions => {
const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => {
const changes: NodePositionChange[] = []
@@ -338,10 +339,20 @@ export default (state: State, getters: ComputedGetters): Actions => {
)
}
const paneNotReady = () => {
console.warn(
`[Vue Flow]: Used viewpane function before pane was ready. Use viewpane functions *after* onPaneReady is emitted.`,
)
let zoomPanHelper: ReturnType<typeof useZoomPanHelper>
const paneReady = async () => {
const zoompan = useZoomPanHelper(id)
return new Promise<ReturnType<typeof useZoomPanHelper>>((resolve) => {
if (!zoomPanHelper) {
state.hooks.paneReady.on(() => {
resolve(zoompan)
zoomPanHelper = zoompan
})
} else {
resolve(zoomPanHelper)
}
})
}
return {
@@ -368,21 +379,40 @@ export default (state: State, getters: ComputedGetters): Actions => {
removeSelectedEdges,
setInteractive,
setState,
fitView: paneNotReady,
zoomIn: paneNotReady,
zoomOut: paneNotReady,
zoomTo: paneNotReady,
setTransform: paneNotReady,
fitView: async (params = { padding: 0.1 }) => {
const { fitView } = await paneReady()
fitView(params)
},
zoomIn: async (options) => {
const { zoomIn } = await paneReady()
zoomIn(options)
},
zoomOut: async (options) => {
const { zoomOut } = await paneReady()
zoomOut(options)
},
zoomTo: async (zoomLevel, options) => {
const { zoomTo } = await paneReady()
zoomTo(zoomLevel, options)
},
setTransform: async (transform, options) => {
const { setTransform } = await paneReady()
setTransform(transform, options)
},
getTransform: () => ({
x: state.viewport.x,
y: state.viewport.y,
zoom: state.viewport.zoom,
}),
setCenter: paneNotReady,
fitBounds: paneNotReady,
project(position) {
return pointToRendererPoint(position, state.viewport, state.snapToGrid, state.snapGrid)
setCenter: async (x, y, options) => {
const { setCenter } = await paneReady()
setCenter(x, y, options)
},
fitBounds: async (bounds, options) => {
const { fitBounds } = await paneReady()
fitBounds(bounds, options)
},
project: (position) => pointToRendererPoint(position, state.viewport, state.snapToGrid, state.snapGrid),
toObject,
$reset: () => {
setState(useState())