dom-pan-zoom 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,777 @@
1
+ (function (global, factory) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
3
+ typeof define === 'function' && define.amd ? define(factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.domPanZoom = factory());
5
+ })(this, (function () { 'use strict';
6
+
7
+ class domPanZoom {
8
+ constructor(options = {}) {
9
+ const defaultOptions = {
10
+ // The wrapper and container element
11
+ // You can use an element object or a selector string
12
+ wrapperElement: null,
13
+ panZoomElement: null,
14
+
15
+ // Start with a centered position
16
+ // This option overrides options initalPanX and initialPanY
17
+ center: true,
18
+
19
+ // Setting the option bounds to 'contain' or 'cover' limits the boundries of the panZoomElement to the wrapperElement
20
+ // This works similar to the CSS property 'background-size: contain / cover'
21
+ // Disable bound by setting this option to 'false'
22
+ // This option might effect the option minZoom
23
+ bounds: 'contain',
24
+
25
+ // Minimum and maximum zoom
26
+ minZoom: 0.1,
27
+ maxZoom: 10,
28
+
29
+ // How many percent to pan by default with the panning methods panLeft, panRight, panUp and panDown
30
+ panStep: 10,
31
+
32
+ // How many percent to zoom by default with the methods zoomIn and zoomOut
33
+ zoomStep: 50,
34
+
35
+ // The speed in which to zoom when using mouse wheel
36
+ zoomSpeedWheel: 1,
37
+
38
+ // The speed in which to zoom when pinching with touch gestures
39
+ // TODO this seems to not work correctly
40
+ zoomSpeedPinch: 4,
41
+
42
+ // Initial zoom
43
+ // Use any zoom value between the options minZoom and maxZoom
44
+ // Use 'cover' or 'contain' to limit the panZoomElement bounds to the wrapperElement
45
+ initialZoom: 'contain',
46
+
47
+ // Initial pan in percent
48
+ // The option 'center' has to be 'false' for initial panning to work
49
+ initialPanX: 0,
50
+ initialPanY: 0,
51
+
52
+ // Prefer scrolling the page to zooming with mousewheel or panning with touch event
53
+ // TODO how does google do it with tough events (use two fingers) ??
54
+ preferPageScroll: true,
55
+
56
+ // The text to show when the option preferPageScroll is enabled
57
+ preferPageScrollText: {
58
+ // TODO Differentiate between mac and windows
59
+ },
60
+
61
+ // Transition speed for panning and zooming in milliseconds
62
+ // Higher values are slower
63
+ transitionSpeed: 400,
64
+
65
+ // Events
66
+ onInit: null,
67
+ onChange: null,
68
+ onZoom: null,
69
+ onPan: null
70
+ };
71
+
72
+ this.options = Object.assign({}, defaultOptions, options);
73
+
74
+ this.init();
75
+ }
76
+
77
+ // Initialize
78
+ init() {
79
+ // Init containers
80
+ const wrapper = this.getWrapper();
81
+ const container = this.getContainer();
82
+
83
+ // Add styles
84
+ wrapper.style.cursor = 'grab';
85
+ wrapper.style.overflow = 'hidden';
86
+
87
+ // Cache
88
+ this.evCache = [];
89
+ this.pinchDiffCache = 0;
90
+ this.pinchMoveCache = null;
91
+
92
+ // Attach events
93
+ this.attachEvents();
94
+
95
+ // Adjust minZoom for option bounds
96
+ if (this.options.bounds) {
97
+ const maxWidth = wrapper.clientWidth;
98
+ const maxHeight = wrapper.clientHeight;
99
+
100
+ const panZoomWidth = container.clientWidth;
101
+ const panZoomHeight = container.clientHeight;
102
+
103
+ const minZoomX = maxWidth / panZoomWidth;
104
+ const minZoomY = maxHeight / panZoomHeight;
105
+
106
+ if (this.options.bounds == 'cover') {
107
+ this.options.minZoom = Math.max(
108
+ this.options.minZoom,
109
+ minZoomX,
110
+ minZoomY
111
+ );
112
+ } else {
113
+ this.options.minZoom = Math.max(
114
+ this.options.minZoom,
115
+ Math.min(minZoomX, minZoomY)
116
+ );
117
+ }
118
+ }
119
+
120
+ // Set initial zoom
121
+ this.zoom = this.sanitizeZoom(this.options.initialZoom);
122
+
123
+ // Set initial pan
124
+ this.x = this.options.initialPanX;
125
+ this.y = this.options.initialPanY;
126
+
127
+ // Set position
128
+ if (this.options.center) {
129
+ this.center(true);
130
+ } else {
131
+ this.panTo(this.options.initialPanX, this.options.initialPanY, true);
132
+ }
133
+
134
+ // Trigger event
135
+ this.fireEvent('onInit', this.getPosition());
136
+ }
137
+
138
+ // Fire an event from the options
139
+ fireEvent(event, pass) {
140
+ this.options[event] && this.options[event].bind(this)(pass);
141
+ }
142
+
143
+ // Attach events
144
+ attachEvents() {
145
+ // Event while mouse moving
146
+ const setPositionEvent = (ev) => {
147
+ if (this.blockPan == true) {
148
+ return;
149
+ }
150
+
151
+ let event = ev;
152
+ if (ev.touches && ev.touches.length) {
153
+ event = ev.touches[0];
154
+ }
155
+
156
+ let movementX = 0;
157
+ let movementY = 0;
158
+
159
+ if (this.previousEvent) {
160
+ movementX = event.pageX - this.previousEvent.pageX;
161
+ movementY = event.pageY - this.previousEvent.pageY;
162
+ }
163
+
164
+ this.x += movementX;
165
+ this.y += movementY;
166
+ this.setPosition(true);
167
+
168
+ this.previousEvent = event;
169
+
170
+ // Trigger event
171
+ this.fireEvent('onPan', this.getPosition());
172
+ };
173
+
174
+ // Mouse down or touchstart event
175
+ const mouseDownTouchStartEvent = (ev) => {
176
+ ev.preventDefault();
177
+ document.body.style.cursor = 'grabbing';
178
+ this.getWrapper().style.cursor = 'grabbing';
179
+ document.addEventListener('mousemove', setPositionEvent, {
180
+ passive: true
181
+ });
182
+ document.addEventListener('touchmove', setPositionEvent, {
183
+ passive: true
184
+ });
185
+ };
186
+
187
+ this.getWrapper().addEventListener('mousedown', mouseDownTouchStartEvent, {
188
+ passive: false
189
+ });
190
+
191
+ this.getWrapper().addEventListener('touchstart', mouseDownTouchStartEvent, {
192
+ passive: false
193
+ });
194
+
195
+ const mouseUpTouchEndEvent = () => {
196
+ this.previousEvent = null;
197
+ document.body.style.cursor = null;
198
+ this.getWrapper().style.cursor = 'grab';
199
+ document.removeEventListener('mousemove', setPositionEvent, {
200
+ passive: true
201
+ });
202
+ document.removeEventListener('touchmove', setPositionEvent, {
203
+ passive: true
204
+ });
205
+ };
206
+
207
+ document.addEventListener('mouseup', mouseUpTouchEndEvent, {
208
+ passive: true
209
+ });
210
+ document.addEventListener('touchend', mouseUpTouchEndEvent, {
211
+ passive: true
212
+ });
213
+
214
+ // Mouse wheel events
215
+ const mouseWheelEvent = (ev) => {
216
+ ev.preventDefault();
217
+
218
+ // Delta
219
+ let delta = ev.deltaY;
220
+ if (ev.deltaMode > 0) {
221
+ delta *= 100;
222
+ }
223
+
224
+ // Speed
225
+ const speed = this.options.zoomSpeedWheel;
226
+
227
+ // Adjust speed (https://github.com/anvaka/panzoom/blob/master/index.js#L884)
228
+ const sign = Math.sign(delta);
229
+ const deltaAdjustedSpeed = 1 - sign * Math.min(0.25, Math.abs((speed * delta) / 128));
230
+ const nextZoom = this.sanitizeZoom(this.zoom * deltaAdjustedSpeed);
231
+
232
+ // Get offset to center, then adjust
233
+ const offsetToCenter = this.getEventOffsetToCenter(ev);
234
+ this.adjustPositionByZoom(nextZoom, offsetToCenter.x, offsetToCenter.y);
235
+
236
+ // Update position
237
+ this.zoom = nextZoom;
238
+ this.setPosition(true);
239
+
240
+ // Trigger event
241
+ this.fireEvent('onZoom', this.getPosition());
242
+ };
243
+
244
+ this.getWrapper().addEventListener('wheel', mouseWheelEvent, {
245
+ passive: false
246
+ });
247
+
248
+ // Pinch events
249
+ const pointerDownEvent = (ev) => {
250
+ this.evCache.push(ev);
251
+ this.zoomCache = this.zoom;
252
+ this.xCache = this.x;
253
+ this.yCache = this.y;
254
+
255
+ if (this.evCache.length == 2) {
256
+ this.blockPan = true;
257
+ this.pinchDiffCache = this.getTouchEventsDistance(
258
+ this.evCache[0],
259
+ this.evCache[1]
260
+ );
261
+ this.touchEventsCenterCache = this.getTouchEventsCenter(
262
+ this.evCache[0],
263
+ this.evCache[1]
264
+ );
265
+ }
266
+ };
267
+
268
+ this.getWrapper().addEventListener('pointerdown', pointerDownEvent, {
269
+ passive: false
270
+ });
271
+
272
+ const pointerMoveEvent = (ev) => {
273
+ for (let i = 0; i < this.evCache.length; i++) {
274
+ if (ev.pointerId == this.evCache[i].pointerId) {
275
+ this.evCache[i] = ev;
276
+ break;
277
+ }
278
+ }
279
+
280
+ // Proceed if two touch gestures detected
281
+ if (this.evCache.length == 2) {
282
+ // Calculate distance between fingers
283
+ let pinchDiff = this.getTouchEventsDistance(
284
+ this.evCache[0],
285
+ this.evCache[1]
286
+ );
287
+ pinchDiff -= this.pinchDiffCache;
288
+
289
+ let pinchDiffPercent = pinchDiff / this.getContainer().clientWidth;
290
+ pinchDiffPercent *= this.options.zoomSpeedPinch;
291
+ pinchDiffPercent += 1;
292
+
293
+ const nextZoom = this.sanitizeZoom(this.zoomCache * pinchDiffPercent);
294
+
295
+ // Get offset to center, then adjust
296
+ const touchEventsCenter = this.getTouchEventsCenter(
297
+ this.evCache[0],
298
+ this.evCache[1]
299
+ );
300
+ const offsetToCenter = this.getEventOffsetToCenter({
301
+ target: this.evCache[0].target,
302
+ clientX: touchEventsCenter.clientX,
303
+ clientY: touchEventsCenter.clientY
304
+ });
305
+ this.adjustPositionByZoom(nextZoom, offsetToCenter.x, offsetToCenter.y);
306
+
307
+ // Adjust position when moving while pinching
308
+ const touchEventsCenterDiff = {
309
+ x: touchEventsCenter.clientX - this.touchEventsCenterCache.clientX,
310
+ y: touchEventsCenter.clientY - this.touchEventsCenterCache.clientY
311
+ };
312
+ this.x = this.xCache + touchEventsCenterDiff.x;
313
+ this.y = this.yCache + touchEventsCenterDiff.y;
314
+
315
+ // Update position
316
+ this.zoom = nextZoom;
317
+ this.setPosition(true);
318
+
319
+ // Trigger events
320
+ this.fireEvent('onZoom', this.getPosition());
321
+ this.fireEvent('onPan', this.getPosition());
322
+ }
323
+ };
324
+
325
+ this.getWrapper().addEventListener('pointermove', pointerMoveEvent, {
326
+ passive: false
327
+ });
328
+
329
+ const pointerUpEvent = (ev) => {
330
+ for (var i = 0; i < this.evCache.length; i++) {
331
+ if (this.evCache[i].pointerId == ev.pointerId) {
332
+ this.evCache.splice(i, 1);
333
+ break;
334
+ }
335
+ }
336
+
337
+ if (this.evCache.length < 2) {
338
+ this.blockPan = false;
339
+ }
340
+ };
341
+
342
+ ['pointerup', 'pointercancel', 'pointerout', 'pointerleave'].forEach(
343
+ (event) => {
344
+ this.getWrapper().addEventListener(event, pointerUpEvent, {
345
+ passive: false
346
+ });
347
+ }
348
+ );
349
+ }
350
+
351
+ // https://stackoverflow.com/questions/8389156/what-substitute-should-we-use-for-layerx-layery-since-they-are-deprecated-in-web
352
+ getEventOffsetToParent(ev) {
353
+ let el = ev.target;
354
+ let x = 0;
355
+ let y = 0;
356
+
357
+ while (el && !isNaN(el.offsetLeft) && !isNaN(el.offsetTop)) {
358
+ x += el.offsetLeft - el.scrollLeft;
359
+ y += el.offsetTop - el.scrollTop;
360
+ el = el.offsetParent;
361
+ }
362
+
363
+ x = ev.clientX - x;
364
+ y = ev.clientY - y;
365
+
366
+ return { x: x, y: y };
367
+ }
368
+
369
+ // Get the event offset to the center
370
+ getEventOffsetToCenter(ev) {
371
+ const wrapper = this.getWrapper();
372
+ const container = this.getContainer();
373
+ const diffX = wrapper.clientWidth - container.clientWidth;
374
+ const diffY = wrapper.clientHeight - container.clientHeight;
375
+ const centerX = diffX * 0.5;
376
+ const centerY = diffY * 0.5;
377
+
378
+ const offsetToCenter = {
379
+ x: 0,
380
+ y: 0
381
+ };
382
+
383
+ if (ev) {
384
+ const offsetToParent = this.getEventOffsetToParent(ev);
385
+ offsetToCenter.x =
386
+ (wrapper.clientWidth / 2 - offsetToParent.x - window.scrollX) * -1;
387
+ offsetToCenter.y =
388
+ (wrapper.clientHeight / 2 - offsetToParent.y - window.scrollY) * -1;
389
+ }
390
+
391
+ const offsetX = this.x - centerX - offsetToCenter.x;
392
+ const offsetY = this.y - centerY - offsetToCenter.y;
393
+
394
+ return {
395
+ x: offsetX,
396
+ y: offsetY
397
+ };
398
+ }
399
+
400
+ // Get the distance between two touch events
401
+ getTouchEventsDistance(ev1, ev2) {
402
+ return Math.abs(Math.hypot(ev1.pageX - ev1.pageX, ev1.pageY - ev2.pageY));
403
+ }
404
+
405
+ // Get the center point between two touch events
406
+ getTouchEventsCenter(ev1, ev2) {
407
+ return {
408
+ pageX: (ev1.pageX + ev2.pageX) / 2,
409
+ pageY: (ev1.pageY + ev2.pageX) / 2,
410
+ clientX: (ev1.clientX + ev2.clientX) / 2,
411
+ clientY: (ev1.clientY + ev2.clientY) / 2
412
+ };
413
+ }
414
+
415
+ // Get current position values
416
+ getPosition() {
417
+ return {
418
+ zoom: this.zoom,
419
+ x: this.x,
420
+ y: this.y
421
+ };
422
+ }
423
+
424
+ // Initialize
425
+ setPosition(instant) {
426
+ this.transition(!instant);
427
+
428
+ // Fit to bounds
429
+ if (this.options.bounds) {
430
+ const wrapper = this.getWrapper();
431
+ const container = this.getContainer();
432
+ const wrapperWidth = wrapper.clientWidth;
433
+ const wrapperHeight = wrapper.clientHeight;
434
+ const containerWidth = container.clientWidth;
435
+ const containerHeight = container.clientHeight;
436
+ const containerZoomWidth = containerWidth * this.zoom;
437
+ const containerZoomHeight = containerHeight * this.zoom;
438
+
439
+ const upperOffsetX = (containerWidth / 2) * (this.zoom - 1);
440
+ const lowerOffsetX = upperOffsetX * -1 + wrapperWidth - containerWidth;
441
+
442
+ if (containerZoomWidth < wrapperWidth) {
443
+ this.x < upperOffsetX && (this.x = upperOffsetX);
444
+ this.x > lowerOffsetX && (this.x = lowerOffsetX);
445
+ } else {
446
+ this.x = Math.min(this.x, upperOffsetX);
447
+ this.x = Math.max(this.x, lowerOffsetX);
448
+ }
449
+
450
+ const upperOffsetY = (containerHeight / 2) * (this.zoom - 1);
451
+ const lowerOffsetY = upperOffsetY * -1 + wrapperHeight - containerHeight;
452
+
453
+ if (containerZoomHeight < wrapperHeight) {
454
+ this.y < upperOffsetY && (this.y = upperOffsetY);
455
+ this.y > lowerOffsetY && (this.y = lowerOffsetY);
456
+ } else {
457
+ this.y = Math.min(this.y, upperOffsetY);
458
+ this.y = Math.max(this.y, lowerOffsetY);
459
+ }
460
+ }
461
+
462
+ // Set position
463
+ this.getContainer().style.transform =
464
+ 'matrix(' +
465
+ this.zoom +
466
+ ', 0, 0, ' +
467
+ this.zoom +
468
+ ', ' +
469
+ this.x +
470
+ ', ' +
471
+ this.y +
472
+ ')';
473
+
474
+ // Trigger event
475
+ this.fireEvent('onChange', this.getPosition());
476
+
477
+ // Return instance
478
+ return this;
479
+ }
480
+
481
+ // Sanitize zoom value
482
+ sanitizeZoom(zoom) {
483
+ // Get values for 'cover' and 'contain'
484
+ if (zoom == 'cover' || zoom == 'contain') {
485
+ const wrapper = this.getWrapper();
486
+ const container = this.getContainer();
487
+
488
+ const maxWidth = wrapper.clientWidth;
489
+ const maxHeight = wrapper.clientHeight;
490
+
491
+ const panZoomWidth = container.clientWidth;
492
+ const panZoomHeight = container.clientHeight;
493
+
494
+ const minZoomX = maxWidth / panZoomWidth;
495
+ const minZoomY = maxHeight / panZoomHeight;
496
+
497
+ // TODO is first cebter OK?
498
+ this.center(true, true);
499
+
500
+ if (zoom == 'cover') {
501
+ zoom = Math.max(minZoomX, minZoomY);
502
+ } else {
503
+ zoom = Math.min(minZoomX, minZoomY);
504
+ }
505
+ }
506
+
507
+ // Adjust for minZoom
508
+ if (zoom < this.options.minZoom) {
509
+ zoom = this.options.minZoom;
510
+ }
511
+
512
+ // Adjust for maxZoom
513
+ if (zoom > this.options.maxZoom) {
514
+ zoom = this.options.maxZoom;
515
+ }
516
+
517
+ return zoom;
518
+ }
519
+
520
+ // Getter for zoom
521
+ getZoom() {
522
+ return this.zoom;
523
+ }
524
+
525
+ // Zoom to
526
+ zoomTo(zoom, instant) {
527
+ // Sanitize zoom
528
+ zoom = this.sanitizeZoom(zoom);
529
+
530
+ // Get offset to center, then adjust
531
+ const offsetToCenter = this.getEventOffsetToCenter();
532
+ this.adjustPositionByZoom(zoom, offsetToCenter.x, offsetToCenter.y);
533
+
534
+ // Set new zoom
535
+ this.zoom = zoom;
536
+ this.setPosition(instant);
537
+
538
+ // Trigger event
539
+ this.fireEvent('onZoom', this.getPosition());
540
+
541
+ // Return instance
542
+ return this;
543
+ }
544
+
545
+ // Zoom in
546
+ zoomIn(step, instant) {
547
+ return this.zoomInOut(step, instant, 'in');
548
+ }
549
+
550
+ // Zoom out
551
+ zoomOut(step, instant) {
552
+ return this.zoomInOut(step, instant, 'out');
553
+ }
554
+
555
+ // Zoom in or out
556
+ zoomInOut(step, instant, direction) {
557
+ // Step is an optional attribute
558
+ if (step === true || step === false) {
559
+ instant = step;
560
+ step = null;
561
+ }
562
+ step = step || this.options.zoomStep;
563
+
564
+ // Calculate nextZoom
565
+ const currentZoom = this.zoom;
566
+ const zoomStep = (100 + step) / 100;
567
+ if (direction === 'out') {
568
+ zoomStep = 1 / zoomStep;
569
+ }
570
+ const nextZoom = currentZoom * zoomStep;
571
+
572
+ // Update zoom
573
+ return this.zoomTo(nextZoom, instant);
574
+ }
575
+
576
+ // Adjust position when zooming
577
+ adjustPositionByZoom(zoom, x, y) {
578
+ const currentZoom = this.zoom;
579
+ const zoomGrowth = (zoom - currentZoom) / currentZoom;
580
+
581
+ const container = this.getContainer();
582
+ const maxOffsetX = container.clientWidth * 0.5 * currentZoom;
583
+ const maxOffsetY = container.clientHeight * 0.5 * currentZoom;
584
+
585
+ x > maxOffsetX && (x = Math.min(x, maxOffsetX));
586
+ x < maxOffsetX * -1 && (x = Math.max(x, maxOffsetX * -1));
587
+
588
+ y > maxOffsetY && (y = Math.min(y, maxOffsetY));
589
+ y < maxOffsetY * -1 && (y = Math.max(y, maxOffsetY * -1));
590
+
591
+ this.x += x * zoomGrowth;
592
+ this.y += y * zoomGrowth;
593
+ }
594
+
595
+ // Center container within wrapper
596
+ center(instant, ignorePosition) {
597
+ return this.panTo(50, 50, instant, ignorePosition);
598
+ }
599
+
600
+ // Getters for pan
601
+ getPan(pixelValues) {
602
+ return {
603
+ x: this.getPanX(pixelValues),
604
+ y: this.getPanY(pixelValues)
605
+ };
606
+ }
607
+
608
+ getPanX(pixelValues) {
609
+ const wrapper = this.getWrapper();
610
+ const container = this.getContainer();
611
+ let panX = wrapper.clientWidth * 0.5 + this.x * -1;
612
+ panX += (this.zoom - 1) * (container.clientWidth * 0.5);
613
+ const percentX = (panX / (container.clientWidth * this.zoom)) * 100;
614
+ return pixelValues ? panX : percentX;
615
+ }
616
+
617
+ getPanY(pixelValues) {
618
+ const wrapper = this.getWrapper();
619
+ const container = this.getContainer();
620
+ let panY = wrapper.clientHeight * 0.5 + this.y * -1;
621
+ panY += (this.zoom - 1) * (container.clientHeight * 0.5);
622
+ const percentY = (panY / (container.clientHeight * this.zoom)) * 100;
623
+ return pixelValues ? panY : percentY;
624
+ }
625
+
626
+ // Pan to position
627
+ panTo(x, y, instant, ignorePosition) {
628
+ const wrapper = this.getWrapper();
629
+ const container = this.getContainer();
630
+
631
+ let panX = ((container.clientWidth * this.zoom * x) / 100) * -1;
632
+ panX += (this.zoom - 1) * (container.clientWidth * 0.5);
633
+ panX += wrapper.clientWidth * 0.5;
634
+
635
+ let panY = ((container.clientHeight * this.zoom * y) / 100) * -1;
636
+ panY += (this.zoom - 1) * (container.clientHeight * 0.5);
637
+ panY += wrapper.clientHeight * 0.5;
638
+
639
+ this.x = panX;
640
+ this.y = panY;
641
+
642
+ // Update position
643
+ if (!ignorePosition) {
644
+ this.setPosition(instant);
645
+ }
646
+
647
+ // Trigger event
648
+ this.fireEvent('onPan', this.getPosition());
649
+
650
+ // Return instance
651
+ return this;
652
+ }
653
+
654
+ panLeft(step, instant) {
655
+ return this.pan(step, instant, 'left');
656
+ }
657
+
658
+ panRight(step, instant) {
659
+ return this.pan(step, instant, 'right');
660
+ }
661
+
662
+ panUp(step, instant) {
663
+ return this.pan(step, instant, 'up');
664
+ }
665
+
666
+ panDown(step, instant) {
667
+ return this.pan(step, instant, 'down');
668
+ }
669
+
670
+ pan(step, instant, direction) {
671
+ if (step === true || step === false) {
672
+ instant = step;
673
+ step = null;
674
+ }
675
+ step = step || this.options.panStep;
676
+
677
+ const container = this.getContainer();
678
+ const panWidth = ((container.clientWidth * step) / 100) * this.zoom;
679
+ const panHeight = ((container.clientWidth * step) / 100) * this.zoom;
680
+
681
+ direction === 'left' && (this.x += panWidth * -1);
682
+ direction === 'right' && (this.x += panWidth);
683
+ direction === 'up' && (this.y += panHeight * -1);
684
+ direction === 'down' && (this.y += panHeight);
685
+
686
+ // Update position
687
+ this.setPosition(instant);
688
+
689
+ // Trigger event
690
+ this.fireEvent('onPan', this.getPosition());
691
+
692
+ // Return instance
693
+ return this;
694
+ }
695
+
696
+ // Get the wrapper element
697
+ getWrapper() {
698
+ // Return element if it is cached
699
+ if (this.wrapperElement) {
700
+ return this.wrapperElement;
701
+ }
702
+
703
+ // Abort if option is empty
704
+ if (!this.options.wrapperElement) {
705
+ console.error('The option wrapperElement is required.');
706
+ return null;
707
+ }
708
+
709
+ // Find the element if selector provided
710
+ if (typeof this.options.wrapperElement === 'string') {
711
+ this.options.wrapperElement = document.querySelector(
712
+ this.options.wrapperElement
713
+ );
714
+ }
715
+
716
+ // Cache element if valid
717
+ if (
718
+ this.options.wrapperElement &&
719
+ this.options.wrapperElement instanceof Element
720
+ ) {
721
+ this.wrapperElement = this.options.wrapperElement;
722
+ return this.options.wrapperElement;
723
+ }
724
+
725
+ console.error(
726
+ 'The option wrapperElement needs to be a valid selector string or an instance of Element.'
727
+ );
728
+ return null;
729
+ }
730
+
731
+ // Get the container element
732
+ getContainer() {
733
+ // Return element if it is cached
734
+ if (this.containerElement) {
735
+ return this.containerElement;
736
+ }
737
+
738
+ // Abort if option is empty
739
+ if (!this.options.panZoomElement) {
740
+ console.error('The option panZoomElement is required.');
741
+ return null;
742
+ }
743
+
744
+ // Find the element if selector provided
745
+ if (typeof this.options.panZoomElement === 'string') {
746
+ this.options.panZoomElement = document.querySelector(
747
+ this.options.panZoomElement
748
+ );
749
+ }
750
+
751
+ // Cache element if valid
752
+ if (
753
+ this.options.panZoomElement &&
754
+ this.options.panZoomElement instanceof Element
755
+ ) {
756
+ this.containerElement = this.options.panZoomElement;
757
+ return this.options.panZoomElement;
758
+ }
759
+
760
+ console.error(
761
+ 'The option panZoomElement needs to be a valid selector string or an instance of Element.'
762
+ );
763
+ return null;
764
+ }
765
+
766
+ // Enable or disable transitions
767
+ transition(enabled) {
768
+ this.getContainer().style.transition = enabled
769
+ ? 'transform ' + this.options.transitionSpeed + 'ms'
770
+ : null;
771
+ }
772
+ }
773
+
774
+ return domPanZoom;
775
+
776
+ }));
777
+ //# sourceMappingURL=dom-pan-zoom.umd.js.map