refactor(zoom): Move paneReady event to transformation pane mounted hook
* await dimensions in fitView function
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { zoomIdentity } from 'd3-zoom'
|
import { zoomIdentity } from 'd3-zoom'
|
||||||
import useVueFlow from './useVueFlow'
|
import useVueFlow from './useVueFlow'
|
||||||
|
import useWindow from './useWindow'
|
||||||
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
||||||
import { GraphNode, FlowStore, UseZoomPanHelper, D3Selection } from '~/types'
|
import { GraphNode, FlowStore, UseZoomPanHelper, D3Selection } from '~/types'
|
||||||
|
|
||||||
@@ -21,13 +22,18 @@ export default (store: FlowStore = useVueFlow().store): UseZoomPanHelper => ({
|
|||||||
y: store.transform[1],
|
y: store.transform[1],
|
||||||
zoom: store.transform[2],
|
zoom: store.transform[2],
|
||||||
}),
|
}),
|
||||||
fitView: (
|
fitView: async (
|
||||||
options = {
|
options = {
|
||||||
padding: DEFAULT_PADDING,
|
padding: DEFAULT_PADDING,
|
||||||
includeHiddenNodes: false,
|
includeHiddenNodes: false,
|
||||||
duration: 0,
|
duration: 0,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
|
// if ssr we can't wait for dimensions, they'll never really exist
|
||||||
|
const window = useWindow()
|
||||||
|
if ('screen' in window)
|
||||||
|
await until(store.dimensions).toMatch(({ height, width }) => !isNaN(width) && width > 0 && !isNaN(height) && height > 0)
|
||||||
|
|
||||||
if (!store.getNodes.length) return
|
if (!store.getNodes.length) return
|
||||||
|
|
||||||
let nodes: GraphNode[] = []
|
let nodes: GraphNode[] = []
|
||||||
|
|||||||
@@ -1,11 +1,36 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import NodeRenderer from '../NodeRenderer/NodeRenderer.vue'
|
import NodeRenderer from '../NodeRenderer/NodeRenderer.vue'
|
||||||
import EdgeRenderer from '../EdgeRenderer/EdgeRenderer.vue'
|
import EdgeRenderer from '../EdgeRenderer/EdgeRenderer.vue'
|
||||||
import { useVueFlow } from '../../composables'
|
import { useVueFlow, useZoomPanHelper } from '../../composables'
|
||||||
|
import { FlowInstance } from '../../types'
|
||||||
|
import { onLoadGetEdges, onLoadGetElements, onLoadGetNodes, onLoadProject, onLoadToObject } from '../../utils'
|
||||||
|
|
||||||
const { id, store } = useVueFlow()
|
const { id, store } = useVueFlow()
|
||||||
|
|
||||||
const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`)
|
const transform = computed(() => `translate(${store.transform[0]}px,${store.transform[1]}px) scale(${store.transform[2]})`)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const { zoomIn, zoomOut, zoomTo, setTransform, getTransform, fitView, fitBounds, setCenter } = useZoomPanHelper(store)
|
||||||
|
const instance: FlowInstance = {
|
||||||
|
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||||
|
zoomIn,
|
||||||
|
zoomOut,
|
||||||
|
zoomTo,
|
||||||
|
setTransform,
|
||||||
|
getTransform,
|
||||||
|
setCenter,
|
||||||
|
fitBounds,
|
||||||
|
project: onLoadProject(store),
|
||||||
|
getElements: onLoadGetElements(store),
|
||||||
|
getNodes: onLoadGetNodes(store),
|
||||||
|
getEdges: onLoadGetEdges(store),
|
||||||
|
toObject: onLoadToObject(store),
|
||||||
|
}
|
||||||
|
store.instance = instance
|
||||||
|
store.fitViewOnInit && instance.fitView()
|
||||||
|
store.paneReady = true
|
||||||
|
store.hooks.paneReady.trigger(instance)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div :key="`transformation-pane-${id}`" class="vue-flow__transformation-pane vue-flow__container" :style="{ transform }">
|
<div :key="`transformation-pane-${id}`" class="vue-flow__transformation-pane vue-flow__container" :style="{ transform }">
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="vue-flow">
|
<div class="vue-flow">
|
||||||
<ZoomPane :key="`renderer-${id}`" :fit-view-on-init="fitViewOnInit">
|
<ZoomPane :key="`renderer-${id}`">
|
||||||
<template v-for="nodeName of Object.keys(getNodeTypes)" #[`node-${nodeName}`]="nodeProps" :key="`node-${nodeName}-${id}`">
|
<template v-for="nodeName of Object.keys(getNodeTypes)" #[`node-${nodeName}`]="nodeProps" :key="`node-${nodeName}-${id}`">
|
||||||
<slot :name="`node-${nodeName}`" v-bind="nodeProps" />
|
<slot :name="`node-${nodeName}`" v-bind="nodeProps" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,22 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
||||||
import { pointer, select } from 'd3-selection'
|
import { pointer, select } from 'd3-selection'
|
||||||
import { FlowInstance, FlowTransform, PanOnScrollMode } from '../../types'
|
import { FlowTransform, PanOnScrollMode } from '../../types'
|
||||||
import { useKeyPress, useWindow, useZoomPanHelper, useVueFlow } from '../../composables'
|
import { useKeyPress, useVueFlow } from '../../composables'
|
||||||
import {
|
import { clamp, clampPosition } from '../../utils'
|
||||||
clamp,
|
|
||||||
clampPosition,
|
|
||||||
onLoadGetEdges,
|
|
||||||
onLoadGetElements,
|
|
||||||
onLoadGetNodes,
|
|
||||||
onLoadProject,
|
|
||||||
onLoadToObject,
|
|
||||||
} from '../../utils'
|
|
||||||
import SelectionPane from '../SelectionPane/SelectionPane.vue'
|
import SelectionPane from '../SelectionPane/SelectionPane.vue'
|
||||||
import TransformationPane from '../TransformationPane/TransformationPane.vue'
|
import TransformationPane from '../TransformationPane/TransformationPane.vue'
|
||||||
|
|
||||||
const props = defineProps<{ fitViewOnInit?: boolean }>()
|
|
||||||
|
|
||||||
const { id, store } = useVueFlow()
|
const { id, store } = useVueFlow()
|
||||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoomPane', null)
|
const zoomPaneEl = templateRef<HTMLDivElement>('zoomPane', null)
|
||||||
|
|
||||||
@@ -55,22 +45,6 @@ onMounted(async () => {
|
|||||||
store.d3ZoomHandler = d3ZoomHandler
|
store.d3ZoomHandler = d3ZoomHandler
|
||||||
store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k]
|
store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k]
|
||||||
|
|
||||||
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
|
||||||
if (viewChanged(transform.value, event.transform)) {
|
|
||||||
const flowTransform = eventToFlowTransform(event.transform)
|
|
||||||
transform.value = flowTransform
|
|
||||||
store.hooks.moveStart.trigger(flowTransform)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
d3z.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
|
||||||
if (viewChanged(transform.value, event.transform)) {
|
|
||||||
const flowTransform = eventToFlowTransform(event.transform)
|
|
||||||
transform.value = flowTransform
|
|
||||||
store.hooks.moveEnd.trigger(flowTransform)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectionKeyPressed = useKeyPress(store.selectionKeyCode, (keyPress) => {
|
const selectionKeyPressed = useKeyPress(store.selectionKeyCode, (keyPress) => {
|
||||||
if (keyPress) {
|
if (keyPress) {
|
||||||
d3z.on('zoom', null)
|
d3z.on('zoom', null)
|
||||||
@@ -87,6 +61,22 @@ onMounted(async () => {
|
|||||||
|
|
||||||
const zoomKeyPressed = store.zoomActivationKeyCode ? useKeyPress(store.zoomActivationKeyCode) : ref(true)
|
const zoomKeyPressed = store.zoomActivationKeyCode ? useKeyPress(store.zoomActivationKeyCode) : ref(true)
|
||||||
|
|
||||||
|
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
if (viewChanged(transform.value, event.transform)) {
|
||||||
|
const flowTransform = eventToFlowTransform(event.transform)
|
||||||
|
transform.value = flowTransform
|
||||||
|
store.hooks.moveStart.trigger(flowTransform)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
d3z.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
if (viewChanged(transform.value, event.transform)) {
|
||||||
|
const flowTransform = eventToFlowTransform(event.transform)
|
||||||
|
transform.value = flowTransform
|
||||||
|
store.hooks.moveEnd.trigger(flowTransform)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
d3s
|
d3s
|
||||||
?.on('wheel', (event: WheelEvent) => {
|
?.on('wheel', (event: WheelEvent) => {
|
||||||
if (zoomKeyPressed.value) {
|
if (zoomKeyPressed.value) {
|
||||||
@@ -163,51 +153,24 @@ onMounted(async () => {
|
|||||||
// default filter for d3-zoom
|
// default filter for d3-zoom
|
||||||
return (!event.ctrlKey || event.type === 'wheel') && !event.button
|
return (!event.ctrlKey || event.type === 'wheel') && !event.button
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
|
||||||
[width, height],
|
|
||||||
([newWidth, newHeight]) => {
|
|
||||||
store.dimensions.width = newWidth
|
|
||||||
store.dimensions.height = newHeight
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
watch(
|
|
||||||
transform,
|
|
||||||
(val) => {
|
|
||||||
const { x, y } = clampPosition(val, store.translateExtent)
|
|
||||||
store.transform = [x, y, clamp(val.zoom, store.minZoom, store.maxZoom)]
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
|
|
||||||
store.paneReady = true
|
|
||||||
|
|
||||||
// if ssr we can't wait for dimensions, they'll never really exist
|
|
||||||
const window = useWindow()
|
|
||||||
if ('screen' in window)
|
|
||||||
await until(store.dimensions).toMatch(({ height, width }) => !isNaN(width) && width > 0 && !isNaN(height) && height > 0)
|
|
||||||
|
|
||||||
const { zoomIn, zoomOut, zoomTo, setTransform, getTransform, fitView, fitBounds, setCenter } = useZoomPanHelper(store)
|
|
||||||
const instance: FlowInstance = {
|
|
||||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
|
||||||
zoomIn,
|
|
||||||
zoomOut,
|
|
||||||
zoomTo,
|
|
||||||
setTransform,
|
|
||||||
getTransform,
|
|
||||||
setCenter,
|
|
||||||
fitBounds,
|
|
||||||
project: onLoadProject(store),
|
|
||||||
getElements: onLoadGetElements(store),
|
|
||||||
getNodes: onLoadGetNodes(store),
|
|
||||||
getEdges: onLoadGetEdges(store),
|
|
||||||
toObject: onLoadToObject(store),
|
|
||||||
}
|
|
||||||
store.instance = instance
|
|
||||||
props.fitViewOnInit && instance.fitView()
|
|
||||||
store.hooks.paneReady.trigger(instance)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
watch(
|
||||||
|
[width, height],
|
||||||
|
([newWidth, newHeight]) => {
|
||||||
|
store.dimensions.width = newWidth
|
||||||
|
store.dimensions.height = newHeight
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
transform,
|
||||||
|
(val) => {
|
||||||
|
const { x, y } = clampPosition(val, store.translateExtent)
|
||||||
|
store.transform = [x, y, clamp(val.zoom, store.minZoom, store.maxZoom)]
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
Reference in New Issue
Block a user