| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.panzoom = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ | 
					
						
							|  |  |  |  | 'use strict'; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* globals SVGElement */ | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * Allows to drag and zoom svg elements | 
					
						
							|  |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | var wheel = require('wheel'); | 
					
						
							|  |  |  |  | var animate = require('amator'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var eventify = require('ngraph.events'); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | var kinetic = require('./lib/kinetic.js'); | 
					
						
							|  |  |  |  | var createTextSelectionInterceptor = require('./lib/createTextSelectionInterceptor.js'); | 
					
						
							|  |  |  |  | var domTextSelectionInterceptor = createTextSelectionInterceptor(); | 
					
						
							|  |  |  |  | var fakeTextSelectorInterceptor = createTextSelectionInterceptor(true); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var Transform = require('./lib/transform.js'); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | var makeSvgController = require('./lib/svgController.js'); | 
					
						
							|  |  |  |  | var makeDomController = require('./lib/domController.js'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | var defaultZoomSpeed = 1; | 
					
						
							|  |  |  |  | var defaultDoubleTapZoomSpeed = 1.75; | 
					
						
							|  |  |  |  | var doubleTapSpeedInMS = 300; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | module.exports = createPanZoom; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * Creates a new instance of panzoom, so that an object can be panned and zoomed | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * @param {DOMElement} domElement where panzoom should be attached. | 
					
						
							|  |  |  |  |  * @param {Object} options that configure behavior. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | function createPanZoom(domElement, options) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   options = options || {}; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var panController = options.controller; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (!panController) { | 
					
						
							|  |  |  |  |     if (domElement instanceof SVGElement) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       panController = makeSvgController(domElement, options); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (domElement instanceof HTMLElement) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       panController = makeDomController(domElement, options); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (!panController) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     throw new Error( | 
					
						
							|  |  |  |  |       'Cannot create panzoom for the current type of dom element' | 
					
						
							|  |  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var owner = panController.getOwner(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   // just to avoid GC pressure, every time we do intermediate transform
 | 
					
						
							|  |  |  |  |   // we return this object. For internal use only. Never give it back to the consumer of this library
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var storedCTMResult = { x: 0, y: 0 }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var isDirty = false; | 
					
						
							|  |  |  |  |   var transform = new Transform(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (panController.initTransform) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     panController.initTransform(transform); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var filterKey = typeof options.filterKey === 'function' ? options.filterKey : noop; | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |   // TODO: likely need to unite pinchSpeed with zoomSpeed
 | 
					
						
							|  |  |  |  |   var pinchSpeed = typeof options.pinchSpeed === 'number' ? options.pinchSpeed : 1; | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var bounds = options.bounds; | 
					
						
							|  |  |  |  |   var maxZoom = typeof options.maxZoom === 'number' ? options.maxZoom : Number.POSITIVE_INFINITY; | 
					
						
							|  |  |  |  |   var minZoom = typeof options.minZoom === 'number' ? options.minZoom : 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var boundsPadding = typeof options.boundsPadding === 'number' ? options.boundsPadding : 0.05; | 
					
						
							|  |  |  |  |   var zoomDoubleClickSpeed = typeof options.zoomDoubleClickSpeed === 'number' ? options.zoomDoubleClickSpeed : defaultDoubleTapZoomSpeed; | 
					
						
							|  |  |  |  |   var beforeWheel = options.beforeWheel || noop; | 
					
						
							|  |  |  |  |   var beforeMouseDown = options.beforeMouseDown || noop; | 
					
						
							|  |  |  |  |   var speed = typeof options.zoomSpeed === 'number' ? options.zoomSpeed : defaultZoomSpeed; | 
					
						
							|  |  |  |  |   var transformOrigin = parseTransformOrigin(options.transformOrigin); | 
					
						
							|  |  |  |  |   var textSelection = options.enableTextSelection ? fakeTextSelectorInterceptor : domTextSelectionInterceptor; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   validateBounds(bounds); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (options.autocenter) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     autocenter(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var frameAnimation; | 
					
						
							|  |  |  |  |   var lastTouchEndTime = 0; | 
					
						
							|  |  |  |  |   var lastSingleFingerOffset; | 
					
						
							|  |  |  |  |   var touchInProgress = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   // We only need to fire panstart when actual move happens
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var panstartFired = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   // cache mouse coordinates here
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var mouseX; | 
					
						
							|  |  |  |  |   var mouseY; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var pinchZoomLength; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var smoothScroll; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   if ('smoothScroll' in options && !options.smoothScroll) { | 
					
						
							|  |  |  |  |     // If user explicitly asked us not to use smooth scrolling, we obey
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll = rigidScroll(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } else { | 
					
						
							|  |  |  |  |     // otherwise we use forward smoothScroll settings to kinetic API
 | 
					
						
							|  |  |  |  |     // which makes scroll smoothing.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll = kinetic(getPoint, scroll, options.smoothScroll); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var moveByAnimation; | 
					
						
							|  |  |  |  |   var zoomToAnimation; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var multiTouch; | 
					
						
							|  |  |  |  |   var paused = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   listenForEvents(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   var api = { | 
					
						
							|  |  |  |  |     dispose: dispose, | 
					
						
							|  |  |  |  |     moveBy: internalMoveBy, | 
					
						
							|  |  |  |  |     moveTo: moveTo, | 
					
						
							|  |  |  |  |     centerOn: centerOn, | 
					
						
							|  |  |  |  |     zoomTo: publicZoomTo, | 
					
						
							|  |  |  |  |     zoomAbs: zoomAbs, | 
					
						
							|  |  |  |  |     smoothZoom: smoothZoom, | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothZoomAbs: smoothZoomAbs, | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     showRectangle: showRectangle, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     pause: pause, | 
					
						
							|  |  |  |  |     resume: resume, | 
					
						
							|  |  |  |  |     isPaused: isPaused, | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     getTransform: getTransformModel, | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     getMinZoom: getMinZoom, | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     setMinZoom: setMinZoom, | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     getMaxZoom: getMaxZoom, | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     setMaxZoom: setMaxZoom, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     getTransformOrigin: getTransformOrigin, | 
					
						
							|  |  |  |  |     setTransformOrigin: setTransformOrigin, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     getZoomSpeed: getZoomSpeed, | 
					
						
							|  |  |  |  |     setZoomSpeed: setZoomSpeed, | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     getOwner: () => owner | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   eventify(api); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return api; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function pause() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     releaseEvents(); | 
					
						
							|  |  |  |  |     paused = true; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function resume() { | 
					
						
							|  |  |  |  |     if (paused) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       listenForEvents(); | 
					
						
							|  |  |  |  |       paused = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function isPaused() { | 
					
						
							|  |  |  |  |     return paused; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function showRectangle(rect) { | 
					
						
							|  |  |  |  |     // TODO: this duplicates autocenter. I think autocenter should go.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var clientRect = owner.getBoundingClientRect(); | 
					
						
							|  |  |  |  |     var size = transformToScreen(clientRect.width, clientRect.height); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var rectWidth = rect.right - rect.left; | 
					
						
							|  |  |  |  |     var rectHeight = rect.bottom - rect.top; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (!Number.isFinite(rectWidth) || !Number.isFinite(rectHeight)) { | 
					
						
							|  |  |  |  |       throw new Error('Invalid rectangle'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var dw = size.x / rectWidth; | 
					
						
							|  |  |  |  |     var dh = size.y / rectHeight; | 
					
						
							|  |  |  |  |     var scale = Math.min(dw, dh); | 
					
						
							|  |  |  |  |     transform.x = -(rect.left + rectWidth / 2) * scale + size.x / 2; | 
					
						
							|  |  |  |  |     transform.y = -(rect.top + rectHeight / 2) * scale + size.y / 2; | 
					
						
							|  |  |  |  |     transform.scale = scale; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function transformToScreen(x, y) { | 
					
						
							|  |  |  |  |     if (panController.getScreenCTM) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var parentCTM = panController.getScreenCTM(); | 
					
						
							|  |  |  |  |       var parentScaleX = parentCTM.a; | 
					
						
							|  |  |  |  |       var parentScaleY = parentCTM.d; | 
					
						
							|  |  |  |  |       var parentOffsetX = parentCTM.e; | 
					
						
							|  |  |  |  |       var parentOffsetY = parentCTM.f; | 
					
						
							|  |  |  |  |       storedCTMResult.x = x * parentScaleX - parentOffsetX; | 
					
						
							|  |  |  |  |       storedCTMResult.y = y * parentScaleY - parentOffsetY; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       storedCTMResult.x = x; | 
					
						
							|  |  |  |  |       storedCTMResult.y = y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return storedCTMResult; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function autocenter() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var w; // width of the parent
 | 
					
						
							|  |  |  |  |     var h; // height of the parent
 | 
					
						
							|  |  |  |  |     var left = 0; | 
					
						
							|  |  |  |  |     var top = 0; | 
					
						
							|  |  |  |  |     var sceneBoundingBox = getBoundingBox(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (sceneBoundingBox) { | 
					
						
							|  |  |  |  |       // If we have bounding box - use it.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       left = sceneBoundingBox.left; | 
					
						
							|  |  |  |  |       top = sceneBoundingBox.top; | 
					
						
							|  |  |  |  |       w = sceneBoundingBox.right - sceneBoundingBox.left; | 
					
						
							|  |  |  |  |       h = sceneBoundingBox.bottom - sceneBoundingBox.top; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else { | 
					
						
							|  |  |  |  |       // otherwise just use whatever space we have
 | 
					
						
							|  |  |  |  |       var ownerRect = owner.getBoundingClientRect(); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       w = ownerRect.width; | 
					
						
							|  |  |  |  |       h = ownerRect.height; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var bbox = panController.getBBox(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (bbox.width === 0 || bbox.height === 0) { | 
					
						
							|  |  |  |  |       // we probably do not have any elements in the SVG
 | 
					
						
							|  |  |  |  |       // just bail out;
 | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var dh = h / bbox.height; | 
					
						
							|  |  |  |  |     var dw = w / bbox.width; | 
					
						
							|  |  |  |  |     var scale = Math.min(dw, dh); | 
					
						
							|  |  |  |  |     transform.x = -(bbox.left + bbox.width / 2) * scale + w / 2 + left; | 
					
						
							|  |  |  |  |     transform.y = -(bbox.top + bbox.height / 2) * scale + h / 2 + top; | 
					
						
							|  |  |  |  |     transform.scale = scale; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getTransformModel() { | 
					
						
							|  |  |  |  |     // TODO: should this be read only?
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return transform; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |   function getMinZoom() { | 
					
						
							|  |  |  |  |     return minZoom; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   function setMinZoom(newMinZoom) { | 
					
						
							|  |  |  |  |     minZoom = newMinZoom; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |   function getMaxZoom() { | 
					
						
							|  |  |  |  |     return maxZoom; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   function setMaxZoom(newMaxZoom) { | 
					
						
							|  |  |  |  |     maxZoom = newMaxZoom; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getTransformOrigin() { | 
					
						
							|  |  |  |  |     return transformOrigin; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function setTransformOrigin(newTransformOrigin) { | 
					
						
							|  |  |  |  |     transformOrigin = parseTransformOrigin(newTransformOrigin); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getZoomSpeed() { | 
					
						
							|  |  |  |  |     return speed; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function setZoomSpeed(newSpeed) { | 
					
						
							|  |  |  |  |     if (!Number.isFinite(newSpeed)) { | 
					
						
							|  |  |  |  |       throw new Error('Zoom speed should be a number'); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     speed = newSpeed; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   function getPoint() { | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       x: transform.x, | 
					
						
							|  |  |  |  |       y: transform.y | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function moveTo(x, y) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     transform.x = x; | 
					
						
							|  |  |  |  |     transform.y = y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     keepTransformInsideBounds(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     triggerEvent('pan'); | 
					
						
							|  |  |  |  |     makeDirty(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function moveBy(dx, dy) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     moveTo(transform.x + dx, transform.y + dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function keepTransformInsideBounds() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var boundingBox = getBoundingBox(); | 
					
						
							|  |  |  |  |     if (!boundingBox) return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var adjusted = false; | 
					
						
							|  |  |  |  |     var clientRect = getClientRect(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var diff = boundingBox.left - clientRect.right; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (diff > 0) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       transform.x += diff; | 
					
						
							|  |  |  |  |       adjusted = true; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     // check the other side:
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     diff = boundingBox.right - clientRect.left; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (diff < 0) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       transform.x += diff; | 
					
						
							|  |  |  |  |       adjusted = true; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // y axis:
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     diff = boundingBox.top - clientRect.bottom; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (diff > 0) { | 
					
						
							|  |  |  |  |       // we adjust transform, so that it matches exactly our bounding box:
 | 
					
						
							|  |  |  |  |       // transform.y = boundingBox.top - (boundingBox.height + boundingBox.y) * transform.scale =>
 | 
					
						
							|  |  |  |  |       // transform.y = boundingBox.top - (clientRect.bottom - transform.y) =>
 | 
					
						
							|  |  |  |  |       // transform.y = diff + transform.y =>
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       transform.y += diff; | 
					
						
							|  |  |  |  |       adjusted = true; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     diff = boundingBox.bottom - clientRect.top; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (diff < 0) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       transform.y += diff; | 
					
						
							|  |  |  |  |       adjusted = true; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return adjusted; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /** | 
					
						
							|  |  |  |  |    * Returns bounding box that should be used to restrict scene movement. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   function getBoundingBox() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (!bounds) return; // client does not want to restrict movement
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (typeof bounds === 'boolean') { | 
					
						
							|  |  |  |  |       // for boolean type we use parent container bounds
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var ownerRect = owner.getBoundingClientRect(); | 
					
						
							|  |  |  |  |       var sceneWidth = ownerRect.width; | 
					
						
							|  |  |  |  |       var sceneHeight = ownerRect.height; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       return { | 
					
						
							|  |  |  |  |         left: sceneWidth * boundsPadding, | 
					
						
							|  |  |  |  |         top: sceneHeight * boundsPadding, | 
					
						
							|  |  |  |  |         right: sceneWidth * (1 - boundsPadding), | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |         bottom: sceneHeight * (1 - boundsPadding) | 
					
						
							|  |  |  |  |       }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return bounds; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getClientRect() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var bbox = panController.getBBox(); | 
					
						
							|  |  |  |  |     var leftTop = client(bbox.left, bbox.top); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       left: leftTop.x, | 
					
						
							|  |  |  |  |       top: leftTop.y, | 
					
						
							|  |  |  |  |       right: bbox.width * transform.scale + leftTop.x, | 
					
						
							|  |  |  |  |       bottom: bbox.height * transform.scale + leftTop.y | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function client(x, y) { | 
					
						
							|  |  |  |  |     return { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       x: x * transform.scale + transform.x, | 
					
						
							|  |  |  |  |       y: y * transform.scale + transform.y | 
					
						
							|  |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function makeDirty() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     isDirty = true; | 
					
						
							|  |  |  |  |     frameAnimation = window.requestAnimationFrame(frame); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function zoomByRatio(clientX, clientY, ratio) { | 
					
						
							|  |  |  |  |     if (isNaN(clientX) || isNaN(clientY) || isNaN(ratio)) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       throw new Error('zoom requires valid numbers'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var newScale = transform.scale * ratio; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (newScale < minZoom) { | 
					
						
							|  |  |  |  |       if (transform.scale === minZoom) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       ratio = minZoom / transform.scale; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     if (newScale > maxZoom) { | 
					
						
							|  |  |  |  |       if (transform.scale === maxZoom) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       ratio = maxZoom / transform.scale; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var size = transformToScreen(clientX, clientY); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     transform.x = size.x - ratio * (size.x - transform.x); | 
					
						
							|  |  |  |  |     transform.y = size.y - ratio * (size.y - transform.y); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     // TODO: https://github.com/anvaka/panzoom/issues/112
 | 
					
						
							|  |  |  |  |     if (bounds && boundsPadding === 1 && minZoom === 1) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       transform.scale *= ratio; | 
					
						
							|  |  |  |  |       keepTransformInsideBounds(); | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var transformAdjusted = keepTransformInsideBounds(); | 
					
						
							|  |  |  |  |       if (!transformAdjusted) transform.scale *= ratio; | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     triggerEvent('zoom'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     makeDirty(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function zoomAbs(clientX, clientY, zoomLevel) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var ratio = zoomLevel / transform.scale; | 
					
						
							|  |  |  |  |     zoomByRatio(clientX, clientY, ratio); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function centerOn(ui) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var parent = ui.ownerSVGElement; | 
					
						
							|  |  |  |  |     if (!parent) | 
					
						
							|  |  |  |  |       throw new Error('ui element is required to be within the scene'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // TODO: should i use controller's screen CTM?
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var clientRect = ui.getBoundingClientRect(); | 
					
						
							|  |  |  |  |     var cx = clientRect.left + clientRect.width / 2; | 
					
						
							|  |  |  |  |     var cy = clientRect.top + clientRect.height / 2; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var container = parent.getBoundingClientRect(); | 
					
						
							|  |  |  |  |     var dx = container.width / 2 - cx; | 
					
						
							|  |  |  |  |     var dy = container.height / 2 - cy; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     internalMoveBy(dx, dy, true); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function internalMoveBy(dx, dy, smooth) { | 
					
						
							|  |  |  |  |     if (!smooth) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       return moveBy(dx, dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (moveByAnimation) moveByAnimation.cancel(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var from = { x: 0, y: 0 }; | 
					
						
							|  |  |  |  |     var to = { x: dx, y: dy }; | 
					
						
							|  |  |  |  |     var lastX = 0; | 
					
						
							|  |  |  |  |     var lastY = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     moveByAnimation = animate(from, to, { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       step: function (v) { | 
					
						
							|  |  |  |  |         moveBy(v.x - lastX, v.y - lastY); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |         lastX = v.x; | 
					
						
							|  |  |  |  |         lastY = v.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function scroll(x, y) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     cancelZoomAnimation(); | 
					
						
							|  |  |  |  |     moveTo(x, y); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function dispose() { | 
					
						
							|  |  |  |  |     releaseEvents(); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function listenForEvents() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     owner.addEventListener('mousedown', onMouseDown, { passive: false }); | 
					
						
							|  |  |  |  |     owner.addEventListener('dblclick', onDoubleClick, { passive: false }); | 
					
						
							|  |  |  |  |     owner.addEventListener('touchstart', onTouch, { passive: false }); | 
					
						
							|  |  |  |  |     owner.addEventListener('keydown', onKeyDown, { passive: false }); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Need to listen on the owner container, so that we are not limited
 | 
					
						
							|  |  |  |  |     // by the size of the scrollable domElement
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     wheel.addWheelListener(owner, onMouseWheel, { passive: false }); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     makeDirty(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function releaseEvents() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     wheel.removeWheelListener(owner, onMouseWheel); | 
					
						
							|  |  |  |  |     owner.removeEventListener('mousedown', onMouseDown); | 
					
						
							|  |  |  |  |     owner.removeEventListener('keydown', onKeyDown); | 
					
						
							|  |  |  |  |     owner.removeEventListener('dblclick', onDoubleClick); | 
					
						
							|  |  |  |  |     owner.removeEventListener('touchstart', onTouch); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (frameAnimation) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       window.cancelAnimationFrame(frameAnimation); | 
					
						
							|  |  |  |  |       frameAnimation = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll.cancel(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     releaseDocumentMouse(); | 
					
						
							|  |  |  |  |     releaseTouches(); | 
					
						
							|  |  |  |  |     textSelection.release(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     triggerPanEnd(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function frame() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (isDirty) applyTransform(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function applyTransform() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     isDirty = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // TODO: Should I allow to cancel this?
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     panController.applyTransform(transform); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     triggerEvent('transform'); | 
					
						
							|  |  |  |  |     frameAnimation = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onKeyDown(e) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var x = 0, | 
					
						
							|  |  |  |  |       y = 0, | 
					
						
							|  |  |  |  |       z = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (e.keyCode === 38) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       y = 1; // up
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else if (e.keyCode === 40) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       y = -1; // down
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else if (e.keyCode === 37) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       x = 1; // left
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else if (e.keyCode === 39) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       x = -1; // right
 | 
					
						
							|  |  |  |  |     } else if (e.keyCode === 189 || e.keyCode === 109) { | 
					
						
							|  |  |  |  |       // DASH or SUBTRACT
 | 
					
						
							|  |  |  |  |       z = 1; // `-` -  zoom out
 | 
					
						
							|  |  |  |  |     } else if (e.keyCode === 187 || e.keyCode === 107) { | 
					
						
							|  |  |  |  |       // EQUAL SIGN or ADD
 | 
					
						
							|  |  |  |  |       z = -1; // `=` - zoom in (equal sign on US layout is under `+`)
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (filterKey(e, x, y, z)) { | 
					
						
							|  |  |  |  |       // They don't want us to handle the key: https://github.com/anvaka/panzoom/issues/45
 | 
					
						
							|  |  |  |  |       return; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (x || y) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       e.preventDefault(); | 
					
						
							|  |  |  |  |       e.stopPropagation(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var clientRect = owner.getBoundingClientRect(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       // movement speed should be the same in both X and Y direction:
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var offset = Math.min(clientRect.width, clientRect.height); | 
					
						
							|  |  |  |  |       var moveSpeedRatio = 0.05; | 
					
						
							|  |  |  |  |       var dx = offset * moveSpeedRatio * x; | 
					
						
							|  |  |  |  |       var dy = offset * moveSpeedRatio * y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       // TODO: currently we do not animate this. It could be better to have animation
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       internalMoveBy(dx, dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (z) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var scaleMultiplier = getScaleMultiplier(z * 100); | 
					
						
							|  |  |  |  |       var offset = transformOrigin ? getTransformOriginOffset() : midPoint(); | 
					
						
							|  |  |  |  |       publicZoomTo(offset.x, offset.y, scaleMultiplier); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   function midPoint() { | 
					
						
							|  |  |  |  |     var ownerRect = owner.getBoundingClientRect(); | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       x: ownerRect.width / 2, | 
					
						
							|  |  |  |  |       y: ownerRect.height / 2 | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   function onTouch(e) { | 
					
						
							|  |  |  |  |     // let the override the touch behavior
 | 
					
						
							|  |  |  |  |     beforeTouch(e); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (e.touches.length === 1) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       return handleSingleFingerTouch(e, e.touches[0]); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else if (e.touches.length === 2) { | 
					
						
							|  |  |  |  |       // handleTouchMove() will care about pinch zoom.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       pinchZoomLength = getPinchZoomLength(e.touches[0], e.touches[1]); | 
					
						
							|  |  |  |  |       multiTouch = true; | 
					
						
							|  |  |  |  |       startTouchListenerIfNeeded(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function beforeTouch(e) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     // TODO: Need to unify this filtering names. E.g. use `beforeTouch`
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (options.onTouch && !options.onTouch(e)) { | 
					
						
							|  |  |  |  |       // if they return `false` from onTouch, we don't want to stop
 | 
					
						
							|  |  |  |  |       // events propagation. Fixes https://github.com/anvaka/panzoom/issues/12
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     e.stopPropagation(); | 
					
						
							|  |  |  |  |     e.preventDefault(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function beforeDoubleClick(e) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     // TODO: Need to unify this filtering names. E.g. use `beforeDoubleClick``
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (options.onDoubleClick && !options.onDoubleClick(e)) { | 
					
						
							|  |  |  |  |       // if they return `false` from onTouch, we don't want to stop
 | 
					
						
							|  |  |  |  |       // events propagation. Fixes https://github.com/anvaka/panzoom/issues/46
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     e.preventDefault(); | 
					
						
							|  |  |  |  |     e.stopPropagation(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function handleSingleFingerTouch(e) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var touch = e.touches[0]; | 
					
						
							|  |  |  |  |     var offset = getOffsetXY(touch); | 
					
						
							|  |  |  |  |     lastSingleFingerOffset = offset; | 
					
						
							|  |  |  |  |     var point = transformToScreen(offset.x, offset.y); | 
					
						
							|  |  |  |  |     mouseX = point.x; | 
					
						
							|  |  |  |  |     mouseY = point.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll.cancel(); | 
					
						
							|  |  |  |  |     startTouchListenerIfNeeded(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function startTouchListenerIfNeeded() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (touchInProgress) { | 
					
						
							|  |  |  |  |       // no need to do anything, as we already listen to events;
 | 
					
						
							|  |  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     touchInProgress = true; | 
					
						
							|  |  |  |  |     document.addEventListener('touchmove', handleTouchMove); | 
					
						
							|  |  |  |  |     document.addEventListener('touchend', handleTouchEnd); | 
					
						
							|  |  |  |  |     document.addEventListener('touchcancel', handleTouchEnd); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function handleTouchMove(e) { | 
					
						
							|  |  |  |  |     if (e.touches.length === 1) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       e.stopPropagation(); | 
					
						
							|  |  |  |  |       var touch = e.touches[0]; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var offset = getOffsetXY(touch); | 
					
						
							|  |  |  |  |       var point = transformToScreen(offset.x, offset.y); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var dx = point.x - mouseX; | 
					
						
							|  |  |  |  |       var dy = point.y - mouseY; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (dx !== 0 && dy !== 0) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |         triggerPanStart(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       mouseX = point.x; | 
					
						
							|  |  |  |  |       mouseY = point.y; | 
					
						
							|  |  |  |  |       internalMoveBy(dx, dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else if (e.touches.length === 2) { | 
					
						
							|  |  |  |  |       // it's a zoom, let's find direction
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       multiTouch = true; | 
					
						
							|  |  |  |  |       var t1 = e.touches[0]; | 
					
						
							|  |  |  |  |       var t2 = e.touches[1]; | 
					
						
							|  |  |  |  |       var currentPinchLength = getPinchZoomLength(t1, t2); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |       // since the zoom speed is always based on distance from 1, we need to apply
 | 
					
						
							|  |  |  |  |       // pinch speed only on that distance from 1:
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var scaleMultiplier = | 
					
						
							|  |  |  |  |         1 + (currentPinchLength / pinchZoomLength - 1) * pinchSpeed; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       var firstTouchPoint = getOffsetXY(t1); | 
					
						
							|  |  |  |  |       var secondTouchPoint = getOffsetXY(t2); | 
					
						
							|  |  |  |  |       mouseX = (firstTouchPoint.x + secondTouchPoint.x) / 2; | 
					
						
							|  |  |  |  |       mouseY = (firstTouchPoint.y + secondTouchPoint.y) / 2; | 
					
						
							|  |  |  |  |       if (transformOrigin) { | 
					
						
							|  |  |  |  |         var offset = getTransformOriginOffset(); | 
					
						
							|  |  |  |  |         mouseX = offset.x; | 
					
						
							|  |  |  |  |         mouseY = offset.y; | 
					
						
							|  |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       publicZoomTo(mouseX, mouseY, scaleMultiplier); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       pinchZoomLength = currentPinchLength; | 
					
						
							|  |  |  |  |       e.stopPropagation(); | 
					
						
							|  |  |  |  |       e.preventDefault(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function handleTouchEnd(e) { | 
					
						
							|  |  |  |  |     if (e.touches.length > 0) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var offset = getOffsetXY(e.touches[0]); | 
					
						
							|  |  |  |  |       var point = transformToScreen(offset.x, offset.y); | 
					
						
							|  |  |  |  |       mouseX = point.x; | 
					
						
							|  |  |  |  |       mouseY = point.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var now = new Date(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       if (now - lastTouchEndTime < doubleTapSpeedInMS) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |         if (transformOrigin) { | 
					
						
							|  |  |  |  |           var offset = getTransformOriginOffset(); | 
					
						
							|  |  |  |  |           smoothZoom(offset.x, offset.y, zoomDoubleClickSpeed); | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |           smoothZoom(lastSingleFingerOffset.x, lastSingleFingerOffset.y, zoomDoubleClickSpeed); | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       lastTouchEndTime = now; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       touchInProgress = false; | 
					
						
							|  |  |  |  |       triggerPanEnd(); | 
					
						
							|  |  |  |  |       releaseTouches(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getPinchZoomLength(finger1, finger2) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var dx = finger1.clientX - finger2.clientX; | 
					
						
							|  |  |  |  |     var dy = finger1.clientY - finger2.clientY; | 
					
						
							|  |  |  |  |     return Math.sqrt(dx * dx + dy * dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onDoubleClick(e) { | 
					
						
							|  |  |  |  |     beforeDoubleClick(e); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var offset = getOffsetXY(e); | 
					
						
							|  |  |  |  |     if (transformOrigin) { | 
					
						
							|  |  |  |  |       // TODO: looks like this is duplicated in the file.
 | 
					
						
							|  |  |  |  |       // Need to refactor
 | 
					
						
							|  |  |  |  |       offset = getTransformOriginOffset(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     smoothZoom(offset.x, offset.y, zoomDoubleClickSpeed); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onMouseDown(e) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     // if client does not want to handle this event - just ignore the call
 | 
					
						
							|  |  |  |  |     if (beforeMouseDown(e)) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (touchInProgress) { | 
					
						
							|  |  |  |  |       // modern browsers will fire mousedown for touch events too
 | 
					
						
							|  |  |  |  |       // we do not want this: touch is handled separately.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       e.stopPropagation(); | 
					
						
							|  |  |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |     // for IE, left click == 1
 | 
					
						
							|  |  |  |  |     // for Firefox, left click == 0
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var isLeftButton = | 
					
						
							|  |  |  |  |       (e.button === 1 && window.event !== null) || e.button === 0; | 
					
						
							|  |  |  |  |     if (!isLeftButton) return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll.cancel(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     var offset = getOffsetXY(e); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var point = transformToScreen(offset.x, offset.y); | 
					
						
							|  |  |  |  |     mouseX = point.x; | 
					
						
							|  |  |  |  |     mouseY = point.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // We need to listen on document itself, since mouse can go outside of the
 | 
					
						
							|  |  |  |  |     // window, and we will loose it
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     document.addEventListener('mousemove', onMouseMove); | 
					
						
							|  |  |  |  |     document.addEventListener('mouseup', onMouseUp); | 
					
						
							|  |  |  |  |     textSelection.capture(e.target || e.srcElement); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onMouseMove(e) { | 
					
						
							|  |  |  |  |     // no need to worry about mouse events when touch is happening
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (touchInProgress) return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     triggerPanStart(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     var offset = getOffsetXY(e); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var point = transformToScreen(offset.x, offset.y); | 
					
						
							|  |  |  |  |     var dx = point.x - mouseX; | 
					
						
							|  |  |  |  |     var dy = point.y - mouseY; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     mouseX = point.x; | 
					
						
							|  |  |  |  |     mouseY = point.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     internalMoveBy(dx, dy); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onMouseUp() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     textSelection.release(); | 
					
						
							|  |  |  |  |     triggerPanEnd(); | 
					
						
							|  |  |  |  |     releaseDocumentMouse(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function releaseDocumentMouse() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     document.removeEventListener('mousemove', onMouseMove); | 
					
						
							|  |  |  |  |     document.removeEventListener('mouseup', onMouseUp); | 
					
						
							|  |  |  |  |     panstartFired = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function releaseTouches() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     document.removeEventListener('touchmove', handleTouchMove); | 
					
						
							|  |  |  |  |     document.removeEventListener('touchend', handleTouchEnd); | 
					
						
							|  |  |  |  |     document.removeEventListener('touchcancel', handleTouchEnd); | 
					
						
							|  |  |  |  |     panstartFired = false; | 
					
						
							|  |  |  |  |     multiTouch = false; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function onMouseWheel(e) { | 
					
						
							|  |  |  |  |     // if client does not want to handle this event - just ignore the call
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (beforeWheel(e)) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     smoothScroll.cancel(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var delta = e.deltaY; | 
					
						
							|  |  |  |  |     if (e.deltaMode > 0) delta *= 100; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var scaleMultiplier = getScaleMultiplier(delta); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (scaleMultiplier !== 1) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var offset = transformOrigin | 
					
						
							|  |  |  |  |         ? getTransformOriginOffset() | 
					
						
							|  |  |  |  |         : getOffsetXY(e); | 
					
						
							|  |  |  |  |       publicZoomTo(offset.x, offset.y, scaleMultiplier); | 
					
						
							|  |  |  |  |       e.preventDefault(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getOffsetXY(e) { | 
					
						
							|  |  |  |  |     var offsetX, offsetY; | 
					
						
							|  |  |  |  |     // I tried using e.offsetX, but that gives wrong results for svg, when user clicks on a path.
 | 
					
						
							|  |  |  |  |     var ownerRect = owner.getBoundingClientRect(); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     offsetX = e.clientX - ownerRect.left; | 
					
						
							|  |  |  |  |     offsetY = e.clientY - ownerRect.top; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return { x: offsetX, y: offsetY }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function smoothZoom(clientX, clientY, scaleMultiplier) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var fromValue = transform.scale; | 
					
						
							|  |  |  |  |     var from = { scale: fromValue }; | 
					
						
							|  |  |  |  |     var to = { scale: scaleMultiplier * fromValue }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll.cancel(); | 
					
						
							|  |  |  |  |     cancelZoomAnimation(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     zoomToAnimation = animate(from, to, { | 
					
						
							|  |  |  |  |       step: function (v) { | 
					
						
							|  |  |  |  |         zoomAbs(clientX, clientY, v.scale); | 
					
						
							|  |  |  |  |       }, | 
					
						
							|  |  |  |  |       done: triggerZoomEnd | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function smoothZoomAbs(clientX, clientY, toScaleValue) { | 
					
						
							|  |  |  |  |     var fromValue = transform.scale; | 
					
						
							|  |  |  |  |     var from = { scale: fromValue }; | 
					
						
							|  |  |  |  |     var to = { scale: toScaleValue }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     smoothScroll.cancel(); | 
					
						
							|  |  |  |  |     cancelZoomAnimation(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     zoomToAnimation = animate(from, to, { | 
					
						
							|  |  |  |  |       step: function (v) { | 
					
						
							|  |  |  |  |         zoomAbs(clientX, clientY, v.scale); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getTransformOriginOffset() { | 
					
						
							|  |  |  |  |     var ownerRect = owner.getBoundingClientRect(); | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       x: ownerRect.width * transformOrigin.x, | 
					
						
							|  |  |  |  |       y: ownerRect.height * transformOrigin.y | 
					
						
							|  |  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function publicZoomTo(clientX, clientY, scaleMultiplier) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     smoothScroll.cancel(); | 
					
						
							|  |  |  |  |     cancelZoomAnimation(); | 
					
						
							|  |  |  |  |     return zoomByRatio(clientX, clientY, scaleMultiplier); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function cancelZoomAnimation() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     if (zoomToAnimation) { | 
					
						
							|  |  |  |  |       zoomToAnimation.cancel(); | 
					
						
							|  |  |  |  |       zoomToAnimation = null; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getScaleMultiplier(delta) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var sign = Math.sign(delta); | 
					
						
							|  |  |  |  |     var deltaAdjustedSpeed = Math.min(0.25, Math.abs(speed * delta / 128)); | 
					
						
							|  |  |  |  |     return 1 - sign * deltaAdjustedSpeed; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function triggerPanStart() { | 
					
						
							|  |  |  |  |     if (!panstartFired) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       triggerEvent('panstart'); | 
					
						
							|  |  |  |  |       panstartFired = true; | 
					
						
							|  |  |  |  |       smoothScroll.start(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function triggerPanEnd() { | 
					
						
							|  |  |  |  |     if (panstartFired) { | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |       // we should never run smooth scrolling if it was multiTouch (pinch zoom animation):
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       if (!multiTouch) smoothScroll.stop(); | 
					
						
							|  |  |  |  |       triggerEvent('panend'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   function triggerZoomEnd() { | 
					
						
							|  |  |  |  |     triggerEvent('zoomend'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   function triggerEvent(name) { | 
					
						
							|  |  |  |  |     api.fire(name, api); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | function parseTransformOrigin(options) { | 
					
						
							|  |  |  |  |   if (!options) return; | 
					
						
							|  |  |  |  |   if (typeof options === 'object') { | 
					
						
							|  |  |  |  |     if (!isNumber(options.x) || !isNumber(options.y)) | 
					
						
							|  |  |  |  |       failTransformOrigin(options); | 
					
						
							|  |  |  |  |     return options; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   failTransformOrigin(); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function failTransformOrigin(options) { | 
					
						
							|  |  |  |  |   console.error(options); | 
					
						
							|  |  |  |  |   throw new Error( | 
					
						
							|  |  |  |  |     [ | 
					
						
							|  |  |  |  |       'Cannot parse transform origin.', | 
					
						
							|  |  |  |  |       'Some good examples:', | 
					
						
							|  |  |  |  |       '  "center center" can be achieved with {x: 0.5, y: 0.5}', | 
					
						
							|  |  |  |  |       '  "top center" can be achieved with {x: 0.5, y: 0}', | 
					
						
							|  |  |  |  |       '  "bottom right" can be achieved with {x: 1, y: 1}' | 
					
						
							|  |  |  |  |     ].join('\n') | 
					
						
							|  |  |  |  |   ); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | function noop() { } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function validateBounds(bounds) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var boundsType = typeof bounds; | 
					
						
							|  |  |  |  |   if (boundsType === 'undefined' || boundsType === 'boolean') return; // this is okay
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   // otherwise need to be more thorough:
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var validBounds = | 
					
						
							|  |  |  |  |     isNumber(bounds.left) && | 
					
						
							|  |  |  |  |     isNumber(bounds.top) && | 
					
						
							|  |  |  |  |     isNumber(bounds.bottom) && | 
					
						
							|  |  |  |  |     isNumber(bounds.right); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   if (!validBounds) | 
					
						
							|  |  |  |  |     throw new Error( | 
					
						
							|  |  |  |  |       'Bounds object is not valid. It can be: ' + | 
					
						
							|  |  |  |  |       'undefined, boolean (true|false) or an object {left, top, right, bottom}' | 
					
						
							|  |  |  |  |     ); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function isNumber(x) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   return Number.isFinite(x); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // IE 11 does not support isNaN:
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | function isNaN(value) { | 
					
						
							|  |  |  |  |   if (Number.isNaN) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return Number.isNaN(value); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   return value !== value; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function rigidScroll() { | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     start: noop, | 
					
						
							|  |  |  |  |     stop: noop, | 
					
						
							|  |  |  |  |     cancel: noop | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function autoRun() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   if (typeof document === 'undefined') return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   var scripts = document.getElementsByTagName('script'); | 
					
						
							|  |  |  |  |   if (!scripts) return; | 
					
						
							|  |  |  |  |   var panzoomScript; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |   for (var i = 0; i < scripts.length; ++i) { | 
					
						
							|  |  |  |  |     var x = scripts[i]; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (x.src && x.src.match(/\bpanzoom(\.min)?\.js/)) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       panzoomScript = x; | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |       break; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (!panzoomScript) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var query = panzoomScript.getAttribute('query'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   if (!query) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var globalName = panzoomScript.getAttribute('name') || 'pz'; | 
					
						
							|  |  |  |  |   var started = Date.now(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   tryAttach(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function tryAttach() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var el = document.querySelector(query); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     if (!el) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       var now = Date.now(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       var elapsed = now - started; | 
					
						
							|  |  |  |  |       if (elapsed < 2000) { | 
					
						
							|  |  |  |  |         // Let's wait a bit
 | 
					
						
							|  |  |  |  |         setTimeout(tryAttach, 100); | 
					
						
							|  |  |  |  |         return; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       // If we don't attach within 2 seconds to the target element, consider it a failure
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       console.error('Cannot find the panzoom element', globalName); | 
					
						
							|  |  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var options = collectOptions(panzoomScript); | 
					
						
							|  |  |  |  |     console.log(options); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     window[globalName] = createPanZoom(el, options); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function collectOptions(script) { | 
					
						
							|  |  |  |  |     var attrs = script.attributes; | 
					
						
							|  |  |  |  |     var options = {}; | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     for (var i = 0; i < attrs.length; ++i) { | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       var attr = attrs[i]; | 
					
						
							|  |  |  |  |       var nameValue = getPanzoomAttributeNameValue(attr); | 
					
						
							|  |  |  |  |       if (nameValue) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |         options[nameValue.name] = nameValue.value; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     return options; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getPanzoomAttributeNameValue(attr) { | 
					
						
							|  |  |  |  |     if (!attr.name) return; | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var isPanZoomAttribute = | 
					
						
							|  |  |  |  |       attr.name[0] === 'p' && attr.name[1] === 'z' && attr.name[2] === '-'; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (!isPanZoomAttribute) return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var name = attr.name.substr(3); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     var value = JSON.parse(attr.value); | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     return { name: name, value: value }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | autoRun(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | },{"./lib/createTextSelectionInterceptor.js":2,"./lib/domController.js":3,"./lib/kinetic.js":4,"./lib/svgController.js":5,"./lib/transform.js":6,"amator":7,"ngraph.events":9,"wheel":10}],2:[function(require,module,exports){ | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * Disallows selecting text. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | module.exports = createTextSelectionInterceptor; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function createTextSelectionInterceptor(useFake) { | 
					
						
							|  |  |  |  |   if (useFake) { | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       capture: noop, | 
					
						
							|  |  |  |  |       release: noop | 
					
						
							|  |  |  |  |     }; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var dragObject; | 
					
						
							|  |  |  |  |   var prevSelectStart; | 
					
						
							|  |  |  |  |   var prevDragStart; | 
					
						
							|  |  |  |  |   var wasCaptured = false; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     capture: capture, | 
					
						
							|  |  |  |  |     release: release | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function capture(domObject) { | 
					
						
							|  |  |  |  |     wasCaptured = true; | 
					
						
							|  |  |  |  |     prevSelectStart = window.document.onselectstart; | 
					
						
							|  |  |  |  |     prevDragStart = window.document.ondragstart; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     window.document.onselectstart = disabled; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     dragObject = domObject; | 
					
						
							|  |  |  |  |     dragObject.ondragstart = disabled; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function release() { | 
					
						
							|  |  |  |  |     if (!wasCaptured) return; | 
					
						
							|  |  |  |  |      | 
					
						
							|  |  |  |  |     wasCaptured = false; | 
					
						
							|  |  |  |  |     window.document.onselectstart = prevSelectStart; | 
					
						
							|  |  |  |  |     if (dragObject) dragObject.ondragstart = prevDragStart; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function disabled(e) { | 
					
						
							|  |  |  |  |   e.stopPropagation(); | 
					
						
							|  |  |  |  |   return false; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function noop() {} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | },{}],3:[function(require,module,exports){ | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | module.exports = makeDomController | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  | function makeDomController(domElement, options) { | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   var elementValid = (domElement instanceof HTMLElement) | 
					
						
							|  |  |  |  |   if (!elementValid) { | 
					
						
							|  |  |  |  |     throw new Error('svg element is required for svg.panzoom to work') | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var owner = domElement.parentElement | 
					
						
							|  |  |  |  |   if (!owner) { | 
					
						
							|  |  |  |  |     throw new Error( | 
					
						
							|  |  |  |  |       'Do not apply panzoom to the detached DOM element. ' | 
					
						
							|  |  |  |  |     ) | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   domElement.scrollTop = 0; | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |    | 
					
						
							|  |  |  |  |   if (!options.disableKeyboardInteraction) { | 
					
						
							|  |  |  |  |     owner.setAttribute('tabindex', 0); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   var api = { | 
					
						
							|  |  |  |  |     getBBox: getBBox, | 
					
						
							|  |  |  |  |     getOwner: getOwner, | 
					
						
							|  |  |  |  |     applyTransform: applyTransform, | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |   return api | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getOwner() { | 
					
						
							|  |  |  |  |     return owner | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getBBox() { | 
					
						
							|  |  |  |  |     // TODO: We should probably cache this?
 | 
					
						
							|  |  |  |  |     return  { | 
					
						
							|  |  |  |  |       left: 0, | 
					
						
							|  |  |  |  |       top: 0, | 
					
						
							|  |  |  |  |       width: domElement.clientWidth, | 
					
						
							|  |  |  |  |       height: domElement.clientHeight | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function applyTransform(transform) { | 
					
						
							|  |  |  |  |     // TODO: Should we cache this?
 | 
					
						
							|  |  |  |  |     domElement.style.transformOrigin = '0 0 0'; | 
					
						
							|  |  |  |  |     domElement.style.transform = 'matrix(' + | 
					
						
							|  |  |  |  |       transform.scale + ', 0, 0, ' + | 
					
						
							|  |  |  |  |       transform.scale + ', ' + | 
					
						
							|  |  |  |  |       transform.x + ', ' + transform.y + ')' | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | },{}],4:[function(require,module,exports){ | 
					
						
							|  |  |  |  | (function (global){ | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | /** | 
					
						
							|  |  |  |  |  * Allows smooth kinetic scrolling of the surface | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | module.exports = kinetic; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function kinetic(getPoint, scroll, settings) { | 
					
						
							|  |  |  |  |   if (typeof settings !== 'object') { | 
					
						
							|  |  |  |  |     // setting could come as boolean, we should ignore it, and use an object.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     settings = {}; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var minVelocity = typeof settings.minVelocity === 'number' ? settings.minVelocity : 5; | 
					
						
							|  |  |  |  |   var amplitude = typeof settings.amplitude === 'number' ? settings.amplitude : 0.25; | 
					
						
							|  |  |  |  |   var cancelAnimationFrame = typeof settings.cancelAnimationFrame === 'function' ? settings.cancelAnimationFrame : getCancelAnimationFrame(); | 
					
						
							|  |  |  |  |   var requestAnimationFrame = typeof settings.requestAnimationFrame === 'function' ? settings.requestAnimationFrame : getRequestAnimationFrame(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var lastPoint; | 
					
						
							|  |  |  |  |   var timestamp; | 
					
						
							|  |  |  |  |   var timeConstant = 342; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var ticker; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   var vx, targetX, ax; | 
					
						
							|  |  |  |  |   var vy, targetY, ay; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   var raf; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     start: start, | 
					
						
							|  |  |  |  |     stop: stop, | 
					
						
							|  |  |  |  |     cancel: dispose | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   function dispose() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     cancelAnimationFrame(ticker); | 
					
						
							|  |  |  |  |     cancelAnimationFrame(raf); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function start() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     lastPoint = getPoint(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     ax = ay = vx = vy = 0; | 
					
						
							|  |  |  |  |     timestamp = new Date(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     cancelAnimationFrame(ticker); | 
					
						
							|  |  |  |  |     cancelAnimationFrame(raf); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // we start polling the point position to accumulate velocity
 | 
					
						
							|  |  |  |  |     // Once we stop(), we will use accumulated velocity to keep scrolling
 | 
					
						
							|  |  |  |  |     // an object.
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     ticker = requestAnimationFrame(track); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function track() { | 
					
						
							|  |  |  |  |     var now = Date.now(); | 
					
						
							|  |  |  |  |     var elapsed = now - timestamp; | 
					
						
							|  |  |  |  |     timestamp = now; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var currentPoint = getPoint(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var dx = currentPoint.x - lastPoint.x; | 
					
						
							|  |  |  |  |     var dy = currentPoint.y - lastPoint.y; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     lastPoint = currentPoint; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var dt = 1000 / (1 + elapsed); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     // moving average
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     vx = 0.8 * dx * dt + 0.2 * vx; | 
					
						
							|  |  |  |  |     vy = 0.8 * dy * dt + 0.2 * vy; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     ticker = requestAnimationFrame(track); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function stop() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     cancelAnimationFrame(ticker); | 
					
						
							|  |  |  |  |     cancelAnimationFrame(raf); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var currentPoint = getPoint(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     targetX = currentPoint.x; | 
					
						
							|  |  |  |  |     targetY = currentPoint.y; | 
					
						
							|  |  |  |  |     timestamp = Date.now(); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (vx < -minVelocity || vx > minVelocity) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       ax = amplitude * vx; | 
					
						
							|  |  |  |  |       targetX += ax; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (vy < -minVelocity || vy > minVelocity) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       ay = amplitude * vy; | 
					
						
							|  |  |  |  |       targetY += ay; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     raf = requestAnimationFrame(autoScroll); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function autoScroll() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var elapsed = Date.now() - timestamp; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var moving = false; | 
					
						
							|  |  |  |  |     var dx = 0; | 
					
						
							|  |  |  |  |     var dy = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (ax) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       dx = -ax * Math.exp(-elapsed / timeConstant); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       if (dx > 0.5 || dx < -0.5) moving = true; | 
					
						
							|  |  |  |  |       else dx = ax = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (ay) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       dy = -ay * Math.exp(-elapsed / timeConstant); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       if (dy > 0.5 || dy < -0.5) moving = true; | 
					
						
							|  |  |  |  |       else dy = ay = 0; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     if (moving) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |       scroll(targetX + dx, targetY + dy); | 
					
						
							|  |  |  |  |       raf = requestAnimationFrame(autoScroll); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | function getCancelAnimationFrame() { | 
					
						
							|  |  |  |  |   if (typeof global.cancelAnimationFrame === 'function') return global.cancelAnimationFrame; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return clearTimeout; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | function getRequestAnimationFrame() { | 
					
						
							|  |  |  |  |   if (typeof global.requestAnimationFrame === 'function') return global.requestAnimationFrame; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return function (handler) { | 
					
						
							|  |  |  |  |     return setTimeout(handler, 16); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | 
					
						
							|  |  |  |  | },{}],5:[function(require,module,exports){ | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | module.exports = makeSvgController | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  | function makeSvgController(svgElement, options) { | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   var elementValid = (svgElement instanceof SVGElement) | 
					
						
							|  |  |  |  |   if (!elementValid) { | 
					
						
							|  |  |  |  |     throw new Error('svg element is required for svg.panzoom to work') | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var owner = svgElement.ownerSVGElement | 
					
						
							|  |  |  |  |   if (!owner) { | 
					
						
							|  |  |  |  |     throw new Error( | 
					
						
							|  |  |  |  |       'Do not apply panzoom to the root <svg> element. ' + | 
					
						
							|  |  |  |  |       'Use its child instead (e.g. <g></g>). ' + | 
					
						
							|  |  |  |  |       'As of March 2016 only FireFox supported transform on the root element') | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-15 21:50:27 +02:00
										 |  |  |  |   if (!options.disableKeyboardInteraction) { | 
					
						
							|  |  |  |  |     owner.setAttribute('tabindex', 0); | 
					
						
							|  |  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   var api = { | 
					
						
							|  |  |  |  |     getBBox: getBBox, | 
					
						
							|  |  |  |  |     getScreenCTM: getScreenCTM, | 
					
						
							|  |  |  |  |     getOwner: getOwner, | 
					
						
							|  |  |  |  |     applyTransform: applyTransform, | 
					
						
							|  |  |  |  |     initTransform: initTransform | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |    | 
					
						
							|  |  |  |  |   return api | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getOwner() { | 
					
						
							|  |  |  |  |     return owner | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getBBox() { | 
					
						
							|  |  |  |  |     var bbox =  svgElement.getBBox() | 
					
						
							|  |  |  |  |     return { | 
					
						
							|  |  |  |  |       left: bbox.x, | 
					
						
							|  |  |  |  |       top: bbox.y, | 
					
						
							|  |  |  |  |       width: bbox.width, | 
					
						
							|  |  |  |  |       height: bbox.height, | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getScreenCTM() { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var ctm = owner.getCTM(); | 
					
						
							|  |  |  |  |     if (!ctm) { | 
					
						
							|  |  |  |  |       // This is likely firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=873106
 | 
					
						
							|  |  |  |  |       // The code below is not entirely correct, but still better than nothing
 | 
					
						
							|  |  |  |  |       return owner.getScreenCTM(); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return ctm; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function initTransform(transform) { | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |     var screenCTM = svgElement.getCTM() | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |     transform.x = screenCTM.e; | 
					
						
							|  |  |  |  |     transform.y = screenCTM.f; | 
					
						
							|  |  |  |  |     transform.scale = screenCTM.a; | 
					
						
							|  |  |  |  |     owner.removeAttributeNS(null, 'viewBox'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function applyTransform(transform) { | 
					
						
							|  |  |  |  |     svgElement.setAttribute('transform', 'matrix(' + | 
					
						
							|  |  |  |  |       transform.scale + ' 0 0 ' + | 
					
						
							|  |  |  |  |       transform.scale + ' ' + | 
					
						
							|  |  |  |  |       transform.x + ' ' + transform.y + ')') | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | },{}],6:[function(require,module,exports){ | 
					
						
							|  |  |  |  | module.exports = Transform; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function Transform() { | 
					
						
							|  |  |  |  |   this.x = 0; | 
					
						
							|  |  |  |  |   this.y = 0; | 
					
						
							|  |  |  |  |   this.scale = 1; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | },{}],7:[function(require,module,exports){ | 
					
						
							|  |  |  |  | var BezierEasing = require('bezier-easing') | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // Predefined set of animations. Similar to CSS easing functions
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var animations = { | 
					
						
							|  |  |  |  |   ease:  BezierEasing(0.25, 0.1, 0.25, 1), | 
					
						
							|  |  |  |  |   easeIn: BezierEasing(0.42, 0, 1, 1), | 
					
						
							|  |  |  |  |   easeOut: BezierEasing(0, 0, 0.58, 1), | 
					
						
							|  |  |  |  |   easeInOut: BezierEasing(0.42, 0, 0.58, 1), | 
					
						
							|  |  |  |  |   linear: BezierEasing(0, 0, 1, 1) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | module.exports = animate; | 
					
						
							|  |  |  |  | module.exports.makeAggregateRaf = makeAggregateRaf; | 
					
						
							|  |  |  |  | module.exports.sharedScheduler = makeAggregateRaf(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function animate(source, target, options) { | 
					
						
							|  |  |  |  |   var start = Object.create(null) | 
					
						
							|  |  |  |  |   var diff = Object.create(null) | 
					
						
							|  |  |  |  |   options = options || {} | 
					
						
							|  |  |  |  |   // We let clients specify their own easing function
 | 
					
						
							|  |  |  |  |   var easing = (typeof options.easing === 'function') ? options.easing : animations[options.easing] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // if nothing is specified, default to ease (similar to CSS animations)
 | 
					
						
							|  |  |  |  |   if (!easing) { | 
					
						
							|  |  |  |  |     if (options.easing) { | 
					
						
							|  |  |  |  |       console.warn('Unknown easing function in amator: ' + options.easing); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     easing = animations.ease | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var step = typeof options.step === 'function' ? options.step : noop | 
					
						
							|  |  |  |  |   var done = typeof options.done === 'function' ? options.done : noop | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var scheduler = getScheduler(options.scheduler) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var keys = Object.keys(target) | 
					
						
							|  |  |  |  |   keys.forEach(function(key) { | 
					
						
							|  |  |  |  |     start[key] = source[key] | 
					
						
							|  |  |  |  |     diff[key] = target[key] - source[key] | 
					
						
							|  |  |  |  |   }) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var durationInMs = typeof options.duration === 'number' ? options.duration : 400 | 
					
						
							|  |  |  |  |   var durationInFrames = Math.max(1, durationInMs * 0.06) // 0.06 because 60 frames pers 1,000 ms
 | 
					
						
							|  |  |  |  |   var previousAnimationId | 
					
						
							|  |  |  |  |   var frame = 0 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   previousAnimationId = scheduler.next(loop) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     cancel: cancel | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function cancel() { | 
					
						
							|  |  |  |  |     scheduler.cancel(previousAnimationId) | 
					
						
							|  |  |  |  |     previousAnimationId = 0 | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function loop() { | 
					
						
							|  |  |  |  |     var t = easing(frame/durationInFrames) | 
					
						
							|  |  |  |  |     frame += 1 | 
					
						
							|  |  |  |  |     setValues(t) | 
					
						
							|  |  |  |  |     if (frame <= durationInFrames) { | 
					
						
							|  |  |  |  |       previousAnimationId = scheduler.next(loop) | 
					
						
							|  |  |  |  |       step(source) | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       previousAnimationId = 0 | 
					
						
							|  |  |  |  |       setTimeout(function() { done(source) }, 0) | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function setValues(t) { | 
					
						
							|  |  |  |  |     keys.forEach(function(key) { | 
					
						
							|  |  |  |  |       source[key] = diff[key] * t + start[key] | 
					
						
							|  |  |  |  |     }) | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function noop() { } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function getScheduler(scheduler) { | 
					
						
							|  |  |  |  |   if (!scheduler) { | 
					
						
							|  |  |  |  |     var canRaf = typeof window !== 'undefined' && window.requestAnimationFrame | 
					
						
							|  |  |  |  |     return canRaf ? rafScheduler() : timeoutScheduler() | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   if (typeof scheduler.next !== 'function') throw new Error('Scheduler is supposed to have next(cb) function') | 
					
						
							|  |  |  |  |   if (typeof scheduler.cancel !== 'function') throw new Error('Scheduler is supposed to have cancel(handle) function') | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return scheduler | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function rafScheduler() { | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     next: window.requestAnimationFrame.bind(window), | 
					
						
							|  |  |  |  |     cancel: window.cancelAnimationFrame.bind(window) | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function timeoutScheduler() { | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     next: function(cb) { | 
					
						
							|  |  |  |  |       return setTimeout(cb, 1000/60) | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     cancel: function (id) { | 
					
						
							|  |  |  |  |       return clearTimeout(id) | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function makeAggregateRaf() { | 
					
						
							|  |  |  |  |   var frontBuffer = new Set(); | 
					
						
							|  |  |  |  |   var backBuffer = new Set(); | 
					
						
							|  |  |  |  |   var frameToken = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     next: next, | 
					
						
							|  |  |  |  |     cancel: next, | 
					
						
							|  |  |  |  |     clearAll: clearAll | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function clearAll() { | 
					
						
							|  |  |  |  |     frontBuffer.clear(); | 
					
						
							|  |  |  |  |     backBuffer.clear(); | 
					
						
							|  |  |  |  |     cancelAnimationFrame(frameToken); | 
					
						
							|  |  |  |  |     frameToken = 0; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function next(callback) { | 
					
						
							|  |  |  |  |     backBuffer.add(callback); | 
					
						
							|  |  |  |  |     renderNextFrame(); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function renderNextFrame() { | 
					
						
							|  |  |  |  |     if (!frameToken) frameToken = requestAnimationFrame(renderFrame); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function renderFrame() { | 
					
						
							|  |  |  |  |     frameToken = 0; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var t = backBuffer; | 
					
						
							|  |  |  |  |     backBuffer = frontBuffer; | 
					
						
							| 
									
										
										
										
											2019-08-28 23:08:05 +02:00
										 |  |  |  |     frontBuffer = t; | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |     frontBuffer.forEach(function(callback) { | 
					
						
							|  |  |  |  |       callback(); | 
					
						
							|  |  |  |  |     }); | 
					
						
							|  |  |  |  |     frontBuffer.clear(); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function cancel(callback) { | 
					
						
							|  |  |  |  |     backBuffer.delete(callback); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | },{"bezier-easing":8}],8:[function(require,module,exports){ | 
					
						
							|  |  |  |  | /** | 
					
						
							|  |  |  |  |  * https://github.com/gre/bezier-easing
 | 
					
						
							|  |  |  |  |  * BezierEasing - use bezier curve for transition easing function | 
					
						
							|  |  |  |  |  * by Gaëtan Renaudeau 2014 - 2015 – MIT License | 
					
						
							|  |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // These values are established by empiricism with tests (tradeoff: performance VS precision)
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var NEWTON_ITERATIONS = 4; | 
					
						
							|  |  |  |  | var NEWTON_MIN_SLOPE = 0.001; | 
					
						
							|  |  |  |  | var SUBDIVISION_PRECISION = 0.0000001; | 
					
						
							|  |  |  |  | var SUBDIVISION_MAX_ITERATIONS = 10; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var kSplineTableSize = 11; | 
					
						
							|  |  |  |  | var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | var float32ArraySupported = typeof Float32Array === 'function'; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } | 
					
						
							|  |  |  |  | function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } | 
					
						
							|  |  |  |  | function C (aA1)      { return 3.0 * aA1; } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; } | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function binarySubdivide (aX, aA, aB, mX1, mX2) { | 
					
						
							|  |  |  |  |   var currentX, currentT, i = 0; | 
					
						
							|  |  |  |  |   do { | 
					
						
							|  |  |  |  |     currentT = aA + (aB - aA) / 2.0; | 
					
						
							|  |  |  |  |     currentX = calcBezier(currentT, mX1, mX2) - aX; | 
					
						
							|  |  |  |  |     if (currentX > 0.0) { | 
					
						
							|  |  |  |  |       aB = currentT; | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       aA = currentT; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); | 
					
						
							|  |  |  |  |   return currentT; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { | 
					
						
							|  |  |  |  |  for (var i = 0; i < NEWTON_ITERATIONS; ++i) { | 
					
						
							|  |  |  |  |    var currentSlope = getSlope(aGuessT, mX1, mX2); | 
					
						
							|  |  |  |  |    if (currentSlope === 0.0) { | 
					
						
							|  |  |  |  |      return aGuessT; | 
					
						
							|  |  |  |  |    } | 
					
						
							|  |  |  |  |    var currentX = calcBezier(aGuessT, mX1, mX2) - aX; | 
					
						
							|  |  |  |  |    aGuessT -= currentX / currentSlope; | 
					
						
							|  |  |  |  |  } | 
					
						
							|  |  |  |  |  return aGuessT; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function LinearEasing (x) { | 
					
						
							|  |  |  |  |   return x; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | module.exports = function bezier (mX1, mY1, mX2, mY2) { | 
					
						
							|  |  |  |  |   if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { | 
					
						
							|  |  |  |  |     throw new Error('bezier x values must be in [0, 1] range'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (mX1 === mY1 && mX2 === mY2) { | 
					
						
							|  |  |  |  |     return LinearEasing; | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   // Precompute samples table
 | 
					
						
							|  |  |  |  |   var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); | 
					
						
							|  |  |  |  |   for (var i = 0; i < kSplineTableSize; ++i) { | 
					
						
							|  |  |  |  |     sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   function getTForX (aX) { | 
					
						
							|  |  |  |  |     var intervalStart = 0.0; | 
					
						
							|  |  |  |  |     var currentSample = 1; | 
					
						
							|  |  |  |  |     var lastSample = kSplineTableSize - 1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { | 
					
						
							|  |  |  |  |       intervalStart += kSampleStepSize; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     --currentSample; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     // Interpolate to provide an initial guess for t
 | 
					
						
							|  |  |  |  |     var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); | 
					
						
							|  |  |  |  |     var guessForT = intervalStart + dist * kSampleStepSize; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     var initialSlope = getSlope(guessForT, mX1, mX2); | 
					
						
							|  |  |  |  |     if (initialSlope >= NEWTON_MIN_SLOPE) { | 
					
						
							|  |  |  |  |       return newtonRaphsonIterate(aX, guessForT, mX1, mX2); | 
					
						
							|  |  |  |  |     } else if (initialSlope === 0.0) { | 
					
						
							|  |  |  |  |       return guessForT; | 
					
						
							|  |  |  |  |     } else { | 
					
						
							|  |  |  |  |       return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return function BezierEasing (x) { | 
					
						
							|  |  |  |  |     // Because JavaScript number are imprecise, we should guarantee the extremes are right.
 | 
					
						
							|  |  |  |  |     if (x === 0) { | 
					
						
							|  |  |  |  |       return 0; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     if (x === 1) { | 
					
						
							|  |  |  |  |       return 1; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |     return calcBezier(getTForX(x), mY1, mY2); | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | },{}],9:[function(require,module,exports){ | 
					
						
							|  |  |  |  | module.exports = function(subject) { | 
					
						
							|  |  |  |  |   validateSubject(subject); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   var eventsStorage = createEventsStorage(subject); | 
					
						
							|  |  |  |  |   subject.on = eventsStorage.on; | 
					
						
							|  |  |  |  |   subject.off = eventsStorage.off; | 
					
						
							|  |  |  |  |   subject.fire = eventsStorage.fire; | 
					
						
							|  |  |  |  |   return subject; | 
					
						
							|  |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function createEventsStorage(subject) { | 
					
						
							|  |  |  |  |   // Store all event listeners to this hash. Key is event name, value is array
 | 
					
						
							|  |  |  |  |   // of callback records.
 | 
					
						
							|  |  |  |  |   //
 | 
					
						
							|  |  |  |  |   // A callback record consists of callback function and its optional context:
 | 
					
						
							|  |  |  |  |   // { 'eventName' => [{callback: function, ctx: object}] }
 | 
					
						
							|  |  |  |  |   var registeredEvents = Object.create(null); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return { | 
					
						
							|  |  |  |  |     on: function (eventName, callback, ctx) { | 
					
						
							|  |  |  |  |       if (typeof callback !== 'function') { | 
					
						
							|  |  |  |  |         throw new Error('callback is expected to be a function'); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       var handlers = registeredEvents[eventName]; | 
					
						
							|  |  |  |  |       if (!handlers) { | 
					
						
							|  |  |  |  |         handlers = registeredEvents[eventName] = []; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       handlers.push({callback: callback, ctx: ctx}); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return subject; | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     off: function (eventName, callback) { | 
					
						
							|  |  |  |  |       var wantToRemoveAll = (typeof eventName === 'undefined'); | 
					
						
							|  |  |  |  |       if (wantToRemoveAll) { | 
					
						
							|  |  |  |  |         // Killing old events storage should be enough in this case:
 | 
					
						
							|  |  |  |  |         registeredEvents = Object.create(null); | 
					
						
							|  |  |  |  |         return subject; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (registeredEvents[eventName]) { | 
					
						
							|  |  |  |  |         var deleteAllCallbacksForEvent = (typeof callback !== 'function'); | 
					
						
							|  |  |  |  |         if (deleteAllCallbacksForEvent) { | 
					
						
							|  |  |  |  |           delete registeredEvents[eventName]; | 
					
						
							|  |  |  |  |         } else { | 
					
						
							|  |  |  |  |           var callbacks = registeredEvents[eventName]; | 
					
						
							|  |  |  |  |           for (var i = 0; i < callbacks.length; ++i) { | 
					
						
							|  |  |  |  |             if (callbacks[i].callback === callback) { | 
					
						
							|  |  |  |  |               callbacks.splice(i, 1); | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-10-25 15:45:14 +02:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return subject; | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     fire: function (eventName) { | 
					
						
							|  |  |  |  |       var callbacks = registeredEvents[eventName]; | 
					
						
							|  |  |  |  |       if (!callbacks) { | 
					
						
							|  |  |  |  |         return subject; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       var fireArguments; | 
					
						
							|  |  |  |  |       if (arguments.length > 1) { | 
					
						
							|  |  |  |  |         fireArguments = Array.prototype.splice.call(arguments, 1); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |       for(var i = 0; i < callbacks.length; ++i) { | 
					
						
							|  |  |  |  |         var callbackInfo = callbacks[i]; | 
					
						
							|  |  |  |  |         callbackInfo.callback.apply(callbackInfo.ctx, fireArguments); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       return subject; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   }; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | function validateSubject(subject) { | 
					
						
							|  |  |  |  |   if (!subject) { | 
					
						
							|  |  |  |  |     throw new Error('Eventify cannot use falsy object as events subject'); | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  |   var reservedWords = ['on', 'fire', 'off']; | 
					
						
							|  |  |  |  |   for (var i = 0; i < reservedWords.length; ++i) { | 
					
						
							|  |  |  |  |     if (subject.hasOwnProperty(reservedWords[i])) { | 
					
						
							|  |  |  |  |       throw new Error("Subject cannot be eventified, since it already has property '" + reservedWords[i] + "'"); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   } | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | },{}],10:[function(require,module,exports){ | 
					
						
							|  |  |  |  | /** | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  |  * This module used to unify mouse wheel behavior between different browsers in 2014 | 
					
						
							|  |  |  |  |  * Now it's just a wrapper around addEventListener('wheel'); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Usage: | 
					
						
							|  |  |  |  |  *  var addWheelListener = require('wheel').addWheelListener; | 
					
						
							|  |  |  |  |  *  var removeWheelListener = require('wheel').removeWheelListener; | 
					
						
							|  |  |  |  |  *  addWheelListener(domElement, function (e) { | 
					
						
							|  |  |  |  |  *    // mouse wheel event
 | 
					
						
							|  |  |  |  |  *  }); | 
					
						
							|  |  |  |  |  *  removeWheelListener(domElement, function); | 
					
						
							|  |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | module.exports = addWheelListener; | 
					
						
							| 
									
										
										
										
											2018-10-18 11:46:07 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // But also expose "advanced" api with unsubscribe:
 | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | module.exports.addWheelListener = addWheelListener; | 
					
						
							|  |  |  |  | module.exports.removeWheelListener = removeWheelListener; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | function addWheelListener(element, listener, useCapture) { | 
					
						
							|  |  |  |  |   element.addEventListener('wheel', listener, useCapture); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-07 20:41:03 +01:00
										 |  |  |  | function removeWheelListener( element, listener, useCapture ) { | 
					
						
							|  |  |  |  |   element.removeEventListener('wheel', listener, useCapture); | 
					
						
							| 
									
										
										
										
											2018-10-30 20:22:05 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | },{}]},{},[1])(1) | 
					
						
							|  |  |  |  | }); |