PageSourceSearch

https://portal.cezesco.cz/cezonline_logon/js/vivus.js

js cezesco.cz collected 2026-10-07 21:15:29 UTC 37,195 bytes, 1,087 lines download raw bytes

vendor: 13,564 bytes, lines 1-383
1/**
2 * vivus - JavaScript library to make drawing animation on SVG
3 * @version v0.4.2
4 * @link https://github.com/maxwellito/vivus
5 * @license MIT
6 */
7
8'use strict';
9
10(function () {
11
12    'use strict';
13
14    /**
15     * Pathformer
16     * Beta version
17     *
18     * Take any SVG version 1.1 and transform
19     * child elements to 'path' elements
20     *
21     * This code is purely forked from
22     * https://github.com/Waest/SVGPathConverter
23     */
24
25    /**
26     * Class constructor
27     *
28     * @param {DOM|String} element Dom element of the SVG or id of it
29     */
30    function Pathformer(element) {
31        // Test params
32        if (typeof element === 'undefined') {
33            throw new Error('Pathformer [constructor]: "element" parameter is required');
34        }
35
36        // Set the element
37        if (element.constructor === String) {
38            element = document.getElementById(element);
39            if (!element) {
40                throw new Error('Pathformer [constructor]: "element" parameter is not related to an existing ID');
41            }
42        }
43        if (element instanceof window.SVGElement ||
44            element instanceof window.SVGGElement ||
45            /^svg$/i.test(element.nodeName)) {
46            this.el = element;
47        } else {
48            throw new Error('Pathformer [constructor]: "element" parameter must be a string or a SVGelement');
49        }
50
51        // Start
52        this.scan(element);
53    }
54
55    /**
56     * List of tags which can be transformed
57     * to path elements
58     *
59     * @type {Array}
60     */
61    Pathformer.prototype.TYPES = ['line', 'ellipse', 'circle', 'polygon', 'polyline', 'rect'];
62
63    /**
64     * List of attribute names which contain
65     * data. This array list them to check if
66     * they contain bad values, like percentage.
67     *
68     * @type {Array}
69     */
70    Pathformer.prototype.ATTR_WATCH = ['cx', 'cy', 'points', 'r', 'rx', 'ry', 'x', 'x1', 'x2', 'y', 'y1', 'y2'];
71
72    /**
73     * Finds the elements compatible for transform
74     * and apply the liked method
75     *
76     * @param  {object} options Object from the constructor
77     */
78    Pathformer.prototype.scan = function (svg) {
79        var fn, element, pathData, pathDom,
80            elements = svg.querySelectorAll(this.TYPES.join(','));
81
82        for (var i = 0; i < elements.length; i++) {
83            element = elements[i];
84            fn = this[element.tagName.toLowerCase() + 'ToPath'];
85            pathData = fn(this.parseAttr(element.attributes));
86            pathDom = this.pathMaker(element, pathData);
87            element.parentNode.replaceChild(pathDom, element);
88        }
89    };
90
91
92    /**
93     * Read `line` element to extract and transform
94     * data, to make it ready for a `path` object.
95     *
96     * @param  {DOMelement} element Line element to transform
97     * @return {object}             Data for a `path` element
98     */
99    Pathformer.prototype.lineToPath = function (element) {
100        var newElement = {},
101            x1 = element.x1 || 0,
102            y1 = element.y1 || 0,
103            x2 = element.x2 || 0,
104            y2 = element.y2 || 0;
105
106        newElement.d = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
107        return newElement;
108    };
109
110    /**
111     * Read `rect` element to extract and transform
112     * data, to make it ready for a `path` object.
113     * The radius-border is not taken in charge yet.
114     * (your help is more than welcomed)
115     *
116     * @param  {DOMelement} element Rect element to transform
117     * @return {object}             Data for a `path` element
118     */
119    Pathformer.prototype.rectToPath = function (element) {
120        var newElement = {},
121            x      = parseFloat(element.x)      || 0,
122            y      = parseFloat(element.y)      || 0,
123            width  = parseFloat(element.width)  || 0,
124            height = parseFloat(element.height) || 0;
125
126        if (element.rx || element.ry) {
127            var rx = parseInt(element.rx, 10) || -1,
128                ry = parseInt(element.ry, 10) || -1;
129            rx = Math.min(Math.max(rx < 0 ? ry : rx, 0), width/2);
130            ry = Math.min(Math.max(ry < 0 ? rx : ry, 0), height/2);
131
132            newElement.d = 'M ' + (x + rx) + ',' + y + ' ' +
133                'L ' + (x + width - rx) + ',' + y + ' ' +
134                'A ' + rx + ',' + ry + ',0,0,1,' + (x + width) + ',' + (y + ry) + ' ' +
135                'L ' + (x + width) + ',' + (y + height - ry) + ' ' +
136                'A ' + rx + ',' + ry + ',0,0,1,' + (x + width - rx) + ',' + (y + height) + ' ' +
137                'L ' + (x + rx) + ',' + (y + height) + ' ' +
138                'A ' + rx + ',' + ry + ',0,0,1,' + x + ',' + (y + height - ry) + ' ' +
139                'L ' + x + ',' + (y + ry) + ' ' +
140                'A ' + rx + ',' + ry + ',0,0,1,' + (x + rx) + ',' + y;
141        }
142        else {
143            newElement.d = 'M' + x + ' ' + y + ' ' +
144                'L' + (x + width) + ' ' + y + ' ' +
145                'L' + (x + width) + ' ' + (y + height) + ' ' +
146                'L' + x + ' ' + (y + height) + ' Z';
147        }
148        return newElement;
149    };
150
151    /**
152     * Read `polyline` element to extract and transform
153     * data, to make it ready for a `path` object.
154     *
155     * @param  {DOMelement} element Polyline element to transform
156     * @return {object}             Data for a `path` element
157     */
158    Pathformer.prototype.polylineToPath = function (element) {
159        var newElement = {},
160            points = element.points.trim().split(' '),
161            i, path;
162
163        // Reformatting if points are defined without commas
164        if (element.points.indexOf(',') === -1) {
165            var formattedPoints = [];
166            for (i = 0; i < points.length; i+=2) {
167                formattedPoints.push(points[i] + ',' + points[i+1]);
168            }
169            points = formattedPoints;
170        }
171
172        // Generate the path.d value
173        path = 'M' + points[0];
174        for(i = 1; i < points.length; i++) {
175            if (points[i].indexOf(',') !== -1) {
176                path += 'L' + points[i];
177            }
178        }
179        newElement.d = path;
180        return newElement;
181    };
182
183    /**
184     * Read `polygon` element to extract and transform
185     * data, to make it ready for a `path` object.
186     * This method rely on polylineToPath, because the
187     * logic is similar. The path created is just closed,
188     * so it needs an 'Z' at the end.
189     *
190     * @param  {DOMelement} element Polygon element to transform
191     * @return {object}             Data for a `path` element
192     */
193    Pathformer.prototype.polygonToPath = function (element) {
194        var newElement = Pathformer.prototype.polylineToPath(element);
195
196        newElement.d += 'Z';
197        return newElement;
198    };
199
200    /**
201     * Read `ellipse` element to extract and transform
202     * data, to make it ready for a `path` object.
203     *
204     * @param  {DOMelement} element ellipse element to transform
205     * @return {object}             Data for a `path` element
206     */
207    Pathformer.prototype.ellipseToPath = function (element) {
208        var newElement = {},
209            rx = parseFloat(element.rx) || 0,
210            ry = parseFloat(element.ry) || 0,
211            cx = parseFloat(element.cx) || 0,
212            cy = parseFloat(element.cy) || 0,
213            startX = cx - rx,
214            startY = cy,
215            endX = parseFloat(cx) + parseFloat(rx),
216            endY = cy;
217
218        newElement.d = 'M' + startX + ',' + startY +
219            'A' + rx + ',' + ry + ' 0,1,1 ' + endX + ',' + endY +
220            'A' + rx + ',' + ry + ' 0,1,1 ' + startX + ',' + endY;
221        return newElement;
222    };
223
224    /**
225     * Read `circle` element to extract and transform
226     * data, to make it ready for a `path` object.
227     *
228     * @param  {DOMelement} element Circle element to transform
229     * @return {object}             Data for a `path` element
230     */
231    Pathformer.prototype.circleToPath = function (element) {
232        var newElement = {},
233            r  = parseFloat(element.r)  || 0,
234            cx = parseFloat(element.cx) || 0,
235            cy = parseFloat(element.cy) || 0,
236            startX = cx - r,
237            startY = cy,
238            endX = parseFloat(cx) + parseFloat(r),
239            endY = cy;
240
241        newElement.d =  'M' + startX + ',' + startY +
242            'A' + r + ',' + r + ' 0,1,1 ' + endX + ',' + endY +
243            'A' + r + ',' + r + ' 0,1,1 ' + startX + ',' + endY;
244        return newElement;
245    };
246
247    /**
248     * Create `path` elements form original element
249     * and prepared objects
250     *
251     * @param  {DOMelement} element  Original element to transform
252     * @param  {object} pathData     Path data (from `toPath` methods)
253     * @return {DOMelement}          Path element
254     */
255    Pathformer.prototype.pathMaker = function (element, pathData) {
256        var i, attr, pathTag = document.createElementNS('http://www.w3.org/2000/svg','path');
257        for(i = 0; i < element.attributes.length; i++) {
258            attr = element.attributes[i];
259            if (this.ATTR_WATCH.indexOf(attr.name) === -1) {
260                pathTag.setAttribute(attr.name, attr.value);
261            }
262        }
263        for(i in pathData) {
264            pathTag.setAttribute(i, pathData[i]);
265        }
266        return pathTag;
267    };
268
269    /**
270     * Parse attributes of a DOM element to
271     * get an object of attribute => value
272     *
273     * @param  {NamedNodeMap} attributes Attributes object from DOM element to parse
274     * @return {object}                  Object of attributes
275     */
276    Pathformer.prototype.parseAttr = function (element) {
277        var attr, output = {};
278        for (var i = 0; i < element.length; i++) {
279            attr = element[i];
280            // Check if no data attribute contains '%', or the transformation is impossible
281            if (this.ATTR_WATCH.indexOf(attr.name) !== -1 && attr.value.indexOf('%') !== -1) {
282                throw new Error('Pathformer [parseAttr]: a SVG shape got values in percentage. This cannot be transformed into \'path\' tags. Please use \'viewBox\'.');
283            }
284            output[attr.name] = attr.value;
285        }
286        return output;
287    };
288
289
290    var setupEnv, requestAnimFrame, cancelAnimFrame, parsePositiveInt;
291
292    /**
293     * Vivus
294     * Beta version
295     *
296     * Take any SVG and make the animation
297     * to give give the impression of live drawing
298     *
299     * This in more than just inspired from codrops
300     * At that point, it's a pure fork.
301     */
302
303    /**
304     * Class constructor
305     * option structure
306     *   type: 'delayed'|'sync'|'oneByOne'|'script' (to know if the items must be drawn synchronously or not, default: delayed)
307     *   duration: <int> (in frames)
308     *   start: 'inViewport'|'manual'|'autostart' (start automatically the animation, default: inViewport)
309     *   delay: <int> (delay between the drawing of first and last path)
310     *   dashGap <integer> whitespace extra margin between dashes
311     *   pathTimingFunction <function> timing animation function for each path element of the SVG
312     *   animTimingFunction <function> timing animation function for the complete SVG
313     *   forceRender <boolean> force the browser to re-render all updated path items
314     *   selfDestroy <boolean> removes all extra styling on the SVG, and leaves it as original
315     *
316     * The attribute 'type' is by default on 'delayed'.
317     *  - 'delayed'
318     *    all paths are draw at the same time but with a
319     *    little delay between them before start
320     *  - 'sync'
321     *    all path are start and finish at the same time
322     *  - 'oneByOne'
323     *    only one path is draw at the time
324     *    the end of the first one will trigger the draw
325     *    of the next one
326     *
327     * All these values can be overwritten individually
328     * for each path item in the SVG
329     * The value of frames will always take the advantage of
330     * the duration value.
331     * If you fail somewhere, an error will be thrown.
332     * Good luck.
333     *
334     * @constructor
335     * @this {Vivus}
336     * @param {DOM|String}   element  Dom element of the SVG or id of it
337     * @param {Object}       options  Options about the animation
338     * @param {Function}     callback Callback for the end of the animation
339     */
340    function Vivus (element, options, callback) {
341
342        setupEnv();
343
344        // Setup
345        this.isReady = false;
346        this.setElement(element, options);
347        this.setOptions(options);
348        this.setCallback(callback);
349
350        if (this.isReady) {
351            this.init();
352        }
353    }
354
355    /**
356     * Timing functions
357     **************************************
358     *
359     * Default functions to help developers.
360     * It always take a number as parameter (between 0 to 1) then
361     * return a number (between 0 and 1)
362     */
363    Vivus.LINEAR          = function (x) {return x;};
364    Vivus.EASE            = function (x) {return -Math.cos(x * Math.PI) / 2 + 0.5;};
365    Vivus.EASE_OUT        = function (x) {return 1 - Math.pow(1-x, 3);};
366    Vivus.EASE_IN         = function (x) {return Math.pow(x, 3);};
367    Vivus.EASE_OUT_BOUNCE = function (x) {
368        var base = -Math.cos(x * (0.5 * Math.PI)) + 1,
369            rate = Math.pow(base,1.5),
370            rateR = Math.pow(1 - x, 2),
371            progress = -Math.abs(Math.cos(rate * (2.5 * Math.PI) )) + 1;
372        return (1- rateR) + (progress * rateR);
373    };
374
375
376    /**
377     * Setters
378     **************************************
379     */
380
381    /**
382     * Check and set the element in the instance
383     * The method will not return anything, but will throw an
384     * error if the parameter is invalid
385     *
386     * @param {DOM|String}   element  SVG Dom element or id of it
387     */
388    Vivus.prototype.setElement = function (element, options) {
389        // Basic check
390        if (typeof element === 'undefined') {
391            throw new Error('Vivus [constructor]: "element" parameter is required');
392        }
393
394        // Set the element
395        if (element.constructor === String) {
396            element = document.getElementById(element);
397            if (!element) {
398                throw new Error('Vivus [constructor]: "element" parameter is not related to an existing ID');
399            }
400        }
401        this.parentEl = element;
402
403        // Create the object element if the property `file` exists in the options object
404        if (options && options.file) {
405            var objElm = document.createElement('object');
406            objElm.setAttribute('type', 'image/svg+xml');
407            objElm.setAttribute('data', options.file);
408            objElm.setAttribute('built-by-vivus', 'true');
409            element.appendChild(objElm);
410            element = objElm;
411        }
412
413        switch (element.constructor) {
414            case window.SVGSVGElement:
415            case window.SVGElement:
416            case window.SVGGElement:
417                this.el = element;
418                this.isReady = true;
419                break;
420
421            case window.HTMLObjectElement:
422                // If we have to wait for it
423                var onLoad, self;
424
425                self = this;
426                onLoad = function (e) {
427                    if (self.isReady) {
428                        return;
429                    }
430                    self.el = element.contentDocument && element.contentDocument.querySelector('svg');
431                    if (!self.el && e) {
432                        throw new Error('Vivus [constructor]: object loaded does not contain any SVG');
433                    }
434                    else if (self.el) {
435                        if (element.getAttribute('built-by-vivus')) {
436                            self.parentEl.insertBefore(self.el, element);
437                            self.parentEl.removeChild(element);
438                            self.el.setAttribute('width', '100%');
439                            self.el.setAttribute('height', '100%');
440                        }
441                        self.isReady = true;
442                        self.init();
443                        return true;
444                    }
445                };
446
447                if (!onLoad()) {
448                    element.addEventListener('load', onLoad);
449                }
450                break;
451
452            default:
453                throw new Error('Vivus [constructor]: "element" parameter is not valid (or miss the "file" attribute)');
454        }
455    };
456
457    /**
458     * Set up user option to the instance
459     * The method will not return anything, but will throw an
460     * error if the parameter is invalid
461     *
462     * @param  {object} options Object from the constructor
463     */
464    Vivus.prototype.setOptions = function (options) {
465        var allowedTypes = ['delayed', 'sync', 'async', 'nsync', 'oneByOne', 'scenario', 'scenario-sync'];
466        var allowedStarts =  ['inViewport', 'manual', 'autostart'];
467
468        // Basic check
469        if (options !== undefined && options.constructor !== Object) {
470            throw new Error('Vivus [constructor]: "options" parameter must be an object');
471        }
472        else {
473            options = options || {};
474        }
475
476        // Set the animation type
477        if (options.type && allowedTypes.indexOf(options.type) === -1) {
478            throw new Error('Vivus [constructor]: ' + options.type + ' is not an existing animation `type`');
479        }
480        else {
481            this.type = options.type || allowedTypes[0];
482        }
483
484        // Set the start type
485        if (options.start && allowedStarts.indexOf(options.start) === -1) {
486            throw new Error('Vivus [constructor]: ' + options.start + ' is not an existing `start` option');
487        }
488        else {
489            this.start = options.start || allowedStarts[0];
490        }
491
492        this.isIE         = (window.navigator.userAgent.indexOf('MSIE') !== -1 || window.navigator.userAgent.indexOf('Trident/') !== -1 || window.navigator.userAgent.indexOf('Edge/') !== -1 );
493        this.duration     = parsePositiveInt(options.duration, 120);
494        this.delay        = parsePositiveInt(options.delay, null);
495        this.dashGap      = parsePositiveInt(options.dashGap, 1);
496        this.forceRender  = options.hasOwnProperty('forceRender') ? !!options.forceRender : this.isIE;
497        this.reverseStack = !!options.reverseStack;
498        this.selfDestroy  = !!options.selfDestroy;
499        this.onReady      = options.onReady;
500        this.map          = [];
501        this.frameLength  = this.currentFrame = this.delayUnit = this.speed = this.handle = null;
502
503        this.ignoreInvisible = options.hasOwnProperty('ignoreInvisible') ? !!options.ignoreInvisible : false;
504
505        this.animTimingFunction = options.animTimingFunction || Vivus.LINEAR;
506        this.pathTimingFunction = options.pathTimingFunction || Vivus.LINEAR;
507
508        if (this.delay >= this.duration) {
509            throw new Error('Vivus [constructor]: delay must be shorter than duration');
510        }
511    };
512
513    /**
514     * Set up callback to the instance
515     * The method will not return enything, but will throw an
516     * error if the parameter is invalid
517     *
518     * @param  {Function} callback Callback for the animation end
519     */
520    Vivus.prototype.setCallback = function (callback) {
521        // Basic check
522        if (!!callback && callback.constructor !== Function) {
523            throw new Error('Vivus [constructor]: "callback" parameter must be a function');
524        }
525        this.callback = callback || function () {};
526    };
527
528
529    /**
530     * Core
531     **************************************
532     */
533
534    /**
535     * Map the svg, path by path.
536     * The method return nothing, it just fill the
537     * `map` array. Each item in this array represent
538     * a path element from the SVG, with informations for
539     * the animation.
540     *
541     * ```
542     * [
543     *   {
544 *     el: <DOMobj> the path element
545 *     length: <number> length of the path line
546 *     startAt: <number> time start of the path animation (in frames)
547 *     duration: <number> path animation duration (in frames)
548 *   },
549     *   ...
550     * ]
551     * ```
552     *
553     */
554    Vivus.prototype.mapping = function () {
555        var i, paths, path, pAttrs, pathObj, totalLength, lengthMeter, timePoint;
556        timePoint = totalLength = lengthMeter = 0;
557        paths = this.el.querySelectorAll('path');
558
559        for (i = 0; i < paths.length; i++) {
560            path = paths[i];
561            if (this.isInvisible(path)) {
562                continue;
563            }
564            pathObj = {
565                el: path,
566                length: Math.ceil(path.getTotalLength())
567            };
568            // Test if the path length is correct
569            if (isNaN(pathObj.length)) {
570                if (window.console && console.warn) {
571                    console.warn('Vivus [mapping]: cannot retrieve a path element length', path);
572                }
573                continue;
574            }
575            this.map.push(pathObj);
576            path.style.strokeDasharray  = pathObj.length + ' ' + (pathObj.length + this.dashGap * 2);
577            path.style.strokeDashoffset = pathObj.length + this.dashGap;
578            pathObj.length += this.dashGap;
579            totalLength += pathObj.length;
580
581            this.renderPath(i);
582        }
583
584        totalLength = totalLength === 0 ? 1 : totalLength;
585        this.delay = this.delay === null ? this.duration / 3 : this.delay;
586        this.delayUnit = this.delay / (paths.length > 1 ? paths.length - 1 : 1);
587
588        // Reverse stack if asked
589        if (this.reverseStack) {
590            this.map.reverse();
591        }
592
593        for (i = 0; i < this.map.length; i++) {
594            pathObj = this.map[i];
595
596            switch (this.type) {
597                case 'delayed':
598                    pathObj.startAt = this.delayUnit * i;
599                    pathObj.duration = this.duration - this.delay;
600                    break;
601
602                case 'oneByOne':
603                    pathObj.startAt = lengthMeter / totalLength * this.duration;
604                    pathObj.duration = pathObj.length / totalLength * this.duration;
605                    break;
606
607                case 'sync':
608                case 'async':
609                case 'nsync':
610                    pathObj.startAt = 0;
611                    pathObj.duration = this.duration;
612                    break;
613
614                case 'scenario-sync':
615                    path = pathObj.el;
616                    pAttrs = this.parseAttr(path);
617                    pathObj.startAt = timePoint + (parsePositiveInt(pAttrs['data-delay'], this.delayUnit) || 0);
618                    pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
619                    timePoint = pAttrs['data-async'] !== undefined ? pathObj.startAt : pathObj.startAt + pathObj.duration;
620                    this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
621                    break;
622
623                case 'scenario':
624                    path = pathObj.el;
625                    pAttrs = this.parseAttr(path);
626                    pathObj.startAt = parsePositiveInt(pAttrs['data-start'], this.delayUnit) || 0;
627                    pathObj.duration = parsePositiveInt(pAttrs['data-duration'], this.duration);
628                    this.frameLength = Math.max(this.frameLength, (pathObj.startAt + pathObj.duration));
629                    break;
630            }
631            lengthMeter += pathObj.length;
632            this.frameLength = this.frameLength || this.duration;
633        }
634    };
635
636    /**
637     * Interval method to draw the SVG from current
638     * position of the animation. It update the value of
639     * `currentFrame` and re-trace the SVG.
640     *
641     * It use this.handle to store the requestAnimationFrame
642     * and clear it one the animation is stopped. So this
643     * attribute can be used to know if the animation is
644     * playing.
645     *
646     * Once the animation at the end, this method will
647     * trigger the Vivus callback.
648     *
649     */
650    Vivus.prototype.drawer = function () {
651        var self = this;
652        this.currentFrame += this.speed;
653
654        if (this.currentFrame <= 0) {
655            this.stop();
656            this.reset();
657        } else if (this.currentFrame >= this.frameLength) {
658            this.stop();
659            this.currentFrame = this.frameLength;
660            this.trace();
vendor: 6,282 bytes, lines 661-853
661            if (this.selfDestroy) {
662                this.destroy();
663            }
664        } else {
665            this.trace();
666            this.handle = requestAnimFrame(function () {
667                self.drawer();
668            });
669            return;
670        }
671
672        this.callback(this);
673        if (this.instanceCallback) {
674            this.instanceCallback(this);
675            this.instanceCallback = null;
676        }
677    };
678
679    /**
680     * Draw the SVG at the current instant from the
681     * `currentFrame` value. Here is where most of the magic is.
682     * The trick is to use the `strokeDashoffset` style property.
683     *
684     * For optimisation reasons, a new property called `progress`
685     * is added in each item of `map`. This one contain the current
686     * progress of the path element. Only if the new value is different
687     * the new value will be applied to the DOM element. This
688     * method save a lot of resources to re-render the SVG. And could
689     * be improved if the animation couldn't be played forward.
690     *
691     */
692    Vivus.prototype.trace = function () {
693        var i, progress, path, currentFrame;
694        currentFrame = this.animTimingFunction(this.currentFrame / this.frameLength) * this.frameLength;
695        for (i = 0; i < this.map.length; i++) {
696            path = this.map[i];
697            progress = (currentFrame - path.startAt) / path.duration;
698            progress = this.pathTimingFunction(Math.max(0, Math.min(1, progress)));
699            if (path.progress !== progress) {
700                path.progress = progress;
701                path.el.style.strokeDashoffset = Math.floor(path.length * (1 - progress));
702                this.renderPath(i);
703            }
704        }
705    };
706
707    /**
708     * Method forcing the browser to re-render a path element
709     * from it's index in the map. Depending on the `forceRender`
710     * value.
711     * The trick is to replace the path element by it's clone.
712     * This practice is not recommended because it's asking more
713     * ressources, too much DOM manupulation..
714     * but it's the only way to let the magic happen on IE.
715     * By default, this fallback is only applied on IE.
716     *
717     * @param  {Number} index Path index
718     */
719    Vivus.prototype.renderPath = function (index) {
720        if (this.forceRender && this.map && this.map[index]) {
721            var pathObj = this.map[index],
722                newPath = pathObj.el.cloneNode(true);
723            pathObj.el.parentNode.replaceChild(newPath, pathObj.el);
724            pathObj.el = newPath;
725        }
726    };
727
728    /**
729     * When the SVG object is loaded and ready,
730     * this method will continue the initialisation.
731     *
732     * This this mainly due to the case of passing an
733     * object tag in the constructor. It will wait
734     * the end of the loading to initialise.
735     *
736     */
737    Vivus.prototype.init = function () {
738        // Set object variables
739        this.frameLength = 0;
740        this.currentFrame = 0;
741        this.map = [];
742
743        // Start
744        new Pathformer(this.el);
745        this.mapping();
746        this.starter();
747
748        if (this.onReady) {
749            this.onReady(this);
750        }
751    };
752
753    /**
754     * Trigger to start of the animation.
755     * Depending on the `start` value, a different script
756     * will be applied.
757     *
758     * If the `start` value is not valid, an error will be thrown.
759     * Even if technically, this is impossible.
760     *
761     */
762    Vivus.prototype.starter = function () {
763        switch (this.start) {
764            case 'manual':
765                return;
766
767            case 'autostart':
768                this.play();
769                break;
770
771            case 'inViewport':
772                var self = this,
773                    listener = function () {
774                        if (self.isInViewport(self.parentEl, 1)) {
775                            self.play();
776                            window.removeEventListener('scroll', listener);
777                        }
778                    };
779                window.addEventListener('scroll', listener);
780                listener();
781                break;
782        }
783    };
784
785
786    /**
787     * Controls
788     **************************************
789     */
790
791    /**
792     * Get the current status of the animation between
793     * three different states: 'start', 'progress', 'end'.
794     * @return {string} Instance status
795     */
796    Vivus.prototype.getStatus = function () {
797        return this.currentFrame === 0 ? 'start' : this.currentFrame === this.frameLength ? 'end' : 'progress';
798    };
799
800    /**
801     * Reset the instance to the initial state : undraw
802     * Be careful, it just reset the animation, if you're
803     * playing the animation, this won't stop it. But just
804     * make it start from start.
805     *
806     */
807    Vivus.prototype.reset = function () {
808        return this.setFrameProgress(0);
809    };
810
811    /**
812     * Set the instance to the final state : drawn
813     * Be careful, it just set the animation, if you're
814     * playing the animation on rewind, this won't stop it.
815     * But just make it start from the end.
816     *
817     */
818    Vivus.prototype.finish = function () {
819        return this.setFrameProgress(1);
820    };
821
822    /**
823     * Set the level of progress of the drawing.
824     *
825     * @param {number} progress Level of progress to set
826     */
827    Vivus.prototype.setFrameProgress = function (progress) {
828        progress = Math.min(1, Math.max(0, progress));
829        this.currentFrame = Math.round(this.frameLength * progress);
830        this.trace();
831        return this;
832    };
833
834    /**
835     * Play the animation at the desired speed.
836     * Speed must be a valid number (no zero).
837     * By default, the speed value is 1.
838     * But a negative value is accepted to go forward.
839     *
840     * And works with float too.
841     * But don't forget we are in JavaScript, se be nice
842     * with him and give him a 1/2^x value.
843     *
844     * @param  {number} speed Animation speed [optional]
845     */
846    Vivus.prototype.play = function (speed, callback) {
847        this.instanceCallback = null;
848
849        if (speed && typeof speed === 'function') {
850            this.instanceCallback = speed; // first parameter is actually the callback function
851            speed = null;
852        }
853        else if (speed && typeof speed !== 'number') {
854            throw new Error('Vivus [play]: invalid speed');
855        }
856        // if the first parameter wasn't the callback, check if the seconds was
857        if (callback && typeof(callback) === 'function' && !this.instanceCallback) {
858            this.instanceCallback = callback;
859        }
860
861
862        this.speed = speed || 1;
863        if (!this.handle) {
864            this.drawer();
865        }
866        return this;
867    };
868
869    /**
870     * Stop the current animation, if on progress.
871     * Should not trigger any error.
872     *
873     */
874    Vivus.prototype.stop = function () {
875        if (this.handle) {
876            cancelAnimFrame(this.handle);
877            this.handle = null;
878        }
879        return this;
880    };
881
882    /**
883     * Destroy the instance.
884     * Remove all bad styling attributes on all
885     * path tags
886     *
887     */
888    Vivus.prototype.destroy = function () {
889        this.stop();
890        var i, path;
891        for (i = 0; i < this.map.length; i++) {
892            path = this.map[i];
893            path.el.style.strokeDashoffset = null;
894            path.el.style.strokeDasharray = null;
895            this.renderPath(i);
896        }
897    };
898
899
900    /**
901     * Utils methods
902     * include methods from Codrops
903     **************************************
904     */
905
906    /**
907     * Method to best guess if a path should added into
908     * the animation or not.
909     *
910     * 1. Use the `data-vivus-ignore` attribute if set
911     * 2. Check if the instance must ignore invisible paths
912     * 3. Check if the path is visible
913     *
914     * For now the visibility checking is unstable.
915     * It will be used for a beta phase.
916     *
917     * Other improvments are planned. Like detecting
918     * is the path got a stroke or a valid opacity.
919     */
920    Vivus.prototype.isInvisible = function (el) {
921        var rect,
922            ignoreAttr = el.getAttribute('data-ignore');
923
924        if (ignoreAttr !== null) {
925            return ignoreAttr !== 'false';
926        }
927
928        if (this.ignoreInvisible) {
929            rect = el.getBoundingClientRect();
930            return !rect.width && !rect.height;
931        }
932        else {
933            return false;
934        }
935    };
936
937    /**
938     * Parse attributes of a DOM element to
939     * get an object of {attributeName => attributeValue}
940     *
941     * @param  {object} element DOM element to parse
942     * @return {object}         Object of attributes
943     */
944    Vivus.prototype.parseAttr = function (element) {
945        var attr, output = {};
946        if (element && element.attributes) {
947            for (var i = 0; i < element.attributes.length; i++) {
948                attr = element.attributes[i];
949                output[attr.name] = attr.value;
950            }
951        }
952        return output;
953    };
954
955    /**
956     * Reply if an element is in the page viewport
957     *
958     * @param  {object} el Element to observe
959     * @param  {number} h  Percentage of height
960     * @return {boolean}
961     */
962    Vivus.prototype.isInViewport = function (el, h) {
963        var scrolled   = this.scrollY(),
964            viewed       = scrolled + this.getViewportH(),
965            elBCR        = el.getBoundingClientRect(),
966            elHeight     = elBCR.height,
967            elTop        = scrolled + elBCR.top,
968            elBottom     = elTop + elHeight;
969
970        // if 0, the element is considered in the viewport as soon as it enters.
971        // if 1, the element is considered in the viewport only when it's fully inside
972        // value in percentage (1 >= h >= 0)
973        h = h || 0;
974
975        return (elTop + elHeight * h) <= viewed && (elBottom) >= scrolled;
976    };
977
978
979    /**
980     * Get the viewport height in pixels
981     *
982     * @return {integer} Viewport height
983     */
984    Vivus.prototype.getViewportH = function () {
985        var client = this.docElem.clientHeight,
986            inner = window.innerHeight;
987
988        if (client < inner) {
989            return inner;
990        }
991        else {
992            return client;
993        }
994    };
995
996    /**
997     * Get the page Y offset
998     *
999     * @return {integer} Page Y offset
1000     */
1001    Vivus.prototype.scrollY = function () {
1002        return window.pageYOffset || this.docElem.scrollTop;
1003    };
1004
1005    setupEnv = function () {
1006
1007        if (Vivus.prototype.docElem) {
1008            return;
1009        }
1010
1011        /**
1012         * Alias for document element
1013         *
1014         * @type {DOMelement}
1015         */
1016        Vivus.prototype.docElem = window.document.documentElement;
1017
1018        /**
1019         * Alias for `requestAnimationFrame` or
1020         * `setTimeout` function for deprecated browsers.
1021         *
1022         */
1023        requestAnimFrame = (function () {
1024            return (
1025                window.requestAnimationFrame       ||
1026                window.webkitRequestAnimationFrame ||
1027                window.mozRequestAnimationFrame    ||
1028                window.oRequestAnimationFrame      ||
1029                window.msRequestAnimationFrame     ||
1030                function(/* function */ callback){
1031                    return window.setTimeout(callback, 1000 / 60);
1032                }
1033            );
1034        })();
1035
1036        /**
1037         * Alias for `cancelAnimationFrame` or
1038         * `cancelTimeout` function for deprecated browsers.
1039         *
1040         */
1041        cancelAnimFrame = (function () {
1042            return (
1043                window.cancelAnimationFrame       ||
1044                window.webkitCancelAnimationFrame ||
1045                window.mozCancelAnimationFrame    ||
1046                window.oCancelAnimationFrame      ||
1047                window.msCancelAnimationFrame     ||
1048                function(id){
1049                    return window.clearTimeout(id);
1050                }
1051            );
1052        })();
1053    };
1054
1055    /**
1056     * Parse string to integer.
1057     * If the number is not positive or null
1058     * the method will return the default value
1059     * or 0 if undefined
1060     *
1061     * @param {string} value String to parse
1062     * @param {*}
1062 defaultValue Value to return if the result parsed is invalid
1063     * @return {number}
1064     *
1065     */
1066    parsePositiveInt = function (value, defaultValue) {
1067        var output = parseInt(value, 10);
1068        return (output >= 0) ? output : defaultValue;
1069    };
1070
1071
1072    if (typeof define === 'function' && define.amd) {
1073        // AMD. Register as an anonymous module.
1074        define([], function() {
1075            return Vivus;
1076        });
1077    } else if (typeof exports === 'object') {
1078        // Node. Does not work with strict CommonJS, but
1079        // only CommonJS-like environments that support module.exports,
1080        // like Node.
1081        module.exports = Vivus;
1082    } else {
1083        // Browser globals
1084        window.Vivus = Vivus;
1085    }
1086
1087}());

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.