1
1
import { zoomIdentity } from 'd3-zoom'
2
- import { computed , ref } from 'vue'
2
+ import { computed } from 'vue'
3
3
import type { ComputedGetters , D3Selection , GraphNode , State , ViewportFunctions } from '~/types'
4
4
import { clampPosition , getRectOfNodes , getTransformForBounds , pointToRendererPoint } from '~/utils'
5
5
@@ -9,7 +9,9 @@ interface ExtendedViewport extends ViewportFunctions {
9
9
10
10
const DEFAULT_PADDING = 0.1
11
11
12
- function noop ( ) { }
12
+ function noop ( ) {
13
+ return Promise . resolve ( false )
14
+ }
13
15
14
16
const initialViewportHelper : ExtendedViewport = {
15
17
zoomIn : noop ,
@@ -25,59 +27,89 @@ const initialViewportHelper: ExtendedViewport = {
25
27
}
26
28
27
29
export function useViewport ( state : State , getters : ComputedGetters ) {
28
- const { nodes, d3Zoom, d3Selection, dimensions, translateExtent, minZoom, maxZoom, viewport, snapToGrid, snapGrid, hooks } =
29
- $ ( state )
30
-
31
- const { getNodes } = getters
30
+ const { nodes, d3Zoom, d3Selection, dimensions, translateExtent, minZoom, maxZoom, viewport, snapToGrid, snapGrid } = $ ( state )
32
31
33
- const nodesInitialized = ref ( false )
34
-
35
- hooks . nodesInitialized . on ( ( ) => {
36
- nodesInitialized . value = true
37
- } )
32
+ const { getNodes, getNodesInitialized } = getters
38
33
39
- const isReady = computed ( ( ) => ! ! d3Zoom && ! ! d3Selection && ! ! dimensions . width && ! ! dimensions . height && nodesInitialized . value )
34
+ const isReady = computed (
35
+ ( ) =>
36
+ ! ! d3Zoom &&
37
+ ! ! d3Selection &&
38
+ ! ! dimensions . width &&
39
+ ! ! dimensions . height &&
40
+ getNodesInitialized . value . length === getNodes . value . length ,
41
+ )
40
42
41
43
function zoom ( scale : number , duration ?: number ) {
42
- if ( d3Selection && d3Zoom ) {
43
- d3Zoom . scaleBy ( transition ( d3Selection , duration ) , scale )
44
- }
44
+ return new Promise < boolean > ( ( resolve ) => {
45
+ if ( d3Selection && d3Zoom ) {
46
+ d3Zoom . scaleBy (
47
+ transition ( d3Selection , duration , ( ) => {
48
+ resolve ( true )
49
+ } ) ,
50
+ scale ,
51
+ )
52
+ } else {
53
+ resolve ( false )
54
+ }
55
+ } )
45
56
}
46
57
47
58
function transformViewport ( x : number , y : number , zoom : number , duration ?: number ) {
48
- // enforce translate extent
49
- const { x : clampedX , y : clampedY } = clampPosition ( { x : - x , y : - y } , translateExtent )
50
-
51
- const nextTransform = zoomIdentity . translate ( - clampedX , - clampedY ) . scale ( zoom )
52
-
53
- if ( d3Selection && d3Zoom ) {
54
- d3Zoom . transform ( transition ( d3Selection , duration ) , nextTransform )
55
- }
59
+ return new Promise < boolean > ( ( resolve ) => {
60
+ // enforce translate extent
61
+ const { x : clampedX , y : clampedY } = clampPosition ( { x : - x , y : - y } , translateExtent )
62
+
63
+ const nextTransform = zoomIdentity . translate ( - clampedX , - clampedY ) . scale ( zoom )
64
+
65
+ if ( d3Selection && d3Zoom ) {
66
+ d3Zoom . transform (
67
+ transition ( d3Selection , duration , ( ) => {
68
+ resolve ( true )
69
+ } ) ,
70
+ nextTransform ,
71
+ )
72
+ } else {
73
+ resolve ( false )
74
+ }
75
+ } )
56
76
}
57
77
58
78
return computed < ExtendedViewport > ( ( ) => {
59
79
if ( isReady . value ) {
60
80
return {
61
81
initialized : true ,
82
+ // todo: allow passing scale as option
62
83
zoomIn : ( options ) => {
63
- zoom ( 1.2 , options ?. duration )
84
+ return zoom ( 1.2 , options ?. duration )
64
85
} ,
65
86
zoomOut : ( options ) => {
66
- zoom ( 1 / 1.2 , options ?. duration )
87
+ return zoom ( 1 / 1.2 , options ?. duration )
67
88
} ,
68
89
zoomTo : ( zoomLevel , options ) => {
69
- if ( d3Selection && d3Zoom ) {
70
- d3Zoom . scaleTo ( transition ( d3Selection , options ?. duration ) , zoomLevel )
71
- }
90
+ return new Promise < boolean > ( ( resolve ) => {
91
+ if ( d3Selection && d3Zoom ) {
92
+ d3Zoom . scaleTo (
93
+ transition ( d3Selection , options ?. duration , ( ) => {
94
+ resolve ( true )
95
+ } ) ,
96
+ zoomLevel ,
97
+ )
98
+ } else {
99
+ resolve ( false )
100
+ }
101
+ } )
72
102
} ,
73
103
setTransform : ( transform , options ) => {
74
- transformViewport ( transform . x , transform . y , transform . zoom , options ?. duration )
104
+ return transformViewport ( transform . x , transform . y , transform . zoom , options ?. duration )
105
+ } ,
106
+ getTransform : ( ) => {
107
+ return {
108
+ x : viewport . x ,
109
+ y : viewport . y ,
110
+ zoom : viewport . zoom ,
111
+ }
75
112
} ,
76
- getTransform : ( ) => ( {
77
- x : viewport . x ,
78
- y : viewport . y ,
79
- zoom : viewport . zoom ,
80
- } ) ,
81
113
fitView : (
82
114
options = {
83
115
padding : DEFAULT_PADDING ,
@@ -97,7 +129,7 @@ export function useViewport(state: State, getters: ComputedGetters) {
97
129
} )
98
130
99
131
if ( ! nodesToFit . length ) {
100
- return
132
+ return Promise . resolve ( false )
101
133
}
102
134
103
135
const bounds = getRectOfNodes ( nodesToFit )
@@ -112,14 +144,14 @@ export function useViewport(state: State, getters: ComputedGetters) {
112
144
options . offset ,
113
145
)
114
146
115
- transformViewport ( x , y , zoom , options ?. duration )
147
+ return transformViewport ( x , y , zoom , options ?. duration )
116
148
} ,
117
149
setCenter : ( x , y , options ) => {
118
150
const nextZoom = typeof options ?. zoom !== 'undefined' ? options . zoom : maxZoom
119
151
const centerX = dimensions . width / 2 - x * nextZoom
120
152
const centerY = dimensions . height / 2 - y * nextZoom
121
153
122
- transformViewport ( centerX , centerY , nextZoom , options ?. duration )
154
+ return transformViewport ( centerX , centerY , nextZoom , options ?. duration )
123
155
} ,
124
156
fitBounds : ( bounds , options = { padding : DEFAULT_PADDING } ) => {
125
157
const { x, y, zoom } = getTransformForBounds (
@@ -131,7 +163,7 @@ export function useViewport(state: State, getters: ComputedGetters) {
131
163
options . padding ,
132
164
)
133
165
134
- transformViewport ( x , y , zoom , options ?. duration )
166
+ return transformViewport ( x , y , zoom , options ?. duration )
135
167
} ,
136
168
project : ( position ) => pointToRendererPoint ( position , viewport , snapToGrid , snapGrid ) ,
137
169
}
@@ -141,6 +173,6 @@ export function useViewport(state: State, getters: ComputedGetters) {
141
173
} )
142
174
}
143
175
144
- function transition ( selection : D3Selection , ms = 0 ) {
145
- return selection . transition ( ) . duration ( ms )
176
+ function transition ( selection : D3Selection , ms = 0 , onEnd : ( ) => void ) {
177
+ return selection . transition ( ) . duration ( ms ) . on ( 'end' , onEnd )
146
178
}
0 commit comments