1
- import { zoomIdentity } from 'd3-zoom'
2
1
import { computed } from 'vue'
3
- import { clampPosition , rendererPointToPoint } from '@xyflow/system'
4
- import type { D3Selection , GraphNode , Project , State , ViewportFunctions } from '../types'
2
+ import { rendererPointToPoint } from '@xyflow/system'
3
+ import type { GraphNode , Project , State , ViewportFunctions } from '../types'
5
4
import { getRectOfNodes , getTransformForBounds , pointToRendererPoint , warn } from '../utils'
6
5
7
6
export interface ViewportHelper extends ViewportFunctions {
@@ -29,9 +28,7 @@ const initialViewportHelper: ViewportHelper = {
29
28
screenToFlowCoordinate : ( position ) => position ,
30
29
flowToScreenCoordinate : ( position ) => position ,
31
30
setViewport : noop ,
32
- setTransform : noop ,
33
31
getViewport : ( ) => ( { x : 0 , y : 0 , zoom : 1 } ) ,
34
- getTransform : ( ) => ( { x : 0 , y : 0 , zoom : 1 } ) ,
35
32
viewportInitialized : false ,
36
33
}
37
34
@@ -42,43 +39,9 @@ const initialViewportHelper: ViewportHelper = {
42
39
* @param state
43
40
*/
44
41
export function useViewportHelper ( state : State ) {
45
- function zoom ( scale : number , duration ?: number ) {
46
- return new Promise < boolean > ( ( resolve ) => {
47
- if ( state . d3Selection && state . d3Zoom ) {
48
- state . d3Zoom . scaleBy (
49
- transition ( state . d3Selection , duration , ( ) => {
50
- resolve ( true )
51
- } ) ,
52
- scale ,
53
- )
54
- } else {
55
- resolve ( false )
56
- }
57
- } )
58
- }
59
-
60
- function transformViewport ( x : number , y : number , zoom : number , duration ?: number ) {
61
- return new Promise < boolean > ( ( resolve ) => {
62
- // enforce translate extent
63
- const { x : clampedX , y : clampedY } = clampPosition ( { x : - x , y : - y } , state . translateExtent )
64
-
65
- const nextTransform = zoomIdentity . translate ( - clampedX , - clampedY ) . scale ( zoom )
66
-
67
- if ( state . d3Selection && state . d3Zoom ) {
68
- state . d3Zoom . transform (
69
- transition ( state . d3Selection , duration , ( ) => {
70
- resolve ( true )
71
- } ) ,
72
- nextTransform ,
73
- )
74
- } else {
75
- resolve ( false )
76
- }
77
- } )
78
- }
79
-
80
42
return computed < ViewportHelper > ( ( ) => {
81
- const isInitialized = state . d3Zoom && state . d3Selection && state . dimensions . width && state . dimensions . height
43
+ const panZoom = state . panZoom
44
+ const isInitialized = state . panZoom && state . dimensions . width && state . dimensions . height
82
45
83
46
if ( ! isInitialized ) {
84
47
return initialViewportHelper
@@ -88,44 +51,36 @@ export function useViewportHelper(state: State) {
88
51
viewportInitialized : true ,
89
52
// todo: allow passing scale as option
90
53
zoomIn : ( options ) => {
91
- return zoom ( 1.2 , options ?. duration )
54
+ return panZoom ? panZoom . scaleBy ( 1.2 , options ) : Promise . resolve ( false )
92
55
} ,
93
56
zoomOut : ( options ) => {
94
- return zoom ( 1 / 1.2 , options ?. duration )
57
+ return panZoom ? panZoom . scaleBy ( 1 / 1.2 , options ) : Promise . resolve ( false )
95
58
} ,
96
59
zoomTo : ( zoomLevel , options ) => {
97
- return new Promise < boolean > ( ( resolve ) => {
98
- if ( state . d3Selection && state . d3Zoom ) {
99
- state . d3Zoom . scaleTo (
100
- transition ( state . d3Selection , options ?. duration , ( ) => {
101
- resolve ( true )
102
- } ) ,
103
- zoomLevel ,
104
- )
105
- } else {
106
- resolve ( false )
107
- }
108
- } )
109
- } ,
110
- setViewport : ( transform , options ) => {
111
- return transformViewport ( transform . x , transform . y , transform . zoom , options ?. duration )
60
+ return panZoom ? panZoom . scaleTo ( zoomLevel , options ) : Promise . resolve ( false )
112
61
} ,
113
- setTransform : ( transform , options ) => {
114
- return transformViewport ( transform . x , transform . y , transform . zoom , options ?. duration )
62
+ setViewport : async ( viewport , options ) => {
63
+ if ( ! panZoom ) {
64
+ return Promise . resolve ( false )
65
+ }
66
+
67
+ await panZoom . setViewport (
68
+ {
69
+ x : viewport . x ?? state . viewport . x ,
70
+ y : viewport . y ?? state . viewport . y ,
71
+ zoom : viewport . zoom ?? state . viewport . zoom ,
72
+ } ,
73
+ options ,
74
+ )
75
+
76
+ return Promise . resolve ( true )
115
77
} ,
116
78
getViewport : ( ) => ( {
117
79
x : state . viewport . x ,
118
80
y : state . viewport . y ,
119
81
zoom : state . viewport . zoom ,
120
82
} ) ,
121
- getTransform : ( ) => {
122
- return {
123
- x : state . viewport . x ,
124
- y : state . viewport . y ,
125
- zoom : state . viewport . zoom ,
126
- }
127
- } ,
128
- fitView : (
83
+ fitView : async (
129
84
options = {
130
85
padding : DEFAULT_PADDING ,
131
86
includeHiddenNodes : false ,
@@ -143,7 +98,7 @@ export function useViewportHelper(state: State) {
143
98
}
144
99
}
145
100
146
- if ( ! nodesToFit . length ) {
101
+ if ( ! nodesToFit . length || ! panZoom ) {
147
102
return Promise . resolve ( false )
148
103
}
149
104
@@ -159,16 +114,28 @@ export function useViewportHelper(state: State) {
159
114
options . offset ,
160
115
)
161
116
162
- return transformViewport ( x , y , zoom , options ?. duration )
117
+ await panZoom . setViewport ( { x, y, zoom } , options )
118
+
119
+ return Promise . resolve ( true )
163
120
} ,
164
- setCenter : ( x , y , options ) => {
121
+ setCenter : async ( x , y , options ) => {
122
+ if ( ! panZoom ) {
123
+ return Promise . resolve ( false )
124
+ }
125
+
165
126
const nextZoom = typeof options ?. zoom !== 'undefined' ? options . zoom : state . maxZoom
166
127
const centerX = state . dimensions . width / 2 - x * nextZoom
167
128
const centerY = state . dimensions . height / 2 - y * nextZoom
168
129
169
- return transformViewport ( centerX , centerY , nextZoom , options ?. duration )
130
+ await panZoom . setViewport ( { x : centerX , y : centerY , zoom : nextZoom } , options )
131
+
132
+ return Promise . resolve ( true )
170
133
} ,
171
- fitBounds : ( bounds , options = { padding : DEFAULT_PADDING } ) => {
134
+ fitBounds : async ( bounds , options = { padding : DEFAULT_PADDING } ) => {
135
+ if ( ! panZoom ) {
136
+ return Promise . resolve ( false )
137
+ }
138
+
172
139
const { x, y, zoom } = getTransformForBounds (
173
140
bounds ,
174
141
state . dimensions . width ,
@@ -178,7 +145,9 @@ export function useViewportHelper(state: State) {
178
145
options . padding ,
179
146
)
180
147
181
- return transformViewport ( x , y , zoom , options ?. duration )
148
+ await panZoom . setViewport ( { x, y, zoom } , options )
149
+
150
+ return Promise . resolve ( true )
182
151
} ,
183
152
project : ( position ) => pointToRendererPoint ( position , state . viewport , state . snapToGrid , state . snapGrid ) ,
184
153
screenToFlowCoordinate : ( position ) => {
@@ -212,7 +181,3 @@ export function useViewportHelper(state: State) {
212
181
}
213
182
} )
214
183
}
215
-
216
- function transition ( selection : D3Selection , ms = 0 , onEnd : ( ) => void ) {
217
- return ( selection as any ) . transition ( ) . duration ( ms ) . on ( 'end' , onEnd )
218
- }
0 commit comments