refactor: Change zoom pane into viewport
* split zoom pane into smaller components as viewport * rename UseZoomPanHelper Type to Viewport
This commit is contained in:
@@ -2,13 +2,13 @@ import { zoomIdentity } from 'd3-zoom'
|
|||||||
import useVueFlow from './useVueFlow'
|
import useVueFlow from './useVueFlow'
|
||||||
import useWindow from './useWindow'
|
import useWindow from './useWindow'
|
||||||
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
import { getRectOfNodes, pointToRendererPoint, getTransformForBounds } from '~/utils'
|
||||||
import { GraphNode, Store, UseZoomPanHelper, D3Selection } from '~/types'
|
import { GraphNode, Store, Viewport, D3Selection } from '~/types'
|
||||||
|
|
||||||
const DEFAULT_PADDING = 0.1
|
const DEFAULT_PADDING = 0.1
|
||||||
|
|
||||||
const transition = (selection: D3Selection, ms = 0) => selection.transition().duration(ms)
|
const transition = (selection: D3Selection, ms = 0) => selection.transition().duration(ms)
|
||||||
|
|
||||||
export default (store: Store = useVueFlow().store): UseZoomPanHelper => ({
|
export default (store: Store = useVueFlow().store): Viewport => ({
|
||||||
zoomIn: (options) => store.d3Selection && store.d3Zoom?.scaleBy(transition(store.d3Selection, options?.duration), 1.2),
|
zoomIn: (options) => store.d3Selection && store.d3Zoom?.scaleBy(transition(store.d3Selection, options?.duration), 1.2),
|
||||||
zoomOut: (options) => store.d3Selection && store.d3Zoom?.scaleBy(transition(store.d3Selection, options?.duration), 1 / 1.2),
|
zoomOut: (options) => store.d3Selection && store.d3Zoom?.scaleBy(transition(store.d3Selection, options?.duration), 1 / 1.2),
|
||||||
zoomTo: (zoomLevel, options) =>
|
zoomTo: (zoomLevel, options) =>
|
||||||
|
|||||||
+1
-1
@@ -33,7 +33,7 @@ const transform = computed(() => `translate(${store.transform[0]}px,${store.tran
|
|||||||
</script>
|
</script>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
export default {
|
export default {
|
||||||
name: 'TransformationPane',
|
name: 'Transform',
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { zoom } from 'd3-zoom'
|
||||||
|
import { select } from 'd3-selection'
|
||||||
|
import { useVueFlow } from '../../composables'
|
||||||
|
import SelectionPane from '../SelectionPane/SelectionPane.vue'
|
||||||
|
import Zoom from './Zoom.vue'
|
||||||
|
import Transform from './Transform.vue'
|
||||||
|
|
||||||
|
const { id, store } = useVueFlow()
|
||||||
|
const zoomPaneEl = templateRef<HTMLDivElement>('viewport', null)
|
||||||
|
|
||||||
|
const { width, height } = useElementBounding(zoomPaneEl)
|
||||||
|
|
||||||
|
useResizeObserver(zoomPaneEl, () => {
|
||||||
|
store.dimensions.width = width.value
|
||||||
|
store.dimensions.height = height.value
|
||||||
|
})
|
||||||
|
|
||||||
|
const d3Zoom = ref()
|
||||||
|
const d3Selection = ref()
|
||||||
|
const d3ZoomHandler = ref()
|
||||||
|
onMounted(() => {
|
||||||
|
d3Zoom.value = zoom<HTMLDivElement, any>().scaleExtent([store.minZoom, store.maxZoom]).translateExtent(store.translateExtent)
|
||||||
|
d3Selection.value = select(zoomPaneEl.value).call(d3Zoom.value)
|
||||||
|
d3ZoomHandler.value = d3Selection.value.on('wheel.zoom')
|
||||||
|
|
||||||
|
store.setState({
|
||||||
|
d3Zoom: d3Zoom.value,
|
||||||
|
d3Selection: d3Selection.value,
|
||||||
|
d3ZoomHandler: d3ZoomHandler.value,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'Viewport',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div ref="viewport" class="vue-flow__viewport vue-flow__container">
|
||||||
|
<Zoom
|
||||||
|
v-if="d3Zoom && d3Selection && d3ZoomHandler"
|
||||||
|
:d3-zoom="d3Zoom"
|
||||||
|
:d3-selection="d3Selection"
|
||||||
|
:d3-zoom-handler="d3ZoomHandler"
|
||||||
|
>
|
||||||
|
<Transform>
|
||||||
|
<slot />
|
||||||
|
</Transform>
|
||||||
|
</Zoom>
|
||||||
|
<SelectionPane :key="`selection-pane-${id}`" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { D3ZoomEvent, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
||||||
|
import { pointer } from 'd3-selection'
|
||||||
|
import { useKeyPress, useVueFlow } from '../../composables'
|
||||||
|
import { D3Selection, D3Zoom, D3ZoomHandler, FlowTransform, PanOnScrollMode } from '../../types'
|
||||||
|
import { clamp, clampPosition } from '../../utils'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
d3Zoom: D3Zoom
|
||||||
|
d3Selection: D3Selection
|
||||||
|
d3ZoomHandler: D3ZoomHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
|
const { store } = useVueFlow()
|
||||||
|
|
||||||
|
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
||||||
|
(prevTransform.x !== eventTransform.x && !isNaN(eventTransform.x)) ||
|
||||||
|
(prevTransform.y !== eventTransform.y && !isNaN(eventTransform.y)) ||
|
||||||
|
(prevTransform.zoom !== eventTransform.k && !isNaN(eventTransform.k))
|
||||||
|
|
||||||
|
const eventToFlowTransform = (eventTransform: ZoomTransform): FlowTransform => ({
|
||||||
|
x: eventTransform.x,
|
||||||
|
y: eventTransform.y,
|
||||||
|
zoom: eventTransform.k,
|
||||||
|
})
|
||||||
|
|
||||||
|
const isWrappedWithClass = (event: Event, className: string | undefined) => (event.target as Element).closest(`.${className}`)
|
||||||
|
|
||||||
|
const clampedZoom = clamp(store.defaultZoom, store.minZoom, store.maxZoom)
|
||||||
|
const transform = ref({
|
||||||
|
...clampPosition({ x: store.defaultPosition[0], y: store.defaultPosition[1] }, store.translateExtent),
|
||||||
|
zoom: clampedZoom,
|
||||||
|
})
|
||||||
|
|
||||||
|
const updatedTransform = zoomIdentity.translate(transform.value.x, transform.value.y).scale(transform.value.zoom)
|
||||||
|
props.d3Zoom.transform(props.d3Selection, updatedTransform)
|
||||||
|
|
||||||
|
store.transform = [updatedTransform.x, updatedTransform.y, updatedTransform.k]
|
||||||
|
|
||||||
|
const selectionKeyPressed = useKeyPress(store.selectionKeyCode, (keyPress) => {
|
||||||
|
if (keyPress) {
|
||||||
|
props.d3Zoom.on('zoom', null)
|
||||||
|
} else {
|
||||||
|
props.d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] })
|
||||||
|
const flowTransform = eventToFlowTransform(event.transform)
|
||||||
|
store.hooks.move.trigger({ event, flowTransform })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const zoomKeyPressed = useKeyPress(store.zoomActivationKeyCode)
|
||||||
|
|
||||||
|
props.d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
const flowTransform = eventToFlowTransform(event.transform)
|
||||||
|
transform.value = flowTransform
|
||||||
|
store.hooks.moveStart.trigger({ event, flowTransform })
|
||||||
|
})
|
||||||
|
|
||||||
|
props.d3Zoom.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
||||||
|
if (viewChanged(transform.value, event.transform)) {
|
||||||
|
const flowTransform = eventToFlowTransform(event.transform)
|
||||||
|
transform.value = flowTransform
|
||||||
|
store.hooks.moveEnd.trigger({ event, flowTransform })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
props.d3Selection
|
||||||
|
?.on('wheel', (event: WheelEvent) => {
|
||||||
|
if (store.panOnScroll && !zoomKeyPressed.value) {
|
||||||
|
if (isWrappedWithClass(event, store.noWheelClassName)) return
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopImmediatePropagation()
|
||||||
|
|
||||||
|
const currentZoom = props.d3Selection?.property('__zoom').k || 1
|
||||||
|
|
||||||
|
if (event.ctrlKey && store.zoomOnPinch) {
|
||||||
|
const point = pointer(event)
|
||||||
|
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
|
||||||
|
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10
|
||||||
|
const zoom = currentZoom * Math.pow(2, pinchDelta)
|
||||||
|
if (props.d3Selection) props.d3Zoom.scaleTo(props.d3Selection, zoom, point)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// increase scroll speed in firefox
|
||||||
|
// firefox: deltaMode === 1; chrome: deltaMode === 0
|
||||||
|
const deltaNormalize = event.deltaMode === 1 ? 20 : 1
|
||||||
|
const deltaX = store.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize
|
||||||
|
const deltaY = store.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize
|
||||||
|
|
||||||
|
if (props.d3Selection && store.panOnScrollSpeed)
|
||||||
|
props.d3Zoom?.translateBy(
|
||||||
|
props.d3Selection,
|
||||||
|
-(deltaX / currentZoom) * store.panOnScrollSpeed,
|
||||||
|
-(deltaY / currentZoom) * store.panOnScrollSpeed,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
(!store.zoomOnScroll && store.preventScrolling) ||
|
||||||
|
!store.preventScrolling ||
|
||||||
|
isWrappedWithClass(event, store.noWheelClassName)
|
||||||
|
)
|
||||||
|
return null
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('wheel.zoom', store.panOnScroll || typeof props.d3ZoomHandler === 'undefined' ? null : (props.d3ZoomHandler as any))
|
||||||
|
|
||||||
|
props.d3Zoom.filter((event: MouseEvent) => {
|
||||||
|
console.log(event)
|
||||||
|
const zoomScroll = zoomKeyPressed.value || store.zoomOnScroll
|
||||||
|
const pinchZoom = store.zoomOnPinch && event.ctrlKey
|
||||||
|
|
||||||
|
// if all interactions are disabled, we prevent all zoom events
|
||||||
|
if (!store.panOnDrag && !zoomScroll && !store.panOnScroll && !store.zoomOnDoubleClick && !store.zoomOnPinch) return false
|
||||||
|
|
||||||
|
// during a selection we prevent all other interactions
|
||||||
|
if (selectionKeyPressed.value) return false
|
||||||
|
|
||||||
|
// if zoom on double click is disabled, we prevent the double click event
|
||||||
|
if (!store.zoomOnDoubleClick && event.type === 'dblclick') return false
|
||||||
|
|
||||||
|
// if the target element is inside an element with the nowheel class, we prevent zooming
|
||||||
|
if (isWrappedWithClass(event, store.noWheelClassName) && event.type === 'wheel') return false
|
||||||
|
|
||||||
|
// if the target element is inside an element with the nopan class, we prevent panning
|
||||||
|
if (isWrappedWithClass(event, store.noPanClassName) && event.type !== 'wheel') return false
|
||||||
|
|
||||||
|
if (!store.zoomOnPinch && event.ctrlKey && event.type === 'wheel') return false
|
||||||
|
|
||||||
|
// when there is no scroll handling enabled, we prevent all wheel events
|
||||||
|
if (!zoomScroll && !store.panOnScroll && !pinchZoom && event.type === 'wheel') return false
|
||||||
|
|
||||||
|
// if the pane is not movable, we prevent dragging it with mousestart or touchstart
|
||||||
|
if (!store.panOnDrag && (event.type === 'mousedown' || event.type === 'touchstart')) return false
|
||||||
|
|
||||||
|
// default filter for d3-zoom
|
||||||
|
return (!event.ctrlKey || event.type === 'wheel') && !event.button
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'Zoom',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<slot />
|
||||||
|
</template>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ZoomPane from '../ZoomPane/ZoomPane.vue'
|
import Viewport from '../Viewport/Viewport.vue'
|
||||||
import { createHooks, useHooks } from '../../store'
|
import { createHooks, useHooks } from '../../store'
|
||||||
import { useVueFlow } from '../../composables'
|
import { useVueFlow } from '../../composables'
|
||||||
import type { FlowProps } from '../../types/flow'
|
import type { FlowProps } from '../../types/flow'
|
||||||
@@ -91,7 +91,7 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="vue-flow">
|
<div class="vue-flow">
|
||||||
<ZoomPane :key="`renderer-${id}`">
|
<Viewport :key="`renderer-${id}`">
|
||||||
<template #nodes>
|
<template #nodes>
|
||||||
<template v-for="nodeName of Object.keys(getNodeTypes)" :key="`node-${nodeName}-${id}`">
|
<template v-for="nodeName of Object.keys(getNodeTypes)" :key="`node-${nodeName}-${id}`">
|
||||||
<slot :name="`node-${nodeName}`" />
|
<slot :name="`node-${nodeName}`" />
|
||||||
@@ -106,7 +106,7 @@ export default {
|
|||||||
<slot name="connection-line" />
|
<slot name="connection-line" />
|
||||||
</template>
|
</template>
|
||||||
<slot name="zoom-pane" />
|
<slot name="zoom-pane" />
|
||||||
</ZoomPane>
|
</Viewport>
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,172 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { D3ZoomEvent, zoom, zoomIdentity, ZoomTransform } from 'd3-zoom'
|
|
||||||
import { pointer, select } from 'd3-selection'
|
|
||||||
import { FlowTransform, PanOnScrollMode } from '../../types'
|
|
||||||
import { useKeyPress, useVueFlow } from '../../composables'
|
|
||||||
import { clamp, clampPosition } from '../../utils'
|
|
||||||
import SelectionPane from '../SelectionPane/SelectionPane.vue'
|
|
||||||
import TransformationPane from '../TransformationPane/TransformationPane.vue'
|
|
||||||
|
|
||||||
const { id, store } = useVueFlow()
|
|
||||||
const zoomPaneEl = templateRef<HTMLDivElement>('zoomPane', null)
|
|
||||||
|
|
||||||
const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
|
|
||||||
(prevTransform.x !== eventTransform.x && !isNaN(eventTransform.x)) ||
|
|
||||||
(prevTransform.y !== eventTransform.y && !isNaN(eventTransform.y)) ||
|
|
||||||
(prevTransform.zoom !== eventTransform.k && !isNaN(eventTransform.k))
|
|
||||||
|
|
||||||
const eventToFlowTransform = (eventTransform: ZoomTransform): FlowTransform => ({
|
|
||||||
x: eventTransform.x,
|
|
||||||
y: eventTransform.y,
|
|
||||||
zoom: eventTransform.k,
|
|
||||||
})
|
|
||||||
|
|
||||||
const isWrappedWithClass = (event: Event, className: string | undefined) => (event.target as Element).closest(`.${className}`)
|
|
||||||
|
|
||||||
const clampedZoom = clamp(store.defaultZoom, store.minZoom, store.maxZoom)
|
|
||||||
const transform = ref({
|
|
||||||
...clampPosition({ x: store.defaultPosition[0], y: store.defaultPosition[1] }, store.translateExtent),
|
|
||||||
zoom: clampedZoom,
|
|
||||||
})
|
|
||||||
const { width, height } = useElementBounding(zoomPaneEl)
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
const d3Zoom = zoom<HTMLDivElement, any>().scaleExtent([store.minZoom, store.maxZoom]).translateExtent(store.translateExtent)
|
|
||||||
const d3Selection = select(zoomPaneEl.value).call(d3Zoom)
|
|
||||||
const d3ZoomHandler = d3Selection.on('wheel.zoom')
|
|
||||||
|
|
||||||
const updatedTransform = zoomIdentity.translate(transform.value.x, transform.value.y).scale(transform.value.zoom)
|
|
||||||
d3Zoom.transform(d3Selection, updatedTransform)
|
|
||||||
|
|
||||||
store.setState({
|
|
||||||
d3Zoom,
|
|
||||||
d3Selection,
|
|
||||||
d3ZoomHandler,
|
|
||||||
transform: [updatedTransform.x, updatedTransform.y, updatedTransform.k],
|
|
||||||
})
|
|
||||||
|
|
||||||
const selectionKeyPressed = useKeyPress(store.selectionKeyCode, (keyPress) => {
|
|
||||||
if (keyPress) {
|
|
||||||
d3Zoom.on('zoom', null)
|
|
||||||
} else {
|
|
||||||
d3Zoom.on('zoom', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
|
||||||
store.setState({ transform: [event.transform.x, event.transform.y, event.transform.k] })
|
|
||||||
const flowTransform = eventToFlowTransform(event.transform)
|
|
||||||
store.hooks.move.trigger({ event, flowTransform })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const zoomKeyPressed = useKeyPress(store.zoomActivationKeyCode)
|
|
||||||
|
|
||||||
d3Zoom.on('start', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
|
||||||
const flowTransform = eventToFlowTransform(event.transform)
|
|
||||||
transform.value = flowTransform
|
|
||||||
store.hooks.moveStart.trigger({ event, flowTransform })
|
|
||||||
})
|
|
||||||
|
|
||||||
d3Zoom.on('end', (event: D3ZoomEvent<HTMLDivElement, any>) => {
|
|
||||||
if (viewChanged(transform.value, event.transform)) {
|
|
||||||
const flowTransform = eventToFlowTransform(event.transform)
|
|
||||||
transform.value = flowTransform
|
|
||||||
store.hooks.moveEnd.trigger({ event, flowTransform })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
d3Selection
|
|
||||||
?.on('wheel', (event: WheelEvent) => {
|
|
||||||
if (store.panOnScroll && !zoomKeyPressed.value) {
|
|
||||||
if (isWrappedWithClass(event, store.noWheelClassName)) return
|
|
||||||
event.preventDefault()
|
|
||||||
event.stopImmediatePropagation()
|
|
||||||
|
|
||||||
const currentZoom = d3Selection?.property('__zoom').k || 1
|
|
||||||
|
|
||||||
if (event.ctrlKey && store.zoomOnPinch) {
|
|
||||||
const point = pointer(event)
|
|
||||||
// taken from https://github.com/d3/d3-zoom/blob/master/src/zoom.js
|
|
||||||
const pinchDelta = -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * 10
|
|
||||||
const zoom = currentZoom * Math.pow(2, pinchDelta)
|
|
||||||
if (d3Selection) d3Zoom.scaleTo(d3Selection, zoom, point)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// increase scroll speed in firefox
|
|
||||||
// firefox: deltaMode === 1; chrome: deltaMode === 0
|
|
||||||
const deltaNormalize = event.deltaMode === 1 ? 20 : 1
|
|
||||||
const deltaX = store.panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize
|
|
||||||
const deltaY = store.panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize
|
|
||||||
|
|
||||||
if (d3Selection && store.panOnScrollSpeed)
|
|
||||||
d3Zoom?.translateBy(
|
|
||||||
d3Selection,
|
|
||||||
-(deltaX / currentZoom) * store.panOnScrollSpeed,
|
|
||||||
-(deltaY / currentZoom) * store.panOnScrollSpeed,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
(!store.zoomOnScroll && store.preventScrolling) ||
|
|
||||||
!store.preventScrolling ||
|
|
||||||
isWrappedWithClass(event, store.noWheelClassName)
|
|
||||||
)
|
|
||||||
return null
|
|
||||||
event.preventDefault()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.on('wheel.zoom', store.panOnScroll || typeof d3ZoomHandler === 'undefined' ? null : (d3ZoomHandler as any))
|
|
||||||
|
|
||||||
d3Zoom.filter((event: MouseEvent) => {
|
|
||||||
const zoomScroll = zoomKeyPressed.value || store.zoomOnScroll
|
|
||||||
const pinchZoom = store.zoomOnPinch && event.ctrlKey
|
|
||||||
|
|
||||||
// if all interactions are disabled, we prevent all zoom events
|
|
||||||
if (!store.panOnDrag && !zoomScroll && !store.panOnScroll && !store.zoomOnDoubleClick && !store.zoomOnPinch) return false
|
|
||||||
|
|
||||||
// during a selection we prevent all other interactions
|
|
||||||
if (selectionKeyPressed.value) return false
|
|
||||||
|
|
||||||
// if zoom on double click is disabled, we prevent the double click event
|
|
||||||
if (!store.zoomOnDoubleClick && event.type === 'dblclick') return false
|
|
||||||
|
|
||||||
// if the target element is inside an element with the nowheel class, we prevent zooming
|
|
||||||
if (isWrappedWithClass(event, store.noWheelClassName) && event.type === 'wheel') return false
|
|
||||||
|
|
||||||
// if the target element is inside an element with the nopan class, we prevent panning
|
|
||||||
if (isWrappedWithClass(event, store.noPanClassName) && event.type !== 'wheel') return false
|
|
||||||
|
|
||||||
if (!store.zoomOnPinch && event.ctrlKey && event.type === 'wheel') return false
|
|
||||||
|
|
||||||
// when there is no scroll handling enabled, we prevent all wheel events
|
|
||||||
if (!zoomScroll && !store.panOnScroll && !pinchZoom && event.type === 'wheel') return false
|
|
||||||
|
|
||||||
// if the pane is not movable, we prevent dragging it with mousestart or touchstart
|
|
||||||
if (!store.panOnDrag && (event.type === 'mousedown' || event.type === 'touchstart')) return false
|
|
||||||
|
|
||||||
// default filter for d3-zoom
|
|
||||||
return (!event.ctrlKey || event.type === 'wheel') && !event.button
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
watch(
|
|
||||||
[width, height],
|
|
||||||
([newWidth, newHeight]) => {
|
|
||||||
store.dimensions.width = newWidth
|
|
||||||
store.dimensions.height = newHeight
|
|
||||||
},
|
|
||||||
{ immediate: true },
|
|
||||||
)
|
|
||||||
</script>
|
|
||||||
<script lang="ts">
|
|
||||||
export default {
|
|
||||||
name: 'ZoomPane',
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<template>
|
|
||||||
<div ref="zoomPane" class="vue-flow__renderer vue-flow__container">
|
|
||||||
<TransformationPane>
|
|
||||||
<slot />
|
|
||||||
</TransformationPane>
|
|
||||||
<SelectionPane :key="`selection-pane-${id}`" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vue-flow__renderer {
|
.vue-flow__viewport {
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { CSSProperties, VNode } from 'vue'
|
|||||||
import { GraphEdge, Edge, DefaultEdgeOptions } from './edge'
|
import { GraphEdge, Edge, DefaultEdgeOptions } from './edge'
|
||||||
import { GraphNode, CoordinateExtent, Node } from './node'
|
import { GraphNode, CoordinateExtent, Node } from './node'
|
||||||
import { ConnectionLineType, ConnectionMode } from './connection'
|
import { ConnectionLineType, ConnectionMode } from './connection'
|
||||||
import { KeyCode, PanOnScrollMode, UseZoomPanHelper } from './zoom'
|
import { KeyCode, PanOnScrollMode, Viewport } from './zoom'
|
||||||
import { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
|
import { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
|
||||||
|
|
||||||
export type ElementData = any
|
export type ElementData = any
|
||||||
@@ -86,14 +86,14 @@ export type FlowExportObject = {
|
|||||||
zoom: number
|
zoom: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ToObject = () => FlowExportObject
|
interface Exports {
|
||||||
|
|
||||||
export type FlowInstance = {
|
|
||||||
getElements: () => FlowElements
|
getElements: () => FlowElements
|
||||||
getNodes: () => GraphNode[]
|
getNodes: () => GraphNode[]
|
||||||
getEdges: () => GraphEdge[]
|
getEdges: () => GraphEdge[]
|
||||||
toObject: ToObject
|
toObject: () => FlowExportObject
|
||||||
} & UseZoomPanHelper
|
}
|
||||||
|
|
||||||
|
export type FlowInstance = Exports & Viewport
|
||||||
|
|
||||||
export interface FlowProps<NodeData = ElementData, EdgeData = ElementData> {
|
export interface FlowProps<NodeData = ElementData, EdgeData = ElementData> {
|
||||||
id?: string
|
id?: string
|
||||||
|
|||||||
@@ -34,15 +34,18 @@ export interface State<NodeData = ElementData, EdgeData = ElementData>
|
|||||||
d3Zoom: D3Zoom | null
|
d3Zoom: D3Zoom | null
|
||||||
d3Selection: D3Selection | null
|
d3Selection: D3Selection | null
|
||||||
d3ZoomHandler: D3ZoomHandler | null
|
d3ZoomHandler: D3ZoomHandler | null
|
||||||
|
|
||||||
minZoom: number
|
minZoom: number
|
||||||
maxZoom: number
|
maxZoom: number
|
||||||
defaultZoom: number
|
defaultZoom: number
|
||||||
translateExtent: CoordinateExtent
|
translateExtent: CoordinateExtent
|
||||||
nodeExtent: CoordinateExtent
|
nodeExtent: CoordinateExtent
|
||||||
/** zoom pane dimensions */
|
|
||||||
|
/** viewport dimensions */
|
||||||
dimensions: Dimensions
|
dimensions: Dimensions
|
||||||
/** transform x, y, z */
|
/** viewport transform x, y, z */
|
||||||
transform: Transform
|
transform: Transform
|
||||||
|
|
||||||
onlyRenderVisibleElements: boolean
|
onlyRenderVisibleElements: boolean
|
||||||
defaultPosition: [number, number]
|
defaultPosition: [number, number]
|
||||||
|
|
||||||
@@ -50,6 +53,7 @@ export interface State<NodeData = ElementData, EdgeData = ElementData>
|
|||||||
nodesSelectionActive: boolean
|
nodesSelectionActive: boolean
|
||||||
userSelectionActive: boolean
|
userSelectionActive: boolean
|
||||||
multiSelectionActive: boolean
|
multiSelectionActive: boolean
|
||||||
|
|
||||||
deleteKeyCode: KeyCode
|
deleteKeyCode: KeyCode
|
||||||
selectionKeyCode: KeyCode
|
selectionKeyCode: KeyCode
|
||||||
multiSelectionKeyCode: KeyCode
|
multiSelectionKeyCode: KeyCode
|
||||||
@@ -63,6 +67,7 @@ export interface State<NodeData = ElementData, EdgeData = ElementData>
|
|||||||
connectionLineType: ConnectionLineType
|
connectionLineType: ConnectionLineType
|
||||||
connectionLineStyle: CSSProperties | null
|
connectionLineStyle: CSSProperties | null
|
||||||
connectionStartHandle: StartHandle | null
|
connectionStartHandle: StartHandle | null
|
||||||
|
|
||||||
connectOnClick: boolean
|
connectOnClick: boolean
|
||||||
edgeUpdaterRadius: number
|
edgeUpdaterRadius: number
|
||||||
|
|
||||||
@@ -73,8 +78,10 @@ export interface State<NodeData = ElementData, EdgeData = ElementData>
|
|||||||
edgesUpdatable: boolean
|
edgesUpdatable: boolean
|
||||||
nodesDraggable: boolean
|
nodesDraggable: boolean
|
||||||
nodesConnectable: boolean
|
nodesConnectable: boolean
|
||||||
|
|
||||||
elementsSelectable: boolean
|
elementsSelectable: boolean
|
||||||
selectNodesOnDrag: boolean
|
selectNodesOnDrag: boolean
|
||||||
|
|
||||||
panOnDrag: boolean
|
panOnDrag: boolean
|
||||||
zoomOnScroll: boolean
|
zoomOnScroll: boolean
|
||||||
zoomOnPinch: boolean
|
zoomOnPinch: boolean
|
||||||
@@ -88,9 +95,11 @@ export interface State<NodeData = ElementData, EdgeData = ElementData>
|
|||||||
applyDefault: boolean
|
applyDefault: boolean
|
||||||
|
|
||||||
fitViewOnInit?: boolean
|
fitViewOnInit?: boolean
|
||||||
|
|
||||||
noDragClassName?: 'nodrag' | string
|
noDragClassName?: 'nodrag' | string
|
||||||
noWheelClassName?: 'nowheel' | string
|
noWheelClassName?: 'nowheel' | string
|
||||||
noPanClassName?: 'nopan' | string
|
noPanClassName?: 'nopan' | string
|
||||||
|
|
||||||
defaultEdgeOptions?: DefaultEdgeOptions
|
defaultEdgeOptions?: DefaultEdgeOptions
|
||||||
|
|
||||||
vueFlowVersion: string
|
vueFlowVersion: string
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export type ZoomTo = (zoomLevel: number, options?: UseZoomPanHelperOptions) => v
|
|||||||
export type GetTransform = () => FlowTransform
|
export type GetTransform = () => FlowTransform
|
||||||
export type SetTransform = (transform: FlowTransform, options?: UseZoomPanHelperOptions) => void
|
export type SetTransform = (transform: FlowTransform, options?: UseZoomPanHelperOptions) => void
|
||||||
|
|
||||||
export interface UseZoomPanHelper {
|
export interface Viewport {
|
||||||
zoomIn: ZoomInOut
|
zoomIn: ZoomInOut
|
||||||
zoomOut: ZoomInOut
|
zoomOut: ZoomInOut
|
||||||
zoomTo: ZoomTo
|
zoomTo: ZoomTo
|
||||||
|
|||||||
Reference in New Issue
Block a user