Skip to content

Commit 5798cc5

Browse files
committed
refactor(core): use useOnInitHandler to emit paneReady event
1 parent 9e72e72 commit 5798cc5

File tree

6 files changed

+138
-135
lines changed

6 files changed

+138
-135
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { watch } from 'vue'
2+
import { useVueFlow } from './useVueFlow'
3+
4+
export function useOnInitHandler() {
5+
const vfInstance = useVueFlow()
6+
7+
watch(vfInstance.viewportInitialized, (isInitialized) => {
8+
if (isInitialized) {
9+
setTimeout(() => {
10+
vfInstance.emits.paneReady(vfInstance)
11+
}, 1)
12+
}
13+
})
14+
}

packages/core/src/composables/useViewport.ts

Lines changed: 116 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { ComputedGetters, D3Selection, GraphNode, Project, State, ViewportF
44
import { clampPosition, getRectOfNodes, getTransformForBounds, pointToRendererPoint, rendererPointToPoint, warn } from '../utils'
55

66
interface ExtendedViewport extends ViewportFunctions {
7-
initialized: boolean
7+
viewportInitialized: boolean
88
screenToFlowCoordinate: Project
99
flowToScreenCoordinate: Project
1010
}
@@ -31,7 +31,7 @@ const initialViewportHelper: ExtendedViewport = {
3131
setTransform: noop,
3232
getViewport: () => ({ x: 0, y: 0, zoom: 1 }),
3333
getTransform: () => ({ x: 0, y: 0, zoom: 1 }),
34-
initialized: false,
34+
viewportInitialized: false,
3535
}
3636

3737
export function useViewport(state: State, getters: ComputedGetters) {
@@ -73,136 +73,138 @@ export function useViewport(state: State, getters: ComputedGetters) {
7373
}
7474

7575
return computed<ExtendedViewport>(() => {
76-
if (state.d3Zoom && state.d3Selection && state.dimensions.width && state.dimensions.height) {
77-
return {
78-
initialized: true,
79-
// todo: allow passing scale as option
80-
zoomIn: (options) => {
81-
return zoom(1.2, options?.duration)
82-
},
83-
zoomOut: (options) => {
84-
return zoom(1 / 1.2, options?.duration)
85-
},
86-
zoomTo: (zoomLevel, options) => {
87-
return new Promise<boolean>((resolve) => {
88-
if (state.d3Selection && state.d3Zoom) {
89-
state.d3Zoom.scaleTo(
90-
transition(state.d3Selection, options?.duration, () => {
91-
resolve(true)
92-
}),
93-
zoomLevel,
94-
)
95-
} else {
96-
resolve(false)
97-
}
98-
})
99-
},
100-
setViewport: (transform, options) => {
101-
return transformViewport(transform.x, transform.y, transform.zoom, options?.duration)
102-
},
103-
setTransform: (transform, options) => {
104-
return transformViewport(transform.x, transform.y, transform.zoom, options?.duration)
105-
},
106-
getViewport: () => ({
76+
const isInitialized = state.d3Zoom && state.d3Selection && state.dimensions.width && state.dimensions.height
77+
78+
if (!isInitialized) {
79+
return initialViewportHelper
80+
}
81+
82+
return {
83+
viewportInitialized: true,
84+
// todo: allow passing scale as option
85+
zoomIn: (options) => {
86+
return zoom(1.2, options?.duration)
87+
},
88+
zoomOut: (options) => {
89+
return zoom(1 / 1.2, options?.duration)
90+
},
91+
zoomTo: (zoomLevel, options) => {
92+
return new Promise<boolean>((resolve) => {
93+
if (state.d3Selection && state.d3Zoom) {
94+
state.d3Zoom.scaleTo(
95+
transition(state.d3Selection, options?.duration, () => {
96+
resolve(true)
97+
}),
98+
zoomLevel,
99+
)
100+
} else {
101+
resolve(false)
102+
}
103+
})
104+
},
105+
setViewport: (transform, options) => {
106+
return transformViewport(transform.x, transform.y, transform.zoom, options?.duration)
107+
},
108+
setTransform: (transform, options) => {
109+
return transformViewport(transform.x, transform.y, transform.zoom, options?.duration)
110+
},
111+
getViewport: () => ({
112+
x: state.viewport.x,
113+
y: state.viewport.y,
114+
zoom: state.viewport.zoom,
115+
}),
116+
getTransform: () => {
117+
return {
107118
x: state.viewport.x,
108119
y: state.viewport.y,
109120
zoom: state.viewport.zoom,
110-
}),
111-
getTransform: () => {
112-
return {
113-
x: state.viewport.x,
114-
y: state.viewport.y,
115-
zoom: state.viewport.zoom,
116-
}
121+
}
122+
},
123+
fitView: (
124+
options = {
125+
padding: DEFAULT_PADDING,
126+
includeHiddenNodes: false,
127+
duration: 0,
117128
},
118-
fitView: (
119-
options = {
120-
padding: DEFAULT_PADDING,
121-
includeHiddenNodes: false,
122-
duration: 0,
123-
},
124-
) => {
125-
const nodesToFit: GraphNode[] = (options.includeHiddenNodes ? state.nodes : getNodes.value).filter((node) => {
126-
const initialized = node.dimensions.width && node.dimensions.height
127-
let shouldInclude = true
128-
129-
if (options.nodes?.length) {
130-
shouldInclude = options.nodes.includes(node.id)
131-
}
132-
133-
return initialized && shouldInclude
134-
})
135-
136-
if (!nodesToFit.length) {
137-
return Promise.resolve(false)
129+
) => {
130+
const nodesToFit: GraphNode[] = (options.includeHiddenNodes ? state.nodes : getNodes.value).filter((node) => {
131+
const initialized = node.dimensions.width && node.dimensions.height
132+
let shouldInclude = true
133+
134+
if (options.nodes?.length) {
135+
shouldInclude = options.nodes.includes(node.id)
138136
}
139137

140-
const bounds = getRectOfNodes(nodesToFit)
138+
return initialized && shouldInclude
139+
})
141140

142-
const { x, y, zoom } = getTransformForBounds(
143-
bounds,
144-
state.dimensions.width,
145-
state.dimensions.height,
146-
options.minZoom ?? state.minZoom,
147-
options.maxZoom ?? state.maxZoom,
148-
options.padding ?? DEFAULT_PADDING,
149-
options.offset,
150-
)
141+
if (!nodesToFit.length) {
142+
return Promise.resolve(false)
143+
}
151144

152-
return transformViewport(x, y, zoom, options?.duration)
153-
},
154-
setCenter: (x, y, options) => {
155-
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : state.maxZoom
156-
const centerX = state.dimensions.width / 2 - x * nextZoom
157-
const centerY = state.dimensions.height / 2 - y * nextZoom
145+
const bounds = getRectOfNodes(nodesToFit)
158146

159-
return transformViewport(centerX, centerY, nextZoom, options?.duration)
160-
},
161-
fitBounds: (bounds, options = { padding: DEFAULT_PADDING }) => {
162-
const { x, y, zoom } = getTransformForBounds(
163-
bounds,
164-
state.dimensions.width,
165-
state.dimensions.height,
166-
state.minZoom,
167-
state.maxZoom,
168-
options.padding,
169-
)
170-
171-
return transformViewport(x, y, zoom, options?.duration)
172-
},
173-
project: (position) => pointToRendererPoint(position, state.viewport, state.snapToGrid, state.snapGrid),
174-
screenToFlowCoordinate: (position) => {
175-
if (state.vueFlowRef) {
176-
const { x: domX, y: domY } = state.vueFlowRef.getBoundingClientRect()
147+
const { x, y, zoom } = getTransformForBounds(
148+
bounds,
149+
state.dimensions.width,
150+
state.dimensions.height,
151+
options.minZoom ?? state.minZoom,
152+
options.maxZoom ?? state.maxZoom,
153+
options.padding ?? DEFAULT_PADDING,
154+
options.offset,
155+
)
156+
157+
return transformViewport(x, y, zoom, options?.duration)
158+
},
159+
setCenter: (x, y, options) => {
160+
const nextZoom = typeof options?.zoom !== 'undefined' ? options.zoom : state.maxZoom
161+
const centerX = state.dimensions.width / 2 - x * nextZoom
162+
const centerY = state.dimensions.height / 2 - y * nextZoom
163+
164+
return transformViewport(centerX, centerY, nextZoom, options?.duration)
165+
},
166+
fitBounds: (bounds, options = { padding: DEFAULT_PADDING }) => {
167+
const { x, y, zoom } = getTransformForBounds(
168+
bounds,
169+
state.dimensions.width,
170+
state.dimensions.height,
171+
state.minZoom,
172+
state.maxZoom,
173+
options.padding,
174+
)
177175

178-
const correctedPosition = {
179-
x: position.x - domX,
180-
y: position.y - domY,
181-
}
176+
return transformViewport(x, y, zoom, options?.duration)
177+
},
178+
project: (position) => pointToRendererPoint(position, state.viewport, state.snapToGrid, state.snapGrid),
179+
screenToFlowCoordinate: (position) => {
180+
if (state.vueFlowRef) {
181+
const { x: domX, y: domY } = state.vueFlowRef.getBoundingClientRect()
182182

183-
return pointToRendererPoint(correctedPosition, state.viewport, state.snapToGrid, state.snapGrid)
183+
const correctedPosition = {
184+
x: position.x - domX,
185+
y: position.y - domY,
184186
}
185187

186-
return { x: 0, y: 0 }
187-
},
188-
flowToScreenCoordinate: (position) => {
189-
if (state.vueFlowRef) {
190-
const { x: domX, y: domY } = state.vueFlowRef.getBoundingClientRect()
188+
return pointToRendererPoint(correctedPosition, state.viewport, state.snapToGrid, state.snapGrid)
189+
}
191190

192-
const correctedPosition = {
193-
x: position.x + domX,
194-
y: position.y + domY,
195-
}
191+
return { x: 0, y: 0 }
192+
},
193+
flowToScreenCoordinate: (position) => {
194+
if (state.vueFlowRef) {
195+
const { x: domX, y: domY } = state.vueFlowRef.getBoundingClientRect()
196196

197-
return rendererPointToPoint(correctedPosition, state.viewport)
197+
const correctedPosition = {
198+
x: position.x + domX,
199+
y: position.y + domY,
198200
}
199201

200-
return { x: 0, y: 0 }
201-
},
202-
}
203-
}
202+
return rendererPointToPoint(correctedPosition, state.viewport)
203+
}
204204

205-
return initialViewportHelper
205+
return { x: 0, y: 0 }
206+
},
207+
}
206208
})
207209
}
208210

packages/core/src/composables/useVueFlow.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class Storage {
5656

5757
const getters = useGetters(reactiveState, nodeIds, edgeIds)
5858

59-
const actions = useActions(id, emits, hooksOn, reactiveState, getters, nodeIds, edgeIds)
59+
const actions = useActions(id, reactiveState, getters, nodeIds, edgeIds)
6060

6161
actions.setState(reactiveState)
6262

packages/core/src/store/actions.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ import { useState } from './state'
5454

5555
export function useActions(
5656
id: string,
57-
emits: any,
58-
hooksOn: any,
5957
state: State,
6058
getters: ComputedGetters,
6159
// todo: change to a Set
@@ -846,7 +844,7 @@ export function useActions(
846844
const y = viewport?.y || position[1]
847845
const nextZoom = viewport?.zoom || zoom || state.viewport.zoom
848846

849-
return until(() => viewportHelper.value.initialized)
847+
return until(() => viewportHelper.value.viewportInitialized)
850848
.toBe(true)
851849
.then(() => {
852850
viewportHelper.value
@@ -891,7 +889,7 @@ export function useActions(
891889
setState(resetState)
892890
}
893891

894-
const actions: Actions = {
892+
return {
895893
updateNodePositions,
896894
updateNodeDimensions,
897895
setElements,
@@ -944,20 +942,4 @@ export function useActions(
944942
$reset,
945943
$destroy: () => {},
946944
}
947-
948-
until(() => viewportHelper.value.initialized)
949-
.toBe(true)
950-
.then(() => {
951-
state.hooks.paneReady.trigger({
952-
id,
953-
emits,
954-
vueFlowVersion: typeof __VUE_FLOW_VERSION__ !== 'undefined' ? __VUE_FLOW_VERSION__ : 'UNKNOWN',
955-
...hooksOn,
956-
...state,
957-
...getters,
958-
...actions,
959-
})
960-
})
961-
962-
return actions
963945
}

packages/core/src/store/state.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ function defaultState(): State {
5050
d3Zoom: null,
5151
d3Selection: null,
5252
d3ZoomHandler: null,
53+
54+
viewportInitialized: false,
55+
5356
minZoom: 0.5,
5457
maxZoom: 2,
5558

packages/core/src/types/store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ export interface State extends Omit<FlowOptions, 'id' | 'modelValue'> {
5757
readonly d3Selection: D3Selection | null
5858
readonly d3ZoomHandler: D3ZoomHandler | null
5959

60+
viewportInitialized: boolean
61+
6062
/** use setMinZoom action to change minZoom */
6163
minZoom: number
6264
/** use setMaxZoom action to change maxZoom */

0 commit comments

Comments
 (0)