fix: zoom pan helper not being initialized timely
This commit is contained in:
@@ -28,7 +28,10 @@ const rfInstance = ref<OnLoadParams | null>(null)
|
||||
const onElementsRemove = (elementsToRemove: Elements) =>
|
||||
(elements.value = removeElements(elementsToRemove, elements.value as Elements))
|
||||
const onConnect = (params: Edge | Connection) => (elements.value = addEdge(params, elements.value as Elements))
|
||||
const onLoad = (revueFlowInstance: OnLoadParams) => (rfInstance.value = revueFlowInstance)
|
||||
const onLoad = (revueFlowInstance: OnLoadParams) => {
|
||||
revueFlowInstance.fitView({ padding: 0.1 })
|
||||
rfInstance.value = revueFlowInstance
|
||||
}
|
||||
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el: FlowElement) => {
|
||||
|
||||
@@ -14,10 +14,6 @@ export interface ControlProps extends HTMLAttributes {
|
||||
showFitView?: boolean
|
||||
showInteractive?: boolean
|
||||
fitViewParams?: FitViewParams
|
||||
onZoomIn?: () => void
|
||||
onZoomOut?: () => void
|
||||
onFitView?: () => void
|
||||
onInteractiveChange?: (interactiveStatus: boolean) => void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<ControlProps>(), {
|
||||
@@ -25,6 +21,8 @@ const props = withDefaults(defineProps<ControlProps>(), {
|
||||
showFitView: true,
|
||||
showInteractive: true,
|
||||
})
|
||||
// todo define types for events
|
||||
const emit = defineEmits(['zoom-in', 'zoom-out', 'fit-view', 'interaction-change'])
|
||||
|
||||
const store = useStore()
|
||||
const { zoomIn, zoomOut, fitView } = useZoomPanHelper()
|
||||
@@ -34,22 +32,22 @@ const mapClasses = ['vue-flow__controls']
|
||||
|
||||
const onZoomInHandler = () => {
|
||||
zoomIn?.()
|
||||
props.onZoomIn?.()
|
||||
emit('zoom-in')
|
||||
}
|
||||
|
||||
const onZoomOutHandler = () => {
|
||||
zoomOut?.()
|
||||
props.onZoomOut?.()
|
||||
emit('zoom-out')
|
||||
}
|
||||
|
||||
const onFitViewHandler = () => {
|
||||
fitView?.(props.fitViewParams)
|
||||
props.onFitView?.()
|
||||
emit('fit-view')
|
||||
}
|
||||
|
||||
const onInteractiveChangeHandler = () => {
|
||||
store.setInteractive?.(!isInteractive.value)
|
||||
props.onInteractiveChange?.(!isInteractive.value)
|
||||
emit('interaction-change', !isInteractive.value)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
|
||||
+10
-16
@@ -2,11 +2,9 @@ import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
||||
import { pointer, select } from 'd3-selection'
|
||||
import { Ref } from 'vue'
|
||||
import { get } from '@vueuse/core'
|
||||
import { FlowTransform, PanOnScrollMode, Transform, UseZoom, UseZoomOptions } from '~/types'
|
||||
import { FlowTransform, PanOnScrollMode, UseZoom, UseZoomOptions } from '~/types'
|
||||
import { clamp } from '~/utils'
|
||||
import useKeyPress from '~/composables/useKeyPress'
|
||||
import useHooks from '~/composables/useHooks'
|
||||
import useStore from '~/composables/useStore'
|
||||
import { useKeyPress, useHooks, useStore } from '~/composables'
|
||||
|
||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||
prevTransform.x !== eventTransform.x || prevTransform.y !== eventTransform.y || prevTransform.zoom !== eventTransform.k
|
||||
@@ -38,12 +36,9 @@ export default (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZoom => {
|
||||
const clampedX = clamp(defaultPosition[0], store.translateExtent[0][0], store.translateExtent[1][0])
|
||||
const clampedY = clamp(defaultPosition[1], store.translateExtent[0][1], store.translateExtent[1][1])
|
||||
const clampedZoom = clamp(defaultZoom, store.minZoom, store.maxZoom)
|
||||
const transform = controlledRef<Transform>([clampedX, clampedY, clampedZoom], {
|
||||
onBeforeChange(val, oldVal) {
|
||||
if (val === oldVal) return false
|
||||
},
|
||||
})
|
||||
store.transform = transform.value
|
||||
const transform = ref({ x: clampedX, y: clampedY, zoom: clampedZoom })
|
||||
biSyncRef(transform, prevTransform)
|
||||
|
||||
const d3Zoom = ref(
|
||||
zoom<HTMLDivElement, any>().scaleExtent([store.minZoom, store.maxZoom]).translateExtent(store.translateExtent),
|
||||
)
|
||||
@@ -60,6 +55,7 @@ export default (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZoom => {
|
||||
const updatedTransform = zoomIdentity.translate(clampedX, clampedY).scale(clampedZoom)
|
||||
d3z.transform(d3s, updatedTransform)
|
||||
store.initD3Zoom({ d3Zoom: d3z, d3Selection: d3s, d3ZoomHandler })
|
||||
store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k]
|
||||
|
||||
const applyZoomHandlers = () => {
|
||||
d3z.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||
@@ -85,12 +81,10 @@ export default (el: Ref<HTMLDivElement>, options: UseZoomOptions): UseZoom => {
|
||||
d3z.on('zoom', null)
|
||||
} else {
|
||||
d3z.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||
transform.value = [
|
||||
clamp(event.transform.x, store.translateExtent[0][0], store.translateExtent[1][0]),
|
||||
clamp(event.transform.y, store.translateExtent[0][1], store.translateExtent[1][1]),
|
||||
clamp(event.transform.k, store.minZoom, store.maxZoom),
|
||||
]
|
||||
hooks.move.trigger(eventToFlowTransform(event.transform))
|
||||
const flowTransform = eventToFlowTransform(event.transform)
|
||||
prevTransform.value = flowTransform
|
||||
|
||||
hooks.move.trigger(flowTransform)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -5,9 +5,7 @@ import useStore from '~/composables/useStore'
|
||||
|
||||
const DEFAULT_PADDING = 0.1
|
||||
|
||||
export default (): UseZoomPanHelper => {
|
||||
const store = useStore()
|
||||
|
||||
export default (store = useStore()): UseZoomPanHelper => {
|
||||
return {
|
||||
zoomIn: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1.2),
|
||||
zoomOut: () => store.d3Selection && store.d3Zoom?.scaleBy(store.d3Selection, 1 / 1.2),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue'
|
||||
import { KeyCode, PanOnScrollMode } from '~/types'
|
||||
import { useHooks, useStore, useZoom, useZoomPanHelper } from '~/composables'
|
||||
import { onLoadGetElements, onLoadProject, onLoadToObject } from '~/utils/graph'
|
||||
@@ -34,27 +35,38 @@ const store = useStore()
|
||||
const hooks = useHooks()
|
||||
|
||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoom-pane', null)
|
||||
const { transform } = useZoom(zoomPaneEl, props)
|
||||
const { width, height } = useElementBounding(zoomPaneEl)
|
||||
watch(width, (val) => (store.dimensions.width = val))
|
||||
watch(height, (val) => (store.dimensions.height = val))
|
||||
watch(transform, (val) => (store.transform = val))
|
||||
|
||||
store.transform = transform.value
|
||||
const { width, height } = useElementBounding(zoomPaneEl)
|
||||
store.dimensions = {
|
||||
width: width.value,
|
||||
height: height.value,
|
||||
}
|
||||
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper()
|
||||
hooks.load.trigger({
|
||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
zoomTo,
|
||||
setTransform,
|
||||
project: onLoadProject(store),
|
||||
getElements: onLoadGetElements(store),
|
||||
toObject: onLoadToObject(store),
|
||||
|
||||
const { transform } = useZoom(zoomPaneEl, props)
|
||||
store.transform = [transform.value.x, transform.value.y, transform.value.zoom]
|
||||
|
||||
watch(width, (val) => (store.dimensions.width = val))
|
||||
watch(height, (val) => (store.dimensions.height = val))
|
||||
watch(transform, (val) => (store.transform = [val.x, val.y, val.zoom]))
|
||||
|
||||
onMounted(() => {
|
||||
const { zoomIn, zoomOut, zoomTo, transform: setTransform, fitView } = useZoomPanHelper(store)
|
||||
|
||||
watchOnce(
|
||||
() => width.value && height.value,
|
||||
() => {
|
||||
hooks.load.trigger({
|
||||
fitView: (params = { padding: 0.1 }) => fitView(params),
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
zoomTo,
|
||||
setTransform,
|
||||
project: onLoadProject(store),
|
||||
getElements: onLoadGetElements(store),
|
||||
toObject: onLoadToObject(store),
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
|
||||
@@ -192,7 +192,6 @@ export default function useFlowStore(preloadedState: FlowState): StoreDefinition
|
||||
}
|
||||
},
|
||||
addSelectedElements(elements) {
|
||||
console.log(elements)
|
||||
const selectedElementsArr = Array.isArray(elements) ? elements : [elements]
|
||||
const selectedElementsUpdated = !isEqual(selectedElementsArr, this.selectedElements)
|
||||
this.selectedElements = selectedElementsUpdated ? selectedElementsArr : this.selectedElements
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Ref } from 'vue'
|
||||
import { ElementId, Transform } from './types'
|
||||
import { ElementId, FlowTransform } from './types'
|
||||
import { D3Zoom, D3Selection, PanOnScrollMode, KeyCode } from './panel'
|
||||
import { Connection } from '@/src'
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface UseZoomOptions {
|
||||
}
|
||||
|
||||
export interface UseZoom {
|
||||
transform: Ref<Transform>
|
||||
transform: Ref<FlowTransform>
|
||||
d3Zoom: Ref<D3Zoom>
|
||||
d3Selection: Ref<D3Selection>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user