From 58783fd4a17f031092b383f99e6490d1264fbabb Mon Sep 17 00:00:00 2001
From: bcakmakoglu <78412429+bcakmakoglu@users.noreply.github.com>
Date: Fri, 27 May 2022 16:11:41 +0200
Subject: [PATCH] refactor(vue-flow,viewpane): remove `instance` property and
merge into `useVueFlow`
# What's changed?
* Remove the `instance` property from store and merge viewport functions into `useVueFlow`
* Add `getElements` getter
* Rename types
* Deprecate `FlowInstance` type
---
.../Controls/Controls.vue | 8 +--
.../src/composables/useZoomPanHelper.ts | 10 ++--
.../src/container/Viewport/Transform.vue | 50 +++----------------
.../src/container/Viewport/Viewport.vue | 6 +--
packages/vue-flow/src/store/actions.ts | 20 ++++++++
packages/vue-flow/src/store/getters.ts | 6 +++
packages/vue-flow/src/store/state.ts | 1 -
packages/vue-flow/src/types/flow.ts | 13 ++---
packages/vue-flow/src/types/hooks.ts | 6 +--
packages/vue-flow/src/types/store.ts | 9 ++--
packages/vue-flow/src/types/zoom.ts | 41 ++++++++++-----
packages/vue-flow/src/utils/changes.ts | 1 +
12 files changed, 86 insertions(+), 85 deletions(-)
diff --git a/packages/vue-flow/src/additional-components/Controls/Controls.vue b/packages/vue-flow/src/additional-components/Controls/Controls.vue
index 21fddd1c..a5ede6b3 100644
--- a/packages/vue-flow/src/additional-components/Controls/Controls.vue
+++ b/packages/vue-flow/src/additional-components/Controls/Controls.vue
@@ -17,22 +17,22 @@ const emit = defineEmits<{
(event: 'interactionChange', active: boolean): void
}>()
-const { instance, nodesDraggable, nodesConnectable, elementsSelectable, setInteractive } = $(useVueFlow())
+const { nodesDraggable, nodesConnectable, elementsSelectable, setInteractive, zoomIn, zoomOut, fitView } = $(useVueFlow())
const isInteractive = computed(() => nodesDraggable && nodesConnectable && elementsSelectable)
const onZoomInHandler = () => {
- instance?.zoomIn()
+ zoomIn()
emit('zoomIn')
}
const onZoomOutHandler = () => {
- instance?.zoomOut()
+ zoomOut()
emit('zoomOut')
}
const onFitViewHandler = () => {
- instance?.fitView(fitViewParams)
+ fitView(fitViewParams)
emit('fitView')
}
diff --git a/packages/vue-flow/src/composables/useZoomPanHelper.ts b/packages/vue-flow/src/composables/useZoomPanHelper.ts
index 51461219..9fd79b8a 100644
--- a/packages/vue-flow/src/composables/useZoomPanHelper.ts
+++ b/packages/vue-flow/src/composables/useZoomPanHelper.ts
@@ -2,7 +2,7 @@ import { zoomIdentity } from 'd3-zoom'
import useVueFlow from './useVueFlow'
import useWindow from './useWindow'
import { clampPosition, getRectOfNodes, getTransformForBounds, pointToRendererPoint } from '~/utils'
-import type { D3Selection, Dimensions, Getters, GraphNode, ViewportFuncs } from '~/types'
+import type { D3Selection, Dimensions, Getters, GraphNode, ViewportFunctions } from '~/types'
const DEFAULT_PADDING = 0.1
@@ -28,7 +28,7 @@ const untilDimensions = async (dimensions: Dimensions, getNodes: Getters['getNod
return true
}
-export default (): ViewportFuncs => {
+export default (): ViewportFunctions => {
const {
onPaneReady,
nodes,
@@ -48,7 +48,7 @@ export default (): ViewportFuncs => {
onPaneReady(() => (hasDimensions = true))
- const zoomTo: ViewportFuncs['zoomTo'] = async (zoomLevel, options) => {
+ const zoomTo: ViewportFunctions['zoomTo'] = async (zoomLevel, options) => {
if (!hasDimensions) await untilDimensions(dimensions, getNodes)
if (d3Selection && d3Zoom) {
@@ -64,11 +64,11 @@ export default (): ViewportFuncs => {
}
}
- const zoomIn: ViewportFuncs['zoomIn'] = async (options) => {
+ const zoomIn: ViewportFunctions['zoomIn'] = async (options) => {
await zoom(1.2, options?.duration)
}
- const zoomOut: ViewportFuncs['zoomOut'] = async (options) => {
+ const zoomOut: ViewportFunctions['zoomOut'] = async (options) => {
await zoom(1 / 1.2, options?.duration)
}
diff --git a/packages/vue-flow/src/container/Viewport/Transform.vue b/packages/vue-flow/src/container/Viewport/Transform.vue
index 17c99e36..005a82f6 100644
--- a/packages/vue-flow/src/container/Viewport/Transform.vue
+++ b/packages/vue-flow/src/container/Viewport/Transform.vue
@@ -1,11 +1,10 @@
diff --git a/packages/vue-flow/src/container/Viewport/Viewport.vue b/packages/vue-flow/src/container/Viewport/Viewport.vue
index 99312d47..aadf3598 100644
--- a/packages/vue-flow/src/container/Viewport/Viewport.vue
+++ b/packages/vue-flow/src/container/Viewport/Viewport.vue
@@ -2,7 +2,7 @@
import type { D3ZoomEvent, ZoomTransform } from 'd3-zoom'
import { zoom, zoomIdentity } from 'd3-zoom'
import { pointer, select } from 'd3-selection'
-import type { FlowTransform } from '../../types'
+import type { ViewpaneTransform } from '../../types'
import { PanOnScrollMode } from '../../types'
import { useKeyPress, useVueFlow } from '../../composables'
import { clamp, clampPosition } from '../../utils'
@@ -35,12 +35,12 @@ const {
const viewportEl = templateRef('viewport', null)
-const viewChanged = (prevTransform: FlowTransform, eventTransform: ZoomTransform): boolean =>
+const viewChanged = (prevTransform: ViewpaneTransform, 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 => ({
+const eventToFlowTransform = (eventTransform: ZoomTransform): ViewpaneTransform => ({
x: eventTransform.x,
y: eventTransform.y,
zoom: eventTransform.k,
diff --git a/packages/vue-flow/src/store/actions.ts b/packages/vue-flow/src/store/actions.ts
index cb789960..5d9f93f1 100644
--- a/packages/vue-flow/src/store/actions.ts
+++ b/packages/vue-flow/src/store/actions.ts
@@ -5,6 +5,8 @@ import type {
CoordinateExtent,
EdgeChange,
EdgeRemoveChange,
+ FlowExportObject,
+ Getters,
GraphEdge,
GraphNode,
NodeChange,
@@ -32,6 +34,7 @@ import {
parseEdge,
updateEdgeAction,
} from '~/utils'
+import { useZoomPanHelper } from '~/composables'
export default (state: State, getters: ComputedGetters): Actions => {
const updateNodePositions: Actions['updateNodePositions'] = (dragItems, changed, dragging) => {
@@ -324,6 +327,20 @@ export default (state: State, getters: ComputedGetters): Actions => {
if (!state.initialized) state.initialized = true
}
+ const toObject = () => {
+ // we have to stringify/parse so objects containing refs (like nodes and edges) can potentially be saved in a storage
+ return JSON.parse(
+ JSON.stringify({
+ nodes: state.nodes,
+ edges: state.edges,
+ position: [state.viewport.x, state.viewport.y],
+ zoom: state.viewport.zoom,
+ } as FlowExportObject),
+ )
+ }
+
+ const { fitView, ...rest } = useZoomPanHelper()
+
return {
updateNodePositions,
updateNodeDimensions,
@@ -348,6 +365,9 @@ export default (state: State, getters: ComputedGetters): Actions => {
removeSelectedEdges,
setInteractive,
setState,
+ fitView: (params = { padding: 0.1 }) => fitView(params),
+ toObject,
+ ...rest,
$reset: () => {
setState(useState())
},
diff --git a/packages/vue-flow/src/store/getters.ts b/packages/vue-flow/src/store/getters.ts
index 79caf392..5b56225d 100644
--- a/packages/vue-flow/src/store/getters.ts
+++ b/packages/vue-flow/src/store/getters.ts
@@ -74,6 +74,7 @@ export default (state: State): ComputedGetters => {
target.dimensions.height
)
}
+
const getEdges = computed(() => {
if (!state.onlyRenderVisibleElements) return state.edges.filter((edge) => edgeHidden(edge))
@@ -98,8 +99,12 @@ export default (state: State): ComputedGetters => {
})
})
+ const getElements: ComputedGetters['getElements'] = computed(() => [...getNodes.value, ...getEdges.value])
+
const getSelectedNodes: ComputedGetters['getSelectedNodes'] = computed(() => state.nodes.filter((n) => n.selected))
+
const getSelectedEdges: ComputedGetters['getSelectedEdges'] = computed(() => state.edges.filter((e) => e.selected))
+
const getSelectedElements: ComputedGetters['getSelectedElements'] = computed(() => [
...(getSelectedNodes.value ?? []),
...(getSelectedEdges.value ?? []),
@@ -108,6 +113,7 @@ export default (state: State): ComputedGetters => {
return {
getNode,
getEdge,
+ getElements,
getEdgeTypes,
getNodeTypes,
getEdges,
diff --git a/packages/vue-flow/src/store/state.ts b/packages/vue-flow/src/store/state.ts
index e1f532c6..b6f78996 100644
--- a/packages/vue-flow/src/store/state.ts
+++ b/packages/vue-flow/src/store/state.ts
@@ -35,7 +35,6 @@ const defaultState = (): State => ({
edgeTypes: {},
initialized: false,
- instance: null,
dimensions: {
width: 0,
diff --git a/packages/vue-flow/src/types/flow.ts b/packages/vue-flow/src/types/flow.ts
index f1d8d9aa..05e56fc7 100644
--- a/packages/vue-flow/src/types/flow.ts
+++ b/packages/vue-flow/src/types/flow.ts
@@ -2,8 +2,9 @@ import type { CSSProperties, Component, VNode } from 'vue'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node'
import type { ConnectionLineType, ConnectionMode } from './connection'
-import type { KeyCode, PanOnScrollMode, ViewportFuncs } from './zoom'
+import type { KeyCode, PanOnScrollMode } from './zoom'
import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent } from './components'
+import type { VueFlowStore } from './store'
export type ElementData = any
@@ -84,14 +85,8 @@ export interface FlowExportObject {
zoom: number
}
-interface Exports {
- getElements: () => FlowElements
- getNodes: () => GraphNode[]
- getEdges: () => GraphEdge[]
- toObject: () => FlowExportObject
-}
-
-export type FlowInstance = Exports & ViewportFuncs
+/** @deprecated will be removed soon, only remains for backwards compatability */
+export type FlowInstance = VueFlowStore
export interface FlowProps {
id?: string
diff --git a/packages/vue-flow/src/types/hooks.ts b/packages/vue-flow/src/types/hooks.ts
index edecabdd..2f7090a5 100644
--- a/packages/vue-flow/src/types/hooks.ts
+++ b/packages/vue-flow/src/types/hooks.ts
@@ -1,11 +1,11 @@
import type { EventHook, EventHookOn, EventHookTrigger } from '@vueuse/core'
import type { D3ZoomEvent } from 'd3-zoom'
-import type { FlowInstance } from './flow'
import type { GraphEdge } from './edge'
import type { GraphNode } from './node'
import type { Connection, OnConnectStartParams } from './connection'
-import type { FlowTransform } from './zoom'
+import type { ViewpaneTransform } from './zoom'
import type { EdgeChange, NodeChange } from './changes'
+import type { VueFlowStore } from './store'
export type MouseTouchEvent = MouseEvent | TouchEvent | PointerEvent
@@ -54,7 +54,7 @@ export interface FlowEvents {
} & OnConnectStartParams
connectStop: MouseEvent
connectEnd: MouseEvent
- paneReady: FlowInstance
+ paneReady: VueFlowStore
move: { event: D3ZoomEvent; flowTransform: FlowTransform }
moveStart: { event: D3ZoomEvent; flowTransform: FlowTransform }
moveEnd: { event: D3ZoomEvent; flowTransform: FlowTransform }
diff --git a/packages/vue-flow/src/types/store.ts b/packages/vue-flow/src/types/store.ts
index 65b58d3f..88e12603 100644
--- a/packages/vue-flow/src/types/store.ts
+++ b/packages/vue-flow/src/types/store.ts
@@ -4,7 +4,7 @@ import type { DefaultEdgeTypes, DefaultNodeTypes, EdgeComponent, NodeComponent }
import type { Connection, ConnectionLineType, ConnectionMode } from './connection'
import type { DefaultEdgeOptions, Edge, GraphEdge } from './edge'
import type { CoordinateExtent, GraphNode, Node } from './node'
-import type { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode, Viewport } from './zoom'
+import type { D3Selection, D3Zoom, D3ZoomHandler, KeyCode, PanOnScrollMode, Viewport, ViewportFunctions } from './zoom'
import type { FlowHooks, FlowHooksEmit, FlowHooksOn } from './hooks'
import type { EdgeChange, NodeChange, NodeDragItem } from './changes'
import type { HandleType, StartHandle } from './handle'
@@ -18,7 +18,6 @@ export interface UpdateNodeDimensionsParams {
export interface State extends Omit {
/** Event hooks, you can manipulate the triggers at your own peril */
readonly hooks: FlowHooks
- readonly instance: FlowInstance | null
/** all stored nodes */
nodes: GraphNode[]
@@ -121,7 +120,7 @@ export type SetState = (
export type UpdateNodePosition = (dragItems: NodeDragItem[], changed: boolean, dragging: boolean) => void
export type UpdateNodeDimensions = (updates: UpdateNodeDimensionsParams[]) => void
-export interface Actions {
+export interface Actions extends ViewportFunctions {
/** parses elements (nodes + edges) and re-sets the state */
setElements: SetElements
/** parses nodes and re-sets the state */
@@ -164,6 +163,8 @@ export interface Actions {
setInteractive: (isInteractive: boolean) => void
/** set new state */
setState: SetState
+ /** return an object of graph values (elements, viewpane transform) for storage and re-loading a graph */
+ toObject: () => FlowExportObject
/** internal position updater, you probably don't want to use this */
updateNodePositions: UpdateNodePosition
@@ -179,6 +180,8 @@ export interface Getters {
getEdgeTypes: Record
/** returns object containing current node types */
getNodeTypes: Record
+ /** get all elements (filters hidden elements) */
+ getElements: FlowElements
/** filters hidden nodes */
getNodes: GraphNode[]
/** filters hidden edges */
diff --git a/packages/vue-flow/src/types/zoom.ts b/packages/vue-flow/src/types/zoom.ts
index 180bba90..8f00c3e4 100644
--- a/packages/vue-flow/src/types/zoom.ts
+++ b/packages/vue-flow/src/types/zoom.ts
@@ -20,7 +20,7 @@ export enum PanOnScrollMode {
Horizontal = 'horizontal',
}
-export interface ViewportFuncsOptions {
+export interface TransitionOptions {
duration?: number
}
@@ -34,32 +34,47 @@ export type FitViewParams = {
y?: number
}
nodes?: string[]
-} & ViewportFuncsOptions
+} & TransitionOptions
-export interface FlowTransform {
+export interface ViewpaneTransform {
x: number
y: number
zoom: number
}
-export type SetCenterOptions = ViewportFuncsOptions & {
+export type SetCenterOptions = TransitionOptions & {
zoom?: number
}
-export type FitBoundsOptions = ViewportFuncsOptions & {
+export type FitBoundsOptions = TransitionOptions & {
padding?: number
}
+/** Fit the viewpane around visible nodes */
export type FitView = (fitViewOptions?: FitViewParams) => void
-export type Project = (position: XYPosition) => XYPosition
-export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void
-export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void
-export type ZoomInOut = (options?: ViewportFuncsOptions) => void
-export type ZoomTo = (zoomLevel: number, options?: ViewportFuncsOptions) => void
-export type GetTransform = () => FlowTransform
-export type SetTransform = (transform: FlowTransform, options?: ViewportFuncsOptions) => void
-export interface ViewportFuncs {
+/** project a position onto the viewpane, i.e. a mouse event clientX/clientY onto graph coordinates */
+export type Project = (position: XYPosition) => XYPosition
+
+/** set center of viewpane */
+export type SetCenter = (x: number, y: number, options?: SetCenterOptions) => void
+
+/** fit the viewpane around bounds */
+export type FitBounds = (bounds: Rect, options?: FitBoundsOptions) => void
+
+/** zoom in/out */
+export type ZoomInOut = (options?: TransitionOptions) => void
+
+/** zoom to a specific level */
+export type ZoomTo = (zoomLevel: number, options?: TransitionOptions) => void
+
+/** get current viewpane transform */
+export type GetTransform = () => ViewpaneTransform
+
+/** set current viewpane transform */
+export type SetTransform = (transform: ViewpaneTransform, options?: TransitionOptions) => void
+
+export interface ViewportFunctions {
zoomIn: ZoomInOut
zoomOut: ZoomInOut
zoomTo: ZoomTo
diff --git a/packages/vue-flow/src/utils/changes.ts b/packages/vue-flow/src/utils/changes.ts
index 9b06eb16..2bf9314b 100644
--- a/packages/vue-flow/src/utils/changes.ts
+++ b/packages/vue-flow/src/utils/changes.ts
@@ -15,6 +15,7 @@ import type {
NodeChange,
NodeRemoveChange,
NodeSelectionChange,
+ XYPosition,
} from '~/types'
function handleParentExpand(updateItem: GraphNode, parent: GraphNode) {