PageSourceSearch

https://club-ihtiolog.ru/o-klube/shema-territorii/assets/svg-pan-zoom.js?160241708291090

js club-ihtiolog.ru collected 2026-10-05 23:01:27 UTC 91,090 bytes, 2,242 lines download raw bytes

vendor: 4,104 bytes, lines 1-74
1// svg-pan-zoom v3.6.1
2// https://github.com/ariutta/svg-pan-zoom
3(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){
4        var SvgUtils = require("./svg-utilities");
5
6        module.exports = {
7            enable: function(instance) {
8                // Select (and create if necessary) defs
9                var defs = instance.svg.querySelector("defs");
10                if (!defs) {
11                    defs = document.createElementNS(SvgUtils.svgNS, "defs");
12                    instance.svg.appendChild(defs);
13                }
14
15                // Check for style element, and create it if it doesn't exist
16                var styleEl = defs.querySelector("style#svg-pan-zoom-controls-styles");
17                if (!styleEl) {
18                    var style = document.createElementNS(SvgUtils.svgNS, "style");
19                    style.setAttribute("id", "svg-pan-zoom-controls-styles");
20                    style.setAttribute("type", "text/css");
21                    style.textContent =
22                        ".svg-pan-zoom-control { cursor: pointer; fill: black; fill-opacity: 0.333; } .svg-pan-zoom-control:hover { fill-opacity: 0.8; } .svg-pan-zoom-control-background { fill: white; fill-opacity: 0.5; } .svg-pan-zoom-control-background { fill-opacity: 0.8; }";
23                    defs.appendChild(style);
24                }
25
26                // Zoom Group
27                var zoomGroup = document.createElementNS(SvgUtils.svgNS, "g");
28                zoomGroup.setAttribute("id", "svg-pan-zoom-controls");
29                zoomGroup.setAttribute(
30                    "transform",
31                    "translate(" +
32                    (instance.width - 70) +
33                    " " +
34                    (instance.height - 76) +
35                    ") scale(0.75)"
36                );
37                zoomGroup.setAttribute("class", "svg-pan-zoom-control");
38
39                // Control elements
40                zoomGroup.appendChild(this._createZoomIn(instance));
41                zoomGroup.appendChild(this._createZoomReset(instance));
42                zoomGroup.appendChild(this._createZoomOut(instance));
43
44                // Finally append created element
45                instance.svg.appendChild(zoomGroup);
46
47                // Cache control instance
48                instance.controlIcons = zoomGroup;
49            },
50
51            _createZoomIn: function(instance) {
52                var zoomIn = document.createElementNS(SvgUtils.svgNS, "g");
53                zoomIn.setAttribute("id", "svg-pan-zoom-zoom-in");
54                zoomIn.setAttribute("transform", "translate(30.5 5) scale(0.015)");
55                zoomIn.setAttribute("class", "svg-pan-zoom-control");
56                zoomIn.addEventListener(
57                    "click",
58                    function() {
59                        instance.getPublicInstance().zoomIn();
60                    },
61                    false
62                );
63                zoomIn.addEventListener(
64                    "touchstart",
65                    function() {
66                        instance.getPublicInstance().zoomIn();
67                    },
68                    false
69                );
70
71                var zoomInBackground = document.createElementNS(SvgUtils.svgNS, "rect"); // TODO change these background space fillers to rounded rectangles so they look prettier
72                zoomInBackground.setAttribute("x", "0");
73                zoomInBackground.setAttribute("y", "0");
74                zoomInBackground.setAttribute("width", "1500"); // larger than expected because the whole group is transformed to scale down
75                zoomInBackground.setAttribute("height", "1400");
76                zoomInBackground.setAttribute("class", "svg-pan-zoom-control-background");
77                zoomIn.appendChild(zoomInBackground);
78
79                var zoomInShape = document.createElementNS(SvgUtils.svgNS, "path");
80                zoomInShape.setAttribute(
81                    "d",
82                    "M1280 576v128q0 26 -19 45t-45 19h-320v320q0 26 -19 45t-45 19h-128q-26 0 -45 -19t-19 -45v-320h-320q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h320v-320q0 -26 19 -45t45 -19h128q26 0 45 19t19 45v320h320q26 0 45 19t19 45zM1536 1120v-960 q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5t84.5 -203.5z"
83                );
84                zoomInShape.setAttribute("class", "svg-pan-zoom-control-element");
85                zoomIn.appendChild(zoomInShape);
86
87                return zoomIn;
88            },
89
90            _createZoomReset: function(instance) {
91                // reset
92                var resetPanZoomControl = document.createElementNS(SvgUtils.svgNS, "g");
93                resetPanZoomControl.setAttribute("id", "svg-pan-zoom-reset-pan-zoom");
94                resetPanZoomControl.setAttribute("transform", "translate(5 35) scale(0.4)");
95                resetPanZoomControl.setAttribute("class", "svg-pan-zoom-control");
96                resetPanZoomControl.addEventListener(
97                    "click",
98                    function() {
99                        instance.getPublicInstance().reset();
100                    },
101                    false
102                );
103                resetPanZoomControl.addEventListener(
104                    "touchstart",
105                    function() {
106                        instance.getPublicInstance().reset();
107                    },
108                    false
109                );
110
111                var resetPanZoomControlBackground = document.createElementNS(
112                    SvgUtils.svgNS,
113                    "rect"
114                ); // TODO change these background space fillers to rounded rectangles so they look prettier
115                resetPanZoomControlBackground.setAttribute("x", "2");
116                resetPanZoomControlBackground.setAttribute("y", "2");
117                resetPanZoomControlBackground.setAttribute("width", "182"); // larger than expected because the whole group is transformed to scale down
118                resetPanZoomControlBackground.setAttribute("height", "58");
119                resetPanZoomControlBackground.setAttribute(
120                    "class",
121                    "svg-pan-zoom-control-background"
122                );
123                resetPanZoomControl.appendChild(resetPanZoomControlBackground);
124
125                var resetPanZoomControlShape1 = document.createElementNS(
126                    SvgUtils.svgNS,
127                    "path"
128                );
129                resetPanZoomControlShape1.setAttribute(
130                    "d",
131                    "M33.051,20.632c-0.742-0.406-1.854-0.609-3.338-0.609h-7.969v9.281h7.769c1.543,0,2.701-0.188,3.473-0.562c1.365-0.656,2.048-1.953,2.048-3.891C35.032,22.757,34.372,21.351,33.051,20.632z"
132                );
133                resetPanZoomControlShape1.setAttribute(
134                    "class",
135                    "svg-pan-zoom-control-element"
136                );
137                resetPanZoomControl.appendChild(resetPanZoomControlShape1);
138
139                var resetPanZoomControlShape2 = document.createElementNS(
140                    SvgUtils.svgNS,
141                    "path"
142                );
143                resetPanZoomControlShape2.setAttribute(
144                    "d",
145                    "M170.231,0.5H15.847C7.102,0.5,0.5,5.708,0.5,11.84v38.861C0.5,56.833,7.102,61.5,15.847,61.5h154.384c8.745,0,15.269-4.667,15.269-10.798V11.84C185.5,5.708,178.976,0.5,170.231,0.5z M42.837,48.569h-7.969c-0.219-0.766-0.375-1.383-0.469-1.852c-0.188-0.969-0.289-1.961-0.305-2.977l-0.047-3.211c-0.03-2.203-0.41-3.672-1.142-4.406c-0.732-0.734-2.103-1.102-4.113-1.102h-7.05v13.547h-7.055V14.022h16.524c2.361,0.047,4.178,0.344,5.45,0.891c1.272,0.547,2.351,1.352,3.234,2.414c0.731,0.875,1.31,1.844,1.737,2.906s0.64,2.273,0.64,3.633c0,1.641-0.414,3.254-1.242,4.84s-2.195,2.707-4.102,3.363c1.594,0.641,2.723,1.551,3.387,2.73s0.996,2.98,0.996,5.402v2.32c0,1.578,0.063,2.648,0.19,3.211c0.19,0.891,0.635,1.547,1.333,1.969V48.569z M75.579,48.569h-26.18V14.022h25.336v6.117H56.454v7.336h16.781v6H56.454v8.883h19.125V48.569z M104.497,46.331c-2.44,2.086-5.887,3.129-10.34,3.129c-4.548,0-8.125-1.027-10.731-3.082s-3.909-4.879-3.909-8.473h6.891c0.224,1.578,0.662,2.758,1.316,3.539c1.196,1.422,3.246,2.133,6.15,2.133c1.739,0,3.151-0.188,4.236-0.562c2.058-0.719,3.087-2.055,3.087-4.008c0-1.141-0.504-2.023-1.512-2.648c-1.008-0.609-2.607-1.148-4.796-1.617l-3.74-0.82c-3.676-0.812-6.201-1.695-7.576-2.648c-2.328-1.594-3.492-4.086-3.492-7.477c0-3.094,1.139-5.664,3.417-7.711s5.623-3.07,10.036-3.07c3.685,0,6.829,0.965,9.431,2.895c2.602,1.93,3.966,4.73,4.093,8.402h-6.938c-0.128-2.078-1.057-3.555-2.787-4.43c-1.154-0.578-2.587-0.867-4.301-0.867c-1.907,0-3.428,0.375-4.565,1.125c-1.138,0.75-1.706,1.797-1.706,3.141c0,1.234,0.561,2.156,1.682,2.766c0.721,0.406,2.25,0.883,4.589,1.43l6.063,1.43c2.657,0.625,4.648,1.461,5.975,2.508c2.059,1.625,3.089,3.977,3.089,7.055C108.157,41.624,106.937,44.245,104.497,46.331z M139.61,48.569h-26.18V14.022h25.336v6.117h-18.281v7.336h16.781v6h-16.781v8.883h19.125V48.569z M170.337,20.14h-10.336v28.43h-7.266V20.14h-10.383v-6.117h27.984V20.14z"
146                );
147                resetPanZoomControlShape2.setAttribute(
148                    "class",
149                    "svg-pan-zoom-control-element"
150                );
151                resetPanZoomControl.appendChild(resetPanZoomControlShape2);
152
153                return resetPanZoomControl;
154            },
155
156            _createZoomOut: function(instance) {
157                // zoom out
158                var zoomOut = document.createElementNS(SvgUtils.svgNS, "g");
159                zoomOut.setAttribute("id", "svg-pan-zoom-zoom-out");
160                zoomOut.setAttribute("transform", "translate(30.5 70) scale(0.015)");
161                zoomOut.setAttribute("class", "svg-pan-zoom-control");
162                zoomOut.addEventListener(
163                    "click",
164                    function() {
165                        instance.getPublicInstance().zoomOut();
166                    },
167                    false
168                );
169                zoomOut.addEventListener(
170                    "touchstart",
171                    function() {
172                        instance.getPublicInstance().zoomOut();
173                    },
174                    false
175                );
176
vendor: 80,175 bytes, lines 177-2242
177                var zoomOutBackground = document.createElementNS(SvgUtils.svgNS, "rect"); // TODO change these background space fillers to rounded rectangles so they look prettier
178                zoomOutBackground.setAttribute("x", "0");
179                zoomOutBackground.setAttribute("y", "0");
180                zoomOutBackground.setAttribute("width", "1500"); // larger than expected because the whole group is transformed to scale down
181                zoomOutBackground.setAttribute("height", "1400");
182                zoomOutBackground.setAttribute("class", "svg-pan-zoom-control-background");
183                zoomOut.appendChild(zoomOutBackground);
184
185                var zoomOutShape = document.createElementNS(SvgUtils.svgNS, "path");
186                zoomOutShape.setAttribute(
187                    "d",
188                    "M1280 576v128q0 26 -19 45t-45 19h-896q-26 0 -45 -19t-19 -45v-128q0 -26 19 -45t45 -19h896q26 0 45 19t19 45zM1536 1120v-960q0 -119 -84.5 -203.5t-203.5 -84.5h-960q-119 0 -203.5 84.5t-84.5 203.5v960q0 119 84.5 203.5t203.5 84.5h960q119 0 203.5 -84.5 t84.5 -203.5z"
189                );
190                zoomOutShape.setAttribute("class", "svg-pan-zoom-control-element");
191                zoomOut.appendChild(zoomOutShape);
192
193                return zoomOut;
194            },
195
196            disable: function(instance) {
197                if (instance.controlIcons) {
198                    instance.controlIcons.parentNode.removeChild(instance.controlIcons);
199                    instance.controlIcons = null;
200                }
201            }
202        };
203
204    },{"./svg-utilities":5}],2:[function(require,module,exports){
205        var SvgUtils = require("./svg-utilities"),
206            Utils = require("./utilities");
207
208        var ShadowViewport = function(viewport, options) {
209            this.init(viewport, options);
210        };
211
212        /**
213         * Initialization
214         *
215         * @param  {SVGElement} viewport
216         * @param  {Object} options
217         */
218        ShadowViewport.prototype.init = function(viewport, options) {
219            // DOM Elements
220            this.viewport = viewport;
221            this.options = options;
222
223            // State cache
224            this.originalState = { zoom: 1, x: 0, y: 0 };
225            this.activeState = { zoom: 1, x: 0, y: 0 };
226
227            this.updateCTMCached = Utils.proxy(this.updateCTM, this);
228
229            // Create a custom requestAnimationFrame taking in account refreshRate
230            this.requestAnimationFrame = Utils.createRequestAnimationFrame(
231                this.options.refreshRate
232            );
233
234            // ViewBox
235            this.viewBox = { x: 0, y: 0, width: 0, height: 0 };
236            this.cacheViewBox();
237
238            // Process CTM
239            var newCTM = this.processCTM();
240
241            // Update viewport CTM and cache zoom and pan
242            this.setCTM(newCTM);
243
244            // Update CTM in this frame
245            this.updateCTM();
246        };
247
248        /**
249         * Cache initial viewBox value
250         * If no viewBox is defined, then use viewport size/position instead for viewBox values
251         */
252        ShadowViewport.prototype.cacheViewBox = function() {
253            var svgViewBox = this.options.svg.getAttribute("viewBox");
254
255            if (svgViewBox) {
256                var viewBoxValues = svgViewBox
257                    .split(/[\s\,]/)
258                    .filter(function(v) {
259                        return v;
260                    })
261                    .map(parseFloat);
262
263                // Cache viewbox x and y offset
264                this.viewBox.x = viewBoxValues[0];
265                this.viewBox.y = viewBoxValues[1];
266                this.viewBox.width = viewBoxValues[2];
267                this.viewBox.height = viewBoxValues[3];
268
269                var zoom = Math.min(
270                    this.options.width / this.viewBox.width,
271                    this.options.height / this.viewBox.height
272                );
273
274                // Update active state
275                this.activeState.zoom = zoom;
276                this.activeState.x = (this.options.width - this.viewBox.width * zoom) / 2;
277                this.activeState.y = (this.options.height - this.viewBox.height * zoom) / 2;
278
279                // Force updating CTM
280                this.updateCTMOnNextFrame();
281
282                this.options.svg.removeAttribute("viewBox");
283            } else {
284                this.simpleViewBoxCache();
285            }
286        };
287
288        /**
289         * Recalculate viewport sizes and update viewBox cache
290         */
291        ShadowViewport.prototype.simpleViewBoxCache = function() {
292            var bBox = this.viewport.getBBox();
293
294            this.viewBox.x = bBox.x;
295            this.viewBox.y = bBox.y;
296            this.viewBox.width = bBox.width;
297            this.viewBox.height = bBox.height;
298        };
299
300        /**
301         * Returns a viewbox object. Safe to alter
302         *
303         * @return {Object} viewbox object
304         */
305        ShadowViewport.prototype.getViewBox = function() {
306            return Utils.extend({}, this.viewBox);
307        };
308
309        /**
310         * Get initial zoom and pan values. Save them into originalState
311         * Parses viewBox attribute to alter initial sizes
312         *
313         * @return {CTM} CTM object based on options
314         */
315        ShadowViewport.prototype.processCTM = function() {
316            var newCTM = this.getCTM();
317
318            if (this.options.fit || this.options.contain) {
319                var newScale;
320                if (this.options.fit) {
321                    newScale = Math.min(
322                        this.options.width / this.viewBox.width,
323                        this.options.height / this.viewBox.height
324                    );
325                } else {
326                    newScale = Math.max(
327                        this.options.width / this.viewBox.width,
328                        this.options.height / this.viewBox.height
329                    );
330                }
331
332                newCTM.a = newScale; //x-scale
333                newCTM.d = newScale; //y-scale
334                newCTM.e = -this.viewBox.x * newScale; //x-transform
335                newCTM.f = -this.viewBox.y * newScale; //y-transform
336            }
337
338            if (this.options.center) {
339                var offsetX =
340                    (this.options.width -
341                        (this.viewBox.width + this.viewBox.x * 2) * newCTM.a) *
342                    0.5,
343                    offsetY =
344                        (this.options.height -
345                            (this.viewBox.height + this.viewBox.y * 2) * newCTM.a) *
346                        0.5;
347
348                newCTM.e = offsetX;
349                newCTM.f = offsetY;
350            }
351
352            // Cache initial values. Based on activeState and fix+center opitons
353            this.originalState.zoom = newCTM.a;
354            this.originalState.x = newCTM.e;
355            this.originalState.y = newCTM.f;
356
357            return newCTM;
358        };
359
360        /**
361         * Return originalState object. Safe to alter
362         *
363         * @return {Object}
364         */
365        ShadowViewport.prototype.getOriginalState = function() {
366            return Utils.extend({}, this.originalState);
367        };
368
369        /**
370         * Return actualState object. Safe to alter
371         *
372         * @return {Object}
373         */
374        ShadowViewport.prototype.getState = function() {
375            return Utils.extend({}, this.activeState);
376        };
377
378        /**
379         * Get zoom scale
380         *
381         * @return {Float} zoom scale
382         */
383        ShadowViewport.prototype.getZoom = function() {
384            return this.activeState.zoom;
385        };
386
387        /**
388         * Get zoom scale for pubilc usage
389         *
390         * @return {Float} zoom scale
391         */
392        ShadowViewport.prototype.getRelativeZoom = function() {
393            return this.activeState.zoom / this.originalState.zoom;
394        };
395
396        /**
397         * Compute zoom scale for pubilc usage
398         *
399         * @return {Float} zoom scale
400         */
401        ShadowViewport.prototype.computeRelativeZoom = function(scale) {
402            return scale / this.originalState.zoom;
403        };
404
405        /**
406         * Get pan
407         *
408         * @return {Object}
409         */
410        ShadowViewport.prototype.getPan = function() {
411            return { x: this.activeState.x, y: this.activeState.y };
412        };
413
414        /**
415         * Return cached viewport CTM value that can be safely modified
416         *
417         * @return {SVGMatrix}
418         */
419        ShadowViewport.prototype.getCTM = function() {
420            var safeCTM = this.options.svg.createSVGMatrix();
421
422            // Copy values manually as in FF they are not itterable
423            safeCTM.a = this.activeState.zoom;
424            safeCTM.b = 0;
425            safeCTM.c = 0;
426            safeCTM.d = this.activeState.zoom;
427            safeCTM.e = this.activeState.x;
428            safeCTM.f = this.activeState.y;
429
430            return safeCTM;
431        };
432
433        /**
434         * Set a new CTM
435         *
436         * @param {SVGMatrix} newCTM
437         */
438        ShadowViewport.prototype.setCTM = function(newCTM) {
439            var willZoom = this.isZoomDifferent(newCTM),
440                willPan = this.isPanDifferent(newCTM);
441
442            if (willZoom || willPan) {
443                // Before zoom
444                if (willZoom) {
445                    // If returns false then cancel zooming
446                    if (
447                        this.options.beforeZoom(
448                            this.getRelativeZoom(),
449                            this.computeRelativeZoom(newCTM.a)
450                        ) === false
451                    ) {
452                        newCTM.a = newCTM.d = this.activeState.zoom;
453                        willZoom = false;
454                    } else {
455                        this.updateCache(newCTM);
456                        this.options.onZoom(this.getRelativeZoom());
457                    }
458                }
459
460                // Before pan
461                if (willPan) {
462                    var preventPan = this.options.beforePan(this.getPan(), {
463                            x: newCTM.e,
464                            y: newCTM.f
465                        }),
466                        // If prevent pan is an object
467                        preventPanX = false,
468                        preventPanY = false;
469
470                    // If prevent pan is Boolean false
471                    if (preventPan === false) {
472                        // Set x and y same as before
473                        newCTM.e = this.getPan().x;
474                        newCTM.f = this.getPan().y;
475
476                        preventPanX = preventPanY = true;
477                    } else if (Utils.isObject(preventPan)) {
478                        // Check for X axes attribute
479                        if (preventPan.x === false) {
480                            // Prevent panning on x axes
481                            newCTM.e = this.getPan().x;
482                            preventPanX = true;
483                        } else if (Utils.isNumber(preventPan.x)) {
484                            // Set a custom pan value
485                            newCTM.e = preventPan.x;
486                        }
487
488                        // Check for Y axes attribute
489                        if (preventPan.y === false) {
490                            // Prevent panning on x axes
491                            newCTM.f = this.getPan().y;
492                            preventPanY = true;
493                        } else if (Utils.isNumber(preventPan.y)) {
494                            // Set a custom pan value
495                            newCTM.f = preventPan.y;
496                        }
497                    }
498
499                    // Update willPan flag
500                    // Check if newCTM is still different
501                    if ((preventPanX && preventPanY) || !this.isPanDifferent(newCTM)) {
502                        willPan = false;
503                    } else {
504                        this.updateCache(newCTM);
505                        this.options.onPan(this.getPan());
506                    }
507                }
508
509                // Check again if should zoom or pan
510                if (willZoom || willPan) {
511                    this.updateCTMOnNextFrame();
512                }
513            }
514        };
515
516        ShadowViewport.prototype.isZoomDifferent = function(newCTM) {
517            return this.activeState.zoom !== newCTM.a;
518        };
519
520        ShadowViewport.prototype.isPanDifferent = function(newCTM) {
521            return this.activeState.x !== newCTM.e || this.activeState.y !== newCTM.f;
522        };
523
524        /**
525         * Update cached CTM and active state
526         *
527         * @param {SVGMatrix} newCTM
528         */
529        ShadowViewport.prototype.updateCache = function(newCTM) {
530            this.activeState.zoom = newCTM.a;
531            this.activeState.x = newCTM.e;
532            this.activeState.y = newCTM.f;
533        };
534
535        ShadowViewport.prototype.pendingUpdate = false;
536
537        /**
538         * Place a request to update CTM on next Frame
539         */
540        ShadowViewport.prototype.updateCTMOnNextFrame = function() {
541            if (!this.pendingUpdate) {
542                // Lock
543                this.pendingUpdate = true;
544
545                // Throttle next update
546                this.requestAnimationFrame.call(window, this.updateCTMCached);
547            }
548        };
549
550        /**
551         * Update viewport CTM with cached CTM
552         */
553        ShadowViewport.prototype.updateCTM = function() {
554            var ctm = this.getCTM();
555
556            // Updates SVG element
557            SvgUtils.setCTM(this.viewport, ctm, this.defs);
558
559            // Free the lock
560            this.pendingUpdate = false;
561
562            // Notify about the update
563            if (this.options.onUpdatedCTM) {
564                this.options.onUpdatedCTM(ctm);
565            }
566        };
567
568        module.exports = function(viewport, options) {
569            return new ShadowViewport(viewport, options);
570        };
571
572    },{"./svg-utilities":5,"./utilities":7}],3:[function(require,module,exports){
573        var svgPanZoom = require("./svg-pan-zoom.js");
574
575// UMD module definition
576        (function(window, document) {
577            // AMD
578            if (typeof define === "function" && define.amd) {
579                define("svg-pan-zoom", function() {
580                    return svgPanZoom;
581                });
582                // CMD
583            } else if (typeof module !== "undefined" && module.exports) {
584                module.exports = svgPanZoom;
585
586                // Browser
587                // Keep exporting globally as module.exports is available because of browserify
588                window.svgPanZoom = svgPanZoom;
589            }
590        })(window, document);
591
592    },{"./svg-pan-zoom.js":4}],4:[function(require,module,exports){
593        var Wheel = require("./uniwheel"),
594            ControlIcons = require("./control-icons"),
595            Utils = require("./utilities"),
596            SvgUtils = require("./svg-utilities"),
597            ShadowViewport = require("./shadow-viewport");
598
599        var SvgPanZoom = function(svg, options) {
600            this.init(svg, options);
601        };
602
603        var optionsDefaults = {
604            viewportSelector: ".svg-pan-zoom_viewport", // Viewport selector. Can be querySelector string or SVGElement
605            panEnabled: true, // enable or disable panning (default enabled)
606            controlIconsEnabled: false, // insert icons to give user an option in addition to mouse events to control pan/zoom (default disabled)
607            zoomEnabled: true, // enable or disable zooming (default enabled)
608            dblClickZoomEnabled: true, // enable or disable zooming by double clicking (default enabled)
609            mouseWheelZoomEnabled: true, // enable or disable zooming by mouse wheel (default enabled)
610            preventMouseEventsDefault: true, // enable or disable preventDefault for mouse events
611            zoomScaleSensitivity: 0.1, // Zoom sensitivity
612            minZoom: 0.5, // Minimum Zoom level
613            maxZoom: 10, // Maximum Zoom level
614            fit: true, // enable or disable viewport fit in SVG (default true)
615            contain: false, // enable or disable viewport contain the svg (default false)
616            center: true, // enable or disable viewport centering in SVG (default true)
617            refreshRate: "auto", // Maximum number of frames per second (altering SVG's viewport)
618            beforeZoom: null,
619            onZoom: null,
620            beforePan: null,
621            onPan: null,
622            customEventsHandler: null,
623            eventsListenerElement: null,
624            onUpdatedCTM: null
625        };
626
627        var passiveListenerOption = { passive: true };
628
629        SvgPanZoom.prototype.init = function(svg, options) {
630            var that = this;
631
632            this.svg = svg;
633            this.defs = svg.querySelector("defs");
634
635            // Add default attributes to SVG
636            SvgUtils.setupSvgAttributes(this.svg);
637
638            // Set options
639            this.options = Utils.extend(Utils.extend({}, optionsDefaults), options);
640
641            // Set default state
642            this.state = "none";
643
644            // Get dimensions
645            var boundingClientRectNormalized = SvgUtils.getBoundingClientRectNormalized(
646                svg
647            );
648            this.width = boundingClientRectNormalized.width;
649            this.height = boundingClientRectNormalized.height;
650
651            // Init shadow viewport
652            this.viewport = ShadowViewport(
653                SvgUtils.getOrCreateViewport(this.svg, this.options.viewportSelector),
654                {
655                    svg: this.svg,
656                    width: this.width,
657                    height: this.height,
658                    fit: this.options.fit,
659                    contain: this.options.contain,
660                    center: this.options.center,
661                    refreshRate: this.options.refreshRate,
662                    // Put callbacks into functions as they can change through time
663                    beforeZoom: function(oldScale, newScale) {
664                        if (that.viewport && that.options.beforeZoom) {
665                            return that.options.beforeZoom(oldScale, newScale);
666                        }
667                    },
668                    onZoom: function(scale) {
669                        if (that.viewport && that.options.onZoom) {
670                            return that.options.onZoom(scale);
671                        }
672                    },
673                    beforePan: function(oldPoint, newPoint) {
674                        if (that.viewport && that.options.beforePan) {
675                            return that.options.beforePan(oldPoint, newPoint);
676                        }
677                    },
678                    onPan: function(point) {
679                        if (that.viewport && that.options.onPan) {
680                            return that.options.onPan(point);
681                        }
682                    },
683                    onUpdatedCTM: function(ctm) {
684                        if (that.viewport && that.options.onUpdatedCTM) {
685                            return that.options.onUpdatedCTM(ctm);
686                        }
687                    }
688                }
689            );
690
691            // Wrap callbacks into public API context
692            var publicInstance = this.getPublicInstance();
693            publicInstance.setBeforeZoom(this.options.beforeZoom);
694            publicInstance.setOnZoom(this.options.onZoom);
695            publicInstance.setBeforePan(this.options.beforePan);
696            publicInstance.setOnPan(this.options.onPan);
697            publicInstance.setOnUpdatedCTM(this.options.onUpdatedCTM);
698
699            if (this.options.controlIconsEnabled) {
700                ControlIcons.enable(this);
701            }
702
703            // Init events handlers
704            this.lastMouseWheelEventTime = Date.now();
705            this.setupHandlers();
706        };
707
708        /**
709         * Register event handlers
710         */
711        SvgPanZoom.prototype.setupHandlers = function() {
712            var that = this,
713                prevEvt = null; // use for touchstart event to detect double tap
714
715            this.eventListeners = {
716                // Mouse down group
717                mousedown: function(evt) {
718                    var result = that.handleMouseDown(evt, prevEvt);
719                    prevEvt = evt;
720                    return result;
721                },
722                touchstart: function(evt) {
723                    var result = that.handleMouseDown(evt, prevEvt);
724                    prevEvt = evt;
725                    return result;
726                },
727
728                // Mouse up group
729                mouseup: function(evt) {
730                    return that.handleMouseUp(evt);
731                },
732                touchend: function(evt) {
733                    return that.handleMouseUp(evt);
734                },
735
736                // Mouse move group
737                mousemove: function(evt) {
738                    return that.handleMouseMove(evt);
739                },
740                touchmove: function(evt) {
741                    return that.handleMouseMove(evt);
742                },
743
744                // Mouse leave group
745                mouseleave: function(evt) {
746                    return that.handleMouseUp(evt);
747                },
748                touchleave: function(evt) {
749                    return that.handleMouseUp(evt);
750                },
751                touchcancel: function(evt) {
752                    return that.handleMouseUp(evt);
753                }
754            };
755
756            // Init custom events handler if available
757            // eslint-disable-next-line eqeqeq
758            if (this.options.customEventsHandler != null) {
759                this.options.customEventsHandler.init({
760                    svgElement: this.svg,
761                    eventsListenerElement: this.options.eventsListenerElement,
762                    instance: this.getPublicInstance()
763                });
764
765                // Custom event handler may halt builtin listeners
766                var haltEventListeners = this.options.customEventsHandler
767                    .haltEventListeners;
768                if (haltEventListeners && haltEventListeners.length) {
769                    for (var i = haltEventListeners.length - 1; i >= 0; i--) {
770                        if (this.eventListeners.hasOwnProperty(haltEventListeners[i])) {
771                            delete this.eventListeners[haltEventListeners[i]];
772                        }
773                    }
774                }
775            }
776
777            // Bind eventListeners
778            for (var event in this.eventListeners) {
779                // Attach event to eventsListenerElement or SVG if not available
780                (this.options.eventsListenerElement || this.svg).addEventListener(
781                    event,
782                    this.eventListeners[event],
783                    !this.options.preventMouseEventsDefault ? passiveListenerOption : false
784                );
785            }
786
787            // Zoom using mouse wheel
788            if (this.options.mouseWheelZoomEnabled) {
789                this.options.mouseWheelZoomEnabled = false; // set to false as enable will set it back to true
790                this.enableMouseWheelZoom();
791            }
792        };
793
794        /**
795         * Enable ability to zoom using mouse wheel
796         */
797        SvgPanZoom.prototype.enableMouseWheelZoom = function() {
798            if (!this.options.mouseWheelZoomEnabled) {
799                var that = this;
800
801                // Mouse wheel listener
802                this.wheelListener = function(evt) {
803                    return that.handleMouseWheel(evt);
804                };
805
806                // Bind wheelListener
807                var isPassiveListener = !this.options.preventMouseEventsDefault;
808                Wheel.on(
809                    this.options.eventsListenerElement || this.svg,
810                    this.wheelListener,
811                    isPassiveListener
812                );
813
814                this.options.mouseWheelZoomEnabled = true;
815            }
816        };
817
818        /**
819         * Disable ability to zoom using mouse wheel
820         */
821        SvgPanZoom.prototype.disableMouseWheelZoom = function() {
822            if (this.options.mouseWheelZoomEnabled) {
823                var isPassiveListener = !this.options.preventMouseEventsDefault;
824                Wheel.off(
825                    this.options.eventsListenerElement || this.svg,
826                    this.wheelListener,
827                    isPassiveListener
828                );
829                this.options.mouseWheelZoomEnabled = false;
830            }
831        };
832
833        /**
834         * Handle mouse wheel event
835         *
836         * @param  {Event} evt
837         */
838        SvgPanZoom.prototype.handleMouseWheel = function(evt) {
839            if (!this.options.zoomEnabled || this.state !== "none") {
840                return;
841            }
842
843            if (this.options.preventMouseEventsDefault) {
844                if (evt.preventDefault) {
845                    evt.preventDefault();
846                } else {
847                    evt.returnValue = false;
848                }
849            }
850
851            // Default delta in case that deltaY is not available
852            var delta = evt.deltaY || 1,
853                timeDelta = Date.now() - this.lastMouseWheelEventTime,
854                divider = 3 + Math.max(0, 30 - timeDelta);
855
856            // Update cache
857            this.lastMouseWheelEventTime = Date.now();
858
859            // Make empirical adjustments for browsers that give deltaY in pixels (deltaMode=0)
860            if ("deltaMode" in evt && evt.deltaMode === 0 && evt.wheelDelta) {
861                delta = evt.deltaY === 0 ? 0 : Math.abs(evt.wheelDelta) / evt.deltaY;
862            }
863
864            delta =
865                -0.3 < delta && delta < 0.3
866                    ? delta
867                    : ((delta > 0 ? 1 : -1) * Math.log(Math.abs(delta) + 10)) / divider;
868
869            var inversedScreenCTM = this.svg.getScreenCTM().inverse(),
870                relativeMousePoint = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(
871                    inversedScreenCTM
872                ),
873                zoom = Math.pow(1 + this.options.zoomScaleSensitivity, -1 * delta); // multiplying by neg. 1 so as to make zoom in/out behavior match Google maps behavior
874
875            this.zoomAtPoint(zoom, relativeMousePoint);
876        };
877
878        /**
879         * Zoom in at a SVG point
880         *
881         * @param  {SVGPoint} point
882         * @param  {Float} zoomScale    Number representing how much to zoom
883         * @param  {Boolean} zoomAbsolute Default false. If true, zoomScale is treated as an absolute value.
884         *                                Otherwise, zoomScale is treated as a multiplied (e.g. 1.10 would zoom in 10%)
885         */
886        SvgPanZoom.prototype.zoomAtPoint = function(zoomScale, point, zoomAbsolute) {
887            var originalState = this.viewport.getOriginalState();
888
889            if (!zoomAbsolute) {
890                // Fit zoomScale in set bounds
891                if (
892                    this.getZoom() * zoomScale <
893                    this.options.minZoom * originalState.zoom
894                ) {
895                    zoomScale = (this.options.minZoom * originalState.zoom) / this.getZoom();
896                } else if (
897                    this.getZoom() * zoomScale >
898                    this.options.maxZoom * originalState.zoom
899                ) {
900                    zoomScale = (this.options.maxZoom * originalState.zoom) / this.getZoom();
901                }
902            } else {
903                // Fit zoomScale in set bounds
904                zoomScale = Math.max(
905                    this.options.minZoom * originalState.zoom,
906                    Math.min(this.options.maxZoom * originalState.zoom, zoomScale)
907                );
908                // Find relative scale to achieve desired scale
909                zoomScale = zoomScale / this.getZoom();
910            }
911
912            var oldCTM = this.viewport.getCTM(),
913                relativePoint = point.matrixTransform(oldCTM.inverse()),
914                modifier = this.svg
915                    .createSVGMatrix()
916                    .translate(relativePoint.x, relativePoint.y)
917                    .scale(zoomScale)
918                    .translate(-relativePoint.x, -relativePoint.y),
919                newCTM = oldCTM.multiply(modifier);
920
921            if (newCTM.a !== oldCTM.a) {
922                this.viewport.setCTM(newCTM);
923            }
924        };
925
926        /**
927         * Zoom at center point
928         *
929         * @param  {Float} scale
930         * @param  {Boolean} absolute Marks zoom scale as relative or absolute
931         */
932        SvgPanZoom.prototype.zoom = function(scale, absolute) {
933            this.zoomAtPoint(
934                scale,
935                SvgUtils.getSvgCenterPoint(this.svg, this.width, this.height),
936                absolute
937            );
938        };
939
940        /**
941         * Zoom used by public instance
942         *
943         * @param  {Float} scale
944         * @param  {Boolean} absolute Marks zoom scale as relative or absolute
945         */
946        SvgPanZoom.prototype.publicZoom = function(scale, absolute) {
947            if (absolute) {
948                scale = this.computeFromRelativeZoom(scale);
949            }
950
951            this.zoom(scale, absolute);
952        };
953
954        /**
955         * Zoom at point used by public instance
956         *
957         * @param  {Float} scale
958         * @param  {SVGPoint|Object} point    An object that has x and y attributes
959         * @param  {Boolean} absolute Marks zoom scale as relative or absolute
960         */
961        SvgPanZoom.prototype.publicZoomAtPoint = function(scale, point, absolute) {
962            if (absolute) {
963                // Transform zoom into a relative value
964                scale = this.computeFromRelativeZoom(scale);
965            }
966
967            // If not a SVGPoint but has x and y then create a SVGPoint
968            if (Utils.getType(point) !== "SVGPoint") {
969                if ("x" in point && "y" in point) {
970                    point = SvgUtils.createSVGPoint(this.svg, point.x, point.y);
971                } else {
972                    throw new Error("Given point is invalid");
973                }
974            }
975
976            this.zoomAtPoint(scale, point, absolute);
977        };
978
979        /**
980         * Get zoom scale
981         *
982         * @return {Float} zoom scale
983         */
984        SvgPanZoom.prototype.getZoom = function() {
985            return this.viewport.getZoom();
986        };
987
988        /**
989         * Get zoom scale for public usage
990         *
991         * @return {Float} zoom scale
992         */
993        SvgPanZoom.prototype.getRelativeZoom = function() {
994            return this.viewport.getRelativeZoom();
995        };
996
997        /**
998         * Compute actual zoom from public zoom
999         *
1000         * @param  {Float} zoom
1001         * @return {Float} zoom scale
1002         */
1003        SvgPanZoom.prototype.computeFromRelativeZoom = function(zoom) {
1004            return zoom * this.viewport.getOriginalState().zoom;
1005        };
1006
1007        /**
1008         * Set zoom to initial state
1009         */
1010        SvgPanZoom.prototype.resetZoom = function() {
1011            var originalState = this.viewport.getOriginalState();
1012
1013            this.zoom(originalState.zoom, true);
1014        };
1015
1016        /**
1017         * Set pan to initial state
1018         */
1019        SvgPanZoom.prototype.resetPan = function() {
1020            this.pan(this.viewport.getOriginalState());
1021        };
1022
1023        /**
1024         * Set pan and zoom to initial state
1025         */
1026        SvgPanZoom.prototype.reset = function() {
1027            this.resetZoom();
1028            this.resetPan();
1029        };
1030
1031        /**
1032         * Handle double click event
1033         * See handleMouseDown() for alternate detection method
1034         *
1035         * @param {Event} evt
1036         */
1037        SvgPanZoom.prototype.handleDblClick = function(evt) {
1038            if (this.options.preventMouseEventsDefault) {
1039                if (evt.preventDefault) {
1040                    evt.preventDefault();
1041                } else {
1042                    evt.returnValue = false;
1043                }
1044            }
1045
1046            // Check if target was a control button
1047            if (this.options.controlIconsEnabled) {
1048                var targetClass = evt.target.getAttribute("class") || "";
1049                if (targetClass.indexOf("svg-pan-zoom-control") > -1) {
1050                    return false;
1051                }
1052            }
1053
1054            var zoomFactor;
1055
1056            if (evt.shiftKey) {
1057                zoomFactor = 1 / ((1 + this.options.zoomScaleSensitivity) * 2); // zoom out when shift key pressed
1058            } else {
1059                zoomFactor = (1 + this.options.zoomScaleSensitivity) * 2;
1060            }
1061
1062            var point = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(
1063                this.svg.getScreenCTM().inverse()
1064            );
1065            this.zoomAtPoint(zoomFactor, point);
1066        };
1067
1068        /**
1069         * Handle click event
1070         *
1071         * @param {Event} evt
1072         */
1073        SvgPanZoom.prototype.handleMouseDown = function(evt, prevEvt) {
1074            if (this.options.preventMouseEventsDefault) {
1075                if (evt.preventDefault) {
1076                    evt.preventDefault();
1077                } else {
1078                    evt.returnValue = false;
1079                }
1080            }
1081
1082            Utils.mouseAndTouchNormalize(evt, this.svg);
1083
1084            // Double click detection; more consistent than ondblclick
1085            if (this.options.dblClickZoomEnabled && Utils.isDblClick(evt, prevEvt)) {
1086                this.handleDblClick(evt);
1087            } else {
1088                // Pan mode
1089                this.state = "pan";
1090                this.firstEventCTM = this.viewport.getCTM();
1091                this.stateOrigin = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(
1092                    this.firstEventCTM.inverse()
1093                );
1094            }
1095        };
1096
1097        /**
1098         * Handle mouse move event
1099         *
1100         * @param  {Event} evt
1101         */
1102        SvgPanZoom.prototype.handleMouseMove = function(evt) {
1103            if (this.options.preventMouseEventsDefault) {
1104                if (evt.preventDefault) {
1105                    evt.preventDefault();
1106                } else {
1107                    evt.returnValue = false;
1108                }
1109            }
1110
1111            if (this.state === "pan" && this.options.panEnabled) {
1112                // Pan mode
1113                var point = SvgUtils.getEventPoint(evt, this.svg).matrixTransform(
1114                    this.firstEventCTM.inverse()
1115                    ),
1116                    viewportCTM = this.firstEventCTM.translate(
1117                        point.x - this.stateOrigin.x,
1118                        point.y - this.stateOrigin.y
1119                    );
1120
1121                this.viewport.setCTM(viewportCTM);
1122            }
1123        };
1124
1125        /**
1126         * Handle mouse button release event
1127         *
1128         * @param {Event} evt
1129         */
1130        SvgPanZoom.prototype.handleMouseUp = function(evt) {
1131            if (this.options.preventMouseEventsDefault) {
1132                if (evt.preventDefault) {
1133                    evt.preventDefault();
1134                } else {
1135                    evt.returnValue = false;
1136                }
1137            }
1138
1139            if (this.state === "pan") {
1140                // Quit pan mode
1141                this.state = "none";
1142            }
1143        };
1144
1145        /**
1146         * Adjust viewport size (only) so it will fit in SVG
1147         * Does not center image
1148         */
1149        SvgPanZoom.prototype.fit = function() {
1150            var viewBox = this.viewport.getViewBox(),
1151                newScale = Math.min(
1152                    this.width / viewBox.width,
1153                    this.height / viewBox.height
1154                );
1155
1156            this.zoom(newScale, true);
1157        };
1158
1159        /**
1160         * Adjust viewport size (only) so it will contain the SVG
1161         * Does not center image
1162         */
1163        SvgPanZoom.prototype.contain = function() {
1164            var viewBox = this.viewport.getViewBox(),
1165                newScale = Math.max(
1166                    this.width / viewBox.width,
1167                    this.height / viewBox.height
1168                );
1169
1170            this.zoom(newScale, true);
1171        };
1172
1173        /**
1174         * Adjust viewport pan (only) so it will be centered in SVG
1175         * Does not zoom/fit/contain image
1176         */
1177        SvgPanZoom.prototype.center = function() {
1178            var viewBox = this.viewport.getViewBox(),
1179                offsetX =
1180                    (this.width - (viewBox.width + viewBox.x * 2) * this.getZoom()) * 0.5,
1181                offsetY =
1182                    (this.height - (viewBox.height + viewBox.y * 2) * this.getZoom()) * 0.5;
1183
1184            this.getPublicInstance().pan({ x: offsetX, y: offsetY });
1185        };
1186
1187        /**
1188         * Update content cached BorderBox
1189         * Use when viewport contents change
1190         */
1191        SvgPanZoom.prototype.updateBBox = function() {
1192            this.viewport.simpleViewBoxCache();
1193        };
1194
1195        /**
1196         * Pan to a rendered position
1197         *
1198         * @param  {Object} point {x: 0, y: 0}
1199         */
1200        SvgPanZoom.prototype.pan = function(point) {
1201            var viewportCTM = this.viewport.getCTM();
1202            viewportCTM.e = point.x;
1203            viewportCTM.f = point.y;
1204            this.viewport.setCTM(viewportCTM);
1205        };
1206
1207        /**
1208         * Relatively pan the graph by a specified rendered position vector
1209         *
1210         * @param  {Object} point {x: 0, y: 0}
1211         */
1212        SvgPanZoom.prototype.panBy = function(point) {
1213            var viewportCTM = this.viewport.getCTM();
1214            viewportCTM.e += point.x;
1215            viewportCTM.f += point.y;
1216            this.viewport.setCTM(viewportCTM);
1217        };
1218
1219        /**
1220         * Get pan vector
1221         *
1222         * @return {Object} {x: 0, y: 0}
1223         */
1224        SvgPanZoom.prototype.getPan = function() {
1225            var state = this.viewport.getState();
1226
1227            return { x: state.x, y: state.y };
1228        };
1229
1230        /**
1231         * Recalculates cached svg dimensions and controls position
1232         */
1233        SvgPanZoom.prototype.resize = function() {
1234            // Get dimensions
1235            var boundingClientRectNormalized = SvgUtils.getBoundingClientRectNormalized(
1236                this.svg
1237            );
1238            this.width = boundingClientRectNormalized.width;
1239            this.height = boundingClientRectNormalized.height;
1240
1241            // Recalculate original state
1242            var viewport = this.viewport;
1243            viewport.options.width = this.width;
1244            viewport.options.height = this.height;
1245            viewport.processCTM();
1246
1247            // Reposition control icons by re-enabling them
1248            if (this.options.controlIconsEnabled) {
1249                this.getPublicInstance().disableControlIcons();
1250                this.getPublicInstance().enableControlIcons();
1251            }
1252        };
1253
1254        /**
1255         * Unbind mouse events, free callbacks and destroy public instance
1256         */
1257        SvgPanZoom.prototype.destroy = function() {
1258            var that = this;
1259
1260            // Free callbacks
1261            this.beforeZoom = null;
1262            this.onZoom = null;
1263            this.beforePan = null;
1264            this.onPan = null;
1265            this.onUpdatedCTM = null;
1266
1267            // Destroy custom event handlers
1268            // eslint-disable-next-line eqeqeq
1269            if (this.options.customEventsHandler != null) {
1270                this.options.customEventsHandler.destroy({
1271                    svgElement: this.svg,
1272                    eventsListenerElement: this.options.eventsListenerElement,
1273                    instance: this.getPublicInstance()
1274                });
1275            }
1276
1277            // Unbind eventListeners
1278            for (var event in this.eventListeners) {
1279                (this.options.eventsListenerElement || this.svg).removeEventListener(
1280                    event,
1281                    this.eventListeners[event],
1282                    !this.options.preventMouseEventsDefault ? passiveListenerOption : false
1283                );
1284            }
1285
1286            // Unbind wheelListener
1287            this.disableMouseWheelZoom();
1288
1289            // Remove control icons
1290            this.getPublicInstance().disableControlIcons();
1291
1292            // Reset zoom and pan
1293            this.reset();
1294
1295            // Remove instance from instancesStore
1296            instancesStore = instancesStore.filter(function(instance) {
1297                return instance.svg !== that.svg;
1298            });
1299
1300            // Delete options and its contents
1301            delete this.options;
1302
1303            // Delete viewport to make public shadow viewport functions uncallable
1304            delete this.viewport;
1305
1306            // Destroy public instance and rewrite getPublicInstance
1307            delete this.publicInstance;
1308            delete this.pi;
1309            this.getPublicInstance = function() {
1310                return null;
1311            };
1312        };
1313
1314        /**
1315         * Returns a public instance object
1316         *
1317         * @return {Object} Public instance object
1318         */
1319        SvgPanZoom.prototype.getPublicInstance = function() {
1320            var that = this;
1321
1322            // Create cache
1323            if (!this.publicInstance) {
1324                this.publicInstance = this.pi = {
1325                    // Pan
1326                    enablePan: function() {
1327                        that.options.panEnabled = true;
1328                        return that.pi;
1329                    },
1330                    disablePan: function() {
1331                        that.options.panEnabled = false;
1332                        return that.pi;
1333                    },
1334                    isPanEnabled: function() {
1335                        return !!that.options.panEnabled;
1336                    },
1337                    pan: function(point) {
1338                        that.pan(point);
1339                        return that.pi;
1340                    },
1341                    panBy: function(point) {
1342                        that.panBy(point);
1343                        return that.pi;
1344                    },
1345                    getPan: function() {
1346                        return that.getPan();
1347                    },
1348                    // Pan event
1349                    setBeforePan: function(fn) {
1350                        that.options.beforePan =
1351                            fn === null ? null : Utils.proxy(fn, that.publicInstance);
1352                        return that.pi;
1353                    },
1354                    setOnPan: function(fn) {
1355                        that.options.onPan =
1356                            fn === null ? null : Utils.proxy(fn, that.publicInstance);
1357                        return that.pi;
1358                    },
1359                    // Zoom and Control Icons
1360                    enableZoom: function() {
1361                        that.options.zoomEnabled = true;
1362                        return that.pi;
1363                    },
1364                    disableZoom: function() {
1365                        that.options.zoomEnabled = false;
1366                        return that.pi;
1367                    },
1368                    isZoomEnabled: function() {
1369                        return !!that.options.zoomEnabled;
1370                    },
1371                    enableControlIcons: function() {
1372                        if (!that.options.controlIconsEnabled) {
1373                            that.options.controlIconsEnabled = true;
1374                            ControlIcons.enable(that);
1375                        }
1376                        return that.pi;
1377                    },
1378                    disableControlIcons: function() {
1379                        if (that.options.controlIconsEnabled) {
1380                            that.options.controlIconsEnabled = false;
1381                            ControlIcons.disable(that);
1382                        }
1383                        return that.pi;
1384                    },
1385                    isControlIconsEnabled: function() {
1386                        return !!that.options.controlIconsEnabled;
1387                    },
1388                    // Double click zoom
1389                    enableDblClickZoom: function() {
1390                        that.options.dblClickZoomEnabled = true;
1391                        return that.pi;
1392                    },
1393                    disableDblClickZoom: function() {
1394                        that.options.dblClickZoomEnabled = false;
1395                        return that.pi;
1396                    },
1397                    isDblClickZoomEnabled: function() {
1398                        return !!that.options.dblClickZoomEnabled;
1399                    },
1400                    // Mouse wheel zoom
1401                    enableMouseWheelZoom: function() {
1402                        that.enableMouseWheelZoom();
1403                        return that.pi;
1404                    },
1405                    disableMouseWheelZoom: function() {
1406                        that.disableMouseWheelZoom();
1407                        return that.pi;
1408                    },
1409                    isMouseWheelZoomEnabled: function() {
1410                        return !!that.options.mouseWheelZoomEnabled;
1411                    },
1412                    // Zoom scale and bounds
1413                    setZoomScaleSensitivity: function(scale) {
1414                        that.options.zoomScaleSensitivity = scale;
1415                        return that.pi;
1416                    },
1417                    setMinZoom: function(zoom) {
1418                        that.options.minZoom = zoom;
1419                        return that.pi;
1420                    },
1421                    setMaxZoom: function(zoom) {
1422                        that.options.maxZoom = zoom;
1423                        return that.pi;
1424                    },
1425                    // Zoom event
1426                    setBeforeZoom: function(fn) {
1427                        that.options.beforeZoom =
1428                            fn === null ? null : Utils.proxy(fn, that.publicInstance);
1429                        return that.pi;
1430                    },
1431                    setOnZoom: function(fn) {
1432                        that.options.onZoom =
1433                            fn === null ? null : Utils.proxy(fn, that.publicInstance);
1434                        return that.pi;
1435                    },
1436                    // Zooming
1437                    zoom: function(scale) {
1438                        that.publicZoom(scale, true);
1439                        return that.pi;
1440                    },
1441                    zoomBy: function(scale) {
1442                        that.publicZoom(scale, false);
1443                        return that.pi;
1444                    },
1445                    zoomAtPoint: function(scale, point) {
1446                        that.publicZoomAtPoint(scale, point, true);
1447                        return that.pi;
1448                    },
1449                    zoomAtPointBy: function(scale, point) {
1450                        that.publicZoomAtPoint(scale, point, false);
1451                        return that.pi;
1452                    },
1453                    zoomIn: function() {
1454                        this.zoomBy(1 + that.options.zoomScaleSensitivity);
1455                        return that.pi;
1456                    },
1457                    zoomOut: function() {
1458                        this.zoomBy(1 / (1 + that.options.zoomScaleSensitivity));
1459                        return that.pi;
1460                    },
1461                    getZoom: function() {
1462                        return that.getRelativeZoom();
1463                    },
1464                    // CTM update
1465                    setOnUpdatedCTM: function(fn) {
1466                        that.options.onUpdatedCTM =
1467                            fn === null ? null : Utils.proxy(fn, that.publicInstance);
1468                        return that.pi;
1469                    },
1470                    // Reset
1471                    resetZoom: function() {
1472                        that.resetZoom();
1473                        return that.pi;
1474                    },
1475                    resetPan: function() {
1476                        that.resetPan();
1477                        return that.pi;
1478                    },
1479                    reset: function() {
1480                        that.reset();
1481                        return that.pi;
1482                    },
1483                    // Fit, Contain and Center
1484                    fit: function() {
1485                        that.fit();
1486                        return that.pi;
1487                    },
1488                    contain: function() {
1489                        that.contain();
1490                        return that.pi;
1491                    },
1492                    center: function() {
1493                        that.center();
1494                        return that.pi;
1495                    },
1496                    // Size and Resize
1497                    updateBBox: function() {
1498                        that.updateBBox();
1499                        return that.pi;
1500                    },
1501                    resize: function() {
1502                        that.resize();
1503                        return that.pi;
1504                    },
1505                    getSizes: function() {
1506                        return {
1507                            width: that.width,
1508                            height: that.height,
1509                            realZoom: that.getZoom(),
1510                            viewBox: that.viewport.getViewBox()
1511                        };
1512                    },
1513                    // Destroy
1514                    destroy: function() {
1515                        that.destroy();
1516                        return that.pi;
1517                    }
1518                };
1519            }
1520
1521            return this.publicInstance;
1522        };
1523
1524        /**
1525         * Stores pairs of instances of SvgPanZoom and SVG
1526         * Each pair is represented by an object {svg: SVGSVGElement, instance: SvgPanZoom}
1527         *
1528         * @type {Array}
1529         */
1530        var instancesStore = [];
1531
1532        var svgPanZoom = function(elementOrSelector, options) {
1533            var svg = Utils.getSvg(elementOrSelector);
1534
1535            if (svg === null) {
1536                return null;
1537            } else {
1538                // Look for existent instance
1539                for (var i = instancesStore.length - 1; i >= 0; i--) {
1540                    if (instancesStore[i].svg === svg) {
1541                        return instancesStore[i].instance.getPublicInstance();
1542                    }
1543                }
1544
1545                // If instance not found - create one
1546                instancesStore.push({
1547                    svg: svg,
1548                    instance: new SvgPanZoom(svg, options)
1549                });
1550
1551                // Return just pushed instance
1552                return instancesStore[
1553                instancesStore.length - 1
1554                    ].instance.getPublicInstance();
1555            }
1556        };
1557
1558        module.exports = svgPanZoom;
1559
1560    },{"./control-icons":1,"./shadow-viewport":2,"./svg-utilities":5,"./uniwheel":6,"./utilities":7}],5:[function(require,module,exports){
1561        var Utils = require("./utilities"),
1562            _browser = "unknown";
1563
1564// http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
1565        if (/*@cc_on!@*/ false || !!document.documentMode) {
1566            // internet explorer
1567            _browser = "ie";
1568        }
1569
1570        module.exports = {
1571            svgNS: "http://www.w3.org/2000/svg",
1572            xmlNS: "http://www.w3.org/XML/1998/namespace",
1573            xmlnsNS: "http://www.w3.org/2000/xmlns/",
1574            xlinkNS: "http://www.w3.org/1999/xlink",
1575            evNS: "http://www.w3.org/2001/xml-events",
1576
1577            /**
1578             * Get svg dimensions: width and height
1579             *
1580             * @param  {SVGSVGElement} svg
1581             * @return {Object}     {width: 0, height: 0}
1582             */
1583            getBoundingClientRectNormalized: function(svg) {
1584                if (svg.clientWidth && svg.clientHeight) {
1585                    return { width: svg.clientWidth, height: svg.clientHeight };
1586                } else if (!!svg.getBoundingClientRect()) {
1587                    return svg.getBoundingClientRect();
1588                } else {
1589                    throw new Error("Cannot get BoundingClientRect for SVG.");
1590                }
1591            },
1592
1593            /**
1594             * Gets g element with class of "viewport" or creates it if it doesn't exist
1595             *
1596             * @param  {SVGSVGElement} svg
1597             * @return {SVGElement}     g (group) element
1598             */
1599            getOrCreateViewport: function(svg, selector) {
1600                var viewport = null;
1601
1602                if (Utils.isElement(selector)) {
1603                    viewport = selector;
1604                } else {
1605                    viewport = svg.querySelector(selector);
1606                }
1607
1608                // Check if there is just one main group in SVG
1609                if (!viewport) {
1610                    var childNodes = Array.prototype.slice
1611                        .call(svg.childNodes || svg.children)
1612                        .filter(function(el) {
1613                            return el.nodeName !== "defs" && el.nodeName !== "#text";
1614                        });
1615
1616                    // Node name should be SVGGElement and should have no transform attribute
1617                    // Groups with transform are not used as viewport because it involves parsing of all transform possibilities
1618                    if (
1619                        childNodes.length === 1 &&
1620                        childNodes[0].nodeName === "g" &&
1621                        childNodes[0].getAttribute("transform") === null
1622                    ) {
1623                        viewport = childNodes[0];
1624                    }
1625                }
1626
1627                // If no favorable group element exists then create one
1628                if (!viewport) {
1629                    var viewportId =
1630                        "viewport-" + new Date().toISOString().replace(/\D/g, "");
1631                    viewport = document.createElementNS(this.svgNS, "g");
1632                    viewport.setAttribute("id", viewportId);
1633
1634                    // Internet Explorer (all versions?) can't use childNodes, but other browsers prefer (require?) using childNodes
1635                    var svgChildren = svg.childNodes || svg.children;
1636                    if (!!svgChildren && svgChildren.length > 0) {
1637                        for (var i = svgChildren.length; i > 0; i--) {
1638                            // Move everything into viewport except defs
1639                            if (svgChildren[svgChildren.length - i].nodeName !== "defs") {
1640                                viewport.appendChild(svgChildren[svgChildren.length - i]);
1641                            }
1642                        }
1643                    }
1644                    svg.appendChild(viewport);
1645                }
1646
1647                // Parse class names
1648                var classNames = [];
1649                if (viewport.getAttribute("class")) {
1650                    classNames = viewport.getAttribute("class").split(" ");
1651                }
1652
1653                // Set class (if not set already)
1654                if (!~classNames.indexOf("svg-pan-zoom_viewport")) {
1655                    classNames.push("svg-pan-zoom_viewport");
1656                    viewport.setAttribute("class", classNames.join(" "));
1657                }
1658
1659                return viewport;
1660            },
1661
1662            /**
1663             * Set SVG attributes
1664             *
1665             * @param  {SVGSVGElement} svg
1666             */
1667            setupSvgAttributes: function(svg) {
1668                // Setting default attributes
1669                svg.setAttribute("xmlns", this.svgNS);
1670                svg.setAttributeNS(this.xmlnsNS, "xmlns:xlink", this.xlinkNS);
1671                svg.setAttributeNS(this.xmlnsNS, "xmlns:ev", this.evNS);
1672
1673                // Needed for Internet Explorer, otherwise the viewport overflows
1674                if (svg.parentNode !== null) {
1675                    var style = svg.getAttribute("style") || "";
1676                    if (style.toLowerCase().indexOf("overflow") === -1) {
1677                        svg.setAttribute("style", "overflow: hidden; " + style);
1678                    }
1679                }
1680            },
1681
1682            /**
1683             * How long Internet Explorer takes to finish updating its display (ms).
1684             */
1685            internetExplorerRedisplayInterval: 300,
1686
1687            /**
1688             * Forces the browser to redisplay all SVG elements that rely on an
1689             * element defined in a 'defs' section. It works globally, for every
1690             * available defs element on the page.
1691             * The throttling is intentionally global.
1692             *
1693             * This is only needed for IE. It is as a hack to make markers (and 'use' elements?)
1694             * visible after pan/zoom when there are multiple SVGs on the page.
1695             * See bug report: https://connect.microsoft.com/IE/feedback/details/781964/
1696             * also see svg-pan-zoom issue: https://github.com/ariutta/svg-pan-zoom/issues/62
1697             */
1698            refreshDefsGlobal: Utils.throttle(
1699                function() {
1700                    var allDefs = document.querySelectorAll("defs");
1701                    var allDefsCount = allDefs.length;
1702                    for (var i = 0; i < allDefsCount; i++) {
1703                        var thisDefs = allDefs[i];
1704                        thisDefs.parentNode.insertBefore(thisDefs, thisDefs);
1705                    }
1706                },
1707                this ? this.internetExplorerRedisplayInterval : null
1708            ),
1709
1710            /**
1711             * Sets the current transform matrix of an element
1712             *
1713             * @param {SVGElement} element
1714             * @param {SVGMatrix} matrix  CTM
1715             * @param {SVGElement} defs
1716             */
1717            setCTM: function(element, matrix, defs) {
1718                var that = this,
1719                    s =
1720                        "matrix(" +
1721                        matrix.a +
1722                        "," +
1723                        matrix.b +
1724                        "," +
1725                        matrix.c +
1726                        "," +
1727                        matrix.d +
1728                        "," +
1729                        matrix.e +
1730                        "," +
1731                        matrix.f +
1732                        ")";
1733
1734                element.setAttributeNS(null, "transform", s);
1735                if ("transform" in element.style) {
1736                    element.style.transform = s;
1737                } else if ("-ms-transform" in element.style) {
1738                    element.style["-ms-transform"] = s;
1739                } else if ("-webkit-transform" in element.style) {
1740                    element.style["-webkit-transform"] = s;
1741                }
1742
1743                // IE has a bug that makes markers disappear on zoom (when the matrix "a" and/or "d" elements change)
1744                // see http://stackoverflow.com/questions/17654578/svg-marker-does-not-work-in-ie9-10
1745                // and http://srndolha.wordpress.com/2013/11/25/svg-line-markers-may-disappear-in-internet-explorer-11/
1746                if (_browser === "ie" && !!defs) {
1747                    // this refresh is intended for redisplaying the SVG during zooming
1748                    defs.parentNode.insertBefore(defs, defs);
1749                    // this refresh is intended for redisplaying the other SVGs on a page when panning a given SVG
1750                    // it is also needed for the given SVG itself, on zoomEnd, if the SVG contains any markers that
1751                    // are located under any other element(s).
1752                    window.setTimeout(function() {
1753                        that.refreshDefsGlobal();
1754                    }, that.internetExplorerRedisplayInterval);
1755                }
1756            },
1757
1758            /**
1759             * Instantiate an SVGPoint object with given event coordinates
1760             *
1761             * @param {Event} evt
1762             * @param  {SVGSVGElement} svg
1763             * @return {SVGPoint}     point
1764             */
1765            getEventPoint: function(evt, svg) {
1766                var point = svg.createSVGPoint();
1767
1768                Utils.mouseAndTouchNormalize(evt, svg);
1769
1770                point.x = evt.clientX;
1771                point.y = evt.clientY;
1772
1773                return point;
1774            },
1775
1776            /**
1777             * Get SVG center point
1778             *
1779             * @param  {SVGSVGElement} svg
1780             * @return {SVGPoint}
1781             */
1782            getSvgCenterPoint: function(svg, width, height) {
1783                return this.createSVGPoint(svg, width / 2, height / 2);
1784            },
1785
1786            /**
1787             * Create a SVGPoint with given x and y
1788             *
1789             * @param  {SVGSVGElement} svg
1790             * @param  {Number} x
1791             * @param  {Number} y
1792             * @return {SVGPoint}
1793             */
1794            createSVGPoint: function(svg, x, y) {
1795                var point = svg.createSVGPoint();
1796                point.x = x;
1797                point.y = y;
1798
1799                return point;
1800            }
1801        };
1802
1803    },{"./utilities":7}],6:[function(require,module,exports){
1804// uniwheel 0.1.2 (customized)
1805// A unified cross browser mouse wheel event handler
1806// https://github.com/teemualap/uniwheel
1807
1808        module.exports = (function(){
1809
1810            //Full details: https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel
1811
1812            var prefix = "", _addEventListener, _removeEventListener, support, fns = [];
1813            var passiveOption = {passive: true};
1814
1815            // detect event model
1816            if ( window.addEventListener ) {
1817                _addEventListener = "addEventListener";
1818                _removeEventListener = "removeEventListener";
1819            } else {
1820                _addEventListener = "attachEvent";
1821                _removeEventListener = "detachEvent";
1822                prefix = "on";
1823            }
1824
1825            // detect available wheel event
1826            support = "onwheel" in document.createElement("div") ? "wheel" : // Modern browsers support "wheel"
1827                document.onmousewheel !== undefined ? "mousewheel" : // Webkit and IE support at least "mousewheel"
1828                    "DOMMouseScroll"; // let's assume that remaining browsers are older Firefox
1829
1830
1831            function createCallback(element,callback) {
1832
1833                var fn = function(originalEvent) {
1834
1835                    !originalEvent && ( originalEvent = window.event );
1836
1837                    // create a normalized event object
1838                    var event = {
1839                        // keep a ref to the original event object
1840                        originalEvent: originalEvent,
1841                        target: originalEvent.target || originalEvent.srcElement,
1842                        type: "wheel",
1843                        deltaMode: originalEvent.type == "MozMousePixelScroll" ? 0 : 1,
1844                        deltaX: 0,
1845                        delatZ: 0,
1846                        preventDefault: function() {
1847                            originalEvent.preventDefault ?
1848                                originalEvent.preventDefault() :
1849                                originalEvent.returnValue = false;
1850                        }
1851                    };
1852
1853                    // calculate deltaY (and deltaX) according to the event
1854                    if ( support == "mousewheel" ) {
1855                        event.deltaY = - 1/40 * originalEvent.wheelDelta;
1856                        // Webkit also support wheelDeltaX
1857                        originalEvent.wheelDeltaX && ( event.deltaX = - 1/40 * originalEvent.wheelDeltaX );
1858                    } else {
1859                        event.deltaY = originalEvent.detail;
1860                    }
1861
1862                    // it's time to fire the callback
1863                    return callback( event );
1864
1865                };
1866
1867                fns.push({
1868                    element: element,
1869                    fn: fn,
1870                });
1871
1872                return fn;
1873            }
1874
1875            function getCallback(element) {
1876                for (var i = 0; i < fns.length; i++) {
1877                    if (fns[i].element === element) {
1878                        return fns[i].fn;
1879                    }
1880                }
1881                return function(){};
1882            }
1883
1884            function removeCallback(element) {
1885                for (var i = 0; i < fns.length; i++) {
1886                    if (fns[i].element === element) {
1887                        return fns.splice(i,1);
1888                    }
1889                }
1890            }
1891
1892            function _addWheelListener(elem, eventName, callback, isPassiveListener ) {
1893                var cb;
1894
1895                if (support === "wheel") {
1896                    cb = callback;
1897                } else {
1898                    cb = createCallback(elem, callback);
1899                }
1900
1901                elem[_addEventListener](prefix + eventName, cb, isPassiveListener ? passiveOption : false);
1902            }
1903
1904            function _removeWheelListener(elem, eventName, callback, isPassiveListener ) {
1905
1906                var cb;
1907
1908                if (support === "wheel") {
1909                    cb = callback;
1910                } else {
1911                    cb = getCallback(elem);
1912                }
1913
1914                elem[_removeEventListener](prefix + eventName, cb, isPassiveListener ? passiveOption : false);
1915
1916                removeCallback(elem);
1917            }
1918
1919            function addWheelListener( elem, callback, isPassiveListener ) {
1920                _addWheelListener(elem, support, callback, isPassiveListener );
1921
1922                // handle MozMousePixelScroll in older Firefox
1923                if( support == "DOMMouseScroll" ) {
1924                    _addWheelListener(elem, "MozMousePixelScroll", callback, isPassiveListener );
1925                }
1926            }
1927
1928            function removeWheelListener(elem, callback, isPassiveListener){
1929                _removeWheelListener(elem, support, callback, isPassiveListener);
1930
1931                // handle MozMousePixelScroll in older Firefox
1932                if( support == "DOMMouseScroll" ) {
1933                    _removeWheelListener(elem, "MozMousePixelScroll", callback, isPassiveListener);
1934                }
1935            }
1936
1937            return {
1938                on: addWheelListener,
1939                off: removeWheelListener
1940            };
1941
1942        })();
1943
1944    },{}],7:[function(require,module,exports){
1945        module.exports = {
1946            /**
1947             * Extends an object
1948             *
1949             * @param  {Object} target object to extend
1950             * @param  {Object} source object to take properties from
1951             * @return {Object}        extended object
1952             */
1953            extend: function(target, source) {
1954                target = target || {};
1955                for (var prop in source) {
1956                    // Go recursively
1957                    if (this.isObject(source[prop])) {
1958                        target[prop] = this.extend(target[prop], source[prop]);
1959                    } else {
1960                        target[prop] = source[prop];
1961                    }
1962                }
1963                return target;
1964            },
1965
1966            /**
1967             * Checks if an object is a DOM element
1968             *
1969             * @param  {Object}  o HTML element or String
1970             * @return {Boolean}   returns true if object is a DOM element
1971             */
1972            isElement: function(o) {
1973                return (
1974                    o instanceof HTMLElement ||
1975                    o instanceof SVGElement ||
1976                    o instanceof SVGSVGElement || //DOM2
1977                    (o &&
1978                        typeof o === "object" &&
1979                        o !== null &&
1980                        o.nodeType === 1 &&
1981                        typeof o.nodeName === "string")
1982                );
1983            },
1984
1985            /**
1986             * Checks if an object is an Object
1987             *
1988             * @param  {Object}  o Object
1989             * @return {Boolean}   returns true if object is an Object
1990             */
1991            isObject: function(o) {
1992                return Object.prototype.toString.call(o) === "[object Object]";
1993            },
1994
1995            /**
1996             * Checks if variable is Number
1997             *
1998             * @param  {Integer|Float}  n
1999             * @return {Boolean}   returns true if variable is Number
2000             */
2001            isNumber: function(n) {
2002                return !isNaN(parseFloat(n)) && isFinite(n);
2003            },
2004
2005            /**
2006             * Search for an SVG element
2007             *
2008             * @param  {Object|String} elementOrSelector DOM Element or selector String
2009             * @return {Object|Null}                   SVG or null
2010             */
2011            getSvg: function(elementOrSelector) {
2012                var element, svg;
2013
2014                if (!this.isElement(elementOrSelector)) {
2015                    // If selector provided
2016                    if (
2017                        typeof elementOrSelector === "string" ||
2018                        elementOrSelector instanceof String
2019                    ) {
2020                        // Try to find the element
2021                        element = document.querySelector(elementOrSelector);
2022
2023                        if (!element) {
2024                            throw new Error(
2025                                "Provided selector did not find any elements. Selector: " +
2026                                elementOrSelector
2027                            );
2028                            return null;
2029                        }
2030                    } else {
2031                        throw new Error("Provided selector is not an HTML object nor String");
2032                        return null;
2033                    }
2034                } else {
2035                    element = elementOrSelector;
2036                }
2037
2038                if (element.tagName.toLowerCase() === "svg") {
2039                    svg = element;
2040                } else {
2041                    if (element.tagName.toLowerCase() === "object") {
2042                        svg = element.contentDocument.documentElement;
2043                    } else {
2044                        if (element.tagName.toLowerCase() === "embed") {
2045                            svg = element.getSVGDocument().documentElement;
2046                        } else {
2047                            if (element.tagName.toLowerCase() === "img") {
2048                                throw new Error(
2049                                    'Cannot script an SVG in an "img" element. Please use an "object" element or an in-line SVG.'
2050                                );
2051                            } else {
2052                                throw new Error("Cannot get SVG.");
2053                            }
2054                            return null;
2055                        }
2056                    }
2057                }
2058
2059                return svg;
2060            },
2061
2062            /**
2063             * Attach a given context to a function
2064             * @param  {Function} fn      Function
2065             * @param  {Object}   context Context
2066             * @return {Function}           Function with certain context
2067             */
2068            proxy: function(fn, context) {
2069                return function() {
2070                    return fn.apply(context, arguments);
2071                };
2072            },
2073
2074            /**
2075             * Returns object type
2076             * Uses toString that returns [object SVGPoint]
2077             * And than parses object type from string
2078             *
2079             * @param  {Object} o Any object
2080             * @return {String}   Object type
2081             */
2082            getType: function(o) {
2083                return Object.prototype.toString
2084                    .apply(o)
2085                    .replace(/^\[object\s/, "")
2086                    .replace(/\]$/, "");
2087            },
2088
2089            /**
2090             * If it is a touch event than add clientX and clientY to event object
2091             *
2092             * @param  {Event} evt
2093             * @param  {SVGSVGElement} svg
2094             */
2095            mouseAndTouchNormalize: function(evt, svg) {
2096                // If no clientX then fallback
2097                if (evt.clientX === void 0 || evt.clientX === null) {
2098                    // Fallback
2099                    evt.clientX = 0;
2100                    evt.clientY = 0;
2101
2102                    // If it is a touch event
2103                    if (evt.touches !== void 0 && evt.touches.length) {
2104                        if (evt.touches[0].clientX !== void 0) {
2105                            evt.clientX = evt.touches[0].clientX;
2106                            evt.clientY = evt.touches[0].clientY;
2107                        } else if (evt.touches[0].pageX !== void 0) {
2108                            var rect = svg.getBoundingClientRect();
2109
2110                            evt.clientX = evt.touches[0].pageX - rect.left;
2111                            evt.clientY = evt.touches[0].pageY - rect.top;
2112                        }
2113                        // If it is a custom event
2114                    } else if (evt.originalEvent !== void 0) {
2115                        if (evt.originalEvent.clientX !== void 0) {
2116                            evt.clientX = evt.originalEvent.clientX;
2117                            evt.clientY = evt.originalEvent.clientY;
2118                        }
2119                    }
2120                }
2121            },
2122
2123            /**
2124             * Check if an event is a double click/tap
2125             * TODO: For touch gestures use a library (hammer.js) that takes in account other events
2126             * (touchmove and touchend). It should take in account tap duration and traveled distance
2127             *
2128             * @param  {Event}  evt
2129             * @param  {Event}  prevEvt Previous Event
2130             * @return {Boolean}
2131             */
2132            isDblClick: function(evt, prevEvt) {
2133                // Double click detected by browser
2134                if (evt.detail === 2) {
2135                    return true;
2136                }
2137                // Try to compare events
2138                else if (prevEvt !== void 0 && prevEvt !== null) {
2139                    var timeStampDiff = evt.timeStamp - prevEvt.timeStamp, // should be lower than 250 ms
2140                        touchesDistance = Math.sqrt(
2141                            Math.pow(evt.clientX - prevEvt.clientX, 2) +
2142                            Math.pow(evt.clientY - prevEvt.clientY, 2)
2143                        );
2144
2145                    return timeStampDiff < 250 && touchesDistance < 10;
2146                }
2147
2148                // Nothing found
2149                return false;
2150            },
2151
2152            /**
2153             * Returns current timestamp as an integer
2154             *
2155             * @return {Number}
2156             */
2157            now:
2158                Date.now ||
2159                function() {
2160                    return new Date().getTime();
2161                },
2162
2163            // From underscore.
2164            // Returns a function, that, when invoked, will only be triggered at most once
2165            // during a given window of time. Normally, the throttled function will run
2166            // as much as it can, without ever going more than once per `wait` duration;
2167            // but if you'd like to disable the execution on the leading edge, pass
2168            // `{leading: false}`. To disable execution on the trailing edge, ditto.
2169            throttle: function(func, wait, options) {
2170                var that = this;
2171                var context, args, result;
2172                var timeout = null;
2173                var previous = 0;
2174                if (!options) {
2175                    options = {};
2176                }
2177                var later = function() {
2178                    previous = options.leading === false ? 0 : that.now();
2179                    timeout = null;
2180                    result = func.apply(context, args);
2181                    if (!timeout) {
2182                        context = args = null;
2183                    }
2184                };
2185                return function() {
2186                    var now = that.now();
2187                    if (!previous && options.leading === false) {
2188                        previous = now;
2189                    }
2190                    var remaining = wait - (now - previous);
2191                    context = this; // eslint-disable-line consistent-this
2192                    args = arguments;
2193                    if (remaining <= 0 || remaining > wait) {
2194                        clearTimeout(timeout);
2195                        timeout = null;
2196                        previous = now;
2197                        result = func.apply(context, args);
2198                        if (!timeout) {
2199                            context = args = null;
2200                        }
2201                    } else if (!timeout && options.trailing !== false) {
2202                        timeout = setTimeout(later, remaining);
2203                    }
2204                    return result;
2205                };
2206            },
2207
2208            /**
2209             * Create a requestAnimationFrame simulation
2210             *
2211             * @param  {Number|String} refreshRate
2212             * @return {Function}
2213             */
2214            createRequestAnimationFrame: function(refreshRate) {
2215                var timeout = null;
2216
2217                // Convert refreshRate to timeout
2218                if (refreshRate !== "auto" && refreshRate < 60 && refreshRate > 1) {
2219                    timeout = Math.floor(1000 / refreshRate);
2220                }
2221
2222                if (timeout === null) {
2223                    return window.requestAnimationFrame || requestTimeout(33);
2224                } else {
2225                    return requestTimeout(timeout);
2226                }
2227            }
2228        };
2229
2230        /**
2231         * Create a callback that will execute after a given timeout
2232         *
2233         * @param  {Function} timeout
2234         * @return {Function}
2235         */
2236        function requestTimeout(timeout) {
2237            return function(callback) {
2238                window.setTimeout(callback, timeout);
2239            };
2240        }
2241
2242    },{}]},{},[3]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.