iwmlib/lib/3rdparty/greensock/src/bonus-files-for-npm-users/GSDevTools.js

1226 lines
74 KiB
JavaScript

/*!
* VERSION: 0.1.9
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* GSDevTools is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
**/
/* eslint-disable */
import { TweenLite, _gsScope, globals, Animation, SimpleTimeline, TweenPlugin, Power2, Power3, Linear } from "gsap/TweenLite.js";
import TimelineLite from "gsap/TimelineLite.js";
import Draggable from "gsap/Draggable.js";
import CSSPlugin from "gsap/CSSPlugin.js";
import AttrPlugin from "gsap/AttrPlugin.js";
TweenPlugin.activate([CSSPlugin, AttrPlugin]); // to ensure treeshaking doesn't dump it.
_gsScope._gsDefine("GSDevTools", ["TweenLite", "core.Animation", "core.SimpleTimeline", "TimelineLite", "utils.Draggable", "plugins.CSSPlugin"], function() {
var _doc = document,
_docElement = _doc.documentElement,
_svgNS = "http://www.w3.org/2000/svg",
_domNS = "http://www.w3.org/1999/xhtml",
_idSeed = 0, //we assign an ID to each GSDevTools instance so that we can segregate the sessionStorage data accordingly.
_lookup = {},
_createElement = function(type, container, cssText) {
var element = _doc.createElementNS ? _doc.createElementNS(type === "svg" ? _svgNS : _domNS, type) : _doc.createElement(type);
if (container) {
if (typeof(container) === "string") {
container = _doc.querySelector(container);
}
container.appendChild(element);
}
if (type === "svg") {
element.setAttribute("xmlns", _svgNS);
element.setAttribute("xmlns:xlink", _domNS);
}
if (cssText) {
element.style.cssText = cssText;
}
return element;
},
_clearSelection = function() {
if (_doc.selection) {
_doc.selection.empty()
} else if (window.getSelection) {
window.getSelection().removeAllRanges();
}
},
_globalTimeline = Animation._rootTimeline,
_getChildrenOf = function(timeline, includeTimelines) {
var a = [],
cnt = 0,
tween = timeline._first;
while (tween) {
if (tween instanceof TweenLite) {
if (tween.vars.id) {
a[cnt++] = tween;
}
} else {
if (includeTimelines && tween.vars.id) {
a[cnt++] = tween;
}
a = a.concat(_getChildrenOf(tween, includeTimelines));
cnt = a.length;
}
tween = tween._next;
}
return a;
},
//eliminates any very long repeating children (direct children, not deeply nested) and returns the duration accordingly.
_getClippedDuration = function(animation, excludeRootRepeats) {
var max = 0,
repeat = Math.max(0, animation._repeat),
t = animation._first;
if (!t) {
max = animation.duration();
}
while (t) {
max = Math.max(max, t.totalDuration() > 999 ? t.endTime(false) : t._startTime + t._totalDuration / t._timeScale);
t = t._next;
}
return (!excludeRootRepeats && repeat) ? max * (repeat + 1) + (animation._repeatDelay * repeat) : max;
},
_getAnimationById = function(id) {
if (!id) {
return null;
}
if (id instanceof Animation) {
return id;
}
var a = _getChildrenOf(_globalTimeline, true),
i = a.length;
while (--i > -1) {
if (a[i].vars.id === id) {
return a[i];
}
}
},
_timeToProgress = function(time, animation, defaultValue, relativeProgress) {
var add, i, a;
if (typeof(time) === "string") {
if (time.charAt(1) === "=") {
add = parseInt(time.charAt(0) + "1", 10) * parseFloat(time.substr(2));
if (add < 0 && relativeProgress === 0) { //if something like inTime:"-=2", we measure it from the END, not the beginning
relativeProgress = 100;
}
time = (relativeProgress / 100 * animation.duration()) + add;
} else if (isNaN(time) && animation.getLabelTime && animation.getLabelTime(time) !== -1) {
time = animation.getLabelTime(time);
} else if (animation === _recordedRoot) { //perhaps they defined an id of an animation, like "myAnimation+=2"
i = time.indexOf("=");
if (i > 0) {
add = parseInt(time.charAt(i-1) + "1", 10) * parseFloat(time.substr(i+1));
time = time.substr(0, i-1);
} else {
add = 0;
}
a = _getAnimationById(time);
if (a) {
time = _getGlobalTime(a, defaultValue / 100 * a.duration()) + add;
}
}
}
time = isNaN(time) ? defaultValue : parseFloat(time);
return Math.min(100, Math.max(0, time / animation.duration() * 100));
},
_getGlobalTime = function(animation, time) {
var tl = animation;
time = time || 0;
if (tl.timeline) {
while (tl.timeline.timeline) {
time = (time / tl._timeScale) + tl._startTime;
tl = tl.timeline;
}
}
return time;
},
_addedCSS,
_createRootElement = function(element, minimal, css) {
if (!_addedCSS) {
_createElement("style", _docElement).innerHTML = '.gs-dev-tools{height:51px;bottom:0;left:0;right:0;display:block;position:fixed;overflow:visible;padding:0}.gs-dev-tools *{box-sizing:content-box;visibility:visible}.gs-dev-tools .gs-top{position:relative;z-index:499}.gs-dev-tools .gs-bottom{display:flex;align-items:center;justify-content:space-between;background-color:rgba(0,0,0,.6);height:42px;border-top:1px solid #999;position:relative}.gs-dev-tools .timeline{position:relative;height:8px;margin-left:15px;margin-right:15px;overflow:visible}.gs-dev-tools .progress-bar,.gs-dev-tools .timeline-track{height:8px;width:100%;position:absolute;top:0;left:0}.gs-dev-tools .timeline-track{background-color:#999;opacity:.6}.gs-dev-tools .progress-bar{background-color:#91e600;height:8px;top:0;width:0;pointer-events:none}.gs-dev-tools .seek-bar{width:100%;position:absolute;height:24px;top:-12px;left:0;background-color:transparent}.gs-dev-tools .in-point,.gs-dev-tools .out-point{width:15px;height:26px;position:absolute;top:-18px}.gs-dev-tools .in-point-shape{fill:#6d9900;stroke:rgba(0,0,0,.5);stroke-width:1}.gs-dev-tools .out-point-shape{fill:#994242;stroke:rgba(0,0,0,.5);stroke-width:1}.gs-dev-tools .in-point{transform:translateX(-100%)}.gs-dev-tools .out-point{left:100%}.gs-dev-tools .grab{stroke:rgba(255,255,255,.3);stroke-width:1}.gs-dev-tools .playhead{position:absolute;top:-5px;transform:translate(-50%,0);left:0;border-radius:50%;width:16px;height:16px;border:1px solid #6d9900;background-color:#91e600}.gs-dev-tools .gs-btn-white{fill:#fff}.gs-dev-tools .pause{opacity:0}.gs-dev-tools .select-animation{vertical-align:middle;position:relative;padding:6px 10px}.gs-dev-tools .select-animation-container{flex-grow:4;width:40%}.gs-dev-tools .select-arrow{display:inline-block;width:12px;height:7px;margin:0 7px;transform:translate(0,-2px)}.gs-dev-tools .select-arrow-shape{stroke:rgba(255,255,255,.6);stroke-width:2px;fill:none}.gs-dev-tools .rewind{height:16px;width:19px;padding:10px 4px;min-width:24px}.gs-dev-tools .rewind-path{opacity:.6}.gs-dev-tools .play-pause{width:24px;height:24px;padding:6px 10px;min-width:24px}.gs-dev-tools .ease{width:30px;height:30px;padding:10px;min-width:30px;display:none}.gs-dev-tools .ease-path{fill:none;stroke:rgba(255,255,255,.6);stroke-width:2px}.gs-dev-tools .ease-border{fill:rgba(255,255,255,.25)}.gs-dev-tools .time-scale{font-family:monospace;font-size:18px;text-align:center;color:rgba(255,255,255,.6);padding:4px 4px 4px 0;min-width:30px;margin-left:7px}.gs-dev-tools .loop{width:20px;padding:5px;min-width:20px}.gs-dev-tools .loop-path{fill:rgba(255,255,255,.6)}.gs-dev-tools label span{color:#fff;font-family:monospace;text-decoration:none;font-size:16px;line-height:18px}.gs-dev-tools .time-scale span{color:rgba(255,255,255,.6)}.gs-dev-tools button:focus,.gs-dev-tools select:focus{outline:0}.gs-dev-tools label{position:relative;cursor:pointer}.gs-dev-tools label.locked{text-decoration:none;cursor:auto}.gs-dev-tools label input,.gs-dev-tools label select{position:absolute;left:0;top:0;z-index:1;font:inherit;font-size:inherit;line-height:inherit;height:100%;width:100%;color:#000!important;opacity:0;background:0 0;border:none;padding:0;margin:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer}.gs-dev-tools label input+.display{position:relative;z-index:2}.gs-dev-tools .gs-bottom-right{vertical-align:middle;display:flex;align-items:center;flex-grow:4;width:40%;justify-content:flex-end}.gs-dev-tools .time-container{font-size:18px;font-family:monospace;color:rgba(255,255,255,.6);margin:0 5px}.gs-dev-tools .logo{width:32px;height:32px;position:relative;top:2px;margin:0 12px}.gs-dev-tools .gs-hit-area{background-color:transparent;width:100%;height:100%;top:0;position:absolute}.gs-dev-tools.minimal{height:auto;display:flex;align-items:stretch}.gs-dev-tools.minimal .gs-top{order:2;flex-grow:4;background-color:rgba(0,0,0,1)}.gs-dev-tools.minimal .gs-bottom{background-color:rgba(0,0,0,1);border-top:none}.gs-dev-tools.minimal .timeline{top:50%;transform:translate(0,-50%)}.gs-dev-tools.minimal .in-point,.gs-dev-tools.minimal .out-point{display:none}.gs-dev-tools.minimal .select-animation-container{display:none}.gs-dev-tools.minimal .rewind{display:none}.gs-dev-tools.minimal .play-pause{width:20px;height:20px;padding:4px 6px;margin-left:14px}.gs-dev-tools.minimal .time-scale{min-width:26px}.gs-dev-tools.minimal .loop{width:18px;min-width:18px;display:none}.gs-dev-tools.minimal .gs-bottom-right{display:none}@media only screen and (max-width:600px){.gs-dev-tools{height:auto;display:flex;align-items:stretch}.gs-dev-tools .gs-top{order:2;flex-grow:4;background-color:rgba(0,0,0,1);height:42px}.gs-dev-tools .gs-bottom{background-color:rgba(0,0,0,1);border-top:none}.gs-dev-tools .timeline{top:50%;transform:translate(0,-50%)}.gs-dev-tools .in-point,.gs-dev-tools .out-point{display:none}.gs-dev-tools .select-animation-container{display:none}.gs-dev-tools .rewind{display:none}.gs-dev-tools .play-pause{width:20px;height:20px;padding:4px 6px;margin-left:14px}.gs-dev-tools .time-scale{min-width:26px}.gs-dev-tools .loop{width:18px;min-width:18px;display:none}.gs-dev-tools .gs-bottom-right{display:none}}';
_addedCSS = true;
}
if (typeof(element) === "string") {
element = document.querySelector(element);
}
var root = _createElement("div", element || _docElement.getElementsByTagName("body")[0] || _docElement);
root.setAttribute("class", "gs-dev-tools" + (minimal ? " minimal" : ""));
root.innerHTML = '<div class=gs-hit-area></div><div class=gs-top><div class=timeline><div class=timeline-track></div><div class=progress-bar></div><div class=seek-bar></div><svg class=in-point viewBox="0 0 15 26"xmlns=http://www.w3.org/2000/svg><polygon class=in-point-shape points=".5 .5 14.5 .5 14.5 25.5 .5 17.5"/><polyline class=grab points="5.5 4 5.5 15"/><polyline class=grab points="9.5 4 9.5 17"/></svg> <svg class=out-point viewBox="0 0 15 26"xmlns=http://www.w3.org/2000/svg><polygon class=out-point-shape points=".5 .5 14.5 .5 14.5 17.5 .5 25.5"/><polyline class=grab points="5.5 4 5.5 17"/><polyline class=grab points="9.5 4 9.5 15"/></svg><div class=playhead></div></div></div><div class=gs-bottom><div class=select-animation-container><label class=select-animation><select class=animation-list><option>Global Timeline<option>myTimeline</select><nobr><span class="display animation-label">Global Timeline</span> <svg class=select-arrow viewBox="0 0 12.05 6.73"xmlns=http://www.w3.org/2000/svg><polyline class=select-arrow-shape points="0.35 0.35 6.03 6.03 11.7 0.35"/></svg></nobr></label></div><svg class=rewind viewBox="0 0 12 15.38"xmlns=http://www.w3.org/2000/svg><path d=M0,.38H2v15H0Zm2,7,10,7.36V0Z class="gs-btn-white rewind-path"/></svg> <svg class=play-pause viewBox="0 0 20.97 25.67"xmlns=http://www.w3.org/2000/svg><g class=play><path d="M8,4.88 C8,10.18 8,15.48 8,20.79 5.33,22.41 2.66,24.04 0,25.67 0,17.11 0,8.55 0,0 2.66,1.62 5.33,3.25 8,4.88"class="gs-btn-white play-1"style=stroke:#fff;stroke-width:.6px /><path d="M14.485,8.855 C16.64,10.18 18.8,11.5 20.97,12.83 16.64,15.48 12.32,18.13 8,20.79 8,15.48 8,10.18 8,4.88 10.16,6.2 12.32,7.53 14.48,8.85"class="gs-btn-white play-2"style=stroke:#fff;stroke-width:.6px /></g></svg> <svg class=loop viewBox="0 0 29 25.38"xmlns=http://www.w3.org/2000/svg><path d=M27.44,5.44,20.19,0V3.06H9.06A9.31,9.31,0,0,0,0,12.41,9.74,9.74,0,0,0,.69,16l3.06-2.23a6,6,0,0,1-.12-1.22,5.49,5.49,0,0,1,5.43-5.5H20.19v3.81Z class=loop-path /><path d=M25.25,11.54a5.18,5.18,0,0,1,.12,1.12,5.41,5.41,0,0,1-5.43,5.41H9.19V14.5L1.94,19.94l7.25,5.44V22.06H19.94A9.2,9.2,0,0,0,29,12.84a9.42,9.42,0,0,0-.68-3.53Z class=loop-path /></svg> <svg class=ease viewBox="0 0 25.67 25.67"xmlns=http://www.w3.org/2000/svg><path d=M.48,25.12c1.74-3.57,4.28-12.6,8.8-10.7s4.75,1.43,6.5-1.11S19.89,1.19,25.2.55 class=ease-path /><path d=M24.67,1V24.67H1V1H24.67m1-1H0V25.67H25.67V0Z class=ease-border /></svg><label class=time-scale><select><option value=10>10x<option value=5>5x<option value=2>2x<option value=1 selected>1x<option value=0.5>0.5x<option value=0.25>0.25x<option value=0.1>0.1x</select><span class="display time-scale-label">1x</span></label><div class=gs-bottom-right><div class=time-container><span class=time>0.00</span> / <span class=duration>0.00</span></div><a href="https://greensock.com/docs/Utilities/GSDevTools?source=GSDevTools"target=_blank title=Docs><svg class=logo viewBox="0 0 100 100"xmlns=http://www.w3.org/2000/svg><path d="M60 15.4c-.3-.4-.5-.6-.5-.7.1-.6.2-1 .2-1.7v-.4c.6.6 1.3 1.3 1.8 1.7.2.2.5.3.8.3.2 0 .3 0 .5.1h1.6c.8 0 1.6.1 2 0 .1 0 .2 0 .3-.1.6-.3 1.4-1 2.1-1.6 0 .6.1 1.2.1 1.7v1.5c0 .3 0 .5.1.7-.1.1-.2.1-.4.2-.7.4-1.7 1-2.3.9-.5-.1-1.5-.3-2.6-.7-1.2-.3-2.4-.8-3.2-1.2 0 0-.1 0-.1-.1s-.2-.4-.4-.6zm24.6 21.9c-.5-1.7-1.9-2-4.2-.7.9-1.5 2.1-1.5 2.3-2.1.9-2.5-.6-4.6-1.2-5.3.7-1.8 1.4-4.5-1-6.8-1-1-2.4-1.2-3.6-1.1 1.8 1.7 3.4 4.4 2.5 7.2-.1.3-.9.7-1.7 1 0 0 .4 2-.3 3.5-.3.6-.8 1.5-1.3 2.6 1 .9 1.6 1 3 1.3-.9.1-1.2.4-1.2.5-.7 3 1 3.4 1.4 4.8 0 .1 0 .2.1.3v.4c-.3.3-1.4.5-2.5.5s-1.8 1-1.8 1c-.2.1-.3.3-.4.4v1c0 .1 0 .4.1.6.1.5.3 1.3.4 1.8.9.6 1.4.9 2.2 1.1.5.1 1 .2 1.5.1.3-.1.7-.3 1-.7 1.5-1.7 1.9-3.2 2.2-4.1 0-.1 0-.2.1-.2 0 .1.1.1.1.2 0 0 .1-.1.1-.2l.1-.1c1.3-1.6 2.9-4.5 2.1-7zM74.3 49.9c-.1-.3-.1-.7-.2-1.1v-.2c-.1-.2-.1-.4-.2-.6 0-.1-.1-.3-.1-.5s-.1-.5-.1-.7v-.1c0-.2-.1-.5-.1-.7-.1-.3-.1-.7-.2-1.1v-.1c0-.2 0-.3-.1-.5v-.9c0-.1 0-.2.1-.3V43h-.3c-1.1.1-3.8.4-6.7.2-1.2-.1-2.4-.3-3.6-.6-1-.3-1.8-.5-2.3-.7-1.2-.4-1.6-.6-1.8-.7 0 .2-.1.4-.1.7 0 .3-.1.5-.1.8-.1.2-.1.4-.2.6l.1.1c.5.5 1.5 1.3 1.5 2.1v.2c-.1.4-.4.5-.8.9-.1.1-.6.7-1.1 1.1l-.6.6c-.1 0-.1.1-.2.1-.1.1-.3.2-.4.3-.2.1-.7.5-.8.6-.1.1-.2.1-.3.1-2.8 8.8-2.2 13.5-1.5 16.1.1.5.3 1 .4 1.3-.4.5-.8 1-1.2 1.4-1.2 1.5-2 2.6-2.6 4.2 0 .1 0 .1-.1.2 0 .1 0 .2-.1.2-.2.5-.3 1-.4 1.5-.6 2.3-.8 4.5-.9 6.6-.1 2.4-.2 4.6-.5 6.9.7.3 3.1.9 4.7.6.2-.1 0-3.9.6-5.7l.6-1.5c.4-.9.9-1.9 1.3-3.1.3-.7.5-1.5.7-2.4.1-.5.2-1 .3-1.6V74v-.1c.1-.6.1-1.3.1-2 0-.2-.7.3-1.1.9.3-1.8 1.3-2.1 2-3.2.3-.5.6-1.1.6-2 2.5-1.7 4-3.7 5-5.7.2-.4.4-.9.6-1.4.3-.8.5-1.6.7-2.4.3-1.4.8-3.2 1.2-4.8v-.1c.4-1.2.8-2.2 1.2-2.6-.2.9-.4 1.7-.6 2.5v.2c-.6 3.5-.7 6.2-2 9.2 1 2.6 1.9 3.9 2 7.6-2 0-3.2 1.6-3.7 3.2 1.2.3 3.9.7 8.3.1h.3c.1-.5.3-1.1.5-1.5.3-.8.5-1.5.6-2.2.2-1.3.1-2.4 0-3.2 3.9-3.7 2.6-11 1.6-16.6zm.3-15.1c.1-.3.2-.6.4-.8.2-.3.3-.7.5-1 .1-.3.3-.6.4-.9.5-1.5.4-2.8.3-3.5-.1 0-.1-.1-.2-.1-.5-.2-.9-.4-1.4-.6-.1 0-.2-.1-.3-.1-3.8-1.2-7.9-.9-11.9.1-1 .2-1.9.5-2.9.1-2.3-.8-3.9-1.9-4.6-2.8l-.2-.2c-.1.2-.2.4-.4.6.2 2.3-.5 3.9-1.4 5.1.9 1.2 2.6 2.8 3.6 3.4 1.1.6 1.7.7 3.4.4-.6.7-1.1 1-1.9 1.4.1.7.2 2 .5 3.4.3.3 1.2.8 2.3 1.3.5.3 1.1.5 1.7.7.8.3 1.7.6 2.4.8.1 0 .2.1.3.1.5.1 1.1.2 1.8.2h.9c2.1 0 4.5-.2 5.4-.3h.1c-.1-2.7.2-4.6.7-6.2.2-.3.4-.7.5-1.1zm-23.2 9.3v.2c-.3 1.7.5 2.4 1.9 3.4.6.5 0 .5.5.8.3.2.7.3 1 .3.3 0 .5 0 .8-.1.2-.1.4-.3.6-.5.1-.1.3-.2.5-.4.3-.2.6-.5.7-.6.1-.1.2-.1.3-.2.2-.2.5-.5.6-.7.2-.2.4-.5.5-.7 0-.1.1-.1.1-.1v-.1c.1-.4-.3-.8-.8-1.3-.2-.2-.4-.3-.5-.5-.3-.3-.6-.5-1-.7-.9-.5-1.9-.7-3-.7l-.3-.3c-2.2-2.5-3.2-4.8-3.9-6.5-.9-2.1-1.9-3.3-3.9-4.9 1 .4 1.8.8 2.3 1.1.5.4 1.3.4 1.9.2.2-.1.5-.2.7-.3.2-.1.4-.2.6-.4 1.6-1.3 2.5-3.8 2.6-5.6v-.1c.2-.3.6-1.1.8-1.4l.1.1c.1.1.3.2.6.5.1 0 .1.1.2.1.1.1.2.1.2.2.8.6 1.9 1.3 2.6 1.7 1.4.7 2.3.7 5.3-.1 2.2-.6 4.8-.8 6.8-.8 1.4 0 2.7.3 4 .7.2.1.4.1.5.2.3.1.6.2.9.4 0 0 .1 0 .1.1.8.4 2.1 1.2 2.5-.3.1-2-.6-3.9-1.6-5.3 0 0-.1 0-.1-.1-.1-.1-.2-.2-.4-.3-.1-.1-.2-.1-.3-.2-.1-.1-.2-.2-.4-.2-.6-.4-1.2-.8-1.6-.9-.1-.1-.3-.1-.4-.2h-.1-.1c-.1 0-.3-.1-.4-.1-.1 0-.1 0-.2-.1h-.1l-.2-.4c-.2-.1-.4-.2-.5-.2h-.6c-.3 0-.5.1-.7.1-.7.1-1.2.3-1.7.4-.2 0-.3.1-.5.1-.5.1-1 .2-1.6.2-.4 0-.9-.1-1.5-.2-.4-.1-.8-.2-1.1-.3-.2-.1-.4-.1-.6-.2-.6-.2-1.1-.3-1.7-.4h-.2-1.8c-.3 0-.6.1-1 .1H57.9c-.8 0-1.5 0-2.3-.1-.2 0-.5-.1-.7-.1-.5-.1-.9-.2-1.3-.4-.2-.1-.3-.1-.4-.2-.1 0-.2 0-.2-.1-.3-.1-.6-.1-.9-.1H51h-.1c-.4 0-.9.1-1.4.2-1.1.2-2.1.6-3 1.3-.3.2-.6.5-.8.8-.1.1-.2.2-.2.3-.4.6-.8 1.2-.9 2 0 .2-.1.4-.1.6 0 .2 1.7.7 2.3 2.8-.8-1.2-2.3-2.5-4.1-1.4-1.5 1-1.1 3.1-2.4 5.4-.3.5-.6.9-1 1.4-.8 1-.7 2.1.2 4.4 1.4 3.4 7.6 5.3 11.5 8.3l.4.4zm8.7-36.3c0 .6.1 1 .2 1.6v.1c0 .3.1.6.1.9.1 1.2.4 2 1 2.9 0 .1.1.1.1.2.3.2.5.3.8.4 1.1.2 3.1.3 4.2 0 .2-.1.5-.3.7-.5.4-.4.7-1.1.9-1.7.1-.7.3-1.3.4-1.8 0-.2.1-.4.1-.5v-.1c0-.2 0-.3.1-.5.2-.7.2-2.4.3-2.8.1-.7 0-1.8-.1-2.5 0-.2-.1-.4-.1-.5v-.1c-.2-.5-1.4-1.4-4.3-1.4-3.1 0-4 1-4.1 1.5v.1c0 .1 0 .3-.1.5-.1.4-.2 1.4-.2 1.9v2.3zm-6 88.6c0-.1-.1-.2-.1-.3-.7-1.5-1.1-3.5-1.3-4.6.4.1.7.6.8.3.2-.5-.4-1.5-.5-2.2v-.1c-.5-.5-4-.5-3.7-.3-.4.8-1 .6-1.3 2.1-.1.7.8.1 1.7.1-1.4.9-3 2.1-3.4 3.2-.1.1-.1.2-.1.3 0 .2-.1.4-.1.5-.1 1.2.5 1.6 2 2.4H48.4c1.4.3 3 .3 4.3.3 1.2-.2 1.6-.7 1.6-1.4-.2-.1-.2-.2-.2-.3z"style=fill:#efefef /><path d="M56.1 36.5c.3 1.4.5 2.4.8 4.2h-.2c-.1.5-.1.9-.1 1.3-1-.4-2.2-.5-2.6-.5-3.7-4.4-2.9-6.1-4.4-8.3.4-.2 1-.4 1.5-.8 1.6 1.9 3.3 3 5 4.1zm-1.7 13.2s-1.4 0-2.3-1c0 0-.1-.5.1-.7 0 0-1.2-1-1.5-1.7-.2-.5-.3-1.1-.2-1.6-4.4-3.7-10.9-4.2-12.9-9.1-.5-1.2-1.3-2.9-.9-3.9-.3.1-.5.2-.8.3-2.9.9-11.7 5.3-17.9 8.8 1.6 1.7 2.6 4.3 3.2 7.2l.3 1.5c.1.5.1 1 .2 1.5.1 1.4.4 2.7.8 3.9.2.8.6 1.5.9 2.2.6 1 1.2 1.9 2.1 2.6.6.5 1.2.9 1.9 1.3 2.1 1.1 5 1.6 8.6 1.5H37.9c.5 0 1 .1 1.5.1h.1c.4.1.9.1 1.3.2h.2c.4.1.9.2 1.3.4h.1c.4.1.8.3 1.1.5h.1c.4.2.7.4 1.1.6h.1c.7.4 1.3.9 1.9 1.5l.1.1c.6.5 1.1 1.1 1.5 1.8 0 .1.1.1.1.2s.1.1.1.2c.4.6 1.2 1.1 1.9 1.3.7-.9 1.5-1.8 2.2-2.8-1.6-6 0-11.7 1.8-16.9zm-26-15.9c5-2.4 9-4.1 9.9-4.5.3-.6.6-1.4.9-2.6.1-.3.2-.5.3-.8 1-2.7 2.7-2.8 3.5-3v-.2c.1-1.1.5-2 1-2.8-8.8 2.5-18 5.5-28 11.7-.1.1-.2.2-.4.2C11.3 34.5 3 40.3 1.3 51c2.4-2.7 6-5.6 10.5-8.5.1-.1.3-.2.5-.3.2-.1.5-.3.7-.4 1.2-.7 2.4-1.4 3.6-2.2 2.2-1.2 4.5-2.4 6.7-3.5 1.8-.8 3.5-1.6 5.1-2.3zm54.9 61.3l-.3-.3c-.8-.6-4.1-1.2-5.5-2.3-.4-.3-1.1-.7-1.7-1.1-1.6-.9-3.5-1.8-3.5-2.1v-.1c-.2-1.7-.2-7 .1-8.8.3-1.8.7-4.4.8-5.1.1-.6.5-1.2.1-1.2h-.4c-.2 0-.4.1-.8.1-1.5.3-4.3.6-6.6.4-.9-.1-1.6-.2-2-.3-.5-.1-.7-.2-.9-.3H62.3c-.4.5 0 2.7.6 4.8.3 1.1.8 2 1.2 3 .3.8.6 1.8.8 3.1 0 .2.1.4.1.7.2 2.8.3 3.6-.2 4.9-.1.3-.3.6-.4 1-.4.9-.7 1.7-.6 2.3 0 .2.1.4.1.5.2.4.6.7 1.2.8.2 0 .3.1.5.1.3 0 .6.1.9.1 3.4 0 5.2 0 8.6.4 2.5.4 3.9.6 5.1.5.4 0 .9-.1 1.4-.1 1.2-.2 1.8-.5 1.9-.9-.1.2-.1.1-.2-.1zM60.2 16.4zm-.5 1.7zm3.8.5c.1 0 .3.1.5.1.4.1.7.2 1.2.3.3.1.6.1.9.1h1.3c.3-.1.7-.1 1-.2.7-.2 1.5-.4 2.7-.6h.3c.3 0 .6.1.9.3.1.1.2.1.4.2.3.2.8.2 1.2.4h.1c.1 0 .1.1.2.1.6.3 1.3.7 1.9 1.1l.3.3c.9-.1 1.6-.2 2.1-.2h.1c-.2-.4-.3-1.3-1.8-.6-.6-.7-.8-1.3-2.1-.9-.1-.2-.2-.3-.3-.4l-.1-.1c-.1-.1-.2-.3-.3-.4 0-.1-.1-.1-.1-.2-.2-.3-.5-.5-.9-.7-.7-.4-1.5-.6-2.3-.5-.2 0-.4.1-.6.2-.1 0-.2.1-.2.1-.1 0-.2.1-.3.2-.5.3-1.3.8-2.1 1-.1 0-.1 0-.2.1-.2 0-.4.1-.5.1H66.5h-.1c-.4-.1-1.1-.2-2-.5-.1 0-.2-.1-.3-.1-.9-.2-1.8-.5-2.7-.8-.3-.1-.7-.2-1-.3-.1 0-.1 0-.2-.1h-.1s-.1 0-.1-.1c-.3-.3-.7-.6-1.3-.8-.5-.2-1.2-.4-2.1-.5-.2 0-.5 0-.7.1-.4.2-.8.6-1.2.9.1.1.3.3.4.5.1.2.2.4.3.7l-.6-.6c-.5-.4-1.1-.8-1.7-.9-.8-.2-1.4.4-2.3.9 1 0 1.8.1 2.5.4.1 0 .1 0 .2.1h.1c.1 0 .2.1.3.1.9.4 1.8.6 2.7.6h1.3c.5 0 .8-.1 1.1-.1.1 0 .4 0 .7-.1h2.2c.4.4.9.6 1.6.8z"style=fill:#88ce02 /><path d="M100 51.8c0-19.5-12.5-36.1-30-42.1.1-1.2.2-2.4.3-3.1.1-1.5.2-3.9-.5-4.9-1.6-2.3-9.1-2.1-10.5-.1-.4.6-.7 3.6-.6 5.9-1.1-.1-2.2-.1-3.3-.1-16.5 0-30.9 9-38.6 22.3-2.4 1.4-4.7 2.8-6.1 4C5.4 38 2.2 43.2 1 47c-1.6 4.7-1.1 7.6.4 5.8 1.2-1.5 6.6-5.9 10.1-8.2-.4 2.3-.6 4.8-.6 7.2 0 21 14.5 38.5 34 43.3-.1 1.1.1 2 .7 2.6.9.8 3.2 2 6.4 1.6 2.9-.3 3.5-.5 3.2-2.9h.2c2.7 0 5.3-.2 7.8-.7.1.1.2.2.4.3 1.5 1 7.1.8 9.6.7s6.2.9 8.6.5c2.9-.5 3.4-2.3 1.6-3.2-1.5-.8-3.8-1.3-6.7-3.1C90.6 83.4 100 68.7 100 51.8zM60.1 5.5c0-.5.1-1.5.2-2.1 0-.2 0-.4.1-.5v-.1c.1-.5 1-1.5 4.1-1.5 2.9 0 4.2.9 4.3 1.4v.1c0 .1 0 .3.1.5.1.8.2 1.9.1 2.7 0 .5-.1 2.1-.2 2.9 0 .1 0 .3-.1.5v.1c0 .2-.1.3-.1.5-.1.5-.2 1.1-.4 1.8-.1.6-.5 1.2-.9 1.7-.2.3-.5.5-.7.5-1.1.3-3.1.3-4.2 0-.3-.1-.5-.2-.8-.4 0-.1-.1-.1-.1-.2-.6-.9-.9-1.7-1-2.9 0-.4-.1-.6-.1-.9v-.1c-.1-.6-.2-1-.2-1.6v-.3c-.1-1.3-.1-2.1-.1-2.1zm-.4 7.5v-.4c.6.6 1.3 1.3 1.8 1.7.2.2.5.3.8.3.2 0 .3 0 .5.1h1.6c.8 0 1.6.1 2 0 .1 0 .2 0 .3-.1.6-.3 1.4-1 2.1-1.6 0 .6.1 1.2.1 1.7v1.5c0 .3 0 .5.1.7-.1.1-.2.1-.4.2-.7.4-1.7 1-2.3.9-.5-.1-1.5-.3-2.6-.7-1.2-.3-2.4-.8-3.2-1.2 0 0-.1 0-.1-.1-.2-.3-.4-.5-.6-.7-.3-.4-.5-.6-.5-.7.3-.4.4-.9.4-1.6zm.5 3.4zm-7.3-.3c.6.1 1.2.5 1.7.9.2.2.5.4.6.6-.1-.2-.2-.5-.3-.7-.1-.2-.3-.4-.4-.5.4-.3.8-.7 1.2-.9.2-.1.4-.1.7-.1.9.1 1.6.2 2.1.5.6.2 1 .5 1.3.8 0 0 .1 0 .1.1h.1c.1 0 .1 0 .2.1.3.1.6.2 1 .3.9.3 1.9.6 2.7.8.1 0 .2.1.3.1.9.2 1.6.4 2 .5h.4c.2 0 .4 0 .5-.1.1 0 .1 0 .2-.1.7-.2 1.5-.7 2.1-1 .1-.1.2-.1.3-.2.1 0 .2-.1.2-.1.2-.1.4-.2.6-.2.8-.2 1.7.1 2.3.5.3.2.6.4.9.7 0 .1.1.1.1.2.1.2.2.3.3.4l.1.1c.1.1.2.2.3.4 1.3-.4 1.5.2 2.1.9 1.6-.7 1.7.2 1.8.6h-.1c-.5 0-1.2 0-2.1.2l-.3-.3c-.5-.4-1.2-.8-1.9-1.1-.1 0-.1-.1-.2-.1h-.1c-.4-.2-.8-.2-1.2-.4-.1-.1-.2-.1-.4-.2-.3-.1-.6-.3-.9-.3h-.3c-1.2.1-2 .4-2.7.6-.3.1-.7.2-1 .2-.4.1-.8.1-1.3 0-.3 0-.6-.1-.9-.1-.5-.1-.8-.2-1.2-.3-.2 0-.3-.1-.5-.1h-.1c-.6-.2-1.2-.3-1.8-.4h-.1-2.1c-.4.1-.6.1-.7.1-.3 0-.7.1-1.1.1h-1.3c-.9 0-1.9-.2-2.7-.6-.1 0-.2-.1-.3-.1H53c-.1 0-.1 0-.2-.1-.7-.3-1.6-.4-2.5-.4 1.2-.8 1.8-1.4 2.6-1.3zm6.8 2zm-15.2 4.1c.1-.7.4-1.4.9-2 .1-.1.2-.2.2-.3l.8-.8c.9-.6 1.9-1.1 3-1.3.5-.1 1-.2 1.4-.2H52c.3 0 .6.1.9.1.1 0 .2 0 .2.1.1.1.2.1.4.2.4.2.8.3 1.3.4.2 0 .5.1.7.1.7.1 1.5.1 2.3.1H58.7c.4 0 .7-.1 1-.1H61.7c.6.1 1.1.2 1.7.4.2 0 .4.1.6.2.3.1.7.2 1.1.3.6.1 1.1.2 1.5.2.6 0 1.1-.1 1.6-.2.2 0 .3-.1.5-.1.5-.1 1-.3 1.7-.4.2 0 .5-.1.7-.1h.6c.2 0 .4.1.5.2l.1.1h.1c.1 0 .1 0 .2.1.2.1.3.1.4.1h.2c.1.1.3.1.4.2.4.2 1 .6 1.6.9.1.1.2.2.4.2.1.1.2.1.3.2.2.1.3.3.4.3l.1.1c1.1 1.4 1.8 3.3 1.6 5.3-.3 1.5-1.6.7-2.5.3 0 0-.1 0-.1-.1-.3-.1-.6-.2-.9-.4-.2-.1-.4-.1-.5-.2-1.2-.4-2.5-.7-4-.7-2 0-4.6.1-6.8.8-3 .8-4 .8-5.3.1-.8-.4-1.8-1.1-2.6-1.7-.1-.1-.2-.1-.2-.2-.1-.1-.1-.1-.2-.1-.3-.2-.6-.4-.6-.5l-.1-.1c-.2.3-.6 1-.8 1.4v.1c-.1 1.7-1 4.2-2.6 5.6-.2.1-.4.3-.6.4-.2.1-.5.2-.7.3-.7.2-1.4.2-1.9-.2-.5-.3-1.3-.7-2.3-1.1 2 1.6 3 2.8 3.9 4.9.7 1.7 1.7 4 3.9 6.5l.3.3c1.1 0 2.1.2 3 .7.4.2.7.4 1 .7.2.2.4.3.5.5.5.4.9.8.8 1.3v.1s0 .1-.1.1c-.1.2-.3.5-.5.7-.1.1-.4.4-.6.7-.1.1-.2.2-.3.2-.1.1-.4.3-.7.6-.2.2-.4.3-.5.4-.2.1-.4.4-.6.5-.3.1-.5.2-.8.1-.3 0-.7-.2-1-.3-.5-.3.1-.3-.5-.8-1.4-1-2.2-1.7-1.9-3.4v-.2c-.2-.1-.3-.3-.5-.4-3.9-3-10.1-4.9-11.5-8.3-.9-2.3-1-3.4-.2-4.4.4-.5.8-1 1-1.4 1.3-2.3.9-4.4 2.4-5.4 1.8-1.2 3.3.2 4.1 1.4-.5-2.1-2.3-2.6-2.3-2.8.3.1.3-.1.3-.3zm29 20s-.1 0 0 0c-.1 0-.1 0 0 0-.9.1-3.3.3-5.4.3h-.9c-.7 0-1.3-.1-1.8-.2-.1 0-.2 0-.3-.1-.7-.2-1.6-.5-2.4-.8-.6-.2-1.2-.5-1.7-.7-1.1-.5-2.1-1.1-2.3-1.3-.5-1.4-.7-2.7-.7-3.4.8-.4 1.3-.7 1.9-1.4-1.7.3-2.4.2-3.4-.4-1-.5-2.6-2.2-3.6-3.4 1-1.2 1.7-2.9 1.4-5.1.1-.2.3-.4.4-.6 0 .1.1.1.2.2.7.9 2.4 2 4.6 2.8 1.1.4 2 .1 2.9-.1 4-1 8.1-1.3 11.9-.1.1 0 .2.1.3.1.5.2.9.4 1.4.6.1 0 .1.1.2.1.1.7.2 2-.3 3.5-.1.3-.2.6-.4.9-.2.3-.3.6-.5 1-.1.3-.2.5-.4.8-.2.4-.3.8-.5 1.3-.4 1.4-.7 3.4-.6 6zm-23.9-9c.4-.2 1-.4 1.5-.8 1.6 1.8 3.3 3 5 4.1.3 1.4.5 2.4.8 4.2h-.2c-.1.5-.1.9-.1 1.3-1-.4-2.2-.5-2.6-.5-3.7-4.3-3-6-4.4-8.3zm-32.9 6.5c-1.3.7-2.5 1.4-3.6 2.2-.2.1-.5.3-.7.4-.1.1-.3.2-.5.3-4.5 2.9-8.1 5.8-10.5 8.5 1.7-10.8 10-16.5 14.3-19.2.1-.1.2-.2.4-.2 10-6.2 19.2-9.2 28-11.7-.5.8-.9 1.7-1 2.8v.2c-.8.1-2.5.2-3.5 3-.1.2-.2.5-.3.8-.3 1.2-.6 2-.9 2.6-.9.4-5 2.2-9.9 4.5-1.6.8-3.3 1.6-5 2.4-2.3 1-4.6 2.2-6.8 3.4zm28 24.8s0-.1 0 0c-.4-.3-.8-.5-1.2-.7h-.1c-.4-.2-.7-.3-1.1-.5h-.1c-.4-.1-.8-.3-1.3-.4h-.2c-.4-.1-.8-.2-1.3-.2h-.1c-.5-.1-1-.1-1.5-.1H35.9c-3.7.1-6.5-.4-8.6-1.5-.7-.4-1.4-.8-1.9-1.3-.9-.7-1.5-1.6-2.1-2.6-.4-.7-.7-1.4-.9-2.2-.4-1.2-.6-2.5-.8-3.9 0-.5-.1-1-.2-1.5l-.3-1.5c-.6-2.9-1.6-5.5-3.2-7.2 6.3-3.5 15-7.9 17.8-8.8.3-.1.6-.2.8-.3-.3 1.1.4 2.7.9 3.9 2.1 4.9 8.6 5.4 12.9 9.1 0 .5 0 1.1.2 1.6.5.6 1.7 1.6 1.7 1.6-.2.2-.1.7-.1.7.9 1 2.3 1 2.3 1-1.8 5.2-3.4 10.9-1.9 16.9-.7 1-1.5 1.8-2.2 2.8-.7-.2-1.4-.6-1.9-1.3 0-.1-.1-.1-.1-.2s-.1-.1-.1-.2l-1.5-1.8-.1-.1c-.5-.4-1.2-.9-1.9-1.3zm7.9 33.6c-1.3.1-2.9 0-4.3-.3h-.2-.1c-1.5-.8-2.1-1.2-2-2.4 0-.2 0-.3.1-.5 0-.1.1-.2.1-.3.5-1.1 2.1-2.2 3.4-3.2-.8 0-1.8.7-1.7-.1.2-1.5.9-1.3 1.3-2.1-.2-.3 3.3-.2 3.8.3v.1c0 .7.7 1.7.5 2.2-.1.3-.4-.2-.8-.3.2 1.1.6 3.1 1.3 4.6.1.1.1.2.1.3 0 .1.1.2.1.3 0 .7-.4 1.2-1.6 1.4zM59 67.7c0 .9-.3 1.6-.6 2-.7 1.1-1.7 1.4-2 3.2.4-.6 1.1-1.1 1.1-.9 0 .8-.1 1.4-.1 2v.2c-.1.6-.2 1.1-.3 1.6-.2.9-.5 1.7-.7 2.4-.4 1.2-.9 2.1-1.3 3.1l-.6 1.5c-.6 1.7-.4 5.6-.6 5.7-1.6.3-4.1-.3-4.7-.6.3-2.2.4-4.5.5-6.9.1-2.1.3-4.3.9-6.6.1-.5.3-1 .4-1.5 0-.1 0-.2.1-.2 0-.1 0-.1.1-.2.5-1.6 1.4-2.7 2.6-4.2.4-.4.7-.9 1.2-1.4-.1-.4-.2-.8-.4-1.3-.7-2.6-1.3-7.3 1.5-16.1.1 0 .2-.1.3-.1.2-.1.7-.5.8-.6.1-.1.3-.2.4-.3.1 0 .1-.1.2-.1l.6-.6 1.1-1.1c.4-.4.7-.5.8-.9v-.2c0-.8-1.1-1.5-1.5-2.1l-.1-.1c.1-.2.1-.4.2-.6 0-.2.1-.5.1-.8 0-.2.1-.5.1-.7.1.1.6.4 1.8.7.6.2 1.3.4 2.3.7 1.1.3 2.4.5 3.6.6 2.9.2 5.6 0 6.7-.2h.3v.1c0 .1 0 .2-.1.3v.9c0 .2 0 .3.1.5v.1c0 .4.1.7.2 1.1 0 .3.1.5.1.7v.1c0 .3.1.5.1.7 0 .2.1.3.1.5.1.2.1.4.2.6v.2c.1.4.2.8.2 1.1 1 5.7 2.3 12.9-1.1 16.7.2.8.3 1.9 0 3.2-.1.7-.3 1.4-.6 2.2-.2.5-.3 1-.5 1.5h-.3c-4.5.6-7.1.2-8.3-.1.5-1.6 1.7-3.3 3.7-3.2-.1-3.7-1.1-5-2-7.6 1.3-3 1.3-5.7 2-9.2v-.2c.2-.8.3-1.6.6-2.5-.4.5-.8 1.5-1.2 2.6v.1c-.5 1.5-.9 3.4-1.2 4.8-.2.8-.4 1.6-.7 2.4-.2.5-.4.9-.6 1.4-1.5 1.9-3 3.9-5.5 5.6zm18.5 24.9c1.5 1.1 4.7 1.8 5.5 2.3l.3.3c.1.1.1.2.1.3-.1.4-.7.7-1.9.9-.5.1-.9.1-1.4.1-1.3 0-2.6-.2-5.1-.5-3.4-.5-5.2-.4-8.6-.4-.3 0-.6 0-.9-.1-.2 0-.4-.1-.5-.1-.6-.2-1-.5-1.2-.8-.1-.2-.1-.3-.1-.5-.1-.7.2-1.5.6-2.3.2-.4.3-.7.4-1 .5-1.3.4-2.1.2-4.9 0-.2-.1-.4-.1-.7-.2-1.3-.5-2.3-.8-3.1-.4-1.1-.9-1.9-1.2-3-.6-2.1-1-4.3-.6-4.8H62.5c.2.1.5.2.9.3.5.1 1.1.2 2 .3 2.2.2 5.1-.2 6.6-.4.3-.1.6-.1.8-.1h.4c.4 0 .1.6-.1 1.2-.1.7-.5 3.3-.8 5.1-.3 1.8-.2 7.1-.1 8.8v.1c0 .3 1.9 1.2 3.5 2.1.7.2 1.4.5 1.8.9zm4.8-48.2c0 .1 0 .1 0 0-.1.1-.2.2-.2.3 0-.1-.1-.1-.1-.2 0 .1 0 .2-.1.2-.2.9-.6 2.4-2.2 4.1-.4.4-.7.6-1 .7-.5.1-.9 0-1.5-.1-.9-.2-1.3-.6-2.2-1.1-.1-.6-.3-1.3-.4-1.8 0-.3-.1-.5-.1-.6v-1l.4-.4s.7-1 1.8-1 2.2-.2 2.5-.5v-.1-.3c0-.1 0-.2-.1-.3-.4-1.4-2.1-1.8-1.4-4.8 0-.2.3-.5 1.2-.5-1.4-.3-2-.4-3-1.3.5-1.1 1-1.9 1.3-2.6.8-1.5.3-3.5.3-3.5.8-.3 1.6-.7 1.7-1 .9-2.8-.7-5.5-2.5-7.2 1.2-.1 2.6.1 3.6 1.1 2.4 2.4 1.8 5 1 6.8.6.7 2.1 2.9 1.2 5.3-.2.6-1.4.6-2.3 2.1 2.3-1.3 3.7-1 4.2.7 1 2.4-.6 5.3-2.1 7z"/><path d="M22 53.4v-.2c0-.2-.1-.5-.2-.9s-.1-.8-.2-1.3c-.5-4.7-1.9-9.4-4.9-11.3 3.7-2 16.8-8.5 21.9-10.5 2.9-1.2.8-.4-.2 1.4-.8 1.4-.3 2.9-.5 3.2-.6.8-12.6 10.5-15.9 19.6zm32.2-2.3c-3.4 3.8-12 11-18.2 11.4 8.7-.2 12.2 4.1 14.7 9.7 2.6-5.2 2.7-10.3 2.6-16.1 0-2.6 1.8-6 .9-5zm5.3-23L54.3 24s-1.1 3.1-1 4.6c.1 1.6-1.8 2.7-.9 3.6.9.9 3.2 2.5 4 3.4.7.9 1.1 7.1 1.1 7.1l2.2 2.7s1-1.8 1.1-6.3c.2-5.4-2.9-7.1-3.3-8.6-.4-1.4.6-2.9 2-2.4zm3.1 45.6l3.9.3s1.2-2.2 2.1-3.5c.9-1.4.4-1.6 0-4.6-.4-3-1.4-9.3-1.2-13.6l-3.1 10.2s1.8 5.6 1.6 6.4c-.1.8-3.3 4.8-3.3 4.8zm5 18.8c-1.1 0-2.5-.4-3.5-.8l-1 .3.2 4s5.2.7 4.6-.4c-.6-1.2-.3-3.1-.3-3.1zm12 .6c-1 0-.3.2.4 1.2.8 1 .1 2-.8 2.3l3.2.5 1.9-1.7c.1 0-3.7-2.3-4.7-2.3zM73 76c-1.6.5-4.2.8-5.9.8-1.7.1-3.7-.1-5-.5v1.4s1.2.5 5.4.5c3.5.1 5.7-.8 5.7-.8l.9-.8c-.1.1.5-1.1-1.1-.6zm-.2 3.1c-1.6.6-3.9.6-5.6.7-1.7.1-3.7-.1-5-.5l.1 1.4s.7.3 4.9.4c3.5.1 5.7-.7 5.7-.7l.3-.5c-.1-.1.3-1-.4-.8zm5.9-42.7c-.9-.8-1.4-2.4-1.5-3.3l-1.9 2.5.7 1.2s2.5.1 2.8.1c.4 0 .3-.1-.1-.5zM69 14.7c.6-.7.2-2.7.2-2.7L66 14.6l-4.4-.8-.5-1.3-1.3-.1c.8 1.8 1.8 2.5 3.3 3.1.9.4 4.5.9 5.9-.8z"style=opacity:.4;fill-rule:evenodd;clip-rule:evenodd /></svg></a></div></div>';
if (element) {
root.style.position = "absolute";
root.style.top = minimal ? "calc(100% - 42px)" : "calc(100% - 51px)";
}
if (css) {
if (typeof(css) === "string") {
root.style.cssText = css;
} else if (typeof(css) === "object") {
css.data = "root";
TweenLite.set(root, css).kill();
}
if (root.style.top) {
root.style.bottom = "auto";
}
if (root.style.width) {
TweenLite.set(root, {xPercent: -50, left: "50%", right: "auto", data:"root"}).kill();
}
}
if (!minimal && root.offsetWidth < 600) {
root.setAttribute("class", "gs-dev-tools minimal");
if (element) {
root.style.top = "calc(100% - 42px)";
}
}
return root;
},
_clickedOnce, //we don't preventDefault() on the first mousedown/touchstart/pointerdown so that iframes get focus properly.
_addListener = function(e, type, callback, capture) {
var handler, altType;
if (type === "mousedown" || type === "mouseup") {
e.style.cursor = "pointer";
}
if (type === "mousedown") {
//some browsers call BOTH mousedown AND touchstart, for example, on a single interaction so we need to skip one of them if both are called within 100ms.
altType = e.onpointerdown !== undefined ? "pointerdown" : e.ontouchstart !== undefined ? "touchstart" : null;
if (altType) {
handler = function(event) {
if (event.target.nodeName.toLowerCase() !== "select" && event.type === altType) { //don't preventDefault() on a <select> or else it won't open!
event.stopPropagation();
if (_clickedOnce) { //otherwise, both touchstart and mousedown will get called.
event.preventDefault();
callback.call(e, event);
}
} else if (event.type !== altType) {
callback.call(e, event);
}
_clickedOnce = true;
};
e.addEventListener(altType, handler, capture);
e.addEventListener(type, handler, capture);
return;
}
}
e.addEventListener(type, callback, capture);
},
_removeListener = function(e, type, callback) {
e.removeEventListener(type, callback);
type = type !== "mousedown" ? null : e.onpointerdown !== undefined ? "pointerdown" : e.ontouchstart !== undefined ? "touchstart" : null;
if (type) {
e.removeEventListener(type, callback);
}
},
_selectValue = function(element, value, label, insertIfAbsent) {
var options = element.options,
i = options.length,
option;
value += "";
while (--i > -1) {
if (options[i].innerHTML === value || options[i].value === value) {
element.selectedIndex = i;
label.innerHTML = options[i].innerHTML;
return options[i];
}
}
if (insertIfAbsent) {
option = _createElement("option", element);
option.setAttribute("value", value);
option.innerHTML = label.innerHTML = typeof(insertIfAbsent) === "string" ? insertIfAbsent : value;
element.selectedIndex = options.length - 1;
}
},
//increments the selected value of a <select> up or down by a certain amount.
_shiftSelectedValue = function(element, amount, label) {
var options = element.options,
i = Math.min(options.length - 1, Math.max(0, element.selectedIndex + amount));
element.selectedIndex = i;
if (label) {
label.innerHTML = options[i].innerHTML;
}
return options[i].value;
},
_recordedRoot = new TimelineLite({data:"root", id:"Global Timeline", autoRemoveChildren:false, smoothChildTiming:true}),
_recordedTemp = new TimelineLite({data:"root", id:"Global Temp", autoRemoveChildren:false, smoothChildTiming:true}),
_rootTween = TweenLite.to(_recordedRoot, 1, {time:1, ease:Linear.easeNone, data:"root", id:"_rootTween", paused:true, immediateRender:false}),
_rootInstance, _rootIsDirty, _keyboardInstance,
//moves everything from _recordedTemp into _recordedRoot and updates the _rootTween if it is currently controlling the Global timeline (_recordedRoot). _recordedTemp is just a temporary recording area for anything that happens while _recordedRoot is paused. Returns true if the _recordedRoot's duration changed due to the merge.
_merge = function() {
var t = _recordedTemp._first,
duration, next;
if (t) {
if (_rootInstance && _rootInstance.animation() === _recordedRoot) {
duration = _recordedRoot._duration;
while (t) {
next = t._next;
if (!(typeof(t.target) === "function" && t.target === t.vars.onComplete && !t._duration) && !(t.target && t.target._gsIgnore)) { //typically, delayedCalls aren't included in the _recordedTemp, but since the hijacked add() below fires BEFORE TweenLite's constructor sets the target, we couldn't check that target === vars.onComplete there. And Draggable creates a tween with just an onComplete (no onReverseComplete), thus it fails that test. Therefore, we test again here to avoid merging that in.
_recordedRoot.add(t, t._startTime - t._delay);
} else {
SimpleTimeline.prototype.add.call(_globalTimeline, t, t._startTime - t._delay);
}
t = next;
}
return (duration !== _recordedRoot.duration());
} else {
//if it's not the _recordedRoot that's currently playing ("global timeline"), merge the temp tweens back into the real global timeline instead and kill any that are already completed. No need to keep them recorded.
while (t) {
next = t._next;
if (t._gc || t._totalTime === t._totalDuration) {
t.kill();
} else {
//SimpleTimeline.prototype.add.call(_globalTimeline, t, t._recordedTime);
//_globalTimeline.add(t, t._startTime - t._delay - _recordedTemp._startTime);
SimpleTimeline.prototype.add.call(_globalTimeline, t, t._startTime - t._delay);
}
t = next;
}
}
}
},
_updateRootDuration = function() {
if (_rootInstance) {
_rootInstance.update();
_rootIsDirty = false;
}
TweenLite.ticker.removeEventListener("tick", _updateRootDuration);
},
_buildPlayPauseMorph = function(svg) {
var tl = new TimelineLite({data:"root", onComplete:function() { tl.kill(); }});
tl.to(svg.querySelector(".play-1"), 0.5, {attr:{d:"M5.75,3.13 C5.75,9.79 5.75,16.46 5.75,23.13 4.08,23.13 2.41,23.13 0.75,23.13 0.75,16.46 0.75,9.79 0.75,3.12 2.41,3.12 4.08,3.12 5.75,3.12"}, ease:Power3.easeInOut, rotation:360, transformOrigin:"50% 50%"})
.to(svg.querySelector(".play-2"), 0.5, {attr:{d:"M16.38,3.13 C16.38,9.79 16.38,16.46 16.38,23.13 14.71,23.13 13.04,23.13 11.38,23.13 11.38,16.46 11.38,9.79 11.38,3.12 13.04,3.12 14.71,3.12 16.38,3.12"}, ease:Power3.easeInOut, rotation:360, transformOrigin:"50% 50%"}, 0.05);
return tl;
},
_buildLoopAnimation = function(svg) {
var tl = new TimelineLite({data:"root", paused:true, onComplete:function() { tl.kill(); }});
tl.to(svg, 0.5, {rotation:360, ease:Power3.easeInOut, transformOrigin:"50% 50%"})
.to(svg.querySelectorAll(".loop-path"), 0.5, {fill:"#91e600", ease:Linear.easeNone}, 0);
return tl;
},
GSDevTools = function(vars) {
this.vars = vars = vars || {};
vars.id = vars.id || (typeof(vars.animation) === "string" ? vars.animation : _idSeed++); //try to find a unique ID so that sessionStorage can be mapped to it (otherwise, for example, all the embedded codepens on a page would share the same settings). So if no id is defined, see if there's a string-based "animation" defined. Last of all, we default to a numeric counter that we increment.
_lookup[vars.id + ""] = this;
if (vars.animation && !_recording && vars.globalSync !== true) { //if the user calls create() and passes in an animation AFTER the initial recording time has elapsed, there's a good chance the animation won't be in the recordedRoot, so we change the default globalSync to false because that's the most intuitive behavior.
vars.globalSync = false;
}
//GENERAL/UTILITY
var _self = this,
root = _createRootElement(vars.container, vars.minimal, vars.css),
find = function(s) {
return root.querySelector(s);
},
record = function(key, value) {
if (vars.persist !== false && typeof(sessionStorage) !== "undefined") {
sessionStorage.setItem("gs-dev-" + key + vars.id, value);
}
return value;
},
recall = function(key) {
var value;
if (vars.persist !== false && typeof(sessionStorage) !== "undefined") {
value = sessionStorage.getItem("gs-dev-" + key + vars.id);
return (key === "animation") ? value : (key === "loop") ? (value === "true") : parseFloat(value); // handle data typing too.
}
},
//SCRUBBER/PROGRESS
playhead = find(".playhead"),
timelineTrack = find(".timeline-track"),
progressBar = find(".progress-bar"),
timeLabel = find(".time"),
durationLabel = find(".duration"),
pixelToTimeRatio, timeAtDragStart, dragged, skipDragUpdates,
progress = 0,
//spits back a common onPress function for anything that's dragged along the timeline (playhead, inPoint, outPoint). The originRatio is a value from 0-1 indicating how far along the x-axis the origin is located (0.5 is in the center, 0 is left, 1 is on right side). limitElement is optional, and sets the bounds such that the element can't be dragged past the limitElement.
onPressTimeline = function(element, originRatio, limitToInOut) {
return function(e) {
var trackBounds = timelineTrack.getBoundingClientRect(),
elementBounds = element.getBoundingClientRect(),
left = elementBounds.width * originRatio,
x = element._gsTransform.x,
minX = trackBounds.left - elementBounds.left - left + x,
maxX = trackBounds.right - elementBounds.right + (elementBounds.width - left) + x,
unlimitedMinX = minX,
limitBounds;
if (limitToInOut) {
if (element !== inPoint) {
limitBounds = inPoint.getBoundingClientRect();
if (limitBounds.left) { //if inPoint is hidden (like display:none), ignore.
minX += (limitBounds.left + limitBounds.width) - trackBounds.left;
}
}
if (element !== outPoint) {
limitBounds = outPoint.getBoundingClientRect();
if (limitBounds.left) { //if outPoint is hidden (like display:none), ignore.
maxX -= (trackBounds.left + trackBounds.width) - limitBounds.left;
}
}
}
pausedWhenDragStarted = paused;
this.applyBounds({minX:minX, maxX:maxX});
//_merge();
pixelToTimeRatio = linkedAnimation.duration() / trackBounds.width;
timeAtDragStart = -unlimitedMinX * pixelToTimeRatio;
if (!skipDragUpdates) {
linkedAnimation.pause(timeAtDragStart + pixelToTimeRatio * this.x);
} else {
linkedAnimation.pause();
}
if (this.target === playhead) {
if (this.activated) {
this.allowEventDefault = false;
}
this.activated = true;
}
dragged = true;
};
},
progressDrag = Draggable.create(playhead, {
type:"x",
cursor: "ew-resize",
allowNativeTouchScrolling: false,
allowEventDefault:true, //otherwise, when dragged outside an iframe, the mouseup doesn't bubble up so it could seem "stuck" to the mouse.
onPress: onPressTimeline(playhead, 0.5, true),
onDrag: function() {
var time = timeAtDragStart + pixelToTimeRatio * this.x;
if (time < 0) {
time = 0;
} else if (time > linkedAnimation._duration) {
time = linkedAnimation._duration;
}
if (!skipDragUpdates) {
linkedAnimation.time(time);
}
progressBar.style.width = Math.min(outProgress - inProgress, Math.max(0, (time / linkedAnimation._duration) * 100 - inProgress)) + "%";
timeLabel.innerHTML = time.toFixed(2);
},
onRelease: function(e) {
if (!paused) {
linkedAnimation.resume();
}
}
})[0],
inPoint = find(".in-point"),
outPoint = find(".out-point"),
resetInOut = function() {
inProgress = 0;
outProgress = 100;
inPoint.style.left = "0%";
outPoint.style.left = "100%";
record("in", inProgress);
record("out", outProgress);
updateProgress(true);
},
inProgress = 0,
outProgress = 100,
pausedWhenDragStarted,
inDrag = Draggable.create(inPoint, {
type:"x",
cursor:"ew-resize",
zIndexBoost:false,
allowNativeTouchScrolling: false,
allowEventDefault:true, //otherwise, when dragged outside an iframe, the mouseup doesn't bubble up so it could seem "stuck" to the mouse.
onPress:onPressTimeline(inPoint, 1, true),
onDoubleClick: resetInOut,
onDrag: function() {
inProgress = (timeAtDragStart + pixelToTimeRatio * this.x) / linkedAnimation.duration() * 100;
linkedAnimation.progress(inProgress / 100);
updateProgress(true);
},
onRelease: function() {
if (inProgress < 0) {
inProgress = 0;
}
_clearSelection();
//for responsiveness, convert the px-based transform into %-based left position.
inPoint.style.left = inProgress + "%";
record("in", inProgress);
TweenLite.set(inPoint, {x:0, data:"root", display:"block"}); //set display:block so that it remains visible even when the minimal skin is enabled.
if (!paused) {
linkedAnimation.resume();
}
}
})[0],
outDrag = Draggable.create(outPoint, {
type:"x",
cursor:"ew-resize",
allowNativeTouchScrolling: false,
allowEventDefault:true, //otherwise, when dragged outside an iframe, the mouseup doesn't bubble up so it could seem "stuck" to the mouse.
zIndexBoost:false,
onPress:onPressTimeline(outPoint, 0, true),
onDoubleClick: resetInOut,
onDrag: function() {
outProgress = (timeAtDragStart + pixelToTimeRatio * this.x) / linkedAnimation.duration() * 100;
linkedAnimation.progress(outProgress / 100);
updateProgress(true);
},
onRelease: function() {
if (outProgress > 100) {
outProgress = 100;
}
_clearSelection();
//for responsiveness, convert the px-based transform into %-based left position.
outPoint.style.left = outProgress + "%";
record("out", outProgress);
TweenLite.set(outPoint, {x:0, data:"root", display:"block"}); //set display:block so that it remains visible even when the minimal skin is enabled.
if (!pausedWhenDragStarted) {
play();
linkedAnimation.resume();
}
}
})[0],
updateProgress = function(force) {
if (progressDrag.isPressed && !force) {
return;
}
var p = (!loopEnabled && selectedAnimation._repeat === -1) ? selectedAnimation.totalTime() / selectedAnimation.duration() * 100 : (linkedAnimation.progress() * 100) || 0,
repeatDelayPhase = (selectedAnimation._repeat && selectedAnimation._repeatDelay && selectedAnimation.totalTime() % (selectedAnimation.duration() + selectedAnimation._repeatDelay) > selectedAnimation.duration());
if (p > 100) {
p = 100;
}
if (p >= outProgress) {
if (loopEnabled && !linkedAnimation.paused() && !progressDrag.isDragging) {
if (!repeatDelayPhase) {
p = inProgress;
if (linkedAnimation.target === selectedAnimation) { //in case there are callbacks on the timeline, when we jump back to the start we should seek() so that the playhead doesn't drag [backward] past those and trigger them.
linkedAnimation.target.seek(startTime + ((endTime - startTime) * inProgress / 100));
}
if (selectedAnimation._repeat > 0 && !inProgress && outProgress === 100) {
if (selectedAnimation.totalProgress() === 1) {
linkedAnimation.totalProgress(0, true).resume();
}
} else {
linkedAnimation.progress(p / 100, true).resume();
}
}
} else {
if (p !== outProgress || selectedAnimation._repeat === -1) {
p = outProgress;
linkedAnimation.progress(p / 100);
}
if (!paused && (selectedAnimation.totalProgress() === 1 || selectedAnimation._repeat === -1)) {
pause();
}
}
} else if (p < inProgress) {
p = inProgress;
linkedAnimation.progress(p / 100, true);
}
if (p !== progress || force) {
progressBar.style.left = inProgress + "%";
progressBar.style.width = Math.max(0, p - inProgress) + "%";
playhead.style.left = p + "%";
timeLabel.innerHTML = linkedAnimation._time.toFixed(2);
durationLabel.innerHTML = linkedAnimation._duration.toFixed(2);
if (dragged) {
playhead.style.transform = "translate(-50%,0)";
playhead._gsTransform.x = 0;
playhead._gsTransform.xPercent = -50;
dragged = false;
}
progress = p;
} else if (linkedAnimation._paused !== paused) { //like if the user has an addPause() in the middle of the animation.
togglePlayPause();
}
},
onPressSeekBar = function(e) {
if (progressDrag.isPressed) {
return;
}
var bounds = e.target.getBoundingClientRect(),
x = (e.changedTouches ? e.changedTouches[0] : e).clientX,
p = ((x - bounds.left) / bounds.width) * 100;
if (p < inProgress) {
inProgress = p = Math.max(0, p);
inPoint.style.left = inProgress + "%";
inDrag.startDrag(e);
return;
} else if (p > outProgress) {
outProgress = p = Math.min(100, p);
outPoint.style.left = outProgress + "%";
outDrag.startDrag(e);
return;
}
linkedAnimation.progress(p / 100).pause();
updateProgress(true);
progressDrag.startDrag(e);
},
//PLAY/PAUSE button
playPauseButton = find(".play-pause"),
playPauseMorph = _buildPlayPauseMorph(playPauseButton),
paused = false,
play = function() {
if (linkedAnimation.progress() >= outProgress / 100) {
if (linkedAnimation.target === selectedAnimation) { //in case there are callbacks on the timeline, when we jump back to the start we should seek() so that the playhead doesn't drag [backward] past those and trigger them.
linkedAnimation.target.seek(startTime + ((endTime - startTime) * inProgress / 100));
}
if (linkedAnimation._repeat && !inProgress) {
linkedAnimation.totalProgress(0, true); //for repeating animations, don't get stuck in the last iteration - jump all the way back to the start.
} else {
linkedAnimation.progress(inProgress / 100, true);
}
}
playPauseMorph.play();
linkedAnimation.resume();
if (paused) {
_self.update();
}
paused = false;
},
pause = function() {
playPauseMorph.reverse();
if (linkedAnimation) {
linkedAnimation.pause();
}
paused = true;
},
togglePlayPause = function() {
if (paused) {
play();
} else {
pause();
}
},
//REWIND button
onPressRewind = function(e) {
if (progressDrag.isPressed) {
return;
}
//_self.update();
if (linkedAnimation.target === selectedAnimation) { //in case there are callbacks on the timeline, when we jump back to the start we should seek() so that the playhead doesn't drag [backward] past those and trigger them.
linkedAnimation.target.seek(startTime + ((endTime - startTime) * inProgress / 100));
}
linkedAnimation.progress(inProgress / 100, true);
if (!paused) {
linkedAnimation.resume();
}
},
//LOOP button
loopButton = find(".loop"),
loopAnimation = _buildLoopAnimation(loopButton),
loopEnabled,
loop = function(value) {
loopEnabled = value;
record("loop", loopEnabled);
if (loopEnabled) {
loopAnimation.play();
if (linkedAnimation.progress() >= outProgress / 100) {
if (linkedAnimation.target === selectedAnimation) { //in case there are callbacks on the timeline, when we jump back to the start we should seek() so that the playhead doesn't drag [backward] past those and trigger them.
linkedAnimation.target.seek(startTime + ((endTime - startTime) * inProgress / 100));
}
if (selectedAnimation._repeat && !inProgress && outProgress === 100) {
linkedAnimation.totalProgress(0, true);
} else {
linkedAnimation.progress(inProgress / 100, true);
}
play();
}
} else {
loopAnimation.reverse();
}
},
toggleLoop = function() {
loop(!loopEnabled);
},
//ANIMATIONS list
list = find(".animation-list"),
animationLabel = find(".animation-label"),
selectedAnimation, //the currently selected animation
linkedAnimation, //the animation that's linked to all the controls and scrubber. This is always _rootTween if globalSync is true, so it can be different than the selectedAnimation!
declaredAnimation, //whatever the user defines in the config object initially (often this will be null). If the user defines a string, it'll be resolved to a real Animation instance for this variable.
startTime, endTime,
updateList = function() {
var animations = _getChildrenOf((declaredAnimation && vars.globalSync === false) ? declaredAnimation : _recordedRoot, true),
options = list.children,
matches = 0,
option, i;
if (declaredAnimation && vars.globalSync === false) {
animations.unshift(declaredAnimation);
} else if (!vars.hideGlobalTimeline) {
animations.unshift(_recordedRoot);
}
for (i = 0; i < animations.length; i++) {
option = options[i] || _createElement("option", list);
option.animation = animations[i];
matches = (i && animations[i].vars.id === animations[i-1].vars.id) ? matches + 1 : 0;
option.setAttribute("value", (option.innerHTML = animations[i].vars.id + (matches ? " [" + matches + "]" : (animations[i+1] && animations[i+1].vars.id === animations[i].vars.id) ? " [0]" : "")));
}
for (; i < options.length; i++) {
list.removeChild(options[i]);
}
},
animation = function(anim) {
var ts = parseFloat(timeScale.options[timeScale.selectedIndex].value) || 1,
tl, maxDuration;
if (!arguments.length) {
return selectedAnimation;
}
if (typeof(anim) === "string") {
anim = _getAnimationById(anim);
}
//console.log("animation() ", anim.vars.id);
if (!(anim instanceof Animation)) {
console.log("GSDevTools error: invalid animation.");
}
if (anim === selectedAnimation) {
return;
}
if (selectedAnimation) {
selectedAnimation._inProgress = inProgress;
selectedAnimation._outProgress = outProgress;
}
selectedAnimation = anim;
if (linkedAnimation) {
ts = linkedAnimation.timeScale();
if (linkedAnimation.target === declaredAnimation) {
declaredAnimation.resume();
linkedAnimation.kill();
}
}
inProgress = selectedAnimation._inProgress || 0;
outProgress = selectedAnimation._outProgress || 100;
inPoint.style.left = inProgress + "%";
outPoint.style.left = outProgress + "%";
if (_fullyInitialized) { //don't record inProgress/outProgress unless we're fully instantiated because people may call GSDevTools.create() before creating/defining their animations, thus the inTime/outTime may not exist yet.
record("animation", selectedAnimation.vars.id);
record("in", inProgress);
record("out", outProgress);
}
startTime = 0;
maxDuration = Math.min(1000, vars.maxDuration || 1000, _getClippedDuration(selectedAnimation));
if (selectedAnimation === _recordedRoot || vars.globalSync !== false) {
_merge();
linkedAnimation = _rootTween;
if (_rootInstance && _rootInstance !== _self) {
console.log("Error: GSDevTools can only have one instance that's globally synchronized.");
}
_rootInstance = _self;
//_recording = true;
if (selectedAnimation !== _recordedRoot) {
tl = selectedAnimation;
endTime = tl.totalDuration();
if (endTime > 99999999) { //in the case of an infinitely repeating animation, just use a single iteration's duration instead.
endTime = tl.duration();
}
while (tl.timeline.timeline) {
startTime = (startTime / tl._timeScale) + tl._startTime;
endTime = (endTime / tl._timeScale) + tl._startTime;
tl = tl.timeline;
}
} else {
endTime = _recordedRoot.duration();
}
if (endTime - startTime > maxDuration) { //cap end time at 1000 because it doesn't seem reasonable to accommodate super long stuff.
endTime = startTime + maxDuration;
}
_recordedRoot.pause(startTime);
_rootTween.vars.time = endTime;
_rootTween.invalidate();
_rootTween.duration(endTime - startTime).timeScale(ts);
//wait for a tick before starting because some browsers freeze things immediately following a <select> selection, like on MacOS it flashes a few times before disappearing, so this prevents a "jump".
if (paused) {
//jump forward and then back in order to make sure the start/end values are recorded internally right away and don't drift outside this tween.
_rootTween.progress(1).pause(0);
} else {
TweenLite.delayedCall(0.01, function() {
_rootTween.resume().progress(inProgress / 100);
if (paused) {
play();
}
});
}
} else {
if (_rootInstance === _self) {
_rootInstance = null;
}
if (selectedAnimation === declaredAnimation || !declaredAnimation) {
linkedAnimation = selectedAnimation;
if (!loopEnabled && linkedAnimation._repeat) {
loop(true);
}
} else { //if an animation is declared in the config object, and the user chooses a sub-animation (nested), we tween the playhead of the declaredAnimation to keep everything synchronized even though globalSync isn't true.
tl = selectedAnimation;
endTime = tl.totalDuration();
if (endTime > 99999999) { //in the case of an infinitely repeating animation, just use a single iteration's duration instead.
endTime = tl.duration();
}
while (tl.timeline.timeline && tl !== declaredAnimation) {
startTime = (startTime / tl._timeScale) + tl._startTime;
endTime = (endTime / tl._timeScale) + tl._startTime;
tl = tl.timeline;
}
if (endTime - startTime > maxDuration) { //cap end time at 1000 because it doesn't seem reasonable to accommodate super long stuff.
endTime = startTime + maxDuration;
}
declaredAnimation.pause(startTime);
linkedAnimation = TweenLite.to(declaredAnimation, endTime - startTime, {time:endTime, ease:Linear.easeNone, data:"root"});
}
linkedAnimation.timeScale(ts);
_rootTween.pause();
_recordedRoot.resume();
linkedAnimation.seek(0);
}
durationLabel.innerHTML = linkedAnimation.duration().toFixed(2);
_selectValue(list, selectedAnimation.vars.id, animationLabel);
},
updateRootDuration = function() {
var time, ratio, duration;
if (selectedAnimation === _recordedRoot) {
time = _recordedRoot._time;
_recordedRoot.progress(1, true).time(time, true); //jump to the end and back again because sometimes a tween that hasn't rendered yet will affect duration, like a TimelineMax.tweenTo() where the duration gets set in the onStart.
time = (_rootTween._timeline._time - _rootTween._startTime) * _rootTween._timeScale;
duration = Math.min(1000, _recordedRoot.duration());
if (duration === 1000) {
duration = Math.min(1000, _getClippedDuration(_recordedRoot));
}
ratio = _rootTween.duration() / duration;
if (ratio !== 1 && duration) {
inProgress *= ratio;
if (outProgress < 100) {
outProgress *= ratio;
}
_rootTween.seek(0);
_rootTween.vars.time = duration;
_rootTween.invalidate();
_rootTween.duration(duration);
_rootTween.time(time);
durationLabel.innerHTML = duration.toFixed(2);
updateProgress(true);
}
}
},
onChangeAnimation = function(e) {
animation(list.options[list.selectedIndex].animation);
if (e.target && e.target.blur) { //so that if an option is selected, and then the user tries to hit the up/down arrow, it doesn't just try selecting something else in the <select>.
e.target.blur();
}
if (paused) {
play();
}
},
//TIMESCALE button
timeScale = find(".time-scale select"),
timeScaleLabel = find(".time-scale-label"),
onChangeTimeScale = function(e) {
var ts = parseFloat(timeScale.options[timeScale.selectedIndex].value) || 1;
linkedAnimation.timeScale(ts);
record("timeScale", ts);
if (!paused) {
if (linkedAnimation.progress() >= outProgress / 100) {
if (linkedAnimation.target === selectedAnimation) { //in case there are callbacks on the timeline, when we jump back to the start we should seek() so that the playhead doesn't drag [backward] past those and trigger them.
linkedAnimation.target.seek(startTime + ((endTime - startTime) * inProgress / 100));
}
linkedAnimation.progress(inProgress / 100, true).pause();
} else {
linkedAnimation.pause();
}
TweenLite.delayedCall(0.01, function() {
linkedAnimation.resume();
});
}
timeScaleLabel.innerHTML = ts + "x";
if (timeScale.blur) { //so that if an option is selected, and then the user tries to hit the up/down arrow, it doesn't just try selecting something else in the <select>.
timeScale.blur();
}
},
//AUTOHIDE
autoHideTween = TweenLite.to([find(".gs-bottom"), find(".gs-top")], 0.3, {autoAlpha:0, y:50, ease:Power2.easeIn, data:"root", paused:true}),
hidden = false,
onMouseOut = function(e) {
if (!Draggable.hitTest(e, root) && !progressDrag.isDragging && !inDrag.isDragging && !outDrag.isDragging) {
autoHideDelayedCall.restart(true);
}
},
hide = function() {
if (!hidden) {
autoHideTween.play();
autoHideDelayedCall.pause();
hidden = true;
}
},
show = function() {
autoHideDelayedCall.pause();
if (hidden) {
autoHideTween.reverse();
hidden = false;
}
},
toggleHide = function() {
if (hidden) {
show();
} else {
hide();
}
},
autoHideDelayedCall = TweenLite.delayedCall(1.3, hide).pause(),
_fullyInitialized, //we call initialize() initially, and then again on the very next tick just in case someone called GSDevTools.create() BEFORE they create their animations. This variable tracks that state. Note: we don't record sessionStorage.setItem() until we're fully initialized, otherwise we may inadvertently set in/out points to the defaults just because the animation couldn't be found (yet).
keyboardHandler,
initialize = function(preliminary) {
//if on startup, someone does a timeline.seek(), we must honor it, so when initialize() is called, we record _recordedRoot._startTime so that we can use that as an offset. Remember, however, that we call initialize() twice on startup, once after a tick has elapsed just in case someone called GSDevTools.create() before their animation code, so we must record the value (once).
if (_startupPhase && !_globalStartTime) {
_globalStartTime = _recordedRoot._startTime;
}
_fullyInitialized = !preliminary;
declaredAnimation = _getAnimationById(vars.animation);
if (declaredAnimation && !declaredAnimation.vars.id) {
declaredAnimation.vars.id = "[no id]";
}
updateList();
var savedAnimation = _getAnimationById(recall("animation"));
if (savedAnimation) {
savedAnimation._inProgress = recall("in") || 0;
savedAnimation._outProgress = recall("out") || 100;
}
if (vars.paused) {
pause();
}
selectedAnimation = null;
animation(declaredAnimation || savedAnimation || _recordedRoot);
var ts = vars.timeScale || recall("timeScale"),
savedInOut = (savedAnimation === selectedAnimation);
if (ts) {
_selectValue(timeScale, ts, timeScaleLabel, ts + "x");
linkedAnimation.timeScale(ts);
}
inProgress = (("inTime" in vars) ? _timeToProgress(vars.inTime, selectedAnimation, 0, 0) : savedInOut ? savedAnimation._inProgress : 0) || 0;
if (inProgress === 100 && !vars.animation && savedAnimation) { //in case there's a recorded animation (sessionStorage) and then the user defines an inTime that exceeds that animation's duration, just default back to the Global Timeline. Otherwise the in/out point will be at the very end and it'd be weird.
animation(_recordedRoot);
inProgress = _timeToProgress(vars.inTime, selectedAnimation, 0, 0) || 0;
}
if (inProgress) {
inPoint.style.left = inProgress + "%";
inPoint.style.display = outPoint.style.display = "block"; //set display:block so that it remains visible even when the minimal skin is enabled.
}
outProgress = (("outTime" in vars) ? _timeToProgress(vars.outTime, selectedAnimation, 100, inProgress) : savedInOut ? savedAnimation._outProgress : 0) || 100;
if (outProgress < inProgress) {
outProgress = 100;
}
if (outProgress !== 100) {
outPoint.style.left = outProgress + "%";
inPoint.style.display = outPoint.style.display = "block"; //set display:block so that it remains visible even when the minimal skin is enabled.
}
loopEnabled = ("loop" in vars) ? vars.loop : recall("loop");
if (loopEnabled) {
loop(true);
}
if (vars.paused) {
linkedAnimation.progress(inProgress / 100, true).pause();
}
if (_startupPhase && selectedAnimation === _recordedRoot && _globalStartTime && vars.globalSync !== false && !paused) {
linkedAnimation.time(-_globalStartTime, true);
}
updateProgress(true);
};
//INITIALIZATION TASKS
_addListener(list, "change", onChangeAnimation);
_addListener(list, "mousedown", updateList);
_addListener(playPauseButton, "mousedown", togglePlayPause);
_addListener(find(".seek-bar"), "mousedown", onPressSeekBar);
_addListener(find(".rewind"), "mousedown", onPressRewind);
_addListener(loopButton, "mousedown", toggleLoop);
_addListener(timeScale, "change", onChangeTimeScale);
if (vars.visibility === "auto") {
_addListener(root, "mouseout", onMouseOut);
//_addListener(find(".gs-hit-area"), "mouseover", show);
_addListener(root, "mouseover", show);
} else if (vars.visibility === "hidden") {
hidden = true;
autoHideTween.progress(1);
}
if (vars.keyboard !== false) {
if (_keyboardInstance && vars.keyboard) {
console.log("[GSDevTools warning] only one instance can be affected by keyboard shortcuts. There is already one active.");
} else {
_keyboardInstance = _self; //we can't have multiple instances all affected by the keyboard.
keyboardHandler = function(e) { //window.parent allows things to work inside of an iframe, like on codepen.
var key = e.keyCode ? e.keyCode : e.which,
ts;
if (key === 32) { //spacebar
togglePlayPause();
} else if (key === 38) { //up arrow
ts = parseFloat(_shiftSelectedValue(timeScale, -1, timeScaleLabel));
linkedAnimation.timeScale(ts);
record("timeScale", ts);
} else if (key === 40) { //down arrow
ts = parseFloat(_shiftSelectedValue(timeScale, 1, timeScaleLabel));
linkedAnimation.timeScale(ts);
record("timeScale", ts);
} else if (key === 37) { //left arrow
onPressRewind(e);
} else if (key === 39) { //right arrow
linkedAnimation.progress(outProgress / 100);
} else if (key === 76) { //"L" key
toggleLoop();
} else if (key === 72) { //"H" key
toggleHide();
} else if (key === 73) { //"I" key
inProgress = linkedAnimation.progress() * 100;
record("in", inProgress);
inPoint.style.left = inProgress + "%";
updateProgress(true);
} else if (key === 79) { //"O" key
outProgress = linkedAnimation.progress() * 100;
record("out", outProgress);
outPoint.style.left = outProgress + "%";
updateProgress(true);
}
};
_addListener(_docElement, "keydown", keyboardHandler);
}
}
TweenLite.set(playhead, {xPercent:-50, x:0, data:"root"}); //so that when we drag, x is properly discerned (browsers report in pure pixels rather than percents)
TweenLite.set(inPoint, {xPercent:-100, x:0, data:"root"});
inPoint._gsIgnore = outPoint._gsIgnore = playhead._gsIgnore = playPauseButton._gsIgnore = loopButton._gsIgnore = true;
//Draggable fires off a TweenLite.set() that affects the transforms, and we don't want them to get into the _recordedRoot, so kill those tweens.
TweenLite.killTweensOf([inPoint, outPoint, playhead]);
initialize(_startupPhase);
if (_startupPhase) {
//developers may call GSDevTools.create() before they even create some of their animations, so the inTime/outTime or animation values may not exist, thus we wait for 1 tick and initialize again, just in case.
TweenLite.delayedCall(0.0001, initialize, [false], this);
}
TweenLite.ticker.addEventListener("tick", updateProgress);
this.update = function(forceMerge) {
if (_rootInstance === _self) {
if (!_rootTween._paused || forceMerge) {
_merge();
}
updateRootDuration();
}
};
this.kill = function() {
_removeListener(list, "change", onChangeAnimation);
_removeListener(list, "mousedown", updateList);
_removeListener(playPauseButton, "mousedown", togglePlayPause);
_removeListener(find(".seek-bar"), "mousedown", onPressSeekBar);
_removeListener(find(".rewind"), "mousedown", onPressRewind);
_removeListener(loopButton, "mousedown", toggleLoop);
_removeListener(timeScale, "change", onChangeTimeScale);
progressDrag.disable();
inDrag.disable();
outDrag.disable();
TweenLite.ticker.removeEventListener("tick", updateProgress);
_removeListener(root, "mouseout", onMouseOut);
_removeListener(root, "mouseover", show);
_removeListener(_docElement, "keydown", keyboardHandler);
root.parentNode.removeChild(root);
if (_rootInstance === _self) {
_rootInstance = null;
}
delete _lookup[vars.id + ""];
};
this.minimal = function(value) {
var isMinimal = root.classList.contains("minimal"),
p;
if (!arguments.length || isMinimal === value) {
return isMinimal;
}
if (value) {
root.classList.add("minimal");
} else {
root.classList.remove("minimal");
}
if (vars.container) {
root.style.top = value ? "calc(100% - 42px)" : "calc(100% - 51px)";
}
if (progressDrag.isPressed) {
skipDragUpdates = true; //just in case there's actually a tween/timeline in the linkedAnimation that is altering this GSDevTool instance's "minimal()" value, it could trigger a recursive loop in the drag handlers, like if they update linkedAnimation's time/progress which in turn triggers this minimal() function which in turn dues the same, and so on.
progressDrag.endDrag(progressDrag.pointerEvent);
skipDragUpdates = false;
p = linkedAnimation.progress() * 100;
progressBar.style.width = Math.max(0, p - inProgress) + "%";
playhead.style.left = p + "%";
playhead.style.transform = "translate(-50%,0)";
playhead._gsTransform.x = 0;
playhead._gsTransform.xPercent = -50;
progressDrag.startDrag(progressDrag.pointerEvent, true);
}
};
//expose methods:
this.animation = animation;
this.updateList = updateList;
},
_recording = true,
_startupPhase = true, //for the first 2 seconds, we don't record any zero-duration tweens because they're typically just setup stuff and/or the "from" or "startAt" tweens. In version 1.20.3 we started flagging those with data:"isStart"|"isFromStart" but this logic helps GSDevTools work with older versions too.
_onOverwrite = TweenLite.onOverwrite,
_globalStartTime = 0; //if on startup, someone does a timeline.seek(), we need to honor it, so when initialize() is called, it'll check the _recordedRoot._startTime so that we can use that as an offset. Remember, however, that we call initialize() twice on startup, once after a tick has elapsed just in case someone called GSDevTools.create() before their animation code, so we must record the value (once).
GSDevTools.version = "0.1.9";
GSDevTools.logOverwrites = false;
GSDevTools.globalRecordingTime = 2;
GSDevTools.getById = function(id) {
return id ? _lookup[id] : _rootInstance;
};
//align the all of the playheads so they're starting at 0 now.
_globalTimeline._startTime += _globalTimeline._time;
_recordedRoot._startTime = _recordedTemp._startTime = _globalTimeline._time = _globalTimeline._totalTime = 0;
//in case GSDevTools.create() is called before anything is actually on the global timeline, we've gotta update it or else the duration will be 0 and it'll be stuck.
TweenLite.delayedCall(0.01, function() {
if (_rootInstance) {
_rootInstance.update();
} else {
_merge();
}
});
//initially we record everything into the _recordedRoot TimelineLite because developers might call GSDevTools.create() AFTER some of their code executes, but after 2 seconds if there aren't any GSDevTool instances that have globalSync enabled, we should dump all the stuff from _recordedRoot into the global timeline to improve performance and avoid issues where _recordedRoot is paused and reaches its end and wants to stop the playhead.
TweenLite.delayedCall(2, function() {
var t, next, offset;
if (!_rootInstance) {
_merge();
t = _recordedRoot._first;
offset = _recordedRoot._startTime;
while (t) {
next = t._next;
//any animations that aren't finished should be dumped into the root timeline. If they're done, just kill them.
if (t._totalDuration !== t._totalTime || (!t._duration && t.ratio !== 1)) {
SimpleTimeline.prototype.add.call(_globalTimeline, t, t._startTime - t._delay + offset);
} else {
t.kill();
}
t = next;
}
}
if (GSDevTools.globalRecordingTime > 2) {
TweenLite.delayedCall(GSDevTools.globalRecordingTime - 2, function() {
if (_rootInstance) {
_rootInstance.update();
}
_recording = false;
});
} else {
_recording = false;
}
_startupPhase = false;
});
//hijack the adding of all children of the global timeline and dump them into _recordedRoot instead, unless they are "rooted" or "exported". If _recordedRoot is paused, we dump them into _recordedTemp so that they actually work, and we merge them back into _recordedRoot when it becomes unpaused.
_globalTimeline.add = function(child, position, align, stagger) {
var data = child.data;
//TODO: idea: what if we ignore any zero-duration tweens that occur in the first second or two, and then lock the "global timeline" down after that anyway? Perhaps offer a way to update() manually?
if (_recording && child.vars && data !== "root" && data !== "ignore" && data !== "isStart" && data !== "isFromStart" && data !== "_draggable" && !(_startupPhase && !child._duration && child instanceof TweenLite) && !(child.vars.onComplete && child.vars.onComplete === child.vars.onReverseComplete)) { //skip delayedCalls too
var tl = _recordedRoot;
if (_rootTween._time) {
if (_rootTween._paused) {
tl = _recordedTemp;
child._recordedTime = _recordedRoot.rawTime();
} else {
position = (_globalTimeline._time - _rootTween._startTime) * _rootTween._timeScale;
if (!_rootIsDirty) {
TweenLite.ticker.addEventListener("tick", _updateRootDuration);
_rootIsDirty = true;
}
}
}
tl.add(child, position, align, stagger);
//TODO: what if timeScale is set initially low, and a delayedCall() fires another animation?? It'd fire early.
if (child.vars.repeat) { //before 1.20.3, repeated TweenMax/TimelineMax instances didn't have their repeats applied until after the constructor ran (which was after it was added to its timeline), so we need to make sure _dirty is true in order to trigger re-calculation of totalDuration. Otherwise, _recordedRoot/_recordedTemp might stop at the end of the first iteration of a repeated tween.
tl._dirty = true;
}
return this;
}
return SimpleTimeline.prototype.add.apply(this, arguments);
};
_recordedRoot._enabled = _recordedTemp._enabled = function(value, ignoreTimeline) {
//skip enabling/disabling the nested animations (performance improvement). SimpleTimeline._enabled() doesn't do that - only TimelineLite._enabled() does.
return SimpleTimeline.prototype._enabled.apply(this, arguments);
};
TimelineLite.prototype._remove = function(tween, skipDisable) { //replace TimelineLite's _remove because before 1.19.1, there was a bug that could cause _time to jump to the end. We want to make sure GSDevTools can still work properly with slightly older versions.
SimpleTimeline.prototype._remove.apply(this, arguments);
var last = this._last;
if (!last) {
this._time = this._totalTime = this._duration = this._totalDuration = 0;
} else if (this._time > this.duration()) {
this._time = this._duration;
this._totalTime = this._totalDuration;
}
return this;
};
TweenLite.onOverwrite = function(overwrittenTween, overwritingTween, target, overwrittenProperties) {
if (GSDevTools.logOverwrites) {
if (overwrittenProperties) {
console.log("[Overwrite warning] the following properties were overwritten: ", overwrittenProperties, "| target:", target, "| overwritten tween: ", overwrittenTween, "| overwriting tween:", overwritingTween);
} else {
console.log("[Overwrite warning] the following tween was overwritten:", overwrittenTween, "by", overwritingTween);
}
}
if (typeof(_onOverwrite) === "function") {
_onOverwrite(overwrittenTween, overwritingTween, target, overwrittenProperties);
}
};
GSDevTools.create = function(vars) {
return new GSDevTools(vars);
};
return GSDevTools;
}, true);
export var GSDevTools = globals.GSDevTools;
export { GSDevTools as default };