@@ -48,6 +48,10 @@ const selectionKeyPressed = ref(false)
48
48
49
49
const isZoomingOrPanning = ref (false )
50
50
51
+ const isPanScrolling = ref (false )
52
+
53
+ const panScrollTimeout = ref <ReturnType <typeof setTimeout >>()
54
+
51
55
let zoomedWithRightMouseButton = false
52
56
53
57
let mouseButton = 0
@@ -183,12 +187,13 @@ onMounted(() => {
183
187
event .stopImmediatePropagation ()
184
188
185
189
const currentZoom = d3Selection .property (' __zoom' ).k || 1
190
+ const _isMacOs = isMacOs ()
186
191
187
- if (event .ctrlKey && zoomOnPinch .value && isMacOs ()) {
192
+ // macOS sets ctrlKey=true for pinch gesture on a trackpad
193
+ if (event .ctrlKey && zoomOnPinch && _isMacOs ) {
188
194
const point = pointer (event )
189
195
const pinchDelta = wheelDelta (event )
190
196
const zoom = currentZoom * 2 ** pinchDelta
191
-
192
197
// @ts-expect-error d3-zoom types are not up to date
193
198
d3Zoom .scaleTo (d3Selection , zoom , point , event )
194
199
@@ -198,14 +203,47 @@ onMounted(() => {
198
203
// increase scroll speed in firefox
199
204
// firefox: deltaMode === 1; chrome: deltaMode === 0
200
205
const deltaNormalize = event .deltaMode === 1 ? 20 : 1
201
- const deltaX = panOnScrollMode .value === PanOnScrollMode .Vertical ? 0 : event .deltaX * deltaNormalize
202
- const deltaY = panOnScrollMode .value === PanOnScrollMode .Horizontal ? 0 : event .deltaY * deltaNormalize
206
+
207
+ let deltaX = panOnScrollMode .value === PanOnScrollMode .Vertical ? 0 : event .deltaX * deltaNormalize
208
+ let deltaY = panOnScrollMode .value === PanOnScrollMode .Horizontal ? 0 : event .deltaY * deltaNormalize
209
+
210
+ // this enables vertical scrolling with shift + scroll on windows
211
+ if (! _isMacOs && event .shiftKey && panOnScrollMode .value !== PanOnScrollMode .Vertical && ! deltaX && deltaY ) {
212
+ deltaX = deltaY
213
+ deltaY = 0
214
+ }
203
215
204
216
d3Zoom .translateBy (
205
217
d3Selection ,
206
218
- (deltaX / currentZoom ) * panOnScrollSpeed .value ,
207
219
- (deltaY / currentZoom ) * panOnScrollSpeed .value ,
208
220
)
221
+
222
+ const nextViewport = eventToFlowTransform (d3Selection .property (' __zoom' ))
223
+
224
+ clearTimeout (panScrollTimeout .value )
225
+
226
+ // for pan on scroll we need to handle the event calls on our own
227
+ // we can't use the start, zoom and end events from d3-zoom
228
+ // because start and move gets called on every scroll event and not once at the beginning
229
+ if (! isPanScrolling .value ) {
230
+ isPanScrolling .value = true
231
+
232
+ emits .moveStart ({ event , flowTransform: nextViewport })
233
+ emits .viewportChangeStart (nextViewport )
234
+ }
235
+
236
+ if (isPanScrolling .value ) {
237
+ emits .move ({ event , flowTransform: nextViewport })
238
+ emits .viewportChange (nextViewport )
239
+
240
+ panScrollTimeout .value = setTimeout (() => {
241
+ emits .moveEnd ({ event , flowTransform: nextViewport })
242
+ emits .viewportChangeEnd (nextViewport )
243
+
244
+ isPanScrolling .value = false
245
+ }, 150 )
246
+ }
209
247
},
210
248
{ passive: false },
211
249
)
0 commit comments