diff --git a/images/wheel-marker.svg b/images/wheel-marker.svg new file mode 100644 index 000000000..e7a39cb7c --- /dev/null +++ b/images/wheel-marker.svg @@ -0,0 +1,30 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/index.html b/index.html index 6e95ad4d0..a11b326da 100644 --- a/index.html +++ b/index.html @@ -21,6 +21,7 @@ + + + @@ -190,6 +193,7 @@ + diff --git a/javascripts/components/options/notation-wheel.js b/javascripts/components/options/notation-wheel.js new file mode 100644 index 000000000..782a25ddc --- /dev/null +++ b/javascripts/components/options/notation-wheel.js @@ -0,0 +1,179 @@ +"use strict"; + +Vue.component("notation-wheel", { + props: { + segments: { + default() { + return [ + { + textFillStyle: '#fff', + fillStyle: '#000', + text: 'Prize 1' + }, + { + textFillStyle: '#000', + fillStyle: '#fadede', + text: 'Prize 2' + }, + { + textFillStyle: '#fff', + fillStyle: '#000', + text: 'Prize 3' + }, + { + textFillStyle: '#000', + fillStyle: '#fadede', + text: 'Prize 4' + }, + { + textFillStyle: '#fff', + fillStyle: '#000', + text: 'Prize 5' + }, + { + textFillStyle: '#000', + fillStyle: '#fadede', + text: 'Prize 6' + }, + { + textFillStyle: '#fff', + fillStyle: '#000', + text: 'Prize 7' + }, + { + textFillStyle: '#000', + fillStyle: '#fadede', + text: 'Prize 8' + } + ] + } + } + }, + data() { + return { + loadingPrize: false, + theWheel: null, + modalPrize: false, + wheelPower: 1, + wheelSpinning: false, + prizeName: 'BUY 1 GET 1', + WinWheelOptions: { + textFontSize: 14, + outterRadius: 410, + innerRadius: 25, + lineWidth: 8, + animation: { + type: 'spinOngoing', + duration: 0.5 + } + } + } + }, + computed: { + notations: () => Notations.all, + segments: () => { + const ret = []; + for (const notation of notations) { + const color = Math.floor(Math.random()*16777215).toString(16); + ret.push( + { + text: notation.name, + textFillStyle: `#${color}`, + fillStyle: `#${(Number(`0x1${color}`) ^ 0xFFFFFF).toString(16).substr(1)}`, + } + ) + } + } + }, + mounted() { + this.initSpin() + }, + updated() { }, + created() { }, + methods: { + showPrize() { + this.modalPrize = true + }, + hidePrize() { + this.modalPrize = false + }, + startSpin() { + if (this.wheelSpinning === false) { + this.theWheel.startAnimation() + this.wheelSpinning = true + this.theWheel = new Winwheel({ + ...this.WinWheelOptions, + numSegments: this.segments.length, + segments: this.segments, + animation: { + type: 'spinToStop', + duration: 5, + spins: 5, + callbackFinished: this.onFinishSpin + } + }) + + // example input prize number get from Backend + // Important thing is to set the stopAngle of the animation before stating the spin. + + var prizeNumber = Math.floor(Math.random() * this.segments.length) // or just get from Backend + var stopAt = 360 / this.segments.length * prizeNumber - 360 / this.segments.length / 2 // center pin + // var stopAt = 360 / this.segments.length * prizeNumber - Math.floor(Math.random() * 60) //random location + this.theWheel.animation.stopAngle = stopAt + this.theWheel.startAnimation() + this.wheelSpinning = false + } + }, + resetWheel() { + this.theWheel = new Winwheel({ + ...this.WinWheelOptions, + numSegments: this.segments.length, + segments: this.segments + }) + + if (this.wheelSpinning) { + this.theWheel.stopAnimation(false) // Stop the animation, false as param so does not call callback function. + } + + this.theWheel.rotationAngle = 0 // Re-set the wheel angle to 0 degrees. + this.theWheel.draw() // Call draw to render changes to the wheel. + this.wheelSpinning = false // Reset to false to power buttons and spin can be clicked again. + }, + initSpin() { + this.loadingPrize = true + this.resetWheel() + this.loadingPrize = false + }, + onFinishSpin(indicatedSegment) { + this.prizeName = indicatedSegment.text + this.showPrize() + } + }, + template: ` +
+
+
+
+ +

Sorry, your browser doesn't support canvas. Please try Google Chrome.

+
+
+
+ SPIN! +
+
+
+ +
+ ` +}); \ No newline at end of file diff --git a/javascripts/components/options/options-button-grid.js b/javascripts/components/options/options-button-grid.js index 99df4512f..9e1d8c769 100644 --- a/javascripts/components/options/options-button-grid.js +++ b/javascripts/components/options/options-button-grid.js @@ -146,5 +146,8 @@ Vue.component("options-button-grid", { onclick="Modal.animationOptions.show();" >Animations +
+ +
` }); diff --git a/javascripts/core/extensions.js b/javascripts/core/extensions.js index 1d0dc576b..df9ab03d6 100644 --- a/javascripts/core/extensions.js +++ b/javascripts/core/extensions.js @@ -1,9 +1,7 @@ "use strict"; Array.prototype.distinct = function() { - return this.filter(function (value, index, self) { - return self.indexOf(value) === index; - }); + return this.filter((value, index, self) => { return self.indexOf(value) === index }); }; Math.wrap = function(number, min, max) { diff --git a/javascripts/lib/tweenmax.min.js b/javascripts/lib/tweenmax.min.js new file mode 100644 index 000000000..efa741606 --- /dev/null +++ b/javascripts/lib/tweenmax.min.js @@ -0,0 +1,17 @@ +/*! + * VERSION: 2.1.3 + * DATE: 2019-05-17 + * UPDATES AND DOCS AT: http://greensock.com + * + * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin + * + * @license Copyright (c) 2008-2019, GreenSock. All rights reserved. + * This work is subject to the terms at http://greensock.com/standard-license or for + * Club GreenSock members, the software agreement that was issued with your membership. + * + * @author: Jack Doyle, jack@greensock.com + **/ +var _gsScope="undefined"!=typeof module&&module.exports&&"undefined"!=typeof global?global:this||window;(_gsScope._gsQueue||(_gsScope._gsQueue=[])).push(function(){"use strict";_gsScope._gsDefine("TweenMax",["core.Animation","core.SimpleTimeline","TweenLite"],function(a,b,c){var d=function(a){var b,c=[],d=a.length;for(b=0;b!==d;c.push(a[b++]));return c},e=function(a,b,c){var d,e,f=a.cycle;for(d in f)e=f[d],a[d]="function"==typeof e?e(c,b[c],b):e[c%e.length];delete a.cycle},f=function(a){if("function"==typeof a)return a;var b="object"==typeof a?a:{each:a},c=b.ease,d=b.from||0,e=b.base||0,f={},g=isNaN(d),h=b.axis,i={center:.5,end:1}[d]||0;return function(a,j,k){var l,m,n,o,p,q,r,s,t,u=(k||b).length,v=f[u];if(!v){if(t="auto"===b.grid?0:(b.grid||[1/0])[0],!t){for(r=-(1/0);r<(r=k[t++].getBoundingClientRect().left)&&u>t;);t--}for(v=f[u]=[],l=g?Math.min(t,u)*i-.5:d%t,m=g?u*i/t-.5:d/t|0,r=0,s=1/0,q=0;u>q;q++)n=q%t-l,o=m-(q/t|0),v[q]=p=h?Math.abs("y"===h?o:n):Math.sqrt(n*n+o*o),p>r&&(r=p),s>p&&(s=p);v.max=r-s,v.min=s,v.v=u=b.amount||b.each*(t>u?u-1:h?"y"===h?u/t:t:Math.max(t,u/t))||0,v.b=0>u?e-u:e}return u=(v[a]-v.min)/v.max,v.b+(c?c.getRatio(u):u)*v.v}},g=function(a,b,d){c.call(this,a,b,d),this._cycle=0,this._yoyo=this.vars.yoyo===!0||!!this.vars.yoyoEase,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._repeat&&this._uncache(!0),this.render=g.prototype.render},h=1e-8,i=c._internals,j=i.isSelector,k=i.isArray,l=g.prototype=c.to({},.1,{}),m=[];g.version="2.1.3",l.constructor=g,l.kill()._gc=!1,g.killTweensOf=g.killDelayedCallsTo=c.killTweensOf,g.getTweensOf=c.getTweensOf,g.lagSmoothing=c.lagSmoothing,g.ticker=c.ticker,g.render=c.render,g.distribute=f,l.invalidate=function(){return this._yoyo=this.vars.yoyo===!0||!!this.vars.yoyoEase,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._yoyoEase=null,this._uncache(!0),c.prototype.invalidate.call(this)},l.updateTo=function(a,b){var d,e=this,f=e.ratio,g=e.vars.immediateRender||a.immediateRender;b&&e._startTime.998){var h=e._totalTime;e.render(0,!0,!1),e._initted=!1,e.render(h,!0,!1)}else if(e._initted=!1,e._init(),e._time>0||g)for(var i,j=1/(1-f),k=e._firstPT;k;)i=k.s+k.c,k.c*=j,k.s=i-k.c,k=k._next;return e},l.render=function(a,b,d){this._initted||0===this._duration&&this.vars.repeat&&this.invalidate();var e,f,g,j,k,l,m,n,o,p=this,q=p._dirty?p.totalDuration():p._totalDuration,r=p._time,s=p._totalTime,t=p._cycle,u=p._duration,v=p._rawPrevTime;if(a>=q-h&&a>=0?(p._totalTime=q,p._cycle=p._repeat,p._yoyo&&0!==(1&p._cycle)?(p._time=0,p.ratio=p._ease._calcEnd?p._ease.getRatio(0):0):(p._time=u,p.ratio=p._ease._calcEnd?p._ease.getRatio(1):1),p._reversed||(e=!0,f="onComplete",d=d||p._timeline.autoRemoveChildren),0===u&&(p._initted||!p.vars.lazy||d)&&(p._startTime===p._timeline._duration&&(a=0),(0>v||0>=a&&a>=-h||v===h&&"isPause"!==p.data)&&v!==a&&(d=!0,v>h&&(f="onReverseComplete")),p._rawPrevTime=n=!b||a||v===a?a:h)):h>a?(p._totalTime=p._time=p._cycle=0,p.ratio=p._ease._calcEnd?p._ease.getRatio(0):0,(0!==s||0===u&&v>0)&&(f="onReverseComplete",e=p._reversed),a>-h?a=0:0>a&&(p._active=!1,0===u&&(p._initted||!p.vars.lazy||d)&&(v>=0&&(d=!0),p._rawPrevTime=n=!b||a||v===a?a:h)),p._initted||(d=!0)):(p._totalTime=p._time=a,0!==p._repeat&&(j=u+p._repeatDelay,p._cycle=p._totalTime/j>>0,0!==p._cycle&&p._cycle===p._totalTime/j&&a>=s&&p._cycle--,p._time=p._totalTime-p._cycle*j,p._yoyo&&0!==(1&p._cycle)&&(p._time=u-p._time,o=p._yoyoEase||p.vars.yoyoEase,o&&(p._yoyoEase||(o!==!0||p._initted?p._yoyoEase=o=o===!0?p._ease:o instanceof Ease?o:Ease.map[o]:(o=p.vars.ease,p._yoyoEase=o=o?o instanceof Ease?o:"function"==typeof o?new Ease(o,p.vars.easeParams):Ease.map[o]||c.defaultEase:c.defaultEase)),p.ratio=o?1-o.getRatio((u-p._time)/u):0)),p._time>u?p._time=u:p._time<0&&(p._time=0)),p._easeType&&!o?(k=p._time/u,l=p._easeType,m=p._easePower,(1===l||3===l&&k>=.5)&&(k=1-k),3===l&&(k*=2),1===m?k*=k:2===m?k*=k*k:3===m?k*=k*k*k:4===m&&(k*=k*k*k*k),p.ratio=1===l?1-k:2===l?k:p._time/u<.5?k/2:1-k/2):o||(p.ratio=p._ease.getRatio(p._time/u))),r===p._time&&!d&&t===p._cycle)return void(s!==p._totalTime&&p._onUpdate&&(b||p._callback("onUpdate")));if(!p._initted){if(p._init(),!p._initted||p._gc)return;if(!d&&p._firstPT&&(p.vars.lazy!==!1&&p._duration||p.vars.lazy&&!p._duration))return p._time=r,p._totalTime=s,p._rawPrevTime=v,p._cycle=t,i.lazyTweens.push(p),void(p._lazy=[a,b]);!p._time||e||o?e&&this._ease._calcEnd&&!o&&(p.ratio=p._ease.getRatio(0===p._time?0:1)):p.ratio=p._ease.getRatio(p._time/u)}for(p._lazy!==!1&&(p._lazy=!1),p._active||!p._paused&&p._time!==r&&a>=0&&(p._active=!0),0===s&&(2===p._initted&&a>0&&p._init(),p._startAt&&(a>=0?p._startAt.render(a,!0,d):f||(f="_dummyGS")),p.vars.onStart&&(0!==p._totalTime||0===u)&&(b||p._callback("onStart"))),g=p._firstPT;g;)g.f?g.t[g.p](g.c*p.ratio+g.s):g.t[g.p]=g.c*p.ratio+g.s,g=g._next;p._onUpdate&&(0>a&&p._startAt&&p._startTime&&p._startAt.render(a,!0,d),b||(p._totalTime!==s||f)&&p._callback("onUpdate")),p._cycle!==t&&(b||p._gc||p.vars.onRepeat&&p._callback("onRepeat")),f&&(!p._gc||d)&&(0>a&&p._startAt&&!p._onUpdate&&p._startTime&&p._startAt.render(a,!0,d),e&&(p._timeline.autoRemoveChildren&&p._enabled(!1,!1),p._active=!1),!b&&p.vars[f]&&p._callback(f),0===u&&p._rawPrevTime===h&&n!==h&&(p._rawPrevTime=0))},g.to=function(a,b,c){return new g(a,b,c)},g.from=function(a,b,c){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,new g(a,b,c)},g.fromTo=function(a,b,c,d){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,new g(a,b,d)},g.staggerTo=g.allTo=function(a,b,h,i,l,n,o){var p,q,r,s,t=[],u=f(h.stagger||i),v=h.cycle,w=(h.startAt||m).cycle;for(k(a)||("string"==typeof a&&(a=c.selector(a)||a),j(a)&&(a=d(a))),a=a||[],p=a.length-1,r=0;p>=r;r++){q={};for(s in h)q[s]=h[s];if(v&&(e(q,a,r),null!=q.duration&&(b=q.duration,delete q.duration)),w){w=q.startAt={};for(s in h.startAt)w[s]=h.startAt[s];e(q.startAt,a,r)}q.delay=u(r,a[r],a)+(q.delay||0),r===p&&l&&(q.onComplete=function(){h.onComplete&&h.onComplete.apply(h.onCompleteScope||this,arguments),l.apply(o||h.callbackScope||this,n||m)}),t[r]=new g(a[r],b,q)}return t},g.staggerFrom=g.allFrom=function(a,b,c,d,e,f,h){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,g.staggerTo(a,b,c,d,e,f,h)},g.staggerFromTo=g.allFromTo=function(a,b,c,d,e,f,h,i){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,g.staggerTo(a,b,d,e,f,h,i)},g.delayedCall=function(a,b,c,d,e){return new g(b,0,{delay:a,onComplete:b,onCompleteParams:c,callbackScope:d,onReverseComplete:b,onReverseCompleteParams:c,immediateRender:!1,useFrames:e,overwrite:0})},g.set=function(a,b){return new g(a,0,b)},g.isTweening=function(a){return c.getTweensOf(a,!0).length>0};var n=function(a,b){for(var d=[],e=0,f=a._first;f;)f instanceof c?d[e++]=f:(b&&(d[e++]=f),d=d.concat(n(f,b)),e=d.length),f=f._next;return d},o=g.getAllTweens=function(b){return n(a._rootTimeline,b).concat(n(a._rootFramesTimeline,b))};g.killAll=function(a,c,d,e){null==c&&(c=!0),null==d&&(d=!0);var f,g,h,i=o(0!=e),j=i.length,k=c&&d&&e;for(h=0;j>h;h++)g=i[h],(k||g instanceof b||(f=g.target===g.vars.onComplete)&&d||c&&!f)&&(a?g.totalTime(g._reversed?0:g.totalDuration()):g._enabled(!1,!1))},g.killChildTweensOf=function(a,b){if(null!=a){var e,f,h,l,m,n=i.tweenLookup;if("string"==typeof a&&(a=c.selector(a)||a),j(a)&&(a=d(a)),k(a))for(l=a.length;--l>-1;)g.killChildTweensOf(a[l],b);else{e=[];for(h in n)for(f=n[h].target.parentNode;f;)f===a&&(e=e.concat(n[h].tweens)),f=f.parentNode;for(m=e.length,l=0;m>l;l++)b&&e[l].totalTime(e[l].totalDuration()),e[l]._enabled(!1,!1)}}};var p=function(a,c,d,e){c=c!==!1,d=d!==!1,e=e!==!1;for(var f,g,h=o(e),i=c&&d&&e,j=h.length;--j>-1;)g=h[j],(i||g instanceof b||(f=g.target===g.vars.onComplete)&&d||c&&!f)&&g.paused(a)};return g.pauseAll=function(a,b,c){p(!0,a,b,c)},g.resumeAll=function(a,b,c){p(!1,a,b,c)},g.globalTimeScale=function(b){var d=a._rootTimeline,e=c.ticker.time;return arguments.length?(b=b||h,d._startTime=e-(e-d._startTime)*d._timeScale/b,d=a._rootFramesTimeline,e=c.ticker.frame,d._startTime=e-(e-d._startTime)*d._timeScale/b,d._timeScale=a._rootTimeline._timeScale=b,b):d._timeScale},l.progress=function(a,b){return arguments.length?this.totalTime(this.duration()*(this._yoyo&&0!==(1&this._cycle)?1-a:a)+this._cycle*(this._duration+this._repeatDelay),b):this.duration()?this._time/this._duration:this.ratio},l.totalProgress=function(a,b){return arguments.length?this.totalTime(this.totalDuration()*a,b):this._totalTime/this.totalDuration()},l.time=function(a,b){if(!arguments.length)return this._time;this._dirty&&this.totalDuration();var c=this._duration,d=this._cycle,e=d*(c+this._repeatDelay);return a>c&&(a=c),this.totalTime(this._yoyo&&1&d?c-a+e:this._repeat?a+e:a,b)},l.duration=function(b){return arguments.length?a.prototype.duration.call(this,b):this._duration},l.totalDuration=function(a){return arguments.length?-1===this._repeat?this:this.duration((a-this._repeat*this._repeatDelay)/(this._repeat+1)):(this._dirty&&(this._totalDuration=-1===this._repeat?999999999999:this._duration*(this._repeat+1)+this._repeatDelay*this._repeat,this._dirty=!1),this._totalDuration)},l.repeat=function(a){return arguments.length?(this._repeat=a,this._uncache(!0)):this._repeat},l.repeatDelay=function(a){return arguments.length?(this._repeatDelay=a,this._uncache(!0)):this._repeatDelay},l.yoyo=function(a){return arguments.length?(this._yoyo=a,this):this._yoyo},g},!0),_gsScope._gsDefine("TimelineLite",["core.Animation","core.SimpleTimeline","TweenLite"],function(a,b,c){var d=function(a){b.call(this,a);var c,d,e=this,f=e.vars;e._labels={},e.autoRemoveChildren=!!f.autoRemoveChildren,e.smoothChildTiming=!!f.smoothChildTiming,e._sortChildren=!0,e._onUpdate=f.onUpdate;for(d in f)c=f[d],i(c)&&-1!==c.join("").indexOf("{self}")&&(f[d]=e._swapSelfInParams(c));i(f.tweens)&&e.add(f.tweens,0,f.align,f.stagger)},e=1e-8,f=c._internals,g=d._internals={},h=f.isSelector,i=f.isArray,j=f.lazyTweens,k=f.lazyRender,l=_gsScope._gsDefine.globals,m=function(a){var b,c={};for(b in a)c[b]=a[b];return c},n=function(a,b,c){var d,e,f=a.cycle;for(d in f)e=f[d],a[d]="function"==typeof e?e(c,b[c],b):e[c%e.length];delete a.cycle},o=g.pauseCallback=function(){},p=function(a){var b,c=[],d=a.length;for(b=0;b!==d;c.push(a[b++]));return c},q=function(a,b,c,d){var e="immediateRender";return e in b||(b[e]=!(c&&c[e]===!1||d)),b},r=function(a){if("function"==typeof a)return a;var b="object"==typeof a?a:{each:a},c=b.ease,d=b.from||0,e=b.base||0,f={},g=isNaN(d),h=b.axis,i={center:.5,end:1}[d]||0;return function(a,j,k){var l,m,n,o,p,q,r,s,t,u=(k||b).length,v=f[u];if(!v){if(t="auto"===b.grid?0:(b.grid||[1/0])[0],!t){for(r=-(1/0);r<(r=k[t++].getBoundingClientRect().left)&&u>t;);t--}for(v=f[u]=[],l=g?Math.min(t,u)*i-.5:d%t,m=g?u*i/t-.5:d/t|0,r=0,s=1/0,q=0;u>q;q++)n=q%t-l,o=m-(q/t|0),v[q]=p=h?Math.abs("y"===h?o:n):Math.sqrt(n*n+o*o),p>r&&(r=p),s>p&&(s=p);v.max=r-s,v.min=s,v.v=u=b.amount||b.each*(t>u?u-1:h?"y"===h?u/t:t:Math.max(t,u/t))||0,v.b=0>u?e-u:e}return u=(v[a]-v.min)/v.max,v.b+(c?c.getRatio(u):u)*v.v}},s=d.prototype=new b;return d.version="2.1.3",d.distribute=r,s.constructor=d,s.kill()._gc=s._forcingPlayhead=s._hasPause=!1,s.to=function(a,b,d,e){var f=d.repeat&&l.TweenMax||c;return b?this.add(new f(a,b,d),e):this.set(a,d,e)},s.from=function(a,b,d,e){return this.add((d.repeat&&l.TweenMax||c).from(a,b,q(this,d)),e)},s.fromTo=function(a,b,d,e,f){var g=e.repeat&&l.TweenMax||c;return e=q(this,e,d),b?this.add(g.fromTo(a,b,d,e),f):this.set(a,e,f)},s.staggerTo=function(a,b,e,f,g,i,j,k){var l,o,q=new d({onComplete:i,onCompleteParams:j,callbackScope:k,smoothChildTiming:this.smoothChildTiming}),s=r(e.stagger||f),t=e.startAt,u=e.cycle;for("string"==typeof a&&(a=c.selector(a)||a),a=a||[],h(a)&&(a=p(a)),o=0;of&&(e=1),i.add(g,f)),g=h;return j.add(i,0),e&&i.totalDuration(),i},s.add=function(e,f,g,h){var j,k,l,m,n,o,p=this;if("number"!=typeof f&&(f=p._parseTimeOrLabel(f,0,!0,e)),!(e instanceof a)){if(e instanceof Array||e&&e.push&&i(e)){for(g=g||"normal",h=h||0,j=f,k=e.length,l=0;k>l;l++)i(m=e[l])&&(m=new d({tweens:m})),p.add(m,j),"string"!=typeof m&&"function"!=typeof m&&("sequence"===g?j=m._startTime+m.totalDuration()/m._timeScale:"start"===g&&(m._startTime-=m.delay())),j+=h;return p._uncache(!0)}if("string"==typeof e)return p.addLabel(e,f);if("function"!=typeof e)throw"Cannot add "+e+" into the timeline; it is not a tween, timeline, function, or string.";e=c.delayedCall(0,e)}if(b.prototype.add.call(p,e,f),(e._time||!e._duration&&e._initted)&&(j=(p.rawTime()-e._startTime)*e._timeScale,(!e._duration||Math.abs(Math.max(0,Math.min(e.totalDuration(),j)))-e._totalTime>1e-5)&&e.render(j,!1,!1)),(p._gc||p._time===p._duration)&&!p._paused&&p._duratione._startTime;n._timeline;)o&&n._timeline.smoothChildTiming?n.totalTime(n._totalTime,!0):n._gc&&n._enabled(!0,!1),n=n._timeline;return p},s.remove=function(b){if(b instanceof a){this._remove(b,!1);var c=b._timeline=b.vars.useFrames?a._rootFramesTimeline:a._rootTimeline;return b._startTime=(b._paused?b._pauseTime:c._time)-(b._reversed?b.totalDuration()-b._totalTime:b._totalTime)/b._timeScale,this}if(b instanceof Array||b&&b.push&&i(b)){for(var d=b.length;--d>-1;)this.remove(b[d]);return this}return"string"==typeof b?this.removeLabel(b):this.kill(null,b)},s._remove=function(a,c){b.prototype._remove.call(this,a,c);var d=this._last;return d?this._time>this.duration()&&(this._time=this._duration,this._totalTime=this._totalDuration):this._time=this._totalTime=this._duration=this._totalDuration=0,this},s.append=function(a,b){return this.add(a,this._parseTimeOrLabel(null,b,!0,a))},s.insert=s.insertMultiple=function(a,b,c,d){return this.add(a,b||0,c,d)},s.appendMultiple=function(a,b,c,d){return this.add(a,this._parseTimeOrLabel(null,b,!0,a),c,d)},s.addLabel=function(a,b){return this._labels[a]=this._parseTimeOrLabel(b),this},s.addPause=function(a,b,d,e){var f=c.delayedCall(0,o,d,e||this);return f.vars.onComplete=f.vars.onReverseComplete=b,f.data="isPause",this._hasPause=!0,this.add(f,a)},s.removeLabel=function(a){return delete this._labels[a],this},s.getLabelTime=function(a){return null!=this._labels[a]?this._labels[a]:-1},s._parseTimeOrLabel=function(b,c,d,e){var f,g;if(e instanceof a&&e.timeline===this)this.remove(e);else if(e&&(e instanceof Array||e.push&&i(e)))for(g=e.length;--g>-1;)e[g]instanceof a&&e[g].timeline===this&&this.remove(e[g]);if(f="number"!=typeof b||c?this.duration()>99999999999?this.recent().endTime(!1):this._duration:0,"string"==typeof c)return this._parseTimeOrLabel(c,d&&"number"==typeof b&&null==this._labels[c]?b-f:0,d);if(c=c||0,"string"!=typeof b||!isNaN(b)&&null==this._labels[b])null==b&&(b=f);else{if(g=b.indexOf("="),-1===g)return null==this._labels[b]?d?this._labels[b]=f+c:c:this._labels[b]+c;c=parseInt(b.charAt(g-1)+"1",10)*Number(b.substr(g+1)),b=g>1?this._parseTimeOrLabel(b.substr(0,g-1),0,d):f}return Number(b)+c},s.seek=function(a,b){return this.totalTime("number"==typeof a?a:this._parseTimeOrLabel(a),b!==!1)},s.stop=function(){return this.paused(!0)},s.gotoAndPlay=function(a,b){return this.play(a,b)},s.gotoAndStop=function(a,b){return this.pause(a,b)},s.render=function(a,b,c){this._gc&&this._enabled(!0,!1);var d,f,g,h,i,l,m,n,o=this,p=o._time,q=o._dirty?o.totalDuration():o._totalDuration,r=o._startTime,s=o._timeScale,t=o._paused;if(p!==o._time&&(a+=o._time-p),o._hasPause&&!o._forcingPlayhead&&!b){if(a>p)for(d=o._first;d&&d._startTime<=a&&!l;)d._duration||"isPause"!==d.data||d.ratio||0===d._startTime&&0===o._rawPrevTime||(l=d),d=d._next;else for(d=o._last;d&&d._startTime>=a&&!l;)d._duration||"isPause"===d.data&&d._rawPrevTime>0&&(l=d),d=d._prev;l&&(o._time=o._totalTime=a=l._startTime,n=o._startTime+(o._reversed?o._duration-a:a)/o._timeScale)}if(a>=q-e&&a>=0)o._totalTime=o._time=q,o._reversed||o._hasPausedChild()||(f=!0,h="onComplete",i=!!o._timeline.autoRemoveChildren,0===o._duration&&(0>=a&&a>=-e||o._rawPrevTime<0||o._rawPrevTime===e)&&o._rawPrevTime!==a&&o._first&&(i=!0,o._rawPrevTime>e&&(h="onReverseComplete"))),o._rawPrevTime=o._duration||!b||a||o._rawPrevTime===a?a:e,a=q+1e-4;else if(e>a)if(o._totalTime=o._time=0,a>-e&&(a=0),(0!==p||0===o._duration&&o._rawPrevTime!==e&&(o._rawPrevTime>0||0>a&&o._rawPrevTime>=0))&&(h="onReverseComplete",f=o._reversed),0>a)o._active=!1,o._timeline.autoRemoveChildren&&o._reversed?(i=f=!0,h="onReverseComplete"):o._rawPrevTime>=0&&o._first&&(i=!0),o._rawPrevTime=a;else{if(o._rawPrevTime=o._duration||!b||a||o._rawPrevTime===a?a:e,0===a&&f)for(d=o._first;d&&0===d._startTime;)d._duration||(f=!1),d=d._next;a=0,o._initted||(i=!0)}else o._totalTime=o._time=o._rawPrevTime=a;if(o._time!==p&&o._first||c||i||l){if(o._initted||(o._initted=!0),o._active||!o._paused&&o._time!==p&&a>0&&(o._active=!0),0===p&&o.vars.onStart&&(0===o._time&&o._duration||b||o._callback("onStart")),m=o._time,m>=p)for(d=o._first;d&&(g=d._next,m===o._time&&(!o._paused||t));)(d._active||d._startTime<=m&&!d._paused&&!d._gc)&&(l===d&&(o.pause(),o._pauseTime=n),d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)),d=g;else for(d=o._last;d&&(g=d._prev,m===o._time&&(!o._paused||t));){if(d._active||d._startTime<=p&&!d._paused&&!d._gc){if(l===d){for(l=d._prev;l&&l.endTime()>o._time;)l.render(l._reversed?l.totalDuration()-(a-l._startTime)*l._timeScale:(a-l._startTime)*l._timeScale,b,c),l=l._prev;l=null,o.pause(),o._pauseTime=n}d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)}d=g}o._onUpdate&&(b||(j.length&&k(),o._callback("onUpdate"))),h&&(o._gc||(r===o._startTime||s!==o._timeScale)&&(0===o._time||q>=o.totalDuration())&&(f&&(j.length&&k(),o._timeline.autoRemoveChildren&&o._enabled(!1,!1),o._active=!1),!b&&o.vars[h]&&o._callback(h)))}},s._hasPausedChild=function(){for(var a=this._first;a;){if(a._paused||a instanceof d&&a._hasPausedChild())return!0;a=a._next}return!1},s.getChildren=function(a,b,d,e){e=e||-9999999999;for(var f=[],g=this._first,h=0;g;)g._startTime-1;)(d[e].timeline===this||b&&this._contains(d[e]))&&(g[h++]=d[e]);return f&&this._enabled(!1,!0),g},s.recent=function(){return this._recent},s._contains=function(a){for(var b=a.timeline;b;){if(b===this)return!0;b=b.timeline}return!1},s.shiftChildren=function(a,b,c){c=c||0;for(var d,e=this._first,f=this._labels;e;)e._startTime>=c&&(e._startTime+=a),e=e._next;if(b)for(d in f)f[d]>=c&&(f[d]+=a);return this._uncache(!0)},s._kill=function(a,b){if(!a&&!b)return this._enabled(!1,!1);for(var c=b?this.getTweensOf(b):this.getChildren(!0,!0,!1),d=c.length,e=!1;--d>-1;)c[d]._kill(a,b)&&(e=!0);return e},s.clear=function(a){var b=this.getChildren(!1,!0,!0),c=b.length;for(this._time=this._totalTime=0;--c>-1;)b[c]._enabled(!1,!1);return a!==!1&&(this._labels={}),this._uncache(!0)},s.invalidate=function(){for(var b=this._first;b;)b.invalidate(),b=b._next;return a.prototype.invalidate.call(this)},s._enabled=function(a,c){if(a===this._gc)for(var d=this._first;d;)d._enabled(a,!0),d=d._next;return b.prototype._enabled.call(this,a,c)},s.totalTime=function(b,c,d){this._forcingPlayhead=!0;var e=a.prototype.totalTime.apply(this,arguments);return this._forcingPlayhead=!1,e},s.duration=function(a){return arguments.length?(0!==this.duration()&&0!==a&&this.timeScale(this._duration/a),this):(this._dirty&&this.totalDuration(),this._duration)},s.totalDuration=function(a){if(!arguments.length){if(this._dirty){for(var b,c,d=0,e=this,f=e._last,g=999999999999;f;)b=f._prev,f._dirty&&f.totalDuration(),f._startTime>g&&e._sortChildren&&!f._paused&&!e._calculatingDuration?(e._calculatingDuration=1,e.add(f,f._startTime-f._delay),e._calculatingDuration=0):g=f._startTime,f._startTime<0&&!f._paused&&(d-=f._startTime,e._timeline.smoothChildTiming&&(e._startTime+=f._startTime/e._timeScale,e._time-=f._startTime,e._totalTime-=f._startTime,e._rawPrevTime-=f._startTime),e.shiftChildren(-f._startTime,!1,-9999999999),g=0),c=f._startTime+f._totalDuration/f._timeScale,c>d&&(d=c),f=b;e._duration=e._totalDuration=d,e._dirty=!1}return this._totalDuration}return a&&this.totalDuration()?this.timeScale(this._totalDuration/a):this},s.paused=function(b){if(b===!1&&this._paused)for(var c=this._first;c;)c._startTime===this._time&&"isPause"===c.data&&(c._rawPrevTime=0),c=c._next;return a.prototype.paused.apply(this,arguments)},s.usesFrames=function(){for(var b=this._timeline;b._timeline;)b=b._timeline;return b===a._rootFramesTimeline},s.rawTime=function(a){return a&&(this._paused||this._repeat&&this.time()>0&&this.totalProgress()<1)?this._totalTime%(this._duration+this._repeatDelay):this._paused?this._totalTime:(this._timeline.rawTime(a)-this._startTime)*this._timeScale},d},!0),_gsScope._gsDefine("TimelineMax",["TimelineLite","TweenLite","easing.Ease"],function(a,b,c){var d=function(b){a.call(this,b),this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._cycle=0,this._yoyo=!!this.vars.yoyo,this._dirty=!0},e=1e-8,f=b._internals,g=f.lazyTweens,h=f.lazyRender,i=_gsScope._gsDefine.globals,j=new c(null,null,1,0),k=d.prototype=new a;return k.constructor=d,k.kill()._gc=!1,d.version="2.1.3",k.invalidate=function(){return this._yoyo=!!this.vars.yoyo,this._repeat=this.vars.repeat||0,this._repeatDelay=this.vars.repeatDelay||0,this._uncache(!0),a.prototype.invalidate.call(this)},k.addCallback=function(a,c,d,e){return this.add(b.delayedCall(0,a,d,e),c)},k.removeCallback=function(a,b){if(a)if(null==b)this._kill(null,a);else for(var c=this.getTweensOf(a,!1),d=c.length,e=this._parseTimeOrLabel(b);--d>-1;)c[d]._startTime===e&&c[d]._enabled(!1,!1);return this},k.removePause=function(b){return this.removeCallback(a._internals.pauseCallback,b)},k.tweenTo=function(a,c){c=c||{};var d,e,f,g={ease:j,useFrames:this.usesFrames(),immediateRender:!1,lazy:!1},h=c.repeat&&i.TweenMax||b;for(e in c)g[e]=c[e];return g.time=this._parseTimeOrLabel(a),d=Math.abs(Number(g.time)-this._time)/this._timeScale||.001,f=new h(this,d,g),g.onStart=function(){f.target.paused(!0),f.vars.time===f.target.time()||d!==f.duration()||f.isFromTo||f.duration(Math.abs(f.vars.time-f.target.time())/f.target._timeScale).render(f.time(),!0,!0),c.onStart&&c.onStart.apply(c.onStartScope||c.callbackScope||f,c.onStartParams||[])},f},k.tweenFromTo=function(a,b,c){c=c||{},a=this._parseTimeOrLabel(a),c.startAt={onComplete:this.seek,onCompleteParams:[a],callbackScope:this},c.immediateRender=c.immediateRender!==!1;var d=this.tweenTo(b,c);return d.isFromTo=1,d.duration(Math.abs(d.vars.time-a)/this._timeScale||.001)},k.render=function(a,b,c){this._gc&&this._enabled(!0,!1);var d,f,i,j,k,l,m,n,o,p=this,q=p._time,r=p._dirty?p.totalDuration():p._totalDuration,s=p._duration,t=p._totalTime,u=p._startTime,v=p._timeScale,w=p._rawPrevTime,x=p._paused,y=p._cycle;if(q!==p._time&&(a+=p._time-q),a>=r-e&&a>=0)p._locked||(p._totalTime=r,p._cycle=p._repeat),p._reversed||p._hasPausedChild()||(f=!0,j="onComplete",k=!!p._timeline.autoRemoveChildren,0===p._duration&&(0>=a&&a>=-e||0>w||w===e)&&w!==a&&p._first&&(k=!0,w>e&&(j="onReverseComplete"))),p._rawPrevTime=p._duration||!b||a||p._rawPrevTime===a?a:e,p._yoyo&&1&p._cycle?p._time=a=0:(p._time=s,a=s+1e-4);else if(e>a)if(p._locked||(p._totalTime=p._cycle=0),p._time=0,a>-e&&(a=0),(0!==q||0===s&&w!==e&&(w>0||0>a&&w>=0)&&!p._locked)&&(j="onReverseComplete",f=p._reversed),0>a)p._active=!1,p._timeline.autoRemoveChildren&&p._reversed?(k=f=!0,j="onReverseComplete"):w>=0&&p._first&&(k=!0),p._rawPrevTime=a;else{if(p._rawPrevTime=s||!b||a||p._rawPrevTime===a?a:e,0===a&&f)for(d=p._first;d&&0===d._startTime;)d._duration||(f=!1),d=d._next;a=0,p._initted||(k=!0)}else 0===s&&0>w&&(k=!0),p._time=p._rawPrevTime=a,p._locked||(p._totalTime=a,0!==p._repeat&&(l=s+p._repeatDelay,p._cycle=p._totalTime/l>>0,p._cycle&&p._cycle===p._totalTime/l&&a>=t&&p._cycle--,p._time=p._totalTime-p._cycle*l,p._yoyo&&1&p._cycle&&(p._time=s-p._time),p._time>s?(p._time=s,a=s+1e-4):p._time<0?p._time=a=0:a=p._time));if(p._hasPause&&!p._forcingPlayhead&&!b){if(a=p._time,a>q||p._repeat&&y!==p._cycle)for(d=p._first;d&&d._startTime<=a&&!m;)d._duration||"isPause"!==d.data||d.ratio||0===d._startTime&&0===p._rawPrevTime||(m=d),d=d._next;else for(d=p._last;d&&d._startTime>=a&&!m;)d._duration||"isPause"===d.data&&d._rawPrevTime>0&&(m=d),d=d._prev;m&&(o=p._startTime+(p._reversed?p._duration-m._startTime:m._startTime)/p._timeScale,m._startTime0&&(p._active=!0),0===t&&p.vars.onStart&&(0===p._totalTime&&p._totalDuration||b||p._callback("onStart")),n=p._time,n>=q)for(d=p._first;d&&(i=d._next,n===p._time&&(!p._paused||x));)(d._active||d._startTime<=p._time&&!d._paused&&!d._gc)&&(m===d&&(p.pause(),p._pauseTime=o),d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)),d=i;else for(d=p._last;d&&(i=d._prev,n===p._time&&(!p._paused||x));){if(d._active||d._startTime<=q&&!d._paused&&!d._gc){if(m===d){for(m=d._prev;m&&m.endTime()>p._time;)m.render(m._reversed?m.totalDuration()-(a-m._startTime)*m._timeScale:(a-m._startTime)*m._timeScale,b,c),m=m._prev;m=null,p.pause(),p._pauseTime=o}d._reversed?d.render((d._dirty?d.totalDuration():d._totalDuration)-(a-d._startTime)*d._timeScale,b,c):d.render((a-d._startTime)*d._timeScale,b,c)}d=i}p._onUpdate&&(b||(g.length&&h(),p._callback("onUpdate"))),j&&(p._locked||p._gc||(u===p._startTime||v!==p._timeScale)&&(0===p._time||r>=p.totalDuration())&&(f&&(g.length&&h(),p._timeline.autoRemoveChildren&&p._enabled(!1,!1),p._active=!1),!b&&p.vars[j]&&p._callback(j)))},k.getActive=function(a,b,c){var d,e,f=[],g=this.getChildren(a||null==a,b||null==a,!!c),h=0,i=g.length;for(d=0;i>d;d++)e=g[d],e.isActive()&&(f[h++]=e);return f},k.getLabelAfter=function(a){a||0!==a&&(a=this._time);var b,c=this.getLabelsArray(),d=c.length;for(b=0;d>b;b++)if(c[b].time>a)return c[b].name;return null},k.getLabelBefore=function(a){null==a&&(a=this._time);for(var b=this.getLabelsArray(),c=b.length;--c>-1;)if(b[c].timec&&(a=c),this.totalTime(this._yoyo&&1&d?c-a+e:this._repeat?a+e:a,b)},k.repeat=function(a){return arguments.length?(this._repeat=a,this._uncache(!0)):this._repeat},k.repeatDelay=function(a){return arguments.length?(this._repeatDelay=a,this._uncache(!0)):this._repeatDelay},k.yoyo=function(a){return arguments.length?(this._yoyo=a,this):this._yoyo},k.currentLabel=function(a){return arguments.length?this.seek(a,!0):this.getLabelBefore(this._time+e)},d},!0),function(){var a=180/Math.PI,b=[],c=[],d=[],e={},f=_gsScope._gsDefine.globals,g=function(a,b,c,d){c===d&&(c=d-(d-b)/1e6),a===b&&(b=a+(c-a)/1e6),this.a=a,this.b=b,this.c=c,this.d=d,this.da=d-a,this.ca=c-a,this.ba=b-a},h=",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,",i=function(a,b,c,d){var e={a:a},f={},g={},h={c:d},i=(a+b)/2,j=(b+c)/2,k=(c+d)/2,l=(i+j)/2,m=(j+k)/2,n=(m-l)/8;return e.b=i+(a-i)/4,f.b=l+n,e.c=f.a=(e.b+f.b)/2,f.c=g.a=(l+m)/2,g.b=m-n,h.b=k+(d-k)/4,g.c=h.a=(g.b+h.b)/2,[e,f,g,h]},j=function(a,e,f,g,h){var j,k,l,m,n,o,p,q,r,s,t,u,v,w=a.length-1,x=0,y=a[0].a;for(j=0;w>j;j++)n=a[x],k=n.a,l=n.d,m=a[x+1].d,h?(t=b[j],u=c[j],v=(u+t)*e*.25/(g?.5:d[j]||.5),o=l-(l-k)*(g?.5*e:0!==t?v/t:0),p=l+(m-l)*(g?.5*e:0!==u?v/u:0),q=l-(o+((p-o)*(3*t/(t+u)+.5)/4||0))):(o=l-(l-k)*e*.5,p=l+(m-l)*e*.5,q=l-(o+p)/2),o+=q,p+=q,n.c=r=o,0!==j?n.b=y:n.b=y=n.a+.6*(n.c-n.a),n.da=l-k,n.ca=r-k,n.ba=y-k,f?(s=i(k,y,r,l),a.splice(x,1,s[0],s[1],s[2],s[3]),x+=4):x++,y=p;n=a[x],n.b=y,n.c=y+.4*(n.d-y),n.da=n.d-n.a,n.ca=n.c-n.a,n.ba=y-n.a,f&&(s=i(n.a,y,n.c,n.d),a.splice(x,1,s[0],s[1],s[2],s[3]))},k=function(a,d,e,f){var h,i,j,k,l,m,n=[];if(f)for(a=[f].concat(a),i=a.length;--i>-1;)"string"==typeof(m=a[i][d])&&"="===m.charAt(1)&&(a[i][d]=f[d]+Number(m.charAt(0)+m.substr(2)));if(h=a.length-2,0>h)return n[0]=new g(a[0][d],0,0,a[0][d]),n;for(i=0;h>i;i++)j=a[i][d],k=a[i+1][d],n[i]=new g(j,0,0,k),e&&(l=a[i+2][d],b[i]=(b[i]||0)+(k-j)*(k-j),c[i]=(c[i]||0)+(l-k)*(l-k));return n[i]=new g(a[i][d],0,0,a[i+1][d]),n},l=function(a,f,g,i,l,m){var n,o,p,q,r,s,t,u,v={},w=[],x=m||a[0];l="string"==typeof l?","+l+",":h,null==f&&(f=1);for(o in a[0])w.push(o);if(a.length>1){for(u=a[a.length-1],t=!0,n=w.length;--n>-1;)if(o=w[n],Math.abs(x[o]-u[o])>.05){t=!1;break}t&&(a=a.concat(),m&&a.unshift(m),a.push(a[1]),m=a[a.length-3])}for(b.length=c.length=d.length=0,n=w.length;--n>-1;)o=w[n],e[o]=-1!==l.indexOf(","+o+","),v[o]=k(a,o,e[o],m);for(n=b.length;--n>-1;)b[n]=Math.sqrt(b[n]),c[n]=Math.sqrt(c[n]);if(!i){for(n=w.length;--n>-1;)if(e[o])for(p=v[w[n]], + s=p.length-1,q=0;s>q;q++)r=p[q+1].da/c[q]+p[q].da/b[q]||0,d[q]=(d[q]||0)+r*r;for(n=d.length;--n>-1;)d[n]=Math.sqrt(d[n])}for(n=w.length,q=g?4:1;--n>-1;)o=w[n],p=v[o],j(p,f,g,i,e[o]),t&&(p.splice(0,q),p.splice(p.length-q,q));return v},m=function(a,b,c){b=b||"soft";var d,e,f,h,i,j,k,l,m,n,o,p={},q="cubic"===b?3:2,r="soft"===b,s=[];if(r&&c&&(a=[c].concat(a)),null==a||a.length-1;){for(m=s[j],p[m]=i=[],n=0,l=a.length,k=0;l>k;k++)d=null==c?a[k][m]:"string"==typeof(o=a[k][m])&&"="===o.charAt(1)?c[m]+Number(o.charAt(0)+o.substr(2)):Number(o),r&&k>1&&l-1>k&&(i[n++]=(d+i[n-2])/2),i[n++]=d;for(l=n-q+1,n=0,k=0;l>k;k+=q)d=i[k],e=i[k+1],f=i[k+2],h=2===q?0:i[k+3],i[n++]=o=3===q?new g(d,e,f,h):new g(d,(2*e+d)/3,(2*e+f)/3,f);i.length=n}return p},n=function(a,b,c){for(var d,e,f,g,h,i,j,k,l,m,n,o=1/c,p=a.length;--p>-1;)for(m=a[p],f=m.a,g=m.d-f,h=m.c-f,i=m.b-f,d=e=0,k=1;c>=k;k++)j=o*k,l=1-j,d=e-(e=(j*j*g+3*l*(j*h+l*i))*j),n=p*c+k-1,b[n]=(b[n]||0)+d*d},o=function(a,b){b=b>>0||6;var c,d,e,f,g=[],h=[],i=0,j=0,k=b-1,l=[],m=[];for(c in a)n(a[c],g,b);for(e=g.length,d=0;e>d;d++)i+=Math.sqrt(g[d]),f=d%b,m[f]=i,f===k&&(j+=i,f=d/b>>0,l[f]=m,h[f]=j,i=0,m=[]);return{length:j,lengths:h,segments:l}},p=_gsScope._gsDefine.plugin({propName:"bezier",priority:-1,version:"1.3.9",API:2,global:!0,init:function(a,b,c){this._target=a,b instanceof Array&&(b={values:b}),this._func={},this._mod={},this._props=[],this._timeRes=null==b.timeResolution?6:parseInt(b.timeResolution,10);var d,e,f,g,h,i=b.values||[],j={},k=i[0],n=b.autoRotate||c.vars.orientToBezier;this._autoRotate=n?n instanceof Array?n:[["x","y","rotation",n===!0?0:Number(n)||0]]:null;for(d in k)this._props.push(d);for(f=this._props.length;--f>-1;)d=this._props[f],this._overwriteProps.push(d),e=this._func[d]="function"==typeof a[d],j[d]=e?a[d.indexOf("set")||"function"!=typeof a["get"+d.substr(3)]?d:"get"+d.substr(3)]():parseFloat(a[d]),h||j[d]!==i[0][d]&&(h=j);if(this._beziers="cubic"!==b.type&&"quadratic"!==b.type&&"soft"!==b.type?l(i,isNaN(b.curviness)?1:b.curviness,!1,"thruBasic"===b.type,b.correlate,h):m(i,b.type,j),this._segCount=this._beziers[d].length,this._timeRes){var p=o(this._beziers,this._timeRes);this._length=p.length,this._lengths=p.lengths,this._segments=p.segments,this._l1=this._li=this._s1=this._si=0,this._l2=this._lengths[0],this._curSeg=this._segments[0],this._s2=this._curSeg[0],this._prec=1/this._curSeg.length}if(n=this._autoRotate)for(this._initialRotations=[],n[0]instanceof Array||(this._autoRotate=n=[n]),f=n.length;--f>-1;){for(g=0;3>g;g++)d=n[f][g],this._func[d]="function"==typeof a[d]?a[d.indexOf("set")||"function"!=typeof a["get"+d.substr(3)]?d:"get"+d.substr(3)]:!1;d=n[f][2],this._initialRotations[f]=(this._func[d]?this._func[d].call(this._target):this._target[d])||0,this._overwriteProps.push(d)}return this._startRatio=c.vars.runBackwards?1:0,!0},set:function(b){var c,d,e,f,g,h,i,j,k,l,m,n=this._segCount,o=this._func,p=this._target,q=b!==this._startRatio;if(this._timeRes){if(k=this._lengths,l=this._curSeg,m=b*this._length,e=this._li,m>this._l2&&n-1>e){for(j=n-1;j>e&&(this._l2=k[++e])<=m;);this._l1=k[e-1],this._li=e,this._curSeg=l=this._segments[e],this._s2=l[this._s1=this._si=0]}else if(m0){for(;e>0&&(this._l1=k[--e])>=m;);0===e&&mthis._s2&&ee&&(this._s2=l[++e])<=m;);this._s1=l[e-1],this._si=e}else if(m0){for(;e>0&&(this._s1=l[--e])>=m;);0===e&&mb?0:b>=1?n-1:n*b>>0,h=(b-c*(1/n))*n;for(d=1-h,e=this._props.length;--e>-1;)f=this._props[e],g=this._beziers[f][c],i=(h*h*g.da+3*d*(h*g.ca+d*g.ba))*h+g.a,this._mod[f]&&(i=this._mod[f](i,p)),o[f]?p[f](i):p[f]=i;if(this._autoRotate){var r,s,t,u,v,w,x,y=this._autoRotate;for(e=y.length;--e>-1;)f=y[e][2],w=y[e][3]||0,x=y[e][4]===!0?1:a,g=this._beziers[y[e][0]],r=this._beziers[y[e][1]],g&&r&&(g=g[c],r=r[c],s=g.a+(g.b-g.a)*h,u=g.b+(g.c-g.b)*h,s+=(u-s)*h,u+=(g.c+(g.d-g.c)*h-u)*h,t=r.a+(r.b-r.a)*h,v=r.b+(r.c-r.b)*h,t+=(v-t)*h,v+=(r.c+(r.d-r.c)*h-v)*h,i=q?Math.atan2(v-t,u-s)*x+w:this._initialRotations[e],this._mod[f]&&(i=this._mod[f](i,p)),o[f]?p[f](i):p[f]=i)}}}),q=p.prototype;p.bezierThrough=l,p.cubicToQuadratic=i,p._autoCSS=!0,p.quadraticToCubic=function(a,b,c){return new g(a,(2*b+a)/3,(2*b+c)/3,c)},p._cssRegister=function(){var a=f.CSSPlugin;if(a){var b=a._internals,c=b._parseToProxy,d=b._setPluginRatio,e=b.CSSPropTween;b._registerComplexSpecialProp("bezier",{parser:function(a,b,f,g,h,i){b instanceof Array&&(b={values:b}),i=new p;var j,k,l,m=b.values,n=m.length-1,o=[],q={};if(0>n)return h;for(j=0;n>=j;j++)l=c(a,m[j],g,h,i,n!==j),o[j]=l.end;for(k in b)q[k]=b[k];return q.values=o,h=new e(a,"bezier",0,0,l.pt,2),h.data=l,h.plugin=i,h.setRatio=d,0===q.autoRotate&&(q.autoRotate=!0),!q.autoRotate||q.autoRotate instanceof Array||(j=q.autoRotate===!0?0:Number(q.autoRotate),q.autoRotate=null!=l.end.left?[["left","top","rotation",j,!1]]:null!=l.end.x?[["x","y","rotation",j,!1]]:!1),q.autoRotate&&(g._transform||g._enableTransforms(!1),l.autoRotate=g._target._gsTransform,l.proxy.rotation=l.autoRotate.rotation||0,g._overwriteProps.push("rotation")),i._onInitTween(l.proxy,q,g._tween),h}})}},q._mod=function(a){for(var b,c=this._overwriteProps,d=c.length;--d>-1;)b=a[c[d]],b&&"function"==typeof b&&(this._mod[c[d]]=b)},q._kill=function(a){var b,c,d=this._props;for(b in this._beziers)if(b in a)for(delete this._beziers[b],delete this._func[b],c=d.length;--c>-1;)d[c]===b&&d.splice(c,1);if(d=this._autoRotate)for(c=d.length;--c>-1;)a[d[c][2]]&&d.splice(c,1);return this._super._kill.call(this,a)}}(),_gsScope._gsDefine("plugins.CSSPlugin",["plugins.TweenPlugin","TweenLite"],function(a,b){var c,d,e,f,g=function(){a.call(this,"css"),this._overwriteProps.length=0,this.setRatio=g.prototype.setRatio},h=_gsScope._gsDefine.globals,i={},j=g.prototype=new a("css");j.constructor=g,g.version="2.1.3",g.API=2,g.defaultTransformPerspective=0,g.defaultSkewType="compensated",g.defaultSmoothOrigin=!0,j="px",g.suffixMap={top:j,right:j,bottom:j,left:j,width:j,height:j,fontSize:j,padding:j,margin:j,perspective:j,lineHeight:""};var k,l,m,n,o,p,q,r,s=/(?:\-|\.|\b)(\d|\.|e\-)+/g,t=/(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g,u=/(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi,v=/(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b),?/gi,w=/(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g,x=/(?:\d|\-|\+|=|#|\.)*/g,y=/opacity *= *([^)]*)/i,z=/opacity:([^;]*)/i,A=/alpha\(opacity *=.+?\)/i,B=/^(rgb|hsl)/,C=/([A-Z])/g,D=/-([a-z])/gi,E=/(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi,F=function(a,b){return b.toUpperCase()},G=/(?:Left|Right|Width)/i,H=/(M11|M12|M21|M22)=[\d\-\.e]+/gi,I=/progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i,J=/,(?=[^\)]*(?:\(|$))/gi,K=/[\s,\(]/i,L=Math.PI/180,M=180/Math.PI,N={},O={style:{}},P=_gsScope.document||{createElement:function(){return O}},Q=function(a,b){var c=P.createElementNS?P.createElementNS(b||"http://www.w3.org/1999/xhtml",a):P.createElement(a);return c.style?c:P.createElement(a)},R=Q("div"),S=Q("img"),T=g._internals={_specialProps:i},U=(_gsScope.navigator||{}).userAgent||"",V=function(){var a=U.indexOf("Android"),b=Q("a");return m=-1!==U.indexOf("Safari")&&-1===U.indexOf("Chrome")&&(-1===a||parseFloat(U.substr(a+8,2))>3),o=m&&parseFloat(U.substr(U.indexOf("Version/")+8,2))<6,n=-1!==U.indexOf("Firefox"),(/MSIE ([0-9]{1,}[\.0-9]{0,})/.exec(U)||/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/.exec(U))&&(p=parseFloat(RegExp.$1)),b?(b.style.cssText="top:1px;opacity:.55;",/^0.55/.test(b.style.opacity)):!1}(),W=function(a){return y.test("string"==typeof a?a:(a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100:1},X=function(a){_gsScope.console&&console.log(a)},Y="",Z="",$=function(a,b){b=b||R;var c,d,e=b.style;if(void 0!==e[a])return a;for(a=a.charAt(0).toUpperCase()+a.substr(1),c=["O","Moz","ms","Ms","Webkit"],d=5;--d>-1&&void 0===e[c[d]+a];);return d>=0?(Z=3===d?"ms":c[d],Y="-"+Z.toLowerCase()+"-",Z+a):null},_="undefined"!=typeof window?window:P.defaultView||{getComputedStyle:function(){}},aa=function(a){return _.getComputedStyle(a)},ba=g.getStyle=function(a,b,c,d,e){var f;return V||"opacity"!==b?(!d&&a.style[b]?f=a.style[b]:(c=c||aa(a))?f=c[b]||c.getPropertyValue(b)||c.getPropertyValue(b.replace(C,"-$1").toLowerCase()):a.currentStyle&&(f=a.currentStyle[b]),null==e||f&&"none"!==f&&"auto"!==f&&"auto auto"!==f?f:e):W(a)},ca=T.convertToPixels=function(a,c,d,e,f){if("px"===e||!e&&"lineHeight"!==c)return d;if("auto"===e||!d)return 0;var h,i,j,k=G.test(c),l=a,m=R.style,n=0>d,o=1===d;if(n&&(d=-d),o&&(d*=100),"lineHeight"!==c||e)if("%"===e&&-1!==c.indexOf("border"))h=d/100*(k?a.clientWidth:a.clientHeight);else{if(m.cssText="border:0 solid red;position:"+ba(a,"position")+";line-height:0;","%"!==e&&l.appendChild&&"v"!==e.charAt(0)&&"rem"!==e)m[k?"borderLeftWidth":"borderTopWidth"]=d+e;else{if(l=a.parentNode||P.body,-1!==ba(l,"display").indexOf("flex")&&(m.position="absolute"),i=l._gsCache,j=b.ticker.frame,i&&k&&i.time===j)return i.width*d/100;m[k?"width":"height"]=d+e}l.appendChild(R),h=parseFloat(R[k?"offsetWidth":"offsetHeight"]),l.removeChild(R),k&&"%"===e&&g.cacheWidths!==!1&&(i=l._gsCache=l._gsCache||{},i.time=j,i.width=h/d*100),0!==h||f||(h=ca(a,c,d,e,!0))}else i=aa(a).lineHeight,a.style.lineHeight=d,h=parseFloat(aa(a).lineHeight),a.style.lineHeight=i;return o&&(h/=100),n?-h:h},da=T.calculateOffset=function(a,b,c){if("absolute"!==ba(a,"position",c))return 0;var d="left"===b?"Left":"Top",e=ba(a,"margin"+d,c);return a["offset"+d]-(ca(a,b,parseFloat(e),e.replace(x,""))||0)},ea=function(a,b){var c,d,e,f={};if(b=b||aa(a,null))if(c=b.length)for(;--c>-1;)e=b[c],(-1===e.indexOf("-transform")||Fa===e)&&(f[e.replace(D,F)]=b.getPropertyValue(e));else for(c in b)(-1===c.indexOf("Transform")||Ea===c)&&(f[c]=b[c]);else if(b=a.currentStyle||a.style)for(c in b)"string"==typeof c&&void 0===f[c]&&(f[c.replace(D,F)]=b[c]);return V||(f.opacity=W(a)),d=Ta(a,b,!1),f.rotation=d.rotation,f.skewX=d.skewX,f.scaleX=d.scaleX,f.scaleY=d.scaleY,f.x=d.x,f.y=d.y,Ha&&(f.z=d.z,f.rotationX=d.rotationX,f.rotationY=d.rotationY,f.scaleZ=d.scaleZ),f.filters&&delete f.filters,f},fa=function(a,b,c,d,e){var f,g,h,i={},j=a.style;for(g in c)"cssText"!==g&&"length"!==g&&isNaN(g)&&(b[g]!==(f=c[g])||e&&e[g])&&-1===g.indexOf("Origin")&&("number"==typeof f||"string"==typeof f)&&(i[g]="auto"!==f||"left"!==g&&"top"!==g?""!==f&&"auto"!==f&&"none"!==f||"string"!=typeof b[g]||""===b[g].replace(w,"")?f:0:da(a,g),void 0!==j[g]&&(h=new ua(j,g,j[g],h)));if(d)for(g in d)"className"!==g&&(i[g]=d[g]);return{difs:i,firstMPT:h}},ga={width:["Left","Right"],height:["Top","Bottom"]},ha=["marginLeft","marginRight","marginTop","marginBottom"],ia=function(a,b,c){if("svg"===(a.nodeName+"").toLowerCase())return(c||aa(a))[b]||0;if(a.getCTM&&Qa(a))return a.getBBox()[b]||0;var d=parseFloat("width"===b?a.offsetWidth:a.offsetHeight),e=ga[b],f=e.length;for(c=c||aa(a,null);--f>-1;)d-=parseFloat(ba(a,"padding"+e[f],c,!0))||0,d-=parseFloat(ba(a,"border"+e[f]+"Width",c,!0))||0;return d},ja=function(a,b){if("contain"===a||"auto"===a||"auto auto"===a)return a+" ";(null==a||""===a)&&(a="0 0");var c,d=a.split(" "),e=-1!==a.indexOf("left")?"0%":-1!==a.indexOf("right")?"100%":d[0],f=-1!==a.indexOf("top")?"0%":-1!==a.indexOf("bottom")?"100%":d[1];if(d.length>3&&!b){for(d=a.split(", ").join(",").split(","),a=[],c=0;c2?" "+d[2]:""),b&&(b.oxp=-1!==e.indexOf("%"),b.oyp=-1!==f.indexOf("%"),b.oxr="="===e.charAt(1),b.oyr="="===f.charAt(1),b.ox=parseFloat(e.replace(w,"")),b.oy=parseFloat(f.replace(w,"")),b.v=a),b||a},ka=function(a,b){return"function"==typeof a&&(a=a(r,q)),"string"==typeof a&&"="===a.charAt(1)?parseInt(a.charAt(0)+"1",10)*parseFloat(a.substr(2)):parseFloat(a)-parseFloat(b)||0},la=function(a,b){"function"==typeof a&&(a=a(r,q));var c="string"==typeof a&&"="===a.charAt(1);return"string"==typeof a&&"v"===a.charAt(a.length-2)&&(a=(c?a.substr(0,2):0)+window["inner"+("vh"===a.substr(-2)?"Height":"Width")]*(parseFloat(c?a.substr(2):a)/100)),null==a?b:c?parseInt(a.charAt(0)+"1",10)*parseFloat(a.substr(2))+b:parseFloat(a)||0},ma=function(a,b,c,d){var e,f,g,h,i,j=1e-6;return"function"==typeof a&&(a=a(r,q)),null==a?h=b:"number"==typeof a?h=a:(e=360,f=a.split("_"),i="="===a.charAt(1),g=(i?parseInt(a.charAt(0)+"1",10)*parseFloat(f[0].substr(2)):parseFloat(f[0]))*(-1===a.indexOf("rad")?1:M)-(i?0:b),f.length&&(d&&(d[c]=b+g),-1!==a.indexOf("short")&&(g%=e,g!==g%(e/2)&&(g=0>g?g+e:g-e)),-1!==a.indexOf("_cw")&&0>g?g=(g+9999999999*e)%e-(g/e|0)*e:-1!==a.indexOf("ccw")&&g>0&&(g=(g-9999999999*e)%e-(g/e|0)*e)),h=b+g),j>h&&h>-j&&(h=0),h},na={aqua:[0,255,255],lime:[0,255,0],silver:[192,192,192],black:[0,0,0],maroon:[128,0,0],teal:[0,128,128],blue:[0,0,255],navy:[0,0,128],white:[255,255,255],fuchsia:[255,0,255],olive:[128,128,0],yellow:[255,255,0],orange:[255,165,0],gray:[128,128,128],purple:[128,0,128],green:[0,128,0],red:[255,0,0],pink:[255,192,203],cyan:[0,255,255],transparent:[255,255,255,0]},oa=function(a,b,c){return a=0>a?a+1:a>1?a-1:a,255*(1>6*a?b+(c-b)*a*6:.5>a?c:2>3*a?b+(c-b)*(2/3-a)*6:b)+.5|0},pa=g.parseColor=function(a,b){var c,d,e,f,g,h,i,j,k,l,m;if(a)if("number"==typeof a)c=[a>>16,a>>8&255,255&a];else{if(","===a.charAt(a.length-1)&&(a=a.substr(0,a.length-1)),na[a])c=na[a];else if("#"===a.charAt(0))4===a.length&&(d=a.charAt(1),e=a.charAt(2),f=a.charAt(3),a="#"+d+d+e+e+f+f),a=parseInt(a.substr(1),16),c=[a>>16,a>>8&255,255&a];else if("hsl"===a.substr(0,3))if(c=m=a.match(s),b){if(-1!==a.indexOf("="))return a.match(t)}else g=Number(c[0])%360/360,h=Number(c[1])/100,i=Number(c[2])/100,e=.5>=i?i*(h+1):i+h-i*h,d=2*i-e,c.length>3&&(c[3]=Number(c[3])),c[0]=oa(g+1/3,d,e),c[1]=oa(g,d,e),c[2]=oa(g-1/3,d,e);else c=a.match(s)||na.transparent;c[0]=Number(c[0]),c[1]=Number(c[1]),c[2]=Number(c[2]),c.length>3&&(c[3]=Number(c[3]))}else c=na.black;return b&&!m&&(d=c[0]/255,e=c[1]/255,f=c[2]/255,j=Math.max(d,e,f),k=Math.min(d,e,f),i=(j+k)/2,j===k?g=h=0:(l=j-k,h=i>.5?l/(2-j-k):l/(j+k),g=j===d?(e-f)/l+(f>e?6:0):j===e?(f-d)/l+2:(d-e)/l+4,g*=60),c[0]=g+.5|0,c[1]=100*h+.5|0,c[2]=100*i+.5|0),c},qa=function(a,b){var c,d,e,f=a.match(ra)||[],g=0,h="";if(!f.length)return a;for(c=0;c0?g[0].replace(s,""):"";return k?e=b?function(a){var b,m,n,o;if("number"==typeof a)a+=l;else if(d&&J.test(a)){for(o=a.replace(J,"|").split("|"),n=0;nn--)for(;++nm--)for(;++mi;i++)h[a[i]]=j[i]=j[i]||j[(i-1)/2>>0];return e.parse(b,h,f,g)}},ua=(T._setPluginRatio=function(a){this.plugin.setRatio(a);for(var b,c,d,e,f,g=this.data,h=g.proxy,i=g.firstMPT,j=1e-6;i;)b=h[i.v],i.r?b=i.r(b):j>b&&b>-j&&(b=0),i.t[i.p]=b,i=i._next;if(g.autoRotate&&(g.autoRotate.rotation=g.mod?g.mod.call(this._tween,h.rotation,this.t,this._tween):h.rotation),1===a||0===a)for(i=g.firstMPT,f=1===a?"e":"b";i;){if(c=i.t,c.type){if(1===c.type){for(e=c.xs0+c.s+c.xs1,d=1;d0;)i="xn"+g,h=d.p+"_"+i,n[h]=d.data[i],m[h]=d[i],f||(j=new ua(d,i,h,j,d.rxp[i]));d=d._next}return{proxy:m,end:n,firstMPT:j,pt:k}},T.CSSPropTween=function(a,b,d,e,g,h,i,j,k,l,m){this.t=a,this.p=b,this.s=d,this.c=e,this.n=i||b,a instanceof va||f.push(this.n),this.r=j?"function"==typeof j?j:Math.round:j,this.type=h||0,k&&(this.pr=k,c=!0),this.b=void 0===l?d:l,this.e=void 0===m?d+e:m,g&&(this._next=g,g._prev=this)}),wa=function(a,b,c,d,e,f){var g=new va(a,b,c,d-c,e,-1,f);return g.b=c,g.e=g.xs0=d,g},xa=g.parseComplex=function(a,b,c,d,e,f,h,i,j,l){c=c||f||"","function"==typeof d&&(d=d(r,q)),h=new va(a,b,0,0,h,l?2:1,null,!1,i,c,d),d+="",e&&ra.test(d+c)&&(d=[c,d],g.colorStringFilter(d),c=d[0],d=d[1]);var m,n,o,p,u,v,w,x,y,z,A,B,C,D=c.split(", ").join(",").split(" "),E=d.split(", ").join(",").split(" "),F=D.length,G=k!==!1;for((-1!==d.indexOf(",")||-1!==c.indexOf(","))&&(-1!==(d+c).indexOf("rgb")||-1!==(d+c).indexOf("hsl")?(D=D.join(" ").replace(J,", ").split(" "),E=E.join(" ").replace(J,", ").split(" ")):(D=D.join(" ").split(",").join(", ").split(" "),E=E.join(" ").split(",").join(", ").split(" ")),F=D.length),F!==E.length&&(D=(f||"").split(" "),F=D.length),h.plugin=j,h.setRatio=l,ra.lastIndex=0,m=0;F>m;m++)if(p=D[m],u=E[m]+"",x=parseFloat(p),x||0===x)h.appendXtra("",x,ka(u,x),u.replace(t,""),G&&-1!==u.indexOf("px")?Math.round:!1,!0);else if(e&&ra.test(p))B=u.indexOf(")")+1,B=")"+(B?u.substr(B):""),C=-1!==u.indexOf("hsl")&&V,z=u,p=pa(p,C),u=pa(u,C),y=p.length+u.length>6,y&&!V&&0===u[3]?(h["xs"+h.l]+=h.l?" transparent":"transparent",h.e=h.e.split(E[m]).join("transparent")):(V||(y=!1),C?h.appendXtra(z.substr(0,z.indexOf("hsl"))+(y?"hsla(":"hsl("),p[0],ka(u[0],p[0]),",",!1,!0).appendXtra("",p[1],ka(u[1],p[1]),"%,",!1).appendXtra("",p[2],ka(u[2],p[2]),y?"%,":"%"+B,!1):h.appendXtra(z.substr(0,z.indexOf("rgb"))+(y?"rgba(":"rgb("),p[0],u[0]-p[0],",",Math.round,!0).appendXtra("",p[1],u[1]-p[1],",",Math.round).appendXtra("",p[2],u[2]-p[2],y?",":B,Math.round),y&&(p=p.length<4?1:p[3],h.appendXtra("",p,(u.length<4?1:u[3])-p,B,!1))),ra.lastIndex=0;else if(v=p.match(s)){if(w=u.match(t),!w||w.length!==v.length)return h;for(o=0,n=0;n0;)j["xn"+ya]=0,j["xs"+ya]="";j.xs0="",j._next=j._prev=j.xfirst=j.data=j.plugin=j.setRatio=j.rxp=null,j.appendXtra=function(a,b,c,d,e,f){var g=this,h=g.l;return g["xs"+h]+=f&&(h||g["xs"+h])?" "+a:a||"",c||0===h||g.plugin?(g.l++,g.type=g.setRatio?2:1,g["xs"+g.l]=d||"",h>0?(g.data["xn"+h]=b+c,g.rxp["xn"+h]=e,g["xn"+h]=b,g.plugin||(g.xfirst=new va(g,"xn"+h,b,c,g.xfirst||g,0,g.n,e,g.pr),g.xfirst.xs0=0),g):(g.data={s:b+c},g.rxp={},g.s=b,g.c=c,g.r=e,g)):(g["xs"+h]+=b+(d||""),g)};var za=function(a,b){b=b||{},this.p=b.prefix?$(a)||a:a,i[a]=i[this.p]=this,this.format=b.formatter||sa(b.defaultValue,b.color,b.collapsible,b.multi),b.parser&&(this.parse=b.parser),this.clrs=b.color,this.multi=b.multi,this.keyword=b.keyword,this.dflt=b.defaultValue,this.allowFunc=b.allowFunc,this.pr=b.priority||0},Aa=T._registerComplexSpecialProp=function(a,b,c){"object"!=typeof b&&(b={parser:c});var d,e,f=a.split(","),g=b.defaultValue;for(c=c||[g],d=0;dh.length?i.length:h.length,g=0;j>g;g++)b=h[g]=h[g]||this.dflt,c=i[g]=i[g]||this.dflt,m&&(k=b.indexOf(m),l=c.indexOf(m),k!==l&&(-1===l?h[g]=h[g].split(m).join(""):-1===k&&(h[g]+=" "+m)));b=h.join(", "),c=i.join(", ")}return xa(a,this.p,b,c,this.clrs,this.dflt,d,this.pr,e,f)},j.parse=function(a,b,c,d,f,g,h){return this.parseComplex(a.style,this.format(ba(a,this.p,e,!1,this.dflt)),this.format(b),f,g)},g.registerSpecialProp=function(a,b,c){Aa(a,{parser:function(a,d,e,f,g,h,i){var j=new va(a,e,0,0,g,2,e,!1,c);return j.plugin=h,j.setRatio=b(a,d,f._tween,e),j},priority:c})},g.useSVGTransformAttr=!0;var Ca,Da="scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent".split(","),Ea=$("transform"),Fa=Y+"transform",Ga=$("transformOrigin"),Ha=null!==$("perspective"),Ia=T.Transform=function(){this.perspective=parseFloat(g.defaultTransformPerspective)||0,this.force3D=g.defaultForce3D!==!1&&Ha?g.defaultForce3D||"auto":!1},Ja=_gsScope.SVGElement,Ka=function(a,b,c){var d,e=P.createElementNS("http://www.w3.org/2000/svg",a),f=/([a-z])([A-Z])/g;for(d in c)e.setAttributeNS(null,d.replace(f,"$1-$2").toLowerCase(),c[d]);return b.appendChild(e),e},La=P.documentElement||{},Ma=function(){var a,b,c,d=p||/Android/i.test(U)&&!_gsScope.chrome;return P.createElementNS&&La.appendChild&&!d&&(a=Ka("svg",La),b=Ka("rect",a,{width:100,height:50,x:100}),c=b.getBoundingClientRect().width,b.style[Ga]="50% 50%",b.style[Ea]="scaleX(0.5)",d=c===b.getBoundingClientRect().width&&!(n&&Ha),La.removeChild(a)),d}(),Na=function(a,b,c,d,e,f){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v=a._gsTransform,w=Sa(a,!0);v&&(t=v.xOrigin,u=v.yOrigin),(!d||(h=d.split(" ")).length<2)&&(n=a.getBBox(),0===n.x&&0===n.y&&n.width+n.height===0&&(n={x:parseFloat(a.hasAttribute("x")?a.getAttribute("x"):a.hasAttribute("cx")?a.getAttribute("cx"):0)||0,y:parseFloat(a.hasAttribute("y")?a.getAttribute("y"):a.hasAttribute("cy")?a.getAttribute("cy"):0)||0,width:0,height:0}),b=ja(b).split(" "),h=[(-1!==b[0].indexOf("%")?parseFloat(b[0])/100*n.width:parseFloat(b[0]))+n.x,(-1!==b[1].indexOf("%")?parseFloat(b[1])/100*n.height:parseFloat(b[1]))+n.y]),c.xOrigin=k=parseFloat(h[0]),c.yOrigin=l=parseFloat(h[1]),d&&w!==Ra&&(m=w[0],n=w[1],o=w[2],p=w[3],q=w[4],r=w[5],s=m*p-n*o,s&&(i=k*(p/s)+l*(-o/s)+(o*r-p*q)/s,j=k*(-n/s)+l*(m/s)-(m*r-n*q)/s,k=c.xOrigin=h[0]=i,l=c.yOrigin=h[1]=j)),v&&(f&&(c.xOffset=v.xOffset,c.yOffset=v.yOffset,v=c),e||e!==!1&&g.defaultSmoothOrigin!==!1?(i=k-t,j=l-u,v.xOffset+=i*w[0]+j*w[2]-i,v.yOffset+=i*w[1]+j*w[3]-j):v.xOffset=v.yOffset=0),f||a.setAttribute("data-svg-origin",h.join(" "))},Oa=function(a){var b,c=Q("svg",this.ownerSVGElement&&this.ownerSVGElement.getAttribute("xmlns")||"http://www.w3.org/2000/svg"),d=this.parentNode,e=this.nextSibling,f=this.style.cssText;if(La.appendChild(c),c.appendChild(this),this.style.display="block",a)try{b=this.getBBox(),this._originalGetBBox=this.getBBox,this.getBBox=Oa}catch(g){}else this._originalGetBBox&&(b=this._originalGetBBox());return e?d.insertBefore(this,e):d.appendChild(this),La.removeChild(c),this.style.cssText=f,b},Pa=function(a){try{return a.getBBox()}catch(b){return Oa.call(a,!0)}},Qa=function(a){return!(!Ja||!a.getCTM||a.parentNode&&!a.ownerSVGElement||!Pa(a))},Ra=[1,0,0,1,0,0],Sa=function(a,b){var c,d,e,f,g,h,i,j=a._gsTransform||new Ia,k=1e5,l=a.style;if(Ea?d=ba(a,Fa,null,!0):a.currentStyle&&(d=a.currentStyle.filter.match(H),d=d&&4===d.length?[d[0].substr(4),Number(d[2].substr(4)),Number(d[1].substr(4)),d[3].substr(4),j.x||0,j.y||0].join(","):""),c=!d||"none"===d||"matrix(1, 0, 0, 1, 0, 0)"===d,Ea&&c&&!a.offsetParent&&a!==La&&(f=l.display,l.display="block",i=a.parentNode,i&&a.offsetParent||(g=1,h=a.nextSibling,La.appendChild(a)),d=ba(a,Fa,null,!0),c=!d||"none"===d||"matrix(1, 0, 0, 1, 0, 0)"===d,f?l.display=f:Xa(l,"display"),g&&(h?i.insertBefore(a,h):i?i.appendChild(a):La.removeChild(a))),(j.svg||a.getCTM&&Qa(a))&&(c&&-1!==(l[Ea]+"").indexOf("matrix")&&(d=l[Ea],c=0),e=a.getAttribute("transform"),c&&e&&(e=a.transform.baseVal.consolidate().matrix,d="matrix("+e.a+","+e.b+","+e.c+","+e.d+","+e.e+","+e.f+")",c=0)),c)return Ra;for(e=(d||"").match(s)||[],ya=e.length;--ya>-1;)f=Number(e[ya]),e[ya]=(g=f-(f|=0))?(g*k+(0>g?-.5:.5)|0)/k+f:f;return b&&e.length>6?[e[0],e[1],e[4],e[5],e[12],e[13]]:e},Ta=T.getTransform=function(a,c,d,e){if(a._gsTransform&&d&&!e)return a._gsTransform;var f,h,i,j,k,l,m=d?a._gsTransform||new Ia:new Ia,n=m.scaleX<0,o=2e-5,p=1e5,q=Ha?parseFloat(ba(a,Ga,c,!1,"0 0 0").split(" ")[2])||m.zOrigin||0:0,r=parseFloat(g.defaultTransformPerspective)||0;if(m.svg=!(!a.getCTM||!Qa(a)),m.svg&&(Na(a,ba(a,Ga,c,!1,"50% 50%")+"",m,a.getAttribute("data-svg-origin")),Ca=g.useSVGTransformAttr||Ma),f=Sa(a),f!==Ra){if(16===f.length){var s,t,u,v,w,x=f[0],y=f[1],z=f[2],A=f[3],B=f[4],C=f[5],D=f[6],E=f[7],F=f[8],G=f[9],H=f[10],I=f[12],J=f[13],K=f[14],L=f[11],N=Math.atan2(D,H);m.zOrigin&&(K=-m.zOrigin,I=F*K-f[12],J=G*K-f[13],K=H*K+m.zOrigin-f[14]),m.rotationX=N*M,N&&(v=Math.cos(-N),w=Math.sin(-N),s=B*v+F*w,t=C*v+G*w,u=D*v+H*w,F=B*-w+F*v,G=C*-w+G*v,H=D*-w+H*v,L=E*-w+L*v,B=s,C=t,D=u),N=Math.atan2(-z,H),m.rotationY=N*M,N&&(v=Math.cos(-N),w=Math.sin(-N),s=x*v-F*w,t=y*v-G*w,u=z*v-H*w,G=y*w+G*v,H=z*w+H*v,L=A*w+L*v,x=s,y=t,z=u),N=Math.atan2(y,x),m.rotation=N*M,N&&(v=Math.cos(N),w=Math.sin(N),s=x*v+y*w,t=B*v+C*w,u=F*v+G*w,y=y*v-x*w,C=C*v-B*w,G=G*v-F*w,x=s,B=t,F=u),m.rotationX&&Math.abs(m.rotationX)+Math.abs(m.rotation)>359.9&&(m.rotationX=m.rotation=0,m.rotationY=180-m.rotationY),N=Math.atan2(B,C),m.scaleX=(Math.sqrt(x*x+y*y+z*z)*p+.5|0)/p,m.scaleY=(Math.sqrt(C*C+D*D)*p+.5|0)/p,m.scaleZ=(Math.sqrt(F*F+G*G+H*H)*p+.5|0)/p,x/=m.scaleX,B/=m.scaleY,y/=m.scaleX,C/=m.scaleY,Math.abs(N)>o?(m.skewX=N*M,B=0,"simple"!==m.skewType&&(m.scaleY*=1/Math.cos(N))):m.skewX=0,m.perspective=L?1/(0>L?-L:L):0,m.x=I,m.y=J,m.z=K,m.svg&&(m.x-=m.xOrigin-(m.xOrigin*x-m.yOrigin*B),m.y-=m.yOrigin-(m.yOrigin*y-m.xOrigin*C))}else if(!Ha||e||!f.length||m.x!==f[4]||m.y!==f[5]||!m.rotationX&&!m.rotationY){var O=f.length>=6,P=O?f[0]:1,Q=f[1]||0,R=f[2]||0,S=O?f[3]:1;m.x=f[4]||0,m.y=f[5]||0,i=Math.sqrt(P*P+Q*Q),j=Math.sqrt(S*S+R*R),k=P||Q?Math.atan2(Q,P)*M:m.rotation||0,l=R||S?Math.atan2(R,S)*M+k:m.skewX||0,m.scaleX=i,m.scaleY=j,m.rotation=k,m.skewX=l,Ha&&(m.rotationX=m.rotationY=m.z=0,m.perspective=r,m.scaleZ=1),m.svg&&(m.x-=m.xOrigin-(m.xOrigin*P+m.yOrigin*R),m.y-=m.yOrigin-(m.xOrigin*Q+m.yOrigin*S))}Math.abs(m.skewX)>90&&Math.abs(m.skewX)<270&&(n?(m.scaleX*=-1,m.skewX+=m.rotation<=0?180:-180,m.rotation+=m.rotation<=0?180:-180):(m.scaleY*=-1,m.skewX+=m.skewX<=0?180:-180)),m.zOrigin=q;for(h in m)m[h]-o&&(m[h]=0)}return d&&(a._gsTransform=m,m.svg&&(Ca&&a.style[Ea]?b.delayedCall(.001,function(){Xa(a.style,Ea)}):!Ca&&a.getAttribute("transform")&&b.delayedCall(.001,function(){a.removeAttribute("transform")}))),m},Ua=function(a){var b,c,d=this.data,e=-d.rotation*L,f=e+d.skewX*L,g=1e5,h=(Math.cos(e)*d.scaleX*g|0)/g,i=(Math.sin(e)*d.scaleX*g|0)/g,j=(Math.sin(f)*-d.scaleY*g|0)/g,k=(Math.cos(f)*d.scaleY*g|0)/g,l=this.t.style,m=this.t.currentStyle;if(m){c=i,i=-j,j=-c,b=m.filter,l.filter="";var n,o,q=this.t.offsetWidth,r=this.t.offsetHeight,s="absolute"!==m.position,t="progid:DXImageTransform.Microsoft.Matrix(M11="+h+", M12="+i+", M21="+j+", M22="+k,u=d.x+q*d.xPercent/100,v=d.y+r*d.yPercent/100;if(null!=d.ox&&(n=(d.oxp?q*d.ox*.01:d.ox)-q/2,o=(d.oyp?r*d.oy*.01:d.oy)-r/2,u+=n-(n*h+o*i),v+=o-(n*j+o*k)),s?(n=q/2,o=r/2,t+=", Dx="+(n-(n*h+o*i)+u)+", Dy="+(o-(n*j+o*k)+v)+")"):t+=", sizingMethod='auto expand')",-1!==b.indexOf("DXImageTransform.Microsoft.Matrix(")?l.filter=b.replace(I,t):l.filter=t+" "+b,(0===a||1===a)&&1===h&&0===i&&0===j&&1===k&&(s&&-1===t.indexOf("Dx=0, Dy=0")||y.test(b)&&100!==parseFloat(RegExp.$1)||-1===b.indexOf(b.indexOf("Alpha"))&&l.removeAttribute("filter")),!s){var w,z,A,B=8>p?1:-1;for(n=d.ieOffsetX||0,o=d.ieOffsetY||0,d.ieOffsetX=Math.round((q-((0>h?-h:h)*q+(0>i?-i:i)*r))/2+u),d.ieOffsetY=Math.round((r-((0>k?-k:k)*r+(0>j?-j:j)*q))/2+v),ya=0;4>ya;ya++)z=ha[ya],w=m[z],c=-1!==w.indexOf("px")?parseFloat(w):ca(this.t,z,parseFloat(w),w.replace(x,""))||0,A=c!==d[z]?2>ya?-d.ieOffsetX:-d.ieOffsetY:2>ya?n-d.ieOffsetX:o-d.ieOffsetY,l[z]=(d[z]=Math.round(c-A*(0===ya||2===ya?1:B)))+"px"}}},Va=T.set3DTransformRatio=T.setTransformRatio=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,o,p,q,r,s,t,u,v,w,x,y,z=this.data,A=this.t.style,B=z.rotation,C=z.rotationX,D=z.rotationY,E=z.scaleX,F=z.scaleY,G=z.scaleZ,H=z.x,I=z.y,J=z.z,K=z.svg,M=z.perspective,N=z.force3D,O=z.skewY,P=z.skewX;if(O&&(P+=O,B+=O),((1===a||0===a)&&"auto"===N&&(this.tween._totalTime===this.tween._totalDuration||!this.tween._totalTime)||!N)&&!J&&!M&&!D&&!C&&1===G||Ca&&K||!Ha)return void(B||P||K?(B*=L,x=P*L,y=1e5,c=Math.cos(B)*E,f=Math.sin(B)*E,d=Math.sin(B-x)*-F,g=Math.cos(B-x)*F,x&&"simple"===z.skewType&&(b=Math.tan(x-O*L),b=Math.sqrt(1+b*b),d*=b,g*=b,O&&(b=Math.tan(O*L),b=Math.sqrt(1+b*b),c*=b,f*=b)),K&&(H+=z.xOrigin-(z.xOrigin*c+z.yOrigin*d)+z.xOffset,I+=z.yOrigin-(z.xOrigin*f+z.yOrigin*g)+z.yOffset,Ca&&(z.xPercent||z.yPercent)&&(q=this.t.getBBox(),H+=.01*z.xPercent*q.width,I+=.01*z.yPercent*q.height),q=1e-6,q>H&&H>-q&&(H=0),q>I&&I>-q&&(I=0)),u=(c*y|0)/y+","+(f*y|0)/y+","+(d*y|0)/y+","+(g*y|0)/y+","+H+","+I+")",K&&Ca?this.t.setAttribute("transform","matrix("+u):A[Ea]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix(":"matrix(")+u):A[Ea]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix(":"matrix(")+E+",0,0,"+F+","+H+","+I+")");if(n&&(q=1e-4,q>E&&E>-q&&(E=G=2e-5),q>F&&F>-q&&(F=G=2e-5),!M||z.z||z.rotationX||z.rotationY||(M=0)),B||P)B*=L,r=c=Math.cos(B),s=f=Math.sin(B),P&&(B-=P*L,r=Math.cos(B),s=Math.sin(B),"simple"===z.skewType&&(b=Math.tan((P-O)*L),b=Math.sqrt(1+b*b),r*=b,s*=b,z.skewY&&(b=Math.tan(O*L),b=Math.sqrt(1+b*b),c*=b,f*=b))),d=-s,g=r;else{if(!(D||C||1!==G||M||K))return void(A[Ea]=(z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) translate3d(":"translate3d(")+H+"px,"+I+"px,"+J+"px)"+(1!==E||1!==F?" scale("+E+","+F+")":""));c=g=1,d=f=0}k=1,e=h=i=j=l=m=0,o=M?-1/M:0,p=z.zOrigin,q=1e-6,v=",",w="0",B=D*L,B&&(r=Math.cos(B),s=Math.sin(B),i=-s,l=o*-s,e=c*s,h=f*s,k=r,o*=r,c*=r,f*=r),B=C*L,B&&(r=Math.cos(B),s=Math.sin(B),b=d*r+e*s,t=g*r+h*s,j=k*s,m=o*s,e=d*-s+e*r,h=g*-s+h*r,k*=r,o*=r,d=b,g=t),1!==G&&(e*=G,h*=G,k*=G,o*=G),1!==F&&(d*=F,g*=F,j*=F,m*=F),1!==E&&(c*=E,f*=E,i*=E,l*=E),(p||K)&&(p&&(H+=e*-p,I+=h*-p,J+=k*-p+p),K&&(H+=z.xOrigin-(z.xOrigin*c+z.yOrigin*d)+z.xOffset,I+=z.yOrigin-(z.xOrigin*f+z.yOrigin*g)+z.yOffset),q>H&&H>-q&&(H=w),q>I&&I>-q&&(I=w),q>J&&J>-q&&(J=0)),u=z.xPercent||z.yPercent?"translate("+z.xPercent+"%,"+z.yPercent+"%) matrix3d(":"matrix3d(",u+=(q>c&&c>-q?w:c)+v+(q>f&&f>-q?w:f)+v+(q>i&&i>-q?w:i),u+=v+(q>l&&l>-q?w:l)+v+(q>d&&d>-q?w:d)+v+(q>g&&g>-q?w:g), + C||D||1!==G?(u+=v+(q>j&&j>-q?w:j)+v+(q>m&&m>-q?w:m)+v+(q>e&&e>-q?w:e),u+=v+(q>h&&h>-q?w:h)+v+(q>k&&k>-q?w:k)+v+(q>o&&o>-q?w:o)+v):u+=",0,0,0,0,1,0,",u+=H+v+I+v+J+v+(M?1+-J/M:1)+")",A[Ea]=u};j=Ia.prototype,j.x=j.y=j.z=j.skewX=j.skewY=j.rotation=j.rotationX=j.rotationY=j.zOrigin=j.xPercent=j.yPercent=j.xOffset=j.yOffset=0,j.scaleX=j.scaleY=j.scaleZ=1,Aa("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent,smoothOrigin",{parser:function(a,b,c,d,f,h,i){if(d._lastParsedTransform===i)return f;d._lastParsedTransform=i;var j=i.scale&&"function"==typeof i.scale?i.scale:0;j&&(i.scale=j(r,a));var k,l,m,n,o,p,s,t,u,v=a._gsTransform,w=a.style,x=1e-6,y=Da.length,z=i,A={},B="transformOrigin",C=Ta(a,e,!0,z.parseTransform),D=z.transform&&("function"==typeof z.transform?z.transform(r,q):z.transform);if(C.skewType=z.skewType||C.skewType||g.defaultSkewType,d._transform=C,"rotationZ"in z&&(z.rotation=z.rotationZ),D&&"string"==typeof D&&Ea)l=R.style,l[Ea]=D,l.display="block",l.position="absolute",-1!==D.indexOf("%")&&(l.width=ba(a,"width"),l.height=ba(a,"height")),P.body.appendChild(R),k=Ta(R,null,!1),"simple"===C.skewType&&(k.scaleY*=Math.cos(k.skewX*L)),C.svg&&(p=C.xOrigin,s=C.yOrigin,k.x-=C.xOffset,k.y-=C.yOffset,(z.transformOrigin||z.svgOrigin)&&(D={},Na(a,ja(z.transformOrigin),D,z.svgOrigin,z.smoothOrigin,!0),p=D.xOrigin,s=D.yOrigin,k.x-=D.xOffset-C.xOffset,k.y-=D.yOffset-C.yOffset),(p||s)&&(t=Sa(R,!0),k.x-=p-(p*t[0]+s*t[2]),k.y-=s-(p*t[1]+s*t[3]))),P.body.removeChild(R),k.perspective||(k.perspective=C.perspective),null!=z.xPercent&&(k.xPercent=la(z.xPercent,C.xPercent)),null!=z.yPercent&&(k.yPercent=la(z.yPercent,C.yPercent));else if("object"==typeof z){if(k={scaleX:la(null!=z.scaleX?z.scaleX:z.scale,C.scaleX),scaleY:la(null!=z.scaleY?z.scaleY:z.scale,C.scaleY),scaleZ:la(z.scaleZ,C.scaleZ),x:la(z.x,C.x),y:la(z.y,C.y),z:la(z.z,C.z),xPercent:la(z.xPercent,C.xPercent),yPercent:la(z.yPercent,C.yPercent),perspective:la(z.transformPerspective,C.perspective)},o=z.directionalRotation,null!=o)if("object"==typeof o)for(l in o)z[l]=o[l];else z.rotation=o;"string"==typeof z.x&&-1!==z.x.indexOf("%")&&(k.x=0,k.xPercent=la(z.x,C.xPercent)),"string"==typeof z.y&&-1!==z.y.indexOf("%")&&(k.y=0,k.yPercent=la(z.y,C.yPercent)),k.rotation=ma("rotation"in z?z.rotation:"shortRotation"in z?z.shortRotation+"_short":C.rotation,C.rotation,"rotation",A),Ha&&(k.rotationX=ma("rotationX"in z?z.rotationX:"shortRotationX"in z?z.shortRotationX+"_short":C.rotationX||0,C.rotationX,"rotationX",A),k.rotationY=ma("rotationY"in z?z.rotationY:"shortRotationY"in z?z.shortRotationY+"_short":C.rotationY||0,C.rotationY,"rotationY",A)),k.skewX=ma(z.skewX,C.skewX),k.skewY=ma(z.skewY,C.skewY)}for(Ha&&null!=z.force3D&&(C.force3D=z.force3D,n=!0),m=C.force3D||C.z||C.rotationX||C.rotationY||k.z||k.rotationX||k.rotationY||k.perspective,m||null==z.scale||(k.scaleZ=1);--y>-1;)u=Da[y],D=k[u]-C[u],(D>x||-x>D||null!=z[u]||null!=N[u])&&(n=!0,f=new va(C,u,C[u],D,f),u in A&&(f.e=A[u]),f.xs0=0,f.plugin=h,d._overwriteProps.push(f.n));return D="function"==typeof z.transformOrigin?z.transformOrigin(r,q):z.transformOrigin,C.svg&&(D||z.svgOrigin)&&(p=C.xOffset,s=C.yOffset,Na(a,ja(D),k,z.svgOrigin,z.smoothOrigin),f=wa(C,"xOrigin",(v?C:k).xOrigin,k.xOrigin,f,B),f=wa(C,"yOrigin",(v?C:k).yOrigin,k.yOrigin,f,B),(p!==C.xOffset||s!==C.yOffset)&&(f=wa(C,"xOffset",v?p:C.xOffset,C.xOffset,f,B),f=wa(C,"yOffset",v?s:C.yOffset,C.yOffset,f,B)),D="0px 0px"),(D||Ha&&m&&C.zOrigin)&&(Ea?(n=!0,u=Ga,D||(D=(ba(a,u,e,!1,"50% 50%")+"").split(" "),D=D[0]+" "+D[1]+" "+C.zOrigin+"px"),D+="",f=new va(w,u,0,0,f,-1,B),f.b=w[u],f.plugin=h,Ha?(l=C.zOrigin,D=D.split(" "),C.zOrigin=(D.length>2?parseFloat(D[2]):l)||0,f.xs0=f.e=D[0]+" "+(D[1]||"50%")+" 0px",f=new va(C,"zOrigin",0,0,f,-1,f.n),f.b=l,f.xs0=f.e=C.zOrigin):f.xs0=f.e=D):ja(D+"",C)),n&&(d._transformType=C.svg&&Ca||!m&&3!==this._transformType?2:3),j&&(i.scale=j),f},allowFunc:!0,prefix:!0}),Aa("boxShadow",{defaultValue:"0px 0px 0px 0px #999",prefix:!0,color:!0,multi:!0,keyword:"inset"}),Aa("clipPath",{defaultValue:"inset(0%)",prefix:!0,multi:!0,formatter:sa("inset(0% 0% 0% 0%)",!1,!0)}),Aa("borderRadius",{defaultValue:"0px",parser:function(a,b,c,f,g,h){b=this.format(b);var i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y=["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"],z=a.style;for(q=parseFloat(a.offsetWidth),r=parseFloat(a.offsetHeight),i=b.split(" "),j=0;jp?1:0))||""):(p=parseFloat(n),s=n.substr((p+"").length)),""===s&&(s=d[c]||t),s!==t&&(v=ca(a,"borderLeft",o,t),w=ca(a,"borderTop",o,t),"%"===s?(m=v/q*100+"%",l=w/r*100+"%"):"em"===s?(x=ca(a,"borderLeft",1,"em"),m=v/x+"em",l=w/x+"em"):(m=v+"px",l=w+"px"),u&&(n=parseFloat(m)+p+s,k=parseFloat(l)+p+s)),g=xa(z,y[j],m+" "+l,n+" "+k,!1,"0px",g);return g},prefix:!0,formatter:sa("0px 0px 0px 0px",!1,!0)}),Aa("borderBottomLeftRadius,borderBottomRightRadius,borderTopLeftRadius,borderTopRightRadius",{defaultValue:"0px",parser:function(a,b,c,d,f,g){return xa(a.style,c,this.format(ba(a,c,e,!1,"0px 0px")),this.format(b),!1,"0px",f)},prefix:!0,formatter:sa("0px 0px",!1,!0)}),Aa("backgroundPosition",{defaultValue:"0 0",parser:function(a,b,c,d,f,g){var h,i,j,k,l,m,n="background-position",o=e||aa(a,null),q=this.format((o?p?o.getPropertyValue(n+"-x")+" "+o.getPropertyValue(n+"-y"):o.getPropertyValue(n):a.currentStyle.backgroundPositionX+" "+a.currentStyle.backgroundPositionY)||"0 0"),r=this.format(b);if(-1!==q.indexOf("%")!=(-1!==r.indexOf("%"))&&r.split(",").length<2&&(m=ba(a,"backgroundImage").replace(E,""),m&&"none"!==m)){for(h=q.split(" "),i=r.split(" "),S.setAttribute("src",m),j=2;--j>-1;)q=h[j],k=-1!==q.indexOf("%"),k!==(-1!==i[j].indexOf("%"))&&(l=0===j?a.offsetWidth-S.width:a.offsetHeight-S.height,h[j]=k?parseFloat(q)/100*l+"px":parseFloat(q)/l*100+"%");q=h.join(" ")}return this.parseComplex(a.style,q,r,f,g)},formatter:ja}),Aa("backgroundSize",{defaultValue:"0 0",formatter:function(a){return a+="","co"===a.substr(0,2)?a:ja(-1===a.indexOf(" ")?a+" "+a:a)}}),Aa("perspective",{defaultValue:"0px",prefix:!0}),Aa("perspectiveOrigin",{defaultValue:"50% 50%",prefix:!0}),Aa("transformStyle",{prefix:!0}),Aa("backfaceVisibility",{prefix:!0}),Aa("userSelect",{prefix:!0}),Aa("margin",{parser:ta("marginTop,marginRight,marginBottom,marginLeft")}),Aa("padding",{parser:ta("paddingTop,paddingRight,paddingBottom,paddingLeft")}),Aa("clip",{defaultValue:"rect(0px,0px,0px,0px)",parser:function(a,b,c,d,f,g){var h,i,j;return 9>p?(i=a.currentStyle,j=8>p?" ":",",h="rect("+i.clipTop+j+i.clipRight+j+i.clipBottom+j+i.clipLeft+")",b=this.format(b).split(",").join(j)):(h=this.format(ba(a,this.p,e,!1,this.dflt)),b=this.format(b)),this.parseComplex(a.style,h,b,f,g)}}),Aa("textShadow",{defaultValue:"0px 0px 0px #999",color:!0,multi:!0}),Aa("autoRound,strictUnits",{parser:function(a,b,c,d,e){return e}}),Aa("border",{defaultValue:"0px solid #000",parser:function(a,b,c,d,f,g){var h=ba(a,"borderTopWidth",e,!1,"0px"),i=this.format(b).split(" "),j=i[0].replace(x,"");return"px"!==j&&(h=parseFloat(h)/ca(a,"borderTopWidth",1,j)+j),this.parseComplex(a.style,this.format(h+" "+ba(a,"borderTopStyle",e,!1,"solid")+" "+ba(a,"borderTopColor",e,!1,"#000")),i.join(" "),f,g)},color:!0,formatter:function(a){var b=a.split(" ");return b[0]+" "+(b[1]||"solid")+" "+(a.match(ra)||["#000"])[0]}}),Aa("borderWidth",{parser:ta("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}),Aa("float,cssFloat,styleFloat",{parser:function(a,b,c,d,e,f){var g=a.style,h="cssFloat"in g?"cssFloat":"styleFloat";return new va(g,h,0,0,e,-1,c,!1,0,g[h],b)}});var Wa=function(a){var b,c=this.t,d=c.filter||ba(this.data,"filter")||"",e=this.s+this.c*a|0;100===e&&(-1===d.indexOf("atrix(")&&-1===d.indexOf("radient(")&&-1===d.indexOf("oader(")?(c.removeAttribute("filter"),b=!ba(this.data,"filter")):(c.filter=d.replace(A,""),b=!0)),b||(this.xn1&&(c.filter=d=d||"alpha(opacity="+e+")"),-1===d.indexOf("pacity")?0===e&&this.xn1||(c.filter=d+" alpha(opacity="+e+")"):c.filter=d.replace(y,"opacity="+e))};Aa("opacity,alpha,autoAlpha",{defaultValue:"1",parser:function(a,b,c,d,f,g){var h=parseFloat(ba(a,"opacity",e,!1,"1")),i=a.style,j="autoAlpha"===c;return"string"==typeof b&&"="===b.charAt(1)&&(b=("-"===b.charAt(0)?-1:1)*parseFloat(b.substr(2))+h),j&&1===h&&"hidden"===ba(a,"visibility",e)&&0!==b&&(h=0),V?f=new va(i,"opacity",h,b-h,f):(f=new va(i,"opacity",100*h,100*(b-h),f),f.xn1=j?1:0,i.zoom=1,f.type=2,f.b="alpha(opacity="+f.s+")",f.e="alpha(opacity="+(f.s+f.c)+")",f.data=a,f.plugin=g,f.setRatio=Wa),j&&(f=new va(i,"visibility",0,0,f,-1,null,!1,0,0!==h?"inherit":"hidden",0===b?"hidden":"inherit"),f.xs0="inherit",d._overwriteProps.push(f.n),d._overwriteProps.push(c)),f}});var Xa=function(a,b){b&&(a.removeProperty?(("ms"===b.substr(0,2)||"webkit"===b.substr(0,6))&&(b="-"+b),a.removeProperty(b.replace(C,"-$1").toLowerCase())):a.removeAttribute(b))},Ya=function(a){if(this.t._gsClassPT=this,1===a||0===a){this.t.setAttribute("class",0===a?this.b:this.e);for(var b=this.data,c=this.t.style;b;)b.v?c[b.p]=b.v:Xa(c,b.p),b=b._next;1===a&&this.t._gsClassPT===this&&(this.t._gsClassPT=null)}else this.t.getAttribute("class")!==this.e&&this.t.setAttribute("class",this.e)};Aa("className",{parser:function(a,b,d,f,g,h,i){var j,k,l,m,n,o=a.getAttribute("class")||"",p=a.style.cssText;if(g=f._classNamePT=new va(a,d,0,0,g,2),g.setRatio=Ya,g.pr=-11,c=!0,g.b=o,k=ea(a,e),l=a._gsClassPT){for(m={},n=l.data;n;)m[n.p]=1,n=n._next;l.setRatio(1)}return a._gsClassPT=g,g.e="="!==b.charAt(1)?b:o.replace(new RegExp("(?:\\s|^)"+b.substr(2)+"(?![\\w-])"),"")+("+"===b.charAt(0)?" "+b.substr(2):""),a.setAttribute("class",g.e),j=fa(a,k,ea(a),i,m),a.setAttribute("class",o),g.data=j.firstMPT,a.style.cssText!==p&&(a.style.cssText=p),g=g.xfirst=f.parse(a,j.difs,g,h)}});var Za=function(a){if((1===a||0===a)&&this.data._totalTime===this.data._totalDuration&&"isFromStart"!==this.data.data){var b,c,d,e,f,g=this.t.style,h=i.transform.parse;if("all"===this.e)g.cssText="",e=!0;else for(b=this.e.split(" ").join("").split(","),d=b.length;--d>-1;)c=b[d],i[c]&&(i[c].parse===h?e=!0:c="transformOrigin"===c?Ga:i[c].p),Xa(g,c);e&&(Xa(g,Ea),f=this.t._gsTransform,f&&(f.svg&&(this.t.removeAttribute("data-svg-origin"),this.t.removeAttribute("transform")),delete this.t._gsTransform))}};for(Aa("clearProps",{parser:function(a,b,d,e,f){return f=new va(a,d,0,0,f,2),f.setRatio=Za,f.e=b,f.pr=-10,f.data=e._tween,c=!0,f}}),j="bezier,throwProps,physicsProps,physics2D".split(","),ya=j.length;ya--;)Ba(j[ya]);j=g.prototype,j._firstPT=j._lastParsedTransform=j._transform=null,j._onInitTween=function(a,b,h,j){if(!a.nodeType)return!1;this._target=q=a,this._tween=h,this._vars=b,r=j,k=b.autoRound,c=!1,d=b.suffixMap||g.suffixMap,e=aa(a,""),f=this._overwriteProps;var n,p,s,t,u,v,w,x,y,A=a.style;if(l&&""===A.zIndex&&(n=ba(a,"zIndex",e),("auto"===n||""===n)&&this._addLazySet(A,"zIndex",0)),"string"==typeof b&&(t=A.cssText,n=ea(a,e),A.cssText=t+";"+b,n=fa(a,n,ea(a)).difs,!V&&z.test(b)&&(n.opacity=parseFloat(RegExp.$1)),b=n,A.cssText=t),b.className?this._firstPT=p=i.className.parse(a,b.className,"className",this,null,null,b):this._firstPT=p=this.parse(a,b,null),this._transformType){for(y=3===this._transformType,Ea?m&&(l=!0,""===A.zIndex&&(w=ba(a,"zIndex",e),("auto"===w||""===w)&&this._addLazySet(A,"zIndex",0)),o&&this._addLazySet(A,"WebkitBackfaceVisibility",this._vars.WebkitBackfaceVisibility||(y?"visible":"hidden"))):A.zoom=1,s=p;s&&s._next;)s=s._next;x=new va(a,"transform",0,0,null,2),this._linkCSSP(x,null,s),x.setRatio=Ea?Va:Ua,x.data=this._transform||Ta(a,e,!0),x.tween=h,x.pr=-1,f.pop()}if(c){for(;p;){for(v=p._next,s=t;s&&s.pr>p.pr;)s=s._next;(p._prev=s?s._prev:u)?p._prev._next=p:t=p,(p._next=s)?s._prev=p:u=p,p=v}this._firstPT=t}return!0},j.parse=function(a,b,c,f){var g,h,j,l,m,n,o,p,s,t,u=a.style;for(g in b){if(n=b[g],h=i[g],"function"!=typeof n||h&&h.allowFunc||(n=n(r,q)),h)c=h.parse(a,n,g,this,c,f,b);else{if("--"===g.substr(0,2)){this._tween._propLookup[g]=this._addTween.call(this._tween,a.style,"setProperty",aa(a).getPropertyValue(g)+"",n+"",g,!1,g);continue}m=ba(a,g,e)+"",s="string"==typeof n,"color"===g||"fill"===g||"stroke"===g||-1!==g.indexOf("Color")||s&&B.test(n)?(s||(n=pa(n),n=(n.length>3?"rgba(":"rgb(")+n.join(",")+")"),c=xa(u,g,m,n,!0,"transparent",c,0,f)):s&&K.test(n)?c=xa(u,g,m,n,!0,null,c,0,f):(j=parseFloat(m),o=j||0===j?m.substr((j+"").length):"",(""===m||"auto"===m)&&("width"===g||"height"===g?(j=ia(a,g,e),o="px"):"left"===g||"top"===g?(j=da(a,g,e),o="px"):(j="opacity"!==g?0:1,o="")),t=s&&"="===n.charAt(1),t?(l=parseInt(n.charAt(0)+"1",10),n=n.substr(2),l*=parseFloat(n),p=n.replace(x,"")):(l=parseFloat(n),p=s?n.replace(x,""):""),""===p&&(p=g in d?d[g]:o),n=l||0===l?(t?l+j:l)+p:b[g],o!==p&&(""!==p||"lineHeight"===g)&&(l||0===l)&&j&&(j=ca(a,g,j,o),"%"===p?(j/=ca(a,g,100,"%")/100,b.strictUnits!==!0&&(m=j+"%")):"em"===p||"rem"===p||"vw"===p||"vh"===p?j/=ca(a,g,1,p):"px"!==p&&(l=ca(a,g,l,p),p="px"),t&&(l||0===l)&&(n=l+j+p)),t&&(l+=j),!j&&0!==j||!l&&0!==l?void 0!==u[g]&&(n||n+""!="NaN"&&null!=n)?(c=new va(u,g,l||j||0,0,c,-1,g,!1,0,m,n),c.xs0="none"!==n||"display"!==g&&-1===g.indexOf("Style")?n:m):X("invalid "+g+" tween value: "+b[g]):(c=new va(u,g,j,l-j,c,0,g,k!==!1&&("px"===p||"zIndex"===g),0,m,n),c.xs0=p))}f&&c&&!c.plugin&&(c.plugin=f)}return c},j.setRatio=function(a){var b,c,d,e=this._firstPT,f=1e-6;if(1!==a||this._tween._time!==this._tween._duration&&0!==this._tween._time)if(a||this._tween._time!==this._tween._duration&&0!==this._tween._time||this._tween._rawPrevTime===-1e-6)for(;e;){if(b=e.c*a+e.s,e.r?b=e.r(b):f>b&&b>-f&&(b=0),e.type)if(1===e.type)if(d=e.l,2===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2;else if(3===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3;else if(4===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3+e.xn3+e.xs4;else if(5===d)e.t[e.p]=e.xs0+b+e.xs1+e.xn1+e.xs2+e.xn2+e.xs3+e.xn3+e.xs4+e.xn4+e.xs5;else{for(c=e.xs0+b+e.xs1,d=1;d-1;)_a(a[e],b,c);else for(d=a.childNodes,e=d.length;--e>-1;)f=d[e],g=f.type,f.style&&(b.push(ea(f)),c&&c.push(f)),1!==g&&9!==g&&11!==g||!f.childNodes.length||_a(f,b,c)};return g.cascadeTo=function(a,c,d){var e,f,g,h,i=b.to(a,c,d),j=[i],k=[],l=[],m=[],n=b._internals.reservedProps;for(a=i._targets||i.target,_a(a,k,m),i.render(c,!0,!0),_a(a,l),i.render(0,!0,!0),i._enabled(!0),e=m.length;--e>-1;)if(f=fa(m[e],k[e],l[e]),f.firstMPT){f=f.difs;for(g in d)n[g]&&(f[g]=d[g]);h={};for(g in f)h[g]=k[e][g];j.push(b.fromTo(m[e],c,h,f))}return j},a.activate([g]),g},!0),function(){var a=_gsScope._gsDefine.plugin({propName:"roundProps",version:"1.7.0",priority:-1,API:2,init:function(a,b,c){return this._tween=c,!0}}),b=function(a){var b=1>a?Math.pow(10,(a+"").length-2):1;return function(c){return(Math.round(c/a)*a*b|0)/b}},c=function(a,b){for(;a;)a.f||a.blob||(a.m=b||Math.round),a=a._next},d=a.prototype;d._onInitAllProps=function(){var a,d,e,f,g=this._tween,h=g.vars.roundProps,i={},j=g._propLookup.roundProps;if("object"!=typeof h||h.push)for("string"==typeof h&&(h=h.split(",")),e=h.length;--e>-1;)i[h[e]]=Math.round;else for(f in h)i[f]=b(h[f]);for(f in i)for(a=g._firstPT;a;)d=a._next,a.pg?a.t._mod(i):a.n===f&&(2===a.f&&a.t?c(a.t._firstPT,i[f]):(this._add(a.t,f,a.s,a.c,i[f]),d&&(d._prev=a._prev),a._prev?a._prev._next=d:g._firstPT===a&&(g._firstPT=d),a._next=a._prev=null,g._propLookup[f]=j)),a=d;return!1},d._add=function(a,b,c,d,e){this._addTween(a,b,c,c+d,b,e||Math.round),this._overwriteProps.push(b)}}(),function(){_gsScope._gsDefine.plugin({propName:"attr",API:2,version:"0.6.1",init:function(a,b,c,d){var e,f;if("function"!=typeof a.setAttribute)return!1;for(e in b)f=b[e],"function"==typeof f&&(f=f(d,a)),this._addTween(a,"setAttribute",a.getAttribute(e)+"",f+"",e,!1,e),this._overwriteProps.push(e);return!0}})}(),_gsScope._gsDefine.plugin({propName:"directionalRotation",version:"0.3.1",API:2,init:function(a,b,c,d){"object"!=typeof b&&(b={rotation:b}),this.finals={};var e,f,g,h,i,j,k=b.useRadians===!0?2*Math.PI:360,l=1e-6;for(e in b)"useRadians"!==e&&(h=b[e],"function"==typeof h&&(h=h(d,a)),j=(h+"").split("_"),f=j[0],g=parseFloat("function"!=typeof a[e]?a[e]:a[e.indexOf("set")||"function"!=typeof a["get"+e.substr(3)]?e:"get"+e.substr(3)]()),h=this.finals[e]="string"==typeof f&&"="===f.charAt(1)?g+parseInt(f.charAt(0)+"1",10)*Number(f.substr(2)):Number(f)||0,i=h-g,j.length&&(f=j.join("_"),-1!==f.indexOf("short")&&(i%=k,i!==i%(k/2)&&(i=0>i?i+k:i-k)),-1!==f.indexOf("_cw")&&0>i?i=(i+9999999999*k)%k-(i/k|0)*k:-1!==f.indexOf("ccw")&&i>0&&(i=(i-9999999999*k)%k-(i/k|0)*k)),(i>l||-l>i)&&(this._addTween(a,e,g,g+i,e),this._overwriteProps.push(e)));return!0},set:function(a){var b;if(1!==a)this._super.setRatio.call(this,a);else for(b=this._firstPT;b;)b.f?b.t[b.p](this.finals[b.p]):b.t[b.p]=this.finals[b.p],b=b._next}})._autoCSS=!0,_gsScope._gsDefine("easing.Back",["easing.Ease"],function(a){var b,c,d,e,f=_gsScope.GreenSockGlobals||_gsScope,g=f.com.greensock,h=2*Math.PI,i=Math.PI/2,j=g._class,k=function(b,c){var d=j("easing."+b,function(){},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,d},l=a.register||function(){},m=function(a,b,c,d,e){var f=j("easing."+a,{easeOut:new b,easeIn:new c,easeInOut:new d},!0);return l(f,a),f},n=function(a,b,c){this.t=a,this.v=b,c&&(this.next=c,c.prev=this,this.c=c.v-b,this.gap=c.t-a)},o=function(b,c){var d=j("easing."+b,function(a){this._p1=a||0===a?a:1.70158,this._p2=1.525*this._p1},!0),e=d.prototype=new a;return e.constructor=d,e.getRatio=c,e.config=function(a){return new d(a)},d},p=m("Back",o("BackOut",function(a){return(a-=1)*a*((this._p1+1)*a+this._p1)+1}),o("BackIn",function(a){return a*a*((this._p1+1)*a-this._p1)}),o("BackInOut",function(a){return(a*=2)<1?.5*a*a*((this._p2+1)*a-this._p2):.5*((a-=2)*a*((this._p2+1)*a+this._p2)+2)})),q=j("easing.SlowMo",function(a,b,c){b=b||0===b?b:.7,null==a?a=.7:a>1&&(a=1),this._p=1!==a?b:0,this._p1=(1-a)/2,this._p2=a,this._p3=this._p1+this._p2,this._calcEnd=c===!0},!0),r=q.prototype=new a;return r.constructor=q,r.getRatio=function(a){var b=a+(.5-a)*this._p;return athis._p3?this._calcEnd?1===a?0:1-(a=(a-this._p3)/this._p1)*a:b+(a-b)*(a=(a-this._p3)/this._p1)*a*a*a:this._calcEnd?1:b},q.ease=new q(.7,.7),r.config=q.config=function(a,b,c){return new q(a,b,c)},b=j("easing.SteppedEase",function(a,b){a=a||1,this._p1=1/a,this._p2=a+(b?0:1),this._p3=b?1:0},!0),r=b.prototype=new a,r.constructor=b,r.getRatio=function(a){return 0>a?a=0:a>=1&&(a=.999999999),((this._p2*a|0)+this._p3)*this._p1},r.config=b.config=function(a,c){return new b(a,c)},c=j("easing.ExpoScaleEase",function(a,b,c){this._p1=Math.log(b/a),this._p2=b-a,this._p3=a,this._ease=c},!0),r=c.prototype=new a,r.constructor=c,r.getRatio=function(a){return this._ease&&(a=this._ease.getRatio(a)),(this._p3*Math.exp(this._p1*a)-this._p3)/this._p2},r.config=c.config=function(a,b,d){return new c(a,b,d)},d=j("easing.RoughEase",function(b){b=b||{};for(var c,d,e,f,g,h,i=b.taper||"none",j=[],k=0,l=0|(b.points||20),m=l,o=b.randomize!==!1,p=b.clamp===!0,q=b.template instanceof a?b.template:null,r="number"==typeof b.strength?.4*b.strength:.4;--m>-1;)c=o?Math.random():1/l*m,d=q?q.getRatio(c):c,"none"===i?e=r:"out"===i?(f=1-c,e=f*f*r):"in"===i?e=c*c*r:.5>c?(f=2*c,e=f*f*.5*r):(f=2*(1-c),e=f*f*.5*r),o?d+=Math.random()*e-.5*e:m%2?d+=.5*e:d-=.5*e,p&&(d>1?d=1:0>d&&(d=0)),j[k++]={x:c,y:d};for(j.sort(function(a,b){return a.x-b.x}),h=new n(1,1,null),m=l;--m>-1;)g=j[m],h=new n(g.x,g.y,h);this._prev=new n(0,0,0!==h.t?h:h.next)},!0),r=d.prototype=new a,r.constructor=d,r.getRatio=function(a){var b=this._prev;if(a>b.t){for(;b.next&&a>=b.t;)b=b.next;b=b.prev}else for(;b.prev&&a<=b.t;)b=b.prev;return this._prev=b,b.v+(a-b.t)/b.gap*b.c},r.config=function(a){return new d(a)},d.ease=new d,m("Bounce",k("BounceOut",function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375}),k("BounceIn",function(a){return(a=1-a)<1/2.75?1-7.5625*a*a:2/2.75>a?1-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?1-(7.5625*(a-=2.25/2.75)*a+.9375):1-(7.5625*(a-=2.625/2.75)*a+.984375)}),k("BounceInOut",function(a){var b=.5>a;return a=b?1-2*a:2*a-1,a=1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375,b?.5*(1-a):.5*a+.5})),m("Circ",k("CircOut",function(a){return Math.sqrt(1-(a-=1)*a)}),k("CircIn",function(a){return-(Math.sqrt(1-a*a)-1)}),k("CircInOut",function(a){return(a*=2)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)})),e=function(b,c,d){var e=j("easing."+b,function(a,b){this._p1=a>=1?a:1,this._p2=(b||d)/(1>a?a:1),this._p3=this._p2/h*(Math.asin(1/this._p1)||0),this._p2=h/this._p2},!0),f=e.prototype=new a;return f.constructor=e,f.getRatio=c,f.config=function(a,b){return new e(a,b)},e},m("Elastic",e("ElasticOut",function(a){return this._p1*Math.pow(2,-10*a)*Math.sin((a-this._p3)*this._p2)+1},.3),e("ElasticIn",function(a){return-(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2))},.3),e("ElasticInOut",function(a){return(a*=2)<1?-.5*(this._p1*Math.pow(2,10*(a-=1))*Math.sin((a-this._p3)*this._p2)):this._p1*Math.pow(2,-10*(a-=1))*Math.sin((a-this._p3)*this._p2)*.5+1},.45)),m("Expo",k("ExpoOut",function(a){return 1-Math.pow(2,-10*a)}),k("ExpoIn",function(a){return Math.pow(2,10*(a-1))-.001}),k("ExpoInOut",function(a){return(a*=2)<1?.5*Math.pow(2,10*(a-1)):.5*(2-Math.pow(2,-10*(a-1)))})),m("Sine",k("SineOut",function(a){return Math.sin(a*i)}),k("SineIn",function(a){return-Math.cos(a*i)+1}),k("SineInOut",function(a){return-.5*(Math.cos(Math.PI*a)-1)})),j("easing.EaseLookup",{find:function(b){return a.map[b]}},!0),l(f.SlowMo,"SlowMo","ease,"),l(d,"RoughEase","ease,"),l(b,"SteppedEase","ease,"),p},!0)}),_gsScope._gsDefine&&_gsScope._gsQueue.pop()(),function(a,b){"use strict";var c={},d=a.document,e=a.GreenSockGlobals=a.GreenSockGlobals||a,f=e[b];if(f)return"undefined"!=typeof module&&module.exports&&(module.exports=f),f;var g,h,i,j,k,l=function(a){var b,c=a.split("."),d=e;for(b=0;b-1;)(k=r[f[p]]||new s(f[p],[])).gsClass?(i[p]=k.gsClass,q--):j&&k.sc.push(this);if(0===q&&g){if(m=("com.greensock."+d).split("."),n=m.pop(),o=l(m.join("."))[n]=this.gsClass=g.apply(g,i),h)if(e[n]=c[n]=o,"undefined"!=typeof module&&module.exports)if(d===b){module.exports=c[b]=o;for(p in c)o[p]=c[p]}else c[b]&&(c[b][n]=o);else"function"==typeof define&&define.amd&&define((a.GreenSockAMDPath?a.GreenSockAMDPath+"/":"")+d.split(".").pop(),[],function(){return o});for(p=0;p-1;)for(f=i[j],e=d?u("easing."+f,null,!0):m.easing[f]||{},g=k.length;--g>-1;)h=k[g],x[f+"."+h]=x[h+f]=e[h]=a.getRatio?a:a[h]||new a};for(i=w.prototype,i._calcEnd=!1,i.getRatio=function(a){if(this._func)return this._params[0]=a,this._func.apply(null,this._params);var b=this._type,c=this._power,d=1===b?1-a:2===b?a:.5>a?2*a:2*(1-a);return 1===c?d*=d:2===c?d*=d*d:3===c?d*=d*d*d:4===c&&(d*=d*d*d*d),1===b?1-d:2===b?d:.5>a?d/2:1-d/2},g=["Linear","Quad","Cubic","Quart","Quint,Strong"],h=g.length;--h>-1;)i=g[h]+",Power"+h,y(new w(null,null,1,h),i,"easeOut",!0),y(new w(null,null,2,h),i,"easeIn"+(0===h?",easeNone":"")),y(new w(null,null,3,h),i,"easeInOut");x.linear=m.easing.Linear.easeIn,x.swing=m.easing.Quad.easeInOut;var z=u("events.EventDispatcher",function(a){this._listeners={},this._eventTarget=a||this});i=z.prototype,i.addEventListener=function(a,b,c,d,e){e=e||0;var f,g,h=this._listeners[a],i=0;for(this!==j||k||j.wake(),null==h&&(this._listeners[a]=h=[]),g=h.length;--g>-1;)f=h[g],f.c===b&&f.s===c?h.splice(g,1):0===i&&f.pr-1;)if(d[c].c===b)return void d.splice(c,1)},i.dispatchEvent=function(a){var b,c,d,e=this._listeners[a];if(e)for(b=e.length,b>1&&(e=e.slice(0)),c=this._eventTarget;--b>-1;)d=e[b],d&&(d.up?d.c.call(d.s||c,{type:a,target:c}):d.c.call(d.s||c))};var A=a.requestAnimationFrame,B=a.cancelAnimationFrame,C=Date.now||function(){return(new Date).getTime()},D=C();for(g=["ms","moz","webkit","o"],h=g.length;--h>-1&&!A;)A=a[g[h]+"RequestAnimationFrame"],B=a[g[h]+"CancelAnimationFrame"]||a[g[h]+"CancelRequestAnimationFrame"];u("Ticker",function(a,b){var c,e,f,g,h,i=this,l=C(),m=b!==!1&&A?"auto":!1,o=500,q=33,r="tick",s=function(a){var b,d,j=C()-D;j>o&&(l+=j-q),D+=j,i.time=(D-l)/1e3,b=i.time-h,(!c||b>0||a===!0)&&(i.frame++,h+=b+(b>=g?.004:g-b),d=!0),a!==!0&&(f=e(s)),d&&i.dispatchEvent(r)};z.call(i),i.time=i.frame=0,i.tick=function(){s(!0)},i.lagSmoothing=function(a,b){return arguments.length?(o=a||1/n,void(q=Math.min(b,o,0))):1/n>o},i.sleep=function(){null!=f&&(m&&B?B(f):clearTimeout(f),e=p,f=null,i===j&&(k=!1))},i.wake=function(a){null!==f?i.sleep():a?l+=-D+(D=C()):i.frame>10&&(D=C()-o+5),e=0===c?p:m&&A?A:function(a){return setTimeout(a,1e3*(h-i.time)+1|0)},i===j&&(k=!0),s(2)},i.fps=function(a){return arguments.length?(c=a,g=1/(c||60),h=this.time+g,void i.wake()):c},i.useRAF=function(a){return arguments.length?(i.sleep(),m=a,void i.fps(c)):m},i.fps(a),setTimeout(function(){"auto"===m&&i.frame<5&&"hidden"!==(d||{}).visibilityState&&i.useRAF(!1)},1500)}),i=m.Ticker.prototype=new m.events.EventDispatcher,i.constructor=m.Ticker;var E=u("core.Animation",function(a,b){if(this.vars=b=b||{},this._duration=this._totalDuration=a||0,this._delay=Number(b.delay)||0,this._timeScale=1,this._active=!!b.immediateRender,this.data=b.data,this._reversed=!!b.reversed,Z){k||j.wake();var c=this.vars.useFrames?Y:Z;c.add(this,c._time),this.vars.paused&&this.paused(!0)}});j=E.ticker=new m.Ticker,i=E.prototype,i._dirty=i._gc=i._initted=i._paused=!1,i._totalTime=i._time=0,i._rawPrevTime=-1,i._next=i._last=i._onUpdate=i._timeline=i.timeline=null,i._paused=!1;var F=function(){k&&C()-D>2e3&&("hidden"!==(d||{}).visibilityState||!j.lagSmoothing())&&j.wake();var a=setTimeout(F,2e3);a.unref&&a.unref()};F(),i.play=function(a,b){return null!=a&&this.seek(a,b),this.reversed(!1).paused(!1)},i.pause=function(a,b){return null!=a&&this.seek(a,b),this.paused(!0)},i.resume=function(a,b){return null!=a&&this.seek(a,b),this.paused(!1)},i.seek=function(a,b){return this.totalTime(Number(a),b!==!1)},i.restart=function(a,b){return this.reversed(!1).paused(!1).totalTime(a?-this._delay:0,b!==!1,!0)},i.reverse=function(a,b){return null!=a&&this.seek(a||this.totalDuration(),b),this.reversed(!0).paused(!1)},i.render=function(a,b,c){},i.invalidate=function(){return this._time=this._totalTime=0,this._initted=this._gc=!1,this._rawPrevTime=-1,(this._gc||!this.timeline)&&this._enabled(!0),this},i.isActive=function(){var a,b=this._timeline,c=this._startTime;return!b||!this._gc&&!this._paused&&b.isActive()&&(a=b.rawTime(!0))>=c&&a-1;)"{self}"===a[b]&&(c[b]=this);return c},i._callback=function(a){var b=this.vars,c=b[a],d=b[a+"Params"],e=b[a+"Scope"]||b.callbackScope||this,f=d?d.length:0;switch(f){case 0:c.call(e);break;case 1:c.call(e,d[0]);break;case 2:c.call(e,d[0],d[1]);break;default:c.apply(e,d)}},i.eventCallback=function(a,b,c,d){if("on"===(a||"").substr(0,2)){var e=this.vars;if(1===arguments.length)return e[a];null==b?delete e[a]:(e[a]=b,e[a+"Params"]=q(c)&&-1!==c.join("").indexOf("{self}")?this._swapSelfInParams(c):c,e[a+"Scope"]=d),"onUpdate"===a&&(this._onUpdate=b)}return this},i.delay=function(a){return arguments.length?(this._timeline.smoothChildTiming&&this.startTime(this._startTime+a-this._delay),this._delay=a,this):this._delay},i.duration=function(a){return arguments.length?(this._duration=this._totalDuration=a,this._uncache(!0),this._timeline.smoothChildTiming&&this._time>0&&this._timethis._duration?this._duration:a,b)):this._time},i.totalTime=function(a,b,c){if(k||j.wake(),!arguments.length)return this._totalTime;if(this._timeline){if(0>a&&!c&&(a+=this.totalDuration()),this._timeline.smoothChildTiming){this._dirty&&this.totalDuration();var d=this._totalDuration,e=this._timeline;if(a>d&&!c&&(a=d),this._startTime=(this._paused?this._pauseTime:e._time)-(this._reversed?d-a:a)/this._timeScale,e._dirty||this._uncache(!1),e._timeline)for(;e._timeline;)e._timeline._time!==(e._startTime+e._totalTime)/e._timeScale&&e.totalTime(e._totalTime,!0), + e=e._timeline}this._gc&&this._enabled(!0,!1),(this._totalTime!==a||0===this._duration)&&(K.length&&_(),this.render(a,b,!1),K.length&&_())}return this},i.progress=i.totalProgress=function(a,b){var c=this.duration();return arguments.length?this.totalTime(c*a,b):c?this._time/c:this.ratio},i.startTime=function(a){return arguments.length?(a!==this._startTime&&(this._startTime=a,this.timeline&&this.timeline._sortChildren&&this.timeline.add(this,a-this._delay)),this):this._startTime},i.endTime=function(a){return this._startTime+(0!=a?this.totalDuration():this.duration())/this._timeScale},i.timeScale=function(a){if(!arguments.length)return this._timeScale;var b,c;for(a=a||n,this._timeline&&this._timeline.smoothChildTiming&&(b=this._pauseTime,c=b||0===b?b:this._timeline.totalTime(),this._startTime=c-(c-this._startTime)*this._timeScale/a),this._timeScale=a,c=this.timeline;c&&c.timeline;)c._dirty=!0,c.totalDuration(),c=c.timeline;return this},i.reversed=function(a){return arguments.length?(a!=this._reversed&&(this._reversed=a,this.totalTime(this._timeline&&!this._timeline.smoothChildTiming?this.totalDuration()-this._totalTime:this._totalTime,!0)),this):this._reversed},i.paused=function(a){if(!arguments.length)return this._paused;var b,c,d=this._timeline;return a!=this._paused&&d&&(k||a||j.wake(),b=d.rawTime(),c=b-this._pauseTime,!a&&d.smoothChildTiming&&(this._startTime+=c,this._uncache(!1)),this._pauseTime=a?b:null,this._paused=a,this._active=this.isActive(),!a&&0!==c&&this._initted&&this.duration()&&(b=d.smoothChildTiming?this._totalTime:(b-this._startTime)/this._timeScale,this.render(b,b===this._totalTime,!0))),this._gc&&!a&&this._enabled(!0,!1),this};var G=u("core.SimpleTimeline",function(a){E.call(this,0,a),this.autoRemoveChildren=this.smoothChildTiming=!0});i=G.prototype=new E,i.constructor=G,i.kill()._gc=!1,i._first=i._last=i._recent=null,i._sortChildren=!1,i.add=i.insert=function(a,b,c,d){var e,f;if(a._startTime=Number(b||0)+a._delay,a._paused&&this!==a._timeline&&(a._pauseTime=this.rawTime()-(a._timeline.rawTime()-a._pauseTime)),a.timeline&&a.timeline._remove(a,!0),a.timeline=a._timeline=this,a._gc&&a._enabled(!0,!0),e=this._last,this._sortChildren)for(f=a._startTime;e&&e._startTime>f;)e=e._prev;return e?(a._next=e._next,e._next=a):(a._next=this._first,this._first=a),a._next?a._next._prev=a:this._last=a,a._prev=e,this._recent=a,this._timeline&&this._uncache(!0),this},i._remove=function(a,b){return a.timeline===this&&(b||a._enabled(!1,!0),a._prev?a._prev._next=a._next:this._first===a&&(this._first=a._next),a._next?a._next._prev=a._prev:this._last===a&&(this._last=a._prev),a._next=a._prev=a.timeline=null,a===this._recent&&(this._recent=this._last),this._timeline&&this._uncache(!0)),this},i.render=function(a,b,c){var d,e=this._first;for(this._totalTime=this._time=this._rawPrevTime=a;e;)d=e._next,(e._active||a>=e._startTime&&!e._paused&&!e._gc)&&(e._reversed?e.render((e._dirty?e.totalDuration():e._totalDuration)-(a-e._startTime)*e._timeScale,b,c):e.render((a-e._startTime)*e._timeScale,b,c)),e=d},i.rawTime=function(){return k||j.wake(),this._totalTime};var H=u("TweenLite",function(b,c,d){if(E.call(this,c,d),this.render=H.prototype.render,null==b)throw"Cannot tween a null target.";this.target=b="string"!=typeof b?b:H.selector(b)||b;var e,f,g,h=b.jquery||b.length&&b!==a&&b[0]&&(b[0]===a||b[0].nodeType&&b[0].style&&!b.nodeType),i=this.vars.overwrite;if(this._overwrite=i=null==i?X[H.defaultOverwrite]:"number"==typeof i?i>>0:X[i],(h||b instanceof Array||b.push&&q(b))&&"number"!=typeof b[0])for(this._targets=g=o(b),this._propLookup=[],this._siblings=[],e=0;e1&&ca(f,this,null,1,this._siblings[e])):(f=g[e--]=H.selector(f),"string"==typeof f&&g.splice(e+1,1)):g.splice(e--,1);else this._propLookup={},this._siblings=aa(b,this,!1),1===i&&this._siblings.length>1&&ca(b,this,null,1,this._siblings);(this.vars.immediateRender||0===c&&0===this._delay&&this.vars.immediateRender!==!1)&&(this._time=-n,this.render(Math.min(0,-this._delay)))},!0),I=function(b){return b&&b.length&&b!==a&&b[0]&&(b[0]===a||b[0].nodeType&&b[0].style&&!b.nodeType)},J=function(a,b){var c,d={};for(c in a)W[c]||c in b&&"transform"!==c&&"x"!==c&&"y"!==c&&"width"!==c&&"height"!==c&&"className"!==c&&"border"!==c||!(!T[c]||T[c]&&T[c]._autoCSS)||(d[c]=a[c],delete a[c]);a.css=d};i=H.prototype=new E,i.constructor=H,i.kill()._gc=!1,i.ratio=0,i._firstPT=i._targets=i._overwrittenProps=i._startAt=null,i._notifyPluginsOfEnabled=i._lazy=!1,H.version="2.1.3",H.defaultEase=i._ease=new w(null,null,1,1),H.defaultOverwrite="auto",H.ticker=j,H.autoSleep=120,H.lagSmoothing=function(a,b){j.lagSmoothing(a,b)},H.selector=a.$||a.jQuery||function(b){var c=a.$||a.jQuery;return c?(H.selector=c,c(b)):(d||(d=a.document),d?d.querySelectorAll?d.querySelectorAll(b):d.getElementById("#"===b.charAt(0)?b.substr(1):b):b)};var K=[],L={},M=/(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/gi,N=/[\+-]=-?[\.\d]/,O=function(a){for(var b,c=this._firstPT,d=1e-6;c;)b=c.blob?1===a&&null!=this.end?this.end:a?this.join(""):this.start:c.c*a+c.s,c.m?b=c.m.call(this._tween,b,this._target||c.t,this._tween):d>b&&b>-d&&!c.blob&&(b=0),c.f?c.fp?c.t[c.p](c.fp,b):c.t[c.p](b):c.t[c.p]=b,c=c._next},P=function(a){return(1e3*a|0)/1e3+""},Q=function(a,b,c,d){var e,f,g,h,i,j,k,l=[],m=0,n="",o=0;for(l.start=a,l.end=b,a=l[0]=a+"",b=l[1]=b+"",c&&(c(l),a=l[0],b=l[1]),l.length=0,e=a.match(M)||[],f=b.match(M)||[],d&&(d._next=null,d.blob=1,l._firstPT=l._applyPT=d),i=f.length,h=0;i>h;h++)k=f[h],j=b.substr(m,b.indexOf(k,m)-m),n+=j||!h?j:",",m+=j.length,o?o=(o+1)%5:"rgba("===j.substr(-5)&&(o=1),k===e[h]||e.length<=h?n+=k:(n&&(l.push(n),n=""),g=parseFloat(e[h]),l.push(g),l._firstPT={_next:l._firstPT,t:l,p:l.length-1,s:g,c:("="===k.charAt(1)?parseInt(k.charAt(0)+"1",10)*parseFloat(k.substr(2)):parseFloat(k)-g)||0,f:0,m:o&&4>o?Math.round:P}),m+=k.length;return n+=b.substr(m),n&&l.push(n),l.setRatio=O,N.test(b)&&(l.end=null),l},R=function(a,b,c,d,e,f,g,h,i){"function"==typeof d&&(d=d(i||0,a));var j,k=typeof a[b],l="function"!==k?"":b.indexOf("set")||"function"!=typeof a["get"+b.substr(3)]?b:"get"+b.substr(3),m="get"!==c?c:l?g?a[l](g):a[l]():a[b],n="string"==typeof d&&"="===d.charAt(1),o={t:a,p:b,s:m,f:"function"===k,pg:0,n:e||b,m:f?"function"==typeof f?f:Math.round:0,pr:0,c:n?parseInt(d.charAt(0)+"1",10)*parseFloat(d.substr(2)):parseFloat(d)-m||0};return("number"!=typeof m||"number"!=typeof d&&!n)&&(g||isNaN(m)||!n&&isNaN(d)||"boolean"==typeof m||"boolean"==typeof d?(o.fp=g,j=Q(m,n?parseFloat(o.s)+o.c+(o.s+"").replace(/[0-9\-\.]/g,""):d,h||H.defaultStringFilter,o),o={t:j,p:"setRatio",s:0,c:1,f:2,pg:0,n:e||b,pr:0,m:0}):(o.s=parseFloat(m),n||(o.c=parseFloat(d)-o.s||0))),o.c?((o._next=this._firstPT)&&(o._next._prev=o),this._firstPT=o,o):void 0},S=H._internals={isArray:q,isSelector:I,lazyTweens:K,blobDif:Q},T=H._plugins={},U=S.tweenLookup={},V=0,W=S.reservedProps={ease:1,delay:1,overwrite:1,onComplete:1,onCompleteParams:1,onCompleteScope:1,useFrames:1,runBackwards:1,startAt:1,onUpdate:1,onUpdateParams:1,onUpdateScope:1,onStart:1,onStartParams:1,onStartScope:1,onReverseComplete:1,onReverseCompleteParams:1,onReverseCompleteScope:1,onRepeat:1,onRepeatParams:1,onRepeatScope:1,easeParams:1,yoyo:1,immediateRender:1,repeat:1,repeatDelay:1,data:1,paused:1,reversed:1,autoCSS:1,lazy:1,onOverwrite:1,callbackScope:1,stringFilter:1,id:1,yoyoEase:1,stagger:1},X={none:0,all:1,auto:2,concurrent:3,allOnStart:4,preexisting:5,"true":1,"false":0},Y=E._rootFramesTimeline=new G,Z=E._rootTimeline=new G,$=30,_=S.lazyRender=function(){var a,b,c=K.length;for(L={},a=0;c>a;a++)b=K[a],b&&b._lazy!==!1&&(b.render(b._lazy[0],b._lazy[1],!0),b._lazy=!1);K.length=0};Z._startTime=j.time,Y._startTime=j.frame,Z._active=Y._active=!0,setTimeout(_,1),E._updateRoot=H.render=function(){var a,b,c;if(K.length&&_(),Z.render((j.time-Z._startTime)*Z._timeScale,!1,!1),Y.render((j.frame-Y._startTime)*Y._timeScale,!1,!1),K.length&&_(),j.frame>=$){$=j.frame+(parseInt(H.autoSleep,10)||120);for(c in U){for(b=U[c].tweens,a=b.length;--a>-1;)b[a]._gc&&b.splice(a,1);0===b.length&&delete U[c]}if(c=Z._first,(!c||c._paused)&&H.autoSleep&&!Y._first&&1===j._listeners.tick.length){for(;c&&c._paused;)c=c._next;c||j.sleep()}}},j.addEventListener("tick",E._updateRoot);var aa=function(a,b,c){var d,e,f=a._gsTweenID;if(U[f||(a._gsTweenID=f="t"+V++)]||(U[f]={target:a,tweens:[]}),b&&(d=U[f].tweens,d[e=d.length]=b,c))for(;--e>-1;)d[e]===b&&d.splice(e,1);return U[f].tweens},ba=function(a,b,c,d){var e,f,g=a.vars.onOverwrite;return g&&(e=g(a,b,c,d)),g=H.onOverwrite,g&&(f=g(a,b,c,d)),e!==!1&&f!==!1},ca=function(a,b,c,d,e){var f,g,h,i;if(1===d||d>=4){for(i=e.length,f=0;i>f;f++)if((h=e[f])!==b)h._gc||h._kill(null,a,b)&&(g=!0);else if(5===d)break;return g}var j,k=b._startTime+n,l=[],m=0,o=0===b._duration;for(f=e.length;--f>-1;)(h=e[f])===b||h._gc||h._paused||(h._timeline!==b._timeline?(j=j||da(b,0,o),0===da(h,j,o)&&(l[m++]=h)):h._startTime<=k&&h._startTime+h.totalDuration()/h._timeScale>k&&((o||!h._initted)&&k-h._startTime<=2*n||(l[m++]=h)));for(f=m;--f>-1;)if(h=l[f],i=h._firstPT,2===d&&h._kill(c,a,b)&&(g=!0),2!==d||!h._firstPT&&h._initted&&i){if(2!==d&&!ba(h,b))continue;h._enabled(!1,!1)&&(g=!0)}return g},da=function(a,b,c){for(var d=a._timeline,e=d._timeScale,f=a._startTime;d._timeline;){if(f+=d._startTime,e*=d._timeScale,d._paused)return-100;d=d._timeline}return f/=e,f>b?f-b:c&&f===b||!a._initted&&2*n>f-b?n:(f+=a.totalDuration()/a._timeScale/e)>b+n?0:f-b-n};i._init=function(){var a,b,c,d,e,f,g=this.vars,h=this._overwrittenProps,i=this._duration,j=!!g.immediateRender,k=g.ease,l=this._startAt;if(g.startAt){l&&(l.render(-1,!0),l.kill()),e={};for(d in g.startAt)e[d]=g.startAt[d];if(e.data="isStart",e.overwrite=!1,e.immediateRender=!0,e.lazy=j&&g.lazy!==!1,e.startAt=e.delay=null,e.onUpdate=g.onUpdate,e.onUpdateParams=g.onUpdateParams,e.onUpdateScope=g.onUpdateScope||g.callbackScope||this,this._startAt=H.to(this.target||{},0,e),j)if(this._time>0)this._startAt=null;else if(0!==i)return}else if(g.runBackwards&&0!==i)if(l)l.render(-1,!0),l.kill(),this._startAt=null;else{0!==this._time&&(j=!1),c={};for(d in g)W[d]&&"autoCSS"!==d||(c[d]=g[d]);if(c.overwrite=0,c.data="isFromStart",c.lazy=j&&g.lazy!==!1,c.immediateRender=j,this._startAt=H.to(this.target,0,c),j){if(0===this._time)return}else this._startAt._init(),this._startAt._enabled(!1),this.vars.immediateRender&&(this._startAt=null)}if(this._ease=k=k?k instanceof w?k:"function"==typeof k?new w(k,g.easeParams):x[k]||H.defaultEase:H.defaultEase,g.easeParams instanceof Array&&k.config&&(this._ease=k.config.apply(k,g.easeParams)),this._easeType=this._ease._type,this._easePower=this._ease._power,this._firstPT=null,this._targets)for(f=this._targets.length,a=0;f>a;a++)this._initProps(this._targets[a],this._propLookup[a]={},this._siblings[a],h?h[a]:null,a)&&(b=!0);else b=this._initProps(this.target,this._propLookup,this._siblings,h,0);if(b&&H._onPluginEvent("_onInitAllProps",this),h&&(this._firstPT||"function"!=typeof this.target&&this._enabled(!1,!1)),g.runBackwards)for(c=this._firstPT;c;)c.s+=c.c,c.c=-c.c,c=c._next;this._onUpdate=g.onUpdate,this._initted=!0},i._initProps=function(b,c,d,e,f){var g,h,i,j,k,l;if(null==b)return!1;L[b._gsTweenID]&&_(),this.vars.css||b.style&&b!==a&&b.nodeType&&T.css&&this.vars.autoCSS!==!1&&J(this.vars,b);for(g in this.vars)if(l=this.vars[g],W[g])l&&(l instanceof Array||l.push&&q(l))&&-1!==l.join("").indexOf("{self}")&&(this.vars[g]=l=this._swapSelfInParams(l,this));else if(T[g]&&(j=new T[g])._onInitTween(b,this.vars[g],this,f)){for(this._firstPT=k={_next:this._firstPT,t:j,p:"setRatio",s:0,c:1,f:1,n:g,pg:1,pr:j._priority,m:0},h=j._overwriteProps.length;--h>-1;)c[j._overwriteProps[h]]=this._firstPT;(j._priority||j._onInitAllProps)&&(i=!0),(j._onDisable||j._onEnable)&&(this._notifyPluginsOfEnabled=!0),k._next&&(k._next._prev=k)}else c[g]=R.call(this,b,g,"get",l,g,0,null,this.vars.stringFilter,f);return e&&this._kill(e,b)?this._initProps(b,c,d,e,f):this._overwrite>1&&this._firstPT&&d.length>1&&ca(b,this,c,this._overwrite,d)?(this._kill(c,b),this._initProps(b,c,d,e,f)):(this._firstPT&&(this.vars.lazy!==!1&&this._duration||this.vars.lazy&&!this._duration)&&(L[b._gsTweenID]=!0),i)},i.render=function(a,b,c){var d,e,f,g,h=this,i=h._time,j=h._duration,k=h._rawPrevTime;if(a>=j-n&&a>=0)h._totalTime=h._time=j,h.ratio=h._ease._calcEnd?h._ease.getRatio(1):1,h._reversed||(d=!0,e="onComplete",c=c||h._timeline.autoRemoveChildren),0===j&&(h._initted||!h.vars.lazy||c)&&(h._startTime===h._timeline._duration&&(a=0),(0>k||0>=a&&a>=-n||k===n&&"isPause"!==h.data)&&k!==a&&(c=!0,k>n&&(e="onReverseComplete")),h._rawPrevTime=g=!b||a||k===a?a:n);else if(n>a)h._totalTime=h._time=0,h.ratio=h._ease._calcEnd?h._ease.getRatio(0):0,(0!==i||0===j&&k>0)&&(e="onReverseComplete",d=h._reversed),a>-n?a=0:0>a&&(h._active=!1,0===j&&(h._initted||!h.vars.lazy||c)&&(k>=0&&(k!==n||"isPause"!==h.data)&&(c=!0),h._rawPrevTime=g=!b||a||k===a?a:n)),(!h._initted||h._startAt&&h._startAt.progress())&&(c=!0);else if(h._totalTime=h._time=a,h._easeType){var l=a/j,m=h._easeType,o=h._easePower;(1===m||3===m&&l>=.5)&&(l=1-l),3===m&&(l*=2),1===o?l*=l:2===o?l*=l*l:3===o?l*=l*l*l:4===o&&(l*=l*l*l*l),h.ratio=1===m?1-l:2===m?l:.5>a/j?l/2:1-l/2}else h.ratio=h._ease.getRatio(a/j);if(h._time!==i||c){if(!h._initted){if(h._init(),!h._initted||h._gc)return;if(!c&&h._firstPT&&(h.vars.lazy!==!1&&h._duration||h.vars.lazy&&!h._duration))return h._time=h._totalTime=i,h._rawPrevTime=k,K.push(h),void(h._lazy=[a,b]);h._time&&!d?h.ratio=h._ease.getRatio(h._time/j):d&&h._ease._calcEnd&&(h.ratio=h._ease.getRatio(0===h._time?0:1))}for(h._lazy!==!1&&(h._lazy=!1),h._active||!h._paused&&h._time!==i&&a>=0&&(h._active=!0),0===i&&(h._startAt&&(a>=0?h._startAt.render(a,!0,c):e||(e="_dummyGS")),h.vars.onStart&&(0!==h._time||0===j)&&(b||h._callback("onStart"))),f=h._firstPT;f;)f.f?f.t[f.p](f.c*h.ratio+f.s):f.t[f.p]=f.c*h.ratio+f.s,f=f._next;h._onUpdate&&(0>a&&h._startAt&&a!==-1e-4&&h._startAt.render(a,!0,c),b||(h._time!==i||d||c)&&h._callback("onUpdate")),e&&(!h._gc||c)&&(0>a&&h._startAt&&!h._onUpdate&&a!==-1e-4&&h._startAt.render(a,!0,c),d&&(h._timeline.autoRemoveChildren&&h._enabled(!1,!1),h._active=!1),!b&&h.vars[e]&&h._callback(e),0===j&&h._rawPrevTime===n&&g!==n&&(h._rawPrevTime=0))}},i._kill=function(a,b,c){if("all"===a&&(a=null),null==a&&(null==b||b===this.target))return this._lazy=!1,this._enabled(!1,!1);b="string"!=typeof b?b||this._targets||this.target:H.selector(b)||b;var d,e,f,g,h,i,j,k,l,m=c&&this._time&&c._startTime===this._startTime&&this._timeline===c._timeline,n=this._firstPT;if((q(b)||I(b))&&"number"!=typeof b[0])for(d=b.length;--d>-1;)this._kill(a,b[d],c)&&(i=!0);else{if(this._targets){for(d=this._targets.length;--d>-1;)if(b===this._targets[d]){h=this._propLookup[d]||{},this._overwrittenProps=this._overwrittenProps||[],e=this._overwrittenProps[d]=a?this._overwrittenProps[d]||{}:"all";break}}else{if(b!==this.target)return!1;h=this._propLookup,e=this._overwrittenProps=a?this._overwrittenProps||{}:"all"}if(h){if(j=a||h,k=a!==e&&"all"!==e&&a!==h&&("object"!=typeof a||!a._tempKill),c&&(H.onOverwrite||this.vars.onOverwrite)){for(f in j)h[f]&&(l||(l=[]),l.push(f));if((l||!a)&&!ba(this,c,b,l))return!1}for(f in j)(g=h[f])&&(m&&(g.f?g.t[g.p](g.s):g.t[g.p]=g.s,i=!0),g.pg&&g.t._kill(j)&&(i=!0),g.pg&&0!==g.t._overwriteProps.length||(g._prev?g._prev._next=g._next:g===this._firstPT&&(this._firstPT=g._next),g._next&&(g._next._prev=g._prev),g._next=g._prev=null),delete h[f]),k&&(e[f]=1);!this._firstPT&&this._initted&&n&&this._enabled(!1,!1)}}return i},i.invalidate=function(){this._notifyPluginsOfEnabled&&H._onPluginEvent("_onDisable",this);var a=this._time;return this._firstPT=this._overwrittenProps=this._startAt=this._onUpdate=null,this._notifyPluginsOfEnabled=this._active=this._lazy=!1,this._propLookup=this._targets?{}:[],E.prototype.invalidate.call(this),this.vars.immediateRender&&(this._time=-n,this.render(a,!1,this.vars.lazy!==!1)),this},i._enabled=function(a,b){if(k||j.wake(),a&&this._gc){var c,d=this._targets;if(d)for(c=d.length;--c>-1;)this._siblings[c]=aa(d[c],this,!0);else this._siblings=aa(this.target,this,!0)}return E.prototype._enabled.call(this,a,b),this._notifyPluginsOfEnabled&&this._firstPT?H._onPluginEvent(a?"_onEnable":"_onDisable",this):!1},H.to=function(a,b,c){return new H(a,b,c)},H.from=function(a,b,c){return c.runBackwards=!0,c.immediateRender=0!=c.immediateRender,new H(a,b,c)},H.fromTo=function(a,b,c,d){return d.startAt=c,d.immediateRender=0!=d.immediateRender&&0!=c.immediateRender,new H(a,b,d)},H.delayedCall=function(a,b,c,d,e){return new H(b,0,{delay:a,onComplete:b,onCompleteParams:c,callbackScope:d,onReverseComplete:b,onReverseCompleteParams:c,immediateRender:!1,lazy:!1,useFrames:e,overwrite:0})},H.set=function(a,b){return new H(a,0,b)},H.getTweensOf=function(a,b){if(null==a)return[];a="string"!=typeof a?a:H.selector(a)||a;var c,d,e,f;if((q(a)||I(a))&&"number"!=typeof a[0]){for(c=a.length,d=[];--c>-1;)d=d.concat(H.getTweensOf(a[c],b));for(c=d.length;--c>-1;)for(f=d[c],e=c;--e>-1;)f===d[e]&&d.splice(c,1)}else if(a._gsTweenID)for(d=aa(a).concat(),c=d.length;--c>-1;)(d[c]._gc||b&&!d[c].isActive())&&d.splice(c,1);return d||[]},H.killTweensOf=H.killDelayedCallsTo=function(a,b,c){"object"==typeof b&&(c=b,b=!1);for(var d=H.getTweensOf(a,b),e=d.length;--e>-1;)d[e]._kill(c,a)};var ea=u("plugins.TweenPlugin",function(a,b){this._overwriteProps=(a||"").split(","),this._propName=this._overwriteProps[0],this._priority=b||0,this._super=ea.prototype},!0);if(i=ea.prototype,ea.version="1.19.0",ea.API=2,i._firstPT=null,i._addTween=R,i.setRatio=O,i._kill=function(a){var b,c=this._overwriteProps,d=this._firstPT;if(null!=a[this._propName])this._overwriteProps=[];else for(b=c.length;--b>-1;)null!=a[c[b]]&&c.splice(b,1);for(;d;)null!=a[d.n]&&(d._next&&(d._next._prev=d._prev),d._prev?(d._prev._next=d._next,d._prev=null):this._firstPT===d&&(this._firstPT=d._next)),d=d._next;return!1},i._mod=i._roundProps=function(a){for(var b,c=this._firstPT;c;)b=a[this._propName]||null!=c.n&&a[c.n.split(this._propName+"_").join("")],b&&"function"==typeof b&&(2===c.f?c.t._applyPT.m=b:c.m=b),c=c._next},H._onPluginEvent=function(a,b){var c,d,e,f,g,h=b._firstPT;if("_onInitAllProps"===a){for(;h;){for(g=h._next,d=e;d&&d.pr>h.pr;)d=d._next;(h._prev=d?d._prev:f)?h._prev._next=h:e=h,(h._next=d)?d._prev=h:f=h,h=g}h=b._firstPT=e}for(;h;)h.pg&&"function"==typeof h.t[a]&&h.t[a]()&&(c=!0),h=h._next;return c},ea.activate=function(a){for(var b=a.length;--b>-1;)a[b].API===ea.API&&(T[(new a[b])._propName]=a[b]);return!0},t.plugin=function(a){if(!(a&&a.propName&&a.init&&a.API))throw"illegal plugin definition.";var b,c=a.propName,d=a.priority||0,e=a.overwriteProps,f={init:"_onInitTween",set:"setRatio",kill:"_kill",round:"_mod",mod:"_mod",initAll:"_onInitAllProps"},g=u("plugins."+c.charAt(0).toUpperCase()+c.substr(1)+"Plugin",function(){ea.call(this,c,d),this._overwriteProps=e||[]},a.global===!0),h=g.prototype=new ea(c);h.constructor=g,g.API=a.API;for(b in f)"function"==typeof a[b]&&(h[f[b]]=a[b]);return g.version=a.version,ea.activate([g]),g},g=a._gsQueue){for(h=0;h 0. Should not exceed outer radius. + numSegments: 1, // The number of segments. Need at least one to draw. + drawMode: 'code', // The draw mode. Possible values are 'code', 'image', 'segmentImage'. Default is code which means segments are drawn using canvas arc() function. + rotationAngle: 0, // The angle of rotation of the wheel - 0 is 12 o'clock position. + textFontFamily: 'sans-serif', // Segment text font, you should use web safe fonts. + textFontSize: 13, // Size of the segment text. + textFontWeight: 'bold', // Font weight. + textOrientation: 'horizontal', // Either horizontal, vertical, or curved. + textAlignment: 'center', // Either center, inner, or outer. + textDirection: 'normal', // Either normal or reversed. In normal mode for horizontal text in segment at 3 o'clock is correct way up, in reversed text at 9 o'clock segment is correct way up. + textMargin: null, // Margin between the inner or outer of the wheel (depends on textAlignment). + textFillStyle: 'black', // This is basically the text colour. + textStrokeStyle: null, // Basically the line colour for segment text, only looks good for large text so off by default. + textLineWidth: 1, // Width of the lines around the text. Even though this defaults to 1, a line is only drawn if textStrokeStyle specified. + fillStyle: 'silver', // The segment background colour. + strokeStyle: null, // Segment line colour. Again segment lines only drawn if this is specified. + lineWidth: 1, // Width of lines around segments. + clearTheCanvas: true, // When set to true the canvas will be cleared before the wheel is drawn. + imageOverlay: false, // If set to true in image drawing mode the outline of the segments will be displayed over the image. Does nothing in code drawMode. + drawText: true, // By default the text of the segments is rendered in code drawMode and not in image drawMode. + pointerAngle: 0, // Location of the pointer that indicates the prize when wheel has stopped. Default is 0 so the (corrected) 12 o'clock position. + wheelImage: null, // Must be set to image data in order to use image to draw the wheel - drawMode must also be 'image'. + imageDirection: 'N', // Used when drawMode is segmentImage. Default is north, can also be (E)ast, (S)outh, (W)est. + } + + // ----------------------------------------- + // Loop through the default options and create properties of this class set to the value for the option passed in + // or if not value for the option was passed in then to the default. + for (var key in defaultOptions) { + if (options != null && typeof options[key] !== 'undefined') { + this[key] = options[key] + } else { + this[key] = defaultOptions[key] + } + } + + // Also loop though the passed in options and add anything specified not part of the class in to it as a property. + if (options != null) { + for (var key in options) { + if (typeof this[key] === 'undefined') { + this[key] = options[key] + } + } + } + + // ------------------------------------------ + // If the id of the canvas is set, try to get the canvas as we need it for drawing. + if (this.canvasId) { + this.canvas = document.getElementById(this.canvasId) + + if (this.canvas) { + // If the centerX and centerY have not been specified in the options then default to center of the canvas + // and make the outerRadius half of the canvas width - this means the wheel will fill the canvas. + if (this.centerX == null) { + this.centerX = this.canvas.width / 2 + } + + if (this.centerY == null) { + this.centerY = this.canvas.height / 2 + } + + if (this.outerRadius == null) { + // Need to set to half the width of the shortest dimension of the canvas as the canvas may not be square. + // Minus the line segment line width otherwise the lines around the segments on the top,left,bottom,right + // side are chopped by the edge of the canvas. + if (this.canvas.width < this.canvas.height) { + this.outerRadius = this.canvas.width / 2 - this.lineWidth + } else { + this.outerRadius = this.canvas.height / 2 - this.lineWidth + } + } + + // Also get a 2D context to the canvas as we need this to draw with. + this.ctx = this.canvas.getContext('2d') + } else { + this.canvas = null + this.ctx = null + } + } else { + this.cavnas = null + this.ctx = null + } + + // ------------------------------------------ + // Add array of segments to the wheel, then populate with segments if number of segments is specified for this object. + this.segments = new Array(null) + + for (var x = 1; x <= this.numSegments; x++) { + // If options for the segments have been specified then create a segment sending these options so + // the specified values are used instead of the defaults. + if (options != null && options['segments'] && typeof options['segments'][x - 1] !== 'undefined') { + this.segments[x] = new Segment(options['segments'][x - 1]) + } else { + this.segments[x] = new Segment() + } + } + + // ------------------------------------------ + // Call function to update the segment sizes setting the starting and ending angles. + this.updateSegmentSizes() + + // If the text margin is null then set to same as font size as we want some by default. + if (this.textMargin === null) { + this.textMargin = this.textFontSize / 1.7 + } + + // ------------------------------------------ + // If the animation options have been passed in then create animation object as a property of this class + // and pass the options to it so the animation is set. Otherwise create default animation object. + if (options != null && options['animation'] && typeof options['animation'] !== 'undefined') { + this.animation = new Animation(options['animation']) + } else { + this.animation = new Animation() + } + + // ------------------------------------------ + // If some pin options then create create a pin object and then pass them in. + if (options != null && options['pins'] && typeof options['pins'] !== 'undefined') { + this.pins = new Pin(options['pins']) + } + + // ------------------------------------------ + // On that note, if the drawMode is image change some defaults provided a value has not been specified. + if (this.drawMode == 'image' || this.drawMode == 'segmentImage') { + // Remove grey fillStyle. + if (typeof options['fillStyle'] === 'undefined') { + this.fillStyle = null + } + + // Set strokeStyle to red. + if (typeof options['strokeStyle'] === 'undefined') { + this.strokeStyle = 'red' + } + + // Set drawText to false as we will assume any text is part of the image. + if (typeof options['drawText'] === 'undefined') { + this.drawText = false + } + + // Also set the lineWidth to 1 so that segment overlay will look correct. + if (typeof options['lineWidth'] === 'undefined') { + this.lineWidth = 1 + } + + // Set drawWheel to false as normally the image needs to be loaded first. + if (typeof drawWheel === 'undefined') { + drawWheel = false + } + } else { + // When in code drawMode the default is the wheel will draw. + if (typeof drawWheel === 'undefined') { + drawWheel = true + } + } + + // Create pointer guide. + if (options != null && options['pointerGuide'] && typeof options['pointerGuide'] !== 'undefined') { + this.pointerGuide = new PointerGuide(options['pointerGuide']) + } else { + this.pointerGuide = new PointerGuide() + } + + // Finally if drawWheel is true then call function to render the wheel, segment text, overlay etc. + if (drawWheel == true) { + this.draw(this.clearTheCanvas) + } else if (this.drawMode == 'segmentImage') { + // If segment image then loop though all the segments and load the images for them setting a callback + // which will call the draw function of the wheel once all the images have been loaded. + winwheelToDrawDuringAnimation = this + winhweelAlreadyDrawn = false + + for (var y = 1; y <= this.numSegments; y++) { + if (this.segments[y].image !== null) { + this.segments[y].imgData = new Image() + this.segments[y].imgData.onload = winwheelLoadedImage + this.segments[y].imgData.src = this.segments[y].image + } + } + } + } + + // ==================================================================================================================== + // This function sorts out the segment sizes. Some segments may have set sizes, for the others what is left out of + // 360 degrees is shared evenly. What this function actually does is set the start and end angle of the arcs. + // ==================================================================================================================== + updateSegmentSizes() { + // If this object actually contains some segments + if (this.segments) { + // First add up the arc used for the segments where the size has been set. + var arcUsed = 0 + var numSet = 0 + + // Remember, to make it easy to access segments, the position of the segments in the array starts from 1 (not 0). + for (var x = 1; x <= this.numSegments; x++) { + if (this.segments[x].size !== null) { + arcUsed += this.segments[x].size + numSet++ + } + } + + var arcLeft = 360 - arcUsed + + // Create variable to hold how much each segment with non-set size will get in terms of degrees. + var degreesEach = 0 + + if (arcLeft > 0) { + degreesEach = arcLeft / (this.numSegments - numSet) + } + + // ------------------------------------------ + // Now loop though and set the start and end angle of each segment. + var currentDegree = 0 + + for (var x = 1; x <= this.numSegments; x++) { + // Set start angle. + this.segments[x].startAngle = currentDegree + + // If the size is set then add this to the current degree to get the end, else add the degreesEach to it. + if (this.segments[x].size) { + currentDegree += this.segments[x].size + } else { + currentDegree += degreesEach + } + + // Set end angle. + this.segments[x].endAngle = currentDegree + } + } + } + + // ==================================================================================================================== + // This function clears the canvas. Will wipe anything else which happens to be drawn on it. + // ==================================================================================================================== + clearCanvas() { + if (this.ctx) { + this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height) + } + } + + // ==================================================================================================================== + // This function draws / re-draws the wheel on the canvas therefore rendering any changes. + // ==================================================================================================================== + draw(clearTheCanvas) { + // If have the canvas context. + if (this.ctx) { + // Clear the canvas, unless told not to. + if (typeof clearTheCanvas !== 'undefined') { + if (clearTheCanvas == true) { + this.clearCanvas() + } + } else { + this.clearCanvas() + } + + // Call functions to draw the segments and then segment text. + if (this.drawMode == 'image') { + // Draw the wheel by loading and drawing an image such as a png on the canvas. + this.drawWheelImage() + + // If we are to draw the text, do so before the overlay is drawn + // as this allows the overlay to be used to create some interesting effects. + if (this.drawText == true) { + this.drawSegmentText() + } + + // If image overlay is true then call function to draw the segments over the top of the image. + // This is useful during development to check alignment between where the code thinks the segments are and where they appear on the image. + if (this.imageOverlay == true) { + this.drawSegments() + } + } else if (this.drawMode == 'segmentImage') { + // Draw the wheel by rendering the image for each segment. + this.drawSegmentImages() + + // If we are to draw the text, do so before the overlay is drawn + // as this allows the overlay to be used to create some interesting effects. + if (this.drawText == true) { + this.drawSegmentText() + } + + // If image overlay is true then call function to draw the segments over the top of the image. + // This is useful during development to check alignment between where the code thinks the segments are and where they appear on the image. + if (this.imageOverlay == true) { + this.drawSegments() + } + } else { + // The default operation is to draw the segments using code via the canvas arc() method. + this.drawSegments() + + // The text is drawn on top. + if (this.drawText == true) { + this.drawSegmentText() + } + } + + // If this class has pins. + if (typeof this.pins !== 'undefined') { + // If they are to be visible then draw them. + if (this.pins.visible == true) this.drawPins() + } + + // If pointer guide is display property is set to true then call function to draw the pointer guide. + if (this.pointerGuide.display == true) { + this.drawPointerGuide() + } + } + } + + // ==================================================================================================================== + // Draws the pins around the outside of the wheel. + // ==================================================================================================================== + drawPins() { + if (this.pins && this.pins.number) { + // Work out the angle to draw each pin a which is simply 360 / the number of pins as they space evenly around. + //++ There is a slight oddity with the pins in that there is a pin at 0 and also one at 360 and these will be drawn + //++ directly over the top of each other. Also pins are 0 indexed which could possibly cause some confusion + //++ with the getCurrentPin function - for now this is just used for audio so probably not a problem. + var pinSpacing = 360 / this.pins.number + + for (var i = 1; i <= this.pins.number; i++) { + this.ctx.save() + + // Set the stroke style and line width. + this.ctx.strokeStyle = this.pins.strokeStyle + this.ctx.lineWidth = this.pins.lineWidth + this.ctx.fillStyle = this.pins.fillStyle + + // Move to the center. + this.ctx.translate(this.centerX, this.centerY) + + // Rotate to to the pin location which is i * the pinSpacing. + this.ctx.rotate(this.degToRad(i * pinSpacing + this.rotationAngle)) + + // Move back out. + this.ctx.translate(-this.centerX, -this.centerY) + + // Create a path for the pin circle. + this.ctx.beginPath() + // x, y, radius, startAngle, endAngle. + this.ctx.arc( + this.centerX, + this.centerY - this.outerRadius + this.pins.outerRadius + this.pins.margin, + this.pins.outerRadius, + 0, + 2 * Math.PI + ) + + if (this.pins.fillStyle) this.ctx.fill() + + if (this.pins.strokeStyle) this.ctx.stroke() + + this.ctx.restore() + } + } + } + + // ==================================================================================================================== + // Draws a line from the center of the wheel to the outside at the angle where the code thinks the pointer is. + // ==================================================================================================================== + drawPointerGuide() { + // If have canvas context. + if (this.ctx) { + this.ctx.save() + + // Rotate the canvas to the line goes towards the location of the pointer. + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(this.pointerAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + // Set line colour and width. + this.ctx.strokeStyle = this.pointerGuide.strokeStyle + this.ctx.lineWidth = this.pointerGuide.lineWidth + + // Draw from the center of the wheel outwards past the wheel outer radius. + this.ctx.beginPath() + this.ctx.moveTo(this.centerX, this.centerY) + this.ctx.lineTo(this.centerX, -(this.outerRadius / 4)) + + this.ctx.stroke() + this.ctx.restore() + } + } + + // ==================================================================================================================== + // This function takes an image such as PNG and draws it on the canvas making its center at the centerX and center for the wheel. + // ==================================================================================================================== + drawWheelImage() { + // Double check the wheelImage property of this class is not null. This does not actually detect that an image + // source was set and actually loaded so might get error if this is not the case. This is why the initial call + // to draw() should be done from a wheelImage.onload callback as detailed in example documentation. + if (this.wheelImage != null) { + // Work out the correct X and Y to draw the image at. We need to get the center point of the image + // aligned over the center point of the wheel, we can't just place it at 0, 0. + var imageLeft = this.centerX - this.wheelImage.height / 2 + var imageTop = this.centerY - this.wheelImage.width / 2 + + // Rotate and then draw the wheel. + // We must rotate by the rotationAngle before drawing to ensure that image wheels will spin. + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(this.rotationAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + this.ctx.drawImage(this.wheelImage, imageLeft, imageTop) + + this.ctx.restore() + } + } + + // ==================================================================================================================== + // This function draws the wheel on the canvas by rendering the image for each segment. + // ==================================================================================================================== + drawSegmentImages() { + // Again check have context in case this function was called directly and not via draw function. + if (this.ctx) { + // Draw the segments if there is at least one in the segments array. + if (this.segments) { + // Loop though and output all segments - position 0 of the array is not used, so start loop from index 1 + // this is to avoid confusion when talking about the first segment. + for (var x = 1; x <= this.numSegments; x++) { + // Get the segment object as we need it to read options from. + var seg = this.segments[x] + + // Check image has loaded so a property such as height has a value. + if (seg.imgData.height) { + // Work out the correct X and Y to draw the image at which depends on the direction of the image. + // Images can be created in 4 directions. North, South, East, West. + // North: Outside at top, inside at bottom. Sits evenly over the 0 degrees angle. + // South: Outside at bottom, inside at top. Sits evenly over the 180 degrees angle. + // East: Outside at right, inside at left. Sits evenly over the 90 degrees angle. + // West: Outside at left, inside at right. Sits evenly over the 270 degrees angle. + var imageLeft = 0 + var imageTop = 0 + var imageAngle = 0 + var imageDirection = '' + + if (seg.imageDirection !== null) imageDirection = seg.imageDirection + else imageDirection = this.imageDirection + + if (imageDirection == 'S') { + // Left set so image sits half/half over the 180 degrees point. + imageLeft = this.centerX - seg.imgData.width / 2 + + // Top so image starts at the centerY. + imageTop = this.centerY + + // Angle to draw the image is its starting angle + half its size. + // Here we add 180 to the angle to the segment is poistioned correctly. + imageAngle = seg.startAngle + 180 + (seg.endAngle - seg.startAngle) / 2 + } else if (imageDirection == 'E') { + // Left set so image starts and the center point. + imageLeft = this.centerX + + // Top is so that it sits half/half over the 90 degree point. + imageTop = this.centerY - seg.imgData.height / 2 + + // Again get the angle in the center of the segment and add it to the rotation angle. + // this time we need to add 270 to that to the segment is rendered the correct place. + imageAngle = seg.startAngle + 270 + (seg.endAngle - seg.startAngle) / 2 + } else if (imageDirection == 'W') { + // Left is the centerX minus the width of the image. + imageLeft = this.centerX - seg.imgData.width + + // Top is so that it sits half/half over the 270 degree point. + imageTop = this.centerY - seg.imgData.height / 2 + + // Again get the angle in the center of the segment and add it to the rotation angle. + // this time we need to add 90 to that to the segment is rendered the correct place. + imageAngle = seg.startAngle + 90 + (seg.endAngle - seg.startAngle) / 2 + } // North is the default. + else { + // Left set so image sits half/half over the 0 degrees point. + imageLeft = this.centerX - seg.imgData.width / 2 + + // Top so image is its height out (above) the center point. + imageTop = this.centerY - seg.imgData.height + + // Angle to draw the image is its starting angle + half its size. + // this sits it half/half over the center angle of the segment. + imageAngle = seg.startAngle + (seg.endAngle - seg.startAngle) / 2 + } + + // -------------------------------------------------- + // Rotate to the position of the segment and then draw the image. + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + + // So math here is the rotation angle of the wheel plus half way between the start and end angle of the segment. + this.ctx.rotate(this.degToRad(this.rotationAngle + imageAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + // Draw the image. + this.ctx.drawImage(seg.imgData, imageLeft, imageTop) + + this.ctx.restore() + } else { + console.log('Segment ' + x + ' imgData is not loaded') + } + } + } + } + } + + // ==================================================================================================================== + // This function draws the wheel on the page by rendering the segments on the canvas. + // ==================================================================================================================== + drawSegments() { + // Again check have context in case this function was called directly and not via draw function. + if (this.ctx) { + // Draw the segments if there is at least one in the segments array. + if (this.segments) { + // Loop though and output all segments - position 0 of the array is not used, so start loop from index 1 + // this is to avoid confusion when talking about the first segment. + for (var x = 1; x <= this.numSegments; x++) { + // Get the segment object as we need it to read options from. + var seg = this.segments[x] + + var fillStyle + var lineWidth + var strokeStyle + + // Set the variables that defined in the segment, or use the default options. + if (seg.fillStyle !== null) fillStyle = seg.fillStyle + else fillStyle = this.fillStyle + + this.ctx.fillStyle = fillStyle + + if (seg.lineWidth !== null) lineWidth = seg.lineWidth + else lineWidth = this.lineWidth + + this.ctx.lineWidth = lineWidth + + if (seg.strokeStyle !== null) strokeStyle = seg.strokeStyle + else strokeStyle = this.strokeStyle + + this.ctx.strokeStyle = strokeStyle + + // Check there is a strokeStyle or fillStyle, if either the the segment is invisible so should not + // try to draw it otherwise a path is began but not ended. + if (strokeStyle || fillStyle) { + // ---------------------------------- + // Begin a path as the segment consists of an arc and 2 lines. + this.ctx.beginPath() + + // If don't have an inner radius then move to the center of the wheel as we want a line out from the center + // to the start of the arc for the outside of the wheel when we arc. Canvas will draw the connecting line for us. + if (!this.innerRadius) { + this.ctx.moveTo(this.centerX, this.centerY) + } else { + //++ do need to draw the starting line in the correct x + y based on the start angle + //++ otherwise as seen when the wheel does not use up 360 the starting segment is missing the stroked side, + } + + // Draw the outer arc of the segment clockwise in direction --> + this.ctx.arc( + this.centerX, + this.centerY, + this.outerRadius, + this.degToRad(seg.startAngle + this.rotationAngle - 90), + this.degToRad(seg.endAngle + this.rotationAngle - 90), + false + ) + + if (this.innerRadius) { + // Draw another arc, this time anticlockwise <-- at the innerRadius between the end angle and the start angle. + // Canvas will draw a connecting line from the end of the outer arc to the beginning of the inner arc completing the shape. + + //++ Think the reason the lines are thinner for 2 of the segments is because the thing auto chops part of it + //++ when doing the next one. Again think that actually drawing the lines will help. + + this.ctx.arc( + this.centerX, + this.centerY, + this.innerRadius, + this.degToRad(seg.endAngle + this.rotationAngle - 90), + this.degToRad(seg.startAngle + this.rotationAngle - 90), + true + ) + } else { + // If no inner radius then we draw a line back to the center of the wheel. + this.ctx.lineTo(this.centerX, this.centerY) + } + + // Fill and stroke the segment. Only do either if a style was specified, if the style is null then + // we assume the developer did not want that particular thing. + // For example no stroke style so no lines to be drawn. + if (fillStyle) this.ctx.fill() + + if (strokeStyle) this.ctx.stroke() + } + } + } + } + } + + // ==================================================================================================================== + // This draws the text on the segments using the specified text options. + // ==================================================================================================================== + drawSegmentText() { + // Again only draw the text if have a canvas context. + if (this.ctx) { + // Declare variables to hold the values. These are populated either with the value for the specific segment, + // or if not specified then the global default value. + var fontFamily + var fontSize + var fontWeight + var orientation + var alignment + var direction + var margin + var fillStyle + var strokeStyle + var lineWidth + var fontSetting + + // Loop though all the segments. + for (var x = 1; x <= this.numSegments; x++) { + // Save the context so it is certain that each segment text option will not affect the other. + this.ctx.save() + + // Get the segment object as we need it to read options from. + var seg = this.segments[x] + + // Check is text as no point trying to draw if there is no text to render. + if (seg.text) { + // Set values to those for the specific segment or use global default if null. + if (seg.textFontFamily !== null) fontFamily = seg.textFontFamily + else fontFamily = this.textFontFamily + if (seg.textFontSize !== null) fontSize = seg.textFontSize + else fontSize = this.textFontSize + if (seg.textFontWeight !== null) fontWeight = seg.textFontWeight + else fontWeight = this.textFontWeight + if (seg.textOrientation !== null) orientation = seg.textOrientation + else orientation = this.textOrientation + if (seg.textAlignment !== null) alignment = seg.textAlignment + else alignment = this.textAlignment + if (seg.textDirection !== null) direction = seg.textDirection + else direction = this.textDirection + if (seg.textMargin !== null) margin = seg.textMargin + else margin = this.textMargin + if (seg.textFillStyle !== null) fillStyle = seg.textFillStyle + else fillStyle = this.textFillStyle + if (seg.textStrokeStyle !== null) strokeStyle = seg.textStrokeStyle + else strokeStyle = this.textStrokeStyle + if (seg.textLineWidth !== null) lineWidth = seg.textLineWidth + else lineWidth = this.textLineWidth + + // ------------------------------ + // We need to put the font bits together in to one string. + fontSetting = '' + + if (fontWeight != null) fontSetting += fontWeight + ' ' + + if (fontSize != null) fontSetting += fontSize + 'px ' // Fonts on canvas are always a px value. + + if (fontFamily != null) fontSetting += fontFamily + + // Now set the canvas context to the decided values. + this.ctx.font = fontSetting + this.ctx.fillStyle = fillStyle + this.ctx.strokeStyle = strokeStyle + this.ctx.lineWidth = lineWidth + + // Split the text in to multiple lines on the \n character. + var lines = seg.text.split('\n') + + // Figure out the starting offset for the lines as when there are multiple lines need to center the text + // vertically in the segment (when thinking of normal horozontal text). + var lineOffset = 0 - fontSize * (lines.length / 2) + fontSize / 2 + + // The offset works great for horozontal and vertial text, also centered curved. But when the text is curved + // and the alignment is outer then the multiline text should not have some text outside the wheel. Same if inner curved. + if (orientation == 'curved' && (alignment == 'inner' || alignment == 'outer')) { + lineOffset = 0 + } + + for (var i = 0; i < lines.length; i++) { + // --------------------------------- + // If direction is reversed then do things differently than if normal (which is the default - see further down) + if (direction == 'reversed') { + // When drawing reversed or 'upside down' we need to do some trickery on our part. + // The canvas text rendering function still draws the text left to right and the correct way up, + // so we need to overcome this with rotating the opposite side of the wheel the correct way up then pulling the text + // through the center point to the correct segment it is supposed to be on. + if (orientation == 'horizontal') { + if (alignment == 'inner') this.ctx.textAlign = 'right' + else if (alignment == 'outer') this.ctx.textAlign = 'left' + else this.ctx.textAlign = 'center' + + this.ctx.textBaseline = 'middle' + + // Work out the angle to rotate the wheel, this is in the center of the segment but on the opposite side of the wheel which is why do -180. + var textAngle = this.degToRad( + seg.endAngle - (seg.endAngle - seg.startAngle) / 2 + this.rotationAngle - 90 - 180 + ) + + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(textAngle) + this.ctx.translate(-this.centerX, -this.centerY) + + if (alignment == 'inner') { + // In reversed state the margin is subtracted from the innerX. + // When inner the inner radius also comes in to play. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX - this.innerRadius - margin, + this.centerY + lineOffset + ) + + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX - this.innerRadius - margin, + this.centerY + lineOffset + ) + } else if (alignment == 'outer') { + // In reversed state the position is the center minus the radius + the margin for outer aligned text. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX - this.outerRadius + margin, + this.centerY + lineOffset + ) + + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX - this.outerRadius + margin, + this.centerY + lineOffset + ) + } else { + // In reversed state the everything in minused. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX - + this.innerRadius - + (this.outerRadius - this.innerRadius) / 2 - + margin, + this.centerY + lineOffset + ) + + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX - + this.innerRadius - + (this.outerRadius - this.innerRadius) / 2 - + margin, + this.centerY + lineOffset + ) + } + + this.ctx.restore() + } else if (orientation == 'vertical') { + // See normal code further down for comments on how it works, this is similar by plus/minus is reversed. + this.ctx.textAlign = 'center' + + // In reversed mode this are reversed. + if (alignment == 'inner') this.ctx.textBaseline = 'top' + else if (alignment == 'outer') this.ctx.textBaseline = 'bottom' + else this.ctx.textBaseline = 'middle' + + var textAngle = seg.endAngle - (seg.endAngle - seg.startAngle) / 2 - 180 + textAngle += this.rotationAngle + + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(textAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + if (alignment == 'outer') var yPos = this.centerY + this.outerRadius - margin + else if (alignment == 'inner') var yPos = this.centerY + this.innerRadius + margin + + // I have found that the text looks best when a fraction of the font size is shaved off. + var yInc = fontSize - fontSize / 9 + + // Loop though and output the characters. + if (alignment == 'outer') { + // In reversed mode outer means text in 6 o'clock segment sits at bottom of the wheel and we draw up. + for (var c = lines[i].length - 1; c >= 0; c--) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos -= yInc + } + } else if (alignment == 'inner') { + // In reversed mode inner text is drawn from top of segment at 6 o'clock position to bottom of the wheel. + for (var c = 0; c < lines[i].length; c++) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos += yInc + } + } else if (alignment == 'center') { + // Again for reversed this is the opposite of before. + // If there is more than one character in the text then an adjustment to the position needs to be done. + // What we are aiming for is to position the center of the text at the center point between the inner and outer radius. + var centerAdjustment = 0 + + if (lines[i].length > 1) { + centerAdjustment = (yInc * (lines[i].length - 1)) / 2 + } + + var yPos = + this.centerY + + this.innerRadius + + (this.outerRadius - this.innerRadius) / 2 + + centerAdjustment + + margin + + for (var c = lines[i].length - 1; c >= 0; c--) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos -= yInc + } + } + + this.ctx.restore() + } else if (orientation == 'curved') { + // There is no built in canvas function to draw text around an arc, + // so we need to do this ourselves. + var radius = 0 + + // Set the alignment of the text - inner, outer, or center by calculating + // how far out from the center point of the wheel the text is drawn. + if (alignment == 'inner') { + // When alignment is inner the radius is the innerRadius plus any margin. + radius = this.innerRadius + margin + this.ctx.textBaseline = 'top' + } else if (alignment == 'outer') { + // Outer it is the outerRadius minus any margin. + radius = this.outerRadius - margin + this.ctx.textBaseline = 'bottom' + + // We need to adjust the radius in this case to take in to multiline text. + // In this case the radius needs to be further out, not at the inner radius. + radius -= fontSize * (lines.length - 1) + } else if (alignment == 'center') { + // When center we want the text halfway between the inner and outer radius. + radius = this.innerRadius + margin + (this.outerRadius - this.innerRadius) / 2 + this.ctx.textBaseline = 'middle' + } + + // Set the angle to increment by when looping though and outputting the characters in the text + // as we do this by rotating the wheel small amounts adding each character. + var anglePerChar = 0 + var drawAngle = 0 + + // If more than one character in the text then... + if (lines[i].length > 1) { + // Text is drawn from the left. + this.ctx.textAlign = 'left' + + // Work out how much angle the text rendering loop below needs to rotate by for each character to render them next to each other. + // I have discovered that 4 * the font size / 10 at 100px radius is the correct spacing for between the characters + // using a monospace font, non monospace may look a little odd as in there will appear to be extra spaces between chars. + anglePerChar = 4 * (fontSize / 10) + + // Work out what percentage the radius the text will be drawn at is of 100px. + radiusPercent = 100 / radius + + // Then use this to scale up or down the anglePerChar value. + // When the radius is less than 100px we need more angle between the letters, when radius is greater (so the text is further + // away from the center of the wheel) the angle needs to be less otherwise the characters will appear further apart. + anglePerChar = anglePerChar * radiusPercent + + // Next we want the text to be drawn in the middle of the segment, without this it would start at the beginning of the segment. + // To do this we need to work out how much arc the text will take up in total then subtract half of this from the center + // of the segment so that it sits centred. + totalArc = anglePerChar * lines[i].length + + // Now set initial draw angle to half way between the start and end of the segment. + drawAngle = seg.startAngle + ((seg.endAngle - seg.startAngle) / 2 - totalArc / 2) + } else { + // The initial draw angle is the center of the segment when only one character. + drawAngle = seg.startAngle + (seg.endAngle - seg.startAngle) / 2 + + // To ensure is dead-center the text alignment also needs to be centered. + this.ctx.textAlign = 'center' + } + + // ---------------------- + // Adjust the initial draw angle as needed to take in to account the rotationAngle of the wheel. + drawAngle += this.rotationAngle + + // And as with other 'reverse' text direction functions we need to subtract 180 degrees from the angle + // because when it comes to draw the characters in the loop below we add the radius instead of subtract it. + drawAngle -= 180 + + // ---------------------- + // Now the drawing itself. + // In reversed direction mode we loop through the characters in the text backwards in order for them to appear on screen correctly + for (c = lines[i].length; c >= 0; c--) { + this.ctx.save() + + character = lines[i].charAt(c) + + // Rotate the wheel to the draw angle as we need to add the character at this location. + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(drawAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + // Now draw the character directly below the center point of the wheel at the appropriate radius. + // Note in the reversed mode we add the radius to the this.centerY instead of subtract. + if (strokeStyle) + this.ctx.strokeText(character, this.centerX, this.centerY + radius + lineOffset) + + if (fillStyle) + this.ctx.fillText(character, this.centerX, this.centerY + radius + lineOffset) + + // Increment the drawAngle by the angle per character so next loop we rotate + // to the next angle required to draw the character at. + drawAngle += anglePerChar + + this.ctx.restore() + } + } + } else { + // Normal direction so do things normally. + // Check text orientation, of horizontal then reasonably straight forward, if vertical then a bit more work to do. + if (orientation == 'horizontal') { + // Based on the text alignment, set the correct value in the context. + if (alignment == 'inner') this.ctx.textAlign = 'left' + else if (alignment == 'outer') this.ctx.textAlign = 'right' + else this.ctx.textAlign = 'center' + + // Set this too. + this.ctx.textBaseline = 'middle' + + // Work out the angle around the wheel to draw the text at, which is simply in the middle of the segment the text is for. + // The rotation angle is added in to correct the annoyance with the canvas arc drawing functions which put the 0 degrees at the 3 oclock + var textAngle = this.degToRad( + seg.endAngle - (seg.endAngle - seg.startAngle) / 2 + this.rotationAngle - 90 + ) + + // We need to rotate in order to draw the text because it is output horizontally, so to + // place correctly around the wheel for all but a segment at 3 o'clock we need to rotate. + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(textAngle) + this.ctx.translate(-this.centerX, -this.centerY) + + // -------------------------- + // Draw the text based on its alignment adding margin if inner or outer. + if (alignment == 'inner') { + // Inner means that the text is aligned with the inner of the wheel. If looking at a segment in in the 3 o'clock position + // it would look like the text is left aligned within the segment. + + // Because the segments are smaller towards the inner of the wheel, in order for the text to fit is is a good idea that + // a margin is added which pushes the text towards the outer a bit. + + // The inner radius also needs to be taken in to account as when inner aligned. + + // If fillstyle is set the draw the text filled in. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX + this.innerRadius + margin, + this.centerY + lineOffset + ) + + // If stroke style is set draw the text outline. + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX + this.innerRadius + margin, + this.centerY + lineOffset + ) + } else if (alignment == 'outer') { + // Outer means the text is aligned with the outside of the wheel, so if looking at a segment in the 3 o'clock position + // it would appear the text is right aligned. To position we add the radius of the wheel in to the equation + // and subtract the margin this time, rather than add it. + + // I don't understand why, but in order of the text to render correctly with stroke and fill, the stroke needs to + // come first when drawing outer, rather than second when doing inner. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX + this.outerRadius - margin, + this.centerY + lineOffset + ) + + // If fillstyle the fill the text. + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX + this.outerRadius - margin, + this.centerY + lineOffset + ) + } else { + // In this case the text is to drawn centred in the segment. + // Typically no margin is required, however even though centred the text can look closer to the inner of the wheel + // due to the way the segments narrow in (is optical effect), so if a margin is specified it is placed on the inner + // side so the text is pushed towards the outer. + + // If stoke style the stroke the text. + if (fillStyle) + this.ctx.fillText( + lines[i], + this.centerX + + this.innerRadius + + (this.outerRadius - this.innerRadius) / 2 + + margin, + this.centerY + lineOffset + ) + + // If fillstyle the fill the text. + if (strokeStyle) + this.ctx.strokeText( + lines[i], + this.centerX + + this.innerRadius + + (this.outerRadius - this.innerRadius) / 2 + + margin, + this.centerY + lineOffset + ) + } + + // Restore the context so that wheel is returned to original position. + this.ctx.restore() + } else if (orientation == 'vertical') { + // If vertical then we need to do this ourselves because as far as I am aware there is no option built in to html canvas + // which causes the text to draw downwards or upwards one character after another. + + // In this case the textAlign is always center, but the baseline is either top or bottom + // depending on if inner or outer alignment has been specified. + this.ctx.textAlign = 'center' + + if (alignment == 'inner') this.ctx.textBaseline = 'bottom' + else if (alignment == 'outer') this.ctx.textBaseline = 'top' + else this.ctx.textBaseline = 'middle' + + // The angle to draw the text at is halfway between the end and the starting angle of the segment. + var textAngle = seg.endAngle - (seg.endAngle - seg.startAngle) / 2 + + // Ensure the rotation angle of the wheel is added in, otherwise the test placement won't match + // the segments they are supposed to be for. + textAngle += this.rotationAngle + + // Rotate so can begin to place the text. + this.ctx.save() + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(textAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + // Work out the position to start drawing in based on the alignment. + // If outer then when considering a segment at the 12 o'clock position want to start drawing down from the top of the wheel. + if (alignment == 'outer') var yPos = this.centerY - this.outerRadius + margin + else if (alignment == 'inner') var yPos = this.centerY - this.innerRadius - margin + + // We need to know how much to move the y axis each time. + // This is not quite simply the font size as that puts a larger gap in between the letters + // than expected, especially with monospace fonts. I found that shaving a little off makes it look "right". + var yInc = fontSize - fontSize / 9 + + // Loop though and output the characters. + if (alignment == 'outer') { + // For this alignment we draw down from the top of a segment at the 12 o'clock position to simply + // loop though the characters in order. + for (var c = 0; c < lines[i].length; c++) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos += yInc + } + } else if (alignment == 'inner') { + // Here we draw from the inner of the wheel up, but in order for the letters in the text text to + // remain in the correct order when reading, we actually need to loop though the text characters backwards. + for (var c = lines[i].length - 1; c >= 0; c--) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos -= yInc + } + } else if (alignment == 'center') { + // This is the most complex of the three as we need to draw the text top down centred between the inner and outer of the wheel. + // So logically we have to put the middle character of the text in the center then put the others each side of it. + // In reality that is a really bad way to do it, we can achieve the same if not better positioning using a + // variation on the method used for the rendering of outer aligned text once we have figured out the height of the text. + + // If there is more than one character in the text then an adjustment to the position needs to be done. + // What we are aiming for is to position the center of the text at the center point between the inner and outer radius. + var centerAdjustment = 0 + + if (lines[i].length > 1) { + centerAdjustment = (yInc * (lines[i].length - 1)) / 2 + } + + // Now work out where to start rendering the string. This is half way between the inner and outer of the wheel, with the + // centerAdjustment included to correctly position texts with more than one character over the center. + // If there is a margin it is used to push the text away from the center of the wheel. + var yPos = + this.centerY - + this.innerRadius - + (this.outerRadius - this.innerRadius) / 2 - + centerAdjustment - + margin + + // Now loop and draw just like outer text rendering. + for (var c = 0; c < lines[i].length; c++) { + character = lines[i].charAt(c) + + if (fillStyle) this.ctx.fillText(character, this.centerX + lineOffset, yPos) + + if (strokeStyle) this.ctx.strokeText(character, this.centerX + lineOffset, yPos) + + yPos += yInc + } + } + + this.ctx.restore() + } else if (orientation == 'curved') { + // There is no built in canvas function to draw text around an arc, so + // we need to do this ourselves. + var radius = 0 + + // Set the alignment of the text - inner, outer, or center by calculating + // how far out from the center point of the wheel the text is drawn. + if (alignment == 'inner') { + // When alignment is inner the radius is the innerRadius plus any margin. + radius = this.innerRadius + margin + this.ctx.textBaseline = 'bottom' + + // We need to adjust the radius in this case to take in to multiline text. + // In this case the radius needs to be further out, not at the inner radius. + radius += fontSize * (lines.length - 1) + } else if (alignment == 'outer') { + // Outer it is the outerRadius minus any margin. + radius = this.outerRadius - margin + this.ctx.textBaseline = 'top' + } else if (alignment == 'center') { + // When center we want the text halfway between the inner and outer radius. + radius = this.innerRadius + margin + (this.outerRadius - this.innerRadius) / 2 + this.ctx.textBaseline = 'middle' + } + + // Set the angle to increment by when looping though and outputting the characters in the text + // as we do this by rotating the wheel small amounts adding each character. + var anglePerChar = 0 + var drawAngle = 0 + + // If more than one character in the text then... + if (lines[i].length > 1) { + // Text is drawn from the left. + this.ctx.textAlign = 'left' + + // Work out how much angle the text rendering loop below needs to rotate by for each character to render them next to each other. + // I have discovered that 4 * the font size / 10 at 100px radius is the correct spacing for between the characters + // using a monospace font, non monospace may look a little odd as in there will appear to be extra spaces between chars. + anglePerChar = 4 * (fontSize / 10) + + // Work out what percentage the radius the text will be drawn at is of 100px. + radiusPercent = 100 / radius + + // Then use this to scale up or down the anglePerChar value. + // When the radius is less than 100px we need more angle between the letters, when radius is greater (so the text is further + // away from the center of the wheel) the angle needs to be less otherwise the characters will appear further apart. + anglePerChar = anglePerChar * radiusPercent + + // Next we want the text to be drawn in the middle of the segment, without this it would start at the beginning of the segment. + // To do this we need to work out how much arc the text will take up in total then subtract half of this from the center + // of the segment so that it sits centred. + totalArc = anglePerChar * lines[i].length + + // Now set initial draw angle to half way between the start and end of the segment. + drawAngle = seg.startAngle + ((seg.endAngle - seg.startAngle) / 2 - totalArc / 2) + } else { + // The initial draw angle is the center of the segment when only one character. + drawAngle = seg.startAngle + (seg.endAngle - seg.startAngle) / 2 + + // To ensure is dead-center the text alignment also needs to be centred. + this.ctx.textAlign = 'center' + } + + // ---------------------- + // Adjust the initial draw angle as needed to take in to account the rotationAngle of the wheel. + drawAngle += this.rotationAngle + + // ---------------------- + // Now the drawing itself. + // Loop for each character in the text. + for (c = 0; c < lines[i].length; c++) { + this.ctx.save() + + character = lines[i].charAt(c) + + // Rotate the wheel to the draw angle as we need to add the character at this location. + this.ctx.translate(this.centerX, this.centerY) + this.ctx.rotate(this.degToRad(drawAngle)) + this.ctx.translate(-this.centerX, -this.centerY) + + // Now draw the character directly above the center point of the wheel at the appropriate radius. + if (strokeStyle) + this.ctx.strokeText(character, this.centerX, this.centerY - radius + lineOffset) + + if (fillStyle) + this.ctx.fillText(character, this.centerX, this.centerY - radius + lineOffset) + + // Increment the drawAngle by the angle per character so next loop we rotate + // to the next angle required to draw the character at. + drawAngle += anglePerChar + + this.ctx.restore() + } + } + } + + // Increment this ready for the next time. + lineOffset += fontSize + } + } + + // Restore so all text options are reset ready for the next text. + this.ctx.restore() + } + } + } + + // ==================================================================================================================== + // Converts degrees to radians which is what is used when specifying the angles on HTML5 canvas arcs. + // ==================================================================================================================== + degToRad(d) { + return d * 0.0174532925199432957 + } + + // ==================================================================================================================== + // This function sets the center location of the wheel, saves a function call to set x then y. + // ==================================================================================================================== + setCenter(x, y) { + this.centerX = x + this.centerY = y + } + + // ==================================================================================================================== + // This function allows a segment to be added to the wheel. The position of the segment is optional, + // if not specified the new segment will be added to the end of the wheel. + // ==================================================================================================================== + addSegment(options, position) { + // Create a new segment object passing the options in. + newSegment = new Segment(options) + + // Increment the numSegments property of the class since new segment being added. + this.numSegments++ + var segmentPos + + // Work out where to place the segment, the default is simply as a new segment at the end of the wheel. + if (typeof position !== 'undefined') { + // Because we need to insert the segment at this position, not overwrite it, we need to move all segments after this + // location along one in the segments array, before finally adding this new segment at the specified location. + for (var x = this.numSegments; x > position; x--) { + this.segments[x] = this.segments[x - 1] + } + + this.segments[position] = newSegment + segmentPos = position + } else { + this.segments[this.numSegments] = newSegment + segmentPos = this.numSegments + } + + // Since a segment has been added the segment sizes need to be re-computed so call function to do this. + this.updateSegmentSizes() + + // Return the segment object just created in the wheel (JavaScript will return it by reference), so that + // further things can be done with it by the calling code if desired. + return this.segments[segmentPos] + } + + // ==================================================================================================================== + // This function must be used if the canvasId is changed as we also need to get the context of the new canvas. + // ==================================================================================================================== + setCanvasId(canvasId) { + if (canvasId) { + this.canvasId = canvasId + this.canvas = document.getElementById(this.canvasId) + + if (this.canvas) { + this.ctx = this.canvas.getContext('2d') + } + } else { + this.canvasId = null + this.ctx = null + this.canvas = null + } + } + + // ==================================================================================================================== + // This function deletes the specified segment from the wheel by removing it from the segments array. + // It then sorts out the other bits such as update of the numSegments. + // ==================================================================================================================== + deleteSegment(position) { + // There needs to be at least one segment in order for the wheel to draw, so only allow delete if there + // is more than one segment currently left in the wheel. + + //++ check that specifying a position that does not exist - say 10 in a 6 segment wheel does not cause issues. + if (this.numSegments > 1) { + // If the position of the segment to remove has been specified. + if (typeof position !== 'undefined') { + // The array is to be shortened so we need to move all segments after the one + // to be removed down one so there is no gap. + for (var x = position; x < this.numSegments; x++) { + this.segments[x] = this.segments[x + 1] + } + } + + // Unset the last item in the segments array since there is now one less. + this.segments[this.numSegments] = undefined + + // Decrement the number of segments, + // then call function to update the segment sizes. + this.numSegments-- + this.updateSegmentSizes() + } + } + + // ==================================================================================================================== + // This function takes the x an the y of a mouse event, such as click or move, and converts the x and the y in to + // co-ordinates on the canvas as the raw values are the x and the y from the top and left of the user's browser. + // ==================================================================================================================== + windowToCanvas(x, y) { + var bbox = this.canvas.getBoundingClientRect() + + return { + x: Math.floor(x - bbox.left * (this.canvas.width / bbox.width)), + y: Math.floor(y - bbox.top * (this.canvas.height / bbox.height)), + } + } + + // ==================================================================================================================== + // This function returns the segment object located at the specified x and y coordinates on the canvas. + // It is used to allow things to be done with a segment clicked by the user, such as highlight, display or change some values, etc. + // ==================================================================================================================== + getSegmentAt(x, y) { + var foundSegment = null + + // Call function to return segment number. + var segmentNumber = this.getSegmentNumberAt(x, y) + + // If found one then set found segment to pointer to the segment object. + if (segmentNumber !== null) { + foundSegment = this.segments[segmentNumber] + } + + return foundSegment + } + + // ==================================================================================================================== + // Returns the number of the segment clicked instead of the segment object. + // ==================================================================================================================== + getSegmentNumberAt(x, y) { + // KNOWN ISSUE: this does not work correct if the canvas is scaled using css, or has padding, border. + // @TODO see if can find a solution at some point, check windowToCanvas working as needed, then below. + + // Call function above to convert the raw x and y from the user's browser to canvas coordinates + // i.e. top and left is top and left of canvas, not top and left of the user's browser. + var loc = this.windowToCanvas(x, y) + + // ------------------------------------------ + // Now start the process of working out the segment clicked. + // First we need to figure out the angle of an imaginary line between the centerX and centerY of the wheel and + // the X and Y of the location (for example a mouse click). + var topBottom + var leftRight + var adjacentSideLength + var oppositeSideLength + var hypotenuseSideLength + + // We will use right triangle maths with the TAN function. + // The start of the triangle is the wheel center, the adjacent side is along the x axis, and the opposite side is along the y axis. + + // We only ever use positive numbers to work out the triangle and the center of the wheel needs to be considered as 0 for the numbers + // in the maths which is why there is the subtractions below. We also remember what quadrant of the wheel the location is in as we + // need this information later to add 90, 180, 270 degrees to the angle worked out from the triangle to get the position around a 360 degree wheel. + if (loc.x > this.centerX) { + adjacentSideLength = loc.x - this.centerX + leftRight = 'R' // Location is in the right half of the wheel. + } else { + adjacentSideLength = this.centerX - loc.x + leftRight = 'L' // Location is in the left half of the wheel. + } + + if (loc.y > this.centerY) { + oppositeSideLength = loc.y - this.centerY + topBottom = 'B' // Bottom half of wheel. + } else { + oppositeSideLength = this.centerY - loc.y + topBottom = 'T' // Top Half of wheel. + } + + // Now divide opposite by adjacent to get tan value. + var tanVal = oppositeSideLength / adjacentSideLength + + // Use the tan function and convert results to degrees since that is what we work with. + var result = (Math.atan(tanVal) * 180) / Math.PI + var locationAngle = 0 + + // We also need the length of the hypotenuse as later on we need to compare this to the outerRadius of the segment / circle. + hypotenuseSideLength = Math.sqrt( + oppositeSideLength * oppositeSideLength + adjacentSideLength * adjacentSideLength + ) + + // ------------------------------------------ + // Now to make sense around the wheel we need to alter the values based on if the location was in top or bottom half + // and also right or left half of the wheel, by adding 90, 180, 270 etc. Also for some the initial locationAngle needs to be inverted. + if (topBottom == 'T' && leftRight == 'R') { + locationAngle = Math.round(90 - result) + } else if (topBottom == 'B' && leftRight == 'R') { + locationAngle = Math.round(result + 90) + } else if (topBottom == 'B' && leftRight == 'L') { + locationAngle = Math.round(90 - result + 180) + } else if (topBottom == 'T' && leftRight == 'L') { + locationAngle = Math.round(result + 270) + } + + // ------------------------------------------ + // And now we have to adjust to make sense when the wheel is rotated from the 0 degrees either + // positive or negative and it can be many times past 360 degrees. + if (this.rotationAngle != 0) { + var rotatedPosition = this.getRotationPosition() + + // So we have this, now we need to alter the locationAngle as a result of this. + locationAngle = locationAngle - rotatedPosition + + // If negative then take the location away from 360. + if (locationAngle < 0) { + locationAngle = 360 - Math.abs(locationAngle) + } + } + + // ------------------------------------------ + // OK, so after all of that we have the angle of a line between the centerX and centerY of the wheel and + // the X and Y of the location on the canvas where the mouse was clicked. Now time to work out the segment + // this corresponds to. We can use the segment start and end angles for this. + var foundSegmentNumber = null + + for (var x = 1; x <= this.numSegments; x++) { + // Due to segments sharing start and end angles, if line is clicked will pick earlier segment. + if (locationAngle >= this.segments[x].startAngle && locationAngle <= this.segments[x].endAngle) { + // To ensure that a click anywhere on the canvas in the segment direction will not cause a + // segment to be matched, as well as the angles, we need to ensure the click was within the radius + // of the segment (or circle if no segment radius). + + // If the hypotenuseSideLength (length of location from the center of the wheel) is with the radius + // then we can assign the segment to the found segment and break out the loop. + + // Have to take in to account hollow wheels (doughnuts) so check is greater than innerRadius as + // well as less than or equal to the outerRadius of the wheel. + if (hypotenuseSideLength >= this.innerRadius && hypotenuseSideLength <= this.outerRadius) { + foundSegmentNumber = x + break + } + } + } + + // Finally return the number. + return foundSegmentNumber + } + + // ==================================================================================================================== + // Returns a reference to the segment that is at the location of the pointer on the wheel. + // ==================================================================================================================== + getIndicatedSegment() { + // Call function below to work this out and return the prizeNumber. + var prizeNumber = this.getIndicatedSegmentNumber() + + // Then simply return the segment in the segments array at that position. + return this.segments[prizeNumber] + } + + // ==================================================================================================================== + // Works out the segment currently pointed to by the pointer of the wheel. Normally called when the spinning has stopped + // to work out the prize the user has won. Returns the number of the segment in the segments array. + // ==================================================================================================================== + getIndicatedSegmentNumber() { + var indicatedPrize = 0 + var rawAngle = this.getRotationPosition() + + // Now we have the angle of the wheel, but we need to take in to account where the pointer is because + // will not always be at the 12 o'clock 0 degrees location. + var relativeAngle = Math.floor(this.pointerAngle - rawAngle) + + if (relativeAngle < 0) { + relativeAngle = 360 - Math.abs(relativeAngle) + } + + // Now we can work out the prize won by seeing what prize segment startAngle and endAngle the relativeAngle is between. + for (var x = 1; x < this.segments.length; x++) { + if (relativeAngle >= this.segments[x]['startAngle'] && relativeAngle <= this.segments[x]['endAngle']) { + indicatedPrize = x + break + } + } + + return indicatedPrize + } + + // ==================================================================================================================== + // Works out what Pin around the wheel is considered the current one which is the one which just passed the pointer. + // Used to work out if the pin has changed during the animation to tigger a sound. + // ==================================================================================================================== + getCurrentPinNumber() { + var currentPin = 0 + + if (this.pins) { + var rawAngle = this.getRotationPosition() + + // Now we have the angle of the wheel, but we need to take in to account where the pointer is because + // will not always be at the 12 o'clock 0 degrees location. + var relativeAngle = Math.floor(this.pointerAngle - rawAngle) + + if (relativeAngle < 0) { + relativeAngle = 360 - Math.abs(relativeAngle) + } + + // Work out the angle of the pins as this is simply 360 / the number of pins as they space evenly around. + var pinSpacing = 360 / this.pins.number + var totalPinAngle = 0 + + // Now we can work out the pin by seeing what pins relativeAngle is between. + for (var x = 0; x < this.pins.number; x++) { + if (relativeAngle >= totalPinAngle && relativeAngle <= totalPinAngle + pinSpacing) { + currentPin = x + break + } + + totalPinAngle += pinSpacing + } + + // Now if rotating clockwise we must add 1 to the current pin as we want the pin which has just passed + // the pointer to be returned as the current pin, not the start of the one we are between. + if (this.animation.direction == 'clockwise') { + currentPin++ + + if (currentPin > this.pins.number) { + currentPin = 0 + } + } + } + + return currentPin + } + + // ================================================================================================================================================== + // Returns the rotation angle of the wheel corrected to 0-360 (i.e. removes all the multiples of 360). + // ================================================================================================================================================== + getRotationPosition() { + var rawAngle = this.rotationAngle // Get current rotation angle of wheel. + + // If positive work out how many times past 360 this is and then take the floor of this off the rawAngle. + if (rawAngle >= 0) { + if (rawAngle > 360) { + // Get floor of the number of times past 360 degrees. + var timesPast360 = Math.floor(rawAngle / 360) + + // Take all this extra off to get just the angle 0-360 degrees. + rawAngle = rawAngle - 360 * timesPast360 + } + } else { + // Is negative, need to take off the extra then convert in to 0-360 degree value + // so if, for example, was -90 then final value will be (360 - 90) = 270 degrees. + if (rawAngle < -360) { + var timesPast360 = Math.ceil(rawAngle / 360) // Ceil when negative. + + rawAngle = rawAngle - 360 * timesPast360 // Is minus because dealing with negative. + } + + rawAngle = 360 + rawAngle // Make in the range 0-360. Is plus because raw is still negative. + } + + return rawAngle + } + + // ================================================================================================================================================== + // This function starts the wheel's animation by using the properties of the animation object of of the wheel to begin the a greensock tween. + // ================================================================================================================================================== + startAnimation() { + if (this.animation) { + // Call function to compute the animation properties. + this.computeAnimation() + + // Set this global variable to this object as an external function is required to call the draw() function on the wheel + // each loop of the animation as Greensock cannot call the draw function directly on this class. + winwheelToDrawDuringAnimation = this + + // Put together the properties of the greesock animation. + var properties = new Array(null) + properties[this.animation.propertyName] = this.animation.propertyValue // Here we set the property to be animated and its value. + properties['yoyo'] = this.animation.yoyo // Set others. + properties['repeat'] = this.animation.repeat + properties['ease'] = this.animation.easing + properties['onUpdate'] = winwheelAnimationLoop // Call function to re-draw the canvas. + properties['onComplete'] = winwheelStopAnimation // Call function to perform actions when animation has finished. + + // Do the tween animation passing the properties from the animation object as an array of key => value pairs. + // Keep reference to the tween object in the wheel as that allows pausing, resuming, and stopping while the animation is still running. + this.tween = TweenMax.to(this, this.animation.duration, properties) + } + } + + // ================================================================================================================================================== + // Use same function function which needs to be outside the class for the callback when it stops because is finished. + // ================================================================================================================================================== + stopAnimation(canCallback) { + // @TODO as part of multiwheel, need to work out how to stop the tween for a single wheel but allow others to continue. + + // We can kill the animation using our tween object. + if (winwheelToDrawDuringAnimation) { + winwheelToDrawDuringAnimation.tween.kill() + + // Call the callback function. + winwheelStopAnimation(canCallback) + } + + // Ensure the winwheelToDrawDuringAnimation is set to this class. + winwheelToDrawDuringAnimation = this + } + + // ================================================================================================================================================== + // Pause animation by telling tween to pause. + // ================================================================================================================================================== + pauseAnimation() { + if (this.tween) { + this.tween.pause() + } + } + + // ================================================================================================================================================== + // Resume the animation by telling tween to continue playing it. + // ================================================================================================================================================== + resumeAnimation() { + if (this.tween) { + this.tween.play() + } + } + + // ==================================================================================================================== + // Called at the beginning of the startAnimation function and computes the values needed to do the animation + // before it starts. This allows the developer to change the animation properties after the wheel has been created + // and have the animation use the new values of the animation properties. + // ==================================================================================================================== + computeAnimation() { + if (this.animation) { + // Set the animation parameters for the specified animation type including some sensible defaults if values have not been specified. + if (this.animation.type == 'spinOngoing') { + // When spinning the rotationAngle is the wheel property which is animated. + this.animation.propertyName = 'rotationAngle' + + if (this.animation.spins == null) { + this.animation.spins = 5 + } + + if (this.animation.repeat == null) { + this.animation.repeat = -1 // -1 means it will repeat forever. + } + + if (this.animation.easing == null) { + this.animation.easing = 'Linear.easeNone' + } + + if (this.animation.yoyo == null) { + this.animation.yoyo = false + } + + // We need to calculate the propertyValue and this is the spins * 360 degrees. + this.animation.propertyValue = this.animation.spins * 360 + + // If the direction is anti-clockwise then make the property value negative. + if (this.animation.direction == 'anti-clockwise') { + this.animation.propertyValue = 0 - this.animation.propertyValue + } + } else if (this.animation.type == 'spinToStop') { + // Spin to stop the rotation angle is affected. + this.animation.propertyName = 'rotationAngle' + + if (this.animation.spins == null) { + this.animation.spins = 5 + } + + if (this.animation.repeat == null) { + this.animation.repeat = 0 // As this is spin to stop we don't normally want it repeated. + } + + if (this.animation.easing == null) { + this.animation.easing = 'Power3.easeOut' // This easing is fast start and slows over time. + } + + if (this.animation.stopAngle == null) { + // If the stop angle has not been specified then pick random between 0 and 359. + this.animation._stopAngle = Math.floor(Math.random() * 359) + } else { + // We need to set the internal to 360 minus what the user entered because the wheel spins past 0 without + // this it would indicate the prize on the opposite side of the wheel. We aslo need to take in to account + // the pointerAngle as the stop angle needs to be relative to that. + this.animation._stopAngle = 360 - this.animation.stopAngle + this.pointerAngle + } + + if (this.animation.yoyo == null) { + this.animation.yoyo = false + } + + // The property value is the spins * 360 then plus or minus the stopAngle depending on if the rotation is clockwise or anti-clockwise. + this.animation.propertyValue = this.animation.spins * 360 + + if (this.animation.direction == 'anti-clockwise') { + this.animation.propertyValue = 0 - this.animation.propertyValue + + // Also if the value is anti-clockwise we need subtract the stopAngle (but to get the wheel to stop in the correct + // place this is 360 minus the stop angle as the wheel is rotating backwards). + this.animation.propertyValue -= 360 - this.animation._stopAngle + } else { + // Add the stopAngle to the propertyValue as the wheel must rotate around to this place and stop there. + this.animation.propertyValue += this.animation._stopAngle + } + } else if (this.animation.type == 'spinAndBack') { + // This is basically is a spin for a number of times then the animation reverses and goes back to start. + // If a repeat is specified then this can be used to make the wheel "rock" left and right. + + // Again this is a spin so the rotationAngle the property which is animated. + this.animation.propertyName = 'rotationAngle' + + if (this.animation.spins == null) { + this.animation.spins = 5 + } + + if (this.animation.repeat == null) { + this.animation.repeat = 1 // This needs to be set to at least 1 in order for the animation to reverse. + } + + if (this.animation.easing == null) { + this.animation.easing = 'Power2.easeInOut' // This is slow at the start and end and fast in the middle. + } + + if (this.animation.yoyo == null) { + this.animation.yoyo = true // This needs to be set to true to have the animation reverse back like a yo-yo. + } + + if (this.animation.stopAngle == null) { + this.animation._stopAngle = 0 + } else { + // We need to set the internal to 360 minus what the user entered + // because the wheel spins past 0 without this it would indicate the + // prize on the opposite side of the wheel. + this.animation._stopAngle = 360 - this.animation.stopAngle + } + + // The property value is the spins * 360 then plus or minus the stopAngle depending on if the rotation is clockwise or anti-clockwise. + this.animation.propertyValue = this.animation.spins * 360 + + if (this.animation.direction == 'anti-clockwise') { + this.animation.propertyValue = 0 - this.animation.propertyValue + + // Also if the value is anti-clockwise we need subtract the stopAngle (but to get the wheel to stop in the correct + // place this is 360 minus the stop angle as the wheel is rotating backwards). + this.animation.propertyValue -= 360 - this.animation._stopAngle + } else { + // Add the stopAngle to the propertyValue as the wheel must rotate around to this place and stop there. + this.animation.propertyValue += this.animation._stopAngle + } + } else if (this.animation.type == 'custom') { + // Do nothing as all values must be set by the developer in the parameters + // especially the propertyName and propertyValue. + } + } + } + + // ==================================================================================================================== + // Calculates and returns a random stop angle inside the specified segment number. Value will always be 1 degree inside + // the start and end of the segment to avoid issue with the segment overlap. + // ==================================================================================================================== + getRandomForSegment(segmentNumber) { + var stopAngle = 0 + + if (segmentNumber) { + if (typeof this.segments[segmentNumber] !== 'undefined') { + var startAngle = this.segments[segmentNumber].startAngle + var endAngle = this.segments[segmentNumber].endAngle + var range = endAngle - startAngle - 2 + + if (range > 0) { + stopAngle = startAngle + 1 + Math.floor(Math.random() * range) + } else { + console.log('Segment size is too small to safely get random angle inside it') + } + } else { + console.log('Segment ' + segmentNumber + ' undefined') + } + } else { + console.log('Segment number not specified') + } + + return stopAngle + } +} + +// ==================================================================================================================== +// Class for the wheel pins. +// ==================================================================================================================== +class Pin { + constructor(options) { + var defaultOptions = { + visible: true, // In future there might be some functionality related to the pins even if they are not displayed. + number: 36, // The number of pins. These are evenly distributed around the wheel. + outerRadius: 3, // Radius of the pins which determines their size. + fillStyle: 'grey', // Fill colour of the pins. + strokeStyle: 'black', // Line colour of the pins. + lineWidth: 1, // Line width of the pins. + margin: 3, // The space between outside edge of the wheel and the pins. + } + + // Now loop through the default options and create properties of this class set to the value for + // the option passed in if a value was, or if not then set the value of the default. + for (var key in defaultOptions) { + if (options != null && typeof options[key] !== 'undefined') this[key] = options[key] + else this[key] = defaultOptions[key] + } + + // Also loop though the passed in options and add anything specified not part of the class in to it as a property. + if (options != null) { + for (var key in options) { + if (typeof this[key] === 'undefined') { + this[key] = options[key] + } + } + } + } +} +// ==================================================================================================================== +// Class for the wheel spinning animation which like a segment becomes a property of the wheel. +// ==================================================================================================================== +class Animation { + constructor(options) { + // Most of these options are null because the defaults are different depending on the type of animation. + var defaultOptions = { + type: 'spinOngoing', // For now there are only supported types are spinOngoing (continuous), spinToStop, spinAndBack, custom. + direction: 'clockwise', // clockwise or anti-clockwise. + propertyName: null, // The name of the winning wheel property to be affected by the animation. + propertyValue: null, // The value the property is to be set to at the end of the animation. + duration: 10, // Duration of the animation. + yoyo: false, // If the animation is to reverse back again i.e. yo-yo. + repeat: null, // The number of times the animation is to repeat, -1 will cause it to repeat forever. + easing: null, // The easing to use for the animation, default is the best for spin to stop. Use Linear.easeNone for no easing. + stopAngle: null, // Used for spinning, the angle at which the wheel is to stop. + spins: null, // Used for spinning, the number of complete 360 degree rotations the wheel is to do. + clearTheCanvas: null, // If set to true the canvas will be cleared before the wheel is re-drawn, false it will not, null the animation will abide by the value of this property for the parent wheel object. + callbackFinished: null, // Function to callback when the animation has finished. + callbackBefore: null, // Function to callback before the wheel is drawn each animation loop. + callbackAfter: null, // Function to callback after the wheel is drawn each animation loop. + callbackSound: null, // Function to callback if a sound should be triggered on change of segment or pin. + soundTrigger: 'segment', // Sound trigger type. Default is segment which triggers when segment changes, can be pin if to trigger when pin passes the pointer. + } + + // Now loop through the default options and create properties of this class set to the value for + // the option passed in if a value was, or if not then set the value of the default. + for (var key in defaultOptions) { + if (options != null && typeof options[key] !== 'undefined') this[key] = options[key] + else this[key] = defaultOptions[key] + } + + // Also loop though the passed in options and add anything specified not part of the class in to it as a property. + if (options != null) { + for (var key in options) { + if (typeof this[key] === 'undefined') { + this[key] = options[key] + } + } + } + } +} +// ==================================================================================================================== +// Class for segments. When creating a json of options can be passed in. +// ==================================================================================================================== +class Segment { + constructor(options) { + // Define default options for segments, most are null so that the global defaults for the wheel + // are used if the values for a particular segment are not specifically set. + var defaultOptions = { + size: null, // Leave null for automatic. Valid values are degrees 0-360. Use percentToDegrees function if needed to convert. + text: '', // Default is blank. + fillStyle: null, // If null for the rest the global default will be used. + strokeStyle: null, + lineWidth: null, + textFontFamily: null, + textFontSize: null, + textFontWeight: null, + textOrientation: null, + textAlignment: null, + textDirection: null, + textMargin: null, + textFillStyle: null, + textStrokeStyle: null, + textLineWidth: null, + image: null, // Name/path to the image + imageDirection: null, // Direction of the image, can be set globally for the whole wheel. + imgData: null, // Image object created here and loaded with image data. + } + + // Now loop through the default options and create properties of this class set to the value for + // the option passed in if a value was, or if not then set the value of the default. + for (var key in defaultOptions) { + if (options != null && typeof options[key] !== 'undefined') this[key] = options[key] + else this[key] = defaultOptions[key] + } + + // Also loop though the passed in options and add anything specified not part of the class in to it as a property. + // This allows the developer to easily add properties to segments at construction time. + if (options != null) { + for (var key in options) { + if (typeof this[key] === 'undefined') { + this[key] = options[key] + } + } + } + + // There are 2 additional properties which are set by the code, so need to define them here. + // They are not in the default options because they are not something that should be set by the user, + // the values are updated every time the updateSegmentSizes() function is called. + this.startAngle = 0 + this.endAngle = 0 + } + + // ==================================================================================================================== + // Changes an image for a segment by setting a callback to render the wheel once the image has loaded. + // ==================================================================================================================== + changeImage(image, imageDirection) { + // Change image name, blank image data. + this.image = image + this.imgData = null + + // Set direction. + if (imageDirection) { + this.imageDirection = imageDirection + } + + // Set imgData to a new image object, change set callback and change src (just like in wheel constructor). + winhweelAlreadyDrawn = false + this.imgData = new Image() + this.imgData.onload = winwheelLoadedImage + this.imgData.src = this.image + } +} + +// ==================================================================================================================== +// Class that is created as property of the wheel. Draws line from center of the wheel out to edge of canvas to +// indicate where the code thinks the pointer location is. Helpful to get alignment correct esp when using images. +// ==================================================================================================================== +class PointerGuide { + constructor(options) { + var defaultOptions = { + display: false, + strokeStyle: 'red', + lineWidth: 3, + } + + // Now loop through the default options and create properties of this class set to the value for + // the option passed in if a value was, or if not then set the value of the default. + for (var key in defaultOptions) { + if (options != null && typeof options[key] !== 'undefined') { + this[key] = options[key] + } else { + this[key] = defaultOptions[key] + } + } + } +} + +// ==================================================================================================================== +// This function takes the percent 0-100 and returns the number of degrees 0-360 this equates to. +// ==================================================================================================================== +function winwheelPercentToDegrees(percentValue) { + var degrees = 0 + + if (percentValue > 0 && percentValue <= 100) { + var divider = percentValue / 100 + degrees = 360 * divider + } + + return degrees +} + +// ==================================================================================================================== +// In order for the wheel to be re-drawn during the spin animation the function greesock calls needs to be outside +// of the class as for some reason it errors if try to call winwheel.draw() directly. +// ==================================================================================================================== +function winwheelAnimationLoop() { + if (winwheelToDrawDuringAnimation) { + // Check if the clearTheCanvas is specified for this animation, if not or it is not false then clear the canvas. + if (winwheelToDrawDuringAnimation.animation.clearTheCanvas != false) { + winwheelToDrawDuringAnimation.ctx.clearRect( + 0, + 0, + winwheelToDrawDuringAnimation.canvas.width, + winwheelToDrawDuringAnimation.canvas.height + ) + } + + var callbackBefore = winwheelToDrawDuringAnimation.animation.callbackBefore + var callbackAfter = winwheelToDrawDuringAnimation.animation.callbackAfter + + // If there is a callback function which is supposed to be called before the wheel is drawn then do that. + if (callbackBefore != null) { + // If the property is a function then call it, otherwise eval the proptery as javascript code. + if (typeof callbackBefore === 'function') { + callbackBefore() + } else { + eval(callbackBefore) + } + } + + // Call code to draw the wheel, pass in false as we never want it to clear the canvas as that would wipe anything drawn in the callbackBefore. + winwheelToDrawDuringAnimation.draw(false) + + // If there is a callback function which is supposed to be called after the wheel has been drawn then do that. + if (callbackAfter != null) { + // If the property is a function then call it, otherwise eval the proptery as javascript code. + if (typeof callbackAfter === 'function') { + callbackAfter() + } else { + eval(callbackAfter) + } + } + + // If there is a sound callback then call a function which figures out if the sound should be triggered + // and if so then call the function specified by the developer. + if (winwheelToDrawDuringAnimation.animation.callbackSound) { + winwheelTriggerSound() + } + } +} + +// ==================================================================================================================== +// This function figures out if the callbackSound function needs to be called by working out if the segment or pin +// has changed since the last animation loop. +// ==================================================================================================================== +function winwheelTriggerSound() { + // If this property does not exist then add it as a property of the winwheel. + if (winwheelToDrawDuringAnimation.hasOwnProperty('_lastSoundTriggerNumber') == false) { + winwheelToDrawDuringAnimation._lastSoundTriggerNumber = 0 + } + + var callbackSound = winwheelToDrawDuringAnimation.animation.callbackSound + var currentTriggerNumber = 0 + + // Now figure out if the sound callback should be called depending on the sound trigger type. + if (winwheelToDrawDuringAnimation.animation.soundTrigger == 'pin') { + // So for the pin type we need to work out which pin we are between. + currentTriggerNumber = winwheelToDrawDuringAnimation.getCurrentPinNumber() + } else { + // Check on the change of segment by working out which segment we are in. + // We can utilise the existing getIndiatedSegmentNumber function. + currentTriggerNumber = winwheelToDrawDuringAnimation.getIndicatedSegmentNumber() + } + + // If the current number is not the same as last time then call the sound callback. + if (currentTriggerNumber != winwheelToDrawDuringAnimation._lastSoundTriggerNumber) { + // If the property is a function then call it, otherwise eval the proptery as javascript code. + if (typeof callbackSound === 'function') { + callbackSound() + } else { + eval(callbackSound) + } + + // Also update the last sound trigger with the current number. + winwheelToDrawDuringAnimation._lastSoundTriggerNumber = currentTriggerNumber + } +} + +// ==================================================================================================================== +// This function is called-back when the greensock animation has finished. +// ==================================================================================================================== +var winwheelToDrawDuringAnimation = null // This global is set by the winwheel class to the wheel object to be re-drawn. + +function winwheelStopAnimation(canCallback) { + // When the animation is stopped if canCallback is not false then try to call the callback. + // false can be passed in to stop the after happening if the animation has been stopped before it ended normally. + if (canCallback != false) { + var callback = winwheelToDrawDuringAnimation.animation.callbackFinished + + if (callback != null) { + // If the callback is a function then call it, otherwise evaluate the property as javascript code. + if (typeof callback === 'function') { + // Pass back the indicated segment as 99% of the time you will want to know this to inform the user of their prize. + callback(winwheelToDrawDuringAnimation.getIndicatedSegment()) + } else { + eval(callback) + } + } + } +} + +// ==================================================================================================================== +// Called after the image has loaded for each segment. Once all the images are loaded it then calls the draw function +// on the wheel to render it. Used in constructor and also when a segment image is changed. +// ==================================================================================================================== +var winhweelAlreadyDrawn = false + +function winwheelLoadedImage() { + // Prevent multiple drawings of the wheel which ocurrs without this check due to timing of function calls. + if (winhweelAlreadyDrawn == false) { + // Set to 0. + var winwheelImageLoadCount = 0 + + // Loop though all the segments of the wheel and check if image data loaded, if so increment counter. + for (var i = 1; i <= winwheelToDrawDuringAnimation.numSegments; i++) { + // Check the image data object is not null and also that the image has completed loading by checking + // that a property of it such as the height has some sort of true value. + if ( + winwheelToDrawDuringAnimation.segments[i].imgData != null && + winwheelToDrawDuringAnimation.segments[i].imgData.height + ) { + winwheelImageLoadCount++ + } + } + + // If number of images loaded matches the segments then all the images for the wheel are loaded. + if (winwheelImageLoadCount == winwheelToDrawDuringAnimation.numSegments) { + // Call draw function to render the wheel. + winhweelAlreadyDrawn = true + winwheelToDrawDuringAnimation.draw() + } + } +} diff --git a/stylesheets/winwheel.css b/stylesheets/winwheel.css new file mode 100644 index 000000000..68911271b --- /dev/null +++ b/stylesheets/winwheel.css @@ -0,0 +1,121 @@ +.vue-winwheel { + text-align: center; + background-size: cover; + background-position: center bottom; + background-repeat: no-repeat; +} +.vue-winwheel h1 { + color: #b32656; + font-family: 'Avenir', Helvetica, Arial, sans-serif; + font-size: 36px; + line-height: 90px; + letter-spacing: 4px; + margin: 0; +} +.vue-winwheel h2 { + margin: 0; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content { + width: calc(100vw - 30px); + padding-top: 52px; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content h2 { + text-transform: uppercase; + color: #b32656; + margin-bottom: 16px; + margin-top: 0; + font-family: 'Avenir', Helvetica, Arial, sans-serif; + font-size: 18px; + letter-spacing: 1.1px; + margin: 0; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content p { + font-family: 'Avenir', Helvetica, Arial, sans-serif; + font-size: 14px; + color: black; + text-align: center; + line-height: 25px; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content p strong { + font-family: 'Avenir', Helvetica, Arial, sans-serif; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content .modal-dismiss { + top: 12px; + right: 12px; +} +.vue-winwheel #modalSpinwheel.custom-modal .content-wrapper .content .modal-dismiss i.icon_close { + font-size: 30px; + color: #da2a52; +} +.vue-winwheel canvas#canvas { + position: relative; +} +.vue-winwheel .canvas-wrapper { + position: relative; +} +.vue-winwheel .canvas-wrapper:after { + content: ''; + display: block; + width: 42px; + background: #c4376f; + height: 42px; + position: absolute; + left: calc(50% - 25px); + margin: auto; + border-radius: 100%; + top: calc(50% - 29px); + border: 5px solid white; + box-sizing: content-box; +} +.vue-winwheel .canvas-wrapper:before { + content: ''; + display: block; + width: 310px; + background: #0f0f0f; + height: 310px; + position: absolute; + left: 0; + right: 0; + margin: 0 auto; + border-radius: 100%; + top: 0; +} +.vue-winwheel .wheel-wrapper { + position: relative; +} +.vue-winwheel .wheel-wrapper:before { + content: ''; + width: 62px; + height: 47px; + position: absolute; + top: -10px; + left: calc(50% - 31px); + right: 0; + display: block; + z-index: 99999; + background-image: url('../images/wheel-marker.svg'); + background-repeat: no-repeat; + background-size: contain; + background-position: center; +} +.vue-winwheel .wheel-wrapper .button-wrapper { + margin: 0 auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 231px; + height: 118px; +} +.vue-winwheel .wheel-wrapper .btn.btn-play { + padding: 0 58px !important; + background: #c4376f; + height: 40px; + line-height: 40px; + color: white; + font-weight: bold; + text-decoration: none; + border-radius: 2px; + font-family: 'Avenir', Helvetica, Arial, sans-serif; + letter-spacing: 2px; +} \ No newline at end of file