/******/ (() => { // webpackBootstrap /******/ var __webpack_modules__ = ({ /***/ 464 (module) { !function(t,e){ true?module.exports=e():0}(this,(function(){"use strict";var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)68?1900:2e3)};var f=function(e){return function(t){this[e]=+t}},h=[/[+-]\d\d:?(\d\d)?|Z/,function(e){(this.zone||(this.zone={})).offset=function(e){if(!e)return 0;if("Z"===e)return 0;var t=e.match(/([+-]|\d\d)/g),n=60*t[1]+(+t[2]||0);return 0===n?0:"+"===t[0]?-n:n}(e)}],u=function(e){var t=s[e];return t&&(t.indexOf?t:t.s.concat(t.f))},d=function(e,t){var n,r=s.meridiem;if(r){for(var i=1;i<=24;i+=1)if(e.indexOf(r(i,0,t))>-1){n=i>12;break}}else n=e===(t?"pm":"PM");return n},c={A:[o,function(e){this.afternoon=d(e,!1)}],a:[o,function(e){this.afternoon=d(e,!0)}],Q:[n,function(e){this.month=3*(e-1)+1}],S:[n,function(e){this.milliseconds=100*+e}],SS:[r,function(e){this.milliseconds=10*+e}],SSS:[/\d{3}/,function(e){this.milliseconds=+e}],s:[i,f("seconds")],ss:[i,f("seconds")],m:[i,f("minutes")],mm:[i,f("minutes")],H:[i,f("hours")],h:[i,f("hours")],HH:[i,f("hours")],hh:[i,f("hours")],D:[i,f("day")],DD:[r,f("day")],Do:[o,function(e){var t=s.ordinal,n=e.match(/\d+/);if(this.day=n[0],t)for(var r=1;r<=31;r+=1)t(r).replace(/\[|\]/g,"")===e&&(this.day=r)}],w:[i,f("week")],ww:[r,f("week")],M:[i,f("month")],MM:[r,f("month")],MMM:[o,function(e){var t=u("months"),n=(u("monthsShort")||t.map((function(e){return e.slice(0,3)}))).indexOf(e)+1;if(n<1)throw new Error;this.month=n%12||n}],MMMM:[o,function(e){var t=u("months").indexOf(e)+1;if(t<1)throw new Error;this.month=t%12||t}],Y:[/[+-]?\d+/,f("year")],YY:[r,function(e){this.year=a(e)}],YYYY:[/\d{4}/,f("year")],Z:h,ZZ:h};function l(n){var r,i;r=n,i=s&&s.formats;for(var o=(n=r.replace(/(\[[^\]]+])|(LTS?|l{1,4}|L{1,4})/g,(function(t,n,r){var o=r&&r.toUpperCase();return n||i[r]||e[r]||i[o].replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g,(function(e,t,n){return t||n.slice(1)}))}))).match(t),a=o.length,f=0;f-1)return new Date(("X"===t?1e3:1)*e);var i=l(t)(e),o=i.year,s=i.month,a=i.day,f=i.hours,h=i.minutes,u=i.seconds,d=i.milliseconds,c=i.zone,m=i.week,M=new Date,Y=a||(o||s?1:M.getDate()),p=o||M.getFullYear(),v=0;o&&!s||(v=s>0?s-1:M.getMonth());var D,w=f||0,g=h||0,y=u||0,L=d||0;return c?new Date(Date.UTC(p,v,Y,w,g,y,L+60*c.offset*1e3)):n?new Date(Date.UTC(p,v,Y,w,g,y,L)):(D=new Date(p,v,Y,w,g,y,L),m&&(D=r(D).week(m).toDate()),D)}catch(e){return new Date("")}}(t,a,r,n),this.init(),d&&!0!==d&&(this.$L=this.locale(d).$L),u&&t!=this.format(a)&&(this.$d=new Date("")),s={}}else if(a instanceof Array)for(var c=a.length,m=1;m<=c;m+=1){o[1]=a[m-1];var M=n.apply(this,o);if(M.isValid()){this.$d=M.$d,this.$L=M.$L,this.init();break}m===c&&(this.$d=new Date(""))}else i.call(this,e)}}})); /***/ }, /***/ 562 (module) { !function(r,e){ true?module.exports=e():0}(this,(function(){"use strict";return function(r,e,t){r=r||{};var n=e.prototype,o={future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"};function i(r,e,t,o){return n.fromToBase(r,e,t,o)}t.en.relativeTime=o,n.fromToBase=function(e,n,i,d,u){for(var f,a,s,l=i.$locale().relativeTime||o,h=r.thresholds||[{l:"s",r:44,d:"second"},{l:"m",r:89},{l:"mm",r:44,d:"minute"},{l:"h",r:89},{l:"hh",r:21,d:"hour"},{l:"d",r:35},{l:"dd",r:25,d:"day"},{l:"M",r:45},{l:"MM",r:10,d:"month"},{l:"y",r:17},{l:"yy",d:"year"}],m=h.length,c=0;c0,p<=y.r||!y.r){p<=1&&c>0&&(y=h[c-1]);var v=l[y.l];u&&(p=u(""+p)),a="string"==typeof v?v.replace("%d",p):v(p,n,y.l,s);break}}if(n)return a;var M=s?l.future:l.past;return"function"==typeof M?M(a):M.replace("%s",a)},n.to=function(r,e){return i(r,e,this,!0)},n.from=function(r,e){return i(r,e,this)};var d=function(r){return r.$u?t.utc():t()};n.toNow=function(r){return this.to(d(this),r)},n.fromNow=function(r){return this.from(d(this),r)}}})); /***/ }, /***/ 168 (module) { !function(t,e){ true?module.exports=e():0}(this,(function(){"use strict";var t={year:0,month:1,day:2,hour:3,minute:4,second:5},e={};return function(n,i,o){var r,a=function(t,n,i){void 0===i&&(i={});var o=new Date(t),r=function(t,n){void 0===n&&(n={});var i=n.timeZoneName||"short",o=t+"|"+i,r=e[o];return r||(r=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",timeZoneName:i}),e[o]=r),r}(n,i);return r.formatToParts(o)},u=function(e,n){for(var i=a(e,n),r=[],u=0;u=0&&(r[c]=parseInt(m,10))}var d=r[3],l=24===d?0:d,h=r[0]+"-"+r[1]+"-"+r[2]+" "+l+":"+r[4]+":"+r[5]+":000",v=+e;return(o.utc(h).valueOf()-(v-=v%1e3))/6e4},f=i.prototype;f.tz=function(t,e){void 0===t&&(t=r);var n,i=this.utcOffset(),a=this.toDate(),u=a.toLocaleString("en-US",{timeZone:t}),f=Math.round((a-new Date(u))/1e3/60),s=15*-Math.round(a.getTimezoneOffset()/15)-f;if(!Number(s))n=this.utcOffset(0,e);else if(n=o(u,{locale:this.$L}).$set("millisecond",this.$ms).utcOffset(s,!0),e){var m=n.utcOffset();n=n.add(i-m,"minute")}return n.$x.$timezone=t,n},f.offsetName=function(t){var e=this.$x.$timezone||o.tz.guess(),n=a(this.valueOf(),e,{timeZoneName:t}).find((function(t){return"timezonename"===t.type.toLowerCase()}));return n&&n.value};var s=f.startOf;f.startOf=function(t,e){if(!this.$x||!this.$x.$timezone)return s.call(this,t,e);var n=o(this.format("YYYY-MM-DD HH:mm:ss:SSS"),{locale:this.$L});return s.call(n,t,e).tz(this.$x.$timezone,!0)},o.tz=function(t,e,n){var i=n&&e,a=n||e||r,f=u(+o(),a);if("string"!=typeof t)return o(t).tz(a);var s=function(t,e,n){var i=t-60*e*1e3,o=u(i,n);if(e===o)return[i,e];var r=u(i-=60*(o-e)*1e3,n);return o===r?[i,o]:[t-60*Math.min(o,r)*1e3,Math.max(o,r)]}(o.utc(t,i).valueOf(),f,a),m=s[0],c=s[1],d=o(m).utcOffset(c);return d.$x.$timezone=a,d},o.tz.guess=function(){return Intl.DateTimeFormat().resolvedOptions().timeZone},o.tz.setDefault=function(t){r=t}}})); /***/ }, /***/ 657 (module) { !function(t,i){ true?module.exports=i():0}(this,(function(){"use strict";var t="minute",i=/[+-]\d\d(?::?\d\d)?/g,e=/([+-]|\d\d)/g;return function(s,f,n){var u=f.prototype;n.utc=function(t){var i={date:t,utc:!0,args:arguments};return new f(i)},u.utc=function(i){var e=n(this.toDate(),{locale:this.$L,utc:!0});return i?e.add(this.utcOffset(),t):e},u.local=function(){return n(this.toDate(),{locale:this.$L,utc:!1})};var r=u.parse;u.parse=function(t){t.utc&&(this.$u=!0),this.$utils().u(t.$offset)||(this.$offset=t.$offset),r.call(this,t)};var o=u.init;u.init=function(){if(this.$u){var t=this.$d;this.$y=t.getUTCFullYear(),this.$M=t.getUTCMonth(),this.$D=t.getUTCDate(),this.$W=t.getUTCDay(),this.$H=t.getUTCHours(),this.$m=t.getUTCMinutes(),this.$s=t.getUTCSeconds(),this.$ms=t.getUTCMilliseconds()}else o.call(this)};var a=u.utcOffset;u.utcOffset=function(s,f){var n=this.$utils().u;if(n(s))return this.$u?0:n(this.$offset)?a.call(this):this.$offset;if("string"==typeof s&&(s=function(t){void 0===t&&(t="");var s=t.match(i);if(!s)return null;var f=(""+s[0]).match(e)||["-",0,0],n=f[0],u=60*+f[1]+ +f[2];return 0===u?0:"+"===n?u:-u}(s),null===s))return this;var u=Math.abs(s)<=16?60*s:s;if(0===u)return this.utc(f);var r=this.clone();if(f)return r.$offset=u,r.$u=!1,r;var o=this.$u?this.toDate().getTimezoneOffset():-1*this.utcOffset();return(r=this.local().add(u+o,t)).$offset=u,r.$x.$localOffset=o,r};var h=u.format;u.format=function(t){var i=t||(this.$u?"YYYY-MM-DDTHH:mm:ss[Z]":"");return h.call(this,i)},u.valueOf=function(){var t=this.$utils().u(this.$offset)?0:this.$offset+(this.$x.$localOffset||this.$d.getTimezoneOffset());return this.$d.valueOf()-6e4*t},u.isUTC=function(){return!!this.$u},u.toISOString=function(){return this.toDate().toISOString()},u.toString=function(){return this.toDate().toUTCString()};var l=u.toDate;u.toDate=function(t){return"s"===t&&this.$offset?n(this.format("YYYY-MM-DD HH:mm:ss:SSS")).toDate():l.call(this)};var c=u.diff;u.diff=function(t,i,e){if(t&&this.$u===t.$u)return c.call(this,t,i,e);var s=this.local(),f=n(t).local();return c.call(s,f,i,e)}}})); /***/ }, /***/ 869 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * matchesSelector v2.0.2 * matchesSelector( element, '.selector' ) * MIT license */ /*jshint browser: true, strict: true, undef: true, unused: true */ ( function( window, factory ) { /*global define: false, module: false */ 'use strict'; // universal module definition if ( true ) { // AMD !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( window, function factory() { 'use strict'; var matchesMethod = ( function() { var ElemProto = window.Element.prototype; // check for the standard method name first if ( ElemProto.matches ) { return 'matches'; } // check un-prefixed if ( ElemProto.matchesSelector ) { return 'matchesSelector'; } // check vendor prefixes var prefixes = [ 'webkit', 'moz', 'ms', 'o' ]; for ( var i=0; i < prefixes.length; i++ ) { var prefix = prefixes[i]; var method = prefix + 'MatchesSelector'; if ( ElemProto[ method ] ) { return method; } } })(); return function matchesSelector( elem, selector ) { return elem[ matchesMethod ]( selector ); }; })); /***/ }, /***/ 240 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * EvEmitter v1.1.0 * Lil' event emitter * MIT License */ /* jshint unused: true, undef: true, strict: true */ ( function( global, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, window */ if ( true ) { // AMD - RequireJS !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( typeof window != 'undefined' ? window : this, function() { "use strict"; function EvEmitter() {} var proto = EvEmitter.prototype; proto.on = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // set events hash var events = this._events = this._events || {}; // set listeners array var listeners = events[ eventName ] = events[ eventName ] || []; // only add once if ( listeners.indexOf( listener ) == -1 ) { listeners.push( listener ); } return this; }; proto.once = function( eventName, listener ) { if ( !eventName || !listener ) { return; } // add event this.on( eventName, listener ); // set once flag // set onceEvents hash var onceEvents = this._onceEvents = this._onceEvents || {}; // set onceListeners object var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {}; // set flag onceListeners[ listener ] = true; return this; }; proto.off = function( eventName, listener ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } var index = listeners.indexOf( listener ); if ( index != -1 ) { listeners.splice( index, 1 ); } return this; }; proto.emitEvent = function( eventName, args ) { var listeners = this._events && this._events[ eventName ]; if ( !listeners || !listeners.length ) { return; } // copy over to avoid interference if .off() in listener listeners = listeners.slice(0); args = args || []; // once stuff var onceListeners = this._onceEvents && this._onceEvents[ eventName ]; for ( var i=0; i < listeners.length; i++ ) { var listener = listeners[i] var isOnce = onceListeners && onceListeners[ listener ]; if ( isOnce ) { // remove listener // remove before trigger to prevent recursion this.off( eventName, listener ); // unset once flag delete onceListeners[ listener ]; } // trigger listener listener.apply( this, args ); } return this; }; proto.allOff = function() { delete this._events; delete this._onceEvents; }; return EvEmitter; })); /***/ }, /***/ 346 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * Fizzy UI utils v2.0.7 * MIT license */ /*jshint browser: true, undef: true, unused: true, strict: true */ ( function( window, factory ) { // universal module definition /*jshint strict: false */ /*globals define, module, require */ if ( true ) { // AMD !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(869) ], __WEBPACK_AMD_DEFINE_RESULT__ = (function( matchesSelector ) { return factory( window, matchesSelector ); }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( window, function factory( window, matchesSelector ) { 'use strict'; var utils = {}; // ----- extend ----- // // extends objects utils.extend = function( a, b ) { for ( var prop in b ) { a[ prop ] = b[ prop ]; } return a; }; // ----- modulo ----- // utils.modulo = function( num, div ) { return ( ( num % div ) + div ) % div; }; // ----- makeArray ----- // var arraySlice = Array.prototype.slice; // turn element or nodeList into an array utils.makeArray = function( obj ) { if ( Array.isArray( obj ) ) { // use object if already an array return obj; } // return empty array if undefined or null. #6 if ( obj === null || obj === undefined ) { return []; } var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number'; if ( isArrayLike ) { // convert nodeList to array return arraySlice.call( obj ); } // array of single index return [ obj ]; }; // ----- removeFrom ----- // utils.removeFrom = function( ary, obj ) { var index = ary.indexOf( obj ); if ( index != -1 ) { ary.splice( index, 1 ); } }; // ----- getParent ----- // utils.getParent = function( elem, selector ) { while ( elem.parentNode && elem != document.body ) { elem = elem.parentNode; if ( matchesSelector( elem, selector ) ) { return elem; } } }; // ----- getQueryElement ----- // // use element as selector string utils.getQueryElement = function( elem ) { if ( typeof elem == 'string' ) { return document.querySelector( elem ); } return elem; }; // ----- handleEvent ----- // // enable .ontype to trigger from .addEventListener( elem, 'type' ) utils.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; // ----- filterFindElements ----- // utils.filterFindElements = function( elems, selector ) { // make array of elems elems = utils.makeArray( elems ); var ffElems = []; elems.forEach( function( elem ) { // check that elem is an actual element if ( !( elem instanceof HTMLElement ) ) { return; } // add elem if no selector if ( !selector ) { ffElems.push( elem ); return; } // filter & find items if we have a selector // filter if ( matchesSelector( elem, selector ) ) { ffElems.push( elem ); } // find children var childElems = elem.querySelectorAll( selector ); // concat childElems to filterFound array for ( var i=0; i < childElems.length; i++ ) { ffElems.push( childElems[i] ); } }); return ffElems; }; // ----- debounceMethod ----- // utils.debounceMethod = function( _class, methodName, threshold ) { threshold = threshold || 100; // original method var method = _class.prototype[ methodName ]; var timeoutName = methodName + 'Timeout'; _class.prototype[ methodName ] = function() { var timeout = this[ timeoutName ]; clearTimeout( timeout ); var args = arguments; var _this = this; this[ timeoutName ] = setTimeout( function() { method.apply( _this, args ); delete _this[ timeoutName ]; }, threshold ); }; }; // ----- docReady ----- // utils.docReady = function( callback ) { var readyState = document.readyState; if ( readyState == 'complete' || readyState == 'interactive' ) { // do async to allow for other scripts to run. metafizzy/flickity#441 setTimeout( callback ); } else { document.addEventListener( 'DOMContentLoaded', callback ); } }; // ----- htmlInit ----- // // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/ utils.toDashed = function( str ) { return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) { return $1 + '-' + $2; }).toLowerCase(); }; var console = window.console; /** * allow user to initialize classes via [data-namespace] or .js-namespace class * htmlInit( Widget, 'widgetName' ) * options are parsed from data-namespace-options */ utils.htmlInit = function( WidgetClass, namespace ) { utils.docReady( function() { var dashedNamespace = utils.toDashed( namespace ); var dataAttr = 'data-' + dashedNamespace; var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' ); var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace ); var elems = utils.makeArray( dataAttrElems ) .concat( utils.makeArray( jsDashElems ) ); var dataOptionsAttr = dataAttr + '-options'; var jQuery = window.jQuery; elems.forEach( function( elem ) { var attr = elem.getAttribute( dataAttr ) || elem.getAttribute( dataOptionsAttr ); var options; try { options = attr && JSON.parse( attr ); } catch ( error ) { // log error, do not initialize if ( console ) { console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className + ': ' + error ); } return; } // initialize var instance = new WidgetClass( elem, options ); // make available via $().data('namespace') if ( jQuery ) { jQuery.data( elem, namespace, instance ); } }); }); }; // ----- ----- // return utils; })); /***/ }, /***/ 928 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! * getSize v2.0.3 * measure size of elements * MIT license */ /* jshint browser: true, strict: true, undef: true, unused: true */ /* globals console: false */ ( function( window, factory ) { /* jshint strict: false */ /* globals define, module */ if ( true ) { // AMD !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} })( window, function factory() { 'use strict'; // -------------------------- helpers -------------------------- // // get a number from a string, not a percentage function getStyleSize( value ) { var num = parseFloat( value ); // not a percent like '100%', and a number var isValid = value.indexOf('%') == -1 && !isNaN( num ); return isValid && num; } function noop() {} var logError = typeof console == 'undefined' ? noop : function( message ) { console.error( message ); }; // -------------------------- measurements -------------------------- // var measurements = [ 'paddingLeft', 'paddingRight', 'paddingTop', 'paddingBottom', 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', 'borderLeftWidth', 'borderRightWidth', 'borderTopWidth', 'borderBottomWidth' ]; var measurementsLength = measurements.length; function getZeroSize() { var size = { width: 0, height: 0, innerWidth: 0, innerHeight: 0, outerWidth: 0, outerHeight: 0 }; for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; size[ measurement ] = 0; } return size; } // -------------------------- getStyle -------------------------- // /** * getStyle, get style of element, check for Firefox bug * https://bugzilla.mozilla.org/show_bug.cgi?id=548397 */ function getStyle( elem ) { var style = getComputedStyle( elem ); if ( !style ) { logError( 'Style returned ' + style + '. Are you running this code in a hidden iframe on Firefox? ' + 'See https://bit.ly/getsizebug1' ); } return style; } // -------------------------- setup -------------------------- // var isSetup = false; var isBoxSizeOuter; /** * setup * check isBoxSizerOuter * do on first getSize() rather than on page load for Firefox bug */ function setup() { // setup once if ( isSetup ) { return; } isSetup = true; // -------------------------- box sizing -------------------------- // /** * Chrome & Safari measure the outer-width on style.width on border-box elems * IE11 & Firefox<29 measures the inner-width */ var div = document.createElement('div'); div.style.width = '200px'; div.style.padding = '1px 2px 3px 4px'; div.style.borderStyle = 'solid'; div.style.borderWidth = '1px 2px 3px 4px'; div.style.boxSizing = 'border-box'; var body = document.body || document.documentElement; body.appendChild( div ); var style = getStyle( div ); // round value for browser zoom. desandro/masonry#928 isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200; getSize.isBoxSizeOuter = isBoxSizeOuter; body.removeChild( div ); } // -------------------------- getSize -------------------------- // function getSize( elem ) { setup(); // use querySeletor if elem is string if ( typeof elem == 'string' ) { elem = document.querySelector( elem ); } // do not proceed on non-objects if ( !elem || typeof elem != 'object' || !elem.nodeType ) { return; } var style = getStyle( elem ); // if hidden, everything is 0 if ( style.display == 'none' ) { return getZeroSize(); } var size = {}; size.width = elem.offsetWidth; size.height = elem.offsetHeight; var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box'; // get all measurements for ( var i=0; i < measurementsLength; i++ ) { var measurement = measurements[i]; var value = style[ measurement ]; var num = parseFloat( value ); // any 'auto', 'medium' value will be 0 size[ measurement ] = !isNaN( num ) ? num : 0; } var paddingWidth = size.paddingLeft + size.paddingRight; var paddingHeight = size.paddingTop + size.paddingBottom; var marginWidth = size.marginLeft + size.marginRight; var marginHeight = size.marginTop + size.marginBottom; var borderWidth = size.borderLeftWidth + size.borderRightWidth; var borderHeight = size.borderTopWidth + size.borderBottomWidth; var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter; // overwrite width and height if we can get it from style var styleWidth = getStyleSize( style.width ); if ( styleWidth !== false ) { size.width = styleWidth + // add padding and border unless it's already including it ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth ); } var styleHeight = getStyleSize( style.height ); if ( styleHeight !== false ) { size.height = styleHeight + // add padding and border unless it's already including it ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight ); } size.innerWidth = size.width - ( paddingWidth + borderWidth ); size.innerHeight = size.height - ( paddingHeight + borderHeight ); size.outerWidth = size.width + marginWidth; size.outerHeight = size.height + marginHeight; return size; } return getSize; }); /***/ }, /***/ 177 () { "use strict"; jsVectorMap.addMap("world",{insets:[{width:900,top:0,left:0,height:440.70631074413296,bbox:[{y:-12671671.123330014,x:-20004297.151525836},{y:6930392.025135122,x:20026572.39474939}]}],paths:{BD:{path:"M651.84,230.21l-0.6,-2.0l-1.36,-1.71l-2.31,-0.11l-0.41,0.48l0.2,0.94l-0.53,0.99l-0.72,-0.36l-0.68,0.35l-1.2,-0.36l-0.37,-2.0l-0.81,-1.86l0.39,-1.46l-0.22,-0.47l-1.14,-0.53l0.29,-0.5l1.48,-0.94l0.03,-0.65l-1.55,-1.22l0.55,-1.14l1.61,0.94l1.04,0.15l0.18,1.54l0.34,0.35l5.64,0.63l-0.84,1.64l-1.22,0.34l-0.77,1.51l0.07,0.47l1.37,1.37l0.67,-0.19l0.42,-1.39l1.21,3.84l-0.03,1.21l-0.33,-0.15l-0.4,0.28Z",name:"Bangladesh"},BE:{path:"M429.29,144.05l1.91,0.24l2.1,-0.63l2.63,1.99l-0.21,1.66l-0.69,0.4l-0.18,1.2l-1.66,-1.13l-1.39,0.15l-2.73,-2.7l-1.17,-0.18l-0.16,-0.52l1.54,-0.5Z",name:"Belgium"},BF:{path:"M421.42,247.64l-0.11,0.95l0.34,1.16l1.4,1.71l0.07,1.1l0.32,0.37l2.55,0.51l-0.04,1.28l-0.38,0.53l-1.07,0.21l-0.72,1.18l-0.63,0.21l-3.22,-0.25l-0.94,0.39l-5.4,-0.05l-0.39,0.38l0.16,2.73l-1.23,-0.43l-1.17,0.1l-0.89,0.57l-2.27,-1.72l-0.13,-1.11l0.61,-0.96l0.02,-0.93l1.87,-1.98l0.44,-1.81l0.43,-0.39l1.28,0.26l1.05,-0.52l0.47,-0.73l1.84,-1.09l0.55,-0.83l2.2,-1.0l1.15,-0.3l0.72,0.45l1.13,-0.01Z",name:"Burkina Faso"},BG:{path:"M491.65,168.18l-0.86,0.88l-0.91,2.17l0.48,1.34l-1.6,-0.24l-2.55,0.95l-0.28,1.51l-1.8,0.22l-2.0,-1.0l-1.92,0.79l-1.42,-0.07l-0.15,-1.63l-1.05,-0.97l0.0,-0.8l1.2,-1.57l0.01,-0.56l-1.14,-1.23l-0.05,-0.94l0.88,0.97l0.88,-0.2l1.91,0.47l3.68,0.16l1.42,-0.81l2.72,-0.66l2.55,1.24Z",name:"Bulgaria"},BA:{path:"M463.49,163.65l2.1,0.5l1.72,-0.03l1.52,0.68l-0.36,0.78l0.08,0.45l1.04,1.02l-0.25,0.98l-1.81,1.15l-0.38,1.38l-1.67,-0.87l-0.89,-1.2l-2.11,-1.83l-1.63,-2.22l0.23,-0.57l0.48,0.38l0.55,-0.06l0.43,-0.51l0.94,-0.06Z",name:"Bosnia and Herz."},BN:{path:"M707.48,273.58l0.68,-0.65l1.41,-0.91l-0.15,1.63l-0.81,-0.05l-0.61,0.58l-0.53,-0.6Z",name:"Brunei"},BO:{path:"M263.83,340.69l-3.09,-0.23l-0.38,0.23l-0.7,1.52l-1.31,-1.53l-3.28,-0.64l-2.37,2.4l-1.31,0.26l-0.88,-3.26l-1.3,-2.86l0.74,-2.37l-0.13,-0.43l-1.2,-1.01l-0.37,-1.89l-1.08,-1.55l1.45,-2.56l-0.96,-2.33l0.47,-1.06l-0.34,-0.73l0.91,-1.32l0.16,-3.84l0.5,-1.18l-1.81,-3.41l2.46,0.07l0.8,-0.85l3.4,-1.91l2.66,-0.35l-0.19,1.38l0.3,1.07l-0.05,1.97l2.72,2.27l2.88,0.49l0.89,0.86l1.79,0.58l0.98,0.7l1.71,0.05l1.17,0.61l0.6,2.7l-0.7,0.54l0.96,2.99l0.37,0.28l4.3,0.1l-0.25,1.2l0.27,1.02l1.43,0.9l0.5,1.35l-0.41,1.86l-0.65,1.08l0.12,1.35l-2.69,-1.65l-2.4,-0.03l-4.36,0.76l-1.49,2.5l-0.11,1.52l-0.75,2.37Z",name:"Bolivia"},JP:{path:"M781.12,166.87l1.81,0.68l1.62,-0.97l0.39,2.42l-3.35,0.75l-2.23,2.88l-3.63,-1.9l-0.56,0.2l-1.26,3.05l-2.16,0.03l-0.29,-2.51l1.08,-2.03l2.45,-0.16l0.37,-0.33l1.25,-5.94l2.47,2.71l2.03,1.12ZM773.56,187.34l-0.91,2.22l0.37,1.52l-1.14,1.75l-3.02,1.26l-4.58,0.27l-3.34,3.01l-1.25,-0.8l-0.09,-1.9l-0.46,-0.38l-4.35,0.62l-3.0,1.32l-2.85,0.05l-0.37,0.27l0.13,0.44l2.32,1.89l-1.54,4.34l-1.26,0.9l-0.79,-0.7l0.56,-2.27l-0.21,-0.45l-1.47,-0.75l-0.74,-1.4l2.12,-0.84l1.26,-1.7l2.45,-1.42l1.83,-1.91l4.78,-0.81l2.6,0.57l0.44,-0.21l2.39,-4.66l1.29,1.06l0.5,0.01l5.1,-4.02l1.69,-3.73l-0.38,-3.4l0.9,-1.61l2.14,-0.44l1.23,3.72l-0.07,2.18l-2.23,2.84l-0.04,3.16ZM757.78,196.26l0.19,0.56l-1.01,1.21l-1.16,-0.68l-1.28,0.65l-0.69,1.45l-1.02,-0.5l0.01,-0.93l1.14,-1.38l1.57,0.14l0.85,-0.98l1.4,0.46Z",name:"Japan"},BI:{path:"M495.45,295.49l-1.08,-2.99l1.14,-0.11l0.64,-1.19l0.76,0.09l0.65,1.83l-2.1,2.36Z",name:"Burundi"},BJ:{path:"M429.57,255.75l-0.05,0.8l0.5,1.34l-0.42,0.86l0.17,0.79l-1.81,2.12l-0.57,1.76l-0.08,5.42l-1.41,0.2l-0.48,-1.36l0.11,-5.71l-0.52,-0.7l-0.2,-1.35l-1.48,-1.48l0.21,-0.9l0.89,-0.43l0.42,-0.92l1.27,-0.36l1.22,-1.34l0.61,-0.0l1.62,1.24Z",name:"Benin"},BT:{path:"M650.32,213.86l0.84,0.71l-0.12,1.1l-3.76,-0.11l-1.57,0.4l-1.93,-0.87l1.48,-1.96l1.13,-0.57l1.63,0.57l1.33,0.08l0.99,0.65Z",name:"Bhutan"},JM:{path:"M228.38,239.28l-0.8,0.4l-2.26,-1.06l0.84,-0.23l2.14,0.3l1.17,0.56l-1.08,0.03Z",name:"Jamaica"},BW:{path:"M483.92,330.07l2.27,4.01l2.83,2.86l0.96,0.31l0.78,2.43l2.13,0.61l1.02,0.76l-3.0,1.64l-2.32,2.02l-1.54,2.69l-1.52,0.45l-0.64,1.94l-1.34,0.52l-1.85,-0.12l-1.21,-0.74l-1.35,-0.3l-1.22,0.62l-0.75,1.37l-2.31,1.9l-1.4,0.21l-0.35,-0.59l0.16,-1.75l-1.48,-2.54l-0.62,-0.43l-0.0,-7.1l2.08,-0.08l0.39,-0.4l0.07,-8.9l5.19,-0.93l0.8,0.89l0.51,0.07l1.5,-0.95l2.21,-0.49Z",name:"Botswana"},BR:{path:"M259.98,275.05l3.24,0.7l0.65,-0.53l4.55,-1.32l1.08,-1.06l-0.02,-0.63l0.55,-0.05l0.28,0.28l-0.26,0.87l0.22,0.48l0.73,0.32l0.4,0.81l-0.62,0.86l-0.4,2.13l0.82,2.56l1.69,1.43l1.43,0.2l3.17,-1.68l3.18,0.3l0.65,-0.75l-0.27,-0.92l1.9,-0.09l2.39,0.99l1.06,-0.61l0.84,0.78l1.2,-0.18l1.18,-1.06l0.84,-1.94l1.36,-2.11l0.37,-0.05l1.89,5.45l1.33,0.59l0.05,1.28l-1.77,1.94l0.02,0.56l1.02,0.87l4.07,0.36l0.08,2.16l0.66,0.29l1.74,-1.5l6.97,2.32l1.02,1.22l-0.35,1.18l0.49,0.5l2.81,-0.74l4.77,1.3l3.75,-0.08l3.57,2.0l3.29,2.86l1.93,0.72l2.12,0.12l0.71,0.62l1.21,4.51l-0.95,3.98l-4.72,5.06l-1.64,2.92l-1.72,2.05l-0.8,0.3l-0.72,2.03l0.18,4.75l-0.94,5.53l-0.81,1.13l-0.43,3.36l-2.55,3.5l-0.4,2.51l-1.86,1.04l-0.67,1.53l-2.54,0.01l-3.94,1.01l-1.83,1.2l-2.87,0.82l-3.03,2.19l-2.2,2.83l-0.36,2.0l0.4,1.58l-0.44,2.6l-0.51,1.2l-1.77,1.54l-2.75,4.78l-3.83,3.42l-1.24,2.74l-1.18,1.15l-0.36,-0.83l0.95,-1.14l0.01,-0.5l-1.52,-1.97l-4.56,-3.32l-1.03,-0.0l-2.38,-2.02l-0.81,-0.0l5.34,-5.45l3.77,-2.58l0.22,-2.46l-1.35,-1.81l-0.91,0.07l0.58,-2.33l0.01,-1.54l-1.11,-0.83l-1.75,0.3l-0.44,-3.11l-0.52,-0.95l-1.88,-0.88l-1.24,0.47l-2.17,-0.41l0.15,-3.21l-0.62,-1.34l0.66,-0.73l-0.22,-1.34l0.66,-1.13l0.44,-2.04l-0.61,-1.83l-1.4,-0.86l-0.2,-0.75l0.34,-1.39l-0.38,-0.5l-4.52,-0.1l-0.72,-2.22l0.59,-0.42l-0.03,-1.1l-0.5,-0.87l-0.32,-1.7l-1.45,-0.76l-1.63,-0.02l-1.05,-0.72l-1.6,-0.48l-1.13,-0.99l-2.69,-0.4l-2.47,-2.06l0.13,-4.35l-0.45,-0.45l-3.46,0.5l-3.44,1.94l-0.6,0.74l-2.9,-0.17l-1.47,0.42l-0.72,-0.18l0.15,-3.52l-0.63,-0.34l-1.94,1.41l-1.87,-0.06l-0.83,-1.18l-1.37,-0.26l0.21,-1.01l-1.35,-1.49l-0.88,-1.91l0.56,-0.6l-0.0,-0.81l1.29,-0.62l0.22,-0.43l-0.22,-1.19l0.61,-0.91l0.15,-0.99l2.65,-1.58l1.99,-0.47l0.42,-0.36l2.06,0.11l0.42,-0.33l1.19,-8.0l-0.41,-1.56l-1.1,-1.0l0.01,-1.33l1.91,-0.42l0.08,-0.96l-0.33,-0.43l-1.14,-0.2l-0.02,-0.83l4.47,0.05l0.82,-0.67l0.82,1.81l0.8,0.07l1.15,1.1l2.26,-0.05l0.71,-0.83l2.78,-0.96l0.48,-1.13l1.6,-0.64l0.24,-0.47l-0.48,-0.82l-1.83,-0.19l-0.36,-3.22Z",name:"Brazil"},BS:{path:"M226.4,223.87l-0.48,-1.15l-0.84,-0.75l0.36,-1.11l0.95,1.95l0.01,1.06ZM225.56,216.43l-1.87,0.29l-0.04,-0.22l0.74,-0.14l1.17,0.06Z",name:"Bahamas"},BY:{path:"M493.84,128.32l0.29,0.7l0.49,0.23l1.19,-0.38l2.09,0.72l0.19,1.26l-0.45,1.24l1.57,2.26l0.89,0.59l0.17,0.81l1.58,0.56l0.4,0.5l-0.53,0.41l-1.87,-0.11l-0.73,0.38l-0.13,0.52l1.04,2.74l-1.91,0.26l-0.89,0.99l-0.11,1.18l-2.73,-0.04l-0.53,-0.62l-0.52,-0.08l-0.75,0.46l-0.91,-0.42l-1.92,-0.07l-2.75,-0.79l-2.6,-0.28l-2.0,0.07l-1.5,0.92l-0.67,0.07l-0.08,-1.22l-0.59,-1.19l1.36,-0.88l0.01,-1.35l-0.7,-1.41l-0.07,-1.0l2.16,-0.02l2.72,-1.3l0.75,-2.04l1.91,-1.04l0.2,-0.41l-0.19,-1.25l3.8,-1.78l2.3,0.77Z",name:"Belarus"},BZ:{path:"M198.03,244.38l0.1,-4.49l0.69,-0.06l0.74,-1.3l0.34,0.28l-0.4,1.3l0.17,0.58l-0.34,2.25l-1.3,1.42Z",name:"Belize"},RU:{path:"M491.55,115.25l2.55,-1.85l-0.01,-0.65l-2.2,-1.5l7.32,-6.76l1.03,-2.11l-0.13,-0.49l-3.46,-2.52l0.86,-2.7l-2.11,-2.81l1.56,-3.67l-2.77,-4.52l2.15,-2.99l-0.08,-0.55l-3.65,-2.73l0.3,-2.54l1.81,-0.37l4.26,-1.77l2.42,-1.45l4.06,2.61l6.79,1.04l9.34,4.85l1.78,1.88l0.14,2.46l-2.55,2.02l-3.9,1.06l-11.07,-3.14l-2.06,0.53l-0.13,0.7l3.94,2.94l0.31,5.86l0.26,0.36l5.14,2.24l0.58,-0.29l0.32,-1.94l-1.35,-1.78l1.13,-1.09l6.13,2.42l2.11,-0.98l0.18,-0.56l-1.51,-2.67l5.41,-3.76l2.07,0.22l2.26,1.41l0.57,-0.16l1.46,-2.87l-0.05,-0.44l-1.92,-2.32l1.12,-2.32l-1.32,-2.27l5.87,1.16l1.04,1.75l-2.59,0.43l-0.33,0.4l0.02,2.36l2.46,1.83l3.87,-0.91l0.86,-2.8l13.69,-5.65l0.99,0.11l-1.92,2.06l0.23,0.67l3.11,0.45l2.0,-1.48l4.56,-0.12l3.64,-1.73l2.65,2.44l0.56,-0.01l2.85,-2.88l-0.01,-0.57l-2.35,-2.29l0.9,-1.01l7.14,1.3l3.41,1.36l9.05,4.97l0.51,-0.11l1.67,-2.27l-0.05,-0.53l-2.43,-2.21l-0.06,-0.78l-0.34,-0.36l-2.52,-0.36l0.64,-1.93l-1.32,-3.46l-0.06,-1.21l4.48,-4.06l1.69,-4.29l1.6,-0.81l6.23,1.18l0.44,2.21l-2.29,3.64l0.06,0.5l1.47,1.39l0.76,3.0l-0.56,6.03l2.69,2.82l-0.96,2.57l-4.86,5.95l0.23,0.64l2.86,0.61l0.42,-0.17l0.93,-1.4l2.64,-1.03l0.87,-2.24l2.09,-1.96l0.07,-0.5l-1.36,-2.28l1.09,-2.69l-0.32,-0.55l-2.47,-0.33l-0.5,-2.06l1.94,-4.38l-0.06,-0.42l-2.96,-3.4l4.12,-2.88l0.16,-0.4l-0.51,-2.93l0.54,-0.05l1.13,2.25l-0.96,4.35l0.27,0.47l2.68,0.84l0.5,-0.51l-1.02,-2.99l3.79,-1.66l5.01,-0.24l4.53,2.61l0.48,-0.06l0.07,-0.48l-2.18,-3.82l-0.23,-4.67l3.98,-0.9l5.97,0.21l5.49,-0.64l0.27,-0.65l-1.83,-2.31l2.56,-2.9l2.87,-0.17l4.8,-2.47l6.54,-0.67l1.03,-1.42l6.25,-0.45l2.32,1.11l5.53,-2.7l4.5,0.08l0.39,-0.28l0.66,-2.15l2.26,-2.12l5.69,-2.11l3.21,1.29l-2.46,0.94l-0.25,0.42l0.34,0.35l5.41,0.77l0.61,2.33l0.58,0.25l2.2,-1.22l7.13,0.07l5.51,2.47l1.79,1.72l-0.53,2.24l-9.16,4.15l-1.97,1.52l0.16,0.71l6.77,1.91l2.16,-0.78l1.13,2.74l0.67,0.11l1.01,-1.15l3.81,-0.73l7.7,0.77l0.54,1.99l0.36,0.29l10.47,0.71l0.43,-0.38l0.13,-3.23l4.87,0.78l3.95,-0.02l3.83,2.4l1.03,2.71l-1.35,1.79l0.02,0.5l3.15,3.64l4.07,1.96l0.53,-0.18l2.23,-4.47l3.95,1.93l4.16,-1.21l4.73,1.39l2.05,-1.26l3.94,0.62l0.43,-0.55l-1.68,-4.02l2.89,-1.8l22.31,3.03l2.16,2.75l6.55,3.51l10.29,-0.81l4.82,0.73l1.85,1.66l-0.29,3.08l0.25,0.41l3.08,1.26l3.56,-0.88l4.35,-0.11l4.8,0.87l4.57,-0.47l4.23,3.79l0.43,0.07l3.1,-1.4l0.16,-0.6l-1.88,-2.62l0.85,-1.52l7.71,1.21l5.22,-0.26l7.09,2.09l9.59,5.22l6.35,4.11l-0.2,2.38l1.88,1.41l0.6,-0.42l-0.48,-2.53l6.15,0.57l4.4,3.51l-1.97,1.43l-4.0,0.41l-0.36,0.39l-0.06,3.79l-0.74,0.62l-2.07,-0.11l-1.91,-1.39l-3.14,-1.11l-0.78,-1.85l-2.72,-0.68l-2.63,0.49l-1.04,-1.1l0.46,-1.31l-0.5,-0.51l-3.0,0.98l-0.22,0.58l0.99,1.7l-1.21,1.48l-3.04,1.68l-3.12,-0.28l-0.4,0.23l0.09,0.46l2.2,2.09l1.46,3.2l1.15,1.1l0.24,1.33l-0.42,0.67l-4.63,-0.77l-6.96,2.9l-2.19,0.44l-7.6,5.06l-0.84,1.45l-3.61,-2.37l-6.24,2.82l-0.94,-1.15l-0.53,-0.08l-2.28,1.52l-3.2,-0.49l-0.44,0.27l-0.78,2.37l-3.05,3.78l0.09,1.47l0.29,0.36l2.54,0.72l-0.29,4.53l-1.97,0.11l-0.35,0.26l-1.07,2.94l0.8,1.45l-3.91,1.58l-1.05,3.95l-3.48,0.77l-0.3,0.3l-0.72,3.29l-3.09,2.65l-0.7,-1.74l-2.44,-12.44l1.16,-4.71l2.04,-2.06l0.22,-1.64l3.8,-0.86l4.46,-4.61l4.28,-3.81l4.48,-3.01l2.17,-5.63l-0.42,-0.54l-3.04,0.33l-1.77,3.31l-5.86,3.86l-1.86,-4.25l-0.45,-0.23l-6.46,1.3l-6.47,6.44l-0.01,0.55l1.58,1.74l-8.24,1.17l0.15,-2.2l-0.34,-0.42l-3.89,-0.56l-3.25,1.81l-7.62,-0.62l-8.45,1.19l-17.71,15.41l0.22,0.7l3.74,0.41l1.36,2.17l2.43,0.76l1.88,-1.68l2.4,0.2l3.4,3.54l0.08,2.6l-1.95,3.42l-0.21,3.9l-1.1,5.06l-3.71,4.54l-0.87,2.21l-8.29,8.89l-3.19,1.7l-1.32,0.03l-1.45,-1.36l-0.49,-0.04l-2.27,1.5l0.41,-3.65l-0.59,-2.47l1.75,-0.89l2.91,0.53l0.42,-0.2l1.68,-3.03l0.87,-3.46l0.97,-1.18l1.32,-2.88l-0.45,-0.56l-4.14,0.95l-2.19,1.25l-3.41,-0.0l-1.06,-2.93l-2.97,-2.3l-4.28,-1.06l-1.75,-5.07l-2.66,-5.01l-2.29,-1.29l-3.75,-1.01l-3.44,0.08l-3.18,0.62l-2.24,1.77l0.05,0.66l1.18,0.69l0.02,1.43l-1.33,1.05l-2.26,3.51l-0.04,1.43l-3.16,1.84l-2.82,-1.16l-3.01,0.23l-1.35,-1.07l-1.5,-0.35l-3.9,2.31l-3.22,0.52l-2.27,0.79l-3.05,-0.51l-2.21,0.03l-1.48,-1.6l-2.6,-1.63l-2.63,-0.43l-5.46,1.01l-3.23,-1.25l-0.72,-2.57l-5.2,-1.24l-2.75,-1.36l-0.5,0.12l-2.59,3.45l0.84,2.1l-2.06,1.93l-3.41,-0.77l-2.42,-0.12l-1.83,-1.54l-2.53,-0.05l-2.42,-0.98l-3.86,1.57l-4.72,2.78l-3.3,0.75l-1.55,-1.92l-3.0,0.41l-1.11,-1.33l-1.62,-0.59l-1.31,-1.94l-1.38,-0.6l-3.7,0.79l-3.31,-1.83l-0.51,0.11l-0.99,1.29l-5.29,-8.05l-2.96,-2.48l0.65,-0.77l0.01,-0.51l-0.5,-0.11l-6.2,3.21l-1.84,0.15l0.15,-1.39l-0.26,-0.42l-3.22,-1.17l-2.46,0.7l-0.69,-3.16l-0.32,-0.31l-4.5,-0.75l-2.47,1.47l-6.19,1.27l-1.29,0.86l-9.51,1.3l-1.15,1.17l-0.03,0.53l1.47,1.9l-1.89,0.69l-0.22,0.56l0.31,0.6l-2.11,1.44l0.03,0.68l3.75,2.12l-0.39,0.98l-3.23,-0.13l-0.86,0.86l-3.09,-1.59l-3.97,0.07l-2.66,1.35l-8.32,-3.56l-4.07,0.06l-5.39,3.68l-0.39,2.0l-2.03,-1.5l-0.59,0.13l-2.0,3.59l0.57,0.93l-1.28,2.16l0.06,0.48l2.13,2.17l1.95,0.04l1.37,1.82l-0.23,1.46l0.25,0.43l0.83,0.33l-0.8,1.31l-2.49,0.62l-2.49,3.2l0.0,0.49l2.17,2.78l-0.15,2.18l2.5,3.24l-1.58,1.59l-0.7,-0.13l-1.63,-1.72l-2.29,-0.84l-0.94,-1.31l-2.34,-0.63l-1.48,0.4l-0.43,-0.47l-3.51,-1.48l-5.76,-1.01l-0.45,0.19l-2.89,-2.34l-2.9,-1.2l-1.53,-1.29l1.29,-0.43l2.08,-2.61l-0.05,-0.55l-0.89,-0.79l3.05,-1.06l0.27,-0.42l-0.07,-0.69l-0.49,-0.35l-1.73,0.39l0.04,-0.68l1.04,-0.72l2.66,-0.48l0.4,-1.32l-0.5,-1.6l0.92,-1.54l0.03,-1.17l-0.29,-0.37l-3.69,-1.06l-1.41,0.02l-1.42,-1.41l-2.19,0.38l-2.77,-1.01l-0.03,-0.59l-0.89,-1.43l-2.0,-0.32l-0.11,-0.54l0.49,-0.53l0.01,-0.53l-1.6,-1.9l-3.58,0.02l-0.88,0.73l-0.46,-0.07l-1.0,-2.79l2.22,-0.02l0.97,-0.74l0.07,-0.57l-0.9,-1.04l-1.35,-0.48l-0.11,-0.7l-0.95,-0.58l-1.38,-1.99l0.46,-0.98l-0.51,-1.96l-2.45,-0.84l-1.21,0.3l-0.46,-0.76l-2.46,-0.83l-0.72,-1.87l-0.21,-1.69l-0.99,-0.85l0.85,-1.17l-0.7,-3.21l1.66,-1.97l-0.16,-0.79ZM749.2,170.72l-0.6,0.4l-0.13,0.16l-0.01,-0.51l0.74,-0.05ZM874.85,67.94l-5.63,0.48l-0.26,-0.84l3.15,-1.89l1.94,0.01l3.19,1.16l-2.39,1.09ZM797.39,48.49l-2.0,1.36l-3.8,-0.42l-4.25,-1.8l0.35,-0.97l9.69,1.83ZM783.67,46.12l-1.63,3.09l-8.98,-0.13l-4.09,1.14l-4.54,-2.97l1.16,-3.01l3.05,-0.89l6.5,0.22l8.54,2.56ZM778.2,134.98l-0.56,-0.9l0.27,-0.12l0.29,1.01ZM778.34,135.48l0.94,3.53l-0.05,3.38l1.05,3.39l2.18,5.0l-2.89,-0.83l-0.49,0.26l-1.54,4.65l2.42,3.5l-0.04,1.13l-1.24,-1.24l-0.61,0.06l-1.09,1.61l-0.28,-1.61l0.27,-3.1l-0.28,-3.4l0.58,-2.47l0.11,-4.39l-1.46,-3.36l0.21,-4.32l2.15,-1.46l0.07,-0.34ZM771.95,56.61l1.76,-1.42l2.89,-0.42l3.28,1.71l0.14,0.6l-3.27,0.03l-4.81,-0.5ZM683.76,31.09l-13.01,1.93l4.03,-6.35l1.82,-0.56l1.73,0.34l5.99,2.98l-0.56,1.66ZM670.85,27.93l-5.08,0.64l-6.86,-1.57l-3.99,-2.05l-2.1,-4.16l-2.6,-0.87l5.72,-3.5l5.2,-1.28l4.69,2.85l5.59,5.4l-0.56,4.53ZM564.15,68.94l-0.64,0.17l-7.85,-0.57l-0.86,-2.04l-4.28,-1.17l-0.28,-1.94l2.27,-0.89l0.25,-0.39l-0.08,-2.38l4.81,-3.97l-0.15,-0.7l-1.47,-0.38l5.3,-3.81l0.15,-0.44l-0.58,-1.94l5.28,-2.51l8.21,-3.27l8.28,-0.96l4.35,-1.94l4.6,-0.64l1.36,1.61l-1.34,1.28l-16.43,4.94l-7.97,4.88l-7.74,9.63l0.66,4.14l4.16,3.27ZM548.81,18.48l-5.5,1.18l-0.58,1.02l-2.59,0.84l-2.13,-1.07l1.12,-1.42l-0.3,-0.65l-2.33,-0.07l1.68,-0.36l3.47,-0.06l0.42,1.29l0.66,0.16l1.38,-1.34l2.15,-0.88l2.94,1.01l-0.39,0.36ZM477.37,133.15l-4.08,0.05l-2.56,-0.32l0.33,-0.87l3.17,-1.03l3.24,0.96l-0.09,1.23Z",name:"Russia"},RW:{path:"M497.0,288.25l0.71,1.01l-0.11,1.09l-1.63,0.03l-1.04,1.39l-0.83,-0.11l0.51,-1.2l0.08,-1.34l0.42,-0.41l0.7,0.14l1.19,-0.61Z",name:"Rwanda"},RS:{path:"M469.4,163.99l0.42,-0.5l-0.01,-0.52l-1.15,-1.63l1.43,-0.62l1.33,0.12l1.17,1.06l0.46,1.13l1.34,0.64l0.35,1.35l1.46,0.9l0.76,-0.29l0.2,0.69l-0.48,0.78l0.22,1.12l1.05,1.22l-0.77,0.8l-0.37,1.52l-1.21,0.08l0.24,-0.64l-0.39,-0.54l-2.08,-1.64l-0.9,0.05l-0.48,0.94l-2.12,-1.37l0.53,-1.6l-1.11,-1.37l0.51,-1.1l-0.41,-0.57Z",name:"Serbia"},LT:{path:"M486.93,129.3l0.17,1.12l-1.81,0.98l-0.72,2.02l-2.47,1.18l-2.1,-0.02l-0.73,-1.05l-1.06,-0.3l-0.09,-1.87l-3.56,-1.13l-0.43,-2.36l2.48,-0.94l4.12,0.22l2.25,-0.31l0.52,0.69l1.24,0.21l2.19,1.56Z",name:"Lithuania"},LU:{path:"M436.08,149.45l-0.48,-0.07l0.3,-1.28l0.27,0.4l-0.09,0.96Z",name:"Luxembourg"},LR:{path:"M399.36,265.97l0.18,1.54l-0.48,0.99l0.08,0.47l2.47,1.8l-0.33,2.8l-2.65,-1.13l-5.78,-4.61l0.58,-1.32l2.1,-2.33l0.86,-0.22l0.77,1.14l-0.14,0.85l0.59,0.87l1.0,0.14l0.76,-0.99Z",name:"Liberia"},RO:{path:"M487.53,154.23l0.6,0.24l2.87,3.98l-0.17,2.69l0.45,1.42l1.32,0.81l1.35,-0.42l0.76,0.36l0.02,0.31l-0.83,0.45l-0.59,-0.22l-0.54,0.3l-0.62,3.3l-1.0,-0.22l-2.07,-1.13l-2.95,0.71l-1.25,0.76l-3.51,-0.15l-1.89,-0.47l-0.87,0.16l-0.82,-1.3l0.29,-0.26l-0.06,-0.64l-1.09,-0.34l-0.56,0.5l-1.05,-0.64l-0.39,-1.39l-1.36,-0.65l-0.35,-1.0l-0.83,-0.75l1.54,-0.54l2.66,-4.21l2.4,-1.24l2.96,0.34l1.48,0.73l0.79,-0.45l1.78,-0.3l0.75,-0.74l0.79,0.0Z",name:"Romania"},GW:{path:"M386.23,253.6l-0.29,0.84l0.15,0.6l-2.21,0.59l-0.86,0.96l-1.04,-0.83l-1.09,-0.23l-0.54,-1.06l-0.66,-0.49l2.41,-0.48l4.13,0.1Z",name:"Guinea-Bissau"},GT:{path:"M195.08,249.77l-2.48,-0.37l-1.03,-0.45l-1.14,-0.89l0.3,-0.99l-0.24,-0.68l0.96,-1.66l2.98,-0.01l0.4,-0.37l-0.19,-1.28l-1.67,-1.4l0.51,-0.4l0.0,-1.05l3.85,0.02l-0.21,4.53l0.4,0.43l1.46,0.38l-1.48,0.98l-0.35,0.7l0.12,0.57l-2.2,1.96Z",name:"Guatemala"},GR:{path:"M487.07,174.59l-0.59,1.43l-0.37,0.21l-2.84,-0.35l-3.03,0.77l-0.18,0.68l1.28,1.23l-0.61,0.23l-1.14,0.0l-1.2,-1.39l-0.63,0.03l-0.53,1.01l0.56,1.76l1.03,1.19l-0.56,0.38l-0.05,0.62l2.52,2.12l0.02,0.87l-1.78,-0.59l-0.48,0.56l0.5,1.0l-1.07,0.2l-0.3,0.53l0.75,2.01l-0.98,0.02l-1.84,-1.12l-1.37,-4.2l-2.21,-2.95l-0.11,-0.56l1.04,-1.28l0.2,-0.95l0.85,-0.66l0.03,-0.46l1.32,-0.21l1.01,-0.64l1.22,0.05l0.65,-0.56l2.26,-0.0l1.82,-0.75l1.85,1.0l2.28,-0.28l0.35,-0.39l0.01,-0.77l0.34,0.22ZM480.49,192.16l0.58,0.4l-0.68,-0.12l0.11,-0.28ZM482.52,192.82l2.51,0.06l0.24,0.32l-1.99,0.13l-0.77,-0.51Z",name:"Greece"},GQ:{path:"M448.79,279.62l0.02,2.22l-4.09,0.0l0.69,-2.27l3.38,0.05Z",name:"Eq. Guinea"},GY:{path:"M277.42,270.07l-0.32,1.83l-1.32,0.57l-0.23,0.46l-0.28,2.0l1.11,1.82l0.83,0.19l0.32,1.25l1.13,1.62l-1.21,-0.19l-1.08,0.71l-1.77,0.5l-0.44,0.46l-0.86,-0.09l-1.32,-1.01l-0.77,-2.27l0.36,-1.9l0.68,-1.23l-0.57,-1.17l-0.74,-0.43l0.12,-1.16l-0.9,-0.69l-1.1,0.09l-1.31,-1.48l0.53,-0.72l-0.04,-0.84l1.99,-0.86l0.05,-0.59l-0.71,-0.78l0.14,-0.57l1.66,-1.24l1.36,0.77l1.41,1.49l0.06,1.15l0.37,0.38l0.8,0.05l2.06,1.86Z",name:"Guyana"},GE:{path:"M521.71,168.93l5.29,0.89l4.07,2.01l1.41,-0.44l2.07,0.56l0.68,1.1l1.07,0.55l-0.12,0.59l0.98,1.29l-1.01,-0.13l-1.81,-0.83l-0.94,0.47l-3.23,0.43l-2.29,-1.39l-2.33,0.05l0.21,-0.97l-0.76,-2.26l-1.45,-1.12l-1.43,-0.39l-0.41,-0.42Z",name:"Georgia"},GB:{path:"M412.61,118.72l-2.19,3.22l-0.0,0.45l5.13,-0.3l-0.53,2.37l-2.2,3.12l0.29,0.63l2.37,0.21l2.33,4.3l1.76,0.69l2.2,5.12l2.94,0.77l-0.23,1.62l-1.15,0.88l-0.1,0.52l0.82,1.42l-1.86,1.43l-3.3,-0.02l-4.12,0.87l-1.04,-0.58l-0.47,0.06l-1.51,1.41l-2.12,-0.34l-1.86,1.18l-0.6,-0.29l3.19,-3.0l2.16,-0.69l0.28,-0.41l-0.34,-0.36l-3.73,-0.53l-0.4,-0.76l2.2,-0.87l0.17,-0.61l-1.26,-1.67l0.36,-1.7l3.38,0.28l0.43,-0.33l0.37,-1.99l-1.79,-2.49l-3.11,-0.72l-0.38,-0.59l0.79,-1.35l-0.04,-0.46l-0.82,-0.97l-0.61,0.01l-0.68,0.84l-0.1,-2.34l-1.23,-1.88l0.85,-3.47l1.77,-2.68l1.85,0.26l2.17,-0.22ZM406.26,132.86l-1.01,1.77l-1.57,-0.59l-1.16,0.01l0.37,-1.54l-0.39,-1.39l1.45,-0.1l2.3,1.84Z",name:"United Kingdom"},GA:{path:"M453.24,279.52l-0.08,0.98l0.7,1.29l2.36,0.24l-0.98,2.63l1.18,1.79l0.25,1.78l-0.29,1.52l-0.6,0.93l-1.84,-0.09l-1.23,-1.11l-0.66,0.23l-0.15,0.84l-1.42,0.26l-1.02,0.7l-0.11,0.52l0.77,1.35l-1.34,0.97l-3.94,-4.3l-1.44,-2.45l0.06,-0.6l0.54,-0.81l1.05,-3.46l4.17,-0.07l0.4,-0.4l-0.02,-2.66l2.39,0.21l1.25,-0.27Z",name:"Gabon"},GN:{path:"M391.8,254.11l0.47,0.8l1.11,-0.32l0.98,0.7l1.07,0.2l2.26,-1.22l0.64,0.44l1.13,1.56l-0.48,1.4l0.8,0.3l-0.08,0.48l0.46,0.68l-0.35,1.36l1.05,2.61l-1.0,0.69l0.03,1.41l-0.72,-0.06l-1.08,1.0l-0.24,-0.27l0.07,-1.11l-1.05,-1.54l-1.79,0.21l-0.35,-2.01l-1.6,-2.18l-2.0,-0.0l-1.31,0.54l-1.95,2.18l-1.86,-2.19l-1.2,-0.78l-0.3,-1.11l-0.8,-0.85l0.65,-0.72l0.81,-0.03l1.64,-0.8l0.23,-1.87l2.67,0.64l0.89,-0.3l1.21,0.15Z",name:"Guinea"},GM:{path:"M379.31,251.39l0.1,-0.35l2.43,-0.07l0.74,-0.61l0.51,-0.03l0.77,0.49l-1.03,-0.3l-1.87,0.9l-1.65,-0.04ZM384.03,250.91l0.91,0.05l0.75,-0.24l-0.59,0.31l-1.08,-0.13Z",name:"Gambia"},GL:{path:"M353.02,1.2l14.69,4.67l-3.68,1.89l-22.97,0.86l-0.36,0.27l0.12,0.43l1.55,1.18l8.79,-0.66l7.48,2.07l4.86,-1.77l1.66,1.73l-2.53,3.19l-0.01,0.48l0.46,0.15l6.35,-2.2l12.06,-2.31l7.24,1.13l1.09,1.99l-9.79,4.01l-1.44,1.32l-7.87,0.98l-0.35,0.41l0.38,0.38l5.07,0.24l-2.53,3.58l-2.07,3.81l0.08,6.05l2.57,3.11l-3.22,0.2l-4.12,1.66l-0.05,0.72l4.45,2.65l0.51,3.75l-2.3,0.4l-0.25,0.64l2.79,3.69l-4.82,0.31l-0.36,0.29l0.16,0.44l2.62,1.8l-0.59,1.22l-3.3,0.7l-3.45,0.01l-0.29,0.68l3.03,3.12l0.02,1.34l-4.4,-1.73l-1.72,1.35l0.15,0.66l3.31,1.15l3.13,2.71l0.81,3.16l-3.85,0.75l-4.89,-4.26l-0.47,-0.03l-0.17,0.44l0.79,2.86l-2.71,2.21l-0.13,0.44l0.37,0.27l8.73,0.34l-12.32,6.64l-7.24,1.48l-2.94,0.08l-2.69,1.75l-3.43,4.41l-5.24,2.84l-1.73,0.18l-7.12,2.1l-2.15,2.52l-0.13,2.99l-1.19,2.45l-4.01,3.09l-0.14,0.44l0.97,2.9l-2.28,6.48l-3.1,0.2l-3.83,-3.07l-4.86,-0.02l-2.25,-1.93l-1.7,-3.79l-4.3,-4.84l-1.21,-2.49l-0.44,-3.8l-3.32,-3.63l0.84,-2.86l-1.56,-1.7l2.28,-4.6l3.83,-1.74l1.03,-1.96l0.52,-3.47l-0.59,-0.41l-4.17,2.21l-2.07,0.58l-2.72,-1.28l-0.15,-2.71l0.85,-2.09l2.01,-0.06l5.06,1.2l0.46,-0.23l-0.14,-0.49l-6.54,-4.47l-2.67,0.55l-1.58,-0.86l2.56,-4.01l-0.03,-0.48l-1.5,-1.74l-4.98,-8.5l-3.13,-1.96l0.03,-1.88l-0.24,-0.37l-6.85,-3.02l-5.36,-0.38l-12.7,0.58l-2.78,-1.57l-3.66,-2.77l5.73,-1.45l5.0,-0.28l0.38,-0.38l-0.35,-0.41l-10.67,-1.38l-5.3,-2.06l0.25,-1.54l18.41,-5.26l1.22,-2.27l-0.25,-0.55l-6.14,-1.86l1.68,-1.77l8.55,-4.03l3.59,-0.63l0.3,-0.54l-0.88,-2.27l5.47,-1.47l7.65,-0.95l7.55,-0.05l3.04,1.85l6.48,-3.27l5.81,2.22l3.56,0.5l5.16,1.94l0.5,-0.21l-0.17,-0.52l-5.71,-3.13l0.28,-2.13l8.12,-3.6l8.7,0.28l3.35,-2.34l8.71,-0.6l19.93,0.8Z",name:"Greenland"},KW:{path:"M540.81,207.91l0.37,0.86l-0.17,0.76l0.6,1.53l-0.95,0.04l-0.82,-1.28l-1.57,-0.18l1.31,-1.88l1.22,0.17Z",name:"Kuwait"},GH:{path:"M420.53,257.51l-0.01,0.72l0.96,1.2l0.24,3.73l0.59,0.95l-0.51,2.1l0.19,1.41l1.02,2.21l-6.97,2.84l-1.8,-0.57l0.04,-0.89l-1.02,-2.04l0.61,-2.65l1.07,-2.32l-0.96,-6.47l5.01,0.07l0.94,-0.39l0.61,0.11Z",name:"Ghana"},OM:{path:"M568.09,230.93l-0.91,1.67l-1.22,0.04l-0.6,0.76l-0.41,1.51l0.27,1.58l-1.16,0.05l-1.56,0.97l-0.76,1.74l-1.62,0.05l-0.98,0.65l-0.17,1.15l-0.89,0.52l-1.49,-0.18l-2.4,0.94l-2.47,-5.4l7.35,-2.71l1.67,-5.23l-1.12,-2.09l0.05,-0.83l0.67,-1.0l0.07,-1.05l0.9,-0.42l-0.05,-2.07l0.7,-0.01l1.0,1.62l1.51,1.08l3.3,0.84l1.73,2.29l0.81,0.37l-1.23,2.35l-0.99,0.79Z",name:"Oman"},_2:{path:"M531.15,258.94l1.51,0.12l5.13,-0.95l5.3,-1.48l-0.01,4.4l-2.67,3.39l-1.85,0.01l-8.04,-2.94l-2.55,-3.17l1.12,-1.71l2.04,2.34Z",name:"Somaliland"},_1:{path:"M472.77,172.64l-1.08,-1.29l0.96,-0.77l0.29,-0.83l1.98,1.64l-0.36,0.67l-1.79,0.58Z",name:"Kosovo"},_0:{path:"M504.91,192.87l0.34,0.01l0.27,-0.07l-0.29,0.26l-0.31,-0.2Z",name:"N. Cyprus"},JO:{path:"M518.64,201.38l-5.14,1.56l-0.19,0.65l2.16,2.39l-0.89,1.14l-1.71,0.34l-1.71,1.8l-2.34,-0.37l1.21,-4.32l0.56,-4.07l2.8,0.94l4.46,-2.71l0.79,2.66Z",name:"Jordan"},HR:{path:"M455.59,162.84l1.09,0.07l-0.82,0.94l-0.27,-1.01ZM456.96,162.92l0.62,-0.41l1.73,0.45l0.42,-0.4l-0.01,-0.59l0.86,-0.52l0.2,-1.05l1.63,-0.68l2.57,1.68l2.07,0.6l0.87,-0.31l1.05,1.57l-0.52,0.63l-1.05,-0.56l-1.68,0.04l-2.1,-0.5l-1.29,0.06l-0.57,0.49l-0.59,-0.47l-0.62,0.16l-0.46,1.7l1.79,2.42l2.79,2.75l-1.18,-0.87l-2.21,-0.87l-1.67,-1.78l0.13,-0.63l-1.05,-1.19l-0.32,-1.27l-1.42,-0.43Z",name:"Croatia"},HT:{path:"M237.05,238.38l-1.16,0.43l-0.91,-0.55l0.05,-0.2l2.02,0.31ZM237.53,238.43l1.06,0.12l-0.05,0.01l-1.01,-0.12ZM239.25,238.45l0.79,-0.51l0.06,-0.62l-1.02,-1.0l0.02,-0.82l-0.3,-0.4l-0.93,-0.32l3.16,0.45l0.02,1.84l-0.48,0.34l-0.08,0.58l0.54,0.72l-1.78,-0.26Z",name:"Haiti"},HU:{path:"M462.08,157.89l0.65,-1.59l-0.09,-0.44l0.64,-0.0l0.39,-0.34l0.1,-0.69l1.75,0.87l2.32,-0.37l0.43,-0.66l3.49,-0.78l0.69,-0.78l0.57,-0.14l2.57,0.93l0.67,-0.23l1.03,0.65l0.08,0.37l-1.42,0.71l-2.59,4.14l-1.8,0.53l-1.68,-0.1l-2.74,1.23l-1.85,-0.54l-2.54,-1.66l-0.66,-1.1Z",name:"Hungary"},HN:{path:"M199.6,249.52l-1.7,-1.21l0.06,-0.94l3.04,-2.14l2.37,0.28l1.27,-0.09l1.1,-0.52l1.3,0.28l1.14,-0.25l1.38,0.37l2.23,1.37l-2.36,0.93l-1.23,-0.39l-0.88,1.3l-1.28,0.99l-0.98,-0.22l-0.42,0.52l-0.96,0.05l-0.36,0.41l0.04,0.88l-0.52,0.6l-0.3,0.04l-0.3,-0.55l-0.66,-0.31l0.11,-0.67l-0.48,-0.65l-0.87,-0.26l-0.73,0.2Z",name:"Honduras"},PR:{path:"M256.17,238.73l-0.26,0.27l-2.83,0.05l-0.07,-0.55l1.95,-0.1l1.22,0.33Z",name:"Puerto Rico"},PS:{path:"M509.21,203.07l0.1,-0.06l-0.02,0.03l-0.09,0.03ZM509.36,202.91l-0.02,-0.63l-0.33,-0.16l0.31,-1.09l0.24,0.1l-0.2,1.78Z",name:"Palestine"},PT:{path:"M401.84,187.38l-0.64,0.47l-1.13,-0.35l-0.91,0.17l0.28,-1.78l-0.24,-1.78l-1.25,-0.56l-0.45,-0.84l0.17,-1.66l1.01,-1.18l0.69,-2.92l-0.04,-1.39l-0.59,-1.9l1.3,-0.85l0.84,1.35l3.1,-0.3l0.46,0.99l-1.05,0.94l-0.03,2.16l-0.41,0.57l-0.08,1.1l-0.79,0.18l-0.26,0.59l0.91,1.6l-0.63,1.75l0.76,1.09l-1.1,1.52l0.07,1.05Z",name:"Portugal"},PY:{path:"M274.9,336.12l0.74,1.52l-0.16,3.45l0.32,0.41l2.64,0.5l1.11,-0.47l1.4,0.59l0.36,0.6l0.53,3.42l1.27,0.4l0.98,-0.38l0.51,0.27l-0.0,1.18l-1.21,5.32l-2.09,1.9l-1.8,0.4l-4.71,-0.98l2.2,-3.63l-0.32,-1.5l-2.78,-1.28l-3.03,-1.94l-2.07,-0.44l-4.34,-4.06l0.91,-2.9l0.08,-1.42l1.07,-2.04l4.13,-0.72l2.18,0.03l2.05,1.17l0.03,0.59Z",name:"Paraguay"},PA:{path:"M213.8,263.68l0.26,-1.52l-0.36,-0.26l-0.01,-0.49l0.44,-0.1l0.93,1.4l1.26,0.03l0.77,0.49l1.38,-0.23l2.51,-1.11l0.86,-0.72l3.45,0.85l1.4,1.18l0.41,1.74l-0.21,0.34l-0.53,-0.12l-0.47,0.29l-0.16,0.6l-0.68,-1.28l0.45,-0.49l-0.19,-0.66l-0.47,-0.13l-0.54,-0.84l-1.5,-0.75l-1.1,0.16l-0.75,0.99l-1.62,0.84l-0.18,0.96l0.85,0.97l-0.58,0.45l-0.69,0.08l-0.34,-1.18l-1.27,0.03l-0.71,-1.05l-2.59,-0.46Z",name:"Panama"},PG:{path:"M808.58,298.86l2.54,2.56l-0.13,0.26l-0.33,0.12l-0.87,-0.78l-1.22,-2.16ZM801.41,293.04l0.5,0.29l0.26,0.27l-0.49,-0.35l-0.27,-0.21ZM803.17,294.58l0.59,0.5l0.08,1.06l-0.29,-0.91l-0.38,-0.65ZM796.68,298.41l0.52,0.75l1.43,-0.19l2.27,-1.81l-0.01,-1.43l1.12,0.16l-0.04,1.1l-0.7,1.28l-1.12,0.18l-0.62,0.79l-2.46,1.11l-1.17,-0.0l-3.08,-1.25l3.41,0.0l0.45,-0.68ZM789.15,303.55l2.31,1.8l1.59,2.61l1.34,0.13l-0.06,0.66l0.31,0.43l1.06,0.24l0.06,0.65l2.25,1.05l-1.22,0.13l-0.72,-0.63l-4.56,-0.65l-3.22,-2.87l-1.49,-2.34l-3.27,-1.1l-2.38,0.72l-1.59,0.86l-0.2,0.42l0.27,1.55l-1.55,0.68l-1.36,-0.4l-2.21,-0.09l-0.08,-15.41l8.39,2.93l2.95,2.4l0.6,1.64l4.02,1.49l0.31,0.68l-1.76,0.21l-0.33,0.52l0.55,1.68Z",name:"Papua New Guinea"},PE:{path:"M244.96,295.21l-1.26,-0.07l-0.57,0.42l-1.93,0.45l-2.98,1.75l-0.36,1.36l-0.58,0.8l0.12,1.37l-1.24,0.59l-0.22,1.22l-0.62,0.84l1.04,2.27l1.28,1.44l-0.41,0.84l0.32,0.57l1.48,0.13l1.16,1.37l2.21,0.07l1.63,-1.08l-0.13,3.02l0.3,0.4l1.14,0.29l1.31,-0.34l1.9,3.59l-0.48,0.85l-0.17,3.85l-0.94,1.59l0.35,0.75l-0.47,1.07l0.98,1.97l-2.1,3.82l-0.98,0.5l-2.17,-1.28l-0.39,-1.16l-4.95,-2.58l-4.46,-2.79l-1.84,-1.51l-0.91,-1.84l0.3,-0.96l-2.11,-3.33l-4.82,-9.68l-1.04,-1.2l-0.87,-1.94l-3.4,-2.48l0.58,-1.18l-1.13,-2.23l0.66,-1.49l1.45,-1.15l-0.6,0.98l0.07,0.92l0.47,0.36l1.74,0.03l0.97,1.17l0.54,0.07l1.42,-1.03l0.6,-1.84l1.42,-2.02l3.04,-1.04l2.73,-2.62l0.86,-1.74l-0.1,-1.87l1.44,1.02l0.9,1.25l1.06,0.59l1.7,2.73l1.86,0.31l1.45,-0.61l0.96,0.39l1.36,-0.19l1.45,0.89l-1.4,2.21l0.31,0.61l0.59,0.05l0.47,0.5Z",name:"Peru"},PK:{path:"M615.09,192.34l-1.83,1.81l-2.6,0.39l-3.73,-0.68l-1.58,1.33l-0.09,0.42l1.77,4.39l1.7,1.23l-1.69,1.27l-0.12,2.14l-2.33,2.64l-1.6,2.8l-2.46,2.67l-3.03,-0.07l-2.76,2.83l0.05,0.6l1.5,1.11l0.26,1.9l1.44,1.5l0.37,1.68l-5.01,-0.01l-1.78,1.7l-1.42,-0.52l-0.76,-1.87l-2.27,-2.15l-11.61,0.86l0.71,-2.34l3.43,-1.32l0.25,-0.44l-0.21,-1.24l-1.2,-0.65l-0.28,-2.46l-2.29,-1.14l-1.28,-1.94l2.82,0.94l2.62,-0.38l1.42,0.33l0.76,-0.56l1.71,0.19l3.25,-1.14l0.27,-0.36l0.08,-2.19l1.18,-1.32l1.68,0.0l0.58,-0.82l1.6,-0.3l1.19,0.16l0.98,-0.78l0.02,-1.88l0.93,-1.47l1.48,-0.66l0.19,-0.55l-0.66,-1.25l2.04,-0.11l0.69,-1.01l-0.02,-1.16l1.11,-1.06l-0.17,-1.78l-0.49,-1.03l1.15,-0.98l5.42,-0.91l2.6,-0.82l1.6,1.16l0.97,2.34l3.45,0.97Z",name:"Pakistan"},PH:{path:"M737.01,263.84l0.39,2.97l-0.44,1.18l-0.55,-1.53l-0.67,-0.14l-1.17,1.28l0.65,2.09l-0.42,0.69l-2.48,-1.23l-0.57,-1.49l0.65,-1.03l-0.1,-0.54l-1.59,-1.19l-0.56,0.08l-0.65,0.87l-1.23,0.0l-1.58,0.97l0.83,-1.8l2.56,-1.42l0.65,0.84l0.45,0.13l1.9,-0.69l0.56,-1.11l1.5,-0.06l0.38,-0.43l-0.09,-1.19l1.21,0.71l0.36,2.02ZM733.59,256.58l0.05,0.75l0.08,0.26l-0.8,-0.42l-0.18,-0.71l0.85,0.12ZM734.08,256.1l-0.12,-1.12l-1.0,-1.27l1.36,0.03l0.53,0.73l0.51,2.04l-1.27,-0.4ZM733.76,257.68l0.38,0.98l-0.32,0.15l-0.07,-1.13ZM724.65,238.43l1.46,0.7l0.72,-0.31l-0.32,1.17l0.79,1.71l-0.57,1.84l-1.53,1.04l-0.39,2.25l0.56,2.04l1.63,0.57l1.16,-0.27l2.71,1.23l-0.19,1.08l0.76,0.84l-0.08,0.36l-1.4,-0.9l-0.88,-1.27l-0.66,0.0l-0.38,0.55l-1.6,-1.31l-2.15,0.36l-0.87,-0.39l0.07,-0.61l0.66,-0.55l-0.01,-0.62l-0.75,-0.59l-0.72,0.44l-0.74,-0.87l-0.39,-2.49l0.32,0.27l0.66,-0.28l0.26,-3.97l0.7,-2.02l1.14,0.0ZM731.03,258.87l-0.88,0.85l-1.19,1.94l-1.05,-1.19l0.93,-1.1l0.32,-1.47l0.52,-0.06l-0.27,1.15l0.22,0.45l0.49,-0.12l1.0,-1.32l-0.08,0.85ZM726.83,255.78l0.83,0.38l1.17,-0.0l-0.02,0.48l-2.0,1.4l0.03,-2.26ZM724.81,252.09l-0.38,1.27l-1.42,-1.95l1.2,0.05l0.6,0.63ZM716.55,261.82l1.1,-0.95l0.03,-0.03l-0.28,0.36l-0.85,0.61ZM719.22,259.06l0.04,-0.06l0.8,-1.53l0.16,0.75l-1.0,0.84Z",name:"Philippines"},PL:{path:"M468.44,149.42l-1.11,-1.54l-1.86,-0.33l-0.48,-1.05l-1.72,-0.37l-0.65,0.69l-0.72,-0.36l0.11,-0.61l-0.33,-0.46l-1.75,-0.27l-1.04,-0.93l-0.94,-1.94l0.16,-1.22l-0.62,-1.8l-0.78,-1.07l0.57,-1.04l-0.48,-1.43l1.41,-0.83l6.91,-2.71l2.14,0.5l0.52,0.91l5.51,0.44l4.55,-0.05l1.07,0.31l0.48,0.84l0.15,1.58l0.65,1.2l-0.01,0.99l-1.27,0.58l-0.19,0.54l0.73,1.48l0.08,1.55l1.2,2.76l-0.17,0.58l-1.23,0.44l-2.27,2.72l0.18,0.95l-1.97,-1.03l-1.98,0.4l-1.36,-0.28l-1.24,0.58l-1.07,-0.97l-1.16,0.24Z",name:"Poland"},ZM:{path:"M481.47,313.3l0.39,0.31l2.52,0.14l0.99,1.17l2.01,0.35l1.4,-0.64l0.69,1.17l1.78,0.33l1.84,2.35l2.23,0.18l0.4,-0.43l-0.21,-2.74l-0.62,-0.3l-0.48,0.32l-1.98,-1.17l0.72,-5.29l-0.51,-1.18l0.57,-1.3l3.68,-0.62l0.26,0.63l1.21,0.63l0.9,-0.22l2.16,0.67l1.33,0.71l1.07,1.02l0.56,1.87l-0.88,2.7l0.43,2.09l-0.73,0.87l-0.76,2.37l0.59,0.68l-6.6,1.83l-0.29,0.44l0.19,1.45l-1.68,0.35l-1.43,1.02l-0.38,0.87l-0.87,0.26l-3.48,3.69l-4.16,-0.53l-1.52,-1.0l-1.77,-0.13l-1.83,0.52l-3.04,-3.4l0.11,-7.59l4.82,0.03l0.39,-0.49l-0.18,-0.76l0.33,-0.83l-0.4,-1.36l0.24,-1.05Z",name:"Zambia"},EH:{path:"M384.42,230.28l0.25,-0.79l1.06,-1.29l0.8,-3.51l3.38,-2.78l0.7,-1.81l0.06,4.84l-1.98,0.2l-0.94,1.59l0.39,3.56l-3.7,-0.01ZM392.01,218.1l0.7,-1.8l1.77,-0.24l2.09,0.34l0.95,-0.62l1.28,-0.07l-0.0,2.51l-6.79,-0.12Z",name:"W. Sahara"},EE:{path:"M485.71,115.04l2.64,0.6l2.56,0.11l-1.6,1.91l0.61,3.54l-0.81,0.87l-1.78,-0.01l-3.22,-1.76l-1.8,0.45l0.21,-1.53l-0.58,-0.41l-0.69,0.34l-1.26,-1.03l-0.17,-1.63l2.83,-0.92l3.05,-0.52Z",name:"Estonia"},EG:{path:"M492.06,205.03l1.46,0.42l2.95,-1.64l2.04,-0.21l1.53,0.3l0.59,1.19l0.69,0.04l0.41,-0.64l1.81,0.58l1.95,0.16l1.04,-0.51l1.42,4.08l-2.03,4.54l-1.66,-1.77l-1.76,-3.85l-0.64,-0.12l-0.36,0.67l1.04,2.88l3.44,6.95l1.78,3.04l2.03,2.65l-0.36,0.53l0.23,2.01l2.7,2.19l-28.41,0.0l0.0,-18.96l-0.73,-2.2l0.59,-1.56l-0.32,-1.26l0.68,-0.99l3.06,-0.04l4.82,1.52Z",name:"Egypt"},ZA:{path:"M467.14,373.21l-0.13,-1.96l-0.68,-1.56l0.7,-0.68l-0.13,-2.33l-4.56,-8.19l0.77,-0.86l0.6,0.45l0.69,1.31l2.83,0.72l1.5,-0.26l2.24,-1.39l0.19,-9.55l1.35,2.3l-0.21,1.5l0.61,1.2l0.4,0.19l1.79,-0.27l2.6,-2.07l0.69,-1.32l0.96,-0.48l2.19,1.04l2.04,0.13l1.77,-0.65l0.85,-2.12l1.38,-0.33l1.59,-2.76l2.15,-1.89l3.41,-1.87l2.0,0.45l1.02,-0.28l0.99,0.2l1.75,5.29l-0.38,3.25l-0.81,-0.23l-1.0,0.46l-0.87,1.68l-0.05,1.16l1.97,1.84l1.47,-0.29l0.69,-1.18l1.09,0.01l-0.76,3.69l-0.58,1.09l-2.2,1.79l-3.17,4.76l-2.8,2.83l-3.57,2.88l-2.53,1.05l-1.22,0.14l-0.51,0.7l-1.18,-0.32l-1.39,0.5l-2.59,-0.52l-1.61,0.33l-1.18,-0.11l-2.55,1.1l-2.1,0.44l-1.6,1.07l-0.85,0.05l-0.93,-0.89l-0.93,-0.15l-0.97,-1.13l-0.25,0.05ZM491.45,364.19l0.62,-0.93l1.48,-0.59l1.18,-2.19l-0.07,-0.49l-1.99,-1.69l-1.66,0.56l-1.43,1.14l-1.34,1.73l0.02,0.51l1.88,2.11l1.31,-0.16Z",name:"South Africa"},EC:{path:"M231.86,285.53l0.29,1.59l-0.69,1.45l-2.61,2.51l-3.13,1.11l-1.53,2.18l-0.49,1.68l-1.0,0.73l-1.02,-1.11l-1.78,-0.16l0.67,-1.15l-0.24,-0.86l1.25,-2.13l-0.54,-1.09l-0.67,-0.08l-0.72,0.87l-0.87,-0.64l0.35,-0.69l-0.36,-1.96l0.81,-0.51l0.45,-1.51l0.92,-1.57l-0.07,-0.97l2.65,-1.33l2.75,1.35l0.77,1.05l2.12,0.35l0.76,-0.32l1.96,1.21Z",name:"Ecuador"},AL:{path:"M470.32,171.8l0.74,0.03l0.92,0.89l-0.17,1.95l0.36,1.28l1.01,0.82l-1.82,2.83l-0.19,-0.61l-1.25,-0.89l-0.18,-1.2l0.53,-2.82l-0.54,-1.47l0.6,-0.83Z",name:"Albania"},AO:{path:"M461.55,300.03l1.26,3.15l1.94,2.36l2.47,-0.53l1.25,0.32l0.44,-0.18l0.93,-1.92l1.31,-0.08l0.41,-0.44l0.47,-0.0l-0.1,0.41l0.39,0.49l2.65,-0.02l0.03,1.19l0.48,1.01l-0.34,1.52l0.18,1.55l0.83,1.04l-0.13,2.85l0.54,0.39l3.96,-0.41l-0.1,1.79l0.39,1.05l-0.24,1.43l-4.7,-0.03l-0.4,0.39l-0.12,8.13l2.92,3.49l-3.83,0.88l-5.89,-0.36l-1.88,-1.24l-10.47,0.22l-1.3,-1.01l-1.85,-0.16l-2.4,0.77l-0.15,-1.06l0.33,-2.16l1.0,-3.45l1.35,-3.2l2.24,-2.8l0.33,-2.06l-0.13,-1.53l-0.8,-1.08l-1.21,-2.87l0.87,-1.62l-1.27,-4.12l-1.17,-1.53l2.47,-0.63l7.03,0.03ZM451.71,298.87l-0.47,-1.25l1.25,-1.11l0.32,0.3l-0.99,1.03l-0.12,1.03Z",name:"Angola"},KZ:{path:"M552.8,172.89l0.46,-1.27l-0.48,-1.05l-2.96,-1.19l-1.06,-2.58l-1.37,-0.87l-0.03,-0.3l1.95,0.23l0.45,-0.38l0.08,-1.96l1.75,-0.41l2.1,0.45l0.48,-0.33l0.45,-3.04l-0.45,-2.09l-0.41,-0.31l-2.42,0.15l-2.36,-0.73l-2.87,1.37l-2.17,0.61l-0.85,-0.34l0.13,-1.61l-1.6,-2.12l-2.02,-0.08l-1.78,-1.82l1.29,-2.18l-0.57,-0.95l1.62,-2.91l2.21,1.63l0.63,-0.27l0.29,-2.22l4.92,-3.43l3.71,-0.08l8.4,3.6l2.92,-1.36l3.77,-0.06l3.11,1.66l0.51,-0.11l0.6,-0.81l3.31,0.13l0.39,-0.25l0.63,-1.57l-0.17,-0.5l-3.5,-1.98l1.87,-1.27l-0.13,-1.03l1.98,-0.72l0.18,-0.62l-1.59,-2.06l0.81,-0.82l9.23,-1.18l1.33,-0.88l6.18,-1.26l2.26,-1.42l4.08,0.68l0.73,3.33l0.51,0.3l2.48,-0.8l2.79,1.02l-0.17,1.56l0.43,0.44l2.55,-0.24l4.89,-2.53l0.03,0.32l3.15,2.61l5.56,8.47l0.65,0.02l1.12,-1.46l3.15,1.74l3.76,-0.78l1.15,0.49l1.14,1.8l1.84,0.76l0.99,1.29l3.35,-0.25l1.02,1.52l-1.6,1.81l-1.93,0.28l-0.34,0.38l-0.11,3.05l-1.13,1.16l-4.75,-1.0l-0.46,0.27l-1.76,5.47l-1.1,0.59l-4.91,1.23l-0.27,0.54l2.1,4.97l-1.37,0.63l-0.23,0.41l0.13,1.13l-0.88,-0.25l-1.42,-1.13l-7.89,-0.4l-0.92,0.31l-3.73,-1.22l-1.42,0.63l-0.53,1.66l-3.72,-0.94l-1.85,0.43l-0.76,1.4l-4.65,2.62l-1.13,2.08l-0.44,0.01l-0.92,-1.4l-2.87,-0.09l-0.45,-2.14l-0.38,-0.32l-0.8,-0.01l0.0,-2.96l-3.0,-2.22l-7.31,0.58l-2.35,-2.68l-6.71,-3.69l-6.45,1.83l-0.29,0.39l0.1,10.85l-0.7,0.08l-1.62,-2.17l-1.83,-0.96l-3.11,0.59l-0.64,0.51Z",name:"Kazakhstan"},ET:{path:"M516.04,247.79l1.1,0.84l1.63,-0.45l0.68,0.47l1.63,0.03l2.01,0.94l1.73,1.66l1.64,2.07l-1.52,2.04l0.16,1.72l0.39,0.38l2.05,0.0l-0.36,1.03l2.86,3.58l8.32,3.08l1.31,0.02l-6.32,6.75l-3.1,0.11l-2.36,1.77l-1.47,0.04l-0.86,0.79l-1.38,-0.0l-1.32,-0.81l-2.29,1.05l-0.76,0.98l-3.29,-0.41l-3.07,-2.07l-1.8,-0.07l-0.62,-0.6l0.0,-1.24l-0.28,-0.38l-1.15,-0.37l-1.4,-2.59l-1.19,-0.68l-0.47,-1.0l-1.27,-1.23l-1.16,-0.22l0.43,-0.72l1.45,-0.28l0.41,-0.95l-0.03,-2.21l0.68,-2.44l1.05,-0.63l1.43,-3.06l1.57,-1.37l1.02,-2.51l0.35,-1.88l2.52,0.46l0.44,-0.24l0.58,-1.43Z",name:"Ethiopia"},ZW:{path:"M498.91,341.09l-1.11,-0.22l-0.92,0.28l-2.09,-0.44l-1.5,-1.11l-1.89,-0.43l-0.62,-1.4l-0.01,-0.84l-0.3,-0.38l-0.97,-0.25l-2.71,-2.74l-1.92,-3.32l3.83,0.45l3.73,-3.82l1.08,-0.44l0.26,-0.77l1.25,-0.9l1.41,-0.26l0.5,0.89l1.99,-0.05l1.72,1.17l1.11,0.17l1.05,0.66l0.01,2.99l-0.59,3.76l0.38,0.86l-0.23,1.23l-0.39,0.35l-0.63,1.81l-2.43,2.75Z",name:"Zimbabwe"},ES:{path:"M416.0,169.21l1.07,1.17l4.61,1.38l1.06,-0.57l2.6,1.26l2.71,-0.3l0.09,1.12l-2.14,1.8l-3.11,0.61l-0.31,0.31l-0.2,0.89l-1.54,1.69l-0.97,2.4l0.84,1.74l-1.32,1.27l-0.48,1.68l-1.88,0.65l-1.66,2.07l-5.36,-0.01l-1.79,1.08l-0.89,0.98l-0.88,-0.17l-0.79,-0.82l-0.68,-1.59l-2.37,-0.63l-0.11,-0.5l1.21,-1.82l-0.77,-1.13l0.61,-1.68l-0.76,-1.62l0.87,-0.49l0.09,-1.25l0.42,-0.6l0.03,-2.11l0.99,-0.69l0.13,-0.5l-1.03,-1.73l-1.46,-0.11l-0.61,0.38l-1.06,0.0l-0.52,-1.23l-0.53,-0.21l-1.32,0.67l-0.01,-1.49l-0.75,-0.96l3.03,-1.88l2.99,0.53l3.32,-0.02l2.63,0.51l6.01,-0.06Z",name:"Spain"},ER:{path:"M520.38,246.23l3.42,2.43l3.5,3.77l0.84,0.54l-0.95,-0.01l-3.51,-3.89l-2.33,-1.15l-1.73,-0.07l-0.91,-0.51l-1.26,0.51l-1.34,-1.02l-0.61,0.17l-0.66,1.61l-2.35,-0.43l-0.17,-0.67l1.29,-5.29l0.61,-0.61l1.95,-0.53l0.87,-1.01l1.17,2.41l0.68,2.33l1.49,1.43Z",name:"Eritrea"},ME:{path:"M468.91,172.53l-1.22,-1.02l0.47,-1.81l0.89,-0.72l2.26,1.51l-0.5,0.57l-0.75,-0.27l-1.14,1.73Z",name:"Montenegro"},MD:{path:"M488.41,153.73l1.4,-0.27l1.72,0.93l1.07,0.15l0.85,0.65l-0.14,0.84l0.96,0.85l1.12,2.47l-1.15,-0.07l-0.66,-0.41l-0.52,0.25l-0.09,0.86l-1.08,1.89l-0.27,-0.86l0.25,-1.34l-0.16,-1.6l-3.29,-4.34Z",name:"Moldova"},MG:{path:"M545.91,319.14l0.4,3.03l0.62,1.21l-0.21,1.02l-0.57,-0.8l-0.69,-0.01l-0.47,0.76l0.41,2.12l-0.18,0.87l-0.73,0.78l-0.15,2.14l-4.71,15.2l-1.06,2.88l-3.92,1.64l-3.12,-1.49l-0.6,-1.21l-0.19,-2.4l-0.86,-2.05l-0.21,-1.77l0.38,-1.62l1.21,-0.75l0.01,-0.76l1.19,-2.04l0.23,-1.66l-1.06,-2.99l-0.19,-2.21l0.81,-1.33l0.32,-1.46l4.63,-1.22l3.44,-3.0l0.85,-1.4l-0.08,-0.7l0.78,-0.04l1.38,-1.77l0.13,-1.64l0.45,-0.61l1.16,1.69l0.59,1.6Z",name:"Madagascar"},MA:{path:"M378.78,230.02l0.06,-0.59l0.92,-0.73l0.82,-1.37l-0.09,-1.04l0.79,-1.7l1.31,-1.58l0.96,-0.59l0.66,-1.55l0.09,-1.47l0.81,-1.48l1.72,-1.07l1.55,-2.69l1.16,-0.96l2.44,-0.39l1.94,-1.82l1.31,-0.78l2.09,-2.28l-0.51,-3.65l1.24,-3.7l1.5,-1.75l4.46,-2.57l2.37,-4.47l1.44,0.01l1.68,1.21l2.32,-0.19l3.47,0.65l0.8,1.54l0.16,1.71l0.86,2.96l0.56,0.59l-0.26,0.61l-3.05,0.44l-1.26,1.05l-1.33,0.22l-0.33,0.37l-0.09,1.78l-2.68,1.0l-1.07,1.42l-4.47,1.13l-4.04,2.01l-0.54,4.64l-1.15,0.06l-0.92,0.61l-1.96,-0.35l-2.42,0.54l-0.74,1.9l-0.86,0.4l-1.14,3.26l-3.53,3.01l-0.8,3.55l-0.96,1.1l-0.29,0.82l-4.95,0.18Z",name:"Morocco"},UZ:{path:"M598.64,172.75l-1.63,1.52l0.06,0.64l1.85,1.12l1.97,-0.64l2.21,1.17l-2.52,1.68l-2.59,-0.22l-0.18,-0.41l0.46,-1.23l-0.45,-0.53l-3.35,0.69l-2.1,3.51l-1.87,-0.12l-1.03,1.51l0.22,0.55l1.64,0.62l0.46,1.83l-1.19,2.49l-2.66,-0.53l0.05,-1.36l-0.26,-0.39l-3.3,-1.23l-2.56,-1.4l-4.4,-3.34l-1.34,-3.14l-1.08,-0.6l-2.58,0.13l-0.69,-0.44l-0.47,-2.52l-3.37,-1.6l-0.43,0.05l-2.07,1.72l-2.1,1.01l-0.21,0.47l0.28,1.01l-1.91,0.03l-0.09,-10.5l5.99,-1.7l6.19,3.54l2.71,2.84l7.05,-0.67l2.71,2.01l-0.17,2.81l0.39,0.42l0.9,0.02l0.44,2.14l0.38,0.32l2.94,0.09l0.95,1.42l1.28,-0.24l1.05,-2.04l4.43,-2.5Z",name:"Uzbekistan"},MM:{path:"M673.9,230.21l-1.97,1.57l-0.57,0.96l-1.4,0.6l-1.36,1.05l-1.99,0.36l-1.08,2.66l-0.91,0.4l-0.19,0.55l1.21,2.27l2.52,3.43l-0.79,1.91l-0.74,0.41l-0.17,0.52l0.65,1.37l1.61,1.95l0.25,2.58l0.9,2.13l-1.92,3.57l0.68,-2.25l-0.81,-1.74l0.19,-2.65l-1.05,-1.53l-1.24,-6.17l-1.12,-2.26l-0.6,-0.13l-4.34,3.02l-2.39,-0.65l0.77,-2.84l-0.52,-2.61l-1.91,-2.96l0.25,-0.75l-0.29,-0.51l-1.33,-0.3l-1.61,-1.93l-0.1,-1.3l0.82,-0.24l0.04,-1.64l1.02,-0.52l0.21,-0.45l-0.23,-0.95l0.54,-0.96l0.08,-2.22l1.46,0.45l0.47,-0.2l1.12,-2.19l0.16,-1.35l1.33,-2.16l-0.0,-1.52l2.89,-1.66l1.63,0.44l0.5,-0.44l-0.17,-1.4l0.64,-0.36l0.08,-1.04l0.77,-0.11l0.71,1.35l1.06,0.69l-0.03,3.86l-2.38,2.37l-0.3,3.15l0.46,0.43l2.28,-0.38l0.51,2.08l1.47,0.67l-0.6,1.8l0.19,0.48l2.97,1.48l1.64,-0.55l0.02,0.32Z",name:"Myanmar"},ML:{path:"M392.61,254.08l-0.19,-2.37l-0.99,-0.87l-0.44,-1.3l-0.09,-1.28l0.81,-0.58l0.35,-1.24l2.37,0.65l1.31,-0.47l0.86,0.15l0.66,-0.56l9.83,-0.04l0.38,-0.28l0.56,-1.8l-0.44,-0.65l-2.35,-21.95l3.27,-0.04l16.7,11.38l0.74,1.31l2.5,1.09l0.02,1.38l0.44,0.39l2.34,-0.21l0.01,5.38l-1.28,1.61l-0.26,1.49l-5.31,0.57l-1.07,0.92l-2.9,0.1l-0.86,-0.48l-1.38,0.36l-2.4,1.08l-0.6,0.87l-1.85,1.09l-0.43,0.7l-0.79,0.39l-1.44,-0.21l-0.81,0.84l-0.34,1.64l-1.91,2.02l-0.06,1.03l-0.67,1.22l0.13,1.16l-0.97,0.39l-0.23,-0.64l-0.52,-0.24l-1.35,0.4l-0.34,0.55l-2.69,-0.28l-0.37,-0.35l-0.02,-0.9l-0.65,-0.35l0.45,-0.64l-0.03,-0.53l-2.12,-2.44l-0.76,-0.01l-2.0,1.16l-0.78,-0.15l-0.8,-0.67l-1.21,0.23Z",name:"Mali"},MN:{path:"M676.61,146.48l3.81,1.68l5.67,-1.0l2.37,0.41l2.34,1.5l1.79,1.75l2.29,-0.03l3.12,0.52l2.47,-0.81l3.41,-0.59l3.53,-2.21l1.25,0.29l1.53,1.13l2.27,-0.21l-2.66,5.01l0.64,1.68l0.47,0.21l1.32,-0.38l2.38,0.48l2.02,-1.11l1.76,0.89l2.06,2.02l-0.13,0.53l-1.72,-0.29l-3.77,0.46l-1.88,0.99l-1.76,1.99l-3.71,1.17l-2.45,1.6l-3.83,-0.87l-0.41,0.17l-1.31,1.99l1.04,2.24l-1.52,0.9l-1.74,1.57l-2.79,1.02l-3.78,0.13l-4.05,1.05l-2.77,1.52l-1.16,-0.85l-2.94,0.0l-3.62,-1.79l-2.58,-0.49l-3.4,0.41l-5.12,-0.67l-2.63,0.06l-1.31,-1.6l-1.4,-3.0l-1.48,-0.33l-3.13,-1.94l-6.16,-0.93l-0.71,-1.06l0.86,-3.82l-1.93,-2.71l-3.5,-1.18l-1.95,-1.58l-0.5,-1.72l2.34,-0.52l4.75,-2.8l3.62,-1.47l2.18,0.97l2.46,0.05l1.81,1.53l2.46,0.12l3.95,0.71l2.43,-2.28l0.08,-0.48l-0.9,-1.72l2.24,-2.98l2.62,1.27l4.94,1.17l0.43,2.24Z",name:"Mongolia"},MK:{path:"M472.8,173.98l0.49,-0.71l3.57,-0.71l1.0,0.77l0.13,1.45l-0.65,0.53l-1.15,-0.05l-1.12,0.67l-1.39,0.22l-0.79,-0.55l-0.29,-1.03l0.19,-0.6Z",name:"Macedonia"},MW:{path:"M505.5,309.31l0.85,1.95l0.15,2.86l-0.69,1.65l0.71,1.8l0.06,1.28l0.49,0.64l0.07,1.06l0.4,0.55l0.8,-0.23l0.55,0.61l0.69,-0.21l0.34,0.6l0.19,2.94l-1.04,0.62l-0.54,1.25l-1.11,-1.08l-0.16,-1.56l0.51,-1.31l-0.32,-1.3l-0.99,-0.65l-0.82,0.12l-2.36,-1.64l0.63,-1.96l0.82,-1.18l-0.46,-2.01l0.9,-2.86l-0.94,-2.51l0.96,0.18l0.29,0.4Z",name:"Malawi"},MR:{path:"M407.36,220.66l-2.58,0.03l-0.39,0.44l2.42,22.56l0.36,0.43l-0.39,1.24l-9.75,0.04l-0.56,0.53l-0.91,-0.11l-1.27,0.45l-1.61,-0.66l-0.97,0.03l-0.36,0.29l-0.38,1.35l-0.42,0.23l-2.93,-3.4l-2.96,-1.52l-1.62,-0.03l-1.27,0.54l-1.12,-0.2l-0.65,0.4l-0.08,-0.49l0.68,-1.29l0.31,-2.43l-0.57,-3.91l0.23,-1.21l-0.69,-1.5l-1.15,-1.02l0.25,-0.39l9.58,0.02l0.4,-0.45l-0.46,-3.68l0.47,-1.04l2.12,-0.21l0.36,-0.4l-0.08,-6.4l7.81,0.13l0.41,-0.4l0.01,-3.31l7.76,5.35Z",name:"Mauritania"},UG:{path:"M498.55,276.32l0.7,-0.46l1.65,0.5l1.96,-0.57l1.7,0.01l1.45,-0.98l0.91,1.33l1.33,3.95l-2.57,4.03l-1.46,-0.4l-2.54,0.91l-1.37,1.61l-0.01,0.81l-2.42,-0.01l-2.26,1.01l-0.17,-1.59l0.58,-1.04l0.14,-1.94l1.37,-2.28l1.78,-1.58l-0.17,-0.65l-0.72,-0.24l0.13,-2.43Z",name:"Uganda"},MY:{path:"M717.47,273.46l-1.39,0.65l-2.12,-0.41l-2.88,-0.0l-0.38,0.28l-0.84,2.75l-0.99,0.96l-1.21,3.29l-1.73,0.45l-2.45,-0.68l-1.39,0.31l-1.33,1.15l-1.59,-0.14l-1.41,0.44l-1.44,-1.19l-0.18,-0.73l1.34,0.53l1.93,-0.47l0.75,-2.22l4.02,-1.03l2.75,-3.21l0.82,0.94l0.64,-0.05l0.4,-0.65l0.96,0.06l0.42,-0.36l0.24,-2.68l1.81,-1.64l1.21,-1.86l0.63,-0.01l1.07,1.05l0.34,1.28l3.44,1.35l-0.06,0.35l-1.37,0.1l-0.35,0.54l0.32,0.88ZM673.68,269.59l0.17,1.09l0.47,0.33l1.65,-0.3l0.87,-0.94l1.61,1.52l0.98,1.56l-0.12,2.81l0.41,2.29l0.95,0.9l0.88,2.44l-1.27,0.12l-5.1,-3.67l-0.34,-1.29l-1.37,-1.59l-0.33,-1.97l-0.88,-1.4l0.25,-1.68l-0.46,-1.05l1.63,0.84Z",name:"Malaysia"},MX:{path:"M133.12,200.41l0.2,0.47l9.63,3.33l6.96,-0.02l0.4,-0.4l0.0,-0.74l3.77,0.0l3.55,2.93l1.39,2.83l1.52,1.04l2.08,0.82l0.47,-0.14l1.46,-2.0l1.73,-0.04l1.59,0.98l2.05,3.35l1.47,1.56l1.26,3.14l2.18,1.02l2.26,0.58l-1.18,3.72l-0.42,5.04l1.79,4.89l1.62,1.89l0.61,1.52l1.2,1.42l2.55,0.66l1.37,1.1l7.54,-1.89l1.86,-1.3l1.14,-4.3l4.1,-1.21l3.57,-0.11l0.32,0.3l-0.06,0.94l-1.26,1.45l-0.67,1.71l0.38,0.7l-0.72,2.27l-0.49,-0.3l-1.0,0.08l-1.0,1.39l-0.47,-0.11l-0.53,0.47l-4.26,-0.02l-0.4,0.4l-0.0,1.06l-1.1,0.26l0.1,0.44l1.82,1.44l0.56,0.91l-3.19,0.21l-1.21,2.09l0.24,0.72l-0.2,0.44l-2.24,-2.18l-1.45,-0.93l-2.22,-0.69l-1.52,0.22l-3.07,1.16l-10.55,-3.85l-2.86,-1.96l-3.78,-0.92l-1.08,-1.19l-2.62,-1.43l-1.18,-1.54l-0.38,-0.81l0.66,-0.63l-0.18,-0.53l0.52,-0.76l0.01,-0.91l-2.0,-3.82l-2.21,-2.63l-2.53,-2.09l-1.19,-1.62l-2.2,-1.17l-0.3,-0.43l0.34,-1.48l-0.21,-0.45l-1.23,-0.6l-1.36,-1.2l-0.59,-1.78l-1.54,-0.47l-2.44,-2.55l-0.16,-0.9l-1.33,-2.03l-0.84,-1.99l-0.16,-1.33l-1.81,-1.1l-0.97,0.05l-1.31,-0.7l-0.57,0.22l-0.4,1.12l0.72,3.77l3.51,3.89l0.28,0.78l0.53,0.26l0.41,1.43l1.33,1.73l1.58,1.41l0.8,2.39l1.43,2.41l0.13,1.32l0.37,0.36l1.04,0.08l1.67,2.28l-0.85,0.76l-0.66,-1.51l-1.68,-1.54l-2.91,-1.87l0.06,-1.82l-0.54,-1.68l-2.91,-2.03l-0.55,0.09l-1.95,-1.1l-0.88,-0.94l0.68,-0.08l0.93,-1.01l0.08,-1.78l-1.93,-1.94l-1.46,-0.77l-3.75,-7.56l4.88,-0.42Z",name:"Mexico"},VU:{path:"M839.04,322.8l0.22,1.14l-0.44,0.03l-0.2,-1.45l0.42,0.27Z",name:"Vanuatu"},FR:{path:"M444.48,172.62l-0.64,1.78l-0.58,-0.31l-0.49,-1.72l0.4,-0.89l1.0,-0.72l0.3,1.85ZM429.64,147.1l1.78,1.58l1.46,-0.13l2.1,1.42l1.35,0.27l1.23,0.83l3.04,0.5l-1.03,1.85l-0.3,2.12l-0.41,0.32l-0.95,-0.24l-0.5,0.43l0.06,0.61l-1.81,1.92l-0.04,1.42l0.55,0.38l0.88,-0.36l0.61,0.97l-0.03,1.0l0.57,0.91l-0.75,1.09l0.65,2.39l1.27,0.57l-0.18,0.82l-2.01,1.53l-4.77,-0.8l-3.82,1.0l-0.53,1.85l-2.49,0.34l-2.71,-1.31l-1.16,0.57l-4.31,-1.29l-0.72,-0.86l1.19,-1.78l0.39,-6.45l-2.58,-3.3l-1.9,-1.66l-3.72,-1.23l-0.19,-1.72l2.81,-0.61l4.12,0.81l0.47,-0.48l-0.6,-2.77l1.94,0.95l5.83,-2.54l0.92,-2.74l1.6,-0.49l0.24,0.78l1.36,0.33l1.05,1.19ZM289.01,278.39l-0.81,0.8l-0.78,0.12l-0.5,-0.66l-0.56,-0.1l-0.91,0.6l-0.46,-0.22l1.09,-2.96l-0.96,-1.77l-0.17,-1.49l1.07,-1.77l2.32,0.75l2.51,2.01l0.3,0.74l-2.14,3.96Z",name:"France"},FI:{path:"M492.17,76.39l-0.23,3.5l3.52,2.63l-2.08,2.88l-0.02,0.44l2.8,4.56l-1.59,3.31l2.16,3.24l-0.94,2.39l0.14,0.47l3.44,2.51l-0.77,1.62l-7.52,6.95l-4.5,0.31l-4.38,1.37l-3.8,0.74l-1.44,-1.96l-2.17,-1.11l0.5,-3.66l-1.16,-3.33l1.09,-2.08l2.21,-2.42l5.67,-4.32l1.64,-0.83l0.21,-0.42l-0.46,-2.02l-3.38,-1.89l-0.75,-1.43l-0.22,-6.74l-6.79,-4.8l0.8,-0.62l2.54,2.12l3.46,-0.12l3.0,0.96l2.51,-2.11l1.17,-3.08l3.55,-1.38l2.76,1.53l-0.95,2.79Z",name:"Finland"},FJ:{path:"M871.53,326.34l-2.8,1.05l-0.08,-0.23l2.97,-1.21l-0.1,0.39ZM867.58,329.25l0.43,0.37l-0.27,0.88l-1.24,0.28l-1.04,-0.24l-0.14,-0.66l0.63,-0.58l0.92,0.26l0.7,-0.31Z",name:"Fiji"},FK:{path:"M274.36,425.85l1.44,1.08l-0.47,0.73l-3.0,0.89l-0.96,-1.0l-0.52,-0.05l-1.83,1.29l-0.73,-0.88l2.46,-1.64l1.93,0.76l1.67,-1.19Z",name:"Falkland Is."},NI:{path:"M202.33,252.67l0.81,-0.18l1.03,-1.02l-0.04,-0.88l0.68,-0.0l0.63,-0.54l0.97,0.22l1.53,-1.26l0.58,-0.99l1.17,0.34l2.41,-0.94l0.13,1.32l-0.81,1.94l0.1,2.74l-0.36,0.37l-0.11,1.75l-0.47,0.81l0.18,1.14l-1.73,-0.85l-0.71,0.27l-1.47,-0.6l-0.52,0.16l-4.01,-3.81Z",name:"Nicaragua"},NL:{path:"M430.31,143.39l0.6,-0.5l2.13,-4.8l3.2,-1.33l1.74,0.08l0.33,0.8l-0.59,2.92l-0.5,0.99l-1.26,0.0l-0.4,0.45l0.33,2.7l-2.2,-1.78l-2.62,0.58l-0.75,-0.11Z",name:"Netherlands"},NO:{path:"M491.44,67.41l6.8,2.89l-2.29,0.86l-0.15,0.65l2.33,2.38l-4.98,1.79l0.84,-2.45l-0.18,-0.48l-3.55,-1.8l-3.89,1.52l-1.42,3.38l-2.12,1.72l-2.64,-1.0l-3.11,0.21l-2.66,-2.22l-0.5,-0.01l-1.41,1.1l-1.44,0.17l-0.35,0.35l-0.32,2.47l-4.32,-0.64l-0.44,0.29l-0.58,2.11l-2.45,0.2l-4.15,7.68l-3.88,5.76l0.78,1.62l-0.64,1.16l-2.24,-0.06l-0.38,0.24l-1.66,3.89l0.15,5.17l1.57,2.04l-0.78,4.16l-2.02,2.48l-0.85,1.63l-1.3,-1.75l-0.58,-0.07l-4.87,4.19l-3.1,0.79l-3.16,-1.7l-0.85,-3.77l-0.77,-8.55l2.14,-2.31l6.55,-3.27l5.02,-4.17l10.63,-13.84l10.98,-8.7l5.35,-1.91l4.34,0.12l3.69,-3.64l4.49,0.19l4.37,-0.89ZM484.55,20.04l4.26,1.75l-3.1,2.55l-7.1,0.65l-7.08,-0.9l-0.37,-1.31l-0.37,-0.29l-3.44,-0.1l-2.08,-2.0l6.87,-1.44l3.9,1.31l2.39,-1.64l6.13,1.4ZM481.69,33.93l-4.45,1.74l-3.54,-0.99l1.12,-0.9l0.05,-0.58l-1.06,-1.22l4.22,-0.89l1.09,1.97l2.57,0.87ZM466.44,24.04l7.43,3.77l-5.41,1.86l-1.58,4.08l-2.26,1.2l-1.12,4.11l-2.61,0.18l-4.79,-2.86l1.84,-1.54l-0.1,-0.68l-3.69,-1.53l-4.77,-4.51l-1.73,-3.89l6.11,-1.82l1.54,1.92l3.57,-0.08l1.2,-1.96l3.32,-0.18l3.05,1.92Z",name:"Norway"},NA:{path:"M474.26,330.66l-0.97,0.04l-0.38,0.4l-0.07,8.9l-2.09,0.08l-0.39,0.4l-0.0,17.42l-1.98,1.23l-1.17,0.17l-2.44,-0.66l-0.48,-1.13l-0.99,-0.74l-0.54,0.05l-0.9,1.01l-1.53,-1.68l-0.93,-1.88l-1.99,-8.56l-0.06,-3.12l-0.33,-1.52l-2.3,-3.34l-1.91,-4.83l-1.96,-2.43l-0.12,-1.57l2.33,-0.79l1.43,0.07l1.81,1.13l10.23,-0.25l1.84,1.23l5.87,0.35ZM474.66,330.64l6.51,-1.6l1.9,0.39l-1.69,0.4l-1.31,0.83l-1.12,-0.94l-4.29,0.92Z",name:"Namibia"},NC:{path:"M838.78,341.24l-0.33,0.22l-2.9,-1.75l-3.26,-3.37l1.65,0.83l4.85,4.07Z",name:"New Caledonia"},NE:{path:"M454.75,226.53l1.33,1.37l0.48,0.07l1.27,-0.7l0.53,3.52l0.94,0.83l0.17,0.92l0.81,0.69l-0.44,0.95l-0.96,5.26l-0.13,3.22l-3.04,2.31l-1.22,3.57l1.02,1.24l-0.0,1.46l0.39,0.4l1.13,0.04l-0.9,1.25l-1.47,-2.42l-0.86,-0.29l-2.09,1.37l-1.74,-0.67l-1.45,-0.17l-0.85,0.35l-1.36,-0.07l-1.64,1.09l-1.06,0.05l-2.94,-1.28l-1.44,0.59l-1.01,-0.03l-0.97,-0.94l-2.7,-0.98l-2.69,0.3l-0.87,0.64l-0.47,1.6l-0.75,1.16l-0.12,1.53l-1.57,-1.1l-1.31,0.24l0.03,-0.81l-0.32,-0.41l-2.59,-0.52l-0.15,-1.16l-1.35,-1.6l-0.29,-1.0l0.13,-0.84l1.29,-0.08l1.08,-0.92l3.31,-0.22l2.22,-0.41l0.32,-0.34l0.2,-1.47l1.39,-1.88l-0.01,-5.66l3.36,-1.12l7.24,-5.12l8.42,-4.92l3.69,1.06Z",name:"Niger"},NG:{path:"M456.32,253.89l0.64,0.65l-0.28,1.04l-2.11,2.01l-2.03,5.18l-1.37,1.16l-1.15,3.18l-1.33,0.66l-1.46,-0.97l-1.21,0.16l-1.38,1.36l-0.91,0.24l-1.79,4.06l-2.33,0.81l-1.11,-0.07l-0.86,0.5l-1.71,-0.05l-1.19,-1.39l-0.89,-1.89l-1.77,-1.66l-3.95,-0.08l0.07,-5.21l0.42,-1.43l1.95,-2.3l-0.14,-0.91l0.43,-1.18l-0.53,-1.41l0.25,-2.92l0.72,-1.07l0.32,-1.34l0.46,-0.39l2.47,-0.28l2.34,0.89l1.15,1.02l1.28,0.04l1.22,-0.58l3.03,1.27l1.49,-0.14l1.36,-1.0l1.33,0.07l0.82,-0.35l3.45,0.8l1.82,-1.32l1.84,2.67l0.66,0.16Z",name:"Nigeria"},NZ:{path:"M857.8,379.65l1.86,3.12l0.44,0.18l0.3,-0.38l0.03,-1.23l0.38,0.27l0.57,2.31l2.02,0.94l1.81,0.27l1.57,-1.06l0.7,0.18l-1.15,3.59l-1.98,0.11l-0.74,1.2l0.2,1.11l-2.42,3.98l-1.49,0.92l-1.04,-0.85l1.21,-2.05l-0.81,-2.01l-2.63,-1.25l0.04,-0.57l1.82,-1.19l0.43,-2.34l-0.16,-2.03l-0.95,-1.82l-0.06,-0.72l-3.11,-3.64l-0.79,-1.52l1.56,1.45l1.76,0.66l0.65,2.34ZM853.83,393.59l0.57,1.24l0.59,0.16l1.42,-0.97l0.46,0.79l0.0,1.03l-2.47,3.48l-1.26,1.2l-0.06,0.5l0.55,0.87l-1.41,0.07l-2.33,1.38l-2.03,5.02l-3.02,2.16l-2.06,-0.06l-1.71,-1.04l-2.47,-0.2l-0.27,-0.73l1.22,-2.1l3.05,-2.94l1.62,-0.59l4.02,-2.82l1.57,-1.67l1.07,-2.16l0.88,-0.7l0.48,-1.75l1.24,-0.97l0.35,0.79Z",name:"New Zealand"},NP:{path:"M641.14,213.62l0.01,3.19l-1.74,0.04l-4.8,-0.86l-1.58,-1.39l-3.37,-0.34l-7.65,-3.7l0.8,-2.09l2.33,-1.7l1.77,0.75l2.49,1.76l1.38,0.41l0.99,1.35l1.9,0.52l1.99,1.17l5.49,0.9Z",name:"Nepal"},CI:{path:"M407.4,259.27l0.86,0.42l0.56,0.9l1.13,0.53l1.19,-0.61l0.97,-0.08l1.42,0.54l0.6,3.24l-1.03,2.08l-0.65,2.84l1.06,2.33l-0.06,0.53l-2.54,-0.47l-1.66,0.03l-3.06,0.46l-4.11,1.6l0.32,-3.06l-1.18,-1.31l-1.32,-0.66l0.42,-0.85l-0.2,-1.4l0.5,-0.67l0.01,-1.59l0.84,-0.32l0.26,-0.5l-1.15,-3.01l0.12,-0.5l0.51,-0.25l0.66,0.31l1.93,0.02l0.67,-0.71l0.71,-0.14l0.25,0.69l0.57,0.22l1.4,-0.61Z",name:"CΓ΄te d'Ivoire"},CH:{path:"M444.62,156.35l-0.29,0.87l0.18,0.53l1.13,0.58l1.0,0.1l-0.1,0.65l-0.79,0.38l-1.72,-0.37l-0.45,0.23l-0.45,1.04l-0.75,0.06l-0.84,-0.4l-1.32,1.0l-0.96,0.12l-0.88,-0.55l-0.81,-1.3l-0.49,-0.16l-0.63,0.26l0.02,-0.65l1.71,-1.66l0.1,-0.56l0.93,0.08l0.58,-0.46l1.99,0.02l0.66,-0.61l2.19,0.79Z",name:"Switzerland"},CO:{path:"M242.07,254.93l-1.7,0.59l-0.59,1.18l-1.7,1.69l-0.38,1.93l-0.67,1.43l0.31,0.57l1.03,0.13l0.25,0.9l0.57,0.64l-0.04,2.34l1.64,1.42l3.16,-0.24l1.26,0.28l1.67,2.06l0.41,0.13l4.09,-0.39l0.45,0.22l-0.92,1.95l-0.2,1.8l0.52,1.83l0.75,1.05l-1.12,1.1l0.07,0.63l0.84,0.51l0.74,1.29l-0.39,-0.45l-0.59,-0.01l-0.71,0.74l-4.71,-0.05l-0.4,0.41l0.03,1.57l0.33,0.39l1.11,0.2l-1.68,0.4l-0.29,0.38l-0.01,1.82l1.16,1.14l0.34,1.25l-1.05,7.05l-1.04,-0.87l1.26,-1.99l-0.13,-0.56l-2.18,-1.23l-1.38,0.2l-1.14,-0.38l-1.27,0.61l-1.55,-0.26l-1.38,-2.46l-1.23,-0.75l-0.85,-1.2l-1.67,-1.19l-0.86,0.13l-2.11,-1.32l-1.01,0.31l-1.8,-0.29l-0.52,-0.91l-3.09,-1.68l0.77,-0.52l-0.1,-1.12l0.41,-0.64l1.34,-0.32l2.0,-2.88l-0.11,-0.57l-0.66,-0.43l0.39,-1.38l-0.52,-2.1l0.49,-0.83l-0.4,-2.13l-0.97,-1.35l0.17,-0.66l0.86,-0.08l0.47,-0.75l-0.46,-1.63l1.41,-0.07l1.8,-1.69l0.93,-0.24l0.3,-0.38l0.45,-2.76l1.22,-1.0l1.44,-0.04l0.45,-0.5l1.91,0.12l2.93,-1.84l1.15,-1.14l0.91,0.46l-0.25,0.45Z",name:"Colombia"},CN:{path:"M740.23,148.97l4.57,1.3l2.8,2.17l0.98,2.9l0.38,0.27l3.8,0.0l2.32,-1.28l3.29,-0.75l-0.96,2.09l-1.02,1.28l-0.85,3.4l-1.52,2.73l-2.76,-0.5l-2.4,1.13l-0.21,0.45l0.64,2.57l-0.32,3.2l-0.94,0.06l-0.37,0.89l-0.91,-1.01l-0.64,0.07l-0.92,1.57l-3.73,1.25l-0.26,0.48l0.26,1.06l-1.5,-0.08l-1.09,-0.86l-0.56,0.06l-1.67,2.06l-2.7,1.56l-2.03,1.88l-3.4,0.83l-1.93,1.4l-1.15,0.34l0.33,-0.7l-0.41,-0.89l1.79,-1.79l0.02,-0.54l-1.32,-1.56l-0.48,-0.1l-2.24,1.09l-2.83,2.06l-1.51,1.83l-2.28,0.13l-1.55,1.49l-0.04,0.5l1.32,1.97l2.0,0.58l0.31,1.35l1.98,0.84l3.0,-1.96l2.0,1.02l1.49,0.11l0.22,0.83l-3.37,0.86l-1.12,1.48l-2.5,1.52l-1.29,1.99l0.14,0.56l2.57,1.48l0.97,2.7l3.17,4.63l-0.03,1.66l-1.35,0.65l-0.2,0.51l0.6,1.47l1.4,0.91l-0.89,3.82l-1.43,0.38l-3.85,6.44l-2.27,3.11l-6.78,4.57l-2.73,0.29l-1.45,1.04l-0.62,-0.61l-0.55,-0.01l-1.36,1.25l-3.39,1.27l-2.61,0.4l-1.1,2.79l-0.81,0.09l-0.49,-1.42l0.5,-0.85l-0.25,-0.59l-3.36,-0.84l-1.3,0.4l-2.31,-0.62l-0.94,-0.84l0.33,-1.28l-0.3,-0.49l-2.19,-0.46l-1.13,-0.93l-0.47,-0.02l-2.06,1.36l-4.29,0.28l-2.76,1.05l-0.28,0.43l0.32,2.53l-0.59,-0.03l-0.19,-1.34l-0.55,-0.34l-1.68,0.7l-2.46,-1.23l0.62,-1.87l-0.26,-0.51l-1.37,-0.44l-0.54,-2.22l-0.45,-0.3l-2.13,0.35l0.24,-2.48l2.39,-2.4l0.03,-4.31l-1.19,-0.92l-0.78,-1.49l-0.41,-0.21l-1.41,0.19l-1.98,-0.3l0.46,-1.07l-1.17,-1.7l-0.55,-0.11l-1.63,1.05l-2.25,-0.57l-2.89,1.73l-2.25,1.98l-1.75,0.29l-1.17,-0.71l-3.31,-0.65l-1.48,0.79l-1.04,1.27l-0.12,-1.17l-0.54,-0.34l-1.44,0.54l-5.55,-0.86l-1.98,-1.16l-1.89,-0.54l-0.99,-1.35l-1.34,-0.37l-2.55,-1.79l-2.01,-0.84l-1.21,0.56l-5.57,-3.45l-0.53,-2.31l1.19,0.25l0.48,-0.37l0.08,-1.42l-0.98,-1.56l0.15,-2.44l-2.69,-3.32l-4.12,-1.23l-0.67,-2.0l-1.92,-1.48l-0.38,-0.7l-0.51,-3.01l-1.52,-0.66l-0.7,0.13l-0.48,-2.05l0.55,-0.51l-0.09,-0.82l2.03,-1.19l1.6,-0.54l2.56,0.38l0.42,-0.22l0.85,-1.7l3.0,-0.33l1.1,-1.26l4.05,-1.77l0.39,-0.91l-0.17,-1.44l1.45,-0.67l0.2,-0.52l-2.07,-4.9l4.51,-1.12l1.37,-0.73l1.89,-5.51l4.98,0.86l1.51,-1.7l0.11,-2.87l1.99,-0.38l1.83,-2.06l0.49,-0.13l0.68,2.08l2.23,1.77l3.44,1.16l1.55,2.29l-0.92,3.49l0.96,1.67l6.54,1.13l2.95,1.87l1.47,0.35l1.06,2.62l1.53,1.91l3.05,0.08l5.14,0.67l3.37,-0.41l2.36,0.43l3.65,1.8l3.06,0.04l1.45,0.88l2.87,-1.59l3.95,-1.02l3.83,-0.14l3.06,-1.14l1.77,-1.6l1.72,-1.01l0.17,-0.49l-1.1,-2.05l1.02,-1.54l4.02,0.8l2.45,-1.61l3.76,-1.19l1.96,-2.13l1.63,-0.83l3.51,-0.4l1.92,0.34l0.46,-0.3l0.17,-1.5l-2.27,-2.22l-2.11,-1.09l-2.18,1.11l-2.32,-0.47l-1.29,0.32l-0.4,-0.82l2.73,-5.16l3.02,1.06l3.53,-2.06l0.18,-1.68l2.16,-3.35l1.49,-1.35l-0.03,-1.85l-1.07,-0.85l1.54,-1.26l2.98,-0.59l3.23,-0.09l3.64,0.99l2.04,1.16l3.29,6.71l0.92,3.19ZM696.92,237.31l-1.87,1.08l-1.63,-0.64l-0.06,-1.79l1.03,-0.98l2.58,-0.69l1.16,0.05l0.3,0.54l-0.98,1.06l-0.53,1.37Z",name:"China"},CM:{path:"M457.92,257.49l1.05,1.91l-1.4,0.16l-1.05,-0.23l-0.45,0.22l-0.54,1.19l0.08,0.45l1.48,1.47l1.05,0.45l1.01,2.46l-1.52,2.99l-0.68,0.68l-0.13,3.69l2.38,3.84l1.09,0.8l0.24,2.48l-3.67,-1.14l-11.27,-0.13l0.23,-1.79l-0.98,-1.66l-1.19,-0.54l-0.44,-0.97l-0.6,-0.42l1.71,-4.27l0.75,-0.13l1.38,-1.36l0.65,-0.03l1.71,0.99l1.93,-1.12l1.14,-3.18l1.38,-1.17l2.0,-5.14l2.17,-2.13l0.3,-1.64l-0.86,-0.88l0.03,-0.33l0.94,1.28l0.07,3.22Z",name:"Cameroon"},CL:{path:"M246.5,429.18l-3.14,1.83l-0.57,3.16l-0.64,0.05l-2.68,-1.06l-2.82,-2.33l-3.04,-1.89l-0.69,-1.85l0.63,-2.14l-1.21,-2.11l-0.31,-5.37l1.01,-2.91l2.57,-2.38l-0.18,-0.68l-3.16,-0.77l2.05,-2.47l0.77,-4.65l2.32,0.9l0.54,-0.29l1.31,-6.31l-0.22,-0.44l-1.68,-0.8l-0.56,0.28l-0.7,3.36l-0.81,-0.22l1.56,-9.41l1.15,-2.24l-0.71,-2.82l-0.18,-2.84l1.01,-0.33l3.26,-9.14l1.07,-4.22l-0.56,-4.21l0.74,-2.34l-0.29,-3.27l1.46,-3.34l2.04,-16.59l-0.66,-7.76l1.03,-0.53l0.54,-0.9l0.79,1.14l0.32,1.78l1.25,1.16l-0.69,2.55l1.33,2.9l0.97,3.59l0.46,0.29l1.5,-0.3l0.11,0.23l-0.76,2.44l-2.57,1.23l-0.23,0.37l0.08,4.33l-0.46,0.77l0.56,1.21l-1.58,1.51l-1.68,2.62l-0.89,2.47l0.2,2.7l-1.48,2.73l1.12,5.09l0.64,0.61l-0.01,2.29l-1.38,2.68l0.01,2.4l-1.89,2.04l0.02,2.75l0.69,2.57l-1.43,1.13l-1.26,5.68l0.39,3.51l-0.97,0.89l0.58,3.5l1.02,1.14l-0.65,1.02l0.15,0.57l1.0,0.53l0.16,0.69l-1.03,0.85l0.26,1.75l-0.89,4.03l-1.31,2.66l0.24,1.75l-0.71,1.83l-1.99,1.7l0.3,3.67l0.88,1.19l1.58,0.01l0.01,2.21l1.04,1.95l5.98,0.63ZM248.69,430.79l0.0,7.33l0.4,0.4l3.52,0.05l-0.44,0.75l-1.94,0.98l-2.49,-0.37l-1.88,-1.06l-2.55,-0.49l-5.59,-3.71l-2.38,-2.63l4.1,2.48l3.32,1.23l0.45,-0.12l1.29,-1.57l0.83,-2.32l2.05,-1.24l1.31,0.29Z",name:"Chile"},CA:{path:"M280.06,145.6l-1.67,2.88l0.07,0.49l0.5,0.04l1.46,-0.98l1.0,0.42l-0.56,0.72l0.17,0.62l2.22,0.89l1.35,-0.71l1.95,0.78l-0.66,2.01l0.5,0.51l1.32,-0.42l0.98,3.17l-0.91,2.41l-0.8,0.08l-1.23,-0.45l0.47,-2.25l-0.89,-0.83l-0.48,0.06l-2.78,2.63l-0.34,-0.02l1.02,-0.85l-0.14,-0.69l-2.4,-0.77l-7.4,0.08l-0.17,-0.41l1.3,-0.94l0.02,-0.64l-0.73,-0.58l1.85,-1.74l2.57,-5.16l1.47,-1.79l1.99,-1.05l0.46,0.06l-1.53,2.45ZM68.32,74.16l4.13,0.95l4.02,2.14l2.61,0.4l2.47,-1.89l2.88,-1.31l3.85,0.48l3.71,-1.94l3.82,-1.04l1.56,1.68l0.49,0.08l1.87,-1.04l0.65,-1.98l1.24,0.35l4.16,3.94l0.54,0.01l2.75,-2.49l0.26,2.59l0.49,0.35l3.08,-0.73l1.04,-1.27l2.73,0.23l3.83,1.86l5.86,1.61l3.47,0.75l2.44,-0.26l2.73,1.78l-2.98,1.81l-0.19,0.41l0.31,0.32l4.53,0.92l6.87,-0.5l2.0,-0.69l2.49,2.39l0.53,0.02l2.72,-2.16l-0.02,-0.64l-2.16,-1.54l1.15,-1.06l4.83,-0.61l1.84,0.95l2.48,2.31l3.01,-0.23l4.55,1.92l3.85,-0.67l3.61,0.1l0.41,-0.44l-0.25,-2.36l1.79,-0.61l3.49,1.32l-0.01,3.77l0.31,0.39l0.45,-0.22l1.48,-3.16l1.74,0.1l0.41,-0.3l1.13,-4.37l-2.78,-3.11l-2.8,-1.74l0.19,-4.64l2.71,-3.07l2.98,0.67l2.41,1.95l3.19,4.8l-1.99,1.97l0.21,0.68l4.33,0.84l-0.01,4.15l0.25,0.37l0.44,-0.09l3.07,-3.15l2.54,2.39l-0.61,3.33l2.42,2.88l0.61,0.0l2.61,-3.08l1.88,-3.82l0.17,-4.58l6.72,0.94l3.13,2.04l0.13,1.82l-1.76,2.19l-0.01,0.49l1.66,2.16l-0.26,1.71l-4.68,2.8l-3.28,0.61l-2.47,-1.2l-0.55,0.23l-0.73,2.04l-2.38,3.43l-0.74,1.77l-2.74,2.57l-3.44,0.25l-2.21,1.78l-0.28,2.53l-2.82,0.55l-3.12,3.22l-2.72,4.31l-1.03,3.17l-0.14,4.31l0.33,0.41l3.44,0.57l2.24,5.95l0.45,0.23l3.4,-0.69l4.52,1.51l2.43,1.31l1.91,1.73l3.1,0.96l2.62,1.46l6.6,0.54l-0.35,2.74l0.81,3.53l1.81,3.78l3.83,3.3l0.45,0.04l2.1,-1.28l1.37,-3.69l-1.31,-5.38l-1.45,-1.58l3.57,-1.47l2.84,-2.46l1.52,-2.8l-0.25,-2.55l-1.7,-3.07l-2.85,-2.61l2.8,-3.95l-1.08,-3.37l-0.79,-5.67l1.36,-0.7l6.76,1.41l2.12,-0.96l5.12,3.36l1.05,1.61l4.08,0.26l-0.06,2.87l0.83,4.7l0.3,0.32l2.16,0.54l1.73,2.06l0.5,0.09l3.63,-2.03l2.52,-4.19l1.26,-1.32l7.6,11.72l-0.92,2.04l0.16,0.51l3.3,1.97l2.22,1.98l4.1,0.98l1.43,0.99l0.95,2.79l2.1,0.68l0.84,1.08l0.17,3.45l-3.37,2.26l-4.22,1.24l-3.06,2.63l-4.06,0.51l-5.35,-0.69l-6.39,0.2l-2.3,2.41l-3.26,1.51l-6.47,7.15l-0.06,0.48l0.44,0.19l2.13,-0.52l4.17,-4.24l5.12,-2.62l3.52,-0.3l1.69,1.21l-2.12,2.21l0.81,3.47l1.02,2.61l3.47,1.6l4.14,-0.45l2.15,-2.8l0.26,1.48l1.14,0.8l-2.56,1.69l-5.5,1.82l-2.54,1.27l-2.74,2.15l-1.4,-0.16l-0.07,-2.01l4.14,-2.44l0.18,-0.45l-0.39,-0.29l-6.63,0.45l-1.39,-1.49l-0.14,-4.43l-1.11,-0.91l-1.82,0.39l-0.66,-0.66l-0.6,0.03l-1.91,2.39l-0.82,2.52l-0.8,1.27l-1.67,0.56l-0.46,0.76l-8.31,0.07l-1.21,0.62l-2.35,1.97l-0.71,-0.14l-1.37,0.96l-1.12,-0.48l-4.74,1.26l-0.9,1.17l0.21,0.62l1.73,0.3l-1.81,0.31l-1.85,0.81l-2.11,-0.13l-2.95,1.78l-0.69,-0.09l1.39,-2.1l1.73,-1.21l0.1,-2.29l1.16,-1.99l0.49,0.53l2.03,0.42l1.2,-1.16l0.02,-0.47l-2.66,-3.51l-2.28,-0.61l-5.64,-0.71l-0.4,-0.57l-0.79,0.13l0.2,-0.41l-0.22,-0.55l-0.68,-0.26l0.19,-1.26l-0.78,-0.73l0.31,-0.64l-0.29,-0.57l-2.6,-0.44l-0.75,-1.63l-0.94,-0.66l-4.31,-0.65l-1.13,1.19l-1.48,0.59l-0.85,1.06l-2.83,-0.76l-2.09,0.39l-2.39,-0.97l-4.24,-0.7l-0.57,-0.4l-0.41,-1.63l-0.4,-0.3l-0.85,0.02l-0.39,0.4l-0.01,0.85l-69.13,-0.01l-6.51,-4.52l-4.5,-1.38l-1.26,-2.66l0.33,-1.93l-0.23,-0.43l-3.01,-1.35l-0.55,-2.77l-2.89,-2.38l-0.04,-1.45l1.39,-1.83l-0.28,-2.55l-4.16,-2.2l-4.07,-6.6l-4.02,-3.22l-1.3,-1.88l-0.5,-0.13l-2.51,1.21l-2.23,1.87l-3.85,-3.88l-2.44,-1.04l-2.22,-0.13l0.03,-37.49ZM260.37,148.65l3.04,0.76l2.26,1.2l-3.78,-0.95l-1.53,-1.01ZM249.4,3.81l6.68,0.49l5.32,0.79l4.26,1.57l-0.07,1.1l-5.85,2.53l-6.02,1.21l-2.39,1.39l-0.18,0.45l0.39,0.29l4.01,-0.02l-4.65,2.82l-4.2,1.74l-4.19,4.59l-5.03,0.92l-1.67,1.15l-7.47,0.59l-0.37,0.37l0.32,0.42l2.41,0.49l-0.81,0.47l-0.12,0.59l1.83,2.41l-2.02,1.59l-3.81,1.51l-1.32,2.16l-3.38,1.53l-0.22,0.48l0.35,1.19l0.4,0.29l3.88,-0.18l0.03,0.61l-6.33,2.95l-6.41,-1.4l-7.43,0.79l-3.72,-0.62l-4.4,-0.25l-0.23,-1.83l4.29,-1.11l0.28,-0.51l-1.1,-3.45l1.0,-0.25l6.58,2.28l0.47,-0.16l-0.05,-0.49l-3.41,-3.45l-3.58,-0.98l1.48,-1.55l4.34,-1.29l0.97,-2.19l-0.16,-0.48l-3.42,-2.13l-0.81,-2.26l6.2,0.22l2.24,0.58l3.91,-2.1l0.2,-0.43l-0.35,-0.32l-5.64,-0.67l-8.73,0.36l-4.26,-1.9l-2.12,-2.4l-2.78,-1.66l-0.41,-1.52l3.31,-1.03l2.93,-0.2l4.91,-0.99l3.7,-2.27l2.87,0.3l2.62,1.67l0.56,-0.14l1.82,-3.2l3.13,-0.94l4.44,-0.69l7.53,-0.26l1.48,0.67l7.19,-1.06l10.8,0.79ZM203.85,57.54l0.01,0.42l1.97,2.97l0.68,-0.02l2.24,-3.72l5.95,-1.86l4.01,4.64l-0.35,2.91l0.5,0.43l4.95,-1.36l2.32,-1.8l5.31,2.28l3.27,2.11l0.3,1.84l0.48,0.33l4.42,-0.99l2.64,2.87l5.97,1.77l2.06,1.72l2.11,3.71l-4.19,1.86l-0.01,0.73l5.9,2.83l3.94,0.94l3.78,3.95l3.46,0.25l-0.63,2.37l-4.11,4.47l-2.76,-1.56l-3.9,-3.94l-3.59,0.41l-0.33,0.34l-0.19,2.72l2.63,2.38l3.42,1.89l0.94,0.97l1.55,3.75l-0.7,2.29l-2.74,-0.92l-6.25,-3.15l-0.51,0.13l0.05,0.52l6.07,5.69l0.18,0.59l-6.09,-1.39l-5.31,-2.24l-2.63,-1.66l0.6,-0.77l-0.12,-0.6l-7.39,-4.01l-0.59,0.37l0.03,0.79l-6.73,0.6l-1.69,-1.1l1.36,-2.46l4.51,-0.07l5.15,-0.52l0.31,-0.6l-0.74,-1.3l0.78,-1.84l3.21,-4.05l-0.67,-2.35l-1.11,-1.6l-3.84,-2.1l-4.35,-1.28l0.91,-0.63l0.06,-0.61l-2.65,-2.75l-2.34,-0.36l-1.89,-1.46l-0.53,0.03l-1.24,1.23l-4.36,0.55l-9.04,-0.99l-9.26,-1.98l-1.6,-1.22l2.22,-1.77l0.13,-0.44l-0.38,-0.27l-3.22,-0.02l-0.72,-4.25l1.83,-4.04l2.42,-1.85l5.5,-1.1l-1.39,2.35ZM261.19,159.33l2.07,0.61l1.44,-0.04l-1.15,0.63l-2.94,-1.23l-0.4,-0.68l0.36,-0.37l0.61,1.07ZM230.83,84.39l-2.37,0.18l-0.49,-1.63l0.93,-2.09l1.94,-0.51l1.62,0.99l0.02,1.52l-1.66,1.54ZM229.43,58.25l0.11,0.65l-4.87,-0.21l-2.72,0.62l-3.1,-2.57l0.08,-1.26l0.86,-0.23l5.57,0.51l4.08,2.5ZM222.0,105.02l-0.72,1.49l-0.63,-0.19l-0.48,-0.84l0.81,-0.99l0.65,0.05l0.37,0.46ZM183.74,38.32l2.9,1.7l4.79,-0.01l1.84,1.46l-0.49,1.68l0.23,0.48l2.82,1.14l1.76,1.26l7.01,0.65l4.1,-1.1l5.03,-0.43l3.93,0.35l2.48,1.77l0.46,1.7l-1.3,1.1l-3.56,1.01l-3.23,-0.59l-7.17,0.76l-5.09,0.09l-3.99,-0.6l-6.42,-1.54l-0.79,-2.51l-0.3,-2.49l-2.64,-2.5l-5.32,-0.72l-2.52,-1.4l0.68,-1.57l4.78,0.31ZM207.38,91.35l0.4,1.56l0.56,0.26l1.06,-0.52l1.32,0.96l5.42,2.57l0.2,1.68l0.46,0.35l1.68,-0.28l1.15,0.85l-1.55,0.87l-3.61,-0.88l-1.32,-1.69l-0.57,-0.06l-2.45,2.1l-3.12,1.79l-0.7,-1.87l-0.42,-0.26l-2.16,0.24l1.39,-1.39l0.32,-3.14l0.76,-3.35l1.18,0.22ZM215.49,102.6l-2.67,1.95l-1.4,-0.07l-0.3,-0.58l1.53,-1.48l2.84,0.18ZM202.7,24.12l2.53,1.59l-2.87,1.4l-4.53,4.05l-4.25,0.38l-5.03,-0.68l-2.45,-2.04l0.03,-1.62l1.82,-1.37l0.14,-0.45l-0.38,-0.27l-4.45,0.04l-2.59,-1.76l-1.41,-2.29l1.57,-2.32l1.62,-1.66l2.44,-0.39l0.25,-0.65l-0.6,-0.74l4.86,-0.25l3.24,3.11l8.16,2.3l1.9,3.61ZM187.47,59.2l-2.76,3.49l-2.38,-0.15l-1.44,-3.84l0.04,-2.2l1.19,-1.88l2.3,-1.23l5.07,0.17l4.11,1.02l-3.24,3.72l-2.88,0.89ZM186.07,48.79l-1.08,1.53l-3.34,-0.34l-2.56,-1.1l1.03,-1.75l3.25,-1.23l1.95,1.58l0.75,1.3ZM185.71,35.32l-5.3,-0.2l-0.32,-0.71l4.31,0.07l1.3,0.84ZM180.68,32.48l-3.34,1.0l-1.79,-1.1l-0.98,-1.87l-0.15,-1.73l4.1,0.53l2.67,1.7l-0.51,1.47ZM180.9,76.31l-1.1,1.08l-3.13,-1.23l-2.12,0.43l-2.71,-1.57l1.72,-1.09l1.55,-1.72l3.81,1.9l1.98,2.2ZM169.74,54.87l2.96,0.97l4.17,-0.57l0.41,0.88l-2.14,2.11l0.09,0.64l3.55,1.92l-0.4,3.72l-3.79,1.65l-2.17,-0.35l-1.72,-1.74l-6.02,-3.5l0.03,-0.85l4.68,0.54l0.4,-0.21l-0.05,-0.45l-2.48,-2.81l2.46,-1.95ZM174.45,40.74l1.37,1.73l0.07,2.44l-1.05,3.45l-3.79,0.47l-2.32,-0.69l0.05,-2.64l-0.44,-0.41l-3.68,0.35l-0.12,-3.1l2.45,0.1l3.67,-1.73l3.41,0.29l0.37,-0.26ZM170.05,31.55l0.67,1.56l-3.33,-0.49l-4.22,-1.77l-4.35,-0.16l1.4,-0.94l-0.06,-0.7l-2.81,-1.23l-0.12,-1.39l4.39,0.68l6.62,1.98l1.81,2.47ZM134.5,58.13l-1.02,1.82l0.45,0.58l5.4,-1.39l3.33,2.29l0.49,-0.03l2.6,-2.23l1.94,1.32l2.0,4.5l0.7,0.06l1.3,-2.29l-1.63,-4.46l1.69,-0.54l2.31,0.71l2.65,1.81l2.49,7.92l8.48,4.27l-0.19,1.35l-3.79,0.33l-0.26,0.67l1.4,1.49l-0.58,1.1l-4.23,-0.64l-4.43,-1.19l-3.0,0.28l-4.66,1.47l-10.52,1.04l-1.43,-2.02l-3.42,-1.2l-2.21,0.43l-2.51,-2.86l4.84,-1.05l3.6,0.19l3.27,-0.78l0.31,-0.39l-0.31,-0.39l-4.84,-1.06l-8.79,0.27l-0.85,-1.07l5.26,-1.66l0.27,-0.45l-0.4,-0.34l-3.8,0.06l-3.81,-1.06l1.81,-3.01l1.66,-1.79l6.48,-2.81l1.97,0.71ZM158.7,56.61l-1.7,2.44l-3.2,-2.75l0.37,-0.3l3.11,-0.18l1.42,0.79ZM149.61,42.73l1.01,1.89l0.5,0.18l2.14,-0.82l2.23,0.19l0.36,2.04l-1.33,2.09l-8.28,0.76l-6.35,2.15l-3.41,0.1l-0.19,-0.96l4.9,-2.08l0.23,-0.46l-0.41,-0.31l-11.25,0.59l-2.89,-0.74l3.04,-4.44l2.14,-1.32l6.81,1.69l4.58,3.06l4.37,0.39l0.36,-0.63l-3.36,-4.6l1.85,-1.53l2.18,0.51l0.77,2.26ZM144.76,34.41l-4.36,1.44l-3.0,-1.4l1.46,-1.24l3.47,-0.52l2.96,0.71l-0.52,1.01ZM145.13,29.83l-1.9,0.66l-3.67,-0.0l2.27,-1.61l3.3,0.95ZM118.92,65.79l-6.03,2.02l-1.33,-1.9l-5.38,-2.28l2.59,-5.05l2.16,-3.14l-0.02,-0.48l-1.97,-2.41l7.64,-0.7l3.6,1.02l6.3,0.27l4.42,2.95l-2.53,0.98l-6.24,3.43l-3.1,3.28l-0.11,2.01ZM129.54,35.53l-0.28,3.37l-1.72,1.62l-2.33,0.28l-4.61,2.19l-3.86,0.76l-2.64,-0.87l3.72,-3.4l5.01,-3.34l3.72,0.07l3.0,-0.67ZM111.09,152.69l-0.67,0.24l-3.85,-1.37l-0.83,-1.17l-2.12,-1.07l-0.66,-1.02l-2.4,-0.55l-0.74,-1.71l6.02,1.45l2.0,2.55l2.52,1.39l0.73,1.27ZM87.8,134.64l0.89,0.29l1.86,-0.21l-0.65,3.34l1.69,2.33l-1.31,-1.33l-0.99,-1.62l-1.17,-0.98l-0.33,-1.82Z",name:"Canada"},CG:{path:"M466.72,276.48l-0.1,1.03l-1.25,2.97l-0.19,3.62l-0.46,1.78l-0.23,0.63l-1.61,1.19l-1.21,1.39l-1.09,2.43l0.04,2.09l-3.25,3.24l-0.5,-0.24l-0.5,-0.83l-1.36,-0.02l-0.98,0.89l-1.68,-0.99l-1.54,1.24l-1.52,-1.96l1.57,-1.14l0.11,-0.52l-0.77,-1.35l2.1,-0.66l0.39,-0.73l1.05,0.82l2.21,0.11l1.12,-1.37l0.37,-1.81l-0.27,-2.09l-1.13,-1.5l1.0,-2.69l-0.13,-0.45l-0.92,-0.58l-1.6,0.17l-0.51,-0.94l0.1,-0.61l2.75,0.09l3.97,1.24l0.51,-0.33l0.17,-1.28l1.24,-2.21l1.28,-1.14l2.76,0.49Z",name:"Congo"},CF:{path:"M461.16,278.2l-0.26,-1.19l-1.09,-0.77l-0.84,-1.17l-0.29,-1.0l-1.04,-1.15l0.08,-3.43l0.58,-0.49l1.16,-2.35l1.85,-0.17l0.61,-0.62l0.97,0.58l3.15,-0.96l2.48,-1.92l0.02,-0.96l2.81,0.02l2.36,-1.17l1.93,-2.85l1.16,-0.93l1.11,-0.3l0.27,0.86l1.34,1.47l-0.39,2.01l0.3,1.01l4.01,2.75l0.17,0.93l2.63,2.31l0.6,1.44l2.08,1.4l-3.84,-0.21l-1.94,0.88l-1.23,-0.49l-2.67,1.2l-1.29,-0.18l-0.51,0.36l-0.6,1.22l-3.35,-0.65l-1.57,-0.91l-2.42,-0.83l-1.45,0.91l-0.97,1.27l-0.26,1.56l-3.22,-0.43l-1.49,1.33l-0.94,1.62Z",name:"Central African Rep."},CD:{path:"M487.01,272.38l2.34,-0.14l1.35,1.84l1.34,0.45l0.86,-0.39l1.21,0.12l1.07,-0.41l0.54,0.89l2.04,1.54l-0.14,2.72l0.7,0.54l-1.38,1.13l-1.53,2.54l-0.17,2.05l-0.59,1.08l-0.02,1.72l-0.72,0.84l-0.66,3.01l0.63,1.32l-0.44,4.26l0.64,1.47l-0.37,1.22l0.86,1.8l1.53,1.41l0.3,1.26l0.44,0.5l-4.08,0.75l-0.92,1.81l0.51,1.34l-0.74,5.43l0.17,0.38l2.45,1.46l0.54,-0.1l0.12,1.62l-1.28,-0.01l-1.85,-2.35l-1.94,-0.45l-0.48,-1.13l-0.55,-0.2l-1.41,0.74l-1.71,-0.3l-1.01,-1.18l-2.49,-0.19l-0.44,-0.77l-1.98,-0.21l-2.88,0.36l0.11,-2.41l-0.85,-1.13l-0.16,-1.36l0.32,-1.73l-0.46,-0.89l-0.04,-1.49l-0.4,-0.39l-2.53,0.02l0.1,-0.41l-0.39,-0.49l-1.28,0.01l-0.43,0.45l-1.62,0.32l-0.83,1.79l-1.09,-0.28l-2.4,0.52l-1.37,-1.91l-1.3,-3.3l-0.38,-0.27l-7.39,-0.03l-2.46,0.42l0.5,-0.45l0.37,-1.47l0.66,-0.38l0.92,0.08l0.73,-0.82l0.87,0.02l0.31,0.68l1.4,0.36l3.59,-3.63l0.01,-2.23l1.02,-2.29l2.69,-2.39l0.43,-0.99l0.49,-1.96l0.17,-3.51l1.25,-2.95l0.36,-3.14l0.86,-1.13l1.1,-0.66l3.57,1.73l3.65,0.73l0.46,-0.21l0.8,-1.46l1.24,0.19l2.61,-1.17l0.81,0.44l1.04,-0.03l0.59,-0.66l0.7,-0.16l1.81,0.25Z",name:"Dem. Rep. Congo"},CZ:{path:"M458.46,144.88l1.22,1.01l1.47,0.23l0.13,0.93l1.36,0.68l0.54,-0.2l0.24,-0.55l1.15,0.25l0.53,1.09l1.68,0.18l0.6,0.84l-1.04,0.73l-0.96,1.28l-1.6,0.17l-0.55,0.56l-1.04,-0.46l-1.05,0.15l-2.12,-0.96l-1.05,0.34l-1.2,1.12l-1.56,-0.87l-2.57,-2.1l-0.53,-1.88l4.7,-2.52l0.71,0.26l0.9,-0.28Z",name:"Czech Rep."},CY:{path:"M504.36,193.47l0.43,0.28l-1.28,0.57l-0.92,-0.28l-0.24,-0.46l2.01,-0.13Z",name:"Cyprus"},CR:{path:"M211.34,258.05l0.48,0.99l1.6,1.6l-0.54,0.45l0.29,1.42l-0.25,1.19l-1.09,-0.59l-0.05,-1.25l-2.46,-1.42l-0.28,-0.77l-0.66,-0.45l-0.45,-0.0l-0.11,1.04l-1.32,-0.95l0.31,-1.3l-0.36,-0.6l0.31,-0.27l1.42,0.58l1.29,-0.14l0.56,0.56l0.74,0.17l0.55,-0.27Z",name:"Costa Rica"},CU:{path:"M221.21,227.25l1.27,1.02l2.19,-0.28l4.43,3.33l2.08,0.43l-0.1,0.38l0.36,0.5l1.75,0.1l1.48,0.84l-3.11,0.51l-4.15,-0.03l0.77,-0.67l-0.04,-0.64l-1.2,-0.74l-1.49,-0.16l-0.7,-0.61l-0.56,-1.4l-0.4,-0.25l-1.34,0.1l-2.2,-0.66l-0.88,-0.58l-3.18,-0.4l-0.27,-0.16l0.58,-0.74l-0.36,-0.29l-2.72,-0.05l-1.7,1.29l-0.91,0.03l-0.61,0.69l-1.01,0.22l1.11,-1.29l1.01,-0.52l3.69,-1.01l3.98,0.21l2.21,0.84Z",name:"Cuba"},SZ:{path:"M500.35,351.36l0.5,2.04l-0.38,0.89l-1.05,0.21l-1.23,-1.2l-0.02,-0.64l0.83,-1.57l1.34,0.27Z",name:"Swaziland"},SY:{path:"M511.0,199.79l0.05,-1.33l0.54,-1.36l1.28,-0.99l0.13,-0.45l-0.41,-1.11l-1.14,-0.36l-0.19,-1.74l0.52,-1.0l1.29,-1.21l0.2,-1.18l0.59,0.23l2.62,-0.76l1.36,0.52l2.06,-0.01l2.95,-1.08l3.25,-0.26l-0.67,0.94l-1.28,0.66l-0.21,0.4l0.23,2.01l-0.88,3.19l-10.15,5.73l-2.15,-0.85Z",name:"Syria"},KG:{path:"M621.35,172.32l-3.87,1.69l-0.96,1.18l-3.04,0.34l-1.13,1.86l-2.36,-0.35l-1.99,0.63l-2.39,1.4l0.06,0.95l-0.4,0.37l-4.52,0.43l-3.02,-0.93l-2.37,0.17l0.11,-0.79l2.32,0.42l1.13,-0.88l1.99,0.2l3.21,-2.14l-0.03,-0.69l-2.97,-1.57l-1.94,0.65l-1.22,-0.74l1.71,-1.58l-0.12,-0.67l-0.36,-0.15l0.32,-0.77l1.36,-0.35l4.02,1.02l0.49,-0.3l0.35,-1.59l1.09,-0.48l3.42,1.22l1.11,-0.31l7.64,0.39l1.16,1.0l1.23,0.39Z",name:"Kyrgyzstan"},KE:{path:"M506.26,284.69l1.87,-2.56l0.93,-2.15l-1.38,-4.08l-1.06,-1.6l2.82,-2.75l0.79,0.26l0.12,1.41l0.86,0.83l1.9,0.11l3.28,2.13l3.57,0.44l1.05,-1.12l1.96,-0.9l0.82,0.68l1.16,0.09l-1.78,2.45l0.03,9.12l1.3,1.94l-1.37,0.78l-0.67,1.03l-1.08,0.46l-0.34,1.67l-0.81,1.07l-0.45,1.55l-0.68,0.56l-3.2,-2.23l-0.35,-1.58l-8.86,-4.98l0.14,-1.6l-0.57,-1.04Z",name:"Kenya"},SS:{path:"M481.71,263.34l1.07,-0.72l1.2,-3.18l1.36,-0.26l1.61,1.99l0.87,0.34l1.1,-0.41l1.5,0.07l0.57,0.53l2.49,0.0l0.44,-0.63l1.07,-0.4l0.45,-0.84l0.59,-0.33l1.9,1.33l1.6,-0.2l2.83,-3.33l-0.32,-2.21l1.59,-0.52l-0.24,1.6l0.3,1.83l1.35,1.18l0.2,1.87l0.35,0.41l0.02,1.53l-0.23,0.47l-1.42,0.25l-0.85,1.44l0.3,0.6l1.4,0.16l1.11,1.08l0.59,1.13l1.03,0.53l1.28,2.36l-4.41,3.98l-1.74,0.01l-1.89,0.55l-1.47,-0.52l-1.15,0.57l-2.96,-2.62l-1.3,0.49l-1.06,-0.15l-0.79,0.39l-0.82,-0.22l-1.8,-2.7l-1.91,-1.1l-0.66,-1.5l-2.62,-2.32l-0.18,-0.94l-2.37,-1.6Z",name:"S. Sudan"},SR:{path:"M283.12,270.19l2.1,0.53l-1.08,1.95l0.2,1.72l0.93,1.49l-0.59,2.03l-0.43,0.71l-1.12,-0.42l-1.32,0.22l-0.93,-0.2l-0.46,0.26l-0.25,0.73l0.33,0.7l-0.89,-0.13l-1.39,-1.97l-0.31,-1.34l-0.97,-0.31l-0.89,-1.47l0.35,-1.61l1.45,-0.82l0.33,-1.87l2.61,0.44l0.57,-0.47l1.75,-0.16Z",name:"Suriname"},KH:{path:"M689.52,249.39l0.49,1.45l-0.28,2.74l-4.0,1.86l-0.16,0.6l0.68,0.95l-2.06,0.17l-2.05,0.97l-1.82,-0.32l-2.12,-3.7l-0.55,-2.85l1.4,-1.85l3.02,-0.45l2.23,0.35l2.01,0.98l0.51,-0.14l0.95,-1.48l1.74,0.74Z",name:"Cambodia"},SV:{path:"M195.8,250.13l1.4,-1.19l2.24,1.45l0.98,-0.27l0.44,0.2l-0.27,1.05l-1.14,-0.03l-3.64,-1.21Z",name:"El Salvador"},SK:{path:"M476.82,151.17l-1.14,1.9l-2.73,-0.92l-0.82,0.2l-0.74,0.8l-3.46,0.73l-0.47,0.69l-1.76,0.33l-1.88,-1.0l-0.18,-0.81l0.38,-0.75l1.87,-0.32l1.74,-1.89l0.83,0.16l0.79,-0.34l1.51,1.04l1.34,-0.63l1.25,0.3l1.65,-0.42l1.81,0.95Z",name:"Slovakia"},KR:{path:"M737.51,185.84l0.98,-0.1l0.87,-1.17l2.69,-0.32l0.33,-0.29l1.76,2.79l0.58,1.76l0.02,3.12l-0.8,1.32l-2.21,0.55l-1.93,1.13l-1.8,0.19l-0.2,-1.1l0.43,-2.28l-0.95,-2.56l1.43,-0.37l0.23,-0.62l-1.43,-2.06Z",name:"Korea"},SI:{path:"M456.18,162.07l-0.51,-1.32l0.18,-1.05l1.69,0.2l1.42,-0.71l2.09,-0.07l0.62,-0.51l0.21,0.47l-1.61,0.67l-0.44,1.34l-0.66,0.24l-0.26,0.82l-1.22,-0.49l-0.84,0.46l-0.69,-0.04Z",name:"Slovenia"},KP:{path:"M736.77,185.16l-0.92,-0.42l-0.88,0.62l-1.21,-0.88l0.96,-1.15l0.59,-2.59l-0.46,-0.74l-2.09,-0.77l1.64,-1.52l2.72,-1.58l1.58,-1.91l1.11,0.78l2.17,0.11l0.41,-0.5l-0.3,-1.22l3.52,-1.18l0.94,-1.4l0.98,1.08l-2.19,2.18l0.01,2.14l-1.06,0.54l-1.41,1.4l-1.7,0.52l-1.25,1.09l-0.14,1.98l0.94,0.45l1.15,1.04l-0.13,0.26l-2.6,0.29l-1.13,1.29l-1.22,0.08Z",name:"Dem. Rep. Korea"},SO:{path:"M525.13,288.48l-1.13,-1.57l-0.03,-8.86l2.66,-3.38l1.67,-0.13l2.13,-1.69l3.41,-0.23l7.08,-7.55l2.91,-3.69l0.08,-4.82l2.98,-0.67l1.24,-0.86l0.45,-0.0l-0.2,3.0l-1.21,3.62l-2.73,5.97l-2.13,3.65l-5.03,6.16l-8.56,6.4l-2.78,3.08l-0.8,1.56Z",name:"Somalia"},SN:{path:"M390.09,248.21l0.12,1.55l0.49,1.46l0.96,0.82l0.05,1.28l-1.26,-0.19l-0.75,0.33l-1.84,-0.61l-5.84,-0.13l-2.54,0.51l-0.22,-1.03l1.77,0.04l2.01,-0.91l1.03,0.48l1.09,0.04l1.29,-0.62l0.14,-0.58l-0.51,-0.74l-1.81,0.25l-1.13,-0.63l-0.79,0.04l-0.72,0.61l-2.31,0.06l-0.92,-1.77l-0.81,-0.64l0.64,-0.35l2.46,-3.74l1.04,0.19l1.38,-0.56l1.19,-0.02l2.72,1.37l3.03,3.48Z",name:"Senegal"},SL:{path:"M394.46,264.11l-1.73,1.98l-0.58,1.33l-2.07,-1.06l-1.22,-1.26l-0.65,-2.39l1.16,-0.96l0.67,-1.17l1.21,-0.52l1.66,0.0l1.03,1.64l0.52,2.41Z",name:"Sierra Leone"},SB:{path:"M826.69,311.6l-0.61,0.09l-0.2,-0.33l0.37,0.15l0.44,0.09ZM824.18,307.38l-0.26,-0.3l-0.31,-0.91l0.03,0.0l0.54,1.21ZM823.04,309.33l-1.66,-0.22l-0.2,-0.52l1.16,0.28l0.69,0.46ZM819.28,304.68l1.14,0.65l0.02,0.03l-0.81,-0.44l-0.35,-0.23Z",name:"Solomon Is."},SA:{path:"M537.53,210.34l2.0,0.24l0.9,1.32l1.49,-0.06l0.87,2.08l1.29,0.76l0.51,0.99l1.56,1.03l-0.1,1.9l0.32,0.9l1.58,2.47l0.76,0.53l0.7,-0.04l1.68,4.23l7.53,1.33l0.51,-0.29l0.77,1.25l-1.55,4.87l-7.29,2.52l-7.3,1.03l-2.34,1.17l-1.88,2.74l-0.76,0.28l-0.82,-0.78l-0.91,0.12l-2.88,-0.51l-3.51,0.25l-0.86,-0.56l-0.57,0.15l-0.66,1.27l0.16,1.11l-0.43,0.32l-0.93,-1.4l-0.33,-1.16l-1.23,-0.88l-1.27,-2.06l-0.78,-2.22l-1.73,-1.79l-1.14,-0.48l-1.54,-2.31l-0.21,-3.41l-1.44,-2.93l-1.27,-1.16l-1.33,-0.57l-1.31,-3.37l-0.77,-0.67l-0.97,-1.97l-2.8,-4.03l-1.06,-0.17l0.37,-1.96l0.2,-0.72l2.74,0.3l1.08,-0.84l0.6,-0.94l1.74,-0.35l0.65,-1.03l0.71,-0.4l0.1,-0.62l-2.06,-2.28l4.39,-1.22l0.48,-0.37l2.77,0.69l3.66,1.9l7.03,5.5l4.87,0.3Z",name:"Saudi Arabia"},SE:{path:"M480.22,89.3l-4.03,1.17l-2.43,2.86l0.26,2.57l-8.77,6.64l-1.78,5.79l1.78,2.68l2.22,1.96l-2.07,3.77l-2.72,1.13l-0.95,6.04l-1.29,3.01l-2.74,-0.31l-0.4,0.22l-1.31,2.59l-2.34,0.13l-0.75,-3.09l-2.08,-4.03l-1.83,-4.96l1.0,-1.93l2.14,-2.7l0.83,-4.45l-1.6,-2.17l-0.15,-4.94l1.48,-3.39l2.58,-0.15l0.87,-1.59l-0.78,-1.57l3.76,-5.59l4.04,-7.48l2.17,0.01l0.39,-0.29l0.57,-2.07l4.37,0.64l0.46,-0.34l0.33,-2.56l1.1,-0.13l6.94,4.87l0.06,6.32l0.66,1.36Z",name:"Sweden"},SD:{path:"M505.98,259.4l-0.34,-0.77l-1.17,-0.9l-0.26,-1.61l0.29,-1.81l-0.34,-0.46l-1.16,-0.17l-0.54,0.59l-1.23,0.11l-0.28,0.65l0.53,0.65l0.17,1.22l-2.44,3.0l-0.96,0.19l-2.39,-1.4l-0.95,0.52l-0.38,0.78l-1.11,0.41l-0.29,0.5l-1.94,0.0l-0.54,-0.52l-1.81,-0.09l-0.95,0.4l-2.45,-2.35l-2.07,0.54l-0.73,1.26l-0.6,2.1l-1.25,0.58l-0.75,-0.62l0.27,-2.65l-1.48,-1.78l-0.22,-1.48l-0.92,-0.96l-0.02,-1.29l-0.57,-1.16l-0.68,-0.16l0.69,-1.29l-0.18,-1.14l0.65,-0.62l0.03,-0.55l-0.36,-0.41l1.55,-2.97l1.91,0.16l0.43,-0.4l-0.1,-10.94l2.49,-0.01l0.4,-0.4l-0.0,-4.82l29.02,0.0l0.64,2.04l-0.49,0.66l0.36,2.69l0.93,3.16l2.12,1.55l-0.89,1.04l-1.72,0.39l-0.98,0.9l-1.43,5.65l0.24,1.15l-0.38,2.06l-0.96,2.38l-1.53,1.31l-1.32,2.91l-1.22,0.86l-0.37,1.34Z",name:"Sudan"},DO:{path:"M241.8,239.2l0.05,-0.65l-0.46,-0.73l0.42,-0.44l0.19,-1.0l-0.09,-1.53l1.66,0.01l1.99,0.63l0.33,0.67l1.28,0.19l0.33,0.76l1.0,0.08l0.8,0.62l-0.45,0.51l-1.13,-0.47l-1.88,-0.01l-1.27,0.59l-0.75,-0.55l-1.01,0.54l-0.79,1.4l-0.23,-0.61Z",name:"Dominican Rep."},DJ:{path:"M528.43,256.18l-0.45,0.66l-0.58,-0.25l-1.51,0.13l-0.18,-1.01l1.45,-1.95l0.83,0.17l0.77,-0.44l0.2,1.0l-1.2,0.51l-0.06,0.7l0.73,0.47Z",name:"Djibouti"},DK:{path:"M452.28,129.07l-1.19,2.24l-2.13,-1.6l-0.23,-0.95l2.98,-0.95l0.57,1.26ZM447.74,126.31l-0.26,0.57l-0.88,-0.07l-1.8,2.53l0.48,1.69l-1.09,0.36l-1.61,-0.39l-0.89,-1.69l-0.07,-3.43l0.96,-1.73l2.02,-0.2l1.09,-1.07l1.33,-0.67l-0.05,1.06l-0.73,1.41l0.3,1.0l1.2,0.64Z",name:"Denmark"},DE:{path:"M453.14,155.55l-0.55,-0.36l-1.2,-0.1l-1.87,0.57l-2.13,-0.13l-0.56,0.63l-0.86,-0.6l-0.96,0.09l-2.57,-0.93l-0.85,0.67l-1.47,-0.02l0.24,-1.75l1.23,-2.14l-0.28,-0.59l-3.52,-0.58l-0.92,-0.66l0.12,-1.2l-0.48,-0.88l0.27,-2.17l-0.37,-3.03l1.41,-0.22l0.63,-1.26l0.66,-3.19l-0.41,-1.18l0.26,-0.39l1.66,-0.15l0.33,0.54l0.62,0.07l1.7,-1.69l-0.54,-3.02l1.37,0.33l1.31,-0.37l0.31,1.18l2.25,0.71l-0.02,0.92l0.5,0.4l2.55,-0.65l1.34,-0.87l2.57,1.24l1.06,0.98l0.48,1.44l-0.57,0.74l-0.0,0.48l0.87,1.15l0.57,1.64l-0.14,1.29l0.82,1.7l-1.5,-0.07l-0.56,0.57l-4.47,2.15l-0.22,0.54l0.68,2.26l2.58,2.16l-0.66,1.11l-0.79,0.36l-0.23,0.43l0.32,1.87Z",name:"Germany"},YE:{path:"M528.27,246.72l0.26,-0.42l-0.22,-1.01l0.19,-1.5l0.92,-0.69l-0.07,-1.35l0.39,-0.75l1.01,0.47l3.34,-0.27l3.76,0.41l0.95,0.81l1.36,-0.58l1.74,-2.62l2.18,-1.09l6.86,-0.94l2.48,5.41l-1.64,0.76l-0.56,1.9l-6.23,2.16l-2.29,1.8l-1.93,0.05l-1.41,1.02l-4.24,0.74l-1.72,1.49l-3.28,0.19l-0.52,-1.18l0.02,-1.51l-1.34,-3.29Z",name:"Yemen"},AT:{path:"M462.89,152.8l0.04,2.25l-1.07,0.0l-0.33,0.63l0.36,0.51l-1.04,2.13l-2.02,0.07l-1.33,0.7l-5.29,-0.99l-0.47,-0.93l-0.44,-0.21l-2.47,0.55l-0.42,0.51l-3.18,-0.81l0.43,-0.91l1.12,0.78l0.6,-0.17l0.25,-0.58l1.93,0.12l1.86,-0.56l1.0,0.08l0.68,0.57l0.62,-0.15l0.26,-0.77l-0.3,-1.78l0.8,-0.44l0.68,-1.15l1.52,0.85l0.47,-0.06l1.34,-1.25l0.64,-0.17l1.81,0.92l1.28,-0.11l0.7,0.37Z",name:"Austria"},DZ:{path:"M441.46,188.44l-0.32,1.07l0.39,2.64l-0.54,2.16l-1.58,1.82l0.37,2.39l1.91,1.55l0.18,0.8l1.42,1.03l1.84,7.23l0.12,1.16l-0.57,5.0l0.2,1.51l-0.87,0.99l-0.02,0.51l1.41,1.86l0.14,1.2l0.89,1.48l0.5,0.16l0.98,-0.41l1.73,1.08l0.82,1.23l-8.22,4.81l-7.23,5.11l-3.43,1.13l-2.3,0.21l-0.28,-1.59l-2.56,-1.09l-0.67,-1.25l-26.12,-17.86l0.01,-3.47l3.77,-1.88l2.44,-0.41l2.12,-0.75l1.08,-1.42l2.81,-1.05l0.35,-2.08l1.33,-0.29l1.04,-0.94l3.47,-0.69l0.46,-1.08l-0.1,-0.45l-0.58,-0.52l-0.82,-2.81l-0.19,-1.83l-0.78,-1.49l2.03,-1.31l2.63,-0.48l1.7,-1.22l2.31,-0.84l8.24,-0.73l1.49,0.38l2.28,-1.1l2.46,-0.02l0.92,0.6l1.35,-0.05Z",name:"Algeria"},US:{path:"M892.72,99.2l1.31,0.53l1.41,-0.37l1.89,0.98l1.89,0.42l-1.32,0.58l-2.9,-1.53l-2.08,0.22l-0.26,-0.15l0.07,-0.67ZM183.22,150.47l0.37,1.47l1.12,0.85l4.23,0.7l2.39,0.98l2.17,-0.38l1.85,0.5l-1.55,0.65l-3.49,2.61l-0.16,0.77l0.5,0.39l2.33,-0.61l1.77,1.02l5.15,-2.4l-0.31,0.65l0.25,0.56l1.36,0.38l1.71,1.16l4.7,-0.88l0.67,0.85l1.31,0.21l0.58,0.58l-1.34,0.17l-2.18,-0.32l-3.6,0.89l-2.71,3.25l0.35,0.9l0.59,-0.0l0.55,-0.6l-1.36,4.65l0.29,3.09l0.67,1.58l0.61,0.45l1.77,-0.44l1.6,-1.96l0.14,-2.21l-0.82,-1.96l0.11,-1.13l1.19,-2.37l0.44,-0.33l0.48,0.75l0.4,-0.29l0.4,-1.37l0.6,-0.47l0.24,-0.8l1.69,0.49l1.65,1.08l-0.03,2.37l-1.27,1.13l-0.0,1.13l0.87,0.36l1.66,-1.29l0.5,0.17l0.5,2.6l-2.49,3.75l0.17,0.61l1.54,0.62l1.48,0.17l1.92,-0.44l4.72,-2.15l2.16,-1.8l-0.05,-1.24l0.75,-0.22l3.92,0.36l2.12,-1.05l0.21,-0.4l-0.28,-1.48l3.27,-2.4l8.32,-0.02l0.56,-0.82l1.9,-0.77l0.93,-1.51l0.74,-2.37l1.58,-1.98l0.92,0.62l1.47,-0.47l0.8,0.66l-0.0,4.09l1.96,2.6l-2.34,1.31l-5.37,2.09l-1.83,2.72l0.02,1.79l0.83,1.59l0.54,0.23l-6.19,0.94l-2.2,0.89l-0.23,0.48l0.45,0.29l2.99,-0.46l-2.19,0.56l-1.13,0.0l-0.15,-0.32l-0.48,0.08l-0.76,0.82l0.22,0.67l0.32,0.06l-0.41,1.62l-1.27,1.58l-1.48,-1.07l-0.49,-0.04l-0.16,0.46l0.52,1.58l0.61,0.59l0.03,0.79l-0.95,1.38l-1.21,-1.22l-0.27,-2.27l-0.35,-0.35l-0.42,0.25l-0.48,1.27l0.33,1.41l-0.97,-0.27l-0.48,0.24l0.18,0.5l1.52,0.83l0.1,2.52l0.79,0.51l0.52,3.42l-1.42,1.88l-2.47,0.8l-1.71,1.66l-1.31,0.25l-1.27,1.03l-0.43,0.99l-2.69,1.78l-2.64,3.03l-0.45,2.12l0.45,2.08l0.85,2.38l1.09,1.9l0.04,1.2l1.16,3.06l-0.18,2.69l-0.55,1.43l-0.47,0.21l-0.89,-0.23l-0.49,-1.18l-0.87,-0.56l-2.75,-5.16l0.48,-1.68l-0.72,-1.78l-2.01,-2.38l-1.12,-0.53l-2.72,1.18l-1.47,-1.35l-1.57,-0.68l-2.99,0.31l-2.17,-0.3l-2.0,0.19l-1.15,0.46l-0.19,0.58l0.39,0.63l0.14,1.34l-0.84,-0.2l-0.84,0.46l-1.58,-0.07l-2.08,-1.44l-2.09,0.33l-1.91,-0.62l-3.73,0.84l-2.39,2.07l-2.54,1.22l-1.45,1.41l-0.61,1.38l0.34,3.71l-0.29,0.02l-3.5,-1.33l-1.25,-3.11l-1.44,-1.5l-2.24,-3.56l-1.76,-1.09l-2.27,-0.01l-1.71,2.07l-1.76,-0.69l-1.16,-0.74l-1.52,-2.98l-3.93,-3.16l-4.34,-0.0l-0.4,0.4l-0.0,0.74l-6.5,0.02l-9.02,-3.14l-0.34,-0.71l-5.7,0.49l-0.43,-1.29l-1.62,-1.61l-1.14,-0.38l-0.55,-0.88l-1.28,-0.13l-1.01,-0.77l-2.22,-0.27l-0.43,-0.3l-0.36,-1.58l-2.4,-2.83l-2.01,-3.85l-0.06,-0.9l-2.92,-3.26l-0.33,-2.29l-1.3,-1.66l0.52,-2.37l-0.09,-2.57l-0.78,-2.3l0.95,-2.82l0.61,-5.68l-0.47,-4.27l-1.46,-4.08l3.19,0.79l1.26,2.83l0.69,0.08l0.69,-1.14l-1.1,-4.79l68.76,-0.0l0.4,-0.4l0.14,-0.86ZM32.44,67.52l1.73,1.97l0.55,0.05l0.99,-0.79l3.65,0.24l-0.09,0.62l0.32,0.45l3.83,0.77l2.61,-0.43l5.19,1.4l4.84,0.43l1.89,0.57l3.42,-0.7l6.14,1.87l-0.03,38.06l0.38,0.4l2.39,0.11l2.31,0.98l3.9,3.99l0.55,0.04l2.4,-2.03l2.16,-1.04l1.2,1.71l3.95,3.14l4.09,6.63l4.2,2.29l0.06,1.83l-1.02,1.23l-1.16,-1.08l-2.04,-1.03l-0.67,-2.89l-3.28,-3.03l-1.65,-3.57l-6.35,-0.32l-2.82,-1.01l-5.26,-3.85l-6.77,-2.04l-3.53,0.3l-4.81,-1.69l-3.25,-1.63l-2.78,0.8l-0.28,0.46l0.44,2.21l-3.91,0.96l-2.26,1.27l-2.3,0.65l-0.27,-1.65l1.05,-3.42l2.49,-1.09l0.16,-0.6l-0.69,-0.96l-0.55,-0.1l-3.19,2.12l-1.78,2.56l-3.55,2.61l-0.04,0.61l1.56,1.52l-2.07,2.29l-5.11,2.57l-0.77,1.66l-3.76,1.77l-0.92,1.73l-2.69,1.38l-1.81,-0.22l-6.95,3.32l-3.97,0.91l4.85,-2.5l2.59,-1.86l3.26,-0.52l1.19,-1.4l3.42,-2.1l2.59,-2.27l0.42,-2.68l1.23,-2.1l-0.04,-0.46l-0.45,-0.11l-2.68,1.03l-0.63,-0.49l-0.53,0.03l-1.05,1.04l-1.36,-1.54l-0.66,0.08l-0.32,0.62l-0.58,-1.14l-0.56,-0.16l-2.41,1.42l-1.07,-0.0l-0.17,-1.75l0.3,-1.71l-1.61,-1.33l-3.41,0.59l-1.96,-1.63l-1.57,-0.84l-0.15,-2.21l-1.7,-1.43l0.82,-1.88l1.99,-2.12l0.88,-1.92l1.71,-0.24l2.04,0.51l1.87,-1.77l1.91,0.25l1.91,-1.23l0.17,-0.43l-0.47,-1.82l-1.07,-0.7l1.39,-1.17l0.12,-0.45l-0.39,-0.26l-1.65,0.07l-2.66,0.88l-0.75,0.78l-1.92,-0.8l-3.46,0.44l-3.44,-0.91l-1.06,-1.61l-2.65,-1.99l2.91,-1.43l5.5,-2.0l1.52,0.0l-0.26,1.62l0.41,0.46l5.29,-0.16l0.3,-0.65l-2.03,-2.59l-3.14,-1.68l-1.79,-2.12l-2.4,-1.83l-3.09,-1.24l1.04,-1.69l4.23,-0.14l3.36,-2.07l0.73,-2.27l2.39,-1.99l2.42,-0.52l4.65,-1.97l2.46,0.23l3.71,-2.35l3.5,0.89ZM37.6,123.41l-2.25,1.23l-0.95,-0.69l-0.29,-1.24l3.21,-1.63l1.42,0.21l0.67,0.7l-1.8,1.42ZM31.06,234.03l0.98,0.47l0.74,0.87l-1.77,1.07l-0.44,-1.53l0.49,-0.89ZM29.34,232.07l0.18,0.05l0.08,0.05l-0.16,0.03l-0.11,-0.14ZM25.16,230.17l0.05,-0.03l0.18,0.22l-0.13,-0.01l-0.1,-0.18ZM5.89,113.26l-1.08,0.41l-2.21,-1.12l1.53,-0.4l1.62,0.28l0.14,0.83Z",name:"United States"},LV:{path:"M489.16,122.85l0.96,0.66l0.22,1.65l0.68,1.76l-3.65,1.7l-2.23,-1.58l-1.29,-0.26l-0.68,-0.77l-2.42,0.34l-4.16,-0.23l-2.47,0.9l0.06,-1.98l1.13,-2.06l1.95,-1.02l2.12,2.58l2.01,-0.07l0.38,-0.33l0.44,-2.52l1.76,-0.53l3.06,1.7l2.15,0.07Z",name:"Latvia"},UY:{path:"M286.85,372.74l-0.92,1.5l-2.59,1.44l-1.69,-0.52l-1.42,0.26l-2.39,-1.19l-1.52,0.08l-1.27,-1.3l0.16,-1.5l0.56,-0.79l-0.02,-2.73l1.21,-4.74l1.19,-0.21l2.37,2.0l1.08,0.03l4.36,3.17l1.22,1.6l-0.96,1.5l0.61,1.4Z",name:"Uruguay"},LB:{path:"M510.37,198.01l-0.88,0.51l1.82,-3.54l0.62,0.08l0.22,0.61l-1.13,0.88l-0.65,1.47Z",name:"Lebanon"},LA:{path:"M689.54,248.53l-1.76,-0.74l-0.49,0.15l-0.94,1.46l-1.32,-0.64l0.62,-0.98l0.11,-2.17l-2.04,-2.42l-0.25,-2.65l-1.9,-2.1l-2.15,-0.31l-0.78,0.91l-1.12,0.06l-1.05,-0.4l-2.06,1.2l-0.04,-1.59l0.61,-2.68l-0.36,-0.49l-1.35,-0.1l-0.11,-1.23l-0.96,-0.88l1.96,-1.89l0.39,0.36l1.33,0.07l0.42,-0.45l-0.34,-2.66l0.7,-0.21l1.28,1.81l1.11,2.35l0.36,0.23l2.82,0.02l0.71,1.67l-1.39,0.65l-0.72,0.93l0.13,0.6l2.91,1.51l3.6,5.25l1.88,1.78l0.56,1.62l-0.35,1.96Z",name:"Lao PDR"},TW:{path:"M724.01,226.68l-0.74,1.48l-0.9,-1.52l-0.25,-1.74l1.38,-2.44l1.73,-1.74l0.64,0.44l-1.85,5.52Z",name:"Taiwan"},TT:{path:"M266.64,259.32l0.28,-1.16l1.13,-0.22l-0.06,1.2l-1.35,0.18Z",name:"Trinidad and Tobago"},TR:{path:"M513.21,175.47l3.64,1.17l3.05,-0.44l2.1,0.26l3.11,-1.56l2.46,-0.13l2.19,1.33l0.33,0.82l-0.22,1.33l0.25,0.44l2.28,1.13l-1.17,0.57l-0.21,0.45l0.75,3.2l-0.41,1.16l1.13,1.92l-0.55,0.22l-0.9,-0.67l-2.91,-0.37l-1.24,0.46l-4.23,0.41l-2.81,1.05l-1.91,0.01l-1.52,-0.53l-2.58,0.75l-0.66,-0.45l-0.62,0.3l-0.12,1.45l-0.89,0.84l-0.47,-0.67l0.79,-1.3l-0.41,-0.2l-1.43,0.23l-2.0,-0.63l-2.02,1.65l-3.51,0.3l-2.13,-1.53l-2.7,-0.1l-0.86,1.24l-1.38,0.27l-2.29,-1.44l-2.71,-0.01l-1.37,-2.65l-1.68,-1.52l1.07,-1.99l-0.09,-0.49l-1.27,-1.12l2.37,-2.41l3.7,-0.11l1.28,-2.24l4.49,0.37l3.21,-1.97l2.81,-0.82l3.99,-0.06l4.29,2.07ZM488.79,176.72l-1.72,1.31l-0.5,-0.88l1.37,-2.57l-0.7,-0.85l1.7,-0.63l1.8,0.34l0.46,1.17l1.76,0.78l-2.87,0.32l-1.3,1.01Z",name:"Turkey"},LK:{path:"M624.16,268.99l-1.82,0.48l-0.99,-1.67l-0.42,-3.46l0.95,-3.43l1.21,0.98l2.26,4.19l-0.34,2.33l-0.85,0.58Z",name:"Sri Lanka"},TN:{path:"M448.1,188.24l-1.0,1.27l-0.02,1.32l0.84,0.88l-0.28,2.09l-1.53,1.32l-0.12,0.42l0.48,1.54l1.42,0.32l0.53,1.11l0.9,0.52l-0.11,1.67l-3.54,2.64l-0.1,2.38l-0.58,0.3l-0.96,-4.45l-1.54,-1.25l-0.16,-0.78l-1.92,-1.56l-0.18,-1.76l1.51,-1.62l0.59,-2.34l-0.38,-2.78l0.42,-1.21l2.45,-1.05l1.29,0.26l-0.06,1.11l0.58,0.38l1.47,-0.73Z",name:"Tunisia"},TL:{path:"M734.55,307.93l-0.1,-0.97l4.5,-0.86l-2.82,1.28l-1.59,0.55Z",name:"Timor-Leste"},TM:{path:"M553.03,173.76l-0.04,0.34l-0.09,-0.22l0.13,-0.12ZM555.87,172.66l0.45,-0.1l1.48,0.74l2.06,2.43l4.07,-0.18l0.38,-0.51l-0.32,-1.19l1.92,-0.94l1.91,-1.59l2.94,1.39l0.43,2.47l1.19,0.67l2.58,-0.13l0.62,0.4l1.32,3.12l4.54,3.44l2.67,1.45l3.06,1.14l-0.04,1.05l-1.33,-0.75l-0.59,0.19l-0.32,0.84l-2.2,0.81l-0.46,2.13l-1.21,0.74l-1.91,0.42l-0.73,1.33l-1.56,0.31l-2.22,-0.94l-0.2,-2.17l-0.38,-0.36l-1.73,-0.09l-2.76,-2.46l-2.14,-0.4l-2.84,-1.48l-1.78,-0.27l-1.24,0.53l-1.57,-0.08l-2.0,1.69l-1.7,0.43l-0.36,-1.58l0.36,-2.98l-0.22,-0.4l-1.65,-0.84l0.54,-1.69l-0.34,-0.52l-1.22,-0.13l0.36,-1.64l2.22,0.59l2.2,-0.95l0.12,-0.65l-1.77,-1.74l-0.66,-1.57Z",name:"Turkmenistan"},TJ:{path:"M597.75,178.82l-2.54,-0.44l-0.47,0.34l-0.24,1.7l0.43,0.45l2.64,-0.22l3.18,0.95l4.39,-0.41l0.56,2.37l0.52,0.29l0.67,-0.24l1.11,0.49l0.21,2.13l-3.76,-0.21l-1.8,1.32l-1.76,0.74l-0.61,-0.58l0.21,-2.23l-0.64,-0.49l-0.07,-0.93l-1.36,-0.66l-0.45,0.07l-1.08,1.01l-0.55,1.48l-1.31,-0.05l-0.95,1.16l-0.9,-0.35l-1.86,0.74l1.26,-2.83l-0.54,-2.17l-1.67,-0.82l0.33,-0.66l2.18,-0.04l1.19,-1.63l0.76,-1.79l2.43,-0.5l-0.26,1.0l0.73,1.05Z",name:"Tajikistan"},LS:{path:"M491.06,363.48l-0.49,0.15l-1.49,-1.67l1.1,-1.43l2.19,-1.44l1.51,1.27l-0.98,1.82l-1.23,0.38l-0.62,0.93Z",name:"Lesotho"},TH:{path:"M670.27,255.86l-1.41,3.87l0.15,2.0l0.38,0.36l1.38,0.07l0.9,2.04l0.55,2.34l1.4,1.44l1.61,0.38l0.96,0.97l-0.5,0.64l-1.1,0.2l-0.34,-1.18l-2.04,-1.1l-0.63,0.23l-0.63,-0.62l-0.48,-1.3l-2.56,-2.63l-0.73,0.41l0.95,-3.89l2.16,-4.22ZM670.67,254.77l-0.92,-2.18l-0.26,-2.61l-2.14,-3.06l0.71,-0.49l0.89,-2.59l-3.61,-5.45l0.87,-0.51l1.05,-2.58l1.74,-0.18l2.6,-1.59l0.76,0.56l0.13,1.39l0.37,0.36l1.23,0.09l-0.51,2.28l0.05,2.42l0.6,0.34l2.43,-1.42l0.77,0.39l1.47,-0.07l0.71,-0.88l1.48,0.14l1.71,1.88l0.25,2.65l1.92,2.11l-0.1,1.89l-0.61,0.86l-2.22,-0.33l-3.5,0.64l-1.6,2.12l0.36,2.58l-1.51,-0.79l-1.84,-0.01l0.28,-1.52l-0.4,-0.47l-2.21,0.01l-0.4,0.37l-0.19,2.74l-0.34,0.93Z",name:"Thailand"},TF:{path:"M596.68,420.38l-3.2,0.18l-0.05,-1.26l0.39,-1.41l1.3,0.78l2.08,0.35l-0.52,1.36Z",name:"Fr. S. Antarctic Lands"},TG:{path:"M422.7,257.63l-0.09,1.23l1.53,1.52l0.08,1.09l0.5,0.65l-0.11,5.62l0.49,1.47l-1.31,0.35l-1.02,-2.13l-0.18,-1.12l0.53,-2.19l-0.63,-1.16l-0.22,-3.68l-1.01,-1.4l0.07,-0.28l1.37,0.03Z",name:"Togo"},TD:{path:"M480.25,235.49l0.12,9.57l-2.1,0.05l-1.14,1.89l-0.69,1.63l0.34,0.73l-0.66,0.91l0.24,0.89l-0.86,1.95l0.45,0.5l0.6,-0.1l0.34,0.64l0.03,1.38l0.9,1.04l-1.45,0.43l-1.27,1.03l-1.83,2.76l-2.16,1.07l-2.31,-0.15l-0.86,0.25l-0.26,0.49l0.17,0.61l-2.11,1.68l-2.85,0.87l-1.09,-0.57l-0.73,0.66l-1.12,0.1l-1.1,-3.12l-1.25,-0.64l-1.22,-1.22l0.29,-0.64l3.01,0.04l0.35,-0.6l-1.3,-2.2l-0.08,-3.31l-0.97,-1.66l0.22,-1.04l-0.38,-0.48l-1.22,-0.04l0.0,-1.25l-0.98,-1.07l0.96,-3.01l3.25,-2.65l0.13,-3.33l0.95,-5.18l0.52,-1.07l-0.1,-0.48l-0.91,-0.78l-0.2,-0.96l-0.8,-0.58l-0.55,-3.65l2.1,-1.2l19.57,9.83Z",name:"Chad"},LY:{path:"M483.48,203.15l-0.75,1.1l0.29,1.39l-0.6,1.83l0.73,2.14l0.0,24.12l-2.48,0.01l-0.41,0.85l-19.41,-9.76l-4.41,2.28l-1.37,-1.33l-3.82,-1.1l-1.14,-1.65l-1.98,-1.23l-1.22,0.32l-0.66,-1.11l-0.17,-1.26l-1.28,-1.69l0.87,-1.19l-0.07,-4.34l0.43,-2.27l-0.86,-3.45l1.13,-0.76l0.22,-1.16l-0.2,-1.03l3.48,-2.61l0.29,-1.94l2.45,0.8l1.18,-0.21l1.98,0.44l3.15,1.18l1.37,2.54l5.72,1.67l2.64,1.35l1.61,-0.72l1.29,-1.34l-0.44,-2.34l0.66,-1.13l1.67,-1.21l1.57,-0.35l3.14,0.53l1.08,1.28l3.99,0.78l0.36,0.54Z",name:"Libya"},AE:{path:"M550.76,223.97l1.88,-0.4l3.84,0.02l4.78,-4.75l0.19,0.36l0.26,1.58l-0.81,0.01l-0.39,0.35l-0.08,2.04l-0.81,0.63l-0.01,0.96l-0.66,0.99l-0.39,1.41l-7.08,-1.25l-0.7,-1.96Z",name:"United Arab Emirates"},VE:{path:"M240.68,256.69l0.53,0.75l-0.02,1.06l-1.07,1.78l0.95,2.0l0.42,0.22l1.4,-0.44l0.56,-1.83l-0.77,-1.17l-0.1,-1.47l2.82,-0.93l0.26,-0.49l-0.28,-0.96l0.3,-0.28l0.66,1.31l1.96,0.26l1.4,1.22l0.08,0.68l0.39,0.35l4.81,-0.22l1.49,1.11l1.92,0.31l1.67,-0.84l0.22,-0.6l3.44,-0.14l-0.17,0.55l0.86,1.19l2.19,0.35l1.67,1.1l0.37,1.86l0.41,0.32l1.55,0.17l-1.66,1.35l-0.22,0.92l0.65,0.97l-1.67,0.54l-0.3,0.4l0.04,0.99l-0.56,0.57l-0.01,0.55l1.85,2.27l-0.66,0.69l-4.47,1.29l-0.72,0.54l-3.69,-0.9l-0.71,0.27l-0.02,0.7l0.91,0.53l-0.08,1.54l0.35,1.58l0.35,0.31l1.66,0.17l-1.3,0.52l-0.48,1.13l-2.68,0.91l-0.6,0.77l-1.57,0.13l-1.17,-1.13l-0.8,-2.52l-1.25,-1.26l1.02,-1.23l-1.29,-2.95l0.18,-1.62l1.0,-2.21l-0.2,-0.49l-1.14,-0.46l-4.02,0.36l-1.82,-2.1l-1.57,-0.33l-2.99,0.22l-1.06,-0.97l0.25,-1.23l-0.2,-1.01l-0.59,-0.69l-0.29,-1.06l-1.08,-0.39l0.78,-2.79l1.9,-2.11Z",name:"Venezuela"},AF:{path:"M600.7,188.88l-1.57,1.3l-0.1,0.48l0.8,2.31l-1.09,1.04l-0.03,1.27l-0.48,0.71l-2.16,-0.08l-0.37,0.59l0.78,1.48l-1.38,0.69l-1.06,1.69l0.06,1.7l-0.65,0.52l-0.91,-0.21l-1.91,0.36l-0.48,0.77l-1.88,0.13l-1.4,1.56l-0.18,2.32l-2.91,1.02l-1.65,-0.23l-0.71,0.55l-1.41,-0.3l-2.41,0.39l-3.52,-1.17l1.96,-2.35l-0.21,-1.78l-0.3,-0.34l-1.63,-0.4l-0.19,-1.58l-0.75,-2.03l0.95,-1.36l-0.19,-0.6l-0.73,-0.28l1.47,-4.8l2.14,0.9l2.12,-0.36l0.74,-1.34l1.77,-0.39l1.54,-0.92l0.63,-2.31l1.87,-0.5l0.49,-0.81l0.94,0.56l2.13,0.11l2.55,0.92l1.95,-0.83l0.65,0.43l0.56,-0.13l0.69,-1.12l1.57,-0.08l0.72,-1.66l0.79,-0.74l0.8,0.39l-0.17,0.56l0.71,0.58l-0.08,2.39l1.11,0.95ZM601.37,188.71l1.73,-0.71l1.43,-1.18l4.03,0.35l-2.23,0.74l-4.95,0.8Z",name:"Afghanistan"},IQ:{path:"M530.82,187.47l0.79,0.66l1.26,-0.28l1.46,3.08l1.63,0.94l0.14,1.23l-1.22,1.05l-0.53,2.52l1.73,2.67l3.12,1.62l1.15,1.88l-0.38,1.85l0.39,0.48l0.41,-0.0l0.02,1.07l0.76,0.94l-2.47,-0.1l-1.71,2.44l-4.31,-0.2l-7.02,-5.48l-3.73,-1.94l-2.88,-0.73l-0.85,-2.87l5.45,-3.02l0.95,-3.43l-0.19,-1.96l1.27,-0.7l1.22,-1.7l0.87,-0.36l2.69,0.34Z",name:"Iraq"},IS:{path:"M384.14,88.06l-0.37,2.61l2.54,2.51l-2.9,2.75l-9.19,3.4l-9.25,-1.66l1.7,-1.22l-0.1,-0.7l-4.05,-1.47l2.96,-0.53l0.33,-0.43l-0.11,-1.2l-0.33,-0.36l-4.67,-0.85l1.28,-2.04l3.45,-0.56l3.77,2.72l0.44,0.02l3.64,-2.16l3.3,1.08l3.98,-2.16l3.58,0.26Z",name:"Iceland"},IR:{path:"M533.43,187.16l-1.27,-2.15l0.42,-0.98l-0.71,-3.04l1.03,-0.5l0.33,0.83l1.26,1.35l2.05,0.51l1.11,-0.16l2.89,-2.11l0.62,-0.14l0.39,0.46l-0.72,1.2l0.06,0.49l1.56,1.53l0.65,0.04l0.67,1.81l2.56,0.83l1.87,1.48l3.69,0.49l3.91,-0.76l0.47,-0.73l2.17,-0.6l1.66,-1.54l1.51,0.08l1.18,-0.53l1.59,0.24l2.83,1.48l1.88,0.3l2.77,2.47l1.77,0.18l0.18,1.99l-1.68,5.49l0.24,0.5l0.61,0.23l-0.82,1.48l0.8,2.18l0.19,1.71l0.3,0.34l1.63,0.4l0.15,1.32l-2.15,2.35l-0.01,0.53l2.21,3.03l2.34,1.24l0.06,2.14l1.24,0.72l0.11,0.69l-3.31,1.27l-1.08,3.03l-9.68,-1.68l-0.99,-3.05l-1.43,-0.73l-2.17,0.46l-2.47,1.26l-2.83,-0.82l-2.46,-2.02l-2.41,-0.8l-3.42,-6.06l-0.48,-0.2l-1.18,0.39l-1.44,-0.82l-0.5,0.08l-0.65,0.74l-0.97,-1.01l-0.02,-1.31l-0.71,-0.39l0.26,-1.81l-1.29,-2.11l-3.13,-1.63l-1.58,-2.43l0.5,-1.9l1.31,-1.26l-0.19,-1.66l-1.74,-1.1l-1.57,-3.3Z",name:"Iran"},AM:{path:"M536.99,182.33l-0.28,0.03l-1.23,-2.13l-0.93,0.01l-0.62,-0.66l-0.69,-0.07l-0.96,-0.81l-1.56,-0.62l0.19,-1.12l-0.26,-0.79l2.72,-0.36l1.09,1.01l-0.17,0.92l1.02,0.78l-0.47,0.62l0.08,0.56l2.04,1.23l0.04,1.4Z",name:"Armenia"},IT:{path:"M451.59,158.63l3.48,0.94l-0.21,1.17l0.3,0.83l-1.49,-0.24l-2.04,1.1l-0.21,0.39l0.13,1.45l-0.25,1.12l0.82,1.57l2.39,1.63l1.31,2.54l2.79,2.43l2.05,0.08l0.21,0.23l-0.39,0.33l0.09,0.67l4.05,1.97l2.17,1.76l-0.16,0.36l-1.17,-1.08l-2.18,-0.49l-0.44,0.2l-1.05,1.91l0.14,0.54l1.57,0.95l-0.19,0.98l-1.06,0.33l-1.25,2.34l-0.37,0.08l0.0,-0.33l1.0,-2.45l-1.73,-3.17l-1.12,-0.51l-0.88,-1.33l-1.51,-0.51l-1.27,-1.25l-1.75,-0.18l-4.12,-3.21l-1.62,-1.65l-1.03,-3.19l-3.53,-1.36l-1.3,0.51l-1.69,1.41l0.16,-0.72l-0.28,-0.47l-1.14,-0.33l-0.53,-1.96l0.72,-0.78l0.04,-0.48l-0.65,-1.17l0.8,0.39l1.4,-0.23l1.11,-0.84l0.52,0.35l1.19,-0.1l0.75,-1.2l1.53,0.33l1.36,-0.56l0.35,-1.14l1.08,0.32l0.68,-0.64l1.98,-0.44l0.42,0.82ZM459.19,184.75l-0.65,1.65l0.32,1.05l-0.31,0.89l-1.5,-0.85l-4.5,-1.67l0.19,-0.82l2.67,0.23l3.78,-0.48ZM443.93,176.05l1.18,1.66l-0.3,3.32l-1.06,-0.01l-0.77,0.73l-0.53,-0.44l-0.1,-3.37l-0.39,-1.22l1.04,0.01l0.92,-0.68Z",name:"Italy"},VN:{path:"M690.56,230.25l-2.7,1.82l-2.09,2.46l-0.63,1.95l4.31,6.45l2.32,1.65l1.43,1.94l1.11,4.59l-0.32,4.24l-1.93,1.54l-2.84,1.61l-2.11,2.15l-2.73,2.06l-0.59,-1.05l0.63,-1.53l-0.13,-0.47l-1.34,-1.04l1.51,-0.71l2.55,-0.18l0.3,-0.63l-0.82,-1.14l4.0,-2.07l0.31,-3.05l-0.57,-1.77l0.42,-2.66l-0.73,-1.97l-1.86,-1.76l-3.63,-5.29l-2.72,-1.46l0.36,-0.47l1.5,-0.64l0.21,-0.52l-0.97,-2.27l-0.37,-0.24l-2.83,-0.02l-2.24,-3.9l0.83,-0.4l4.39,-0.29l2.06,-1.31l1.15,0.89l1.88,0.4l-0.17,1.51l1.35,1.16l1.67,0.45Z",name:"Vietnam"},AR:{path:"M249.29,428.93l-2.33,-0.52l-5.83,-0.43l-0.89,-1.66l0.05,-2.37l-0.45,-0.4l-1.43,0.18l-0.67,-0.91l-0.2,-3.13l1.88,-1.47l0.79,-2.04l-0.25,-1.7l1.3,-2.68l0.91,-4.15l-0.22,-1.69l0.85,-0.45l0.2,-0.44l-0.27,-1.16l-0.98,-0.68l0.59,-0.92l-0.05,-0.5l-1.04,-1.07l-0.52,-3.1l0.97,-0.86l-0.42,-3.58l1.2,-5.43l1.38,-0.98l0.16,-0.43l-0.75,-2.79l-0.01,-2.43l1.78,-1.75l0.06,-2.57l1.43,-2.85l0.01,-2.58l-0.69,-0.74l-1.09,-4.52l1.47,-2.7l-0.18,-2.79l0.85,-2.35l1.59,-2.46l1.73,-1.64l0.05,-0.52l-0.6,-0.84l0.44,-0.85l-0.07,-4.19l2.7,-1.44l0.86,-2.75l-0.21,-0.71l1.76,-2.01l2.9,0.57l1.38,1.78l0.68,-0.08l0.87,-1.87l2.39,0.09l4.95,4.77l2.17,0.49l3.0,1.92l2.47,1.0l0.25,0.82l-2.37,3.93l0.23,0.59l5.39,1.16l2.12,-0.44l2.45,-2.16l0.5,-2.38l0.76,-0.31l0.98,1.2l-0.04,1.8l-3.67,2.51l-2.85,2.66l-3.43,3.88l-1.3,5.07l0.01,2.72l-0.54,0.73l-0.36,3.28l3.14,2.64l-0.16,2.11l1.4,1.11l-0.1,1.09l-2.29,3.52l-3.55,1.49l-4.92,0.6l-2.71,-0.29l-0.43,0.51l0.5,1.65l-0.49,2.1l0.38,1.42l-1.19,0.83l-2.36,0.38l-2.3,-1.04l-1.38,0.83l0.41,3.64l1.69,0.91l1.4,-0.71l0.36,0.76l-2.04,0.86l-2.01,1.89l-0.97,4.63l-2.34,0.1l-2.09,1.78l-0.61,2.75l2.46,2.31l2.17,0.63l-0.7,2.32l-2.83,1.73l-1.73,3.86l-2.17,1.22l-1.16,1.67l0.75,3.76l1.04,1.28ZM256.71,438.88l-2.0,0.15l-1.4,-1.22l-3.82,-0.1l-0.0,-5.83l1.6,3.05l3.26,2.07l3.08,0.78l-0.71,1.1Z",name:"Argentina"},AU:{path:"M705.8,353.26l0.26,0.04l0.17,-0.47l-0.48,-1.42l0.92,1.11l0.45,0.15l0.27,-0.39l-0.1,-1.56l-1.98,-3.63l1.09,-3.31l-0.24,-1.57l0.34,-0.62l0.38,1.06l0.43,-0.19l0.99,-1.7l1.91,-0.83l1.29,-1.15l1.81,-0.91l0.96,-0.17l0.92,0.26l1.92,-0.95l1.47,-0.28l1.03,-0.8l1.43,0.04l2.78,-0.84l1.36,-1.15l0.71,-1.45l1.41,-1.26l0.3,-2.58l1.27,-1.59l0.78,1.65l0.54,0.19l1.07,-0.51l0.15,-0.6l-0.73,-1.0l0.45,-0.71l0.78,0.39l0.58,-0.3l0.28,-1.82l1.87,-2.14l1.12,-0.39l0.28,-0.58l0.62,0.17l0.53,-0.73l1.87,-0.57l1.65,1.05l1.35,1.48l3.39,0.38l0.43,-0.54l-0.46,-1.23l1.05,-1.79l1.04,-0.61l0.14,-0.55l-0.25,-0.41l0.88,-1.17l1.31,-0.77l1.3,0.27l2.1,-0.48l0.31,-0.4l-0.05,-1.3l-0.92,-0.77l1.48,0.56l1.41,1.07l2.11,0.65l0.81,-0.2l1.4,0.7l1.69,-0.66l0.8,0.19l0.64,-0.33l0.71,0.77l-1.33,1.94l-0.71,0.07l-0.35,0.51l0.24,0.86l-1.52,2.35l0.12,1.05l2.15,1.65l1.97,0.85l3.04,2.36l1.97,0.65l0.55,0.88l2.72,0.85l1.84,-1.1l2.07,-5.97l-0.42,-3.59l0.3,-1.73l0.47,-0.87l-0.31,-0.68l1.09,-3.28l0.46,-0.47l0.4,0.71l0.16,1.51l0.65,0.52l0.16,1.04l0.85,1.21l0.12,2.38l0.9,2.0l0.57,0.18l1.3,-0.78l1.69,1.7l-0.2,1.08l0.53,2.2l0.39,1.3l0.68,0.48l0.6,1.95l-0.19,1.48l0.81,1.76l6.01,3.69l-0.11,0.76l1.38,1.58l0.95,2.77l0.58,0.22l0.72,-0.41l0.8,0.9l0.61,0.01l0.46,2.41l4.81,4.71l0.66,2.02l-0.07,3.31l1.14,2.2l-0.13,2.24l-1.1,3.68l0.03,1.64l-0.47,1.89l-1.05,2.4l-1.9,1.47l-1.72,3.51l-2.38,6.09l-0.24,2.82l-1.14,0.8l-2.85,0.15l-2.31,1.19l-2.51,2.25l-3.09,-1.57l0.3,-1.15l-0.54,-0.47l-1.5,0.63l-2.01,1.94l-7.12,-2.18l-1.48,-1.63l-1.14,-3.74l-1.45,-1.26l-1.81,-0.26l0.56,-1.18l-0.61,-2.1l-0.72,-0.1l-1.14,1.82l-0.9,0.21l0.63,-0.82l0.36,-1.55l0.92,-1.31l-0.13,-2.34l-0.7,-0.22l-2.0,2.34l-1.51,0.93l-0.94,2.01l-1.35,-0.81l-0.02,-1.52l-1.57,-2.04l-1.09,-0.88l0.24,-0.33l-0.14,-0.59l-3.21,-1.69l-1.83,-0.12l-2.54,-1.35l-4.58,0.28l-6.02,1.9l-2.53,-0.13l-2.62,1.41l-2.13,0.63l-1.49,2.6l-3.49,0.31l-2.29,-0.5l-3.48,0.43l-1.6,1.47l-0.81,-0.04l-2.37,1.63l-3.26,-0.1l-3.72,-2.21l0.04,-1.05l1.19,-0.46l0.49,-0.89l0.21,-2.97l-0.28,-1.64l-1.34,-2.86l-0.38,-1.47l0.05,-1.72l-0.95,-1.7l-0.18,-0.97l-1.01,-0.99l-0.29,-1.98l-1.13,-1.75ZM784.92,393.44l2.65,1.02l3.23,-0.96l1.09,0.14l0.15,3.06l-0.85,1.13l-0.17,1.63l-0.87,-0.24l-1.57,1.91l-1.68,-0.18l-1.4,-2.36l-0.37,-2.04l-1.39,-2.51l0.04,-0.8l1.15,0.18Z",name:"Australia"},IL:{path:"M507.76,203.05l0.4,-0.78l0.18,0.4l-0.33,1.03l0.52,0.44l0.68,-0.22l-0.86,3.6l-1.16,-3.32l0.59,-0.74l-0.03,-0.41ZM508.73,200.34l0.37,-1.02l0.64,0.0l0.52,-0.51l-0.49,1.53l-0.56,-0.24l-0.48,0.23Z",name:"Israel"},IN:{path:"M623.34,207.03l-1.24,1.04l-0.97,2.55l0.22,0.51l8.04,3.87l3.42,0.37l1.57,1.38l4.92,0.88l2.18,-0.04l0.38,-0.3l0.29,-1.24l-0.32,-1.64l0.14,-0.87l0.82,-0.31l0.45,2.48l2.28,1.02l1.77,-0.38l4.14,0.1l0.38,-0.36l0.18,-1.66l-0.5,-0.65l1.37,-0.29l2.25,-1.99l2.7,-1.62l1.93,0.62l1.8,-0.98l0.79,1.14l-0.68,0.91l0.26,0.63l2.42,0.36l0.09,0.47l-0.83,0.75l0.13,1.07l-1.52,-0.29l-3.24,1.86l-0.13,1.78l-1.32,2.14l-0.18,1.39l-0.93,1.82l-1.64,-0.5l-0.52,0.37l-0.09,2.63l-0.56,1.11l0.19,0.81l-0.53,0.27l-1.18,-3.73l-1.08,-0.27l-0.38,0.31l-0.24,1.0l-0.66,-0.66l0.54,-1.06l1.22,-0.34l1.15,-2.25l-0.24,-0.56l-1.57,-0.47l-4.34,-0.28l-0.18,-1.56l-0.35,-0.35l-1.11,-0.12l-1.91,-1.12l-0.56,0.17l-0.88,1.82l0.11,0.49l1.36,1.07l-1.09,0.69l-0.69,1.11l0.18,0.56l1.24,0.57l-0.32,1.54l0.85,1.94l0.36,2.01l-0.22,0.59l-4.58,0.52l-0.33,0.42l0.13,1.8l-1.17,1.36l-3.65,1.81l-2.79,3.03l-4.32,3.28l-0.18,1.27l-4.65,1.79l-0.77,2.16l0.64,5.3l-1.06,2.49l-0.01,3.94l-1.24,0.28l-1.14,1.93l0.39,0.84l-1.68,0.53l-1.04,1.83l-0.65,0.47l-2.06,-2.05l-2.1,-6.02l-2.2,-3.64l-1.05,-4.75l-2.29,-3.57l-1.76,-8.2l0.01,-3.11l-0.49,-2.53l-0.55,-0.29l-3.53,1.52l-1.53,-0.27l-2.86,-2.77l0.85,-0.67l0.08,-0.55l-0.74,-1.03l-2.67,-2.06l1.24,-1.32l5.34,0.01l0.39,-0.49l-0.5,-2.29l-1.42,-1.46l-0.27,-1.93l-1.43,-1.2l2.31,-2.37l3.05,0.06l2.62,-2.85l1.6,-2.81l2.4,-2.73l0.07,-2.04l1.97,-1.48l-0.02,-0.65l-1.93,-1.31l-0.82,-1.78l-0.8,-2.21l0.9,-0.89l3.59,0.65l2.92,-0.42l2.33,-2.19l2.31,2.85l-0.24,2.13l0.99,1.59l-0.05,0.82l-1.34,-0.28l-0.47,0.48l0.7,3.06l2.62,1.99l2.99,1.65Z",name:"India"},TZ:{path:"M495.56,296.42l2.8,-3.12l-0.02,-0.81l-0.64,-1.3l0.68,-0.52l0.14,-1.47l-0.76,-1.25l0.31,-0.11l2.26,0.03l-0.51,2.76l0.76,1.3l0.5,0.12l1.05,-0.53l1.19,-0.12l0.61,0.24l1.43,-0.62l0.1,-0.67l-0.71,-0.62l1.57,-1.7l8.65,4.86l0.32,1.53l3.34,2.33l-1.05,2.8l0.13,1.61l1.63,1.12l-0.6,1.76l-0.01,2.33l1.89,4.03l0.57,0.43l-1.46,1.08l-2.61,0.94l-1.43,-0.04l-1.06,0.77l-2.29,0.36l-2.87,-0.68l-0.83,0.07l-0.63,-0.75l-0.31,-2.78l-1.32,-1.35l-3.25,-0.77l-3.96,-1.58l-1.18,-2.41l-0.32,-1.75l-1.76,-1.49l0.42,-1.05l-0.44,-0.89l0.08,-0.96l-0.46,-0.58l0.06,-0.56Z",name:"Tanzania"},AZ:{path:"M539.29,175.73l1.33,0.32l1.94,-1.8l2.3,3.34l1.43,0.43l-1.26,0.15l-0.35,0.32l-0.8,3.14l-0.99,0.96l0.05,1.11l-1.26,-1.13l0.7,-1.18l-0.04,-0.47l-0.74,-0.86l-1.48,0.15l-2.34,1.71l-0.03,-1.27l-2.03,-1.35l0.47,-0.62l-0.08,-0.56l-1.03,-0.79l0.29,-0.43l-0.14,-0.58l-1.13,-0.86l1.89,0.68l1.69,0.06l0.37,-0.87l-0.81,-1.37l0.42,0.06l1.63,1.72ZM533.78,180.57l0.61,0.46l0.69,-0.0l0.59,1.15l-0.68,-0.15l-1.21,-1.45Z",name:"Azerbaijan"},IE:{path:"M405.08,135.42l0.35,2.06l-1.75,2.78l-4.22,1.88l-2.84,-0.4l1.73,-3.0l-1.18,-3.53l4.6,-3.74l0.32,1.15l-0.49,1.74l0.4,0.51l1.47,-0.04l1.6,0.6Z",name:"Ireland"},ID:{path:"M756.47,287.89l0.69,4.01l2.79,1.78l0.51,-0.1l2.04,-2.59l2.71,-1.43l2.05,-0.0l3.9,1.73l2.46,0.45l0.08,15.12l-1.75,-1.54l-2.54,-0.51l-0.88,0.71l-2.32,0.06l0.69,-1.33l1.45,-0.64l0.23,-0.46l-0.65,-2.74l-1.24,-2.21l-5.04,-2.29l-2.09,-0.23l-3.68,-2.27l-0.55,0.13l-0.65,1.07l-0.52,0.12l-0.55,-1.89l-1.21,-0.78l1.84,-0.62l1.72,0.05l0.39,-0.52l-0.21,-0.66l-0.38,-0.28l-3.45,-0.0l-1.13,-1.48l-2.1,-0.43l-0.52,-0.6l2.69,-0.48l1.28,-0.78l3.66,0.94l0.3,0.71ZM757.91,300.34l-0.62,0.82l-0.1,-0.8l0.59,-1.12l0.13,1.1ZM747.38,292.98l0.34,0.72l-1.22,-0.57l-4.68,-0.1l0.27,-0.62l2.78,-0.09l2.52,0.67ZM741.05,285.25l-0.67,-2.88l0.64,-2.01l0.41,0.86l1.21,0.18l0.16,0.7l-0.1,1.68l-0.84,-0.16l-0.46,0.3l-0.34,1.34ZM739.05,293.5l-0.5,0.44l-1.34,-0.36l-0.17,-0.37l1.73,-0.08l0.27,0.36ZM721.45,284.51l-0.19,1.97l2.24,2.23l0.54,0.02l1.27,-1.07l2.75,-0.5l-0.9,1.21l-2.11,0.93l-0.16,0.6l2.22,3.01l-0.3,1.07l1.36,1.74l-2.26,0.85l-0.28,-0.31l0.12,-1.19l-1.64,-1.34l0.17,-2.23l-0.56,-0.39l-1.67,0.76l-0.23,0.39l0.3,6.17l-1.1,0.25l-0.69,-0.47l0.64,-2.21l-0.39,-2.42l-0.39,-0.34l-0.8,-0.01l-0.58,-1.29l0.98,-1.6l0.35,-1.96l1.32,-3.87ZM728.59,296.27l0.38,0.49l-0.02,1.28l-0.88,0.49l-0.53,-0.47l1.04,-1.79ZM729.04,286.98l0.27,-0.05l-0.02,0.13l-0.24,-0.08ZM721.68,284.05l0.16,-0.32l1.89,-1.65l1.83,0.68l3.16,0.35l2.94,-0.1l2.39,-1.66l-1.73,2.13l-1.66,0.43l-2.41,-0.48l-4.17,0.13l-2.39,0.51ZM730.55,310.47l1.11,-1.93l2.03,-0.82l0.08,0.62l-1.45,1.67l-1.77,0.46ZM728.12,305.88l-0.1,0.38l-3.46,0.66l-2.91,-0.27l-0.0,-0.25l1.54,-0.41l1.66,0.73l1.67,-0.19l1.61,-0.65ZM722.9,310.24l-0.64,0.03l-2.26,-1.2l1.11,-0.24l1.78,1.41ZM716.26,305.77l0.88,0.51l1.28,-0.17l0.2,0.35l-4.65,0.73l0.39,-0.67l1.15,-0.02l0.75,-0.73ZM711.66,293.84l-0.38,-0.16l-2.54,1.01l-1.12,-1.44l-1.69,-0.13l-1.16,-0.75l-3.04,0.77l-1.1,-1.15l-3.31,-0.11l-0.35,-3.05l-1.35,-0.95l-1.11,-1.98l-0.33,-2.06l0.27,-2.14l0.9,-1.01l0.37,1.15l2.09,1.49l1.53,-0.48l1.82,0.08l1.38,-1.19l1.0,-0.18l2.28,0.67l2.26,-0.53l1.52,-3.64l1.01,-0.99l0.78,-2.57l4.1,0.3l-1.11,1.77l0.02,0.46l1.7,2.2l-0.23,1.39l2.07,1.71l-2.33,0.42l-0.88,1.9l0.1,2.05l-2.4,1.9l-0.06,2.45l-0.7,2.79ZM692.58,302.03l0.35,0.26l4.8,0.25l0.78,-0.97l4.17,1.09l1.13,1.68l3.69,0.45l2.13,1.04l-1.8,0.6l-2.77,-0.99l-4.8,-0.12l-5.24,-1.41l-1.84,-0.25l-1.11,0.3l-4.26,-0.97l-0.7,-1.14l-1.59,-0.13l1.18,-1.65l2.74,0.13l2.87,1.13l0.26,0.68ZM685.53,299.17l-2.22,0.04l-2.06,-2.03l-3.15,-2.01l-2.93,-3.51l-3.11,-5.33l-2.2,-2.12l-1.64,-4.06l-2.32,-1.69l-1.27,-2.07l-1.96,-1.5l-2.51,-2.65l-0.11,-0.66l4.81,0.53l2.15,2.38l3.31,2.74l2.35,2.66l2.7,0.17l1.95,1.59l1.54,2.17l1.59,0.95l-0.84,1.71l0.15,0.52l1.44,0.87l0.79,0.1l0.4,1.58l0.87,1.4l1.96,0.39l1.0,1.31l-0.6,3.01l-0.09,3.5Z",name:"Indonesia"},UA:{path:"M492.5,162.44l1.28,-2.49l1.82,0.19l0.66,-0.23l0.09,-0.71l-0.25,-0.75l-0.79,-0.72l-0.33,-1.21l-0.86,-0.62l-0.02,-1.19l-1.13,-0.86l-1.15,-0.19l-2.04,-1.0l-1.66,0.32l-0.66,0.47l-0.92,-0.0l-0.84,0.78l-2.48,0.7l-1.18,-0.71l-3.07,-0.36l-0.89,0.43l-0.24,-0.55l-1.11,-0.7l0.35,-0.93l1.26,-1.02l-0.54,-1.23l2.04,-2.43l1.4,-0.62l0.25,-1.19l-1.04,-2.39l0.83,-0.13l1.28,-0.84l1.8,-0.07l2.47,0.26l2.86,0.81l1.88,0.06l0.86,0.44l1.04,-0.41l0.77,0.66l2.18,-0.15l0.92,0.3l0.52,-0.34l0.15,-1.53l0.56,-0.54l2.85,-0.05l0.84,-0.72l3.04,-0.18l1.23,1.46l-0.48,0.77l0.21,1.03l0.36,0.32l1.8,0.14l0.93,2.08l3.18,1.15l1.94,-0.45l1.67,1.49l1.4,-0.03l3.35,0.96l0.02,0.54l-0.96,1.59l0.47,1.97l-0.26,0.7l-2.36,0.28l-1.29,0.89l-0.23,1.38l-1.83,0.27l-1.58,0.97l-2.41,0.21l-2.16,1.17l-0.21,0.38l0.34,2.26l1.23,0.75l2.13,-0.08l-0.14,0.31l-2.65,0.53l-3.23,1.69l-0.87,-0.39l0.42,-1.1l-0.25,-0.52l-2.21,-0.73l2.35,-1.06l0.12,-0.65l-0.93,-0.82l-3.62,-0.74l-0.13,-0.89l-0.46,-0.34l-2.61,0.59l-0.91,1.69l-1.71,2.04l-0.86,-0.4l-1.62,0.27Z",name:"Ukraine"},QA:{path:"M549.33,221.64l-0.76,-0.23l-0.14,-1.64l0.84,-1.29l0.47,0.52l0.04,1.34l-0.45,1.3Z",name:"Qatar"},MZ:{path:"M508.58,318.75l-0.34,-2.57l0.51,-2.05l3.55,0.63l2.5,-0.38l1.02,-0.76l1.49,0.01l2.74,-0.98l1.66,-1.2l0.5,9.24l0.41,1.23l-0.68,1.67l-0.93,1.71l-1.5,1.5l-5.16,2.28l-2.78,2.73l-1.02,0.53l-1.71,1.8l-0.98,0.57l-0.35,2.41l1.16,1.94l0.49,2.17l0.43,0.31l-0.06,2.06l-0.39,1.17l0.5,0.72l-0.25,0.73l-0.92,0.83l-5.12,2.39l-1.22,1.36l0.21,1.13l0.58,0.39l-0.11,0.72l-1.22,-0.01l-0.73,-2.97l0.42,-3.09l-1.78,-5.37l2.49,-2.81l0.69,-1.89l0.44,-0.43l0.28,-1.53l-0.39,-0.93l0.59,-3.65l-0.01,-3.26l-1.49,-1.16l-1.2,-0.22l-1.74,-1.17l-1.92,0.01l-0.29,-2.08l7.06,-1.96l1.28,1.09l0.89,-0.1l0.67,0.44l0.1,0.73l-0.51,1.29l0.19,1.81l1.75,1.83l0.65,-0.13l0.71,-1.65l1.17,-0.86l-0.26,-3.47l-1.05,-1.85l-1.04,-0.94Z",name:"Mozambique"}},height:440.70631074413296,width:900,projection:{type:"mill",centralMeridian:11.5}}); /***/ }, /***/ 95 (module) { const API_URL = 'https://maps.googleapis.com/maps/api/js' const CALLBACK_NAME = '__googleMapsApiOnLoadCallback' const optionsKeys = ['channel', 'client', 'key', 'language', 'region', 'v'] let promise = null module.exports = function (options = {}) { promise = promise || new Promise(function (resolve, reject) { // Reject the promise after a timeout const timeoutId = setTimeout(function () { window[CALLBACK_NAME] = function () {} // Set the on load callback to a no-op reject(new Error('Could not load the Google Maps API')) }, options.timeout || 10000) // Hook up the on load callback window[CALLBACK_NAME] = function () { if (timeoutId !== null) { clearTimeout(timeoutId) } resolve(window.google.maps) delete window[CALLBACK_NAME] } // Prepare the `script` tag to be inserted into the page const scriptElement = document.createElement('script') const params = [`callback=${CALLBACK_NAME}`] optionsKeys.forEach(function (key) { if (options[key]) { params.push(`${key}=${options[key]}`) } }) if (options.libraries && options.libraries.length) { params.push(`libraries=${options.libraries.join(',')}`) } scriptElement.src = `${options.apiUrl || API_URL}?${params.join('&')}` // Insert the `script` tag document.body.appendChild(scriptElement) }) return promise } /***/ }, /***/ 201 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! * Masonry v4.2.2 * Cascading grid layout library * https://masonry.desandro.com * MIT License * by David DeSandro */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /*globals define, module, require */ if ( true ) { // AMD !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(442), __webpack_require__(928) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( window, function factory( Outlayer, getSize ) { 'use strict'; // -------------------------- masonryDefinition -------------------------- // // create an Outlayer layout class var Masonry = Outlayer.create('masonry'); // isFitWidth -> fitWidth Masonry.compatOptions.fitWidth = 'isFitWidth'; var proto = Masonry.prototype; proto._resetLayout = function() { this.getSize(); this._getMeasurement( 'columnWidth', 'outerWidth' ); this._getMeasurement( 'gutter', 'outerWidth' ); this.measureColumns(); // reset column Y this.colYs = []; for ( var i=0; i < this.cols; i++ ) { this.colYs.push( 0 ); } this.maxY = 0; this.horizontalColIndex = 0; }; proto.measureColumns = function() { this.getContainerWidth(); // if columnWidth is 0, default to outerWidth of first item if ( !this.columnWidth ) { var firstItem = this.items[0]; var firstItemElem = firstItem && firstItem.element; // columnWidth fall back to item of first element this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth || // if first elem has no width, default to size of container this.containerWidth; } var columnWidth = this.columnWidth += this.gutter; // calculate columns var containerWidth = this.containerWidth + this.gutter; var cols = containerWidth / columnWidth; // fix rounding errors, typically with gutters var excess = columnWidth - containerWidth % columnWidth; // if overshoot is less than a pixel, round up, otherwise floor it var mathMethod = excess && excess < 1 ? 'round' : 'floor'; cols = Math[ mathMethod ]( cols ); this.cols = Math.max( cols, 1 ); }; proto.getContainerWidth = function() { // container is parent if fit width var isFitWidth = this._getOption('fitWidth'); var container = isFitWidth ? this.element.parentNode : this.element; // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var size = getSize( container ); this.containerWidth = size && size.innerWidth; }; proto._getItemLayoutPosition = function( item ) { item.getSize(); // how many columns does this brick span var remainder = item.size.outerWidth % this.columnWidth; var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil'; // round if off by 1 pixel, otherwise use ceil var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth ); colSpan = Math.min( colSpan, this.cols ); // use horizontal or top column position var colPosMethod = this.options.horizontalOrder ? '_getHorizontalColPosition' : '_getTopColPosition'; var colPosition = this[ colPosMethod ]( colSpan, item ); // position the brick var position = { x: this.columnWidth * colPosition.col, y: colPosition.y }; // apply setHeight to necessary columns var setHeight = colPosition.y + item.size.outerHeight; var setMax = colSpan + colPosition.col; for ( var i = colPosition.col; i < setMax; i++ ) { this.colYs[i] = setHeight; } return position; }; proto._getTopColPosition = function( colSpan ) { var colGroup = this._getTopColGroup( colSpan ); // get the minimum Y value from the columns var minimumY = Math.min.apply( Math, colGroup ); return { col: colGroup.indexOf( minimumY ), y: minimumY, }; }; /** * @param {Number} colSpan - number of columns the element spans * @returns {Array} colGroup */ proto._getTopColGroup = function( colSpan ) { if ( colSpan < 2 ) { // if brick spans only one column, use all the column Ys return this.colYs; } var colGroup = []; // how many different places could this brick fit horizontally var groupCount = this.cols + 1 - colSpan; // for each group potential horizontal position for ( var i = 0; i < groupCount; i++ ) { colGroup[i] = this._getColGroupY( i, colSpan ); } return colGroup; }; proto._getColGroupY = function( col, colSpan ) { if ( colSpan < 2 ) { return this.colYs[ col ]; } // make an array of colY values for that one group var groupColYs = this.colYs.slice( col, col + colSpan ); // and get the max value of the array return Math.max.apply( Math, groupColYs ); }; // get column position based on horizontal index. #873 proto._getHorizontalColPosition = function( colSpan, item ) { var col = this.horizontalColIndex % this.cols; var isOver = colSpan > 1 && col + colSpan > this.cols; // shift to next row if item can't fit on current row col = isOver ? 0 : col; // don't let zero-size items take up space var hasSize = item.size.outerWidth && item.size.outerHeight; this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex; return { col: col, y: this._getColGroupY( col, colSpan ), }; }; proto._manageStamp = function( stamp ) { var stampSize = getSize( stamp ); var offset = this._getElementOffset( stamp ); // get the columns that this stamp affects var isOriginLeft = this._getOption('originLeft'); var firstX = isOriginLeft ? offset.left : offset.right; var lastX = firstX + stampSize.outerWidth; var firstCol = Math.floor( firstX / this.columnWidth ); firstCol = Math.max( 0, firstCol ); var lastCol = Math.floor( lastX / this.columnWidth ); // lastCol should not go over if multiple of columnWidth #425 lastCol -= lastX % this.columnWidth ? 0 : 1; lastCol = Math.min( this.cols - 1, lastCol ); // set colYs to bottom of the stamp var isOriginTop = this._getOption('originTop'); var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) + stampSize.outerHeight; for ( var i = firstCol; i <= lastCol; i++ ) { this.colYs[i] = Math.max( stampMaxY, this.colYs[i] ); } }; proto._getContainerSize = function() { this.maxY = Math.max.apply( Math, this.colYs ); var size = { height: this.maxY }; if ( this._getOption('fitWidth') ) { size.width = this._getContainerFitWidth(); } return size; }; proto._getContainerFitWidth = function() { var unusedCols = 0; // count unused columns var i = this.cols; while ( --i ) { if ( this.colYs[i] !== 0 ) { break; } unusedCols++; } // fit container to columns that have been used return ( this.cols - unusedCols ) * this.columnWidth - this.gutter; }; proto.needsResizeLayout = function() { var previousWidth = this.containerWidth; this.getContainerWidth(); return previousWidth != this.containerWidth; }; return Masonry; })); /***/ }, /***/ 396 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/** * Outlayer Item */ ( function( window, factory ) { // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( true ) { // AMD - RequireJS !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(240), __webpack_require__(928) ], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( window, function factory( EvEmitter, getSize ) { 'use strict'; // ----- helpers ----- // function isEmptyObj( obj ) { for ( var prop in obj ) { return false; } prop = null; return true; } // -------------------------- CSS3 support -------------------------- // var docElemStyle = document.documentElement.style; var transitionProperty = typeof docElemStyle.transition == 'string' ? 'transition' : 'WebkitTransition'; var transformProperty = typeof docElemStyle.transform == 'string' ? 'transform' : 'WebkitTransform'; var transitionEndEvent = { WebkitTransition: 'webkitTransitionEnd', transition: 'transitionend' }[ transitionProperty ]; // cache all vendor properties that could have vendor prefix var vendorProperties = { transform: transformProperty, transition: transitionProperty, transitionDuration: transitionProperty + 'Duration', transitionProperty: transitionProperty + 'Property', transitionDelay: transitionProperty + 'Delay' }; // -------------------------- Item -------------------------- // function Item( element, layout ) { if ( !element ) { return; } this.element = element; // parent layout class, i.e. Masonry, Isotope, or Packery this.layout = layout; this.position = { x: 0, y: 0 }; this._create(); } // inherit EvEmitter var proto = Item.prototype = Object.create( EvEmitter.prototype ); proto.constructor = Item; proto._create = function() { // transition objects this._transn = { ingProperties: {}, clean: {}, onEnd: {} }; this.css({ position: 'absolute' }); }; // trigger specified handler for event type proto.handleEvent = function( event ) { var method = 'on' + event.type; if ( this[ method ] ) { this[ method ]( event ); } }; proto.getSize = function() { this.size = getSize( this.element ); }; /** * apply CSS styles to element * @param {Object} style */ proto.css = function( style ) { var elemStyle = this.element.style; for ( var prop in style ) { // use vendor property if available var supportedProp = vendorProperties[ prop ] || prop; elemStyle[ supportedProp ] = style[ prop ]; } }; // measure position, and sets it proto.getPosition = function() { var style = getComputedStyle( this.element ); var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); var xValue = style[ isOriginLeft ? 'left' : 'right' ]; var yValue = style[ isOriginTop ? 'top' : 'bottom' ]; var x = parseFloat( xValue ); var y = parseFloat( yValue ); // convert percent to pixels var layoutSize = this.layout.size; if ( xValue.indexOf('%') != -1 ) { x = ( x / 100 ) * layoutSize.width; } if ( yValue.indexOf('%') != -1 ) { y = ( y / 100 ) * layoutSize.height; } // clean up 'auto' or other non-integer values x = isNaN( x ) ? 0 : x; y = isNaN( y ) ? 0 : y; // remove padding from measurement x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight; y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom; this.position.x = x; this.position.y = y; }; // set settled position, apply padding proto.layoutPosition = function() { var layoutSize = this.layout.size; var style = {}; var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); // x var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight'; var xProperty = isOriginLeft ? 'left' : 'right'; var xResetProperty = isOriginLeft ? 'right' : 'left'; var x = this.position.x + layoutSize[ xPadding ]; // set in percentage or pixels style[ xProperty ] = this.getXValue( x ); // reset other property style[ xResetProperty ] = ''; // y var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom'; var yProperty = isOriginTop ? 'top' : 'bottom'; var yResetProperty = isOriginTop ? 'bottom' : 'top'; var y = this.position.y + layoutSize[ yPadding ]; // set in percentage or pixels style[ yProperty ] = this.getYValue( y ); // reset other property style[ yResetProperty ] = ''; this.css( style ); this.emitEvent( 'layout', [ this ] ); }; proto.getXValue = function( x ) { var isHorizontal = this.layout._getOption('horizontal'); return this.layout.options.percentPosition && !isHorizontal ? ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px'; }; proto.getYValue = function( y ) { var isHorizontal = this.layout._getOption('horizontal'); return this.layout.options.percentPosition && isHorizontal ? ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px'; }; proto._transitionTo = function( x, y ) { this.getPosition(); // get current x & y from top/left var curX = this.position.x; var curY = this.position.y; var didNotMove = x == this.position.x && y == this.position.y; // save end position this.setPosition( x, y ); // if did not move and not transitioning, just go to layout if ( didNotMove && !this.isTransitioning ) { this.layoutPosition(); return; } var transX = x - curX; var transY = y - curY; var transitionStyle = {}; transitionStyle.transform = this.getTranslate( transX, transY ); this.transition({ to: transitionStyle, onTransitionEnd: { transform: this.layoutPosition }, isCleaning: true }); }; proto.getTranslate = function( x, y ) { // flip cooridinates if origin on right or bottom var isOriginLeft = this.layout._getOption('originLeft'); var isOriginTop = this.layout._getOption('originTop'); x = isOriginLeft ? x : -x; y = isOriginTop ? y : -y; return 'translate3d(' + x + 'px, ' + y + 'px, 0)'; }; // non transition + transform support proto.goTo = function( x, y ) { this.setPosition( x, y ); this.layoutPosition(); }; proto.moveTo = proto._transitionTo; proto.setPosition = function( x, y ) { this.position.x = parseFloat( x ); this.position.y = parseFloat( y ); }; // ----- transition ----- // /** * @param {Object} style - CSS * @param {Function} onTransitionEnd */ // non transition, just trigger callback proto._nonTransition = function( args ) { this.css( args.to ); if ( args.isCleaning ) { this._removeStyles( args.to ); } for ( var prop in args.onTransitionEnd ) { args.onTransitionEnd[ prop ].call( this ); } }; /** * proper transition * @param {Object} args - arguments * @param {Object} to - style to transition to * @param {Object} from - style to start transition from * @param {Boolean} isCleaning - removes transition styles after transition * @param {Function} onTransitionEnd - callback */ proto.transition = function( args ) { // redirect to nonTransition if no transition duration if ( !parseFloat( this.layout.options.transitionDuration ) ) { this._nonTransition( args ); return; } var _transition = this._transn; // keep track of onTransitionEnd callback by css property for ( var prop in args.onTransitionEnd ) { _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ]; } // keep track of properties that are transitioning for ( prop in args.to ) { _transition.ingProperties[ prop ] = true; // keep track of properties to clean up when transition is done if ( args.isCleaning ) { _transition.clean[ prop ] = true; } } // set from styles if ( args.from ) { this.css( args.from ); // force redraw. http://blog.alexmaccaw.com/css-transitions var h = this.element.offsetHeight; // hack for JSHint to hush about unused var h = null; } // enable transition this.enableTransition( args.to ); // set styles that are transitioning this.css( args.to ); this.isTransitioning = true; }; // dash before all cap letters, including first for // WebkitTransform => -webkit-transform function toDashedAll( str ) { return str.replace( /([A-Z])/g, function( $1 ) { return '-' + $1.toLowerCase(); }); } var transitionProps = 'opacity,' + toDashedAll( transformProperty ); proto.enableTransition = function(/* style */) { // HACK changing transitionProperty during a transition // will cause transition to jump if ( this.isTransitioning ) { return; } // make `transition: foo, bar, baz` from style object // HACK un-comment this when enableTransition can work // while a transition is happening // var transitionValues = []; // for ( var prop in style ) { // // dash-ify camelCased properties like WebkitTransition // prop = vendorProperties[ prop ] || prop; // transitionValues.push( toDashedAll( prop ) ); // } // munge number to millisecond, to match stagger var duration = this.layout.options.transitionDuration; duration = typeof duration == 'number' ? duration + 'ms' : duration; // enable transition styles this.css({ transitionProperty: transitionProps, transitionDuration: duration, transitionDelay: this.staggerDelay || 0 }); // listen for transition end event this.element.addEventListener( transitionEndEvent, this, false ); }; // ----- events ----- // proto.onwebkitTransitionEnd = function( event ) { this.ontransitionend( event ); }; proto.onotransitionend = function( event ) { this.ontransitionend( event ); }; // properties that I munge to make my life easier var dashedVendorProperties = { '-webkit-transform': 'transform' }; proto.ontransitionend = function( event ) { // disregard bubbled events from children if ( event.target !== this.element ) { return; } var _transition = this._transn; // get property name of transitioned property, convert to prefix-free var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName; // remove property that has completed transitioning delete _transition.ingProperties[ propertyName ]; // check if any properties are still transitioning if ( isEmptyObj( _transition.ingProperties ) ) { // all properties have completed transitioning this.disableTransition(); } // clean style if ( propertyName in _transition.clean ) { // clean up style this.element.style[ event.propertyName ] = ''; delete _transition.clean[ propertyName ]; } // trigger onTransitionEnd callback if ( propertyName in _transition.onEnd ) { var onTransitionEnd = _transition.onEnd[ propertyName ]; onTransitionEnd.call( this ); delete _transition.onEnd[ propertyName ]; } this.emitEvent( 'transitionEnd', [ this ] ); }; proto.disableTransition = function() { this.removeTransitionStyles(); this.element.removeEventListener( transitionEndEvent, this, false ); this.isTransitioning = false; }; /** * removes style property from element * @param {Object} style **/ proto._removeStyles = function( style ) { // clean up transition styles var cleanStyle = {}; for ( var prop in style ) { cleanStyle[ prop ] = ''; } this.css( cleanStyle ); }; var cleanTransitionStyle = { transitionProperty: '', transitionDuration: '', transitionDelay: '' }; proto.removeTransitionStyles = function() { // remove transition this.css( cleanTransitionStyle ); }; // ----- stagger ----- // proto.stagger = function( delay ) { delay = isNaN( delay ) ? 0 : delay; this.staggerDelay = delay + 'ms'; }; // ----- show/hide/remove ----- // // remove element from DOM proto.removeElem = function() { this.element.parentNode.removeChild( this.element ); // remove display: none this.css({ display: '' }); this.emitEvent( 'remove', [ this ] ); }; proto.remove = function() { // just remove element if no transition support or no transition if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) { this.removeElem(); return; } // start transition this.once( 'transitionEnd', function() { this.removeElem(); }); this.hide(); }; proto.reveal = function() { delete this.isHidden; // remove display: none this.css({ display: '' }); var options = this.layout.options; var onTransitionEnd = {}; var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle'); onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd; this.transition({ from: options.hiddenStyle, to: options.visibleStyle, isCleaning: true, onTransitionEnd: onTransitionEnd }); }; proto.onRevealTransitionEnd = function() { // check if still visible // during transition, item may have been hidden if ( !this.isHidden ) { this.emitEvent('reveal'); } }; /** * get style property use for hide/reveal transition end * @param {String} styleProperty - hiddenStyle/visibleStyle * @returns {String} */ proto.getHideRevealTransitionEndProperty = function( styleProperty ) { var optionStyle = this.layout.options[ styleProperty ]; // use opacity if ( optionStyle.opacity ) { return 'opacity'; } // get first property for ( var prop in optionStyle ) { return prop; } }; proto.hide = function() { // set flag this.isHidden = true; // remove display: none this.css({ display: '' }); var options = this.layout.options; var onTransitionEnd = {}; var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle'); onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd; this.transition({ from: options.visibleStyle, to: options.hiddenStyle, // keep hidden stuff hidden isCleaning: true, onTransitionEnd: onTransitionEnd }); }; proto.onHideTransitionEnd = function() { // check if still hidden // during transition, item may have been un-hidden if ( this.isHidden ) { this.css({ display: 'none' }); this.emitEvent('hide'); } }; proto.destroy = function() { this.css({ position: '', left: '', right: '', top: '', bottom: '', transition: '', transform: '' }); }; return Item; })); /***/ }, /***/ 442 (module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! * Outlayer v2.1.1 * the brains and guts of a layout library * MIT license */ ( function( window, factory ) { 'use strict'; // universal module definition /* jshint strict: false */ /* globals define, module, require */ if ( true ) { // AMD - RequireJS !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(240), __webpack_require__(928), __webpack_require__(346), __webpack_require__(396) ], __WEBPACK_AMD_DEFINE_RESULT__ = (function( EvEmitter, getSize, utils, Item ) { return factory( window, EvEmitter, getSize, utils, Item); }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else // removed by dead control flow {} }( window, function factory( window, EvEmitter, getSize, utils, Item ) { 'use strict'; // ----- vars ----- // var console = window.console; var jQuery = window.jQuery; var noop = function() {}; // -------------------------- Outlayer -------------------------- // // globally unique identifiers var GUID = 0; // internal store of all Outlayer intances var instances = {}; /** * @param {Element, String} element * @param {Object} options * @constructor */ function Outlayer( element, options ) { var queryElement = utils.getQueryElement( element ); if ( !queryElement ) { if ( console ) { console.error( 'Bad element for ' + this.constructor.namespace + ': ' + ( queryElement || element ) ); } return; } this.element = queryElement; // add jQuery if ( jQuery ) { this.$element = jQuery( this.element ); } // options this.options = utils.extend( {}, this.constructor.defaults ); this.option( options ); // add id for Outlayer.getFromElement var id = ++GUID; this.element.outlayerGUID = id; // expando instances[ id ] = this; // associate via id // kick it off this._create(); var isInitLayout = this._getOption('initLayout'); if ( isInitLayout ) { this.layout(); } } // settings are for internal use only Outlayer.namespace = 'outlayer'; Outlayer.Item = Item; // default options Outlayer.defaults = { containerStyle: { position: 'relative' }, initLayout: true, originLeft: true, originTop: true, resize: true, resizeContainer: true, // item options transitionDuration: '0.4s', hiddenStyle: { opacity: 0, transform: 'scale(0.001)' }, visibleStyle: { opacity: 1, transform: 'scale(1)' } }; var proto = Outlayer.prototype; // inherit EvEmitter utils.extend( proto, EvEmitter.prototype ); /** * set options * @param {Object} opts */ proto.option = function( opts ) { utils.extend( this.options, opts ); }; /** * get backwards compatible option value, check old name */ proto._getOption = function( option ) { var oldOption = this.constructor.compatOptions[ option ]; return oldOption && this.options[ oldOption ] !== undefined ? this.options[ oldOption ] : this.options[ option ]; }; Outlayer.compatOptions = { // currentName: oldName initLayout: 'isInitLayout', horizontal: 'isHorizontal', layoutInstant: 'isLayoutInstant', originLeft: 'isOriginLeft', originTop: 'isOriginTop', resize: 'isResizeBound', resizeContainer: 'isResizingContainer' }; proto._create = function() { // get items from children this.reloadItems(); // elements that affect layout, but are not laid out this.stamps = []; this.stamp( this.options.stamp ); // set container style utils.extend( this.element.style, this.options.containerStyle ); // bind resize method var canBindResize = this._getOption('resize'); if ( canBindResize ) { this.bindResize(); } }; // goes through all children again and gets bricks in proper order proto.reloadItems = function() { // collection of item elements this.items = this._itemize( this.element.children ); }; /** * turn elements into Outlayer.Items to be used in layout * @param {Array or NodeList or HTMLElement} elems * @returns {Array} items - collection of new Outlayer Items */ proto._itemize = function( elems ) { var itemElems = this._filterFindItemElements( elems ); var Item = this.constructor.Item; // create new Outlayer Items for collection var items = []; for ( var i=0; i < itemElems.length; i++ ) { var elem = itemElems[i]; var item = new Item( elem, this ); items.push( item ); } return items; }; /** * get item elements to be used in layout * @param {Array or NodeList or HTMLElement} elems * @returns {Array} items - item elements */ proto._filterFindItemElements = function( elems ) { return utils.filterFindElements( elems, this.options.itemSelector ); }; /** * getter method for getting item elements * @returns {Array} elems - collection of item elements */ proto.getItemElements = function() { return this.items.map( function( item ) { return item.element; }); }; // ----- init & layout ----- // /** * lays out all items */ proto.layout = function() { this._resetLayout(); this._manageStamps(); // don't animate first layout var layoutInstant = this._getOption('layoutInstant'); var isInstant = layoutInstant !== undefined ? layoutInstant : !this._isLayoutInited; this.layoutItems( this.items, isInstant ); // flag for initalized this._isLayoutInited = true; }; // _init is alias for layout proto._init = proto.layout; /** * logic before any new layout */ proto._resetLayout = function() { this.getSize(); }; proto.getSize = function() { this.size = getSize( this.element ); }; /** * get measurement from option, for columnWidth, rowHeight, gutter * if option is String -> get element from selector string, & get size of element * if option is Element -> get size of element * else use option as a number * * @param {String} measurement * @param {String} size - width or height * @private */ proto._getMeasurement = function( measurement, size ) { var option = this.options[ measurement ]; var elem; if ( !option ) { // default to 0 this[ measurement ] = 0; } else { // use option as an element if ( typeof option == 'string' ) { elem = this.element.querySelector( option ); } else if ( option instanceof HTMLElement ) { elem = option; } // use size of element, if element this[ measurement ] = elem ? getSize( elem )[ size ] : option; } }; /** * layout a collection of item elements * @api public */ proto.layoutItems = function( items, isInstant ) { items = this._getItemsForLayout( items ); this._layoutItems( items, isInstant ); this._postLayout(); }; /** * get the items to be laid out * you may want to skip over some items * @param {Array} items * @returns {Array} items */ proto._getItemsForLayout = function( items ) { return items.filter( function( item ) { return !item.isIgnored; }); }; /** * layout items * @param {Array} items * @param {Boolean} isInstant */ proto._layoutItems = function( items, isInstant ) { this._emitCompleteOnItems( 'layout', items ); if ( !items || !items.length ) { // no items, emit event with empty array return; } var queue = []; items.forEach( function( item ) { // get x/y object from method var position = this._getItemLayoutPosition( item ); // enqueue position.item = item; position.isInstant = isInstant || item.isLayoutInstant; queue.push( position ); }, this ); this._processLayoutQueue( queue ); }; /** * get item layout position * @param {Outlayer.Item} item * @returns {Object} x and y position */ proto._getItemLayoutPosition = function( /* item */ ) { return { x: 0, y: 0 }; }; /** * iterate over array and position each item * Reason being - separating this logic prevents 'layout invalidation' * thx @paul_irish * @param {Array} queue */ proto._processLayoutQueue = function( queue ) { this.updateStagger(); queue.forEach( function( obj, i ) { this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i ); }, this ); }; // set stagger from option in milliseconds number proto.updateStagger = function() { var stagger = this.options.stagger; if ( stagger === null || stagger === undefined ) { this.stagger = 0; return; } this.stagger = getMilliseconds( stagger ); return this.stagger; }; /** * Sets position of item in DOM * @param {Outlayer.Item} item * @param {Number} x - horizontal position * @param {Number} y - vertical position * @param {Boolean} isInstant - disables transitions */ proto._positionItem = function( item, x, y, isInstant, i ) { if ( isInstant ) { // if not transition, just set CSS item.goTo( x, y ); } else { item.stagger( i * this.stagger ); item.moveTo( x, y ); } }; /** * Any logic you want to do after each layout, * i.e. size the container */ proto._postLayout = function() { this.resizeContainer(); }; proto.resizeContainer = function() { var isResizingContainer = this._getOption('resizeContainer'); if ( !isResizingContainer ) { return; } var size = this._getContainerSize(); if ( size ) { this._setContainerMeasure( size.width, true ); this._setContainerMeasure( size.height, false ); } }; /** * Sets width or height of container if returned * @returns {Object} size * @param {Number} width * @param {Number} height */ proto._getContainerSize = noop; /** * @param {Number} measure - size of width or height * @param {Boolean} isWidth */ proto._setContainerMeasure = function( measure, isWidth ) { if ( measure === undefined ) { return; } var elemSize = this.size; // add padding and border width if border box if ( elemSize.isBorderBox ) { measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight + elemSize.borderLeftWidth + elemSize.borderRightWidth : elemSize.paddingBottom + elemSize.paddingTop + elemSize.borderTopWidth + elemSize.borderBottomWidth; } measure = Math.max( measure, 0 ); this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px'; }; /** * emit eventComplete on a collection of items events * @param {String} eventName * @param {Array} items - Outlayer.Items */ proto._emitCompleteOnItems = function( eventName, items ) { var _this = this; function onComplete() { _this.dispatchEvent( eventName + 'Complete', null, [ items ] ); } var count = items.length; if ( !items || !count ) { onComplete(); return; } var doneCount = 0; function tick() { doneCount++; if ( doneCount == count ) { onComplete(); } } // bind callback items.forEach( function( item ) { item.once( eventName, tick ); }); }; /** * emits events via EvEmitter and jQuery events * @param {String} type - name of event * @param {Event} event - original event * @param {Array} args - extra arguments */ proto.dispatchEvent = function( type, event, args ) { // add original event to arguments var emitArgs = event ? [ event ].concat( args ) : args; this.emitEvent( type, emitArgs ); if ( jQuery ) { // set this.$element this.$element = this.$element || jQuery( this.element ); if ( event ) { // create jQuery event var $event = jQuery.Event( event ); $event.type = type; this.$element.trigger( $event, args ); } else { // just trigger with type if no event available this.$element.trigger( type, args ); } } }; // -------------------------- ignore & stamps -------------------------- // /** * keep item in collection, but do not lay it out * ignored items do not get skipped in layout * @param {Element} elem */ proto.ignore = function( elem ) { var item = this.getItem( elem ); if ( item ) { item.isIgnored = true; } }; /** * return item to layout collection * @param {Element} elem */ proto.unignore = function( elem ) { var item = this.getItem( elem ); if ( item ) { delete item.isIgnored; } }; /** * adds elements to stamps * @param {NodeList, Array, Element, or String} elems */ proto.stamp = function( elems ) { elems = this._find( elems ); if ( !elems ) { return; } this.stamps = this.stamps.concat( elems ); // ignore elems.forEach( this.ignore, this ); }; /** * removes elements to stamps * @param {NodeList, Array, or Element} elems */ proto.unstamp = function( elems ) { elems = this._find( elems ); if ( !elems ){ return; } elems.forEach( function( elem ) { // filter out removed stamp elements utils.removeFrom( this.stamps, elem ); this.unignore( elem ); }, this ); }; /** * finds child elements * @param {NodeList, Array, Element, or String} elems * @returns {Array} elems */ proto._find = function( elems ) { if ( !elems ) { return; } // if string, use argument as selector string if ( typeof elems == 'string' ) { elems = this.element.querySelectorAll( elems ); } elems = utils.makeArray( elems ); return elems; }; proto._manageStamps = function() { if ( !this.stamps || !this.stamps.length ) { return; } this._getBoundingRect(); this.stamps.forEach( this._manageStamp, this ); }; // update boundingLeft / Top proto._getBoundingRect = function() { // get bounding rect for container element var boundingRect = this.element.getBoundingClientRect(); var size = this.size; this._boundingRect = { left: boundingRect.left + size.paddingLeft + size.borderLeftWidth, top: boundingRect.top + size.paddingTop + size.borderTopWidth, right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ), bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth ) }; }; /** * @param {Element} stamp **/ proto._manageStamp = noop; /** * get x/y position of element relative to container element * @param {Element} elem * @returns {Object} offset - has left, top, right, bottom */ proto._getElementOffset = function( elem ) { var boundingRect = elem.getBoundingClientRect(); var thisRect = this._boundingRect; var size = getSize( elem ); var offset = { left: boundingRect.left - thisRect.left - size.marginLeft, top: boundingRect.top - thisRect.top - size.marginTop, right: thisRect.right - boundingRect.right - size.marginRight, bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom }; return offset; }; // -------------------------- resize -------------------------- // // enable event handlers for listeners // i.e. resize -> onresize proto.handleEvent = utils.handleEvent; /** * Bind layout to window resizing */ proto.bindResize = function() { window.addEventListener( 'resize', this ); this.isResizeBound = true; }; /** * Unbind layout to window resizing */ proto.unbindResize = function() { window.removeEventListener( 'resize', this ); this.isResizeBound = false; }; proto.onresize = function() { this.resize(); }; utils.debounceMethod( Outlayer, 'onresize', 100 ); proto.resize = function() { // don't trigger if size did not change // or if resize was unbound. See #9 if ( !this.isResizeBound || !this.needsResizeLayout() ) { return; } this.layout(); }; /** * check if layout is needed post layout * @returns Boolean */ proto.needsResizeLayout = function() { var size = getSize( this.element ); // check that this.size and size are there // IE8 triggers resize on body size change, so they might not be var hasSizes = this.size && size; return hasSizes && size.innerWidth !== this.size.innerWidth; }; // -------------------------- methods -------------------------- // /** * add items to Outlayer instance * @param {Array or NodeList or Element} elems * @returns {Array} items - Outlayer.Items **/ proto.addItems = function( elems ) { var items = this._itemize( elems ); // add items to collection if ( items.length ) { this.items = this.items.concat( items ); } return items; }; /** * Layout newly-appended item elements * @param {Array or NodeList or Element} elems */ proto.appended = function( elems ) { var items = this.addItems( elems ); if ( !items.length ) { return; } // layout and reveal just the new items this.layoutItems( items, true ); this.reveal( items ); }; /** * Layout prepended elements * @param {Array or NodeList or Element} elems */ proto.prepended = function( elems ) { var items = this._itemize( elems ); if ( !items.length ) { return; } // add items to beginning of collection var previousItems = this.items.slice(0); this.items = items.concat( previousItems ); // start new layout this._resetLayout(); this._manageStamps(); // layout new stuff without transition this.layoutItems( items, true ); this.reveal( items ); // layout previous items this.layoutItems( previousItems ); }; /** * reveal a collection of items * @param {Array of Outlayer.Items} items */ proto.reveal = function( items ) { this._emitCompleteOnItems( 'reveal', items ); if ( !items || !items.length ) { return; } var stagger = this.updateStagger(); items.forEach( function( item, i ) { item.stagger( i * stagger ); item.reveal(); }); }; /** * hide a collection of items * @param {Array of Outlayer.Items} items */ proto.hide = function( items ) { this._emitCompleteOnItems( 'hide', items ); if ( !items || !items.length ) { return; } var stagger = this.updateStagger(); items.forEach( function( item, i ) { item.stagger( i * stagger ); item.hide(); }); }; /** * reveal item elements * @param {Array}, {Element}, {NodeList} items */ proto.revealItemElements = function( elems ) { var items = this.getItems( elems ); this.reveal( items ); }; /** * hide item elements * @param {Array}, {Element}, {NodeList} items */ proto.hideItemElements = function( elems ) { var items = this.getItems( elems ); this.hide( items ); }; /** * get Outlayer.Item, given an Element * @param {Element} elem * @param {Function} callback * @returns {Outlayer.Item} item */ proto.getItem = function( elem ) { // loop through items to get the one that matches for ( var i=0; i < this.items.length; i++ ) { var item = this.items[i]; if ( item.element == elem ) { // return item return item; } } }; /** * get collection of Outlayer.Items, given Elements * @param {Array} elems * @returns {Array} items - Outlayer.Items */ proto.getItems = function( elems ) { elems = utils.makeArray( elems ); var items = []; elems.forEach( function( elem ) { var item = this.getItem( elem ); if ( item ) { items.push( item ); } }, this ); return items; }; /** * remove element(s) from instance and DOM * @param {Array or NodeList or Element} elems */ proto.remove = function( elems ) { var removeItems = this.getItems( elems ); this._emitCompleteOnItems( 'remove', removeItems ); // bail if no items to remove if ( !removeItems || !removeItems.length ) { return; } removeItems.forEach( function( item ) { item.remove(); // remove item from collection utils.removeFrom( this.items, item ); }, this ); }; // ----- destroy ----- // // remove and disable Outlayer instance proto.destroy = function() { // clean up dynamic styles var style = this.element.style; style.height = ''; style.position = ''; style.width = ''; // destroy items this.items.forEach( function( item ) { item.destroy(); }); this.unbindResize(); var id = this.element.outlayerGUID; delete instances[ id ]; // remove reference to instance by id delete this.element.outlayerGUID; // remove data for jQuery if ( jQuery ) { jQuery.removeData( this.element, this.constructor.namespace ); } }; // -------------------------- data -------------------------- // /** * get Outlayer instance from element * @param {Element} elem * @returns {Outlayer} */ Outlayer.data = function( elem ) { elem = utils.getQueryElement( elem ); var id = elem && elem.outlayerGUID; return id && instances[ id ]; }; // -------------------------- create Outlayer class -------------------------- // /** * create a layout class * @param {String} namespace */ Outlayer.create = function( namespace, options ) { // sub-class Outlayer var Layout = subclass( Outlayer ); // apply new options and compatOptions Layout.defaults = utils.extend( {}, Outlayer.defaults ); utils.extend( Layout.defaults, options ); Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions ); Layout.namespace = namespace; Layout.data = Outlayer.data; // sub-class Item Layout.Item = subclass( Item ); // -------------------------- declarative -------------------------- // utils.htmlInit( Layout, namespace ); // -------------------------- jQuery bridge -------------------------- // // make into jQuery plugin if ( jQuery && jQuery.bridget ) { jQuery.bridget( namespace, Layout ); } return Layout; }; function subclass( Parent ) { function SubClass() { Parent.apply( this, arguments ); } SubClass.prototype = Object.create( Parent.prototype ); SubClass.prototype.constructor = SubClass; return SubClass; } // ----- helpers ----- // // how many milliseconds are in each unit var msUnits = { ms: 1, s: 1000 }; // munge time-like parameter into millisecond number // '0.4s' -> 40 function getMilliseconds( time ) { if ( typeof time == 'number' ) { return time; } var matches = time.match( /(^\d*\.?\d*)(\w*)/ ); var num = matches && matches[1]; var unit = matches && matches[2]; if ( !num.length ) { return 0; } num = parseFloat( num ); var mult = msUnits[ unit ] || 1; return num * mult; } // ----- fin ----- // // back in global Outlayer.Item = Item; return Outlayer; })); /***/ }, /***/ 658 (module) { "use strict"; /* jshint browser:true, node:true */ module.exports = function(global) { /* Set up a RequestAnimationFrame shim so we can animate efficiently FOR * GREAT JUSTICE. */ var requestInterval, cancelInterval; (function() { var raf = global.requestAnimationFrame || global.webkitRequestAnimationFrame || global.mozRequestAnimationFrame || global.oRequestAnimationFrame || global.msRequestAnimationFrame , caf = global.cancelAnimationFrame || global.webkitCancelAnimationFrame || global.mozCancelAnimationFrame || global.oCancelAnimationFrame || global.msCancelAnimationFrame ; if(raf && caf) { requestInterval = function(fn, delay) { var handle = {value: null}; function loop() { handle.value = raf(loop); fn(); } loop(); return handle; }; cancelInterval = function(handle) { caf(handle.value); }; } else { requestInterval = setInterval; cancelInterval = clearInterval; } }()); /* Catmull-rom spline stuffs. */ /* function upsample(n, spline) { var polyline = [], len = spline.length, bx = spline[0], by = spline[1], cx = spline[2], cy = spline[3], dx = spline[4], dy = spline[5], i, j, ax, ay, px, qx, rx, sx, py, qy, ry, sy, t; for(i = 6; i !== spline.length; i += 2) { ax = bx; bx = cx; cx = dx; dx = spline[i ]; px = -0.5 * ax + 1.5 * bx - 1.5 * cx + 0.5 * dx; qx = ax - 2.5 * bx + 2.0 * cx - 0.5 * dx; rx = -0.5 * ax + 0.5 * cx ; sx = bx ; ay = by; by = cy; cy = dy; dy = spline[i + 1]; py = -0.5 * ay + 1.5 * by - 1.5 * cy + 0.5 * dy; qy = ay - 2.5 * by + 2.0 * cy - 0.5 * dy; ry = -0.5 * ay + 0.5 * cy ; sy = by ; for(j = 0; j !== n; ++j) { t = j / n; polyline.push( ((px * t + qx) * t + rx) * t + sx, ((py * t + qy) * t + ry) * t + sy ); } } polyline.push( px + qx + rx + sx, py + qy + ry + sy ); return polyline; } function downsample(n, polyline) { var len = 0, i, dx, dy; for(i = 2; i !== polyline.length; i += 2) { dx = polyline[i ] - polyline[i - 2]; dy = polyline[i + 1] - polyline[i - 1]; len += Math.sqrt(dx * dx + dy * dy); } len /= n; var small = [], target = len, min = 0, max, t; small.push(polyline[0], polyline[1]); for(i = 2; i !== polyline.length; i += 2) { dx = polyline[i ] - polyline[i - 2]; dy = polyline[i + 1] - polyline[i - 1]; max = min + Math.sqrt(dx * dx + dy * dy); if(max > target) { t = (target - min) / (max - min); small.push( polyline[i - 2] + dx * t, polyline[i - 1] + dy * t ); target += len; } min = max; } small.push(polyline[polyline.length - 2], polyline[polyline.length - 1]); return small; } */ /* Define skycon things. */ /* FIXME: I'm *really really* sorry that this code is so gross. Really, I am. * I'll try to clean it up eventually! Promise! */ var KEYFRAME = 500, STROKE = 0.08, TAU = 2.0 * Math.PI, TWO_OVER_SQRT_2 = 2.0 / Math.sqrt(2); function circle(ctx, x, y, r) { ctx.beginPath(); ctx.arc(x, y, r, 0, TAU, false); ctx.fill(); } function line(ctx, ax, ay, bx, by) { ctx.beginPath(); ctx.moveTo(ax, ay); ctx.lineTo(bx, by); ctx.stroke(); } function puff(ctx, t, cx, cy, rx, ry, rmin, rmax) { var c = Math.cos(t * TAU), s = Math.sin(t * TAU); rmax -= rmin; circle( ctx, cx - s * rx, cy + c * ry + rmax * 0.5, rmin + (1 - c * 0.5) * rmax ); } function puffs(ctx, t, cx, cy, rx, ry, rmin, rmax) { var i; for(i = 5; i--; ) puff(ctx, t + i / 5, cx, cy, rx, ry, rmin, rmax); } function cloud(ctx, t, cx, cy, cw, s, color) { t /= 30000; var a = cw * 0.21, b = cw * 0.12, c = cw * 0.24, d = cw * 0.28; ctx.fillStyle = color; puffs(ctx, t, cx, cy, a, b, c, d); ctx.globalCompositeOperation = 'destination-out'; puffs(ctx, t, cx, cy, a, b, c - s, d - s); ctx.globalCompositeOperation = 'source-over'; } function sun(ctx, t, cx, cy, cw, s, color) { t /= 120000; var a = cw * 0.25 - s * 0.5, b = cw * 0.32 + s * 0.5, c = cw * 0.50 - s * 0.5, i, p, cos, sin; ctx.strokeStyle = color; ctx.lineWidth = s; ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.beginPath(); ctx.arc(cx, cy, a, 0, TAU, false); ctx.stroke(); for(i = 8; i--; ) { p = (t + i / 8) * TAU; cos = Math.cos(p); sin = Math.sin(p); line(ctx, cx + cos * b, cy + sin * b, cx + cos * c, cy + sin * c); } } function moon(ctx, t, cx, cy, cw, s, color) { t /= 15000; var a = cw * 0.29 - s * 0.5, b = cw * 0.05, c = Math.cos(t * TAU), p = c * TAU / -16; ctx.strokeStyle = color; ctx.lineWidth = s; ctx.lineCap = "round"; ctx.lineJoin = "round"; cx += c * b; ctx.beginPath(); ctx.arc(cx, cy, a, p + TAU / 8, p + TAU * 7 / 8, false); ctx.arc(cx + Math.cos(p) * a * TWO_OVER_SQRT_2, cy + Math.sin(p) * a * TWO_OVER_SQRT_2, a, p + TAU * 5 / 8, p + TAU * 3 / 8, true); ctx.closePath(); ctx.stroke(); } function rain(ctx, t, cx, cy, cw, s, color) { t /= 1350; var a = cw * 0.16, b = TAU * 11 / 12, c = TAU * 7 / 12, i, p, x, y; ctx.fillStyle = color; for(i = 4; i--; ) { p = (t + i / 4) % 1; x = cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a; y = cy + p * p * cw; ctx.beginPath(); ctx.moveTo(x, y - s * 1.5); ctx.arc(x, y, s * 0.75, b, c, false); ctx.fill(); } } function sleet(ctx, t, cx, cy, cw, s, color) { t /= 750; var a = cw * 0.1875, b = TAU * 11 / 12, c = TAU * 7 / 12, i, p, x, y; ctx.strokeStyle = color; ctx.lineWidth = s * 0.5; ctx.lineCap = "round"; ctx.lineJoin = "round"; for(i = 4; i--; ) { p = (t + i / 4) % 1; x = Math.floor(cx + ((i - 1.5) / 1.5) * (i === 1 || i === 2 ? -1 : 1) * a) + 0.5; y = cy + p * cw; line(ctx, x, y - s * 1.5, x, y + s * 1.5); } } function snow(ctx, t, cx, cy, cw, s, color) { t /= 3000; var a = cw * 0.16, b = s * 0.75, u = t * TAU * 0.7, ux = Math.cos(u) * b, uy = Math.sin(u) * b, v = u + TAU / 3, vx = Math.cos(v) * b, vy = Math.sin(v) * b, w = u + TAU * 2 / 3, wx = Math.cos(w) * b, wy = Math.sin(w) * b, i, p, x, y; ctx.strokeStyle = color; ctx.lineWidth = s * 0.5; ctx.lineCap = "round"; ctx.lineJoin = "round"; for(i = 4; i--; ) { p = (t + i / 4) % 1; x = cx + Math.sin((p + i / 4) * TAU) * a; y = cy + p * cw; line(ctx, x - ux, y - uy, x + ux, y + uy); line(ctx, x - vx, y - vy, x + vx, y + vy); line(ctx, x - wx, y - wy, x + wx, y + wy); } } function fogbank(ctx, t, cx, cy, cw, s, color) { t /= 30000; var a = cw * 0.21, b = cw * 0.06, c = cw * 0.21, d = cw * 0.28; ctx.fillStyle = color; puffs(ctx, t, cx, cy, a, b, c, d); ctx.globalCompositeOperation = 'destination-out'; puffs(ctx, t, cx, cy, a, b, c - s, d - s); ctx.globalCompositeOperation = 'source-over'; } /* var WIND_PATHS = [ downsample(63, upsample(8, [ -1.00, -0.28, -0.75, -0.18, -0.50, 0.12, -0.20, 0.12, -0.04, -0.04, -0.07, -0.18, -0.19, -0.18, -0.23, -0.05, -0.12, 0.11, 0.02, 0.16, 0.20, 0.15, 0.50, 0.07, 0.75, 0.18, 1.00, 0.28 ])), downsample(31, upsample(16, [ -1.00, -0.10, -0.75, 0.00, -0.50, 0.10, -0.25, 0.14, 0.00, 0.10, 0.25, 0.00, 0.50, -0.10, 0.75, -0.14, 1.00, -0.10 ])) ]; */ var WIND_PATHS = [ [ -0.7500, -0.1800, -0.7219, -0.1527, -0.6971, -0.1225, -0.6739, -0.0910, -0.6516, -0.0588, -0.6298, -0.0262, -0.6083, 0.0065, -0.5868, 0.0396, -0.5643, 0.0731, -0.5372, 0.1041, -0.5033, 0.1259, -0.4662, 0.1406, -0.4275, 0.1493, -0.3881, 0.1530, -0.3487, 0.1526, -0.3095, 0.1488, -0.2708, 0.1421, -0.2319, 0.1342, -0.1943, 0.1217, -0.1600, 0.1025, -0.1290, 0.0785, -0.1012, 0.0509, -0.0764, 0.0206, -0.0547, -0.0120, -0.0378, -0.0472, -0.0324, -0.0857, -0.0389, -0.1241, -0.0546, -0.1599, -0.0814, -0.1876, -0.1193, -0.1964, -0.1582, -0.1935, -0.1931, -0.1769, -0.2157, -0.1453, -0.2290, -0.1085, -0.2327, -0.0697, -0.2240, -0.0317, -0.2064, 0.0033, -0.1853, 0.0362, -0.1613, 0.0672, -0.1350, 0.0961, -0.1051, 0.1213, -0.0706, 0.1397, -0.0332, 0.1512, 0.0053, 0.1580, 0.0442, 0.1624, 0.0833, 0.1636, 0.1224, 0.1615, 0.1613, 0.1565, 0.1999, 0.1500, 0.2378, 0.1402, 0.2749, 0.1279, 0.3118, 0.1147, 0.3487, 0.1015, 0.3858, 0.0892, 0.4236, 0.0787, 0.4621, 0.0715, 0.5012, 0.0702, 0.5398, 0.0766, 0.5768, 0.0890, 0.6123, 0.1055, 0.6466, 0.1244, 0.6805, 0.1440, 0.7147, 0.1630, 0.7500, 0.1800 ], [ -0.7500, 0.0000, -0.7033, 0.0195, -0.6569, 0.0399, -0.6104, 0.0600, -0.5634, 0.0789, -0.5155, 0.0954, -0.4667, 0.1089, -0.4174, 0.1206, -0.3676, 0.1299, -0.3174, 0.1365, -0.2669, 0.1398, -0.2162, 0.1391, -0.1658, 0.1347, -0.1157, 0.1271, -0.0661, 0.1169, -0.0170, 0.1046, 0.0316, 0.0903, 0.0791, 0.0728, 0.1259, 0.0534, 0.1723, 0.0331, 0.2188, 0.0129, 0.2656, -0.0064, 0.3122, -0.0263, 0.3586, -0.0466, 0.4052, -0.0665, 0.4525, -0.0847, 0.5007, -0.1002, 0.5497, -0.1130, 0.5991, -0.1240, 0.6491, -0.1325, 0.6994, -0.1380, 0.7500, -0.1400 ] ], WIND_OFFSETS = [ {start: 0.36, end: 0.11}, {start: 0.56, end: 0.16} ]; function leaf(ctx, t, x, y, cw, s, color) { var a = cw / 8, b = a / 3, c = 2 * b, d = (t % 1) * TAU, e = Math.cos(d), f = Math.sin(d); ctx.fillStyle = color; ctx.strokeStyle = color; ctx.lineWidth = s; ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.beginPath(); ctx.arc(x , y , a, d , d + Math.PI, false); ctx.arc(x - b * e, y - b * f, c, d + Math.PI, d , false); ctx.arc(x + c * e, y + c * f, b, d + Math.PI, d , true ); ctx.globalCompositeOperation = 'destination-out'; ctx.fill(); ctx.globalCompositeOperation = 'source-over'; ctx.stroke(); } function swoosh(ctx, t, cx, cy, cw, s, index, total, color) { t /= 2500; var path = WIND_PATHS[index], a = (t + index - WIND_OFFSETS[index].start) % total, c = (t + index - WIND_OFFSETS[index].end ) % total, e = (t + index ) % total, b, d, f, i; ctx.strokeStyle = color; ctx.lineWidth = s; ctx.lineCap = "round"; ctx.lineJoin = "round"; if(a < 1) { ctx.beginPath(); a *= path.length / 2 - 1; b = Math.floor(a); a -= b; b *= 2; b += 2; ctx.moveTo( cx + (path[b - 2] * (1 - a) + path[b ] * a) * cw, cy + (path[b - 1] * (1 - a) + path[b + 1] * a) * cw ); if(c < 1) { c *= path.length / 2 - 1; d = Math.floor(c); c -= d; d *= 2; d += 2; for(i = b; i !== d; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); ctx.lineTo( cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw, cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw ); } else for(i = b; i !== path.length; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); ctx.stroke(); } else if(c < 1) { ctx.beginPath(); c *= path.length / 2 - 1; d = Math.floor(c); c -= d; d *= 2; d += 2; ctx.moveTo(cx + path[0] * cw, cy + path[1] * cw); for(i = 2; i !== d; i += 2) ctx.lineTo(cx + path[i] * cw, cy + path[i + 1] * cw); ctx.lineTo( cx + (path[d - 2] * (1 - c) + path[d ] * c) * cw, cy + (path[d - 1] * (1 - c) + path[d + 1] * c) * cw ); ctx.stroke(); } if(e < 1) { e *= path.length / 2 - 1; f = Math.floor(e); e -= f; f *= 2; f += 2; leaf( ctx, t, cx + (path[f - 2] * (1 - e) + path[f ] * e) * cw, cy + (path[f - 1] * (1 - e) + path[f + 1] * e) * cw, cw, s, color ); } } var Skycons = function(opts) { this.list = []; this.interval = null; this.color = opts && opts.color ? opts.color : "black"; this.resizeClear = !!(opts && opts.resizeClear); }; Skycons.CLEAR_DAY = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); sun(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); }; Skycons.CLEAR_NIGHT = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); moon(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); }; Skycons.PARTLY_CLOUDY_DAY = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); sun(ctx, t, w * 0.625, h * 0.375, s * 0.75, s * STROKE, color); cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); }; Skycons.PARTLY_CLOUDY_NIGHT = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); moon(ctx, t, w * 0.667, h * 0.375, s * 0.75, s * STROKE, color); cloud(ctx, t, w * 0.375, h * 0.625, s * 0.75, s * STROKE, color); }; Skycons.CLOUDY = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); cloud(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, color); }; Skycons.RAIN = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); rain(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); }; Skycons.SLEET = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); sleet(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); }; Skycons.SNOW = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); snow(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); cloud(ctx, t, w * 0.5, h * 0.37, s * 0.9, s * STROKE, color); }; Skycons.WIND = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h); swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 0, 2, color); swoosh(ctx, t, w * 0.5, h * 0.5, s, s * STROKE, 1, 2, color); }; Skycons.FOG = function(ctx, t, color) { var w = ctx.canvas.width, h = ctx.canvas.height, s = Math.min(w, h), k = s * STROKE; fogbank(ctx, t, w * 0.5, h * 0.32, s * 0.75, k, color); t /= 5000; var a = Math.cos((t ) * TAU) * s * 0.02, b = Math.cos((t + 0.25) * TAU) * s * 0.02, c = Math.cos((t + 0.50) * TAU) * s * 0.02, d = Math.cos((t + 0.75) * TAU) * s * 0.02, n = h * 0.936, e = Math.floor(n - k * 0.5) + 0.5, f = Math.floor(n - k * 2.5) + 0.5; ctx.strokeStyle = color; ctx.lineWidth = k; ctx.lineCap = "round"; ctx.lineJoin = "round"; line(ctx, a + w * 0.2 + k * 0.5, e, b + w * 0.8 - k * 0.5, e); line(ctx, c + w * 0.2 + k * 0.5, f, d + w * 0.8 - k * 0.5, f); }; Skycons.prototype = { _determineDrawingFunction: function(draw) { if(typeof draw === "string") draw = Skycons[draw.toUpperCase().replace(/-/g, "_")] || null; return draw; }, add: function(el, draw) { var obj; if(typeof el === "string") el = document.getElementById(el); // Does nothing if canvas name doesn't exists if(el === null) return; draw = this._determineDrawingFunction(draw); // Does nothing if the draw function isn't actually a function if(typeof draw !== "function") return; obj = { element: el, context: el.getContext("2d"), drawing: draw }; this.list.push(obj); this.draw(obj, KEYFRAME); }, set: function(el, draw) { var i; if(typeof el === "string") el = document.getElementById(el); for(i = this.list.length; i--; ) if(this.list[i].element === el) { this.list[i].drawing = this._determineDrawingFunction(draw); this.draw(this.list[i], KEYFRAME); return; } this.add(el, draw); }, remove: function(el) { var i; if(typeof el === "string") el = document.getElementById(el); for(i = this.list.length; i--; ) if(this.list[i].element === el) { this.list.splice(i, 1); return; } }, draw: function(obj, time) { var canvas = obj.context.canvas; if(this.resizeClear) canvas.width = canvas.width; else obj.context.clearRect(0, 0, canvas.width, canvas.height); obj.drawing(obj.context, time, this.color); }, play: function() { var self = this; this.pause(); this.interval = requestInterval(function() { var now = Date.now(), i; for(i = self.list.length; i--; ) self.draw(self.list[i], now); }, 1000 / 60); }, pause: function() { var i; if(this.interval) { cancelInterval(this.interval); this.interval = null; } } }; return Skycons; }; /***/ } /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = (module) => { /******/ var getter = module && module.__esModule ? /******/ () => (module['default']) : /******/ () => (module); /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = (exports, definition) => { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ })(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry needs to be wrapped in an IIFE because it needs to be in strict mode. (() => { "use strict"; ;// ../assets/scripts/utils/dom.js /** * Adminator DOM Utility Functions * Provides jQuery-like functionality using vanilla JavaScript * * @module utils/dom * @example * import { DOM } from './utils/dom'; * * // Select elements * const button = DOM.select('.my-button'); * const items = DOM.selectAll('.list-item'); * * // Add event listeners * DOM.on(button, 'click', () => console.log('Clicked!')); * * // Manipulate classes * DOM.addClass(button, 'active'); * DOM.toggleClass(button, 'loading'); */ /** * DOM utility object providing jQuery-like methods * @namespace */ const DOM = { /** * Select a single element matching the selector * Replaces jQuery's $('selector').first() * * @param {string} selector - CSS selector * @param {Document|Element} [context=document] - Context to search within * @returns {Element|null} The matched element or null * * @example * const header = DOM.select('.header'); * const navItem = DOM.select('.nav-item', sidebar); */ select: function (selector) { let context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; return context.querySelector(selector); }, /** * Select all elements matching the selector * Replaces jQuery's $('selector') * * @param {string} selector - CSS selector * @param {Document|Element} [context=document] - Context to search within * @returns {Element[]} Array of matched elements * * @example * const buttons = DOM.selectAll('.btn'); * buttons.forEach(btn => DOM.addClass(btn, 'initialized')); */ selectAll: function (selector) { let context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : document; return Array.from(context.querySelectorAll(selector)); }, /** * Check if an element matching the selector exists * * @param {string} selector - CSS selector * @returns {boolean} True if element exists * * @example * if (DOM.exists('.sidebar')) { * initSidebar(); * } */ exists: selector => { return document.querySelector(selector) !== null; }, /** * Add an event listener to an element * Replaces jQuery's $.on() * * @param {Element|string} element - Element or selector * @param {string} event - Event name (e.g., 'click', 'change') * @param {Function} handler - Event handler function * @param {Object} [options={}] - addEventListener options * * @example * DOM.on('.btn', 'click', handleClick); * DOM.on(button, 'click', handleClick, { once: true }); */ on: function (element, event, handler) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.addEventListener(event, handler, options); } }, /** * Remove an event listener from an element * Replaces jQuery's $.off() * * @param {Element|string} element - Element or selector * @param {string} event - Event name * @param {Function} handler - Event handler to remove * * @example * DOM.off(button, 'click', handleClick); */ off: (element, event, handler) => { if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.removeEventListener(event, handler); } }, /** * Add a class to an element * Replaces jQuery's $.addClass() * * @param {Element|string} element - Element or selector * @param {string} className - Class name to add * * @example * DOM.addClass('.menu', 'open'); */ addClass: (element, className) => { if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.classList.add(className); } }, /** * Remove a class from an element * Replaces jQuery's $.removeClass() * * @param {Element|string} element - Element or selector * @param {string} className - Class name to remove * * @example * DOM.removeClass('.menu', 'open'); */ removeClass: (element, className) => { if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.classList.remove(className); } }, /** * Toggle a class on an element * Replaces jQuery's $.toggleClass() * * @param {Element|string} element - Element or selector * @param {string} className - Class name to toggle * * @example * DOM.toggleClass('.dropdown', 'show'); */ toggleClass: (element, className) => { if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.classList.toggle(className); } }, /** * Check if an element has a class * Replaces jQuery's $.hasClass() * * @param {Element|string} element - Element or selector * @param {string} className - Class name to check * @returns {boolean} True if element has the class * * @example * if (DOM.hasClass('.menu', 'open')) { * closeMenu(); * } */ hasClass: (element, className) => { if (typeof element === 'string') { element = document.querySelector(element); } return element ? element.classList.contains(className) : false; }, /** * Get or set an attribute on an element * Replaces jQuery's $.attr() * * @param {Element|string} element - Element or selector * @param {string} name - Attribute name * @param {string} [value] - Value to set (omit to get) * @returns {string|Element|null} Attribute value when getting, element when setting * * @example * // Get attribute * const href = DOM.attr(link, 'href'); * * // Set attribute * DOM.attr(link, 'href', '/new-page'); */ attr: (element, name, value) => { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return null; if (value === undefined) { return element.getAttribute(name); } else { element.setAttribute(name, value); return element; } }, /** * Get or set a data attribute on an element * Replaces jQuery's $.data() * * @param {Element|string} element - Element or selector * @param {string} name - Data attribute name (without 'data-' prefix) * @param {string} [value] - Value to set (omit to get) * @returns {string|Element|null} Data value when getting, element when setting * * @example * // Get data attribute * const id = DOM.data(row, 'id'); // Gets data-id * * // Set data attribute * DOM.data(row, 'id', '123'); */ data: (element, name, value) => { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return null; const dataName = `data-${name}`; if (value === undefined) { return element.getAttribute(dataName); } else { element.setAttribute(dataName, value); return element; } }, /** * Get or set text content of an element * Replaces jQuery's $.text() * * @param {Element|string} element - Element or selector * @param {string} [content] - Text to set (omit to get) * @returns {string|Element|null} Text content when getting, element when setting * * @example * const text = DOM.text('.title'); * DOM.text('.title', 'New Title'); */ text: (element, content) => { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return null; if (content === undefined) { return element.textContent; } else { element.textContent = content; return element; } }, /** * Get or set HTML content of an element * Replaces jQuery's $.html() * * @param {Element|string} element - Element or selector * @param {string} [content] - HTML to set (omit to get) * @returns {string|Element|null} HTML content when getting, element when setting * * @example * const html = DOM.html('.container'); * DOM.html('.container', '

New content

'); */ html: (element, content) => { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return null; if (content === undefined) { return element.innerHTML; } else { element.innerHTML = content; return element; } }, /** * Hide an element * Replaces jQuery's $.hide() * * @param {Element|string} element - Element or selector * * @example * DOM.hide('.modal'); */ hide: element => { if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.style.display = 'none'; } }, /** * Show an element * Replaces jQuery's $.show() * * @param {Element|string} element - Element or selector * @param {string} [display='block'] - Display value to use * * @example * DOM.show('.modal'); * DOM.show('.flex-item', 'flex'); */ show: function (element) { let display = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'block'; if (typeof element === 'string') { element = document.querySelector(element); } if (element) { element.style.display = display; } }, /** * Toggle element visibility * Replaces jQuery's $.toggle() * * @param {Element|string} element - Element or selector * @param {string} [display='block'] - Display value when showing * * @example * DOM.toggle('.menu'); */ toggle: function (element) { let display = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'block'; if (typeof element === 'string') { element = document.querySelector(element); } if (element) { if (element.style.display === 'none') { element.style.display = display; } else { element.style.display = 'none'; } } }, /** * Animate element sliding up (collapsing) * Replaces jQuery's $.slideUp() * * @param {Element|string} element - Element or selector * @param {number} [duration=300] - Animation duration in ms * @returns {Promise} Resolves when animation completes * * @example * await DOM.slideUp('.panel'); */ slideUp: function (element) { let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return Promise.resolve(); return new Promise(resolve => { const height = element.scrollHeight; element.style.height = `${height}px`; element.style.overflow = 'hidden'; element.animate([{ height: `${height}px` }, { height: '0px' }], { duration, easing: 'ease-in-out' }).onfinish = () => { element.style.display = 'none'; element.style.height = ''; element.style.overflow = ''; resolve(); }; }); }, /** * Animate element sliding down (expanding) * Replaces jQuery's $.slideDown() * * @param {Element|string} element - Element or selector * @param {number} [duration=300] - Animation duration in ms * @returns {Promise} Resolves when animation completes * * @example * await DOM.slideDown('.panel'); */ slideDown: function (element) { let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return Promise.resolve(); return new Promise(resolve => { element.style.display = 'block'; element.style.height = '0px'; element.style.overflow = 'hidden'; const height = element.scrollHeight; element.animate([{ height: '0px' }, { height: `${height}px` }], { duration, easing: 'ease-in-out' }).onfinish = () => { element.style.height = 'auto'; element.style.overflow = 'visible'; resolve(); }; }); }, /** * Animate element fading in * Replaces jQuery's $.fadeIn() * * @param {Element|string} element - Element or selector * @param {number} [duration=300] - Animation duration in ms * @returns {Promise} Resolves when animation completes * * @example * await DOM.fadeIn('.modal'); */ fadeIn: function (element) { let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return Promise.resolve(); return new Promise(resolve => { element.style.opacity = '0'; element.style.display = 'block'; element.animate([{ opacity: 0 }, { opacity: 1 }], { duration, easing: 'ease-in-out' }).onfinish = () => { element.style.opacity = ''; resolve(); }; }); }, /** * Animate element fading out * Replaces jQuery's $.fadeOut() * * @param {Element|string} element - Element or selector * @param {number} [duration=300] - Animation duration in ms * @returns {Promise} Resolves when animation completes * * @example * await DOM.fadeOut('.modal'); */ fadeOut: function (element) { let duration = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300; if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return Promise.resolve(); return new Promise(resolve => { element.animate([{ opacity: 1 }, { opacity: 0 }], { duration, easing: 'ease-in-out' }).onfinish = () => { element.style.display = 'none'; element.style.opacity = ''; resolve(); }; }); }, /** * Get element dimensions and position relative to viewport * * @param {Element|string} element - Element or selector * @returns {Object|null} Dimensions object or null * @property {number} width - Element width * @property {number} height - Element height * @property {number} top - Distance from viewport top * @property {number} left - Distance from viewport left * @property {number} bottom - Distance from viewport bottom * @property {number} right - Distance from viewport right * * @example * const { width, height, top, left } = DOM.dimensions('.card'); */ dimensions: element => { if (typeof element === 'string') { element = document.querySelector(element); } if (!element) return null; const rect = element.getBoundingClientRect(); return { width: rect.width, height: rect.height, top: rect.top, left: rect.left, bottom: rect.bottom, right: rect.right }; }, /** * Execute callback when DOM is ready * Replaces jQuery's $(document).ready() * * @param {Function} callback - Function to execute when DOM is ready * * @example * DOM.ready(() => { * initApp(); * }); */ ready: callback => { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', callback); } else { callback(); } }, /** * Create an element with optional attributes and children * * @param {string} tag - HTML tag name * @param {Object} [attrs={}] - Attributes to set * @param {Array} [children=[]] - Child elements or text * @returns {Element} The created element * * @example * const button = DOM.create('button', { class: 'btn', type: 'submit' }, ['Submit']); */ create: function (tag) { let attrs = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; let children = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; const el = document.createElement(tag); Object.entries(attrs).forEach(_ref => { let [key, value] = _ref; if (key === 'class') { el.className = value; } else if (key.startsWith('data-')) { el.setAttribute(key, value); } else { el[key] = value; } }); children.forEach(child => { if (typeof child === 'string') { el.appendChild(document.createTextNode(child)); } else if (child instanceof Element) { el.appendChild(child); } }); return el; }, /** * Find the closest ancestor matching a selector * * @param {Element|string} element - Element or selector * @param {string} selector - Selector to match * @returns {Element|null} Closest matching ancestor or null * * @example * const form = DOM.closest(input, 'form'); */ closest: (element, selector) => { if (typeof element === 'string') { element = document.querySelector(element); } return element ? element.closest(selector) : null; } }; /* harmony default export */ const dom = ((/* unused pure expression or super */ null && (DOM))); // EXTERNAL MODULE: ../../node_modules/dayjs/dayjs.min.js var dayjs_min = __webpack_require__(464); var dayjs_min_default = /*#__PURE__*/__webpack_require__.n(dayjs_min); // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/utc.js var utc = __webpack_require__(657); var utc_default = /*#__PURE__*/__webpack_require__.n(utc); // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/timezone.js var timezone = __webpack_require__(168); var timezone_default = /*#__PURE__*/__webpack_require__.n(timezone); // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/relativeTime.js var relativeTime = __webpack_require__(562); var relativeTime_default = /*#__PURE__*/__webpack_require__.n(relativeTime); // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/customParseFormat.js var customParseFormat = __webpack_require__(630); var customParseFormat_default = /*#__PURE__*/__webpack_require__.n(customParseFormat); // EXTERNAL MODULE: ../../node_modules/dayjs/plugin/advancedFormat.js var advancedFormat = __webpack_require__(258); var advancedFormat_default = /*#__PURE__*/__webpack_require__.n(advancedFormat); ;// ../assets/scripts/utils/date.js /** * Modern Date Utilities * Using Day.js (2KB) instead of Moment.js (67KB) - 97% size reduction * Provides consistent date formatting and manipulation across the application */ // Enable Day.js plugins dayjs_min_default().extend((utc_default())); dayjs_min_default().extend((timezone_default())); dayjs_min_default().extend((relativeTime_default())); dayjs_min_default().extend((customParseFormat_default())); dayjs_min_default().extend((advancedFormat_default())); const DateUtils = { /** * Get current date/time */ now: () => dayjs_min_default()(), /** * Parse date from string or Date object */ parse: function (input) { let format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; return format ? dayjs_min_default()(input, format) : dayjs_min_default()(input); }, /** * Format date for display */ format: function (date) { let format = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'YYYY-MM-DD'; return dayjs_min_default()(date).format(format); }, /** * Common date formatting presets */ formatters: { // Dashboard display formats shortDate: date => dayjs_min_default()(date).format('MMM DD, YYYY'), longDate: date => dayjs_min_default()(date).format('MMMM DD, YYYY'), dateTime: date => dayjs_min_default()(date).format('MMM DD, YYYY h:mm A'), // Calendar formats calendarDate: date => dayjs_min_default()(date).format('YYYY-MM-DD'), calendarDateTime: date => dayjs_min_default()(date).format('YYYY-MM-DD HH:mm:ss'), // Form input formats inputDate: date => dayjs_min_default()(date).format('YYYY-MM-DD'), inputDateTime: date => dayjs_min_default()(date).format('YYYY-MM-DDTHH:mm'), // Display formats timeOnly: date => dayjs_min_default()(date).format('h:mm A'), monthYear: date => dayjs_min_default()(date).format('MMMM YYYY'), dayMonth: date => dayjs_min_default()(date).format('DD MMM'), // Relative time relative: date => dayjs_min_default()(date).fromNow(), relativeCalendar: date => { const now = dayjs_min_default()(); const target = dayjs_min_default()(date); const diffDays = now.diff(target, 'day'); if (diffDays === 0) return 'Today'; if (diffDays === 1) return 'Yesterday'; if (diffDays === -1) return 'Tomorrow'; if (diffDays > 1 && diffDays < 7) return `${diffDays} days ago`; if (diffDays < -1 && diffDays > -7) return `In ${Math.abs(diffDays)} days`; return target.format('MMM DD, YYYY'); } }, /** * Date manipulation */ add: (date, amount, unit) => dayjs_min_default()(date).add(amount, unit), subtract: (date, amount, unit) => dayjs_min_default()(date).subtract(amount, unit), startOf: (date, unit) => dayjs_min_default()(date).startOf(unit), endOf: (date, unit) => dayjs_min_default()(date).endOf(unit), /** * Date comparison */ isBefore: (date1, date2) => dayjs_min_default()(date1).isBefore(dayjs_min_default()(date2)), isAfter: (date1, date2) => dayjs_min_default()(date1).isAfter(dayjs_min_default()(date2)), isSame: function (date1, date2) { let unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'day'; return dayjs_min_default()(date1).isSame(dayjs_min_default()(date2), unit); }, isBetween: (date, start, end) => dayjs_min_default()(date).isBetween(dayjs_min_default()(start), dayjs_min_default()(end)), /** * Date validation */ isValid: date => dayjs_min_default()(date).isValid(), /** * Timezone utilities */ timezone: { convert: (date, tz) => dayjs_min_default()(date).tz(tz), utc: date => dayjs_min_default()(date).utc(), local: date => dayjs_min_default()(date).local(), guess: () => dayjs_min_default().tz.guess() }, /** * Calendar utilities */ calendar: { // Get calendar month data for building calendar views getMonthData: function () { let date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; const target = date ? dayjs_min_default()(date) : dayjs_min_default()(); const startOfMonth = target.startOf('month'); const endOfMonth = target.endOf('month'); const startOfCalendar = startOfMonth.startOf('week'); const endOfCalendar = endOfMonth.endOf('week'); const days = []; let current = startOfCalendar; while (current.isBefore(endOfCalendar) || current.isSame(endOfCalendar, 'day')) { days.push({ date: current.format('YYYY-MM-DD'), day: current.date(), isCurrentMonth: current.isSame(target, 'month'), isToday: current.isSame(dayjs_min_default()(), 'day'), dayjs: current.clone() }); current = current.add(1, 'day'); } return { month: target.format('MMMM YYYY'), year: target.year(), monthIndex: target.month(), days }; }, // Get week data getWeekData: function () { let date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null; const target = date ? dayjs_min_default()(date) : dayjs_min_default()(); const startOfWeek = target.startOf('week'); const endOfWeek = target.endOf('week'); const days = []; let current = startOfWeek; while (current.isBefore(endOfWeek) || current.isSame(endOfWeek, 'day')) { days.push({ date: current.format('YYYY-MM-DD'), day: current.date(), dayName: current.format('dddd'), shortDayName: current.format('ddd'), isToday: current.isSame(dayjs_min_default()(), 'day'), dayjs: current.clone() }); current = current.add(1, 'day'); } return { weekStart: startOfWeek.format('MMM DD'), weekEnd: endOfWeek.format('MMM DD, YYYY'), days }; } }, /** * Form utilities */ form: { // Convert date to HTML5 input format toInputValue: date => dayjs_min_default()(date).format('YYYY-MM-DD'), toDateTimeInputValue: date => dayjs_min_default()(date).format('YYYY-MM-DDTHH:mm'), // Parse from HTML5 input fromInputValue: value => dayjs_min_default()(value), // Validate date input validateDateInput: value => { const parsed = dayjs_min_default()(value); return parsed.isValid() && value.length >= 8; // Basic validation } }, /** * Chart/Data utilities */ charts: { // Generate date ranges for charts generateDateRange: function (start, end) { let interval = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 'day'; const dates = []; let current = dayjs_min_default()(start); const endDate = dayjs_min_default()(end); while (current.isBefore(endDate) || current.isSame(endDate, interval)) { dates.push({ date: current.format('YYYY-MM-DD'), label: current.format('MMM DD'), value: current.toISOString(), dayjs: current.clone() }); current = current.add(1, interval); } return dates; }, // Get common chart date labels getChartLabels: function () { let period = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'week'; const now = dayjs_min_default()(); switch (period) { case 'week': return Array.from({ length: 7 }, (_, i) => now.subtract(6 - i, 'day').format('ddd')); case 'month': return Array.from({ length: 30 }, (_, i) => now.subtract(29 - i, 'day').format('DD')); case 'year': return Array.from({ length: 12 }, (_, i) => now.subtract(11 - i, 'month').format('MMM')); default: return []; } } } }; // Export dayjs instance for direct use when needed // Default export /* harmony default export */ const date = (DateUtils); ;// ../assets/scripts/utils/theme.js /** * Adminator Theme Manager * Handles light/dark mode switching with localStorage persistence * * @module utils/theme * @example * // Get current theme * const current = Theme.current(); // 'light' or 'dark' * * // Toggle theme * Theme.toggle(); * * // Apply specific theme * Theme.apply('dark'); * * // Listen for theme changes * window.addEventListener('adminator:themeChanged', (e) => { * console.log('New theme:', e.detail.theme); * }); */ /* global Chart */ /** @constant {string} Storage key for theme preference */ const THEME_KEY = 'adminator-theme'; /** @constant {string[]} Valid theme values */ const VALID_THEMES = ['light', 'dark']; /** * Safe localStorage wrapper * Handles cases where localStorage is unavailable (private browsing, etc.) * @private */ const Storage = { /** * Get item from localStorage * @param {string} key - Storage key * @returns {string|null} Stored value or null */ get(key) { try { return localStorage.getItem(key); } catch { return null; } }, /** * Set item in localStorage * @param {string} key - Storage key * @param {string} value - Value to store * @returns {boolean} Success status */ set(key, value) { try { localStorage.setItem(key, value); return true; } catch { return false; } } }; /** * Theme Manager * @namespace */ const Theme = { /** * Apply a theme to the document * Updates Chart.js defaults if available * * @param {('light'|'dark')} theme - Theme to apply * @fires adminator:themeChanged * @returns {boolean} Success status * * @example * Theme.apply('dark'); */ apply(theme) { // Validate theme if (!VALID_THEMES.includes(theme)) { console.warn(`[Adminator] Invalid theme "${theme}". Using "light".`); theme = 'light'; } // Apply to document document.documentElement.setAttribute('data-theme', theme); // Update Chart.js defaults if available if (window.Chart && Chart.defaults) { const isDark = theme === 'dark'; const textColor = isDark ? '#FFFFFF' : '#212529'; const mutedColor = isDark ? '#D1D5DB' : '#6C757D'; const borderColor = isDark ? '#374151' : '#E2E5E8'; const gridColor = isDark ? 'rgba(209, 213, 219, 0.15)' : 'rgba(0, 0, 0, 0.05)'; const tooltipBg = isDark ? '#1F2937' : 'rgba(255, 255, 255, 0.95)'; // Set global defaults Chart.defaults.color = textColor; Chart.defaults.borderColor = borderColor; Chart.defaults.backgroundColor = tooltipBg; // Set plugin defaults Chart.defaults.plugins.legend.labels.color = textColor; Chart.defaults.plugins.tooltip.backgroundColor = tooltipBg; Chart.defaults.plugins.tooltip.titleColor = textColor; Chart.defaults.plugins.tooltip.bodyColor = textColor; Chart.defaults.plugins.tooltip.borderColor = borderColor; // Set scale defaults const scales = ['category', 'linear', 'logarithmic', 'time', 'radialLinear']; scales.forEach(scale => { if (Chart.defaults.scales[scale]) { Chart.defaults.scales[scale].ticks.color = mutedColor; Chart.defaults.scales[scale].grid.color = gridColor; } }); // RadialLinear specific if (Chart.defaults.scales.radialLinear) { Chart.defaults.scales.radialLinear.pointLabels.color = mutedColor; Chart.defaults.scales.radialLinear.angleLines.color = gridColor; } } // Persist to storage Storage.set(THEME_KEY, theme); // Update toggle accessibility state if exists const toggle = document.getElementById('theme-toggle'); if (toggle) { toggle.setAttribute('aria-checked', theme === 'dark' ? 'true' : 'false'); } // Dispatch event for other components window.dispatchEvent(new CustomEvent('adminator:themeChanged', { detail: { theme } })); return true; }, /** * Toggle between light and dark themes * * @returns {('light'|'dark')} The new theme * * @example * const newTheme = Theme.toggle(); * console.log('Switched to:', newTheme); */ toggle() { const next = this.current() === 'dark' ? 'light' : 'dark'; this.apply(next); return next; }, /** * Get the current theme * * @returns {('light'|'dark')} Current theme * * @example * if (Theme.current() === 'dark') { * // Dark mode specific logic * } */ current() { const stored = Storage.get(THEME_KEY); return VALID_THEMES.includes(stored) ? stored : 'light'; }, /** * Initialize the theme system * Detects OS preference on first visit, otherwise uses stored preference * * @returns {('light'|'dark')} The applied theme * * @example * // Call once on app initialization * Theme.init(); */ init() { const stored = Storage.get(THEME_KEY); if (!stored) { // First visit - detect OS preference const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches; const theme = prefersDark ? 'dark' : 'light'; this.apply(theme); return theme; } // Use stored preference this.apply(this.current()); return this.current(); }, /** * Get a CSS variable value from the document * * @param {string} varName - CSS variable name (with or without --) * @returns {string} The CSS variable value * * @example * const bgColor = Theme.getCSSVar('--c-bkg-body'); */ getCSSVar(varName) { const name = varName.startsWith('--') ? varName : `--${varName}`; return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); }, /** * Get theme-aware colors for vector maps * * @returns {Object} Vector map color configuration * @property {string} backgroundColor - Map background color * @property {string} borderColor - Border color * @property {string} regionColor - Default region fill color * @property {string} markerFill - Marker fill color * @property {string} markerStroke - Marker stroke color * @property {string} hoverColor - Region hover color * @property {string} selectedColor - Selected region color * @property {string} scaleStart - Scale gradient start * @property {string} scaleEnd - Scale gradient end */ getVectorMapColors() { return { backgroundColor: this.getCSSVar('--vmap-bg-color'), borderColor: this.getCSSVar('--vmap-border-color'), regionColor: this.getCSSVar('--vmap-region-color'), markerFill: this.getCSSVar('--vmap-marker-fill'), markerStroke: this.getCSSVar('--vmap-marker-stroke'), hoverColor: this.getCSSVar('--vmap-hover-color'), selectedColor: this.getCSSVar('--vmap-selected-color'), scaleStart: this.getCSSVar('--vmap-scale-start'), scaleEnd: this.getCSSVar('--vmap-scale-end'), scaleLight: this.getCSSVar('--vmap-scale-light'), scaleDark: this.getCSSVar('--vmap-scale-dark') }; }, /** * Get theme-aware colors for sparkline charts * * @returns {Object} Sparkline color configuration */ getSparklineColors() { return { success: this.getCSSVar('--sparkline-success'), purple: this.getCSSVar('--sparkline-purple'), info: this.getCSSVar('--sparkline-info'), danger: this.getCSSVar('--sparkline-danger'), light: this.getCSSVar('--sparkline-light') }; }, /** * Get theme-aware colors for Chart.js charts * * @returns {Object} Chart color configuration * @property {string} textColor - Main text color * @property {string} mutedColor - Muted/secondary text color * @property {string} borderColor - Border color * @property {string} gridColor - Grid line color * @property {string} tooltipBg - Tooltip background color */ getChartColors() { const isDark = this.current() === 'dark'; return { textColor: isDark ? '#FFFFFF' : '#212529', mutedColor: isDark ? '#D1D5DB' : '#6C757D', borderColor: isDark ? '#374151' : '#E2E5E8', gridColor: isDark ? 'rgba(209, 213, 219, 0.15)' : 'rgba(0, 0, 0, 0.05)', tooltipBg: isDark ? '#1F2937' : 'rgba(255, 255, 255, 0.95)' }; }, /** * Check if dark mode is currently active * * @returns {boolean} True if dark mode is active * * @example * if (Theme.isDark()) { * // Apply dark-specific styles * } */ isDark() { return this.current() === 'dark'; }, /** * Check if light mode is currently active * * @returns {boolean} True if light mode is active */ isLight() { return this.current() === 'light'; } }; /* harmony default export */ const theme = (Theme); ;// ../assets/scripts/utils/events.js /** * Adminator Event Utilities * Provides efficient event handling with delegation and cleanup * * @module utils/events */ /** * Store for event handlers to enable proper cleanup * @type {WeakMap>>} */ const handlerRegistry = new WeakMap(); /** * Store for AbortControllers to enable easy cleanup * @type {WeakMap} */ const controllerRegistry = new WeakMap(); /** * Event utilities namespace * @namespace */ const Events = { /** * Add an event listener with automatic cleanup support * Uses AbortController for efficient removal * * @param {Element} element - Target element * @param {string} event - Event type * @param {Function} handler - Event handler * @param {Object} [options={}] - Event listener options * @returns {Function} Cleanup function to remove the listener * * @example * const cleanup = Events.on(button, 'click', handleClick); * // Later: cleanup() to remove */ on(element, event, handler) { let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; if (!element) return () => {}; // Get or create AbortController for this element let controller = controllerRegistry.get(element); if (!controller) { controller = new AbortController(); controllerRegistry.set(element, controller); } // Register handler if (!handlerRegistry.has(element)) { handlerRegistry.set(element, new Map()); } const elementHandlers = handlerRegistry.get(element); if (!elementHandlers.has(event)) { elementHandlers.set(event, new Set()); } elementHandlers.get(event).add(handler); // Add listener with abort signal element.addEventListener(event, handler, { ...options, signal: controller.signal }); // Return cleanup function return () => { var _handlerRegistry$get; element.removeEventListener(event, handler, options); const handlers = (_handlerRegistry$get = handlerRegistry.get(element)) === null || _handlerRegistry$get === void 0 ? void 0 : _handlerRegistry$get.get(event); if (handlers) { handlers.delete(handler); } }; }, /** * Remove all event listeners from an element * * @param {Element} element - Target element * * @example * Events.off(element); // Removes all listeners */ off(element) { if (!element) return; const controller = controllerRegistry.get(element); if (controller) { controller.abort(); controllerRegistry.delete(element); } handlerRegistry.delete(element); }, /** * Add event delegation - listen on parent for events from children * More efficient than adding listeners to many elements * * @param {Element} parent - Parent element to listen on * @param {string} event - Event type * @param {string} selector - CSS selector for target elements * @param {Function} handler - Event handler (receives event and matched element) * @param {Object} [options={}] - Event listener options * @returns {Function} Cleanup function * * @example * // Instead of adding click to every .btn * Events.delegate(container, 'click', '.btn', (e, btn) => { * console.log('Button clicked:', btn); * }); */ delegate(parent, event, selector, handler) { let options = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {}; if (!parent) return () => {}; const delegatedHandler = e => { const target = e.target.closest(selector); if (target && parent.contains(target)) { handler.call(target, e, target); } }; return this.on(parent, event, delegatedHandler, options); }, /** * Add a one-time event listener * * @param {Element} element - Target element * @param {string} event - Event type * @param {Function} handler - Event handler * @returns {Function} Cleanup function * * @example * Events.once(button, 'click', handleFirstClick); */ once(element, event, handler) { return this.on(element, event, handler, { once: true }); }, /** * Create a debounced event handler * * @param {Function} handler - Original handler * @param {number} [delay=250] - Debounce delay in ms * @returns {Function} Debounced handler * * @example * const debouncedResize = Events.debounce(handleResize, 200); * window.addEventListener('resize', debouncedResize); */ debounce(handler) { let delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250; let timeoutId; return function debounced() { for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } clearTimeout(timeoutId); timeoutId = setTimeout(() => handler.apply(this, args), delay); }; }, /** * Create a throttled event handler * * @param {Function} handler - Original handler * @param {number} [limit=250] - Throttle limit in ms * @returns {Function} Throttled handler * * @example * const throttledScroll = Events.throttle(handleScroll, 100); * window.addEventListener('scroll', throttledScroll); */ throttle(handler) { let limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 250; let inThrottle; return function throttled() { if (!inThrottle) { for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { args[_key2] = arguments[_key2]; } handler.apply(this, args); inThrottle = true; setTimeout(() => inThrottle = false, limit); } }; }, /** * Dispatch a custom event * * @param {Element|Window} target - Target to dispatch on * @param {string} eventName - Event name * @param {Object} [detail={}] - Event detail data * @param {Object} [options={}] - Event options (bubbles, cancelable) * @returns {boolean} Whether the event was not cancelled * * @example * Events.emit(element, 'custom:event', { data: 'value' }); */ emit(target, eventName) { let detail = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; const event = new CustomEvent(eventName, { detail, bubbles: options.bubbles ?? true, cancelable: options.cancelable ?? true }); return target.dispatchEvent(event); } }; /* harmony default export */ const events = (Events); ;// ../assets/scripts/utils/performance.js /** * Adminator Performance Utilities * Provides ResizeObserver, IntersectionObserver, and lazy loading utilities * * @module utils/performance */ /** * Store for ResizeObserver instances * @type {WeakMap} */ const resizeCallbacks = new WeakMap(); /** * Shared ResizeObserver instance for efficiency * @type {ResizeObserver|null} */ let sharedResizeObserver = null; /** * Store for IntersectionObserver callbacks * @type {WeakMap} */ const intersectionCallbacks = new WeakMap(); /** * Map of IntersectionObservers by threshold * @type {Map} */ const intersectionObservers = new Map(); /** * Performance utilities namespace * @namespace */ const Performance = { /** * Observe element resize events efficiently * Uses shared ResizeObserver for better performance * * @param {Element} element - Element to observe * @param {Function} callback - Callback receiving { width, height, entry } * @returns {Function} Cleanup function to stop observing * * @example * const unobserve = Performance.onResize(chart, ({ width, height }) => { * chart.resize(width, height); * }); */ onResize(element, callback) { if (!element || typeof callback !== 'function') { return () => {}; } // Create shared observer if needed if (!sharedResizeObserver) { sharedResizeObserver = new ResizeObserver(entries => { for (const entry of entries) { const cb = resizeCallbacks.get(entry.target); if (cb) { const { width, height } = entry.contentRect; cb({ width, height, entry }); } } }); } // Store callback and observe resizeCallbacks.set(element, callback); sharedResizeObserver.observe(element); // Return cleanup function return () => { var _sharedResizeObserver; resizeCallbacks.delete(element); (_sharedResizeObserver = sharedResizeObserver) === null || _sharedResizeObserver === void 0 || _sharedResizeObserver.unobserve(element); }; }, /** * Observe when element enters/exits viewport * Useful for lazy loading and animations * * @param {Element} element - Element to observe * @param {Function} callback - Callback receiving { isIntersecting, entry } * @param {Object} [options={}] - IntersectionObserver options * @param {number} [options.threshold=0] - Visibility threshold (0-1) * @param {string} [options.rootMargin='0px'] - Root margin * @returns {Function} Cleanup function to stop observing * * @example * const unobserve = Performance.onVisible(element, ({ isIntersecting }) => { * if (isIntersecting) { * loadContent(); * unobserve(); // Stop after first trigger * } * }); */ onVisible(element, callback) { let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; if (!element || typeof callback !== 'function') { return () => {}; } const { threshold = 0, rootMargin = '0px' } = options; const key = `${threshold}-${rootMargin}`; // Get or create observer for this threshold if (!intersectionObservers.has(key)) { const observer = new IntersectionObserver(entries => { for (const entry of entries) { const cb = intersectionCallbacks.get(entry.target); if (cb) { cb({ isIntersecting: entry.isIntersecting, ratio: entry.intersectionRatio, entry }); } } }, { threshold, rootMargin }); intersectionObservers.set(key, observer); } const observer = intersectionObservers.get(key); // Store callback and observe intersectionCallbacks.set(element, callback); observer.observe(element); // Return cleanup function return () => { intersectionCallbacks.delete(element); observer.unobserve(element); }; }, /** * Lazy load an element when it becomes visible * Automatically handles cleanup after loading * * @param {Element} element - Element to lazy load * @param {Function} loadFn - Function to call when visible * @param {Object} [options={}] - Options * @param {string} [options.rootMargin='100px'] - Preload margin * @returns {Function} Cleanup function * * @example * Performance.lazyLoad(chartContainer, () => { * initializeChart(chartContainer); * }); */ lazyLoad(element, loadFn) { let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; const { rootMargin = '100px' } = options; let loaded = false; const unobserve = this.onVisible(element, _ref => { let { isIntersecting } = _ref; if (isIntersecting && !loaded) { loaded = true; loadFn(); unobserve(); } }, { rootMargin }); return unobserve; }, /** * Batch DOM reads and writes to prevent layout thrashing * * @param {Function} readFn - Function that reads from DOM * @param {Function} writeFn - Function that writes to DOM * * @example * Performance.batch( * () => element.offsetHeight, // Read * (height) => element.style.minHeight = height + 'px' // Write * ); */ batch(readFn, writeFn) { // Use requestAnimationFrame for batching requestAnimationFrame(() => { const value = readFn(); requestAnimationFrame(() => { writeFn(value); }); }); }, /** * Execute callback on next animation frame * * @param {Function} callback - Function to execute * @returns {number} Request ID for cancellation * * @example * const id = Performance.nextFrame(() => updateUI()); * // Cancel: cancelAnimationFrame(id); */ nextFrame(callback) { return requestAnimationFrame(callback); }, /** * Execute callback when browser is idle * Falls back to setTimeout if requestIdleCallback not available * * @param {Function} callback - Function to execute * @param {Object} [options={}] - Options * @param {number} [options.timeout=1000] - Maximum wait time * @returns {number} Request ID for cancellation * * @example * Performance.whenIdle(() => { * // Non-critical work * preloadNextPage(); * }); */ whenIdle(callback) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; const { timeout = 1000 } = options; if ('requestIdleCallback' in window) { return requestIdleCallback(callback, { timeout }); } // Fallback for Safari return setTimeout(callback, 1); }, /** * Cancel an idle callback * * @param {number} id - Request ID from whenIdle */ cancelIdle(id) { if ('cancelIdleCallback' in window) { cancelIdleCallback(id); } else { clearTimeout(id); } }, /** * Preload a resource (image, script, etc.) * * @param {string} url - URL to preload * @param {string} [as='image'] - Resource type (image, script, style, font) * @returns {Promise} Resolves when loaded * * @example * await Performance.preload('/images/hero.jpg', 'image'); */ preload(url) { let as = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'image'; return new Promise((resolve, reject) => { const link = document.createElement('link'); link.rel = 'preload'; link.as = as; link.href = url; link.onload = resolve; link.onerror = reject; document.head.appendChild(link); }); }, /** * Measure execution time of a function * * @param {string} label - Label for the measurement * @param {Function} fn - Function to measure * @returns {*} Return value of the function * * @example * const result = Performance.measure('render', () => renderChart()); */ measure(label, fn) { const start = performance.now(); const result = fn(); const end = performance.now(); if (false) // removed by dead control flow {} return result; }, /** * Cleanup all observers * Call this when destroying the app */ cleanup() { // Cleanup resize observer if (sharedResizeObserver) { sharedResizeObserver.disconnect(); sharedResizeObserver = null; } // Cleanup intersection observers for (const observer of intersectionObservers.values()) { observer.disconnect(); } intersectionObservers.clear(); } }; /* harmony default export */ const utils_performance = (Performance); ;// ../assets/scripts/utils/logger.js /** * Adminator Logger Utility * Development-only logging utility for debugging * * @module utils/logger */ /** * Check if we're in development mode * @returns {boolean} */ const isDev = () => { try { return false || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; } catch { return false; } }; /** * Logger object with development-only output * All methods are no-ops in production for zero overhead */ const Logger = { /** * Log informational messages (development only) * @param {string} message - The message to log * @param {Object} [context] - Additional context data */ info(message, context) { if (isDev()) { console.info(`[Adminator] ${message}`, context || ''); } }, /** * Log warning messages (development only) * @param {string} message - The warning message * @param {Object} [context] - Additional context data */ warn(message, context) { if (isDev()) { console.warn(`[Adminator] ${message}`, context || ''); } }, /** * Log error messages (development only) * @param {string} message - The error message * @param {Error|Object} [context] - Error object or context data */ error(message, context) { if (isDev()) { console.error(`[Adminator] ${message}`, context || ''); } }, /** * Log debug messages (development only) * @param {string} message - The debug message * @param {Object} [context] - Additional context data */ debug(message, context) { if (isDev()) { console.debug(`[Adminator] ${message}`, context || ''); } }, /** * Group related log messages (development only) * @param {string} label - Group label */ group(label) { if (isDev()) { console.group(`[Adminator] ${label}`); } }, /** * End a log group (development only) */ groupEnd() { if (isDev()) { console.groupEnd(); } }, /** * Log with timing information (development only) * @param {string} label - Timer label */ time(label) { if (isDev()) { console.time(`[Adminator] ${label}`); } }, /** * End timing and log result (development only) * @param {string} label - Timer label (must match time() call) */ timeEnd(label) { if (isDev()) { console.timeEnd(`[Adminator] ${label}`); } }, /** * Log a table of data (development only) * @param {Array|Object} data - Data to display as table */ table(data) { if (isDev()) { console.table(data); } } }; /* harmony default export */ const logger = (Logger); ;// ../assets/scripts/components/Sidebar.js /** * Modern Sidebar Component * Replaces jQuery-based sidebar functionality with vanilla JavaScript */ class Sidebar { constructor() { this.sidebar = document.querySelector('.sidebar'); this.sidebarMenu = document.querySelector('.sidebar .sidebar-menu'); this.sidebarToggleLinks = document.querySelectorAll('.sidebar-toggle a'); this.sidebarToggleById = document.querySelector('#sidebar-toggle'); this.app = document.querySelector('.app'); this.init(); } init() { if (!this.sidebar || !this.sidebarMenu) { return; } this.setupMenuToggle(); this.setupSidebarToggle(); this.setActiveLink(); } /** * Setup dropdown menu functionality */ setupMenuToggle() { const menuLinks = this.sidebarMenu.querySelectorAll('li a'); menuLinks.forEach(link => { link.addEventListener('click', e => { const listItem = link.parentElement; const dropdownMenu = listItem.querySelector('.dropdown-menu'); // If this is a regular navigation link (not dropdown), allow normal navigation if (!dropdownMenu) { // Don't prevent default for regular navigation links return; } // Only prevent default for dropdown toggles e.preventDefault(); if (listItem.classList.contains('open')) { this.closeDropdown(listItem, dropdownMenu); } else { this.closeAllDropdowns(); this.openDropdown(listItem, dropdownMenu); } }); }); } /** * Open dropdown with smooth animation */ openDropdown(listItem, dropdownMenu) { listItem.classList.add('open'); dropdownMenu.style.display = 'block'; dropdownMenu.style.height = '0px'; dropdownMenu.style.overflow = 'hidden'; // Get the natural height const height = dropdownMenu.scrollHeight; // Animate to full height dropdownMenu.animate([{ height: '0px' }, { height: `${height}px` }], { duration: 200, easing: 'ease-out' }).onfinish = () => { dropdownMenu.style.height = 'auto'; dropdownMenu.style.overflow = 'visible'; }; } /** * Close dropdown with smooth animation */ closeDropdown(listItem, dropdownMenu) { const height = dropdownMenu.scrollHeight; dropdownMenu.style.height = `${height}px`; dropdownMenu.style.overflow = 'hidden'; dropdownMenu.animate([{ height: `${height}px` }, { height: '0px' }], { duration: 200, easing: 'ease-in' }).onfinish = () => { listItem.classList.remove('open'); dropdownMenu.style.display = 'none'; dropdownMenu.style.height = ''; dropdownMenu.style.overflow = ''; }; } /** * Close all open dropdowns */ closeAllDropdowns() { const openItems = this.sidebarMenu.querySelectorAll('li.open'); openItems.forEach(item => { const dropdownMenu = item.querySelector('.dropdown-menu'); if (dropdownMenu) { this.closeDropdown(item, dropdownMenu); } // Also remove the has-active-child class item.classList.remove('has-active-child'); }); } /** * Setup sidebar toggle functionality */ setupSidebarToggle() { // Handle mobile sidebar toggle links (inside .sidebar-toggle divs) this.sidebarToggleLinks.forEach(link => { if (link && this.app) { link.addEventListener('click', e => { e.preventDefault(); this.toggleSidebar(); }); } }); // Handle the main topbar sidebar toggle if (this.sidebarToggleById && this.app) { this.sidebarToggleById.addEventListener('click', e => { e.preventDefault(); this.toggleSidebar(); }); } } /** * Toggle sidebar and handle resize events properly */ toggleSidebar() { this.app.classList.toggle('is-collapsed'); // Only trigger resize for masonry, but avoid chart redraw issues setTimeout(() => { // Dispatch a custom event instead of generic resize to avoid chart issues window.dispatchEvent(new CustomEvent('sidebar:toggle', { detail: { collapsed: this.app.classList.contains('is-collapsed') } })); // Still trigger resize for masonry but with a specific check if (window.EVENT) { window.dispatchEvent(window.EVENT); } }, 300); } /** * Set active link based on current URL */ setActiveLink() { // Remove active class from all nav items (including dropdown items) const allNavItems = this.sidebar.querySelectorAll('.nav-item'); allNavItems.forEach(item => { item.classList.remove('actived'); }); // Close all dropdowns first this.closeAllDropdowns(); // Get current page filename const currentPath = window.location.pathname; const currentPage = currentPath.split('/').pop() || 'index.html'; // Find and activate the correct nav item const allLinks = this.sidebar.querySelectorAll('a[href]'); allLinks.forEach(link => { const href = link.getAttribute('href'); if (!href || href === 'javascript:void(0);' || href === 'javascript:void(0)') return; // Extract filename from href const linkPage = href.split('/').pop(); if (linkPage === currentPage) { const navItem = link.closest('.nav-item'); if (navItem) { navItem.classList.add('actived'); // If this is inside a dropdown, handle parent dropdown specially const parentDropdown = navItem.closest('.dropdown-menu'); if (parentDropdown) { const parentDropdownItem = parentDropdown.closest('.nav-item.dropdown'); if (parentDropdownItem) { // Open the parent dropdown parentDropdownItem.classList.add('open'); parentDropdown.style.display = 'block'; // Add special styling to indicate parent has active child parentDropdownItem.classList.add('has-active-child'); } } } } }); } /** * Public method to refresh active links (useful for SPA navigation) */ refreshActiveLink() { this.setActiveLink(); } /** * Public method to toggle sidebar programmatically */ toggle() { if (this.app) { this.app.classList.toggle('is-collapsed'); } } /** * Public method to check if sidebar is collapsed */ isCollapsed() { return this.app ? this.app.classList.contains('is-collapsed') : false; } } /* harmony default export */ const components_Sidebar = (Sidebar); ;// ../../node_modules/@kurkle/color/dist/color.esm.js /*! * @kurkle/color v0.3.4 * https://github.com/kurkle/color#readme * (c) 2024 Jukka Kurkela * Released under the MIT License */ function round(v) { return v + 0.5 | 0; } const lim = (v, l, h) => Math.max(Math.min(v, h), l); function p2b(v) { return lim(round(v * 2.55), 0, 255); } function b2p(v) { return lim(round(v / 2.55), 0, 100); } function n2b(v) { return lim(round(v * 255), 0, 255); } function b2n(v) { return lim(round(v / 2.55) / 100, 0, 1); } function n2p(v) { return lim(round(v * 100), 0, 100); } const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15}; const hex = [...'0123456789ABCDEF']; const h1 = b => hex[b & 0xF]; const h2 = b => hex[(b & 0xF0) >> 4] + hex[b & 0xF]; const eq = b => ((b & 0xF0) >> 4) === (b & 0xF); const isShort = v => eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); function hexParse(str) { var len = str.length; var ret; if (str[0] === '#') { if (len === 4 || len === 5) { ret = { r: 255 & map$1[str[1]] * 17, g: 255 & map$1[str[2]] * 17, b: 255 & map$1[str[3]] * 17, a: len === 5 ? map$1[str[4]] * 17 : 255 }; } else if (len === 7 || len === 9) { ret = { r: map$1[str[1]] << 4 | map$1[str[2]], g: map$1[str[3]] << 4 | map$1[str[4]], b: map$1[str[5]] << 4 | map$1[str[6]], a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255 }; } } return ret; } const alpha = (a, f) => a < 255 ? f(a) : ''; function hexString(v) { var f = isShort(v) ? h1 : h2; return v ? '#' + f(v.r) + f(v.g) + f(v.b) + alpha(v.a, f) : undefined; } const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; function hsl2rgbn(h, s, l) { const a = s * Math.min(l, 1 - l); const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); return [f(0), f(8), f(4)]; } function hsv2rgbn(h, s, v) { const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); return [f(5), f(3), f(1)]; } function hwb2rgbn(h, w, b) { const rgb = hsl2rgbn(h, 1, 0.5); let i; if (w + b > 1) { i = 1 / (w + b); w *= i; b *= i; } for (i = 0; i < 3; i++) { rgb[i] *= 1 - w - b; rgb[i] += w; } return rgb; } function hueValue(r, g, b, d, max) { if (r === max) { return ((g - b) / d) + (g < b ? 6 : 0); } if (g === max) { return (b - r) / d + 2; } return (r - g) / d + 4; } function rgb2hsl(v) { const range = 255; const r = v.r / range; const g = v.g / range; const b = v.b / range; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const l = (max + min) / 2; let h, s, d; if (max !== min) { d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); h = hueValue(r, g, b, d, max); h = h * 60 + 0.5; } return [h | 0, s || 0, l]; } function calln(f, a, b, c) { return ( Array.isArray(a) ? f(a[0], a[1], a[2]) : f(a, b, c) ).map(n2b); } function hsl2rgb(h, s, l) { return calln(hsl2rgbn, h, s, l); } function hwb2rgb(h, w, b) { return calln(hwb2rgbn, h, w, b); } function hsv2rgb(h, s, v) { return calln(hsv2rgbn, h, s, v); } function hue(h) { return (h % 360 + 360) % 360; } function hueParse(str) { const m = HUE_RE.exec(str); let a = 255; let v; if (!m) { return; } if (m[5] !== v) { a = m[6] ? p2b(+m[5]) : n2b(+m[5]); } const h = hue(+m[2]); const p1 = +m[3] / 100; const p2 = +m[4] / 100; if (m[1] === 'hwb') { v = hwb2rgb(h, p1, p2); } else if (m[1] === 'hsv') { v = hsv2rgb(h, p1, p2); } else { v = hsl2rgb(h, p1, p2); } return { r: v[0], g: v[1], b: v[2], a: a }; } function rotate(v, deg) { var h = rgb2hsl(v); h[0] = hue(h[0] + deg); h = hsl2rgb(h); v.r = h[0]; v.g = h[1]; v.b = h[2]; } function hslString(v) { if (!v) { return; } const a = rgb2hsl(v); const h = a[0]; const s = n2p(a[1]); const l = n2p(a[2]); return v.a < 255 ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})` : `hsl(${h}, ${s}%, ${l}%)`; } const map = { x: 'dark', Z: 'light', Y: 're', X: 'blu', W: 'gr', V: 'medium', U: 'slate', A: 'ee', T: 'ol', S: 'or', B: 'ra', C: 'lateg', D: 'ights', R: 'in', Q: 'turquois', E: 'hi', P: 'ro', O: 'al', N: 'le', M: 'de', L: 'yello', F: 'en', K: 'ch', G: 'arks', H: 'ea', I: 'ightg', J: 'wh' }; const names$1 = { OiceXe: 'f0f8ff', antiquewEte: 'faebd7', aqua: 'ffff', aquamarRe: '7fffd4', azuY: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '0', blanKedOmond: 'ffebcd', Xe: 'ff', XeviTet: '8a2be2', bPwn: 'a52a2a', burlywood: 'deb887', caMtXe: '5f9ea0', KartYuse: '7fff00', KocTate: 'd2691e', cSO: 'ff7f50', cSnflowerXe: '6495ed', cSnsilk: 'fff8dc', crimson: 'dc143c', cyan: 'ffff', xXe: '8b', xcyan: '8b8b', xgTMnPd: 'b8860b', xWay: 'a9a9a9', xgYF: '6400', xgYy: 'a9a9a9', xkhaki: 'bdb76b', xmagFta: '8b008b', xTivegYF: '556b2f', xSange: 'ff8c00', xScEd: '9932cc', xYd: '8b0000', xsOmon: 'e9967a', xsHgYF: '8fbc8f', xUXe: '483d8b', xUWay: '2f4f4f', xUgYy: '2f4f4f', xQe: 'ced1', xviTet: '9400d3', dAppRk: 'ff1493', dApskyXe: 'bfff', dimWay: '696969', dimgYy: '696969', dodgerXe: '1e90ff', fiYbrick: 'b22222', flSOwEte: 'fffaf0', foYstWAn: '228b22', fuKsia: 'ff00ff', gaRsbSo: 'dcdcdc', ghostwEte: 'f8f8ff', gTd: 'ffd700', gTMnPd: 'daa520', Way: '808080', gYF: '8000', gYFLw: 'adff2f', gYy: '808080', honeyMw: 'f0fff0', hotpRk: 'ff69b4', RdianYd: 'cd5c5c', Rdigo: '4b0082', ivSy: 'fffff0', khaki: 'f0e68c', lavFMr: 'e6e6fa', lavFMrXsh: 'fff0f5', lawngYF: '7cfc00', NmoncEffon: 'fffacd', ZXe: 'add8e6', ZcSO: 'f08080', Zcyan: 'e0ffff', ZgTMnPdLw: 'fafad2', ZWay: 'd3d3d3', ZgYF: '90ee90', ZgYy: 'd3d3d3', ZpRk: 'ffb6c1', ZsOmon: 'ffa07a', ZsHgYF: '20b2aa', ZskyXe: '87cefa', ZUWay: '778899', ZUgYy: '778899', ZstAlXe: 'b0c4de', ZLw: 'ffffe0', lime: 'ff00', limegYF: '32cd32', lRF: 'faf0e6', magFta: 'ff00ff', maPon: '800000', VaquamarRe: '66cdaa', VXe: 'cd', VScEd: 'ba55d3', VpurpN: '9370db', VsHgYF: '3cb371', VUXe: '7b68ee', VsprRggYF: 'fa9a', VQe: '48d1cc', VviTetYd: 'c71585', midnightXe: '191970', mRtcYam: 'f5fffa', mistyPse: 'ffe4e1', moccasR: 'ffe4b5', navajowEte: 'ffdead', navy: '80', Tdlace: 'fdf5e6', Tive: '808000', TivedBb: '6b8e23', Sange: 'ffa500', SangeYd: 'ff4500', ScEd: 'da70d6', pOegTMnPd: 'eee8aa', pOegYF: '98fb98', pOeQe: 'afeeee', pOeviTetYd: 'db7093', papayawEp: 'ffefd5', pHKpuff: 'ffdab9', peru: 'cd853f', pRk: 'ffc0cb', plum: 'dda0dd', powMrXe: 'b0e0e6', purpN: '800080', YbeccapurpN: '663399', Yd: 'ff0000', Psybrown: 'bc8f8f', PyOXe: '4169e1', saddNbPwn: '8b4513', sOmon: 'fa8072', sandybPwn: 'f4a460', sHgYF: '2e8b57', sHshell: 'fff5ee', siFna: 'a0522d', silver: 'c0c0c0', skyXe: '87ceeb', UXe: '6a5acd', UWay: '708090', UgYy: '708090', snow: 'fffafa', sprRggYF: 'ff7f', stAlXe: '4682b4', tan: 'd2b48c', teO: '8080', tEstN: 'd8bfd8', tomato: 'ff6347', Qe: '40e0d0', viTet: 'ee82ee', JHt: 'f5deb3', wEte: 'ffffff', wEtesmoke: 'f5f5f5', Lw: 'ffff00', LwgYF: '9acd32' }; function unpack() { const unpacked = {}; const keys = Object.keys(names$1); const tkeys = Object.keys(map); let i, j, k, ok, nk; for (i = 0; i < keys.length; i++) { ok = nk = keys[i]; for (j = 0; j < tkeys.length; j++) { k = tkeys[j]; nk = nk.replace(k, map[k]); } k = parseInt(names$1[ok], 16); unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; } return unpacked; } let names; function nameParse(str) { if (!names) { names = unpack(); names.transparent = [0, 0, 0, 0]; } const a = names[str.toLowerCase()]; return a && { r: a[0], g: a[1], b: a[2], a: a.length === 4 ? a[3] : 255 }; } const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; function rgbParse(str) { const m = RGB_RE.exec(str); let a = 255; let r, g, b; if (!m) { return; } if (m[7] !== r) { const v = +m[7]; a = m[8] ? p2b(v) : lim(v * 255, 0, 255); } r = +m[1]; g = +m[3]; b = +m[5]; r = 255 & (m[2] ? p2b(r) : lim(r, 0, 255)); g = 255 & (m[4] ? p2b(g) : lim(g, 0, 255)); b = 255 & (m[6] ? p2b(b) : lim(b, 0, 255)); return { r: r, g: g, b: b, a: a }; } function rgbString(v) { return v && ( v.a < 255 ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})` : `rgb(${v.r}, ${v.g}, ${v.b})` ); } const to = v => v <= 0.0031308 ? v * 12.92 : Math.pow(v, 1.0 / 2.4) * 1.055 - 0.055; const from = v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); function interpolate(rgb1, rgb2, t) { const r = from(b2n(rgb1.r)); const g = from(b2n(rgb1.g)); const b = from(b2n(rgb1.b)); return { r: n2b(to(r + t * (from(b2n(rgb2.r)) - r))), g: n2b(to(g + t * (from(b2n(rgb2.g)) - g))), b: n2b(to(b + t * (from(b2n(rgb2.b)) - b))), a: rgb1.a + t * (rgb2.a - rgb1.a) }; } function modHSL(v, i, ratio) { if (v) { let tmp = rgb2hsl(v); tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); tmp = hsl2rgb(tmp); v.r = tmp[0]; v.g = tmp[1]; v.b = tmp[2]; } } function clone(v, proto) { return v ? Object.assign(proto || {}, v) : v; } function fromObject(input) { var v = {r: 0, g: 0, b: 0, a: 255}; if (Array.isArray(input)) { if (input.length >= 3) { v = {r: input[0], g: input[1], b: input[2], a: 255}; if (input.length > 3) { v.a = n2b(input[3]); } } } else { v = clone(input, {r: 0, g: 0, b: 0, a: 1}); v.a = n2b(v.a); } return v; } function functionParse(str) { if (str.charAt(0) === 'r') { return rgbParse(str); } return hueParse(str); } class Color { constructor(input) { if (input instanceof Color) { return input; } const type = typeof input; let v; if (type === 'object') { v = fromObject(input); } else if (type === 'string') { v = hexParse(input) || nameParse(input) || functionParse(input); } this._rgb = v; this._valid = !!v; } get valid() { return this._valid; } get rgb() { var v = clone(this._rgb); if (v) { v.a = b2n(v.a); } return v; } set rgb(obj) { this._rgb = fromObject(obj); } rgbString() { return this._valid ? rgbString(this._rgb) : undefined; } hexString() { return this._valid ? hexString(this._rgb) : undefined; } hslString() { return this._valid ? hslString(this._rgb) : undefined; } mix(color, weight) { if (color) { const c1 = this.rgb; const c2 = color.rgb; let w2; const p = weight === w2 ? 0.5 : weight; const w = 2 * p - 1; const a = c1.a - c2.a; const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; w2 = 1 - w1; c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; c1.a = p * c1.a + (1 - p) * c2.a; this.rgb = c1; } return this; } interpolate(color, t) { if (color) { this._rgb = interpolate(this._rgb, color._rgb, t); } return this; } clone() { return new Color(this.rgb); } alpha(a) { this._rgb.a = n2b(a); return this; } clearer(ratio) { const rgb = this._rgb; rgb.a *= 1 - ratio; return this; } greyscale() { const rgb = this._rgb; const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); rgb.r = rgb.g = rgb.b = val; return this; } opaquer(ratio) { const rgb = this._rgb; rgb.a *= 1 + ratio; return this; } negate() { const v = this._rgb; v.r = 255 - v.r; v.g = 255 - v.g; v.b = 255 - v.b; return this; } lighten(ratio) { modHSL(this._rgb, 2, ratio); return this; } darken(ratio) { modHSL(this._rgb, 2, -ratio); return this; } saturate(ratio) { modHSL(this._rgb, 1, ratio); return this; } desaturate(ratio) { modHSL(this._rgb, 1, -ratio); return this; } rotate(deg) { rotate(this._rgb, deg); return this; } } function index_esm(input) { return new Color(input); } ;// ../../node_modules/chart.js/dist/chunks/helpers.dataset.js /*! * Chart.js v4.5.1 * https://www.chartjs.org * (c) 2025 Chart.js Contributors * Released under the MIT License */ /** * @namespace Chart.helpers */ /** * An empty function that can be used, for example, for optional callback. */ function noop() { /* noop */ } /** * Returns a unique id, sequentially generated from a global variable. */ const uid = (()=>{ let id = 0; return ()=>id++; })(); /** * Returns true if `value` is neither null nor undefined, else returns false. * @param value - The value to test. * @since 2.7.0 */ function isNullOrUndef(value) { return value === null || value === undefined; } /** * Returns true if `value` is an array (including typed arrays), else returns false. * @param value - The value to test. * @function */ function isArray(value) { if (Array.isArray && Array.isArray(value)) { return true; } const type = Object.prototype.toString.call(value); if (type.slice(0, 7) === '[object' && type.slice(-6) === 'Array]') { return true; } return false; } /** * Returns true if `value` is an object (excluding null), else returns false. * @param value - The value to test. * @since 2.7.0 */ function isObject(value) { return value !== null && Object.prototype.toString.call(value) === '[object Object]'; } /** * Returns true if `value` is a finite number, else returns false * @param value - The value to test. */ function isNumberFinite(value) { return (typeof value === 'number' || value instanceof Number) && isFinite(+value); } /** * Returns `value` if finite, else returns `defaultValue`. * @param value - The value to return if defined. * @param defaultValue - The value to return if `value` is not finite. */ function finiteOrDefault(value, defaultValue) { return isNumberFinite(value) ? value : defaultValue; } /** * Returns `value` if defined, else returns `defaultValue`. * @param value - The value to return if defined. * @param defaultValue - The value to return if `value` is undefined. */ function valueOrDefault(value, defaultValue) { return typeof value === 'undefined' ? defaultValue : value; } const toPercentage = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 : +value / dimension; const toDimension = (value, dimension)=>typeof value === 'string' && value.endsWith('%') ? parseFloat(value) / 100 * dimension : +value; /** * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the * value returned by `fn`. If `fn` is not a function, this method returns undefined. * @param fn - The function to call. * @param args - The arguments with which `fn` should be called. * @param [thisArg] - The value of `this` provided for the call to `fn`. */ function callback(fn, args, thisArg) { if (fn && typeof fn.call === 'function') { return fn.apply(thisArg, args); } } function each(loopable, fn, thisArg, reverse) { let i, len, keys; if (isArray(loopable)) { len = loopable.length; if (reverse) { for(i = len - 1; i >= 0; i--){ fn.call(thisArg, loopable[i], i); } } else { for(i = 0; i < len; i++){ fn.call(thisArg, loopable[i], i); } } } else if (isObject(loopable)) { keys = Object.keys(loopable); len = keys.length; for(i = 0; i < len; i++){ fn.call(thisArg, loopable[keys[i]], keys[i]); } } } /** * Returns true if the `a0` and `a1` arrays have the same content, else returns false. * @param a0 - The array to compare * @param a1 - The array to compare * @private */ function _elementsEqual(a0, a1) { let i, ilen, v0, v1; if (!a0 || !a1 || a0.length !== a1.length) { return false; } for(i = 0, ilen = a0.length; i < ilen; ++i){ v0 = a0[i]; v1 = a1[i]; if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { return false; } } return true; } /** * Returns a deep copy of `source` without keeping references on objects and arrays. * @param source - The value to clone. */ function helpers_dataset_clone(source) { if (isArray(source)) { return source.map(helpers_dataset_clone); } if (isObject(source)) { const target = Object.create(null); const keys = Object.keys(source); const klen = keys.length; let k = 0; for(; k < klen; ++k){ target[keys[k]] = helpers_dataset_clone(source[keys[k]]); } return target; } return source; } function isValidKey(key) { return [ '__proto__', 'prototype', 'constructor' ].indexOf(key) === -1; } /** * The default merger when Chart.helpers.merge is called without merger option. * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback. * @private */ function _merger(key, target, source, options) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { // eslint-disable-next-line @typescript-eslint/no-use-before-define merge(tval, sval, options); } else { target[key] = helpers_dataset_clone(sval); } } function merge(target, source, options) { const sources = isArray(source) ? source : [ source ]; const ilen = sources.length; if (!isObject(target)) { return target; } options = options || {}; const merger = options.merger || _merger; let current; for(let i = 0; i < ilen; ++i){ current = sources[i]; if (!isObject(current)) { continue; } const keys = Object.keys(current); for(let k = 0, klen = keys.length; k < klen; ++k){ merger(keys[k], target, current, options); } } return target; } function mergeIf(target, source) { // eslint-disable-next-line @typescript-eslint/no-use-before-define return merge(target, source, { merger: _mergerIf }); } /** * Merges source[key] in target[key] only if target[key] is undefined. * @private */ function _mergerIf(key, target, source) { if (!isValidKey(key)) { return; } const tval = target[key]; const sval = source[key]; if (isObject(tval) && isObject(sval)) { mergeIf(tval, sval); } else if (!Object.prototype.hasOwnProperty.call(target, key)) { target[key] = helpers_dataset_clone(sval); } } /** * @private */ function _deprecated(scope, value, previous, current) { if (value !== undefined) { console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead'); } } // resolveObjectKey resolver cache const keyResolvers = { // Chart.helpers.core resolveObjectKey should resolve empty key to root object '': (v)=>v, // default resolvers x: (o)=>o.x, y: (o)=>o.y }; /** * @private */ function _splitKey(key) { const parts = key.split('.'); const keys = []; let tmp = ''; for (const part of parts){ tmp += part; if (tmp.endsWith('\\')) { tmp = tmp.slice(0, -1) + '.'; } else { keys.push(tmp); tmp = ''; } } return keys; } function _getKeyResolver(key) { const keys = _splitKey(key); return (obj)=>{ for (const k of keys){ if (k === '') { break; } obj = obj && obj[k]; } return obj; }; } function resolveObjectKey(obj, key) { const resolver = keyResolvers[key] || (keyResolvers[key] = _getKeyResolver(key)); return resolver(obj); } /** * @private */ function _capitalize(str) { return str.charAt(0).toUpperCase() + str.slice(1); } const defined = (value)=>typeof value !== 'undefined'; const isFunction = (value)=>typeof value === 'function'; // Adapted from https://stackoverflow.com/questions/31128855/comparing-ecma6-sets-for-equality#31129384 const setsEqual = (a, b)=>{ if (a.size !== b.size) { return false; } for (const item of a){ if (!b.has(item)) { return false; } } return true; }; /** * @param e - The event * @private */ function _isClickEvent(e) { return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu'; } /** * @alias Chart.helpers.math * @namespace */ const PI = Math.PI; const TAU = 2 * PI; const PITAU = TAU + PI; const INFINITY = Number.POSITIVE_INFINITY; const RAD_PER_DEG = PI / 180; const HALF_PI = PI / 2; const QUARTER_PI = PI / 4; const TWO_THIRDS_PI = PI * 2 / 3; const log10 = Math.log10; const sign = Math.sign; function almostEquals(x, y, epsilon) { return Math.abs(x - y) < epsilon; } /** * Implementation of the nice number algorithm used in determining where axis labels will go */ function niceNum(range) { const roundedRange = Math.round(range); range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range; const niceRange = Math.pow(10, Math.floor(log10(range))); const fraction = range / niceRange; const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10; return niceFraction * niceRange; } /** * Returns an array of factors sorted from 1 to sqrt(value) * @private */ function _factorize(value) { const result = []; const sqrt = Math.sqrt(value); let i; for(i = 1; i < sqrt; i++){ if (value % i === 0) { result.push(i); result.push(value / i); } } if (sqrt === (sqrt | 0)) { result.push(sqrt); } result.sort((a, b)=>a - b).pop(); return result; } /** * Verifies that attempting to coerce n to string or number won't throw a TypeError. */ function isNonPrimitive(n) { return typeof n === 'symbol' || typeof n === 'object' && n !== null && !(Symbol.toPrimitive in n || 'toString' in n || 'valueOf' in n); } function isNumber(n) { return !isNonPrimitive(n) && !isNaN(parseFloat(n)) && isFinite(n); } function almostWhole(x, epsilon) { const rounded = Math.round(x); return rounded - epsilon <= x && rounded + epsilon >= x; } /** * @private */ function _setMinAndMaxByKey(array, target, property) { let i, ilen, value; for(i = 0, ilen = array.length; i < ilen; i++){ value = array[i][property]; if (!isNaN(value)) { target.min = Math.min(target.min, value); target.max = Math.max(target.max, value); } } } function toRadians(degrees) { return degrees * (PI / 180); } function toDegrees(radians) { return radians * (180 / PI); } /** * Returns the number of decimal places * i.e. the number of digits after the decimal point, of the value of this Number. * @param x - A number. * @returns The number of decimal places. * @private */ function _decimalPlaces(x) { if (!isNumberFinite(x)) { return; } let e = 1; let p = 0; while(Math.round(x * e) / e !== x){ e *= 10; p++; } return p; } // Gets the angle from vertical upright to the point about a centre. function getAngleFromPoint(centrePoint, anglePoint) { const distanceFromXCenter = anglePoint.x - centrePoint.x; const distanceFromYCenter = anglePoint.y - centrePoint.y; const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); if (angle < -0.5 * PI) { angle += TAU; // make sure the returned angle is in the range of (-PI/2, 3PI/2] } return { angle, distance: radialDistanceFromCenter }; } function distanceBetweenPoints(pt1, pt2) { return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); } /** * Shortest distance between angles, in either direction. * @private */ function _angleDiff(a, b) { return (a - b + PITAU) % TAU - PI; } /** * Normalize angle to be between 0 and 2*PI * @private */ function _normalizeAngle(a) { return (a % TAU + TAU) % TAU; } /** * @private */ function _angleBetween(angle, start, end, sameAngleIsFullCircle) { const a = _normalizeAngle(angle); const s = _normalizeAngle(start); const e = _normalizeAngle(end); const angleToStart = _normalizeAngle(s - a); const angleToEnd = _normalizeAngle(e - a); const startToAngle = _normalizeAngle(a - s); const endToAngle = _normalizeAngle(a - e); return a === s || a === e || sameAngleIsFullCircle && s === e || angleToStart > angleToEnd && startToAngle < endToAngle; } /** * Limit `value` between `min` and `max` * @param value * @param min * @param max * @private */ function _limitValue(value, min, max) { return Math.max(min, Math.min(max, value)); } /** * @param {number} value * @private */ function _int16Range(value) { return _limitValue(value, -32768, 32767); } /** * @param value * @param start * @param end * @param [epsilon] * @private */ function _isBetween(value, start, end, epsilon = 1e-6) { return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon; } function _lookup(table, value, cmp) { cmp = cmp || ((index)=>table[index] < value); let hi = table.length - 1; let lo = 0; let mid; while(hi - lo > 1){ mid = lo + hi >> 1; if (cmp(mid)) { lo = mid; } else { hi = mid; } } return { lo, hi }; } /** * Binary search * @param table - the table search. must be sorted! * @param key - property name for the value in each entry * @param value - value to find * @param last - lookup last index * @private */ const _lookupByKey = (table, key, value, last)=>_lookup(table, value, last ? (index)=>{ const ti = table[index][key]; return ti < value || ti === value && table[index + 1][key] === value; } : (index)=>table[index][key] < value); /** * Reverse binary search * @param table - the table search. must be sorted! * @param key - property name for the value in each entry * @param value - value to find * @private */ const _rlookupByKey = (table, key, value)=>_lookup(table, value, (index)=>table[index][key] >= value); /** * Return subset of `values` between `min` and `max` inclusive. * Values are assumed to be in sorted order. * @param values - sorted array of values * @param min - min value * @param max - max value */ function _filterBetween(values, min, max) { let start = 0; let end = values.length; while(start < end && values[start] < min){ start++; } while(end > start && values[end - 1] > max){ end--; } return start > 0 || end < values.length ? values.slice(start, end) : values; } const arrayEvents = [ 'push', 'pop', 'shift', 'splice', 'unshift' ]; function listenArrayEvents(array, listener) { if (array._chartjs) { array._chartjs.listeners.push(listener); return; } Object.defineProperty(array, '_chartjs', { configurable: true, enumerable: false, value: { listeners: [ listener ] } }); arrayEvents.forEach((key)=>{ const method = '_onData' + _capitalize(key); const base = array[key]; Object.defineProperty(array, key, { configurable: true, enumerable: false, value (...args) { const res = base.apply(this, args); array._chartjs.listeners.forEach((object)=>{ if (typeof object[method] === 'function') { object[method](...args); } }); return res; } }); }); } function unlistenArrayEvents(array, listener) { const stub = array._chartjs; if (!stub) { return; } const listeners = stub.listeners; const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } if (listeners.length > 0) { return; } arrayEvents.forEach((key)=>{ delete array[key]; }); delete array._chartjs; } /** * @param items */ function _arrayUnique(items) { const set = new Set(items); if (set.size === items.length) { return items; } return Array.from(set); } function fontString(pixelSize, fontStyle, fontFamily) { return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; } /** * Request animation polyfill */ const requestAnimFrame = function() { if (typeof window === 'undefined') { return function(callback) { return callback(); }; } return window.requestAnimationFrame; }(); /** * Throttles calling `fn` once per animation frame * Latest arguments are used on the actual call */ function throttled(fn, thisArg) { let argsToUse = []; let ticking = false; return function(...args) { // Save the args for use later argsToUse = args; if (!ticking) { ticking = true; requestAnimFrame.call(window, ()=>{ ticking = false; fn.apply(thisArg, argsToUse); }); } }; } /** * Debounces calling `fn` for `delay` ms */ function debounce(fn, delay) { let timeout; return function(...args) { if (delay) { clearTimeout(timeout); timeout = setTimeout(fn, delay, args); } else { fn.apply(this, args); } return delay; }; } /** * Converts 'start' to 'left', 'end' to 'right' and others to 'center' * @private */ const _toLeftRightCenter = (align)=>align === 'start' ? 'left' : align === 'end' ? 'right' : 'center'; /** * Returns `start`, `end` or `(start + end) / 2` depending on `align`. Defaults to `center` * @private */ const _alignStartEnd = (align, start, end)=>align === 'start' ? start : align === 'end' ? end : (start + end) / 2; /** * Returns `left`, `right` or `(left + right) / 2` depending on `align`. Defaults to `left` * @private */ const _textX = (align, left, right, rtl)=>{ const check = rtl ? 'left' : 'right'; return align === check ? right : align === 'center' ? (left + right) / 2 : left; }; /** * Return start and count of visible points. * @private */ function _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { const pointCount = points.length; let start = 0; let count = pointCount; if (meta._sorted) { const { iScale , vScale , _parsed } = meta; const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null; const axis = iScale.axis; const { min , max , minDefined , maxDefined } = iScale.getUserBounds(); if (minDefined) { start = Math.min(// @ts-expect-error Need to type _parsed _lookupByKey(_parsed, axis, min).lo, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo); if (spanGaps) { const distanceToDefinedLo = _parsed.slice(0, start + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis])); start -= Math.max(0, distanceToDefinedLo); } start = _limitValue(start, 0, pointCount - 1); } if (maxDefined) { let end = Math.max(// @ts-expect-error Need to type _parsed _lookupByKey(_parsed, iScale.axis, max, true).hi + 1, // @ts-expect-error Need to fix types on _lookupByKey animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1); if (spanGaps) { const distanceToDefinedHi = _parsed.slice(end - 1).findIndex((point)=>!isNullOrUndef(point[vScale.axis])); end += Math.max(0, distanceToDefinedHi); } count = _limitValue(end, start, pointCount) - start; } else { count = pointCount - start; } } return { start, count }; } /** * Checks if the scale ranges have changed. * @param {object} meta - dataset meta. * @returns {boolean} * @private */ function _scaleRangesChanged(meta) { const { xScale , yScale , _scaleRanges } = meta; const newRanges = { xmin: xScale.min, xmax: xScale.max, ymin: yScale.min, ymax: yScale.max }; if (!_scaleRanges) { meta._scaleRanges = newRanges; return true; } const changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max; Object.assign(_scaleRanges, newRanges); return changed; } const atEdge = (t)=>t === 0 || t === 1; const elasticIn = (t, s, p)=>-(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p)); const elasticOut = (t, s, p)=>Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1; /** * Easing functions adapted from Robert Penner's easing equations. * @namespace Chart.helpers.easing.effects * @see http://www.robertpenner.com/easing/ */ const effects = { linear: (t)=>t, easeInQuad: (t)=>t * t, easeOutQuad: (t)=>-t * (t - 2), easeInOutQuad: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t : -0.5 * (--t * (t - 2) - 1), easeInCubic: (t)=>t * t * t, easeOutCubic: (t)=>(t -= 1) * t * t + 1, easeInOutCubic: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t : 0.5 * ((t -= 2) * t * t + 2), easeInQuart: (t)=>t * t * t * t, easeOutQuart: (t)=>-((t -= 1) * t * t * t - 1), easeInOutQuart: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t : -0.5 * ((t -= 2) * t * t * t - 2), easeInQuint: (t)=>t * t * t * t * t, easeOutQuint: (t)=>(t -= 1) * t * t * t * t + 1, easeInOutQuint: (t)=>(t /= 0.5) < 1 ? 0.5 * t * t * t * t * t : 0.5 * ((t -= 2) * t * t * t * t + 2), easeInSine: (t)=>-Math.cos(t * HALF_PI) + 1, easeOutSine: (t)=>Math.sin(t * HALF_PI), easeInOutSine: (t)=>-0.5 * (Math.cos(PI * t) - 1), easeInExpo: (t)=>t === 0 ? 0 : Math.pow(2, 10 * (t - 1)), easeOutExpo: (t)=>t === 1 ? 1 : -Math.pow(2, -10 * t) + 1, easeInOutExpo: (t)=>atEdge(t) ? t : t < 0.5 ? 0.5 * Math.pow(2, 10 * (t * 2 - 1)) : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2), easeInCirc: (t)=>t >= 1 ? t : -(Math.sqrt(1 - t * t) - 1), easeOutCirc: (t)=>Math.sqrt(1 - (t -= 1) * t), easeInOutCirc: (t)=>(t /= 0.5) < 1 ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1), easeInElastic: (t)=>atEdge(t) ? t : elasticIn(t, 0.075, 0.3), easeOutElastic: (t)=>atEdge(t) ? t : elasticOut(t, 0.075, 0.3), easeInOutElastic (t) { const s = 0.1125; const p = 0.45; return atEdge(t) ? t : t < 0.5 ? 0.5 * elasticIn(t * 2, s, p) : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p); }, easeInBack (t) { const s = 1.70158; return t * t * ((s + 1) * t - s); }, easeOutBack (t) { const s = 1.70158; return (t -= 1) * t * ((s + 1) * t + s) + 1; }, easeInOutBack (t) { let s = 1.70158; if ((t /= 0.5) < 1) { return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s)); } return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2); }, easeInBounce: (t)=>1 - effects.easeOutBounce(1 - t), easeOutBounce (t) { const m = 7.5625; const d = 2.75; if (t < 1 / d) { return m * t * t; } if (t < 2 / d) { return m * (t -= 1.5 / d) * t + 0.75; } if (t < 2.5 / d) { return m * (t -= 2.25 / d) * t + 0.9375; } return m * (t -= 2.625 / d) * t + 0.984375; }, easeInOutBounce: (t)=>t < 0.5 ? effects.easeInBounce(t * 2) * 0.5 : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5 }; function isPatternOrGradient(value) { if (value && typeof value === 'object') { const type = value.toString(); return type === '[object CanvasPattern]' || type === '[object CanvasGradient]'; } return false; } function color(value) { return isPatternOrGradient(value) ? value : new Color(value); } function getHoverColor(value) { return isPatternOrGradient(value) ? value : new Color(value).saturate(0.5).darken(0.1).hexString(); } const numbers = [ 'x', 'y', 'borderWidth', 'radius', 'tension' ]; const colors = [ 'color', 'borderColor', 'backgroundColor' ]; function applyAnimationsDefaults(defaults) { defaults.set('animation', { delay: undefined, duration: 1000, easing: 'easeOutQuart', fn: undefined, from: undefined, loop: undefined, to: undefined, type: undefined }); defaults.describe('animation', { _fallback: false, _indexable: false, _scriptable: (name)=>name !== 'onProgress' && name !== 'onComplete' && name !== 'fn' }); defaults.set('animations', { colors: { type: 'color', properties: colors }, numbers: { type: 'number', properties: numbers } }); defaults.describe('animations', { _fallback: 'animation' }); defaults.set('transitions', { active: { animation: { duration: 400 } }, resize: { animation: { duration: 0 } }, show: { animations: { colors: { from: 'transparent' }, visible: { type: 'boolean', duration: 0 } } }, hide: { animations: { colors: { to: 'transparent' }, visible: { type: 'boolean', easing: 'linear', fn: (v)=>v | 0 } } } }); } function applyLayoutsDefaults(defaults) { defaults.set('layout', { autoPadding: true, padding: { top: 0, right: 0, bottom: 0, left: 0 } }); } const intlCache = new Map(); function getNumberFormat(locale, options) { options = options || {}; const cacheKey = locale + JSON.stringify(options); let formatter = intlCache.get(cacheKey); if (!formatter) { formatter = new Intl.NumberFormat(locale, options); intlCache.set(cacheKey, formatter); } return formatter; } function formatNumber(num, locale, options) { return getNumberFormat(locale, options).format(num); } const formatters = { values (value) { return isArray(value) ? value : '' + value; }, numeric (tickValue, index, ticks) { if (tickValue === 0) { return '0'; } const locale = this.chart.options.locale; let notation; let delta = tickValue; if (ticks.length > 1) { const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); if (maxTick < 1e-4 || maxTick > 1e+15) { notation = 'scientific'; } delta = calculateDelta(tickValue, ticks); } const logDelta = log10(Math.abs(delta)); const numDecimal = isNaN(logDelta) ? 1 : Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); const options = { notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal }; Object.assign(options, this.options.ticks.format); return formatNumber(tickValue, locale, options); }, logarithmic (tickValue, index, ticks) { if (tickValue === 0) { return '0'; } const remain = ticks[index].significand || tickValue / Math.pow(10, Math.floor(log10(tickValue))); if ([ 1, 2, 3, 5, 10, 15 ].includes(remain) || index > 0.8 * ticks.length) { return formatters.numeric.call(this, tickValue, index, ticks); } return ''; } }; function calculateDelta(tickValue, ticks) { let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) { delta = tickValue - Math.floor(tickValue); } return delta; } var Ticks = { formatters }; function applyScaleDefaults(defaults) { defaults.set('scale', { display: true, offset: false, reverse: false, beginAtZero: false, bounds: 'ticks', clip: true, grace: 0, grid: { display: true, lineWidth: 1, drawOnChartArea: true, drawTicks: true, tickLength: 8, tickWidth: (_ctx, options)=>options.lineWidth, tickColor: (_ctx, options)=>options.color, offset: false }, border: { display: true, dash: [], dashOffset: 0.0, width: 1 }, title: { display: false, text: '', padding: { top: 4, bottom: 4 } }, ticks: { minRotation: 0, maxRotation: 50, mirror: false, textStrokeWidth: 0, textStrokeColor: '', padding: 3, display: true, autoSkip: true, autoSkipPadding: 3, labelOffset: 0, callback: Ticks.formatters.values, minor: {}, major: {}, align: 'center', crossAlign: 'near', showLabelBackdrop: false, backdropColor: 'rgba(255, 255, 255, 0.75)', backdropPadding: 2 } }); defaults.route('scale.ticks', 'color', '', 'color'); defaults.route('scale.grid', 'color', '', 'borderColor'); defaults.route('scale.border', 'color', '', 'borderColor'); defaults.route('scale.title', 'color', '', 'color'); defaults.describe('scale', { _fallback: false, _scriptable: (name)=>!name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser', _indexable: (name)=>name !== 'borderDash' && name !== 'tickBorderDash' && name !== 'dash' }); defaults.describe('scales', { _fallback: 'scale' }); defaults.describe('scale.ticks', { _scriptable: (name)=>name !== 'backdropPadding' && name !== 'callback', _indexable: (name)=>name !== 'backdropPadding' }); } const overrides = Object.create(null); const descriptors = Object.create(null); function getScope$1(node, key) { if (!key) { return node; } const keys = key.split('.'); for(let i = 0, n = keys.length; i < n; ++i){ const k = keys[i]; node = node[k] || (node[k] = Object.create(null)); } return node; } function set(root, scope, values) { if (typeof scope === 'string') { return merge(getScope$1(root, scope), values); } return merge(getScope$1(root, ''), scope); } class Defaults { constructor(_descriptors, _appliers){ this.animation = undefined; this.backgroundColor = 'rgba(0,0,0,0.1)'; this.borderColor = 'rgba(0,0,0,0.1)'; this.color = '#666'; this.datasets = {}; this.devicePixelRatio = (context)=>context.chart.platform.getDevicePixelRatio(); this.elements = {}; this.events = [ 'mousemove', 'mouseout', 'click', 'touchstart', 'touchmove' ]; this.font = { family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", size: 12, style: 'normal', lineHeight: 1.2, weight: null }; this.hover = {}; this.hoverBackgroundColor = (ctx, options)=>getHoverColor(options.backgroundColor); this.hoverBorderColor = (ctx, options)=>getHoverColor(options.borderColor); this.hoverColor = (ctx, options)=>getHoverColor(options.color); this.indexAxis = 'x'; this.interaction = { mode: 'nearest', intersect: true, includeInvisible: false }; this.maintainAspectRatio = true; this.onHover = null; this.onClick = null; this.parsing = true; this.plugins = {}; this.responsive = true; this.scale = undefined; this.scales = {}; this.showLine = true; this.drawActiveElementsOnTop = true; this.describe(_descriptors); this.apply(_appliers); } set(scope, values) { return set(this, scope, values); } get(scope) { return getScope$1(this, scope); } describe(scope, values) { return set(descriptors, scope, values); } override(scope, values) { return set(overrides, scope, values); } route(scope, name, targetScope, targetName) { const scopeObject = getScope$1(this, scope); const targetScopeObject = getScope$1(this, targetScope); const privateName = '_' + name; Object.defineProperties(scopeObject, { [privateName]: { value: scopeObject[name], writable: true }, [name]: { enumerable: true, get () { const local = this[privateName]; const target = targetScopeObject[targetName]; if (isObject(local)) { return Object.assign({}, target, local); } return valueOrDefault(local, target); }, set (value) { this[privateName] = value; } } }); } apply(appliers) { appliers.forEach((apply)=>apply(this)); } } var defaults = /* #__PURE__ */ new Defaults({ _scriptable: (name)=>!name.startsWith('on'), _indexable: (name)=>name !== 'events', hover: { _fallback: 'interaction' }, interaction: { _scriptable: false, _indexable: false } }, [ applyAnimationsDefaults, applyLayoutsDefaults, applyScaleDefaults ]); /** * Converts the given font object into a CSS font string. * @param font - A font object. * @return The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font * @private */ function toFontString(font) { if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { return null; } return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family; } /** * @private */ function _measureText(ctx, data, gc, longest, string) { let textWidth = data[string]; if (!textWidth) { textWidth = data[string] = ctx.measureText(string).width; gc.push(string); } if (textWidth > longest) { longest = textWidth; } return longest; } /** * @private */ // eslint-disable-next-line complexity function _longestText(ctx, font, arrayOfThings, cache) { cache = cache || {}; let data = cache.data = cache.data || {}; let gc = cache.garbageCollect = cache.garbageCollect || []; if (cache.font !== font) { data = cache.data = {}; gc = cache.garbageCollect = []; cache.font = font; } ctx.save(); ctx.font = font; let longest = 0; const ilen = arrayOfThings.length; let i, j, jlen, thing, nestedThing; for(i = 0; i < ilen; i++){ thing = arrayOfThings[i]; // Undefined strings and arrays should not be measured if (thing !== undefined && thing !== null && !isArray(thing)) { longest = _measureText(ctx, data, gc, longest, thing); } else if (isArray(thing)) { // if it is an array lets measure each element // to do maybe simplify this function a bit so we can do this more recursively? for(j = 0, jlen = thing.length; j < jlen; j++){ nestedThing = thing[j]; // Undefined strings and arrays should not be measured if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { longest = _measureText(ctx, data, gc, longest, nestedThing); } } } } ctx.restore(); const gcLen = gc.length / 2; if (gcLen > arrayOfThings.length) { for(i = 0; i < gcLen; i++){ delete data[gc[i]]; } gc.splice(0, gcLen); } return longest; } /** * Returns the aligned pixel value to avoid anti-aliasing blur * @param chart - The chart instance. * @param pixel - A pixel value. * @param width - The width of the element. * @returns The aligned pixel value. * @private */ function _alignPixel(chart, pixel, width) { const devicePixelRatio = chart.currentDevicePixelRatio; const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0; return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; } /** * Clears the entire canvas. */ function clearCanvas(canvas, ctx) { if (!ctx && !canvas) { return; } ctx = ctx || canvas.getContext('2d'); ctx.save(); // canvas.width and canvas.height do not consider the canvas transform, // while clearRect does ctx.resetTransform(); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.restore(); } function drawPoint(ctx, options, x, y) { // eslint-disable-next-line @typescript-eslint/no-use-before-define drawPointLegend(ctx, options, x, y, null); } // eslint-disable-next-line complexity function drawPointLegend(ctx, options, x, y, w) { let type, xOffset, yOffset, size, cornerRadius, width, xOffsetW, yOffsetW; const style = options.pointStyle; const rotation = options.rotation; const radius = options.radius; let rad = (rotation || 0) * RAD_PER_DEG; if (style && typeof style === 'object') { type = style.toString(); if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { ctx.save(); ctx.translate(x, y); ctx.rotate(rad); ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); ctx.restore(); return; } } if (isNaN(radius) || radius <= 0) { return; } ctx.beginPath(); switch(style){ // Default includes circle default: if (w) { ctx.ellipse(x, y, w / 2, radius, 0, 0, TAU); } else { ctx.arc(x, y, radius, 0, TAU); } ctx.closePath(); break; case 'triangle': width = w ? w / 2 : radius; ctx.moveTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); rad += TWO_THIRDS_PI; ctx.lineTo(x + Math.sin(rad) * width, y - Math.cos(rad) * radius); ctx.closePath(); break; case 'rectRounded': // NOTE: the rounded rect implementation changed to use `arc` instead of // `quadraticCurveTo` since it generates better results when rect is // almost a circle. 0.516 (instead of 0.5) produces results with visually // closer proportion to the previous impl and it is inscribed in the // circle with `radius`. For more details, see the following PRs: // https://github.com/chartjs/Chart.js/issues/5597 // https://github.com/chartjs/Chart.js/issues/5858 cornerRadius = radius * 0.516; size = radius - cornerRadius; xOffset = Math.cos(rad + QUARTER_PI) * size; xOffsetW = Math.cos(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); yOffset = Math.sin(rad + QUARTER_PI) * size; yOffsetW = Math.sin(rad + QUARTER_PI) * (w ? w / 2 - cornerRadius : size); ctx.arc(x - xOffsetW, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); ctx.arc(x + yOffsetW, y - xOffset, cornerRadius, rad - HALF_PI, rad); ctx.arc(x + xOffsetW, y + yOffset, cornerRadius, rad, rad + HALF_PI); ctx.arc(x - yOffsetW, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); ctx.closePath(); break; case 'rect': if (!rotation) { size = Math.SQRT1_2 * radius; width = w ? w / 2 : size; ctx.rect(x - width, y - size, 2 * width, 2 * size); break; } rad += QUARTER_PI; /* falls through */ case 'rectRot': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + yOffsetW, y - xOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.lineTo(x - yOffsetW, y + xOffset); ctx.closePath(); break; case 'crossRot': rad += QUARTER_PI; /* falls through */ case 'cross': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'star': xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); rad += QUARTER_PI; xOffsetW = Math.cos(rad) * (w ? w / 2 : radius); xOffset = Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; yOffsetW = Math.sin(rad) * (w ? w / 2 : radius); ctx.moveTo(x - xOffsetW, y - yOffset); ctx.lineTo(x + xOffsetW, y + yOffset); ctx.moveTo(x + yOffsetW, y - xOffset); ctx.lineTo(x - yOffsetW, y + xOffset); break; case 'line': xOffset = w ? w / 2 : Math.cos(rad) * radius; yOffset = Math.sin(rad) * radius; ctx.moveTo(x - xOffset, y - yOffset); ctx.lineTo(x + xOffset, y + yOffset); break; case 'dash': ctx.moveTo(x, y); ctx.lineTo(x + Math.cos(rad) * (w ? w / 2 : radius), y + Math.sin(rad) * radius); break; case false: ctx.closePath(); break; } ctx.fill(); if (options.borderWidth > 0) { ctx.stroke(); } } /** * Returns true if the point is inside the rectangle * @param point - The point to test * @param area - The rectangle * @param margin - allowed margin * @private */ function _isPointInArea(point, area, margin) { margin = margin || 0.5; // margin - default is to match rounded decimals return !area || point && point.x > area.left - margin && point.x < area.right + margin && point.y > area.top - margin && point.y < area.bottom + margin; } function clipArea(ctx, area) { ctx.save(); ctx.beginPath(); ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); ctx.clip(); } function unclipArea(ctx) { ctx.restore(); } /** * @private */ function _steppedLineTo(ctx, previous, target, flip, mode) { if (!previous) { return ctx.lineTo(target.x, target.y); } if (mode === 'middle') { const midpoint = (previous.x + target.x) / 2.0; ctx.lineTo(midpoint, previous.y); ctx.lineTo(midpoint, target.y); } else if (mode === 'after' !== !!flip) { ctx.lineTo(previous.x, target.y); } else { ctx.lineTo(target.x, previous.y); } ctx.lineTo(target.x, target.y); } /** * @private */ function _bezierCurveTo(ctx, previous, target, flip) { if (!previous) { return ctx.lineTo(target.x, target.y); } ctx.bezierCurveTo(flip ? previous.cp1x : previous.cp2x, flip ? previous.cp1y : previous.cp2y, flip ? target.cp2x : target.cp1x, flip ? target.cp2y : target.cp1y, target.x, target.y); } function setRenderOpts(ctx, opts) { if (opts.translation) { ctx.translate(opts.translation[0], opts.translation[1]); } if (!isNullOrUndef(opts.rotation)) { ctx.rotate(opts.rotation); } if (opts.color) { ctx.fillStyle = opts.color; } if (opts.textAlign) { ctx.textAlign = opts.textAlign; } if (opts.textBaseline) { ctx.textBaseline = opts.textBaseline; } } function decorateText(ctx, x, y, line, opts) { if (opts.strikethrough || opts.underline) { /** * Now that IE11 support has been dropped, we can use more * of the TextMetrics object. The actual bounding boxes * are unflagged in Chrome, Firefox, Edge, and Safari so they * can be safely used. * See https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics#Browser_compatibility */ const metrics = ctx.measureText(line); const left = x - metrics.actualBoundingBoxLeft; const right = x + metrics.actualBoundingBoxRight; const top = y - metrics.actualBoundingBoxAscent; const bottom = y + metrics.actualBoundingBoxDescent; const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom; ctx.strokeStyle = ctx.fillStyle; ctx.beginPath(); ctx.lineWidth = opts.decorationWidth || 2; ctx.moveTo(left, yDecoration); ctx.lineTo(right, yDecoration); ctx.stroke(); } } function drawBackdrop(ctx, opts) { const oldColor = ctx.fillStyle; ctx.fillStyle = opts.color; ctx.fillRect(opts.left, opts.top, opts.width, opts.height); ctx.fillStyle = oldColor; } /** * Render text onto the canvas */ function renderText(ctx, text, x, y, font, opts = {}) { const lines = isArray(text) ? text : [ text ]; const stroke = opts.strokeWidth > 0 && opts.strokeColor !== ''; let i, line; ctx.save(); ctx.font = font.string; setRenderOpts(ctx, opts); for(i = 0; i < lines.length; ++i){ line = lines[i]; if (opts.backdrop) { drawBackdrop(ctx, opts.backdrop); } if (stroke) { if (opts.strokeColor) { ctx.strokeStyle = opts.strokeColor; } if (!isNullOrUndef(opts.strokeWidth)) { ctx.lineWidth = opts.strokeWidth; } ctx.strokeText(line, x, y, opts.maxWidth); } ctx.fillText(line, x, y, opts.maxWidth); decorateText(ctx, x, y, line, opts); y += Number(font.lineHeight); } ctx.restore(); } /** * Add a path of a rectangle with rounded corners to the current sub-path * @param ctx - Context * @param rect - Bounding rect */ function addRoundedRectPath(ctx, rect) { const { x , y , w , h , radius } = rect; // top left arc ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, 1.5 * PI, PI, true); // line from top left to bottom left ctx.lineTo(x, y + h - radius.bottomLeft); // bottom left arc ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true); // line from bottom left to bottom right ctx.lineTo(x + w - radius.bottomRight, y + h); // bottom right arc ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true); // line from bottom right to top right ctx.lineTo(x + w, y + radius.topRight); // top right arc ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true); // line from top right to top left ctx.lineTo(x + radius.topLeft, y); } const LINE_HEIGHT = /^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/; const FONT_STYLE = /^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/; /** * @alias Chart.helpers.options * @namespace */ /** * Converts the given line height `value` in pixels for a specific font `size`. * @param value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em'). * @param size - The font size (in pixels) used to resolve relative `value`. * @returns The effective line height in pixels (size * 1.2 if value is invalid). * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height * @since 2.7.0 */ function toLineHeight(value, size) { const matches = ('' + value).match(LINE_HEIGHT); if (!matches || matches[1] === 'normal') { return size * 1.2; } value = +matches[2]; switch(matches[3]){ case 'px': return value; case '%': value /= 100; break; } return size * value; } const numberOrZero = (v)=>+v || 0; function _readValueToProps(value, props) { const ret = {}; const objProps = isObject(props); const keys = objProps ? Object.keys(props) : props; const read = isObject(value) ? objProps ? (prop)=>valueOrDefault(value[prop], value[props[prop]]) : (prop)=>value[prop] : ()=>value; for (const prop of keys){ ret[prop] = numberOrZero(read(prop)); } return ret; } /** * Converts the given value into a TRBL object. * @param value - If a number, set the value to all TRBL component, * else, if an object, use defined properties and sets undefined ones to 0. * x / y are shorthands for same value for left/right and top/bottom. * @returns The padding values (top, right, bottom, left) * @since 3.0.0 */ function toTRBL(value) { return _readValueToProps(value, { top: 'y', right: 'x', bottom: 'y', left: 'x' }); } /** * Converts the given value into a TRBL corners object (similar with css border-radius). * @param value - If a number, set the value to all TRBL corner components, * else, if an object, use defined properties and sets undefined ones to 0. * @returns The TRBL corner values (topLeft, topRight, bottomLeft, bottomRight) * @since 3.0.0 */ function toTRBLCorners(value) { return _readValueToProps(value, [ 'topLeft', 'topRight', 'bottomLeft', 'bottomRight' ]); } /** * Converts the given value into a padding object with pre-computed width/height. * @param value - If a number, set the value to all TRBL component, * else, if an object, use defined properties and sets undefined ones to 0. * x / y are shorthands for same value for left/right and top/bottom. * @returns The padding values (top, right, bottom, left, width, height) * @since 2.7.0 */ function toPadding(value) { const obj = toTRBL(value); obj.width = obj.left + obj.right; obj.height = obj.top + obj.bottom; return obj; } /** * Parses font options and returns the font object. * @param options - A object that contains font options to be parsed. * @param fallback - A object that contains fallback font options. * @return The font object. * @private */ function toFont(options, fallback) { options = options || {}; fallback = fallback || defaults.font; let size = valueOrDefault(options.size, fallback.size); if (typeof size === 'string') { size = parseInt(size, 10); } let style = valueOrDefault(options.style, fallback.style); if (style && !('' + style).match(FONT_STYLE)) { console.warn('Invalid font style specified: "' + style + '"'); style = undefined; } const font = { family: valueOrDefault(options.family, fallback.family), lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), size, style, weight: valueOrDefault(options.weight, fallback.weight), string: '' }; font.string = toFontString(font); return font; } /** * Evaluates the given `inputs` sequentially and returns the first defined value. * @param inputs - An array of values, falling back to the last value. * @param context - If defined and the current value is a function, the value * is called with `context` as first argument and the result becomes the new input. * @param index - If defined and the current value is an array, the value * at `index` become the new input. * @param info - object to return information about resolution in * @param info.cacheable - Will be set to `false` if option is not cacheable. * @since 2.7.0 */ function resolve(inputs, context, index, info) { let cacheable = true; let i, ilen, value; for(i = 0, ilen = inputs.length; i < ilen; ++i){ value = inputs[i]; if (value === undefined) { continue; } if (context !== undefined && typeof value === 'function') { value = value(context); cacheable = false; } if (index !== undefined && isArray(value)) { value = value[index % value.length]; cacheable = false; } if (value !== undefined) { if (info && !cacheable) { info.cacheable = false; } return value; } } } /** * @param minmax * @param grace * @param beginAtZero * @private */ function _addGrace(minmax, grace, beginAtZero) { const { min , max } = minmax; const change = toDimension(grace, (max - min) / 2); const keepZero = (value, add)=>beginAtZero && value === 0 ? 0 : value + add; return { min: keepZero(min, -Math.abs(change)), max: keepZero(max, change) }; } function createContext(parentContext, context) { return Object.assign(Object.create(parentContext), context); } /** * Creates a Proxy for resolving raw values for options. * @param scopes - The option scopes to look for values, in resolution order * @param prefixes - The prefixes for values, in resolution order. * @param rootScopes - The root option scopes * @param fallback - Parent scopes fallback * @param getTarget - callback for getting the target for changed values * @returns Proxy * @private */ function _createResolver(scopes, prefixes = [ '' ], rootScopes, fallback, getTarget = ()=>scopes[0]) { const finalRootScopes = rootScopes || scopes; if (typeof fallback === 'undefined') { fallback = _resolve('_fallback', scopes); } const cache = { [Symbol.toStringTag]: 'Object', _cacheable: true, _scopes: scopes, _rootScopes: finalRootScopes, _fallback: fallback, _getTarget: getTarget, override: (scope)=>_createResolver([ scope, ...scopes ], prefixes, finalRootScopes, fallback) }; return new Proxy(cache, { /** * A trap for the delete operator. */ deleteProperty (target, prop) { delete target[prop]; // remove from cache delete target._keys; // remove cached keys delete scopes[0][prop]; // remove from top level scope return true; }, /** * A trap for getting property values. */ get (target, prop) { return _cached(target, prop, ()=>_resolveWithPrefixes(prop, prefixes, scopes, target)); }, /** * A trap for Object.getOwnPropertyDescriptor. * Also used by Object.hasOwnProperty. */ getOwnPropertyDescriptor (target, prop) { return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop); }, /** * A trap for Object.getPrototypeOf. */ getPrototypeOf () { return Reflect.getPrototypeOf(scopes[0]); }, /** * A trap for the in operator. */ has (target, prop) { return getKeysFromAllScopes(target).includes(prop); }, /** * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols. */ ownKeys (target) { return getKeysFromAllScopes(target); }, /** * A trap for setting property values. */ set (target, prop, value) { const storage = target._storage || (target._storage = getTarget()); target[prop] = storage[prop] = value; // set to top level scope + cache delete target._keys; // remove cached keys return true; } }); } /** * Returns an Proxy for resolving option values with context. * @param proxy - The Proxy returned by `_createResolver` * @param context - Context object for scriptable/indexable options * @param subProxy - The proxy provided for scriptable options * @param descriptorDefaults - Defaults for descriptors * @private */ function _attachContext(proxy, context, subProxy, descriptorDefaults) { const cache = { _cacheable: false, _proxy: proxy, _context: context, _subProxy: subProxy, _stack: new Set(), _descriptors: _descriptors(proxy, descriptorDefaults), setContext: (ctx)=>_attachContext(proxy, ctx, subProxy, descriptorDefaults), override: (scope)=>_attachContext(proxy.override(scope), context, subProxy, descriptorDefaults) }; return new Proxy(cache, { /** * A trap for the delete operator. */ deleteProperty (target, prop) { delete target[prop]; // remove from cache delete proxy[prop]; // remove from proxy return true; }, /** * A trap for getting property values. */ get (target, prop, receiver) { return _cached(target, prop, ()=>_resolveWithContext(target, prop, receiver)); }, /** * A trap for Object.getOwnPropertyDescriptor. * Also used by Object.hasOwnProperty. */ getOwnPropertyDescriptor (target, prop) { return target._descriptors.allKeys ? Reflect.has(proxy, prop) ? { enumerable: true, configurable: true } : undefined : Reflect.getOwnPropertyDescriptor(proxy, prop); }, /** * A trap for Object.getPrototypeOf. */ getPrototypeOf () { return Reflect.getPrototypeOf(proxy); }, /** * A trap for the in operator. */ has (target, prop) { return Reflect.has(proxy, prop); }, /** * A trap for Object.getOwnPropertyNames and Object.getOwnPropertySymbols. */ ownKeys () { return Reflect.ownKeys(proxy); }, /** * A trap for setting property values. */ set (target, prop, value) { proxy[prop] = value; // set to proxy delete target[prop]; // remove from cache return true; } }); } /** * @private */ function _descriptors(proxy, defaults = { scriptable: true, indexable: true }) { const { _scriptable =defaults.scriptable , _indexable =defaults.indexable , _allKeys =defaults.allKeys } = proxy; return { allKeys: _allKeys, scriptable: _scriptable, indexable: _indexable, isScriptable: isFunction(_scriptable) ? _scriptable : ()=>_scriptable, isIndexable: isFunction(_indexable) ? _indexable : ()=>_indexable }; } const readKey = (prefix, name)=>prefix ? prefix + _capitalize(name) : name; const needsSubResolver = (prop, value)=>isObject(value) && prop !== 'adapters' && (Object.getPrototypeOf(value) === null || value.constructor === Object); function _cached(target, prop, resolve) { if (Object.prototype.hasOwnProperty.call(target, prop) || prop === 'constructor') { return target[prop]; } const value = resolve(); // cache the resolved value target[prop] = value; return value; } function _resolveWithContext(target, prop, receiver) { const { _proxy , _context , _subProxy , _descriptors: descriptors } = target; let value = _proxy[prop]; // resolve from proxy // resolve with context if (isFunction(value) && descriptors.isScriptable(prop)) { value = _resolveScriptable(prop, value, target, receiver); } if (isArray(value) && value.length) { value = _resolveArray(prop, value, target, descriptors.isIndexable); } if (needsSubResolver(prop, value)) { // if the resolved value is an object, create a sub resolver for it value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors); } return value; } function _resolveScriptable(prop, getValue, target, receiver) { const { _proxy , _context , _subProxy , _stack } = target; if (_stack.has(prop)) { throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop); } _stack.add(prop); let value = getValue(_context, _subProxy || receiver); _stack.delete(prop); if (needsSubResolver(prop, value)) { // When scriptable option returns an object, create a resolver on that. value = createSubResolver(_proxy._scopes, _proxy, prop, value); } return value; } function _resolveArray(prop, value, target, isIndexable) { const { _proxy , _context , _subProxy , _descriptors: descriptors } = target; if (typeof _context.index !== 'undefined' && isIndexable(prop)) { return value[_context.index % value.length]; } else if (isObject(value[0])) { // Array of objects, return array or resolvers const arr = value; const scopes = _proxy._scopes.filter((s)=>s !== arr); value = []; for (const item of arr){ const resolver = createSubResolver(scopes, _proxy, prop, item); value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors)); } } return value; } function resolveFallback(fallback, prop, value) { return isFunction(fallback) ? fallback(prop, value) : fallback; } const getScope = (key, parent)=>key === true ? parent : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined; function addScopes(set, parentScopes, key, parentFallback, value) { for (const parent of parentScopes){ const scope = getScope(key, parent); if (scope) { set.add(scope); const fallback = resolveFallback(scope._fallback, key, value); if (typeof fallback !== 'undefined' && fallback !== key && fallback !== parentFallback) { // When we reach the descriptor that defines a new _fallback, return that. // The fallback will resume to that new scope. return fallback; } } else if (scope === false && typeof parentFallback !== 'undefined' && key !== parentFallback) { // Fallback to `false` results to `false`, when falling back to different key. // For example `interaction` from `hover` or `plugins.tooltip` and `animation` from `animations` return null; } } return false; } function createSubResolver(parentScopes, resolver, prop, value) { const rootScopes = resolver._rootScopes; const fallback = resolveFallback(resolver._fallback, prop, value); const allScopes = [ ...parentScopes, ...rootScopes ]; const set = new Set(); set.add(value); let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value); if (key === null) { return false; } if (typeof fallback !== 'undefined' && fallback !== prop) { key = addScopesFromKey(set, allScopes, fallback, key, value); if (key === null) { return false; } } return _createResolver(Array.from(set), [ '' ], rootScopes, fallback, ()=>subGetTarget(resolver, prop, value)); } function addScopesFromKey(set, allScopes, key, fallback, item) { while(key){ key = addScopes(set, allScopes, key, fallback, item); } return key; } function subGetTarget(resolver, prop, value) { const parent = resolver._getTarget(); if (!(prop in parent)) { parent[prop] = {}; } const target = parent[prop]; if (isArray(target) && isObject(value)) { // For array of objects, the object is used to store updated values return value; } return target || {}; } function _resolveWithPrefixes(prop, prefixes, scopes, proxy) { let value; for (const prefix of prefixes){ value = _resolve(readKey(prefix, prop), scopes); if (typeof value !== 'undefined') { return needsSubResolver(prop, value) ? createSubResolver(scopes, proxy, prop, value) : value; } } } function _resolve(key, scopes) { for (const scope of scopes){ if (!scope) { continue; } const value = scope[key]; if (typeof value !== 'undefined') { return value; } } } function getKeysFromAllScopes(target) { let keys = target._keys; if (!keys) { keys = target._keys = resolveKeysFromAllScopes(target._scopes); } return keys; } function resolveKeysFromAllScopes(scopes) { const set = new Set(); for (const scope of scopes){ for (const key of Object.keys(scope).filter((k)=>!k.startsWith('_'))){ set.add(key); } } return Array.from(set); } function _parseObjectDataRadialScale(meta, data, start, count) { const { iScale } = meta; const { key ='r' } = this._parsing; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { r: iScale.parse(resolveObjectKey(item, key), index) }; } return parsed; } const EPSILON = Number.EPSILON || 1e-14; const getPoint = (points, i)=>i < points.length && !points[i].skip && points[i]; const getValueAxis = (indexAxis)=>indexAxis === 'x' ? 'y' : 'x'; function splineCurve(firstPoint, middlePoint, afterPoint, t) { // Props to Rob Spencer at scaled innovation for his post on splining between points // http://scaledinnovation.com/analytics/splines/aboutSplines.html // This function must also respect "skipped" points const previous = firstPoint.skip ? middlePoint : firstPoint; const current = middlePoint; const next = afterPoint.skip ? middlePoint : afterPoint; const d01 = distanceBetweenPoints(current, previous); const d12 = distanceBetweenPoints(next, current); let s01 = d01 / (d01 + d12); let s12 = d12 / (d01 + d12); // If all points are the same, s01 & s02 will be inf s01 = isNaN(s01) ? 0 : s01; s12 = isNaN(s12) ? 0 : s12; const fa = t * s01; // scaling factor for triangle Ta const fb = t * s12; return { previous: { x: current.x - fa * (next.x - previous.x), y: current.y - fa * (next.y - previous.y) }, next: { x: current.x + fb * (next.x - previous.x), y: current.y + fb * (next.y - previous.y) } }; } /** * Adjust tangents to ensure monotonic properties */ function monotoneAdjust(points, deltaK, mK) { const pointsLen = points.length; let alphaK, betaK, tauK, squaredMagnitude, pointCurrent; let pointAfter = getPoint(points, 0); for(let i = 0; i < pointsLen - 1; ++i){ pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent || !pointAfter) { continue; } if (almostEquals(deltaK[i], 0, EPSILON)) { mK[i] = mK[i + 1] = 0; continue; } alphaK = mK[i] / deltaK[i]; betaK = mK[i + 1] / deltaK[i]; squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); if (squaredMagnitude <= 9) { continue; } tauK = 3 / Math.sqrt(squaredMagnitude); mK[i] = alphaK * tauK * deltaK[i]; mK[i + 1] = betaK * tauK * deltaK[i]; } } function monotoneCompute(points, mK, indexAxis = 'x') { const valueAxis = getValueAxis(indexAxis); const pointsLen = points.length; let delta, pointBefore, pointCurrent; let pointAfter = getPoint(points, 0); for(let i = 0; i < pointsLen; ++i){ pointBefore = pointCurrent; pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent) { continue; } const iPixel = pointCurrent[indexAxis]; const vPixel = pointCurrent[valueAxis]; if (pointBefore) { delta = (iPixel - pointBefore[indexAxis]) / 3; pointCurrent[`cp1${indexAxis}`] = iPixel - delta; pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i]; } if (pointAfter) { delta = (pointAfter[indexAxis] - iPixel) / 3; pointCurrent[`cp2${indexAxis}`] = iPixel + delta; pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i]; } } } /** * This function calculates BΓ©zier control points in a similar way than |splineCurve|, * but preserves monotonicity of the provided data and ensures no local extremums are added * between the dataset discrete points due to the interpolation. * See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation */ function splineCurveMonotone(points, indexAxis = 'x') { const valueAxis = getValueAxis(indexAxis); const pointsLen = points.length; const deltaK = Array(pointsLen).fill(0); const mK = Array(pointsLen); // Calculate slopes (deltaK) and initialize tangents (mK) let i, pointBefore, pointCurrent; let pointAfter = getPoint(points, 0); for(i = 0; i < pointsLen; ++i){ pointBefore = pointCurrent; pointCurrent = pointAfter; pointAfter = getPoint(points, i + 1); if (!pointCurrent) { continue; } if (pointAfter) { const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis]; // In the case of two points that appear at the same x pixel, slopeDeltaX is 0 deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0; } mK[i] = !pointBefore ? deltaK[i] : !pointAfter ? deltaK[i - 1] : sign(deltaK[i - 1]) !== sign(deltaK[i]) ? 0 : (deltaK[i - 1] + deltaK[i]) / 2; } monotoneAdjust(points, deltaK, mK); monotoneCompute(points, mK, indexAxis); } function capControlPoint(pt, min, max) { return Math.max(Math.min(pt, max), min); } function capBezierPoints(points, area) { let i, ilen, point, inArea, inAreaPrev; let inAreaNext = _isPointInArea(points[0], area); for(i = 0, ilen = points.length; i < ilen; ++i){ inAreaPrev = inArea; inArea = inAreaNext; inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area); if (!inArea) { continue; } point = points[i]; if (inAreaPrev) { point.cp1x = capControlPoint(point.cp1x, area.left, area.right); point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom); } if (inAreaNext) { point.cp2x = capControlPoint(point.cp2x, area.left, area.right); point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom); } } } /** * @private */ function _updateBezierControlPoints(points, options, area, loop, indexAxis) { let i, ilen, point, controlPoints; // Only consider points that are drawn in case the spanGaps option is used if (options.spanGaps) { points = points.filter((pt)=>!pt.skip); } if (options.cubicInterpolationMode === 'monotone') { splineCurveMonotone(points, indexAxis); } else { let prev = loop ? points[points.length - 1] : points[0]; for(i = 0, ilen = points.length; i < ilen; ++i){ point = points[i]; controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension); point.cp1x = controlPoints.previous.x; point.cp1y = controlPoints.previous.y; point.cp2x = controlPoints.next.x; point.cp2y = controlPoints.next.y; prev = point; } } if (options.capBezierPoints) { capBezierPoints(points, area); } } /** * @private */ function _isDomSupported() { return typeof window !== 'undefined' && typeof document !== 'undefined'; } /** * @private */ function _getParentNode(domNode) { let parent = domNode.parentNode; if (parent && parent.toString() === '[object ShadowRoot]') { parent = parent.host; } return parent; } /** * convert max-width/max-height values that may be percentages into a number * @private */ function parseMaxStyle(styleValue, node, parentProperty) { let valueInPixels; if (typeof styleValue === 'string') { valueInPixels = parseInt(styleValue, 10); if (styleValue.indexOf('%') !== -1) { // percentage * size in dimension valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; } } else { valueInPixels = styleValue; } return valueInPixels; } const helpers_dataset_getComputedStyle = (element)=>element.ownerDocument.defaultView.getComputedStyle(element, null); function getStyle(el, property) { return helpers_dataset_getComputedStyle(el).getPropertyValue(property); } const positions = [ 'top', 'right', 'bottom', 'left' ]; function getPositionedStyle(styles, style, suffix) { const result = {}; suffix = suffix ? '-' + suffix : ''; for(let i = 0; i < 4; i++){ const pos = positions[i]; result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; } result.width = result.left + result.right; result.height = result.top + result.bottom; return result; } const useOffsetPos = (x, y, target)=>(x > 0 || y > 0) && (!target || !target.shadowRoot); /** * @param e * @param canvas * @returns Canvas position */ function getCanvasPosition(e, canvas) { const touches = e.touches; const source = touches && touches.length ? touches[0] : e; const { offsetX , offsetY } = source; let box = false; let x, y; if (useOffsetPos(offsetX, offsetY, e.target)) { x = offsetX; y = offsetY; } else { const rect = canvas.getBoundingClientRect(); x = source.clientX - rect.left; y = source.clientY - rect.top; box = true; } return { x, y, box }; } /** * Gets an event's x, y coordinates, relative to the chart area * @param event * @param chart * @returns x and y coordinates of the event */ function getRelativePosition(event, chart) { if ('native' in event) { return event; } const { canvas , currentDevicePixelRatio } = chart; const style = helpers_dataset_getComputedStyle(canvas); const borderBox = style.boxSizing === 'border-box'; const paddings = getPositionedStyle(style, 'padding'); const borders = getPositionedStyle(style, 'border', 'width'); const { x , y , box } = getCanvasPosition(event, canvas); const xOffset = paddings.left + (box && borders.left); const yOffset = paddings.top + (box && borders.top); let { width , height } = chart; if (borderBox) { width -= paddings.width + borders.width; height -= paddings.height + borders.height; } return { x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) }; } function getContainerSize(canvas, width, height) { let maxWidth, maxHeight; if (width === undefined || height === undefined) { const container = canvas && _getParentNode(canvas); if (!container) { width = canvas.clientWidth; height = canvas.clientHeight; } else { const rect = container.getBoundingClientRect(); // this is the border box of the container const containerStyle = helpers_dataset_getComputedStyle(container); const containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); const containerPadding = getPositionedStyle(containerStyle, 'padding'); width = rect.width - containerPadding.width - containerBorder.width; height = rect.height - containerPadding.height - containerBorder.height; maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); } } return { width, height, maxWidth: maxWidth || INFINITY, maxHeight: maxHeight || INFINITY }; } const round1 = (v)=>Math.round(v * 10) / 10; // eslint-disable-next-line complexity function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { const style = helpers_dataset_getComputedStyle(canvas); const margins = getPositionedStyle(style, 'margin'); const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY; const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY; const containerSize = getContainerSize(canvas, bbWidth, bbHeight); let { width , height } = containerSize; if (style.boxSizing === 'content-box') { const borders = getPositionedStyle(style, 'border', 'width'); const paddings = getPositionedStyle(style, 'padding'); width -= paddings.width + borders.width; height -= paddings.height + borders.height; } width = Math.max(0, width - margins.width); height = Math.max(0, aspectRatio ? width / aspectRatio : height - margins.height); width = round1(Math.min(width, maxWidth, containerSize.maxWidth)); height = round1(Math.min(height, maxHeight, containerSize.maxHeight)); if (width && !height) { // https://github.com/chartjs/Chart.js/issues/4659 // If the canvas has width, but no height, default to aspectRatio of 2 (canvas default) height = round1(width / 2); } const maintainHeight = bbWidth !== undefined || bbHeight !== undefined; if (maintainHeight && aspectRatio && containerSize.height && height > containerSize.height) { height = containerSize.height; width = round1(Math.floor(height * aspectRatio)); } return { width, height }; } /** * @param chart * @param forceRatio * @param forceStyle * @returns True if the canvas context size or transformation has changed. */ function retinaScale(chart, forceRatio, forceStyle) { const pixelRatio = forceRatio || 1; const deviceHeight = round1(chart.height * pixelRatio); const deviceWidth = round1(chart.width * pixelRatio); chart.height = round1(chart.height); chart.width = round1(chart.width); const canvas = chart.canvas; // If no style has been set on the canvas, the render size is used as display size, // making the chart visually bigger, so let's enforce it to the "correct" values. // See https://github.com/chartjs/Chart.js/issues/3575 if (canvas.style && (forceStyle || !canvas.style.height && !canvas.style.width)) { canvas.style.height = `${chart.height}px`; canvas.style.width = `${chart.width}px`; } if (chart.currentDevicePixelRatio !== pixelRatio || canvas.height !== deviceHeight || canvas.width !== deviceWidth) { chart.currentDevicePixelRatio = pixelRatio; canvas.height = deviceHeight; canvas.width = deviceWidth; chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); return true; } return false; } /** * Detects support for options object argument in addEventListener. * https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support * @private */ const supportsEventListenerOptions = function() { let passiveSupported = false; try { const options = { get passive () { passiveSupported = true; return false; } }; if (_isDomSupported()) { window.addEventListener('test', null, options); window.removeEventListener('test', null, options); } } catch (e) { // continue regardless of error } return passiveSupported; }(); /** * The "used" size is the final value of a dimension property after all calculations have * been performed. This method uses the computed style of `element` but returns undefined * if the computed style is not expressed in pixels. That can happen in some cases where * `element` has a size relative to its parent and this last one is not yet displayed, * for example because of `display: none` on a parent node. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value * @returns Size in pixels or undefined if unknown. */ function readUsedSize(element, property) { const value = getStyle(element, property); const matches = value && value.match(/^(\d+)(\.\d+)?px$/); return matches ? +matches[1] : undefined; } /** * @private */ function _pointInLine(p1, p2, t, mode) { return { x: p1.x + t * (p2.x - p1.x), y: p1.y + t * (p2.y - p1.y) }; } /** * @private */ function _steppedInterpolation(p1, p2, t, mode) { return { x: p1.x + t * (p2.x - p1.x), y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y }; } /** * @private */ function _bezierInterpolation(p1, p2, t, mode) { const cp1 = { x: p1.cp2x, y: p1.cp2y }; const cp2 = { x: p2.cp1x, y: p2.cp1y }; const a = _pointInLine(p1, cp1, t); const b = _pointInLine(cp1, cp2, t); const c = _pointInLine(cp2, p2, t); const d = _pointInLine(a, b, t); const e = _pointInLine(b, c, t); return _pointInLine(d, e, t); } const getRightToLeftAdapter = function(rectX, width) { return { x (x) { return rectX + rectX + width - x; }, setWidth (w) { width = w; }, textAlign (align) { if (align === 'center') { return align; } return align === 'right' ? 'left' : 'right'; }, xPlus (x, value) { return x - value; }, leftForLtr (x, itemWidth) { return x - itemWidth; } }; }; const getLeftToRightAdapter = function() { return { x (x) { return x; }, setWidth (w) {}, textAlign (align) { return align; }, xPlus (x, value) { return x + value; }, leftForLtr (x, _itemWidth) { return x; } }; }; function getRtlAdapter(rtl, rectX, width) { return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); } function overrideTextDirection(ctx, direction) { let style, original; if (direction === 'ltr' || direction === 'rtl') { style = ctx.canvas.style; original = [ style.getPropertyValue('direction'), style.getPropertyPriority('direction') ]; style.setProperty('direction', direction, 'important'); ctx.prevTextDirection = original; } } function restoreTextDirection(ctx, original) { if (original !== undefined) { delete ctx.prevTextDirection; ctx.canvas.style.setProperty('direction', original[0], original[1]); } } function propertyFn(property) { if (property === 'angle') { return { between: _angleBetween, compare: _angleDiff, normalize: _normalizeAngle }; } return { between: _isBetween, compare: (a, b)=>a - b, normalize: (x)=>x }; } function normalizeSegment({ start , end , count , loop , style }) { return { start: start % count, end: end % count, loop: loop && (end - start + 1) % count === 0, style }; } function getSegment(segment, points, bounds) { const { property , start: startBound , end: endBound } = bounds; const { between , normalize } = propertyFn(property); const count = points.length; let { start , end , loop } = segment; let i, ilen; if (loop) { start += count; end += count; for(i = 0, ilen = count; i < ilen; ++i){ if (!between(normalize(points[start % count][property]), startBound, endBound)) { break; } start--; end--; } start %= count; end %= count; } if (end < start) { end += count; } return { start, end, loop, style: segment.style }; } function _boundSegment(segment, points, bounds) { if (!bounds) { return [ segment ]; } const { property , start: startBound , end: endBound } = bounds; const count = points.length; const { compare , between , normalize } = propertyFn(property); const { start , end , loop , style } = getSegment(segment, points, bounds); const result = []; let inside = false; let subStart = null; let value, point, prevValue; const startIsBefore = ()=>between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; const endIsBefore = ()=>compare(endBound, value) === 0 || between(endBound, prevValue, value); const shouldStart = ()=>inside || startIsBefore(); const shouldStop = ()=>!inside || endIsBefore(); for(let i = start, prev = start; i <= end; ++i){ point = points[i % count]; if (point.skip) { continue; } value = normalize(point[property]); if (value === prevValue) { continue; } inside = between(value, startBound, endBound); if (subStart === null && shouldStart()) { subStart = compare(value, startBound) === 0 ? i : prev; } if (subStart !== null && shouldStop()) { result.push(normalizeSegment({ start: subStart, end: i, loop, count, style })); subStart = null; } prev = i; prevValue = value; } if (subStart !== null) { result.push(normalizeSegment({ start: subStart, end, loop, count, style })); } return result; } function _boundSegments(line, bounds) { const result = []; const segments = line.segments; for(let i = 0; i < segments.length; i++){ const sub = _boundSegment(segments[i], line.points, bounds); if (sub.length) { result.push(...sub); } } return result; } function findStartAndEnd(points, count, loop, spanGaps) { let start = 0; let end = count - 1; if (loop && !spanGaps) { while(start < count && !points[start].skip){ start++; } } while(start < count && points[start].skip){ start++; } start %= count; if (loop) { end += start; } while(end > start && points[end % count].skip){ end--; } end %= count; return { start, end }; } function solidSegments(points, start, max, loop) { const count = points.length; const result = []; let last = start; let prev = points[start]; let end; for(end = start + 1; end <= max; ++end){ const cur = points[end % count]; if (cur.skip || cur.stop) { if (!prev.skip) { loop = false; result.push({ start: start % count, end: (end - 1) % count, loop }); start = last = cur.stop ? end : null; } } else { last = end; if (prev.skip) { start = end; } } prev = cur; } if (last !== null) { result.push({ start: start % count, end: last % count, loop }); } return result; } function _computeSegments(line, segmentOptions) { const points = line.points; const spanGaps = line.options.spanGaps; const count = points.length; if (!count) { return []; } const loop = !!line._loop; const { start , end } = findStartAndEnd(points, count, loop, spanGaps); if (spanGaps === true) { return splitByStyles(line, [ { start, end, loop } ], points, segmentOptions); } const max = end < start ? end + count : end; const completeLoop = !!line._fullLoop && start === 0 && end === count - 1; return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions); } function splitByStyles(line, segments, points, segmentOptions) { if (!segmentOptions || !segmentOptions.setContext || !points) { return segments; } return doSplitByStyles(line, segments, points, segmentOptions); } function doSplitByStyles(line, segments, points, segmentOptions) { const chartContext = line._chart.getContext(); const baseStyle = readStyle(line.options); const { _datasetIndex: datasetIndex , options: { spanGaps } } = line; const count = points.length; const result = []; let prevStyle = baseStyle; let start = segments[0].start; let i = start; function addStyle(s, e, l, st) { const dir = spanGaps ? -1 : 1; if (s === e) { return; } s += count; while(points[s % count].skip){ s -= dir; } while(points[e % count].skip){ e += dir; } if (s % count !== e % count) { result.push({ start: s % count, end: e % count, loop: l, style: st }); prevStyle = st; start = e % count; } } for (const segment of segments){ start = spanGaps ? start : segment.start; let prev = points[start % count]; let style; for(i = start + 1; i <= segment.end; i++){ const pt = points[i % count]; style = readStyle(segmentOptions.setContext(createContext(chartContext, { type: 'segment', p0: prev, p1: pt, p0DataIndex: (i - 1) % count, p1DataIndex: i % count, datasetIndex }))); if (styleChanged(style, prevStyle)) { addStyle(start, i - 1, segment.loop, prevStyle); } prev = pt; prevStyle = style; } if (start < i - 1) { addStyle(start, i - 1, segment.loop, prevStyle); } } return result; } function readStyle(options) { return { backgroundColor: options.backgroundColor, borderCapStyle: options.borderCapStyle, borderDash: options.borderDash, borderDashOffset: options.borderDashOffset, borderJoinStyle: options.borderJoinStyle, borderWidth: options.borderWidth, borderColor: options.borderColor }; } function styleChanged(style, prevStyle) { if (!prevStyle) { return false; } const cache = []; const replacer = function(key, value) { if (!isPatternOrGradient(value)) { return value; } if (!cache.includes(value)) { cache.push(value); } return cache.indexOf(value); }; return JSON.stringify(style, replacer) !== JSON.stringify(prevStyle, replacer); } function getSizeForArea(scale, chartArea, field) { return scale.options.clip ? scale[field] : chartArea[field]; } function getDatasetArea(meta, chartArea) { const { xScale , yScale } = meta; if (xScale && yScale) { return { left: getSizeForArea(xScale, chartArea, 'left'), right: getSizeForArea(xScale, chartArea, 'right'), top: getSizeForArea(yScale, chartArea, 'top'), bottom: getSizeForArea(yScale, chartArea, 'bottom') }; } return chartArea; } function getDatasetClipArea(chart, meta) { const clip = meta._clip; if (clip.disabled) { return false; } const area = getDatasetArea(meta, chart.chartArea); return { left: clip.left === false ? 0 : area.left - (clip.left === true ? 0 : clip.left), right: clip.right === false ? chart.width : area.right + (clip.right === true ? 0 : clip.right), top: clip.top === false ? 0 : area.top - (clip.top === true ? 0 : clip.top), bottom: clip.bottom === false ? chart.height : area.bottom + (clip.bottom === true ? 0 : clip.bottom) }; } //# sourceMappingURL=helpers.dataset.js.map ;// ../../node_modules/chart.js/dist/chart.js /*! * Chart.js v4.5.1 * https://www.chartjs.org * (c) 2025 Chart.js Contributors * Released under the MIT License */ class Animator { constructor(){ this._request = null; this._charts = new Map(); this._running = false; this._lastDate = undefined; } _notify(chart, anims, date, type) { const callbacks = anims.listeners[type]; const numSteps = anims.duration; callbacks.forEach((fn)=>fn({ chart, initial: anims.initial, numSteps, currentStep: Math.min(date - anims.start, numSteps) })); } _refresh() { if (this._request) { return; } this._running = true; this._request = requestAnimFrame.call(window, ()=>{ this._update(); this._request = null; if (this._running) { this._refresh(); } }); } _update(date = Date.now()) { let remaining = 0; this._charts.forEach((anims, chart)=>{ if (!anims.running || !anims.items.length) { return; } const items = anims.items; let i = items.length - 1; let draw = false; let item; for(; i >= 0; --i){ item = items[i]; if (item._active) { if (item._total > anims.duration) { anims.duration = item._total; } item.tick(date); draw = true; } else { items[i] = items[items.length - 1]; items.pop(); } } if (draw) { chart.draw(); this._notify(chart, anims, date, 'progress'); } if (!items.length) { anims.running = false; this._notify(chart, anims, date, 'complete'); anims.initial = false; } remaining += items.length; }); this._lastDate = date; if (remaining === 0) { this._running = false; } } _getAnims(chart) { const charts = this._charts; let anims = charts.get(chart); if (!anims) { anims = { running: false, initial: true, items: [], listeners: { complete: [], progress: [] } }; charts.set(chart, anims); } return anims; } listen(chart, event, cb) { this._getAnims(chart).listeners[event].push(cb); } add(chart, items) { if (!items || !items.length) { return; } this._getAnims(chart).items.push(...items); } has(chart) { return this._getAnims(chart).items.length > 0; } start(chart) { const anims = this._charts.get(chart); if (!anims) { return; } anims.running = true; anims.start = Date.now(); anims.duration = anims.items.reduce((acc, cur)=>Math.max(acc, cur._duration), 0); this._refresh(); } running(chart) { if (!this._running) { return false; } const anims = this._charts.get(chart); if (!anims || !anims.running || !anims.items.length) { return false; } return true; } stop(chart) { const anims = this._charts.get(chart); if (!anims || !anims.items.length) { return; } const items = anims.items; let i = items.length - 1; for(; i >= 0; --i){ items[i].cancel(); } anims.items = []; this._notify(chart, anims, Date.now(), 'complete'); } remove(chart) { return this._charts.delete(chart); } } var animator = /* #__PURE__ */ new Animator(); const transparent = 'transparent'; const interpolators = { boolean (from, to, factor) { return factor > 0.5 ? to : from; }, color (from, to, factor) { const c0 = color(from || transparent); const c1 = c0.valid && color(to || transparent); return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to; }, number (from, to, factor) { return from + (to - from) * factor; } }; class Animation { constructor(cfg, target, prop, to){ const currentValue = target[prop]; to = resolve([ cfg.to, to, currentValue, cfg.from ]); const from = resolve([ cfg.from, currentValue, to ]); this._active = true; this._fn = cfg.fn || interpolators[cfg.type || typeof from]; this._easing = effects[cfg.easing] || effects.linear; this._start = Math.floor(Date.now() + (cfg.delay || 0)); this._duration = this._total = Math.floor(cfg.duration); this._loop = !!cfg.loop; this._target = target; this._prop = prop; this._from = from; this._to = to; this._promises = undefined; } active() { return this._active; } update(cfg, to, date) { if (this._active) { this._notify(false); const currentValue = this._target[this._prop]; const elapsed = date - this._start; const remain = this._duration - elapsed; this._start = date; this._duration = Math.floor(Math.max(remain, cfg.duration)); this._total += elapsed; this._loop = !!cfg.loop; this._to = resolve([ cfg.to, to, currentValue, cfg.from ]); this._from = resolve([ cfg.from, currentValue, to ]); } } cancel() { if (this._active) { this.tick(Date.now()); this._active = false; this._notify(false); } } tick(date) { const elapsed = date - this._start; const duration = this._duration; const prop = this._prop; const from = this._from; const loop = this._loop; const to = this._to; let factor; this._active = from !== to && (loop || elapsed < duration); if (!this._active) { this._target[prop] = to; this._notify(true); return; } if (elapsed < 0) { this._target[prop] = from; return; } factor = elapsed / duration % 2; factor = loop && factor > 1 ? 2 - factor : factor; factor = this._easing(Math.min(1, Math.max(0, factor))); this._target[prop] = this._fn(from, to, factor); } wait() { const promises = this._promises || (this._promises = []); return new Promise((res, rej)=>{ promises.push({ res, rej }); }); } _notify(resolved) { const method = resolved ? 'res' : 'rej'; const promises = this._promises || []; for(let i = 0; i < promises.length; i++){ promises[i][method](); } } } class Animations { constructor(chart, config){ this._chart = chart; this._properties = new Map(); this.configure(config); } configure(config) { if (!isObject(config)) { return; } const animationOptions = Object.keys(defaults.animation); const animatedProps = this._properties; Object.getOwnPropertyNames(config).forEach((key)=>{ const cfg = config[key]; if (!isObject(cfg)) { return; } const resolved = {}; for (const option of animationOptions){ resolved[option] = cfg[option]; } (isArray(cfg.properties) && cfg.properties || [ key ]).forEach((prop)=>{ if (prop === key || !animatedProps.has(prop)) { animatedProps.set(prop, resolved); } }); }); } _animateOptions(target, values) { const newOptions = values.options; const options = resolveTargetOptions(target, newOptions); if (!options) { return []; } const animations = this._createAnimations(options, newOptions); if (newOptions.$shared) { awaitAll(target.options.$animations, newOptions).then(()=>{ target.options = newOptions; }, ()=>{ }); } return animations; } _createAnimations(target, values) { const animatedProps = this._properties; const animations = []; const running = target.$animations || (target.$animations = {}); const props = Object.keys(values); const date = Date.now(); let i; for(i = props.length - 1; i >= 0; --i){ const prop = props[i]; if (prop.charAt(0) === '$') { continue; } if (prop === 'options') { animations.push(...this._animateOptions(target, values)); continue; } const value = values[prop]; let animation = running[prop]; const cfg = animatedProps.get(prop); if (animation) { if (cfg && animation.active()) { animation.update(cfg, value, date); continue; } else { animation.cancel(); } } if (!cfg || !cfg.duration) { target[prop] = value; continue; } running[prop] = animation = new Animation(cfg, target, prop, value); animations.push(animation); } return animations; } update(target, values) { if (this._properties.size === 0) { Object.assign(target, values); return; } const animations = this._createAnimations(target, values); if (animations.length) { animator.add(this._chart, animations); return true; } } } function awaitAll(animations, properties) { const running = []; const keys = Object.keys(properties); for(let i = 0; i < keys.length; i++){ const anim = animations[keys[i]]; if (anim && anim.active()) { running.push(anim.wait()); } } return Promise.all(running); } function resolveTargetOptions(target, newOptions) { if (!newOptions) { return; } let options = target.options; if (!options) { target.options = newOptions; return; } if (options.$shared) { target.options = options = Object.assign({}, options, { $shared: false, $animations: {} }); } return options; } function scaleClip(scale, allowedOverflow) { const opts = scale && scale.options || {}; const reverse = opts.reverse; const min = opts.min === undefined ? allowedOverflow : 0; const max = opts.max === undefined ? allowedOverflow : 0; return { start: reverse ? max : min, end: reverse ? min : max }; } function defaultClip(xScale, yScale, allowedOverflow) { if (allowedOverflow === false) { return false; } const x = scaleClip(xScale, allowedOverflow); const y = scaleClip(yScale, allowedOverflow); return { top: y.end, right: x.end, bottom: y.start, left: x.start }; } function toClip(value) { let t, r, b, l; if (isObject(value)) { t = value.top; r = value.right; b = value.bottom; l = value.left; } else { t = r = b = l = value; } return { top: t, right: r, bottom: b, left: l, disabled: value === false }; } function getSortedDatasetIndices(chart, filterVisible) { const keys = []; const metasets = chart._getSortedDatasetMetas(filterVisible); let i, ilen; for(i = 0, ilen = metasets.length; i < ilen; ++i){ keys.push(metasets[i].index); } return keys; } function applyStack(stack, value, dsIndex, options = {}) { const keys = stack.keys; const singleMode = options.mode === 'single'; let i, ilen, datasetIndex, otherValue; if (value === null) { return; } let found = false; for(i = 0, ilen = keys.length; i < ilen; ++i){ datasetIndex = +keys[i]; if (datasetIndex === dsIndex) { found = true; if (options.all) { continue; } break; } otherValue = stack.values[datasetIndex]; if (isNumberFinite(otherValue) && (singleMode || value === 0 || sign(value) === sign(otherValue))) { value += otherValue; } } if (!found && !options.all) { return 0; } return value; } function convertObjectDataToArray(data, meta) { const { iScale , vScale } = meta; const iAxisKey = iScale.axis === 'x' ? 'x' : 'y'; const vAxisKey = vScale.axis === 'x' ? 'x' : 'y'; const keys = Object.keys(data); const adata = new Array(keys.length); let i, ilen, key; for(i = 0, ilen = keys.length; i < ilen; ++i){ key = keys[i]; adata[i] = { [iAxisKey]: key, [vAxisKey]: data[key] }; } return adata; } function isStacked(scale, meta) { const stacked = scale && scale.options.stacked; return stacked || stacked === undefined && meta.stack !== undefined; } function getStackKey(indexScale, valueScale, meta) { return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`; } function getUserBounds(scale) { const { min , max , minDefined , maxDefined } = scale.getUserBounds(); return { min: minDefined ? min : Number.NEGATIVE_INFINITY, max: maxDefined ? max : Number.POSITIVE_INFINITY }; } function getOrCreateStack(stacks, stackKey, indexValue) { const subStack = stacks[stackKey] || (stacks[stackKey] = {}); return subStack[indexValue] || (subStack[indexValue] = {}); } function getLastIndexInStack(stack, vScale, positive, type) { for (const meta of vScale.getMatchingVisibleMetas(type).reverse()){ const value = stack[meta.index]; if (positive && value > 0 || !positive && value < 0) { return meta.index; } } return null; } function updateStacks(controller, parsed) { const { chart , _cachedMeta: meta } = controller; const stacks = chart._stacks || (chart._stacks = {}); const { iScale , vScale , index: datasetIndex } = meta; const iAxis = iScale.axis; const vAxis = vScale.axis; const key = getStackKey(iScale, vScale, meta); const ilen = parsed.length; let stack; for(let i = 0; i < ilen; ++i){ const item = parsed[i]; const { [iAxis]: index , [vAxis]: value } = item; const itemStacks = item._stacks || (item._stacks = {}); stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); stack[datasetIndex] = value; stack._top = getLastIndexInStack(stack, vScale, true, meta.type); stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); const visualValues = stack._visualValues || (stack._visualValues = {}); visualValues[datasetIndex] = value; } } function getFirstScaleId(chart, axis) { const scales = chart.scales; return Object.keys(scales).filter((key)=>scales[key].axis === axis).shift(); } function createDatasetContext(parent, index) { return createContext(parent, { active: false, dataset: undefined, datasetIndex: index, index, mode: 'default', type: 'dataset' }); } function createDataContext(parent, index, element) { return createContext(parent, { active: false, dataIndex: index, parsed: undefined, raw: undefined, element, index, mode: 'default', type: 'data' }); } function clearStacks(meta, items) { const datasetIndex = meta.controller.index; const axis = meta.vScale && meta.vScale.axis; if (!axis) { return; } items = items || meta._parsed; for (const parsed of items){ const stacks = parsed._stacks; if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) { return; } delete stacks[axis][datasetIndex]; if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) { delete stacks[axis]._visualValues[datasetIndex]; } } } const isDirectUpdateMode = (mode)=>mode === 'reset' || mode === 'none'; const cloneIfNotShared = (cached, shared)=>shared ? cached : Object.assign({}, cached); const createStack = (canStack, meta, chart)=>canStack && !meta.hidden && meta._stacked && { keys: getSortedDatasetIndices(chart, true), values: null }; class DatasetController { static defaults = {}; static datasetElementType = null; static dataElementType = null; constructor(chart, datasetIndex){ this.chart = chart; this._ctx = chart.ctx; this.index = datasetIndex; this._cachedDataOpts = {}; this._cachedMeta = this.getMeta(); this._type = this._cachedMeta.type; this.options = undefined; this._parsing = false; this._data = undefined; this._objectData = undefined; this._sharedOptions = undefined; this._drawStart = undefined; this._drawCount = undefined; this.enableOptionSharing = false; this.supportsDecimation = false; this.$context = undefined; this._syncList = []; this.datasetElementType = new.target.datasetElementType; this.dataElementType = new.target.dataElementType; this.initialize(); } initialize() { const meta = this._cachedMeta; this.configure(); this.linkScales(); meta._stacked = isStacked(meta.vScale, meta); this.addElements(); if (this.options.fill && !this.chart.isPluginEnabled('filler')) { console.warn("Tried to use the 'fill' option without the 'Filler' plugin enabled. Please import and register the 'Filler' plugin and make sure it is not disabled in the options"); } } updateIndex(datasetIndex) { if (this.index !== datasetIndex) { clearStacks(this._cachedMeta); } this.index = datasetIndex; } linkScales() { const chart = this.chart; const meta = this._cachedMeta; const dataset = this.getDataset(); const chooseId = (axis, x, y, r)=>axis === 'x' ? x : axis === 'r' ? r : y; const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); const indexAxis = meta.indexAxis; const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); meta.xScale = this.getScaleForId(xid); meta.yScale = this.getScaleForId(yid); meta.rScale = this.getScaleForId(rid); meta.iScale = this.getScaleForId(iid); meta.vScale = this.getScaleForId(vid); } getDataset() { return this.chart.data.datasets[this.index]; } getMeta() { return this.chart.getDatasetMeta(this.index); } getScaleForId(scaleID) { return this.chart.scales[scaleID]; } _getOtherScale(scale) { const meta = this._cachedMeta; return scale === meta.iScale ? meta.vScale : meta.iScale; } reset() { this._update('reset'); } _destroy() { const meta = this._cachedMeta; if (this._data) { unlistenArrayEvents(this._data, this); } if (meta._stacked) { clearStacks(meta); } } _dataCheck() { const dataset = this.getDataset(); const data = dataset.data || (dataset.data = []); const _data = this._data; if (isObject(data)) { const meta = this._cachedMeta; this._data = convertObjectDataToArray(data, meta); } else if (_data !== data) { if (_data) { unlistenArrayEvents(_data, this); const meta = this._cachedMeta; clearStacks(meta); meta._parsed = []; } if (data && Object.isExtensible(data)) { listenArrayEvents(data, this); } this._syncList = []; this._data = data; } } addElements() { const meta = this._cachedMeta; this._dataCheck(); if (this.datasetElementType) { meta.dataset = new this.datasetElementType(); } } buildOrUpdateElements(resetNewElements) { const meta = this._cachedMeta; const dataset = this.getDataset(); let stackChanged = false; this._dataCheck(); const oldStacked = meta._stacked; meta._stacked = isStacked(meta.vScale, meta); if (meta.stack !== dataset.stack) { stackChanged = true; clearStacks(meta); meta.stack = dataset.stack; } this._resyncElements(resetNewElements); if (stackChanged || oldStacked !== meta._stacked) { updateStacks(this, meta._parsed); meta._stacked = isStacked(meta.vScale, meta); } } configure() { const config = this.chart.config; const scopeKeys = config.datasetScopeKeys(this._type); const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true); this.options = config.createResolver(scopes, this.getContext()); this._parsing = this.options.parsing; this._cachedDataOpts = {}; } parse(start, count) { const { _cachedMeta: meta , _data: data } = this; const { iScale , _stacked } = meta; const iAxis = iScale.axis; let sorted = start === 0 && count === data.length ? true : meta._sorted; let prev = start > 0 && meta._parsed[start - 1]; let i, cur, parsed; if (this._parsing === false) { meta._parsed = data; meta._sorted = true; parsed = data; } else { if (isArray(data[start])) { parsed = this.parseArrayData(meta, data, start, count); } else if (isObject(data[start])) { parsed = this.parseObjectData(meta, data, start, count); } else { parsed = this.parsePrimitiveData(meta, data, start, count); } const isNotInOrderComparedToPrev = ()=>cur[iAxis] === null || prev && cur[iAxis] < prev[iAxis]; for(i = 0; i < count; ++i){ meta._parsed[i + start] = cur = parsed[i]; if (sorted) { if (isNotInOrderComparedToPrev()) { sorted = false; } prev = cur; } } meta._sorted = sorted; } if (_stacked) { updateStacks(this, parsed); } } parsePrimitiveData(meta, data, start, count) { const { iScale , vScale } = meta; const iAxis = iScale.axis; const vAxis = vScale.axis; const labels = iScale.getLabels(); const singleScale = iScale === vScale; const parsed = new Array(count); let i, ilen, index; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; parsed[i] = { [iAxis]: singleScale || iScale.parse(labels[index], index), [vAxis]: vScale.parse(data[index], index) }; } return parsed; } parseArrayData(meta, data, start, count) { const { xScale , yScale } = meta; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { x: xScale.parse(item[0], index), y: yScale.parse(item[1], index) }; } return parsed; } parseObjectData(meta, data, start, count) { const { xScale , yScale } = meta; const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; const parsed = new Array(count); let i, ilen, index, item; for(i = 0, ilen = count; i < ilen; ++i){ index = i + start; item = data[index]; parsed[i] = { x: xScale.parse(resolveObjectKey(item, xAxisKey), index), y: yScale.parse(resolveObjectKey(item, yAxisKey), index) }; } return parsed; } getParsed(index) { return this._cachedMeta._parsed[index]; } getDataElement(index) { return this._cachedMeta.data[index]; } applyStack(scale, parsed, mode) { const chart = this.chart; const meta = this._cachedMeta; const value = parsed[scale.axis]; const stack = { keys: getSortedDatasetIndices(chart, true), values: parsed._stacks[scale.axis]._visualValues }; return applyStack(stack, value, meta.index, { mode }); } updateRangeFromParsed(range, scale, parsed, stack) { const parsedValue = parsed[scale.axis]; let value = parsedValue === null ? NaN : parsedValue; const values = stack && parsed._stacks[scale.axis]; if (stack && values) { stack.values = values; value = applyStack(stack, parsedValue, this._cachedMeta.index); } range.min = Math.min(range.min, value); range.max = Math.max(range.max, value); } getMinMax(scale, canStack) { const meta = this._cachedMeta; const _parsed = meta._parsed; const sorted = meta._sorted && scale === meta.iScale; const ilen = _parsed.length; const otherScale = this._getOtherScale(scale); const stack = createStack(canStack, meta, this.chart); const range = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY }; const { min: otherMin , max: otherMax } = getUserBounds(otherScale); let i, parsed; function _skip() { parsed = _parsed[i]; const otherValue = parsed[otherScale.axis]; return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue; } for(i = 0; i < ilen; ++i){ if (_skip()) { continue; } this.updateRangeFromParsed(range, scale, parsed, stack); if (sorted) { break; } } if (sorted) { for(i = ilen - 1; i >= 0; --i){ if (_skip()) { continue; } this.updateRangeFromParsed(range, scale, parsed, stack); break; } } return range; } getAllParsedValues(scale) { const parsed = this._cachedMeta._parsed; const values = []; let i, ilen, value; for(i = 0, ilen = parsed.length; i < ilen; ++i){ value = parsed[i][scale.axis]; if (isNumberFinite(value)) { values.push(value); } } return values; } getMaxOverflow() { return false; } getLabelAndValue(index) { const meta = this._cachedMeta; const iScale = meta.iScale; const vScale = meta.vScale; const parsed = this.getParsed(index); return { label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' }; } _update(mode) { const meta = this._cachedMeta; this.update(mode || 'default'); meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow()))); } update(mode) {} draw() { const ctx = this._ctx; const chart = this.chart; const meta = this._cachedMeta; const elements = meta.data || []; const area = chart.chartArea; const active = []; const start = this._drawStart || 0; const count = this._drawCount || elements.length - start; const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop; let i; if (meta.dataset) { meta.dataset.draw(ctx, area, start, count); } for(i = start; i < start + count; ++i){ const element = elements[i]; if (element.hidden) { continue; } if (element.active && drawActiveElementsOnTop) { active.push(element); } else { element.draw(ctx, area); } } for(i = 0; i < active.length; ++i){ active[i].draw(ctx, area); } } getStyle(index, active) { const mode = active ? 'active' : 'default'; return index === undefined && this._cachedMeta.dataset ? this.resolveDatasetElementOptions(mode) : this.resolveDataElementOptions(index || 0, mode); } getContext(index, active, mode) { const dataset = this.getDataset(); let context; if (index >= 0 && index < this._cachedMeta.data.length) { const element = this._cachedMeta.data[index]; context = element.$context || (element.$context = createDataContext(this.getContext(), index, element)); context.parsed = this.getParsed(index); context.raw = dataset.data[index]; context.index = context.dataIndex = index; } else { context = this.$context || (this.$context = createDatasetContext(this.chart.getContext(), this.index)); context.dataset = dataset; context.index = context.datasetIndex = this.index; } context.active = !!active; context.mode = mode; return context; } resolveDatasetElementOptions(mode) { return this._resolveElementOptions(this.datasetElementType.id, mode); } resolveDataElementOptions(index, mode) { return this._resolveElementOptions(this.dataElementType.id, mode, index); } _resolveElementOptions(elementType, mode = 'default', index) { const active = mode === 'active'; const cache = this._cachedDataOpts; const cacheKey = elementType + '-' + mode; const cached = cache[cacheKey]; const sharing = this.enableOptionSharing && defined(index); if (cached) { return cloneIfNotShared(cached, sharing); } const config = this.chart.config; const scopeKeys = config.datasetElementScopeKeys(this._type, elementType); const prefixes = active ? [ `${elementType}Hover`, 'hover', elementType, '' ] : [ elementType, '' ]; const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); const names = Object.keys(defaults.elements[elementType]); const context = ()=>this.getContext(index, active, mode); const values = config.resolveNamedOptions(scopes, names, context, prefixes); if (values.$shared) { values.$shared = sharing; cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing)); } return values; } _resolveAnimations(index, transition, active) { const chart = this.chart; const cache = this._cachedDataOpts; const cacheKey = `animation-${transition}`; const cached = cache[cacheKey]; if (cached) { return cached; } let options; if (chart.options.animation !== false) { const config = this.chart.config; const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition); const scopes = config.getOptionScopes(this.getDataset(), scopeKeys); options = config.createResolver(scopes, this.getContext(index, active, transition)); } const animations = new Animations(chart, options && options.animations); if (options && options._cacheable) { cache[cacheKey] = Object.freeze(animations); } return animations; } getSharedOptions(options) { if (!options.$shared) { return; } return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); } includeOptions(mode, sharedOptions) { return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled; } _getSharedOptions(start, mode) { const firstOpts = this.resolveDataElementOptions(start, mode); const previouslySharedOptions = this._sharedOptions; const sharedOptions = this.getSharedOptions(firstOpts); const includeOptions = this.includeOptions(mode, sharedOptions) || sharedOptions !== previouslySharedOptions; this.updateSharedOptions(sharedOptions, mode, firstOpts); return { sharedOptions, includeOptions }; } updateElement(element, index, properties, mode) { if (isDirectUpdateMode(mode)) { Object.assign(element, properties); } else { this._resolveAnimations(index, mode).update(element, properties); } } updateSharedOptions(sharedOptions, mode, newOptions) { if (sharedOptions && !isDirectUpdateMode(mode)) { this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions); } } _setStyle(element, index, mode, active) { element.active = active; const options = this.getStyle(index, active); this._resolveAnimations(index, mode, active).update(element, { options: !active && this.getSharedOptions(options) || options }); } removeHoverStyle(element, datasetIndex, index) { this._setStyle(element, index, 'active', false); } setHoverStyle(element, datasetIndex, index) { this._setStyle(element, index, 'active', true); } _removeDatasetHoverStyle() { const element = this._cachedMeta.dataset; if (element) { this._setStyle(element, undefined, 'active', false); } } _setDatasetHoverStyle() { const element = this._cachedMeta.dataset; if (element) { this._setStyle(element, undefined, 'active', true); } } _resyncElements(resetNewElements) { const data = this._data; const elements = this._cachedMeta.data; for (const [method, arg1, arg2] of this._syncList){ this[method](arg1, arg2); } this._syncList = []; const numMeta = elements.length; const numData = data.length; const count = Math.min(numData, numMeta); if (count) { this.parse(0, count); } if (numData > numMeta) { this._insertElements(numMeta, numData - numMeta, resetNewElements); } else if (numData < numMeta) { this._removeElements(numData, numMeta - numData); } } _insertElements(start, count, resetNewElements = true) { const meta = this._cachedMeta; const data = meta.data; const end = start + count; let i; const move = (arr)=>{ arr.length += count; for(i = arr.length - 1; i >= end; i--){ arr[i] = arr[i - count]; } }; move(data); for(i = start; i < end; ++i){ data[i] = new this.dataElementType(); } if (this._parsing) { move(meta._parsed); } this.parse(start, count); if (resetNewElements) { this.updateElements(data, start, count, 'reset'); } } updateElements(element, start, count, mode) {} _removeElements(start, count) { const meta = this._cachedMeta; if (this._parsing) { const removed = meta._parsed.splice(start, count); if (meta._stacked) { clearStacks(meta, removed); } } meta.data.splice(start, count); } _sync(args) { if (this._parsing) { this._syncList.push(args); } else { const [method, arg1, arg2] = args; this[method](arg1, arg2); } this.chart._dataChanges.push([ this.index, ...args ]); } _onDataPush() { const count = arguments.length; this._sync([ '_insertElements', this.getDataset().data.length - count, count ]); } _onDataPop() { this._sync([ '_removeElements', this._cachedMeta.data.length - 1, 1 ]); } _onDataShift() { this._sync([ '_removeElements', 0, 1 ]); } _onDataSplice(start, count) { if (count) { this._sync([ '_removeElements', start, count ]); } const newCount = arguments.length - 2; if (newCount) { this._sync([ '_insertElements', start, newCount ]); } } _onDataUnshift() { this._sync([ '_insertElements', 0, arguments.length ]); } } function getAllScaleValues(scale, type) { if (!scale._cache.$bar) { const visibleMetas = scale.getMatchingVisibleMetas(type); let values = []; for(let i = 0, ilen = visibleMetas.length; i < ilen; i++){ values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale)); } scale._cache.$bar = _arrayUnique(values.sort((a, b)=>a - b)); } return scale._cache.$bar; } function computeMinSampleSize(meta) { const scale = meta.iScale; const values = getAllScaleValues(scale, meta.type); let min = scale._length; let i, ilen, curr, prev; const updateMinAndPrev = ()=>{ if (curr === 32767 || curr === -32768) { return; } if (defined(prev)) { min = Math.min(min, Math.abs(curr - prev) || min); } prev = curr; }; for(i = 0, ilen = values.length; i < ilen; ++i){ curr = scale.getPixelForValue(values[i]); updateMinAndPrev(); } prev = undefined; for(i = 0, ilen = scale.ticks.length; i < ilen; ++i){ curr = scale.getPixelForTick(i); updateMinAndPrev(); } return min; } function computeFitCategoryTraits(index, ruler, options, stackCount) { const thickness = options.barThickness; let size, ratio; if (isNullOrUndef(thickness)) { size = ruler.min * options.categoryPercentage; ratio = options.barPercentage; } else { size = thickness * stackCount; ratio = 1; } return { chunk: size / stackCount, ratio, start: ruler.pixels[index] - size / 2 }; } function computeFlexCategoryTraits(index, ruler, options, stackCount) { const pixels = ruler.pixels; const curr = pixels[index]; let prev = index > 0 ? pixels[index - 1] : null; let next = index < pixels.length - 1 ? pixels[index + 1] : null; const percent = options.categoryPercentage; if (prev === null) { prev = curr - (next === null ? ruler.end - ruler.start : next - curr); } if (next === null) { next = curr + curr - prev; } const start = curr - (curr - Math.min(prev, next)) / 2 * percent; const size = Math.abs(next - prev) / 2 * percent; return { chunk: size / stackCount, ratio: options.barPercentage, start }; } function parseFloatBar(entry, item, vScale, i) { const startValue = vScale.parse(entry[0], i); const endValue = vScale.parse(entry[1], i); const min = Math.min(startValue, endValue); const max = Math.max(startValue, endValue); let barStart = min; let barEnd = max; if (Math.abs(min) > Math.abs(max)) { barStart = max; barEnd = min; } item[vScale.axis] = barEnd; item._custom = { barStart, barEnd, start: startValue, end: endValue, min, max }; } function parseValue(entry, item, vScale, i) { if (isArray(entry)) { parseFloatBar(entry, item, vScale, i); } else { item[vScale.axis] = vScale.parse(entry, i); } return item; } function parseArrayOrPrimitive(meta, data, start, count) { const iScale = meta.iScale; const vScale = meta.vScale; const labels = iScale.getLabels(); const singleScale = iScale === vScale; const parsed = []; let i, ilen, item, entry; for(i = start, ilen = start + count; i < ilen; ++i){ entry = data[i]; item = {}; item[iScale.axis] = singleScale || iScale.parse(labels[i], i); parsed.push(parseValue(entry, item, vScale, i)); } return parsed; } function isFloatBar(custom) { return custom && custom.barStart !== undefined && custom.barEnd !== undefined; } function barSign(size, vScale, actualBase) { if (size !== 0) { return sign(size); } return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1); } function borderProps(properties) { let reverse, start, end, top, bottom; if (properties.horizontal) { reverse = properties.base > properties.x; start = 'left'; end = 'right'; } else { reverse = properties.base < properties.y; start = 'bottom'; end = 'top'; } if (reverse) { top = 'end'; bottom = 'start'; } else { top = 'start'; bottom = 'end'; } return { start, end, reverse, top, bottom }; } function setBorderSkipped(properties, options, stack, index) { let edge = options.borderSkipped; const res = {}; if (!edge) { properties.borderSkipped = res; return; } if (edge === true) { properties.borderSkipped = { top: true, right: true, bottom: true, left: true }; return; } const { start , end , reverse , top , bottom } = borderProps(properties); if (edge === 'middle' && stack) { properties.enableBorderRadius = true; if ((stack._top || 0) === index) { edge = top; } else if ((stack._bottom || 0) === index) { edge = bottom; } else { res[parseEdge(bottom, start, end, reverse)] = true; edge = top; } } res[parseEdge(edge, start, end, reverse)] = true; properties.borderSkipped = res; } function parseEdge(edge, a, b, reverse) { if (reverse) { edge = swap(edge, a, b); edge = startEnd(edge, b, a); } else { edge = startEnd(edge, a, b); } return edge; } function swap(orig, v1, v2) { return orig === v1 ? v2 : orig === v2 ? v1 : orig; } function startEnd(v, start, end) { return v === 'start' ? start : v === 'end' ? end : v; } function setInflateAmount(properties, { inflateAmount }, ratio) { properties.inflateAmount = inflateAmount === 'auto' ? ratio === 1 ? 0.33 : 0 : inflateAmount; } class BarController extends DatasetController { static id = 'bar'; static defaults = { datasetElementType: false, dataElementType: 'bar', categoryPercentage: 0.8, barPercentage: 0.9, grouped: true, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'base', 'width', 'height' ] } } }; static overrides = { scales: { _index_: { type: 'category', offset: true, grid: { offset: true } }, _value_: { type: 'linear', beginAtZero: true } } }; parsePrimitiveData(meta, data, start, count) { return parseArrayOrPrimitive(meta, data, start, count); } parseArrayData(meta, data, start, count) { return parseArrayOrPrimitive(meta, data, start, count); } parseObjectData(meta, data, start, count) { const { iScale , vScale } = meta; const { xAxisKey ='x' , yAxisKey ='y' } = this._parsing; const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; const parsed = []; let i, ilen, item, obj; for(i = start, ilen = start + count; i < ilen; ++i){ obj = data[i]; item = {}; item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); } return parsed; } updateRangeFromParsed(range, scale, parsed, stack) { super.updateRangeFromParsed(range, scale, parsed, stack); const custom = parsed._custom; if (custom && scale === this._cachedMeta.vScale) { range.min = Math.min(range.min, custom.min); range.max = Math.max(range.max, custom.max); } } getMaxOverflow() { return 0; } getLabelAndValue(index) { const meta = this._cachedMeta; const { iScale , vScale } = meta; const parsed = this.getParsed(index); const custom = parsed._custom; const value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]); return { label: '' + iScale.getLabelForValue(parsed[iScale.axis]), value }; } initialize() { this.enableOptionSharing = true; super.initialize(); const meta = this._cachedMeta; meta.stack = this.getDataset().stack; } update(mode) { const meta = this._cachedMeta; this.updateElements(meta.data, 0, meta.data.length, mode); } updateElements(bars, start, count, mode) { const reset = mode === 'reset'; const { index , _cachedMeta: { vScale } } = this; const base = vScale.getBasePixel(); const horizontal = vScale.isHorizontal(); const ruler = this._getRuler(); const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); for(let i = start; i < start + count; i++){ const parsed = this.getParsed(i); const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? { base, head: base } : this._calculateBarValuePixels(i); const ipixels = this._calculateBarIndexPixels(i, ruler); const stack = (parsed._stacks || {})[vScale.axis]; const properties = { horizontal, base: vpixels.base, enableBorderRadius: !stack || isFloatBar(parsed._custom) || index === stack._top || index === stack._bottom, x: horizontal ? vpixels.head : ipixels.center, y: horizontal ? ipixels.center : vpixels.head, height: horizontal ? ipixels.size : Math.abs(vpixels.size), width: horizontal ? Math.abs(vpixels.size) : ipixels.size }; if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode); } const options = properties.options || bars[i].options; setBorderSkipped(properties, options, stack, index); setInflateAmount(properties, options, ruler.ratio); this.updateElement(bars[i], i, properties, mode); } } _getStacks(last, dataIndex) { const { iScale } = this._cachedMeta; const metasets = iScale.getMatchingVisibleMetas(this._type).filter((meta)=>meta.controller.options.grouped); const stacked = iScale.options.stacked; const stacks = []; const currentParsed = this._cachedMeta.controller.getParsed(dataIndex); const iScaleValue = currentParsed && currentParsed[iScale.axis]; const skipNull = (meta)=>{ const parsed = meta._parsed.find((item)=>item[iScale.axis] === iScaleValue); const val = parsed && parsed[meta.vScale.axis]; if (isNullOrUndef(val) || isNaN(val)) { return true; } }; for (const meta of metasets){ if (dataIndex !== undefined && skipNull(meta)) { continue; } if (stacked === false || stacks.indexOf(meta.stack) === -1 || stacked === undefined && meta.stack === undefined) { stacks.push(meta.stack); } if (meta.index === last) { break; } } if (!stacks.length) { stacks.push(undefined); } return stacks; } _getStackCount(index) { return this._getStacks(undefined, index).length; } _getAxisCount() { return this._getAxis().length; } getFirstScaleIdForIndexAxis() { const scales = this.chart.scales; const indexScaleId = this.chart.options.indexAxis; return Object.keys(scales).filter((key)=>scales[key].axis === indexScaleId).shift(); } _getAxis() { const axis = {}; const firstScaleAxisId = this.getFirstScaleIdForIndexAxis(); for (const dataset of this.chart.data.datasets){ axis[valueOrDefault(this.chart.options.indexAxis === 'x' ? dataset.xAxisID : dataset.yAxisID, firstScaleAxisId)] = true; } return Object.keys(axis); } _getStackIndex(datasetIndex, name, dataIndex) { const stacks = this._getStacks(datasetIndex, dataIndex); const index = name !== undefined ? stacks.indexOf(name) : -1; return index === -1 ? stacks.length - 1 : index; } _getRuler() { const opts = this.options; const meta = this._cachedMeta; const iScale = meta.iScale; const pixels = []; let i, ilen; for(i = 0, ilen = meta.data.length; i < ilen; ++i){ pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i)); } const barThickness = opts.barThickness; const min = barThickness || computeMinSampleSize(meta); return { min, pixels, start: iScale._startPixel, end: iScale._endPixel, stackCount: this._getStackCount(), scale: iScale, grouped: opts.grouped, ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage }; } _calculateBarValuePixels(index) { const { _cachedMeta: { vScale , _stacked , index: datasetIndex } , options: { base: baseValue , minBarLength } } = this; const actualBase = baseValue || 0; const parsed = this.getParsed(index); const custom = parsed._custom; const floating = isFloatBar(custom); let value = parsed[vScale.axis]; let start = 0; let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value; let head, size; if (length !== value) { start = length - value; length = value; } if (floating) { value = custom.barStart; length = custom.barEnd - custom.barStart; if (value !== 0 && sign(value) !== sign(custom.barEnd)) { start = 0; } start += value; } const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; let base = vScale.getPixelForValue(startValue); if (this.chart.getDataVisibility(index)) { head = vScale.getPixelForValue(start + length); } else { head = base; } size = head - base; if (Math.abs(size) < minBarLength) { size = barSign(size, vScale, actualBase) * minBarLength; if (value === actualBase) { base -= size / 2; } const startPixel = vScale.getPixelForDecimal(0); const endPixel = vScale.getPixelForDecimal(1); const min = Math.min(startPixel, endPixel); const max = Math.max(startPixel, endPixel); base = Math.max(Math.min(base, max), min); head = base + size; if (_stacked && !floating) { parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base); } } if (base === vScale.getPixelForValue(actualBase)) { const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2; base += halfGrid; size -= halfGrid; } return { size, base, head, center: head + size / 2 }; } _calculateBarIndexPixels(index, ruler) { const scale = ruler.scale; const options = this.options; const skipNull = options.skipNull; const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity); let center, size; const axisCount = this._getAxisCount(); if (ruler.grouped) { const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount; const range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options, stackCount * axisCount) : computeFitCategoryTraits(index, ruler, options, stackCount * axisCount); const axisID = this.chart.options.indexAxis === 'x' ? this.getDataset().xAxisID : this.getDataset().yAxisID; const axisNumber = this._getAxis().indexOf(valueOrDefault(axisID, this.getFirstScaleIdForIndexAxis())); const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined) + axisNumber; center = range.start + range.chunk * stackIndex + range.chunk / 2; size = Math.min(maxBarThickness, range.chunk * range.ratio); } else { center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index); size = Math.min(maxBarThickness, ruler.min * ruler.ratio); } return { base: center - size / 2, head: center + size / 2, center, size }; } draw() { const meta = this._cachedMeta; const vScale = meta.vScale; const rects = meta.data; const ilen = rects.length; let i = 0; for(; i < ilen; ++i){ if (this.getParsed(i)[vScale.axis] !== null && !rects[i].hidden) { rects[i].draw(this._ctx); } } } } class BubbleController extends DatasetController { static id = 'bubble'; static defaults = { datasetElementType: false, dataElementType: 'point', animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'borderWidth', 'radius' ] } } }; static overrides = { scales: { x: { type: 'linear' }, y: { type: 'linear' } } }; initialize() { this.enableOptionSharing = true; super.initialize(); } parsePrimitiveData(meta, data, start, count) { const parsed = super.parsePrimitiveData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ parsed[i]._custom = this.resolveDataElementOptions(i + start).radius; } return parsed; } parseArrayData(meta, data, start, count) { const parsed = super.parseArrayData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ const item = data[start + i]; parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius); } return parsed; } parseObjectData(meta, data, start, count) { const parsed = super.parseObjectData(meta, data, start, count); for(let i = 0; i < parsed.length; i++){ const item = data[start + i]; parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius); } return parsed; } getMaxOverflow() { const data = this._cachedMeta.data; let max = 0; for(let i = data.length - 1; i >= 0; --i){ max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); } return max > 0 && max; } getLabelAndValue(index) { const meta = this._cachedMeta; const labels = this.chart.data.labels || []; const { xScale , yScale } = meta; const parsed = this.getParsed(index); const x = xScale.getLabelForValue(parsed.x); const y = yScale.getLabelForValue(parsed.y); const r = parsed._custom; return { label: labels[index] || '', value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' }; } update(mode) { const points = this._cachedMeta.data; this.updateElements(points, 0, points.length, mode); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale } = this._cachedMeta; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); const iAxis = iScale.axis; const vAxis = vScale.axis; for(let i = start; i < start + count; i++){ const point = points[i]; const parsed = !reset && this.getParsed(i); const properties = {}; const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]); const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]); properties.skip = isNaN(iPixel) || isNaN(vPixel); if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); if (reset) { properties.options.radius = 0; } } this.updateElement(point, i, properties, mode); } } resolveDataElementOptions(index, mode) { const parsed = this.getParsed(index); let values = super.resolveDataElementOptions(index, mode); if (values.$shared) { values = Object.assign({}, values, { $shared: false }); } const radius = values.radius; if (mode !== 'active') { values.radius = 0; } values.radius += valueOrDefault(parsed && parsed._custom, radius); return values; } } function getRatioAndOffset(rotation, circumference, cutout) { let ratioX = 1; let ratioY = 1; let offsetX = 0; let offsetY = 0; if (circumference < TAU) { const startAngle = rotation; const endAngle = startAngle + circumference; const startX = Math.cos(startAngle); const startY = Math.sin(startAngle); const endX = Math.cos(endAngle); const endY = Math.sin(endAngle); const calcMax = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout); const calcMin = (angle, a, b)=>_angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout); const maxX = calcMax(0, startX, endX); const maxY = calcMax(HALF_PI, startY, endY); const minX = calcMin(PI, startX, endX); const minY = calcMin(PI + HALF_PI, startY, endY); ratioX = (maxX - minX) / 2; ratioY = (maxY - minY) / 2; offsetX = -(maxX + minX) / 2; offsetY = -(maxY + minY) / 2; } return { ratioX, ratioY, offsetX, offsetY }; } class DoughnutController extends DatasetController { static id = 'doughnut'; static defaults = { datasetElementType: false, dataElementType: 'arc', animation: { animateRotate: true, animateScale: false }, animations: { numbers: { type: 'number', properties: [ 'circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing' ] } }, cutout: '50%', rotation: 0, circumference: 360, radius: '100%', spacing: 0, indexAxis: 'r' }; static descriptors = { _scriptable: (name)=>name !== 'spacing', _indexable: (name)=>name !== 'spacing' && !name.startsWith('borderDash') && !name.startsWith('hoverBorderDash') }; static overrides = { aspectRatio: 1, plugins: { legend: { labels: { generateLabels (chart) { const data = chart.data; const { labels: { pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options; if (data.labels.length && data.datasets.length) { return data.labels.map((label, i)=>{ const meta = chart.getDatasetMeta(0); const style = meta.controller.getStyle(i); return { text: label, fillStyle: style.backgroundColor, fontColor: color, hidden: !chart.getDataVisibility(i), lineDash: style.borderDash, lineDashOffset: style.borderDashOffset, lineJoin: style.borderJoinStyle, lineWidth: style.borderWidth, strokeStyle: style.borderColor, textAlign: textAlign, pointStyle: pointStyle, borderRadius: useBorderRadius && (borderRadius || style.borderRadius), index: i }; }); } return []; } }, onClick (e, legendItem, legend) { legend.chart.toggleDataVisibility(legendItem.index); legend.chart.update(); } } } }; constructor(chart, datasetIndex){ super(chart, datasetIndex); this.enableOptionSharing = true; this.innerRadius = undefined; this.outerRadius = undefined; this.offsetX = undefined; this.offsetY = undefined; } linkScales() {} parse(start, count) { const data = this.getDataset().data; const meta = this._cachedMeta; if (this._parsing === false) { meta._parsed = data; } else { let getter = (i)=>+data[i]; if (isObject(data[start])) { const { key ='value' } = this._parsing; getter = (i)=>+resolveObjectKey(data[i], key); } let i, ilen; for(i = start, ilen = start + count; i < ilen; ++i){ meta._parsed[i] = getter(i); } } } _getRotation() { return toRadians(this.options.rotation - 90); } _getCircumference() { return toRadians(this.options.circumference); } _getRotationExtents() { let min = TAU; let max = -TAU; for(let i = 0; i < this.chart.data.datasets.length; ++i){ if (this.chart.isDatasetVisible(i) && this.chart.getDatasetMeta(i).type === this._type) { const controller = this.chart.getDatasetMeta(i).controller; const rotation = controller._getRotation(); const circumference = controller._getCircumference(); min = Math.min(min, rotation); max = Math.max(max, rotation + circumference); } } return { rotation: min, circumference: max - min }; } update(mode) { const chart = this.chart; const { chartArea } = chart; const meta = this._cachedMeta; const arcs = meta.data; const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing; const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0); const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1); const chartWeight = this._getRingWeight(this.index); const { circumference , rotation } = this._getRotationExtents(); const { ratioX , ratioY , offsetX , offsetY } = getRatioAndOffset(rotation, circumference, cutout); const maxWidth = (chartArea.width - spacing) / ratioX; const maxHeight = (chartArea.height - spacing) / ratioY; const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); const outerRadius = toDimension(this.options.radius, maxRadius); const innerRadius = Math.max(outerRadius * cutout, 0); const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal(); this.offsetX = offsetX * outerRadius; this.offsetY = offsetY * outerRadius; meta.total = this.calculateTotal(); this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index); this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0); this.updateElements(arcs, 0, arcs.length, mode); } _circumference(i, reset) { const opts = this.options; const meta = this._cachedMeta; const circumference = this._getCircumference(); if (reset && opts.animation.animateRotate || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) { return 0; } return this.calculateCircumference(meta._parsed[i] * circumference / TAU); } updateElements(arcs, start, count, mode) { const reset = mode === 'reset'; const chart = this.chart; const chartArea = chart.chartArea; const opts = chart.options; const animationOpts = opts.animation; const centerX = (chartArea.left + chartArea.right) / 2; const centerY = (chartArea.top + chartArea.bottom) / 2; const animateScale = reset && animationOpts.animateScale; const innerRadius = animateScale ? 0 : this.innerRadius; const outerRadius = animateScale ? 0 : this.outerRadius; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); let startAngle = this._getRotation(); let i; for(i = 0; i < start; ++i){ startAngle += this._circumference(i, reset); } for(i = start; i < start + count; ++i){ const circumference = this._circumference(i, reset); const arc = arcs[i]; const properties = { x: centerX + this.offsetX, y: centerY + this.offsetY, startAngle, endAngle: startAngle + circumference, circumference, outerRadius, innerRadius }; if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode); } startAngle += circumference; this.updateElement(arc, i, properties, mode); } } calculateTotal() { const meta = this._cachedMeta; const metaData = meta.data; let total = 0; let i; for(i = 0; i < metaData.length; i++){ const value = meta._parsed[i]; if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) { total += Math.abs(value); } } return total; } calculateCircumference(value) { const total = this._cachedMeta.total; if (total > 0 && !isNaN(value)) { return TAU * (Math.abs(value) / total); } return 0; } getLabelAndValue(index) { const meta = this._cachedMeta; const chart = this.chart; const labels = chart.data.labels || []; const value = formatNumber(meta._parsed[index], chart.options.locale); return { label: labels[index] || '', value }; } getMaxBorderWidth(arcs) { let max = 0; const chart = this.chart; let i, ilen, meta, controller, options; if (!arcs) { for(i = 0, ilen = chart.data.datasets.length; i < ilen; ++i){ if (chart.isDatasetVisible(i)) { meta = chart.getDatasetMeta(i); arcs = meta.data; controller = meta.controller; break; } } } if (!arcs) { return 0; } for(i = 0, ilen = arcs.length; i < ilen; ++i){ options = controller.resolveDataElementOptions(i); if (options.borderAlign !== 'inner') { max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); } } return max; } getMaxOffset(arcs) { let max = 0; for(let i = 0, ilen = arcs.length; i < ilen; ++i){ const options = this.resolveDataElementOptions(i); max = Math.max(max, options.offset || 0, options.hoverOffset || 0); } return max; } _getRingWeightOffset(datasetIndex) { let ringWeightOffset = 0; for(let i = 0; i < datasetIndex; ++i){ if (this.chart.isDatasetVisible(i)) { ringWeightOffset += this._getRingWeight(i); } } return ringWeightOffset; } _getRingWeight(datasetIndex) { return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); } _getVisibleDatasetWeightTotal() { return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; } } class LineController extends DatasetController { static id = 'line'; static defaults = { datasetElementType: 'line', dataElementType: 'point', showLine: true, spanGaps: false }; static overrides = { scales: { _index_: { type: 'category' }, _value_: { type: 'linear' } } }; initialize() { this.enableOptionSharing = true; this.supportsDecimation = true; super.initialize(); } update(mode) { const meta = this._cachedMeta; const { dataset: line , data: points = [] , _dataset } = meta; const animationsDisabled = this.chart._animationsDisabled; let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); this._drawStart = start; this._drawCount = count; if (_scaleRangesChanged(meta)) { start = 0; count = points.length; } line._chart = this.chart; line._datasetIndex = this.index; line._decimated = !!_dataset._decimated; line.points = points; const options = this.resolveDatasetElementOptions(mode); if (!this.options.showLine) { options.borderWidth = 0; } options.segment = this.options.segment; this.updateElement(line, undefined, { animated: !animationsDisabled, options }, mode); this.updateElements(points, start, count, mode); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; const { sharedOptions , includeOptions } = this._getSharedOptions(start, mode); const iAxis = iScale.axis; const vAxis = vScale.axis; const { spanGaps , segment } = this.options; const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; const end = start + count; const pointsCount = points.length; let prevParsed = start > 0 && this.getParsed(start - 1); for(let i = 0; i < pointsCount; ++i){ const point = points[i]; const properties = directUpdate ? point : {}; if (i < start || i >= end) { properties.skip = true; continue; } const parsed = this.getParsed(i); const nullData = isNullOrUndef(parsed[vAxis]); const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; if (segment) { properties.parsed = parsed; properties.raw = _dataset.data[i]; } if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); } if (!directUpdate) { this.updateElement(point, i, properties, mode); } prevParsed = parsed; } } getMaxOverflow() { const meta = this._cachedMeta; const dataset = meta.dataset; const border = dataset.options && dataset.options.borderWidth || 0; const data = meta.data || []; if (!data.length) { return border; } const firstPoint = data[0].size(this.resolveDataElementOptions(0)); const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); return Math.max(border, firstPoint, lastPoint) / 2; } draw() { const meta = this._cachedMeta; meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis); super.draw(); } } class PolarAreaController extends DatasetController { static id = 'polarArea'; static defaults = { dataElementType: 'arc', animation: { animateRotate: true, animateScale: true }, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius' ] } }, indexAxis: 'r', startAngle: 0 }; static overrides = { aspectRatio: 1, plugins: { legend: { labels: { generateLabels (chart) { const data = chart.data; if (data.labels.length && data.datasets.length) { const { labels: { pointStyle , color } } = chart.legend.options; return data.labels.map((label, i)=>{ const meta = chart.getDatasetMeta(0); const style = meta.controller.getStyle(i); return { text: label, fillStyle: style.backgroundColor, strokeStyle: style.borderColor, fontColor: color, lineWidth: style.borderWidth, pointStyle: pointStyle, hidden: !chart.getDataVisibility(i), index: i }; }); } return []; } }, onClick (e, legendItem, legend) { legend.chart.toggleDataVisibility(legendItem.index); legend.chart.update(); } } }, scales: { r: { type: 'radialLinear', angleLines: { display: false }, beginAtZero: true, grid: { circular: true }, pointLabels: { display: false }, startAngle: 0 } } }; constructor(chart, datasetIndex){ super(chart, datasetIndex); this.innerRadius = undefined; this.outerRadius = undefined; } getLabelAndValue(index) { const meta = this._cachedMeta; const chart = this.chart; const labels = chart.data.labels || []; const value = formatNumber(meta._parsed[index].r, chart.options.locale); return { label: labels[index] || '', value }; } parseObjectData(meta, data, start, count) { return _parseObjectDataRadialScale.bind(this)(meta, data, start, count); } update(mode) { const arcs = this._cachedMeta.data; this._updateRadius(); this.updateElements(arcs, 0, arcs.length, mode); } getMinMax() { const meta = this._cachedMeta; const range = { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY }; meta.data.forEach((element, index)=>{ const parsed = this.getParsed(index).r; if (!isNaN(parsed) && this.chart.getDataVisibility(index)) { if (parsed < range.min) { range.min = parsed; } if (parsed > range.max) { range.max = parsed; } } }); return range; } _updateRadius() { const chart = this.chart; const chartArea = chart.chartArea; const opts = chart.options; const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); const outerRadius = Math.max(minSize / 2, 0); const innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0); const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); this.outerRadius = outerRadius - radiusLength * this.index; this.innerRadius = this.outerRadius - radiusLength; } updateElements(arcs, start, count, mode) { const reset = mode === 'reset'; const chart = this.chart; const opts = chart.options; const animationOpts = opts.animation; const scale = this._cachedMeta.rScale; const centerX = scale.xCenter; const centerY = scale.yCenter; const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI; let angle = datasetStartAngle; let i; const defaultAngle = 360 / this.countVisibleElements(); for(i = 0; i < start; ++i){ angle += this._computeAngle(i, mode, defaultAngle); } for(i = start; i < start + count; i++){ const arc = arcs[i]; let startAngle = angle; let endAngle = angle + this._computeAngle(i, mode, defaultAngle); let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(this.getParsed(i).r) : 0; angle = endAngle; if (reset) { if (animationOpts.animateScale) { outerRadius = 0; } if (animationOpts.animateRotate) { startAngle = endAngle = datasetStartAngle; } } const properties = { x: centerX, y: centerY, innerRadius: 0, outerRadius, startAngle, endAngle, options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode) }; this.updateElement(arc, i, properties, mode); } } countVisibleElements() { const meta = this._cachedMeta; let count = 0; meta.data.forEach((element, index)=>{ if (!isNaN(this.getParsed(index).r) && this.chart.getDataVisibility(index)) { count++; } }); return count; } _computeAngle(index, mode, defaultAngle) { return this.chart.getDataVisibility(index) ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle) : 0; } } class PieController extends DoughnutController { static id = 'pie'; static defaults = { cutout: 0, rotation: 0, circumference: 360, radius: '100%' }; } class RadarController extends DatasetController { static id = 'radar'; static defaults = { datasetElementType: 'line', dataElementType: 'point', indexAxis: 'r', showLine: true, elements: { line: { fill: 'start' } } }; static overrides = { aspectRatio: 1, scales: { r: { type: 'radialLinear' } } }; getLabelAndValue(index) { const vScale = this._cachedMeta.vScale; const parsed = this.getParsed(index); return { label: vScale.getLabels()[index], value: '' + vScale.getLabelForValue(parsed[vScale.axis]) }; } parseObjectData(meta, data, start, count) { return _parseObjectDataRadialScale.bind(this)(meta, data, start, count); } update(mode) { const meta = this._cachedMeta; const line = meta.dataset; const points = meta.data || []; const labels = meta.iScale.getLabels(); line.points = points; if (mode !== 'resize') { const options = this.resolveDatasetElementOptions(mode); if (!this.options.showLine) { options.borderWidth = 0; } const properties = { _loop: true, _fullLoop: labels.length === points.length, options }; this.updateElement(line, undefined, properties, mode); } this.updateElements(points, 0, points.length, mode); } updateElements(points, start, count, mode) { const scale = this._cachedMeta.rScale; const reset = mode === 'reset'; for(let i = start; i < start + count; i++){ const point = points[i]; const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode); const pointPosition = scale.getPointPositionForValue(i, this.getParsed(i).r); const x = reset ? scale.xCenter : pointPosition.x; const y = reset ? scale.yCenter : pointPosition.y; const properties = { x, y, angle: pointPosition.angle, skip: isNaN(x) || isNaN(y), options }; this.updateElement(point, i, properties, mode); } } } class ScatterController extends DatasetController { static id = 'scatter'; static defaults = { datasetElementType: false, dataElementType: 'point', showLine: false, fill: false }; static overrides = { interaction: { mode: 'point' }, scales: { x: { type: 'linear' }, y: { type: 'linear' } } }; getLabelAndValue(index) { const meta = this._cachedMeta; const labels = this.chart.data.labels || []; const { xScale , yScale } = meta; const parsed = this.getParsed(index); const x = xScale.getLabelForValue(parsed.x); const y = yScale.getLabelForValue(parsed.y); return { label: labels[index] || '', value: '(' + x + ', ' + y + ')' }; } update(mode) { const meta = this._cachedMeta; const { data: points = [] } = meta; const animationsDisabled = this.chart._animationsDisabled; let { start , count } = _getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); this._drawStart = start; this._drawCount = count; if (_scaleRangesChanged(meta)) { start = 0; count = points.length; } if (this.options.showLine) { if (!this.datasetElementType) { this.addElements(); } const { dataset: line , _dataset } = meta; line._chart = this.chart; line._datasetIndex = this.index; line._decimated = !!_dataset._decimated; line.points = points; const options = this.resolveDatasetElementOptions(mode); options.segment = this.options.segment; this.updateElement(line, undefined, { animated: !animationsDisabled, options }, mode); } else if (this.datasetElementType) { delete meta.dataset; this.datasetElementType = false; } this.updateElements(points, start, count, mode); } addElements() { const { showLine } = this.options; if (!this.datasetElementType && showLine) { this.datasetElementType = this.chart.registry.getElement('line'); } super.addElements(); } updateElements(points, start, count, mode) { const reset = mode === 'reset'; const { iScale , vScale , _stacked , _dataset } = this._cachedMeta; const firstOpts = this.resolveDataElementOptions(start, mode); const sharedOptions = this.getSharedOptions(firstOpts); const includeOptions = this.includeOptions(mode, sharedOptions); const iAxis = iScale.axis; const vAxis = vScale.axis; const { spanGaps , segment } = this.options; const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; const directUpdate = this.chart._animationsDisabled || reset || mode === 'none'; let prevParsed = start > 0 && this.getParsed(start - 1); for(let i = start; i < start + count; ++i){ const point = points[i]; const parsed = this.getParsed(i); const properties = directUpdate ? point : {}; const nullData = isNullOrUndef(parsed[vAxis]); const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i); const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i); properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData; properties.stop = i > 0 && Math.abs(parsed[iAxis] - prevParsed[iAxis]) > maxGapLength; if (segment) { properties.parsed = parsed; properties.raw = _dataset.data[i]; } if (includeOptions) { properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode); } if (!directUpdate) { this.updateElement(point, i, properties, mode); } prevParsed = parsed; } this.updateSharedOptions(sharedOptions, mode, firstOpts); } getMaxOverflow() { const meta = this._cachedMeta; const data = meta.data || []; if (!this.options.showLine) { let max = 0; for(let i = data.length - 1; i >= 0; --i){ max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2); } return max > 0 && max; } const dataset = meta.dataset; const border = dataset.options && dataset.options.borderWidth || 0; if (!data.length) { return border; } const firstPoint = data[0].size(this.resolveDataElementOptions(0)); const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1)); return Math.max(border, firstPoint, lastPoint) / 2; } } var controllers = /*#__PURE__*/Object.freeze({ __proto__: null, BarController: BarController, BubbleController: BubbleController, DoughnutController: DoughnutController, LineController: LineController, PieController: PieController, PolarAreaController: PolarAreaController, RadarController: RadarController, ScatterController: ScatterController }); /** * @namespace Chart._adapters * @since 2.8.0 * @private */ function chart_abstract() { throw new Error('This method is not implemented: Check that a complete date adapter is provided.'); } /** * Date adapter (current used by the time scale) * @namespace Chart._adapters._date * @memberof Chart._adapters * @private */ class DateAdapterBase { /** * Override default date adapter methods. * Accepts type parameter to define options type. * @example * Chart._adapters._date.override<{myAdapterOption: string}>({ * init() { * console.log(this.options.myAdapterOption); * } * }) */ static override(members) { Object.assign(DateAdapterBase.prototype, members); } options; constructor(options){ this.options = options || {}; } // eslint-disable-next-line @typescript-eslint/no-empty-function init() {} formats() { return chart_abstract(); } parse() { return chart_abstract(); } format() { return chart_abstract(); } add() { return chart_abstract(); } diff() { return chart_abstract(); } startOf() { return chart_abstract(); } endOf() { return chart_abstract(); } } var adapters = { _date: DateAdapterBase }; function binarySearch(metaset, axis, value, intersect) { const { controller , data , _sorted } = metaset; const iScale = controller._cachedMeta.iScale; const spanGaps = metaset.dataset ? metaset.dataset.options ? metaset.dataset.options.spanGaps : null : null; if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) { const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; if (!intersect) { const result = lookupMethod(data, axis, value); if (spanGaps) { const { vScale } = controller._cachedMeta; const { _parsed } = metaset; const distanceToDefinedLo = _parsed.slice(0, result.lo + 1).reverse().findIndex((point)=>!isNullOrUndef(point[vScale.axis])); result.lo -= Math.max(0, distanceToDefinedLo); const distanceToDefinedHi = _parsed.slice(result.hi).findIndex((point)=>!isNullOrUndef(point[vScale.axis])); result.hi += Math.max(0, distanceToDefinedHi); } return result; } else if (controller._sharedOptions) { const el = data[0]; const range = typeof el.getRange === 'function' && el.getRange(axis); if (range) { const start = lookupMethod(data, axis, value - range); const end = lookupMethod(data, axis, value + range); return { lo: start.lo, hi: end.hi }; } } } return { lo: 0, hi: data.length - 1 }; } function evaluateInteractionItems(chart, axis, position, handler, intersect) { const metasets = chart.getSortedVisibleDatasetMetas(); const value = position[axis]; for(let i = 0, ilen = metasets.length; i < ilen; ++i){ const { index , data } = metasets[i]; const { lo , hi } = binarySearch(metasets[i], axis, value, intersect); for(let j = lo; j <= hi; ++j){ const element = data[j]; if (!element.skip) { handler(element, index, j); } } } } function getDistanceMetricForAxis(axis) { const useX = axis.indexOf('x') !== -1; const useY = axis.indexOf('y') !== -1; return function(pt1, pt2) { const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); }; } function getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) { const items = []; if (!includeInvisible && !chart.isPointInArea(position)) { return items; } const evaluationFunc = function(element, datasetIndex, index) { if (!includeInvisible && !_isPointInArea(element, chart.chartArea, 0)) { return; } if (element.inRange(position.x, position.y, useFinalPosition)) { items.push({ element, datasetIndex, index }); } }; evaluateInteractionItems(chart, axis, position, evaluationFunc, true); return items; } function getNearestRadialItems(chart, position, axis, useFinalPosition) { let items = []; function evaluationFunc(element, datasetIndex, index) { const { startAngle , endAngle } = element.getProps([ 'startAngle', 'endAngle' ], useFinalPosition); const { angle } = getAngleFromPoint(element, { x: position.x, y: position.y }); if (_angleBetween(angle, startAngle, endAngle)) { items.push({ element, datasetIndex, index }); } } evaluateInteractionItems(chart, axis, position, evaluationFunc); return items; } function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { let items = []; const distanceMetric = getDistanceMetricForAxis(axis); let minDistance = Number.POSITIVE_INFINITY; function evaluationFunc(element, datasetIndex, index) { const inRange = element.inRange(position.x, position.y, useFinalPosition); if (intersect && !inRange) { return; } const center = element.getCenterPoint(useFinalPosition); const pointInArea = !!includeInvisible || chart.isPointInArea(center); if (!pointInArea && !inRange) { return; } const distance = distanceMetric(position, center); if (distance < minDistance) { items = [ { element, datasetIndex, index } ]; minDistance = distance; } else if (distance === minDistance) { items.push({ element, datasetIndex, index }); } } evaluateInteractionItems(chart, axis, position, evaluationFunc); return items; } function getNearestItems(chart, position, axis, intersect, useFinalPosition, includeInvisible) { if (!includeInvisible && !chart.isPointInArea(position)) { return []; } return axis === 'r' && !intersect ? getNearestRadialItems(chart, position, axis, useFinalPosition) : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition, includeInvisible); } function getAxisItems(chart, position, axis, intersect, useFinalPosition) { const items = []; const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; let intersectsItem = false; evaluateInteractionItems(chart, axis, position, (element, datasetIndex, index)=>{ if (element[rangeMethod] && element[rangeMethod](position[axis], useFinalPosition)) { items.push({ element, datasetIndex, index }); intersectsItem = intersectsItem || element.inRange(position.x, position.y, useFinalPosition); } }); if (intersect && !intersectsItem) { return []; } return items; } var Interaction = { evaluateInteractionItems, modes: { index (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); const axis = options.axis || 'x'; const includeInvisible = options.includeInvisible || false; const items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); const elements = []; if (!items.length) { return []; } chart.getSortedVisibleDatasetMetas().forEach((meta)=>{ const index = items[0].index; const element = meta.data[index]; if (element && !element.skip) { elements.push({ element, datasetIndex: meta.index, index }); } }); return elements; }, dataset (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; let items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible) : getNearestItems(chart, position, axis, false, useFinalPosition, includeInvisible); if (items.length > 0) { const datasetIndex = items[0].datasetIndex; const data = chart.getDatasetMeta(datasetIndex).data; items = []; for(let i = 0; i < data.length; ++i){ items.push({ element: data[i], datasetIndex, index: i }); } } return items; }, point (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; return getIntersectItems(chart, position, axis, useFinalPosition, includeInvisible); }, nearest (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); const axis = options.axis || 'xy'; const includeInvisible = options.includeInvisible || false; return getNearestItems(chart, position, axis, options.intersect, useFinalPosition, includeInvisible); }, x (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); return getAxisItems(chart, position, 'x', options.intersect, useFinalPosition); }, y (chart, e, options, useFinalPosition) { const position = getRelativePosition(e, chart); return getAxisItems(chart, position, 'y', options.intersect, useFinalPosition); } } }; const STATIC_POSITIONS = [ 'left', 'top', 'right', 'bottom' ]; function filterByPosition(array, position) { return array.filter((v)=>v.pos === position); } function filterDynamicPositionByAxis(array, axis) { return array.filter((v)=>STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); } function sortByWeight(array, reverse) { return array.sort((a, b)=>{ const v0 = reverse ? b : a; const v1 = reverse ? a : b; return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight; }); } function wrapBoxes(boxes) { const layoutBoxes = []; let i, ilen, box, pos, stack, stackWeight; for(i = 0, ilen = (boxes || []).length; i < ilen; ++i){ box = boxes[i]; ({ position: pos , options: { stack , stackWeight =1 } } = box); layoutBoxes.push({ index: i, box, pos, horizontal: box.isHorizontal(), weight: box.weight, stack: stack && pos + stack, stackWeight }); } return layoutBoxes; } function buildStacks(layouts) { const stacks = {}; for (const wrap of layouts){ const { stack , pos , stackWeight } = wrap; if (!stack || !STATIC_POSITIONS.includes(pos)) { continue; } const _stack = stacks[stack] || (stacks[stack] = { count: 0, placed: 0, weight: 0, size: 0 }); _stack.count++; _stack.weight += stackWeight; } return stacks; } function setLayoutDims(layouts, params) { const stacks = buildStacks(layouts); const { vBoxMaxWidth , hBoxMaxHeight } = params; let i, ilen, layout; for(i = 0, ilen = layouts.length; i < ilen; ++i){ layout = layouts[i]; const { fullSize } = layout.box; const stack = stacks[layout.stack]; const factor = stack && layout.stackWeight / stack.weight; if (layout.horizontal) { layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth; layout.height = hBoxMaxHeight; } else { layout.width = vBoxMaxWidth; layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight; } } return stacks; } function buildLayoutBoxes(boxes) { const layoutBoxes = wrapBoxes(boxes); const fullSize = sortByWeight(layoutBoxes.filter((wrap)=>wrap.box.fullSize), true); const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); return { fullSize, leftAndTop: left.concat(top), rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), chartArea: filterByPosition(layoutBoxes, 'chartArea'), vertical: left.concat(right).concat(centerVertical), horizontal: top.concat(bottom).concat(centerHorizontal) }; } function getCombinedMax(maxPadding, chartArea, a, b) { return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); } function updateMaxPadding(maxPadding, boxPadding) { maxPadding.top = Math.max(maxPadding.top, boxPadding.top); maxPadding.left = Math.max(maxPadding.left, boxPadding.left); maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); maxPadding.right = Math.max(maxPadding.right, boxPadding.right); } function updateDims(chartArea, params, layout, stacks) { const { pos , box } = layout; const maxPadding = chartArea.maxPadding; if (!isObject(pos)) { if (layout.size) { chartArea[pos] -= layout.size; } const stack = stacks[layout.stack] || { size: 0, count: 1 }; stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width); layout.size = stack.size / stack.count; chartArea[pos] += layout.size; } if (box.getPadding) { updateMaxPadding(maxPadding, box.getPadding()); } const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right')); const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom')); const widthChanged = newWidth !== chartArea.w; const heightChanged = newHeight !== chartArea.h; chartArea.w = newWidth; chartArea.h = newHeight; return layout.horizontal ? { same: widthChanged, other: heightChanged } : { same: heightChanged, other: widthChanged }; } function handleMaxPadding(chartArea) { const maxPadding = chartArea.maxPadding; function updatePos(pos) { const change = Math.max(maxPadding[pos] - chartArea[pos], 0); chartArea[pos] += change; return change; } chartArea.y += updatePos('top'); chartArea.x += updatePos('left'); updatePos('right'); updatePos('bottom'); } function getMargins(horizontal, chartArea) { const maxPadding = chartArea.maxPadding; function marginForPositions(positions) { const margin = { left: 0, top: 0, right: 0, bottom: 0 }; positions.forEach((pos)=>{ margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); }); return margin; } return horizontal ? marginForPositions([ 'left', 'right' ]) : marginForPositions([ 'top', 'bottom' ]); } function fitBoxes(boxes, chartArea, params, stacks) { const refitBoxes = []; let i, ilen, layout, box, refit, changed; for(i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i){ layout = boxes[i]; box = layout.box; box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea)); const { same , other } = updateDims(chartArea, params, layout, stacks); refit |= same && refitBoxes.length; changed = changed || other; if (!box.fullSize) { refitBoxes.push(layout); } } return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed; } function setBoxDims(box, left, top, width, height) { box.top = top; box.left = left; box.right = left + width; box.bottom = top + height; box.width = width; box.height = height; } function placeBoxes(boxes, chartArea, params, stacks) { const userPadding = params.padding; let { x , y } = chartArea; for (const layout of boxes){ const box = layout.box; const stack = stacks[layout.stack] || { count: 1, placed: 0, weight: 1 }; const weight = layout.stackWeight / stack.weight || 1; if (layout.horizontal) { const width = chartArea.w * weight; const height = stack.size || box.height; if (defined(stack.start)) { y = stack.start; } if (box.fullSize) { setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height); } else { setBoxDims(box, chartArea.left + stack.placed, y, width, height); } stack.start = y; stack.placed += width; y = box.bottom; } else { const height = chartArea.h * weight; const width = stack.size || box.width; if (defined(stack.start)) { x = stack.start; } if (box.fullSize) { setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top); } else { setBoxDims(box, x, chartArea.top + stack.placed, width, height); } stack.start = x; stack.placed += height; x = box.right; } } chartArea.x = x; chartArea.y = y; } var layouts = { addBox (chart, item) { if (!chart.boxes) { chart.boxes = []; } item.fullSize = item.fullSize || false; item.position = item.position || 'top'; item.weight = item.weight || 0; item._layers = item._layers || function() { return [ { z: 0, draw (chartArea) { item.draw(chartArea); } } ]; }; chart.boxes.push(item); }, removeBox (chart, layoutItem) { const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; if (index !== -1) { chart.boxes.splice(index, 1); } }, configure (chart, item, options) { item.fullSize = options.fullSize; item.position = options.position; item.weight = options.weight; }, update (chart, width, height, minPadding) { if (!chart) { return; } const padding = toPadding(chart.options.layout.padding); const availableWidth = Math.max(width - padding.width, 0); const availableHeight = Math.max(height - padding.height, 0); const boxes = buildLayoutBoxes(chart.boxes); const verticalBoxes = boxes.vertical; const horizontalBoxes = boxes.horizontal; each(chart.boxes, (box)=>{ if (typeof box.beforeLayout === 'function') { box.beforeLayout(); } }); const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap)=>wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1; const params = Object.freeze({ outerWidth: width, outerHeight: height, padding, availableWidth, availableHeight, vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount, hBoxMaxHeight: availableHeight / 2 }); const maxPadding = Object.assign({}, padding); updateMaxPadding(maxPadding, toPadding(minPadding)); const chartArea = Object.assign({ maxPadding, w: availableWidth, h: availableHeight, x: padding.left, y: padding.top }, padding); const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); fitBoxes(boxes.fullSize, chartArea, params, stacks); fitBoxes(verticalBoxes, chartArea, params, stacks); if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) { fitBoxes(verticalBoxes, chartArea, params, stacks); } handleMaxPadding(chartArea); placeBoxes(boxes.leftAndTop, chartArea, params, stacks); chartArea.x += chartArea.w; chartArea.y += chartArea.h; placeBoxes(boxes.rightAndBottom, chartArea, params, stacks); chart.chartArea = { left: chartArea.left, top: chartArea.top, right: chartArea.left + chartArea.w, bottom: chartArea.top + chartArea.h, height: chartArea.h, width: chartArea.w }; each(boxes.chartArea, (layout)=>{ const box = layout.box; Object.assign(box, chart.chartArea); box.update(chartArea.w, chartArea.h, { left: 0, top: 0, right: 0, bottom: 0 }); }); } }; class BasePlatform { acquireContext(canvas, aspectRatio) {} releaseContext(context) { return false; } addEventListener(chart, type, listener) {} removeEventListener(chart, type, listener) {} getDevicePixelRatio() { return 1; } getMaximumSize(element, width, height, aspectRatio) { width = Math.max(0, width || element.width); height = height || element.height; return { width, height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) }; } isAttached(canvas) { return true; } updateConfig(config) { } } class BasicPlatform extends BasePlatform { acquireContext(item) { return item && item.getContext && item.getContext('2d') || null; } updateConfig(config) { config.options.animation = false; } } const EXPANDO_KEY = '$chartjs'; const EVENT_TYPES = { touchstart: 'mousedown', touchmove: 'mousemove', touchend: 'mouseup', pointerenter: 'mouseenter', pointerdown: 'mousedown', pointermove: 'mousemove', pointerup: 'mouseup', pointerleave: 'mouseout', pointerout: 'mouseout' }; const isNullOrEmpty = (value)=>value === null || value === ''; function initCanvas(canvas, aspectRatio) { const style = canvas.style; const renderHeight = canvas.getAttribute('height'); const renderWidth = canvas.getAttribute('width'); canvas[EXPANDO_KEY] = { initial: { height: renderHeight, width: renderWidth, style: { display: style.display, height: style.height, width: style.width } } }; style.display = style.display || 'block'; style.boxSizing = style.boxSizing || 'border-box'; if (isNullOrEmpty(renderWidth)) { const displayWidth = readUsedSize(canvas, 'width'); if (displayWidth !== undefined) { canvas.width = displayWidth; } } if (isNullOrEmpty(renderHeight)) { if (canvas.style.height === '') { canvas.height = canvas.width / (aspectRatio || 2); } else { const displayHeight = readUsedSize(canvas, 'height'); if (displayHeight !== undefined) { canvas.height = displayHeight; } } } return canvas; } const eventListenerOptions = supportsEventListenerOptions ? { passive: true } : false; function addListener(node, type, listener) { if (node) { node.addEventListener(type, listener, eventListenerOptions); } } function removeListener(chart, type, listener) { if (chart && chart.canvas) { chart.canvas.removeEventListener(type, listener, eventListenerOptions); } } function fromNativeEvent(event, chart) { const type = EVENT_TYPES[event.type] || event.type; const { x , y } = getRelativePosition(event, chart); return { type, chart, native: event, x: x !== undefined ? x : null, y: y !== undefined ? y : null }; } function nodeListContains(nodeList, canvas) { for (const node of nodeList){ if (node === canvas || node.contains(canvas)) { return true; } } } function createAttachObserver(chart, type, listener) { const canvas = chart.canvas; const observer = new MutationObserver((entries)=>{ let trigger = false; for (const entry of entries){ trigger = trigger || nodeListContains(entry.addedNodes, canvas); trigger = trigger && !nodeListContains(entry.removedNodes, canvas); } if (trigger) { listener(); } }); observer.observe(document, { childList: true, subtree: true }); return observer; } function createDetachObserver(chart, type, listener) { const canvas = chart.canvas; const observer = new MutationObserver((entries)=>{ let trigger = false; for (const entry of entries){ trigger = trigger || nodeListContains(entry.removedNodes, canvas); trigger = trigger && !nodeListContains(entry.addedNodes, canvas); } if (trigger) { listener(); } }); observer.observe(document, { childList: true, subtree: true }); return observer; } const drpListeningCharts = new Map(); let oldDevicePixelRatio = 0; function onWindowResize() { const dpr = window.devicePixelRatio; if (dpr === oldDevicePixelRatio) { return; } oldDevicePixelRatio = dpr; drpListeningCharts.forEach((resize, chart)=>{ if (chart.currentDevicePixelRatio !== dpr) { resize(); } }); } function listenDevicePixelRatioChanges(chart, resize) { if (!drpListeningCharts.size) { window.addEventListener('resize', onWindowResize); } drpListeningCharts.set(chart, resize); } function unlistenDevicePixelRatioChanges(chart) { drpListeningCharts.delete(chart); if (!drpListeningCharts.size) { window.removeEventListener('resize', onWindowResize); } } function createResizeObserver(chart, type, listener) { const canvas = chart.canvas; const container = canvas && _getParentNode(canvas); if (!container) { return; } const resize = throttled((width, height)=>{ const w = container.clientWidth; listener(width, height); if (w < container.clientWidth) { listener(); } }, window); const observer = new ResizeObserver((entries)=>{ const entry = entries[0]; const width = entry.contentRect.width; const height = entry.contentRect.height; if (width === 0 && height === 0) { return; } resize(width, height); }); observer.observe(container); listenDevicePixelRatioChanges(chart, resize); return observer; } function releaseObserver(chart, type, observer) { if (observer) { observer.disconnect(); } if (type === 'resize') { unlistenDevicePixelRatioChanges(chart); } } function createProxyAndListen(chart, type, listener) { const canvas = chart.canvas; const proxy = throttled((event)=>{ if (chart.ctx !== null) { listener(fromNativeEvent(event, chart)); } }, chart); addListener(canvas, type, proxy); return proxy; } class DomPlatform extends BasePlatform { acquireContext(canvas, aspectRatio) { const context = canvas && canvas.getContext && canvas.getContext('2d'); if (context && context.canvas === canvas) { initCanvas(canvas, aspectRatio); return context; } return null; } releaseContext(context) { const canvas = context.canvas; if (!canvas[EXPANDO_KEY]) { return false; } const initial = canvas[EXPANDO_KEY].initial; [ 'height', 'width' ].forEach((prop)=>{ const value = initial[prop]; if (isNullOrUndef(value)) { canvas.removeAttribute(prop); } else { canvas.setAttribute(prop, value); } }); const style = initial.style || {}; Object.keys(style).forEach((key)=>{ canvas.style[key] = style[key]; }); canvas.width = canvas.width; delete canvas[EXPANDO_KEY]; return true; } addEventListener(chart, type, listener) { this.removeEventListener(chart, type); const proxies = chart.$proxies || (chart.$proxies = {}); const handlers = { attach: createAttachObserver, detach: createDetachObserver, resize: createResizeObserver }; const handler = handlers[type] || createProxyAndListen; proxies[type] = handler(chart, type, listener); } removeEventListener(chart, type) { const proxies = chart.$proxies || (chart.$proxies = {}); const proxy = proxies[type]; if (!proxy) { return; } const handlers = { attach: releaseObserver, detach: releaseObserver, resize: releaseObserver }; const handler = handlers[type] || removeListener; handler(chart, type, proxy); proxies[type] = undefined; } getDevicePixelRatio() { return window.devicePixelRatio; } getMaximumSize(canvas, width, height, aspectRatio) { return getMaximumSize(canvas, width, height, aspectRatio); } isAttached(canvas) { const container = canvas && _getParentNode(canvas); return !!(container && container.isConnected); } } function _detectPlatform(canvas) { if (!_isDomSupported() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) { return BasicPlatform; } return DomPlatform; } class chart_Element { static defaults = {}; static defaultRoutes = undefined; x; y; active = false; options; $animations; tooltipPosition(useFinalPosition) { const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return { x, y }; } hasValue() { return isNumber(this.x) && isNumber(this.y); } getProps(props, final) { const anims = this.$animations; if (!final || !anims) { // let's not create an object, if not needed return this; } const ret = {}; props.forEach((prop)=>{ ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop]; }); return ret; } } function autoSkip(scale, ticks) { const tickOpts = scale.options.ticks; const determinedMaxTicks = determineMaxTicks(scale); const ticksLimit = Math.min(tickOpts.maxTicksLimit || determinedMaxTicks, determinedMaxTicks); const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; const numMajorIndices = majorIndices.length; const first = majorIndices[0]; const last = majorIndices[numMajorIndices - 1]; const newTicks = []; if (numMajorIndices > ticksLimit) { skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); return newTicks; } const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); if (numMajorIndices > 0) { let i, ilen; const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); for(i = 0, ilen = numMajorIndices - 1; i < ilen; i++){ skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); } skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); return newTicks; } skip(ticks, newTicks, spacing); return newTicks; } function determineMaxTicks(scale) { const offset = scale.options.offset; const tickLength = scale._tickSize(); const maxScale = scale._length / tickLength + (offset ? 0 : 1); const maxChart = scale._maxLength / tickLength; return Math.floor(Math.min(maxScale, maxChart)); } function calculateSpacing(majorIndices, ticks, ticksLimit) { const evenMajorSpacing = getEvenSpacing(majorIndices); const spacing = ticks.length / ticksLimit; if (!evenMajorSpacing) { return Math.max(spacing, 1); } const factors = _factorize(evenMajorSpacing); for(let i = 0, ilen = factors.length - 1; i < ilen; i++){ const factor = factors[i]; if (factor > spacing) { return factor; } } return Math.max(spacing, 1); } function getMajorIndices(ticks) { const result = []; let i, ilen; for(i = 0, ilen = ticks.length; i < ilen; i++){ if (ticks[i].major) { result.push(i); } } return result; } function skipMajors(ticks, newTicks, majorIndices, spacing) { let count = 0; let next = majorIndices[0]; let i; spacing = Math.ceil(spacing); for(i = 0; i < ticks.length; i++){ if (i === next) { newTicks.push(ticks[i]); count++; next = majorIndices[count * spacing]; } } } function skip(ticks, newTicks, spacing, majorStart, majorEnd) { const start = valueOrDefault(majorStart, 0); const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); let count = 0; let length, i, next; spacing = Math.ceil(spacing); if (majorEnd) { length = majorEnd - majorStart; spacing = length / Math.floor(length / spacing); } next = start; while(next < 0){ count++; next = Math.round(start + count * spacing); } for(i = Math.max(start, 0); i < end; i++){ if (i === next) { newTicks.push(ticks[i]); count++; next = Math.round(start + count * spacing); } } } function getEvenSpacing(arr) { const len = arr.length; let i, diff; if (len < 2) { return false; } for(diff = arr[0], i = 1; i < len; ++i){ if (arr[i] - arr[i - 1] !== diff) { return false; } } return diff; } const reverseAlign = (align)=>align === 'left' ? 'right' : align === 'right' ? 'left' : align; const offsetFromEdge = (scale, edge, offset)=>edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset; const getTicksLimit = (ticksLength, maxTicksLimit)=>Math.min(maxTicksLimit || ticksLength, ticksLength); function sample(arr, numItems) { const result = []; const increment = arr.length / numItems; const len = arr.length; let i = 0; for(; i < len; i += increment){ result.push(arr[Math.floor(i)]); } return result; } function getPixelForGridLine(scale, index, offsetGridLines) { const length = scale.ticks.length; const validIndex = Math.min(index, length - 1); const start = scale._startPixel; const end = scale._endPixel; const epsilon = 1e-6; let lineValue = scale.getPixelForTick(validIndex); let offset; if (offsetGridLines) { if (length === 1) { offset = Math.max(lineValue - start, end - lineValue); } else if (index === 0) { offset = (scale.getPixelForTick(1) - lineValue) / 2; } else { offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; } lineValue += validIndex < index ? offset : -offset; if (lineValue < start - epsilon || lineValue > end + epsilon) { return; } } return lineValue; } function garbageCollect(caches, length) { each(caches, (cache)=>{ const gc = cache.gc; const gcLen = gc.length / 2; let i; if (gcLen > length) { for(i = 0; i < gcLen; ++i){ delete cache.data[gc[i]]; } gc.splice(0, gcLen); } }); } function getTickMarkLength(options) { return options.drawTicks ? options.tickLength : 0; } function getTitleHeight(options, fallback) { if (!options.display) { return 0; } const font = toFont(options.font, fallback); const padding = toPadding(options.padding); const lines = isArray(options.text) ? options.text.length : 1; return lines * font.lineHeight + padding.height; } function createScaleContext(parent, scale) { return createContext(parent, { scale, type: 'scale' }); } function createTickContext(parent, index, tick) { return createContext(parent, { tick, index, type: 'tick' }); } function titleAlign(align, position, reverse) { let ret = _toLeftRightCenter(align); if (reverse && position !== 'right' || !reverse && position === 'right') { ret = reverseAlign(ret); } return ret; } function titleArgs(scale, offset, position, align) { const { top , left , bottom , right , chart } = scale; const { chartArea , scales } = chart; let rotation = 0; let maxWidth, titleX, titleY; const height = bottom - top; const width = right - left; if (scale.isHorizontal()) { titleX = _alignStartEnd(align, left, right); if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; titleY = scales[positionAxisID].getPixelForValue(value) + height - offset; } else if (position === 'center') { titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset; } else { titleY = offsetFromEdge(scale, position, offset); } maxWidth = right - left; } else { if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; titleX = scales[positionAxisID].getPixelForValue(value) - width + offset; } else if (position === 'center') { titleX = (chartArea.left + chartArea.right) / 2 - width + offset; } else { titleX = offsetFromEdge(scale, position, offset); } titleY = _alignStartEnd(align, bottom, top); rotation = position === 'left' ? -HALF_PI : HALF_PI; } return { titleX, titleY, maxWidth, rotation }; } class Scale extends chart_Element { constructor(cfg){ super(); this.id = cfg.id; this.type = cfg.type; this.options = undefined; this.ctx = cfg.ctx; this.chart = cfg.chart; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.width = undefined; this.height = undefined; this._margins = { left: 0, right: 0, top: 0, bottom: 0 }; this.maxWidth = undefined; this.maxHeight = undefined; this.paddingTop = undefined; this.paddingBottom = undefined; this.paddingLeft = undefined; this.paddingRight = undefined; this.axis = undefined; this.labelRotation = undefined; this.min = undefined; this.max = undefined; this._range = undefined; this.ticks = []; this._gridLineItems = null; this._labelItems = null; this._labelSizes = null; this._length = 0; this._maxLength = 0; this._longestTextCache = {}; this._startPixel = undefined; this._endPixel = undefined; this._reversePixels = false; this._userMax = undefined; this._userMin = undefined; this._suggestedMax = undefined; this._suggestedMin = undefined; this._ticksLength = 0; this._borderValue = 0; this._cache = {}; this._dataLimitsCached = false; this.$context = undefined; } init(options) { this.options = options.setContext(this.getContext()); this.axis = options.axis; this._userMin = this.parse(options.min); this._userMax = this.parse(options.max); this._suggestedMin = this.parse(options.suggestedMin); this._suggestedMax = this.parse(options.suggestedMax); } parse(raw, index) { return raw; } getUserBounds() { let { _userMin , _userMax , _suggestedMin , _suggestedMax } = this; _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY); _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY); _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY); _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY); return { min: finiteOrDefault(_userMin, _suggestedMin), max: finiteOrDefault(_userMax, _suggestedMax), minDefined: isNumberFinite(_userMin), maxDefined: isNumberFinite(_userMax) }; } getMinMax(canStack) { let { min , max , minDefined , maxDefined } = this.getUserBounds(); let range; if (minDefined && maxDefined) { return { min, max }; } const metas = this.getMatchingVisibleMetas(); for(let i = 0, ilen = metas.length; i < ilen; ++i){ range = metas[i].controller.getMinMax(this, canStack); if (!minDefined) { min = Math.min(min, range.min); } if (!maxDefined) { max = Math.max(max, range.max); } } min = maxDefined && min > max ? max : min; max = minDefined && min > max ? min : max; return { min: finiteOrDefault(min, finiteOrDefault(max, min)), max: finiteOrDefault(max, finiteOrDefault(min, max)) }; } getPadding() { return { left: this.paddingLeft || 0, top: this.paddingTop || 0, right: this.paddingRight || 0, bottom: this.paddingBottom || 0 }; } getTicks() { return this.ticks; } getLabels() { const data = this.chart.data; return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; } getLabelItems(chartArea = this.chart.chartArea) { const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea)); return items; } beforeLayout() { this._cache = {}; this._dataLimitsCached = false; } beforeUpdate() { callback(this.options.beforeUpdate, [ this ]); } update(maxWidth, maxHeight, margins) { const { beginAtZero , grace , ticks: tickOpts } = this.options; const sampleSize = tickOpts.sampleSize; this.beforeUpdate(); this.maxWidth = maxWidth; this.maxHeight = maxHeight; this._margins = margins = Object.assign({ left: 0, right: 0, top: 0, bottom: 0 }, margins); this.ticks = null; this._labelSizes = null; this._gridLineItems = null; this._labelItems = null; this.beforeSetDimensions(); this.setDimensions(); this.afterSetDimensions(); this._maxLength = this.isHorizontal() ? this.width + margins.left + margins.right : this.height + margins.top + margins.bottom; if (!this._dataLimitsCached) { this.beforeDataLimits(); this.determineDataLimits(); this.afterDataLimits(); this._range = _addGrace(this, grace, beginAtZero); this._dataLimitsCached = true; } this.beforeBuildTicks(); this.ticks = this.buildTicks() || []; this.afterBuildTicks(); const samplingEnabled = sampleSize < this.ticks.length; this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks); this.configure(); this.beforeCalculateLabelRotation(); this.calculateLabelRotation(); this.afterCalculateLabelRotation(); if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) { this.ticks = autoSkip(this, this.ticks); this._labelSizes = null; this.afterAutoSkip(); } if (samplingEnabled) { this._convertTicksToLabels(this.ticks); } this.beforeFit(); this.fit(); this.afterFit(); this.afterUpdate(); } configure() { let reversePixels = this.options.reverse; let startPixel, endPixel; if (this.isHorizontal()) { startPixel = this.left; endPixel = this.right; } else { startPixel = this.top; endPixel = this.bottom; reversePixels = !reversePixels; } this._startPixel = startPixel; this._endPixel = endPixel; this._reversePixels = reversePixels; this._length = endPixel - startPixel; this._alignToPixels = this.options.alignToPixels; } afterUpdate() { callback(this.options.afterUpdate, [ this ]); } beforeSetDimensions() { callback(this.options.beforeSetDimensions, [ this ]); } setDimensions() { if (this.isHorizontal()) { this.width = this.maxWidth; this.left = 0; this.right = this.width; } else { this.height = this.maxHeight; this.top = 0; this.bottom = this.height; } this.paddingLeft = 0; this.paddingTop = 0; this.paddingRight = 0; this.paddingBottom = 0; } afterSetDimensions() { callback(this.options.afterSetDimensions, [ this ]); } _callHooks(name) { this.chart.notifyPlugins(name, this.getContext()); callback(this.options[name], [ this ]); } beforeDataLimits() { this._callHooks('beforeDataLimits'); } determineDataLimits() {} afterDataLimits() { this._callHooks('afterDataLimits'); } beforeBuildTicks() { this._callHooks('beforeBuildTicks'); } buildTicks() { return []; } afterBuildTicks() { this._callHooks('afterBuildTicks'); } beforeTickToLabelConversion() { callback(this.options.beforeTickToLabelConversion, [ this ]); } generateTickLabels(ticks) { const tickOpts = this.options.ticks; let i, ilen, tick; for(i = 0, ilen = ticks.length; i < ilen; i++){ tick = ticks[i]; tick.label = callback(tickOpts.callback, [ tick.value, i, ticks ], this); } } afterTickToLabelConversion() { callback(this.options.afterTickToLabelConversion, [ this ]); } beforeCalculateLabelRotation() { callback(this.options.beforeCalculateLabelRotation, [ this ]); } calculateLabelRotation() { const options = this.options; const tickOpts = options.ticks; const numTicks = getTicksLimit(this.ticks.length, options.ticks.maxTicksLimit); const minRotation = tickOpts.minRotation || 0; const maxRotation = tickOpts.maxRotation; let labelRotation = minRotation; let tickWidth, maxHeight, maxLabelDiagonal; if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) { this.labelRotation = minRotation; return; } const labelSizes = this._getLabelSizes(); const maxLabelWidth = labelSizes.widest.width; const maxLabelHeight = labelSizes.highest.height; const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth); tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1); if (maxLabelWidth + 6 > tickWidth) { tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); maxHeight = this.maxHeight - getTickMarkLength(options.grid) - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font); maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); labelRotation = toDegrees(Math.min(Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)), Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1)))); labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); } this.labelRotation = labelRotation; } afterCalculateLabelRotation() { callback(this.options.afterCalculateLabelRotation, [ this ]); } afterAutoSkip() {} beforeFit() { callback(this.options.beforeFit, [ this ]); } fit() { const minSize = { width: 0, height: 0 }; const { chart , options: { ticks: tickOpts , title: titleOpts , grid: gridOpts } } = this; const display = this._isVisible(); const isHorizontal = this.isHorizontal(); if (display) { const titleHeight = getTitleHeight(titleOpts, chart.options.font); if (isHorizontal) { minSize.width = this.maxWidth; minSize.height = getTickMarkLength(gridOpts) + titleHeight; } else { minSize.height = this.maxHeight; minSize.width = getTickMarkLength(gridOpts) + titleHeight; } if (tickOpts.display && this.ticks.length) { const { first , last , widest , highest } = this._getLabelSizes(); const tickPadding = tickOpts.padding * 2; const angleRadians = toRadians(this.labelRotation); const cos = Math.cos(angleRadians); const sin = Math.sin(angleRadians); if (isHorizontal) { const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height; minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding); } else { const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height; minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding); } this._calculatePadding(first, last, sin, cos); } } this._handleMargins(); if (isHorizontal) { this.width = this._length = chart.width - this._margins.left - this._margins.right; this.height = minSize.height; } else { this.width = minSize.width; this.height = this._length = chart.height - this._margins.top - this._margins.bottom; } } _calculatePadding(first, last, sin, cos) { const { ticks: { align , padding } , position } = this.options; const isRotated = this.labelRotation !== 0; const labelsBelowTicks = position !== 'top' && this.axis === 'x'; if (this.isHorizontal()) { const offsetLeft = this.getPixelForTick(0) - this.left; const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1); let paddingLeft = 0; let paddingRight = 0; if (isRotated) { if (labelsBelowTicks) { paddingLeft = cos * first.width; paddingRight = sin * last.height; } else { paddingLeft = sin * first.height; paddingRight = cos * last.width; } } else if (align === 'start') { paddingRight = last.width; } else if (align === 'end') { paddingLeft = first.width; } else if (align !== 'inner') { paddingLeft = first.width / 2; paddingRight = last.width / 2; } this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0); this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0); } else { let paddingTop = last.height / 2; let paddingBottom = first.height / 2; if (align === 'start') { paddingTop = 0; paddingBottom = first.height; } else if (align === 'end') { paddingTop = last.height; paddingBottom = 0; } this.paddingTop = paddingTop + padding; this.paddingBottom = paddingBottom + padding; } } _handleMargins() { if (this._margins) { this._margins.left = Math.max(this.paddingLeft, this._margins.left); this._margins.top = Math.max(this.paddingTop, this._margins.top); this._margins.right = Math.max(this.paddingRight, this._margins.right); this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom); } } afterFit() { callback(this.options.afterFit, [ this ]); } isHorizontal() { const { axis , position } = this.options; return position === 'top' || position === 'bottom' || axis === 'x'; } isFullSize() { return this.options.fullSize; } _convertTicksToLabels(ticks) { this.beforeTickToLabelConversion(); this.generateTickLabels(ticks); let i, ilen; for(i = 0, ilen = ticks.length; i < ilen; i++){ if (isNullOrUndef(ticks[i].label)) { ticks.splice(i, 1); ilen--; i--; } } this.afterTickToLabelConversion(); } _getLabelSizes() { let labelSizes = this._labelSizes; if (!labelSizes) { const sampleSize = this.options.ticks.sampleSize; let ticks = this.ticks; if (sampleSize < ticks.length) { ticks = sample(ticks, sampleSize); } this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length, this.options.ticks.maxTicksLimit); } return labelSizes; } _computeLabelSizes(ticks, length, maxTicksLimit) { const { ctx , _longestTextCache: caches } = this; const widths = []; const heights = []; const increment = Math.floor(length / getTicksLimit(length, maxTicksLimit)); let widestLabelSize = 0; let highestLabelSize = 0; let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; for(i = 0; i < length; i += increment){ label = ticks[i].label; tickFont = this._resolveTickFontOptions(i); ctx.font = fontString = tickFont.string; cache = caches[fontString] = caches[fontString] || { data: {}, gc: [] }; lineHeight = tickFont.lineHeight; width = height = 0; if (!isNullOrUndef(label) && !isArray(label)) { width = _measureText(ctx, cache.data, cache.gc, width, label); height = lineHeight; } else if (isArray(label)) { for(j = 0, jlen = label.length; j < jlen; ++j){ nestedLabel = label[j]; if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); height += lineHeight; } } } widths.push(width); heights.push(height); widestLabelSize = Math.max(width, widestLabelSize); highestLabelSize = Math.max(height, highestLabelSize); } garbageCollect(caches, length); const widest = widths.indexOf(widestLabelSize); const highest = heights.indexOf(highestLabelSize); const valueAt = (idx)=>({ width: widths[idx] || 0, height: heights[idx] || 0 }); return { first: valueAt(0), last: valueAt(length - 1), widest: valueAt(widest), highest: valueAt(highest), widths, heights }; } getLabelForValue(value) { return value; } getPixelForValue(value, index) { return NaN; } getValueForPixel(pixel) {} getPixelForTick(index) { const ticks = this.ticks; if (index < 0 || index > ticks.length - 1) { return null; } return this.getPixelForValue(ticks[index].value); } getPixelForDecimal(decimal) { if (this._reversePixels) { decimal = 1 - decimal; } const pixel = this._startPixel + decimal * this._length; return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel); } getDecimalForPixel(pixel) { const decimal = (pixel - this._startPixel) / this._length; return this._reversePixels ? 1 - decimal : decimal; } getBasePixel() { return this.getPixelForValue(this.getBaseValue()); } getBaseValue() { const { min , max } = this; return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0; } getContext(index) { const ticks = this.ticks || []; if (index >= 0 && index < ticks.length) { const tick = ticks[index]; return tick.$context || (tick.$context = createTickContext(this.getContext(), index, tick)); } return this.$context || (this.$context = createScaleContext(this.chart.getContext(), this)); } _tickSize() { const optionTicks = this.options.ticks; const rot = toRadians(this.labelRotation); const cos = Math.abs(Math.cos(rot)); const sin = Math.abs(Math.sin(rot)); const labelSizes = this._getLabelSizes(); const padding = optionTicks.autoSkipPadding || 0; const w = labelSizes ? labelSizes.widest.width + padding : 0; const h = labelSizes ? labelSizes.highest.height + padding : 0; return this.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin; } _isVisible() { const display = this.options.display; if (display !== 'auto') { return !!display; } return this.getMatchingVisibleMetas().length > 0; } _computeGridLineItems(chartArea) { const axis = this.axis; const chart = this.chart; const options = this.options; const { grid , position , border } = options; const offset = grid.offset; const isHorizontal = this.isHorizontal(); const ticks = this.ticks; const ticksLength = ticks.length + (offset ? 1 : 0); const tl = getTickMarkLength(grid); const items = []; const borderOpts = border.setContext(this.getContext()); const axisWidth = borderOpts.display ? borderOpts.width : 0; const axisHalfWidth = axisWidth / 2; const alignBorderValue = function(pixel) { return _alignPixel(chart, pixel, axisWidth); }; let borderValue, i, lineValue, alignedLineValue; let tx1, ty1, tx2, ty2, x1, y1, x2, y2; if (position === 'top') { borderValue = alignBorderValue(this.bottom); ty1 = this.bottom - tl; ty2 = borderValue - axisHalfWidth; y1 = alignBorderValue(chartArea.top) + axisHalfWidth; y2 = chartArea.bottom; } else if (position === 'bottom') { borderValue = alignBorderValue(this.top); y1 = chartArea.top; y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; ty1 = borderValue + axisHalfWidth; ty2 = this.top + tl; } else if (position === 'left') { borderValue = alignBorderValue(this.right); tx1 = this.right - tl; tx2 = borderValue - axisHalfWidth; x1 = alignBorderValue(chartArea.left) + axisHalfWidth; x2 = chartArea.right; } else if (position === 'right') { borderValue = alignBorderValue(this.left); x1 = chartArea.left; x2 = alignBorderValue(chartArea.right) - axisHalfWidth; tx1 = borderValue + axisHalfWidth; tx2 = this.left + tl; } else if (axis === 'x') { if (position === 'center') { borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5); } else if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); } y1 = chartArea.top; y2 = chartArea.bottom; ty1 = borderValue + axisHalfWidth; ty2 = ty1 + tl; } else if (axis === 'y') { if (position === 'center') { borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); } else if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value)); } tx1 = borderValue - axisHalfWidth; tx2 = tx1 - tl; x1 = chartArea.left; x2 = chartArea.right; } const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength); const step = Math.max(1, Math.ceil(ticksLength / limit)); for(i = 0; i < ticksLength; i += step){ const context = this.getContext(i); const optsAtIndex = grid.setContext(context); const optsAtIndexBorder = border.setContext(context); const lineWidth = optsAtIndex.lineWidth; const lineColor = optsAtIndex.color; const borderDash = optsAtIndexBorder.dash || []; const borderDashOffset = optsAtIndexBorder.dashOffset; const tickWidth = optsAtIndex.tickWidth; const tickColor = optsAtIndex.tickColor; const tickBorderDash = optsAtIndex.tickBorderDash || []; const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset; lineValue = getPixelForGridLine(this, i, offset); if (lineValue === undefined) { continue; } alignedLineValue = _alignPixel(chart, lineValue, lineWidth); if (isHorizontal) { tx1 = tx2 = x1 = x2 = alignedLineValue; } else { ty1 = ty2 = y1 = y2 = alignedLineValue; } items.push({ tx1, ty1, tx2, ty2, x1, y1, x2, y2, width: lineWidth, color: lineColor, borderDash, borderDashOffset, tickWidth, tickColor, tickBorderDash, tickBorderDashOffset }); } this._ticksLength = ticksLength; this._borderValue = borderValue; return items; } _computeLabelItems(chartArea) { const axis = this.axis; const options = this.options; const { position , ticks: optionTicks } = options; const isHorizontal = this.isHorizontal(); const ticks = this.ticks; const { align , crossAlign , padding , mirror } = optionTicks; const tl = getTickMarkLength(options.grid); const tickAndPadding = tl + padding; const hTickAndPadding = mirror ? -padding : tickAndPadding; const rotation = -toRadians(this.labelRotation); const items = []; let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; let textBaseline = 'middle'; if (position === 'top') { y = this.bottom - hTickAndPadding; textAlign = this._getXAxisLabelAlignment(); } else if (position === 'bottom') { y = this.top + hTickAndPadding; textAlign = this._getXAxisLabelAlignment(); } else if (position === 'left') { const ret = this._getYAxisLabelAlignment(tl); textAlign = ret.textAlign; x = ret.x; } else if (position === 'right') { const ret = this._getYAxisLabelAlignment(tl); textAlign = ret.textAlign; x = ret.x; } else if (axis === 'x') { if (position === 'center') { y = (chartArea.top + chartArea.bottom) / 2 + tickAndPadding; } else if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding; } textAlign = this._getXAxisLabelAlignment(); } else if (axis === 'y') { if (position === 'center') { x = (chartArea.left + chartArea.right) / 2 - tickAndPadding; } else if (isObject(position)) { const positionAxisID = Object.keys(position)[0]; const value = position[positionAxisID]; x = this.chart.scales[positionAxisID].getPixelForValue(value); } textAlign = this._getYAxisLabelAlignment(tl).textAlign; } if (axis === 'y') { if (align === 'start') { textBaseline = 'top'; } else if (align === 'end') { textBaseline = 'bottom'; } } const labelSizes = this._getLabelSizes(); for(i = 0, ilen = ticks.length; i < ilen; ++i){ tick = ticks[i]; label = tick.label; const optsAtIndex = optionTicks.setContext(this.getContext(i)); pixel = this.getPixelForTick(i) + optionTicks.labelOffset; font = this._resolveTickFontOptions(i); lineHeight = font.lineHeight; lineCount = isArray(label) ? label.length : 1; const halfCount = lineCount / 2; const color = optsAtIndex.color; const strokeColor = optsAtIndex.textStrokeColor; const strokeWidth = optsAtIndex.textStrokeWidth; let tickTextAlign = textAlign; if (isHorizontal) { x = pixel; if (textAlign === 'inner') { if (i === ilen - 1) { tickTextAlign = !this.options.reverse ? 'right' : 'left'; } else if (i === 0) { tickTextAlign = !this.options.reverse ? 'left' : 'right'; } else { tickTextAlign = 'center'; } } if (position === 'top') { if (crossAlign === 'near' || rotation !== 0) { textOffset = -lineCount * lineHeight + lineHeight / 2; } else if (crossAlign === 'center') { textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight; } else { textOffset = -labelSizes.highest.height + lineHeight / 2; } } else { if (crossAlign === 'near' || rotation !== 0) { textOffset = lineHeight / 2; } else if (crossAlign === 'center') { textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight; } else { textOffset = labelSizes.highest.height - lineCount * lineHeight; } } if (mirror) { textOffset *= -1; } if (rotation !== 0 && !optsAtIndex.showLabelBackdrop) { x += lineHeight / 2 * Math.sin(rotation); } } else { y = pixel; textOffset = (1 - lineCount) * lineHeight / 2; } let backdrop; if (optsAtIndex.showLabelBackdrop) { const labelPadding = toPadding(optsAtIndex.backdropPadding); const height = labelSizes.heights[i]; const width = labelSizes.widths[i]; let top = textOffset - labelPadding.top; let left = 0 - labelPadding.left; switch(textBaseline){ case 'middle': top -= height / 2; break; case 'bottom': top -= height; break; } switch(textAlign){ case 'center': left -= width / 2; break; case 'right': left -= width; break; case 'inner': if (i === ilen - 1) { left -= width; } else if (i > 0) { left -= width / 2; } break; } backdrop = { left, top, width: width + labelPadding.width, height: height + labelPadding.height, color: optsAtIndex.backdropColor }; } items.push({ label, font, textOffset, options: { rotation, color, strokeColor, strokeWidth, textAlign: tickTextAlign, textBaseline, translation: [ x, y ], backdrop } }); } return items; } _getXAxisLabelAlignment() { const { position , ticks } = this.options; const rotation = -toRadians(this.labelRotation); if (rotation) { return position === 'top' ? 'left' : 'right'; } let align = 'center'; if (ticks.align === 'start') { align = 'left'; } else if (ticks.align === 'end') { align = 'right'; } else if (ticks.align === 'inner') { align = 'inner'; } return align; } _getYAxisLabelAlignment(tl) { const { position , ticks: { crossAlign , mirror , padding } } = this.options; const labelSizes = this._getLabelSizes(); const tickAndPadding = tl + padding; const widest = labelSizes.widest.width; let textAlign; let x; if (position === 'left') { if (mirror) { x = this.right + padding; if (crossAlign === 'near') { textAlign = 'left'; } else if (crossAlign === 'center') { textAlign = 'center'; x += widest / 2; } else { textAlign = 'right'; x += widest; } } else { x = this.right - tickAndPadding; if (crossAlign === 'near') { textAlign = 'right'; } else if (crossAlign === 'center') { textAlign = 'center'; x -= widest / 2; } else { textAlign = 'left'; x = this.left; } } } else if (position === 'right') { if (mirror) { x = this.left + padding; if (crossAlign === 'near') { textAlign = 'right'; } else if (crossAlign === 'center') { textAlign = 'center'; x -= widest / 2; } else { textAlign = 'left'; x -= widest; } } else { x = this.left + tickAndPadding; if (crossAlign === 'near') { textAlign = 'left'; } else if (crossAlign === 'center') { textAlign = 'center'; x += widest / 2; } else { textAlign = 'right'; x = this.right; } } } else { textAlign = 'right'; } return { textAlign, x }; } _computeLabelArea() { if (this.options.ticks.mirror) { return; } const chart = this.chart; const position = this.options.position; if (position === 'left' || position === 'right') { return { top: 0, left: this.left, bottom: chart.height, right: this.right }; } if (position === 'top' || position === 'bottom') { return { top: this.top, left: 0, bottom: this.bottom, right: chart.width }; } } drawBackground() { const { ctx , options: { backgroundColor } , left , top , width , height } = this; if (backgroundColor) { ctx.save(); ctx.fillStyle = backgroundColor; ctx.fillRect(left, top, width, height); ctx.restore(); } } getLineWidthForValue(value) { const grid = this.options.grid; if (!this._isVisible() || !grid.display) { return 0; } const ticks = this.ticks; const index = ticks.findIndex((t)=>t.value === value); if (index >= 0) { const opts = grid.setContext(this.getContext(index)); return opts.lineWidth; } return 0; } drawGrid(chartArea) { const grid = this.options.grid; const ctx = this.ctx; const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea)); let i, ilen; const drawLine = (p1, p2, style)=>{ if (!style.width || !style.color) { return; } ctx.save(); ctx.lineWidth = style.width; ctx.strokeStyle = style.color; ctx.setLineDash(style.borderDash || []); ctx.lineDashOffset = style.borderDashOffset; ctx.beginPath(); ctx.moveTo(p1.x, p1.y); ctx.lineTo(p2.x, p2.y); ctx.stroke(); ctx.restore(); }; if (grid.display) { for(i = 0, ilen = items.length; i < ilen; ++i){ const item = items[i]; if (grid.drawOnChartArea) { drawLine({ x: item.x1, y: item.y1 }, { x: item.x2, y: item.y2 }, item); } if (grid.drawTicks) { drawLine({ x: item.tx1, y: item.ty1 }, { x: item.tx2, y: item.ty2 }, { color: item.tickColor, width: item.tickWidth, borderDash: item.tickBorderDash, borderDashOffset: item.tickBorderDashOffset }); } } } } drawBorder() { const { chart , ctx , options: { border , grid } } = this; const borderOpts = border.setContext(this.getContext()); const axisWidth = border.display ? borderOpts.width : 0; if (!axisWidth) { return; } const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth; const borderValue = this._borderValue; let x1, x2, y1, y2; if (this.isHorizontal()) { x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2; x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2; y1 = y2 = borderValue; } else { y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2; y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2; x1 = x2 = borderValue; } ctx.save(); ctx.lineWidth = borderOpts.width; ctx.strokeStyle = borderOpts.color; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); ctx.restore(); } drawLabels(chartArea) { const optionTicks = this.options.ticks; if (!optionTicks.display) { return; } const ctx = this.ctx; const area = this._computeLabelArea(); if (area) { clipArea(ctx, area); } const items = this.getLabelItems(chartArea); for (const item of items){ const renderTextOptions = item.options; const tickFont = item.font; const label = item.label; const y = item.textOffset; renderText(ctx, label, 0, y, tickFont, renderTextOptions); } if (area) { unclipArea(ctx); } } drawTitle() { const { ctx , options: { position , title , reverse } } = this; if (!title.display) { return; } const font = toFont(title.font); const padding = toPadding(title.padding); const align = title.align; let offset = font.lineHeight / 2; if (position === 'bottom' || position === 'center' || isObject(position)) { offset += padding.bottom; if (isArray(title.text)) { offset += font.lineHeight * (title.text.length - 1); } } else { offset += padding.top; } const { titleX , titleY , maxWidth , rotation } = titleArgs(this, offset, position, align); renderText(ctx, title.text, 0, 0, font, { color: title.color, maxWidth, rotation, textAlign: titleAlign(align, position, reverse), textBaseline: 'middle', translation: [ titleX, titleY ] }); } draw(chartArea) { if (!this._isVisible()) { return; } this.drawBackground(); this.drawGrid(chartArea); this.drawBorder(); this.drawTitle(); this.drawLabels(chartArea); } _layers() { const opts = this.options; const tz = opts.ticks && opts.ticks.z || 0; const gz = valueOrDefault(opts.grid && opts.grid.z, -1); const bz = valueOrDefault(opts.border && opts.border.z, 0); if (!this._isVisible() || this.draw !== Scale.prototype.draw) { return [ { z: tz, draw: (chartArea)=>{ this.draw(chartArea); } } ]; } return [ { z: gz, draw: (chartArea)=>{ this.drawBackground(); this.drawGrid(chartArea); this.drawTitle(); } }, { z: bz, draw: ()=>{ this.drawBorder(); } }, { z: tz, draw: (chartArea)=>{ this.drawLabels(chartArea); } } ]; } getMatchingVisibleMetas(type) { const metas = this.chart.getSortedVisibleDatasetMetas(); const axisID = this.axis + 'AxisID'; const result = []; let i, ilen; for(i = 0, ilen = metas.length; i < ilen; ++i){ const meta = metas[i]; if (meta[axisID] === this.id && (!type || meta.type === type)) { result.push(meta); } } return result; } _resolveTickFontOptions(index) { const opts = this.options.ticks.setContext(this.getContext(index)); return toFont(opts.font); } _maxDigits() { const fontSize = this._resolveTickFontOptions(0).lineHeight; return (this.isHorizontal() ? this.width : this.height) / fontSize; } } class TypedRegistry { constructor(type, scope, override){ this.type = type; this.scope = scope; this.override = override; this.items = Object.create(null); } isForType(type) { return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); } register(item) { const proto = Object.getPrototypeOf(item); let parentScope; if (isIChartComponent(proto)) { parentScope = this.register(proto); } const items = this.items; const id = item.id; const scope = this.scope + '.' + id; if (!id) { throw new Error('class does not have id: ' + item); } if (id in items) { return scope; } items[id] = item; registerDefaults(item, scope, parentScope); if (this.override) { defaults.override(item.id, item.overrides); } return scope; } get(id) { return this.items[id]; } unregister(item) { const items = this.items; const id = item.id; const scope = this.scope; if (id in items) { delete items[id]; } if (scope && id in defaults[scope]) { delete defaults[scope][id]; if (this.override) { delete overrides[id]; } } } } function registerDefaults(item, scope, parentScope) { const itemDefaults = merge(Object.create(null), [ parentScope ? defaults.get(parentScope) : {}, defaults.get(scope), item.defaults ]); defaults.set(scope, itemDefaults); if (item.defaultRoutes) { routeDefaults(scope, item.defaultRoutes); } if (item.descriptors) { defaults.describe(scope, item.descriptors); } } function routeDefaults(scope, routes) { Object.keys(routes).forEach((property)=>{ const propertyParts = property.split('.'); const sourceName = propertyParts.pop(); const sourceScope = [ scope ].concat(propertyParts).join('.'); const parts = routes[property].split('.'); const targetName = parts.pop(); const targetScope = parts.join('.'); defaults.route(sourceScope, sourceName, targetScope, targetName); }); } function isIChartComponent(proto) { return 'id' in proto && 'defaults' in proto; } class Registry { constructor(){ this.controllers = new TypedRegistry(DatasetController, 'datasets', true); this.elements = new TypedRegistry(chart_Element, 'elements'); this.plugins = new TypedRegistry(Object, 'plugins'); this.scales = new TypedRegistry(Scale, 'scales'); this._typedRegistries = [ this.controllers, this.scales, this.elements ]; } add(...args) { this._each('register', args); } remove(...args) { this._each('unregister', args); } addControllers(...args) { this._each('register', args, this.controllers); } addElements(...args) { this._each('register', args, this.elements); } addPlugins(...args) { this._each('register', args, this.plugins); } addScales(...args) { this._each('register', args, this.scales); } getController(id) { return this._get(id, this.controllers, 'controller'); } getElement(id) { return this._get(id, this.elements, 'element'); } getPlugin(id) { return this._get(id, this.plugins, 'plugin'); } getScale(id) { return this._get(id, this.scales, 'scale'); } removeControllers(...args) { this._each('unregister', args, this.controllers); } removeElements(...args) { this._each('unregister', args, this.elements); } removePlugins(...args) { this._each('unregister', args, this.plugins); } removeScales(...args) { this._each('unregister', args, this.scales); } _each(method, args, typedRegistry) { [ ...args ].forEach((arg)=>{ const reg = typedRegistry || this._getRegistryForType(arg); if (typedRegistry || reg.isForType(arg) || reg === this.plugins && arg.id) { this._exec(method, reg, arg); } else { each(arg, (item)=>{ const itemReg = typedRegistry || this._getRegistryForType(item); this._exec(method, itemReg, item); }); } }); } _exec(method, registry, component) { const camelMethod = _capitalize(method); callback(component['before' + camelMethod], [], component); registry[method](component); callback(component['after' + camelMethod], [], component); } _getRegistryForType(type) { for(let i = 0; i < this._typedRegistries.length; i++){ const reg = this._typedRegistries[i]; if (reg.isForType(type)) { return reg; } } return this.plugins; } _get(id, typedRegistry, type) { const item = typedRegistry.get(id); if (item === undefined) { throw new Error('"' + id + '" is not a registered ' + type + '.'); } return item; } } var registry = /* #__PURE__ */ new Registry(); class PluginService { constructor(){ this._init = undefined; } notify(chart, hook, args, filter) { if (hook === 'beforeInit') { this._init = this._createDescriptors(chart, true); this._notify(this._init, chart, 'install'); } if (this._init === undefined) { return; } const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart); const result = this._notify(descriptors, chart, hook, args); if (hook === 'afterDestroy') { this._notify(descriptors, chart, 'stop'); this._notify(this._init, chart, 'uninstall'); this._init = undefined; } return result; } _notify(descriptors, chart, hook, args) { args = args || {}; for (const descriptor of descriptors){ const plugin = descriptor.plugin; const method = plugin[hook]; const params = [ chart, args, descriptor.options ]; if (callback(method, params, plugin) === false && args.cancelable) { return false; } } return true; } invalidate() { if (!isNullOrUndef(this._cache)) { this._oldCache = this._cache; this._cache = undefined; } } _descriptors(chart) { if (this._cache) { return this._cache; } const descriptors = this._cache = this._createDescriptors(chart); this._notifyStateChanges(chart); return descriptors; } _createDescriptors(chart, all) { const config = chart && chart.config; const options = valueOrDefault(config.options && config.options.plugins, {}); const plugins = allPlugins(config); return options === false && !all ? [] : createDescriptors(chart, plugins, options, all); } _notifyStateChanges(chart) { const previousDescriptors = this._oldCache || []; const descriptors = this._cache; const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.plugin.id === y.plugin.id)); this._notify(diff(previousDescriptors, descriptors), chart, 'stop'); this._notify(diff(descriptors, previousDescriptors), chart, 'start'); } } function allPlugins(config) { const localIds = {}; const plugins = []; const keys = Object.keys(registry.plugins.items); for(let i = 0; i < keys.length; i++){ plugins.push(registry.getPlugin(keys[i])); } const local = config.plugins || []; for(let i = 0; i < local.length; i++){ const plugin = local[i]; if (plugins.indexOf(plugin) === -1) { plugins.push(plugin); localIds[plugin.id] = true; } } return { plugins, localIds }; } function getOpts(options, all) { if (!all && options === false) { return null; } if (options === true) { return {}; } return options; } function createDescriptors(chart, { plugins , localIds }, options, all) { const result = []; const context = chart.getContext(); for (const plugin of plugins){ const id = plugin.id; const opts = getOpts(options[id], all); if (opts === null) { continue; } result.push({ plugin, options: pluginOpts(chart.config, { plugin, local: localIds[id] }, opts, context) }); } return result; } function pluginOpts(config, { plugin , local }, opts, context) { const keys = config.pluginScopeKeys(plugin); const scopes = config.getOptionScopes(opts, keys); if (local && plugin.defaults) { scopes.push(plugin.defaults); } return config.createResolver(scopes, context, [ '' ], { scriptable: false, indexable: false, allKeys: true }); } function getIndexAxis(type, options) { const datasetDefaults = defaults.datasets[type] || {}; const datasetOptions = (options.datasets || {})[type] || {}; return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; } function getAxisFromDefaultScaleID(id, indexAxis) { let axis = id; if (id === '_index_') { axis = indexAxis; } else if (id === '_value_') { axis = indexAxis === 'x' ? 'y' : 'x'; } return axis; } function getDefaultScaleIDFromAxis(axis, indexAxis) { return axis === indexAxis ? '_index_' : '_value_'; } function idMatchesAxis(id) { if (id === 'x' || id === 'y' || id === 'r') { return id; } } function axisFromPosition(position) { if (position === 'top' || position === 'bottom') { return 'x'; } if (position === 'left' || position === 'right') { return 'y'; } } function determineAxis(id, ...scaleOptions) { if (idMatchesAxis(id)) { return id; } for (const opts of scaleOptions){ const axis = opts.axis || axisFromPosition(opts.position) || id.length > 1 && idMatchesAxis(id[0].toLowerCase()); if (axis) { return axis; } } throw new Error(`Cannot determine type of '${id}' axis. Please provide 'axis' or 'position' option.`); } function getAxisFromDataset(id, axis, dataset) { if (dataset[axis + 'AxisID'] === id) { return { axis }; } } function retrieveAxisFromDatasets(id, config) { if (config.data && config.data.datasets) { const boundDs = config.data.datasets.filter((d)=>d.xAxisID === id || d.yAxisID === id); if (boundDs.length) { return getAxisFromDataset(id, 'x', boundDs[0]) || getAxisFromDataset(id, 'y', boundDs[0]); } } return {}; } function mergeScaleConfig(config, options) { const chartDefaults = overrides[config.type] || { scales: {} }; const configScales = options.scales || {}; const chartIndexAxis = getIndexAxis(config.type, options); const scales = Object.create(null); Object.keys(configScales).forEach((id)=>{ const scaleConf = configScales[id]; if (!isObject(scaleConf)) { return console.error(`Invalid scale configuration for scale: ${id}`); } if (scaleConf._proxy) { return console.warn(`Ignoring resolver passed as options for scale: ${id}`); } const axis = determineAxis(id, scaleConf, retrieveAxisFromDatasets(id, config), defaults.scales[scaleConf.type]); const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); const defaultScaleOptions = chartDefaults.scales || {}; scales[id] = mergeIf(Object.create(null), [ { axis }, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId] ]); }); config.data.datasets.forEach((dataset)=>{ const type = dataset.type || config.type; const indexAxis = dataset.indexAxis || getIndexAxis(type, options); const datasetDefaults = overrides[type] || {}; const defaultScaleOptions = datasetDefaults.scales || {}; Object.keys(defaultScaleOptions).forEach((defaultID)=>{ const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); const id = dataset[axis + 'AxisID'] || axis; scales[id] = scales[id] || Object.create(null); mergeIf(scales[id], [ { axis }, configScales[id], defaultScaleOptions[defaultID] ]); }); }); Object.keys(scales).forEach((key)=>{ const scale = scales[key]; mergeIf(scale, [ defaults.scales[scale.type], defaults.scale ]); }); return scales; } function initOptions(config) { const options = config.options || (config.options = {}); options.plugins = valueOrDefault(options.plugins, {}); options.scales = mergeScaleConfig(config, options); } function initData(data) { data = data || {}; data.datasets = data.datasets || []; data.labels = data.labels || []; return data; } function initConfig(config) { config = config || {}; config.data = initData(config.data); initOptions(config); return config; } const keyCache = new Map(); const keysCached = new Set(); function cachedKeys(cacheKey, generate) { let keys = keyCache.get(cacheKey); if (!keys) { keys = generate(); keyCache.set(cacheKey, keys); keysCached.add(keys); } return keys; } const addIfFound = (set, obj, key)=>{ const opts = resolveObjectKey(obj, key); if (opts !== undefined) { set.add(opts); } }; class Config { constructor(config){ this._config = initConfig(config); this._scopeCache = new Map(); this._resolverCache = new Map(); } get platform() { return this._config.platform; } get type() { return this._config.type; } set type(type) { this._config.type = type; } get data() { return this._config.data; } set data(data) { this._config.data = initData(data); } get options() { return this._config.options; } set options(options) { this._config.options = options; } get plugins() { return this._config.plugins; } update() { const config = this._config; this.clearCache(); initOptions(config); } clearCache() { this._scopeCache.clear(); this._resolverCache.clear(); } datasetScopeKeys(datasetType) { return cachedKeys(datasetType, ()=>[ [ `datasets.${datasetType}`, '' ] ]); } datasetAnimationScopeKeys(datasetType, transition) { return cachedKeys(`${datasetType}.transition.${transition}`, ()=>[ [ `datasets.${datasetType}.transitions.${transition}`, `transitions.${transition}` ], [ `datasets.${datasetType}`, '' ] ]); } datasetElementScopeKeys(datasetType, elementType) { return cachedKeys(`${datasetType}-${elementType}`, ()=>[ [ `datasets.${datasetType}.elements.${elementType}`, `datasets.${datasetType}`, `elements.${elementType}`, '' ] ]); } pluginScopeKeys(plugin) { const id = plugin.id; const type = this.type; return cachedKeys(`${type}-plugin-${id}`, ()=>[ [ `plugins.${id}`, ...plugin.additionalOptionScopes || [] ] ]); } _cachedScopes(mainScope, resetCache) { const _scopeCache = this._scopeCache; let cache = _scopeCache.get(mainScope); if (!cache || resetCache) { cache = new Map(); _scopeCache.set(mainScope, cache); } return cache; } getOptionScopes(mainScope, keyLists, resetCache) { const { options , type } = this; const cache = this._cachedScopes(mainScope, resetCache); const cached = cache.get(keyLists); if (cached) { return cached; } const scopes = new Set(); keyLists.forEach((keys)=>{ if (mainScope) { scopes.add(mainScope); keys.forEach((key)=>addIfFound(scopes, mainScope, key)); } keys.forEach((key)=>addIfFound(scopes, options, key)); keys.forEach((key)=>addIfFound(scopes, overrides[type] || {}, key)); keys.forEach((key)=>addIfFound(scopes, defaults, key)); keys.forEach((key)=>addIfFound(scopes, descriptors, key)); }); const array = Array.from(scopes); if (array.length === 0) { array.push(Object.create(null)); } if (keysCached.has(keyLists)) { cache.set(keyLists, array); } return array; } chartOptionScopes() { const { options , type } = this; return [ options, overrides[type] || {}, defaults.datasets[type] || {}, { type }, defaults, descriptors ]; } resolveNamedOptions(scopes, names, context, prefixes = [ '' ]) { const result = { $shared: true }; const { resolver , subPrefixes } = getResolver(this._resolverCache, scopes, prefixes); let options = resolver; if (needContext(resolver, names)) { result.$shared = false; context = isFunction(context) ? context() : context; const subResolver = this.createResolver(scopes, context, subPrefixes); options = _attachContext(resolver, context, subResolver); } for (const prop of names){ result[prop] = options[prop]; } return result; } createResolver(scopes, context, prefixes = [ '' ], descriptorDefaults) { const { resolver } = getResolver(this._resolverCache, scopes, prefixes); return isObject(context) ? _attachContext(resolver, context, undefined, descriptorDefaults) : resolver; } } function getResolver(resolverCache, scopes, prefixes) { let cache = resolverCache.get(scopes); if (!cache) { cache = new Map(); resolverCache.set(scopes, cache); } const cacheKey = prefixes.join(); let cached = cache.get(cacheKey); if (!cached) { const resolver = _createResolver(scopes, prefixes); cached = { resolver, subPrefixes: prefixes.filter((p)=>!p.toLowerCase().includes('hover')) }; cache.set(cacheKey, cached); } return cached; } const hasFunction = (value)=>isObject(value) && Object.getOwnPropertyNames(value).some((key)=>isFunction(value[key])); function needContext(proxy, names) { const { isScriptable , isIndexable } = _descriptors(proxy); for (const prop of names){ const scriptable = isScriptable(prop); const indexable = isIndexable(prop); const value = (indexable || scriptable) && proxy[prop]; if (scriptable && (isFunction(value) || hasFunction(value)) || indexable && isArray(value)) { return true; } } return false; } var version = "4.5.1"; const KNOWN_POSITIONS = [ 'top', 'bottom', 'left', 'right', 'chartArea' ]; function positionIsHorizontal(position, axis) { return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'; } function compare2Level(l1, l2) { return function(a, b) { return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1]; }; } function onAnimationsComplete(context) { const chart = context.chart; const animationOptions = chart.options.animation; chart.notifyPlugins('afterRender'); callback(animationOptions && animationOptions.onComplete, [ context ], chart); } function onAnimationProgress(context) { const chart = context.chart; const animationOptions = chart.options.animation; callback(animationOptions && animationOptions.onProgress, [ context ], chart); } function getCanvas(item) { if (_isDomSupported() && typeof item === 'string') { item = document.getElementById(item); } else if (item && item.length) { item = item[0]; } if (item && item.canvas) { item = item.canvas; } return item; } const instances = {}; const getChart = (key)=>{ const canvas = getCanvas(key); return Object.values(instances).filter((c)=>c.canvas === canvas).pop(); }; function moveNumericKeys(obj, start, move) { const keys = Object.keys(obj); for (const key of keys){ const intKey = +key; if (intKey >= start) { const value = obj[key]; delete obj[key]; if (move > 0 || intKey > start) { obj[intKey + move] = value; } } } } function determineLastEvent(e, lastEvent, inChartArea, isClick) { if (!inChartArea || e.type === 'mouseout') { return null; } if (isClick) { return lastEvent; } return e; } class chart_Chart { static defaults = defaults; static instances = instances; static overrides = overrides; static registry = registry; static version = version; static getChart = getChart; static register(...items) { registry.add(...items); invalidatePlugins(); } static unregister(...items) { registry.remove(...items); invalidatePlugins(); } constructor(item, userConfig){ const config = this.config = new Config(userConfig); const initialCanvas = getCanvas(item); const existingChart = getChart(initialCanvas); if (existingChart) { throw new Error('Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' + ' must be destroyed before the canvas with ID \'' + existingChart.canvas.id + '\' can be reused.'); } const options = config.createResolver(config.chartOptionScopes(), this.getContext()); this.platform = new (config.platform || _detectPlatform(initialCanvas))(); this.platform.updateConfig(config); const context = this.platform.acquireContext(initialCanvas, options.aspectRatio); const canvas = context && context.canvas; const height = canvas && canvas.height; const width = canvas && canvas.width; this.id = uid(); this.ctx = context; this.canvas = canvas; this.width = width; this.height = height; this._options = options; this._aspectRatio = this.aspectRatio; this._layers = []; this._metasets = []; this._stacks = undefined; this.boxes = []; this.currentDevicePixelRatio = undefined; this.chartArea = undefined; this._active = []; this._lastEvent = undefined; this._listeners = {}; this._responsiveListeners = undefined; this._sortedMetasets = []; this.scales = {}; this._plugins = new PluginService(); this.$proxies = {}; this._hiddenIndices = {}; this.attached = false; this._animationsDisabled = undefined; this.$context = undefined; this._doResize = debounce((mode)=>this.update(mode), options.resizeDelay || 0); this._dataChanges = []; instances[this.id] = this; if (!context || !canvas) { console.error("Failed to create chart: can't acquire context from the given item"); return; } animator.listen(this, 'complete', onAnimationsComplete); animator.listen(this, 'progress', onAnimationProgress); this._initialize(); if (this.attached) { this.update(); } } get aspectRatio() { const { options: { aspectRatio , maintainAspectRatio } , width , height , _aspectRatio } = this; if (!isNullOrUndef(aspectRatio)) { return aspectRatio; } if (maintainAspectRatio && _aspectRatio) { return _aspectRatio; } return height ? width / height : null; } get data() { return this.config.data; } set data(data) { this.config.data = data; } get options() { return this._options; } set options(options) { this.config.options = options; } get registry() { return registry; } _initialize() { this.notifyPlugins('beforeInit'); if (this.options.responsive) { this.resize(); } else { retinaScale(this, this.options.devicePixelRatio); } this.bindEvents(); this.notifyPlugins('afterInit'); return this; } clear() { clearCanvas(this.canvas, this.ctx); return this; } stop() { animator.stop(this); return this; } resize(width, height) { if (!animator.running(this)) { this._resize(width, height); } else { this._resizeBeforeDraw = { width, height }; } } _resize(width, height) { const options = this.options; const canvas = this.canvas; const aspectRatio = options.maintainAspectRatio && this.aspectRatio; const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio); const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio(); const mode = this.width ? 'resize' : 'attach'; this.width = newSize.width; this.height = newSize.height; this._aspectRatio = this.aspectRatio; if (!retinaScale(this, newRatio, true)) { return; } this.notifyPlugins('resize', { size: newSize }); callback(options.onResize, [ this, newSize ], this); if (this.attached) { if (this._doResize(mode)) { this.render(); } } } ensureScalesHaveIDs() { const options = this.options; const scalesOptions = options.scales || {}; each(scalesOptions, (axisOptions, axisID)=>{ axisOptions.id = axisID; }); } buildOrUpdateScales() { const options = this.options; const scaleOpts = options.scales; const scales = this.scales; const updated = Object.keys(scales).reduce((obj, id)=>{ obj[id] = false; return obj; }, {}); let items = []; if (scaleOpts) { items = items.concat(Object.keys(scaleOpts).map((id)=>{ const scaleOptions = scaleOpts[id]; const axis = determineAxis(id, scaleOptions); const isRadial = axis === 'r'; const isHorizontal = axis === 'x'; return { options: scaleOptions, dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' }; })); } each(items, (item)=>{ const scaleOptions = item.options; const id = scaleOptions.id; const axis = determineAxis(id, scaleOptions); const scaleType = valueOrDefault(scaleOptions.type, item.dtype); if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { scaleOptions.position = item.dposition; } updated[id] = true; let scale = null; if (id in scales && scales[id].type === scaleType) { scale = scales[id]; } else { const scaleClass = registry.getScale(scaleType); scale = new scaleClass({ id, type: scaleType, ctx: this.ctx, chart: this }); scales[scale.id] = scale; } scale.init(scaleOptions, options); }); each(updated, (hasUpdated, id)=>{ if (!hasUpdated) { delete scales[id]; } }); each(scales, (scale)=>{ layouts.configure(this, scale, scale.options); layouts.addBox(this, scale); }); } _updateMetasets() { const metasets = this._metasets; const numData = this.data.datasets.length; const numMeta = metasets.length; metasets.sort((a, b)=>a.index - b.index); if (numMeta > numData) { for(let i = numData; i < numMeta; ++i){ this._destroyDatasetMeta(i); } metasets.splice(numData, numMeta - numData); } this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); } _removeUnreferencedMetasets() { const { _metasets: metasets , data: { datasets } } = this; if (metasets.length > datasets.length) { delete this._stacks; } metasets.forEach((meta, index)=>{ if (datasets.filter((x)=>x === meta._dataset).length === 0) { this._destroyDatasetMeta(index); } }); } buildOrUpdateControllers() { const newControllers = []; const datasets = this.data.datasets; let i, ilen; this._removeUnreferencedMetasets(); for(i = 0, ilen = datasets.length; i < ilen; i++){ const dataset = datasets[i]; let meta = this.getDatasetMeta(i); const type = dataset.type || this.config.type; if (meta.type && meta.type !== type) { this._destroyDatasetMeta(i); meta = this.getDatasetMeta(i); } meta.type = type; meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options); meta.order = dataset.order || 0; meta.index = i; meta.label = '' + dataset.label; meta.visible = this.isDatasetVisible(i); if (meta.controller) { meta.controller.updateIndex(i); meta.controller.linkScales(); } else { const ControllerClass = registry.getController(type); const { datasetElementType , dataElementType } = defaults.datasets[type]; Object.assign(ControllerClass, { dataElementType: registry.getElement(dataElementType), datasetElementType: datasetElementType && registry.getElement(datasetElementType) }); meta.controller = new ControllerClass(this, i); newControllers.push(meta.controller); } } this._updateMetasets(); return newControllers; } _resetElements() { each(this.data.datasets, (dataset, datasetIndex)=>{ this.getDatasetMeta(datasetIndex).controller.reset(); }, this); } reset() { this._resetElements(); this.notifyPlugins('reset'); } update(mode) { const config = this.config; config.update(); const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext()); const animsDisabled = this._animationsDisabled = !options.animation; this._updateScales(); this._checkEventBindings(); this._updateHiddenIndices(); this._plugins.invalidate(); if (this.notifyPlugins('beforeUpdate', { mode, cancelable: true }) === false) { return; } const newControllers = this.buildOrUpdateControllers(); this.notifyPlugins('beforeElementsUpdate'); let minPadding = 0; for(let i = 0, ilen = this.data.datasets.length; i < ilen; i++){ const { controller } = this.getDatasetMeta(i); const reset = !animsDisabled && newControllers.indexOf(controller) === -1; controller.buildOrUpdateElements(reset); minPadding = Math.max(+controller.getMaxOverflow(), minPadding); } minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0; this._updateLayout(minPadding); if (!animsDisabled) { each(newControllers, (controller)=>{ controller.reset(); }); } this._updateDatasets(mode); this.notifyPlugins('afterUpdate', { mode }); this._layers.sort(compare2Level('z', '_idx')); const { _active , _lastEvent } = this; if (_lastEvent) { this._eventHandler(_lastEvent, true); } else if (_active.length) { this._updateHoverStyles(_active, _active, true); } this.render(); } _updateScales() { each(this.scales, (scale)=>{ layouts.removeBox(this, scale); }); this.ensureScalesHaveIDs(); this.buildOrUpdateScales(); } _checkEventBindings() { const options = this.options; const existingEvents = new Set(Object.keys(this._listeners)); const newEvents = new Set(options.events); if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) { this.unbindEvents(); this.bindEvents(); } } _updateHiddenIndices() { const { _hiddenIndices } = this; const changes = this._getUniformDataChanges() || []; for (const { method , start , count } of changes){ const move = method === '_removeElements' ? -count : count; moveNumericKeys(_hiddenIndices, start, move); } } _getUniformDataChanges() { const _dataChanges = this._dataChanges; if (!_dataChanges || !_dataChanges.length) { return; } this._dataChanges = []; const datasetCount = this.data.datasets.length; const makeSet = (idx)=>new Set(_dataChanges.filter((c)=>c[0] === idx).map((c, i)=>i + ',' + c.splice(1).join(','))); const changeSet = makeSet(0); for(let i = 1; i < datasetCount; i++){ if (!setsEqual(changeSet, makeSet(i))) { return; } } return Array.from(changeSet).map((c)=>c.split(',')).map((a)=>({ method: a[1], start: +a[2], count: +a[3] })); } _updateLayout(minPadding) { if (this.notifyPlugins('beforeLayout', { cancelable: true }) === false) { return; } layouts.update(this, this.width, this.height, minPadding); const area = this.chartArea; const noArea = area.width <= 0 || area.height <= 0; this._layers = []; each(this.boxes, (box)=>{ if (noArea && box.position === 'chartArea') { return; } if (box.configure) { box.configure(); } this._layers.push(...box._layers()); }, this); this._layers.forEach((item, index)=>{ item._idx = index; }); this.notifyPlugins('afterLayout'); } _updateDatasets(mode) { if (this.notifyPlugins('beforeDatasetsUpdate', { mode, cancelable: true }) === false) { return; } for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this.getDatasetMeta(i).controller.configure(); } for(let i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this._updateDataset(i, isFunction(mode) ? mode({ datasetIndex: i }) : mode); } this.notifyPlugins('afterDatasetsUpdate', { mode }); } _updateDataset(index, mode) { const meta = this.getDatasetMeta(index); const args = { meta, index, mode, cancelable: true }; if (this.notifyPlugins('beforeDatasetUpdate', args) === false) { return; } meta.controller._update(mode); args.cancelable = false; this.notifyPlugins('afterDatasetUpdate', args); } render() { if (this.notifyPlugins('beforeRender', { cancelable: true }) === false) { return; } if (animator.has(this)) { if (this.attached && !animator.running(this)) { animator.start(this); } } else { this.draw(); onAnimationsComplete({ chart: this }); } } draw() { let i; if (this._resizeBeforeDraw) { const { width , height } = this._resizeBeforeDraw; this._resizeBeforeDraw = null; this._resize(width, height); } this.clear(); if (this.width <= 0 || this.height <= 0) { return; } if (this.notifyPlugins('beforeDraw', { cancelable: true }) === false) { return; } const layers = this._layers; for(i = 0; i < layers.length && layers[i].z <= 0; ++i){ layers[i].draw(this.chartArea); } this._drawDatasets(); for(; i < layers.length; ++i){ layers[i].draw(this.chartArea); } this.notifyPlugins('afterDraw'); } _getSortedDatasetMetas(filterVisible) { const metasets = this._sortedMetasets; const result = []; let i, ilen; for(i = 0, ilen = metasets.length; i < ilen; ++i){ const meta = metasets[i]; if (!filterVisible || meta.visible) { result.push(meta); } } return result; } getSortedVisibleDatasetMetas() { return this._getSortedDatasetMetas(true); } _drawDatasets() { if (this.notifyPlugins('beforeDatasetsDraw', { cancelable: true }) === false) { return; } const metasets = this.getSortedVisibleDatasetMetas(); for(let i = metasets.length - 1; i >= 0; --i){ this._drawDataset(metasets[i]); } this.notifyPlugins('afterDatasetsDraw'); } _drawDataset(meta) { const ctx = this.ctx; const args = { meta, index: meta.index, cancelable: true }; const clip = getDatasetClipArea(this, meta); if (this.notifyPlugins('beforeDatasetDraw', args) === false) { return; } if (clip) { clipArea(ctx, clip); } meta.controller.draw(); if (clip) { unclipArea(ctx); } args.cancelable = false; this.notifyPlugins('afterDatasetDraw', args); } isPointInArea(point) { return _isPointInArea(point, this.chartArea, this._minPadding); } getElementsAtEventForMode(e, mode, options, useFinalPosition) { const method = Interaction.modes[mode]; if (typeof method === 'function') { return method(this, e, options, useFinalPosition); } return []; } getDatasetMeta(datasetIndex) { const dataset = this.data.datasets[datasetIndex]; const metasets = this._metasets; let meta = metasets.filter((x)=>x && x._dataset === dataset).pop(); if (!meta) { meta = { type: null, data: [], dataset: null, controller: null, hidden: null, xAxisID: null, yAxisID: null, order: dataset && dataset.order || 0, index: datasetIndex, _dataset: dataset, _parsed: [], _sorted: false }; metasets.push(meta); } return meta; } getContext() { return this.$context || (this.$context = createContext(null, { chart: this, type: 'chart' })); } getVisibleDatasetCount() { return this.getSortedVisibleDatasetMetas().length; } isDatasetVisible(datasetIndex) { const dataset = this.data.datasets[datasetIndex]; if (!dataset) { return false; } const meta = this.getDatasetMeta(datasetIndex); return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden; } setDatasetVisibility(datasetIndex, visible) { const meta = this.getDatasetMeta(datasetIndex); meta.hidden = !visible; } toggleDataVisibility(index) { this._hiddenIndices[index] = !this._hiddenIndices[index]; } getDataVisibility(index) { return !this._hiddenIndices[index]; } _updateVisibility(datasetIndex, dataIndex, visible) { const mode = visible ? 'show' : 'hide'; const meta = this.getDatasetMeta(datasetIndex); const anims = meta.controller._resolveAnimations(undefined, mode); if (defined(dataIndex)) { meta.data[dataIndex].hidden = !visible; this.update(); } else { this.setDatasetVisibility(datasetIndex, visible); anims.update(meta, { visible }); this.update((ctx)=>ctx.datasetIndex === datasetIndex ? mode : undefined); } } hide(datasetIndex, dataIndex) { this._updateVisibility(datasetIndex, dataIndex, false); } show(datasetIndex, dataIndex) { this._updateVisibility(datasetIndex, dataIndex, true); } _destroyDatasetMeta(datasetIndex) { const meta = this._metasets[datasetIndex]; if (meta && meta.controller) { meta.controller._destroy(); } delete this._metasets[datasetIndex]; } _stop() { let i, ilen; this.stop(); animator.remove(this); for(i = 0, ilen = this.data.datasets.length; i < ilen; ++i){ this._destroyDatasetMeta(i); } } destroy() { this.notifyPlugins('beforeDestroy'); const { canvas , ctx } = this; this._stop(); this.config.clearCache(); if (canvas) { this.unbindEvents(); clearCanvas(canvas, ctx); this.platform.releaseContext(ctx); this.canvas = null; this.ctx = null; } delete instances[this.id]; this.notifyPlugins('afterDestroy'); } toBase64Image(...args) { return this.canvas.toDataURL(...args); } bindEvents() { this.bindUserEvents(); if (this.options.responsive) { this.bindResponsiveEvents(); } else { this.attached = true; } } bindUserEvents() { const listeners = this._listeners; const platform = this.platform; const _add = (type, listener)=>{ platform.addEventListener(this, type, listener); listeners[type] = listener; }; const listener = (e, x, y)=>{ e.offsetX = x; e.offsetY = y; this._eventHandler(e); }; each(this.options.events, (type)=>_add(type, listener)); } bindResponsiveEvents() { if (!this._responsiveListeners) { this._responsiveListeners = {}; } const listeners = this._responsiveListeners; const platform = this.platform; const _add = (type, listener)=>{ platform.addEventListener(this, type, listener); listeners[type] = listener; }; const _remove = (type, listener)=>{ if (listeners[type]) { platform.removeEventListener(this, type, listener); delete listeners[type]; } }; const listener = (width, height)=>{ if (this.canvas) { this.resize(width, height); } }; let detached; const attached = ()=>{ _remove('attach', attached); this.attached = true; this.resize(); _add('resize', listener); _add('detach', detached); }; detached = ()=>{ this.attached = false; _remove('resize', listener); this._stop(); this._resize(0, 0); _add('attach', attached); }; if (platform.isAttached(this.canvas)) { attached(); } else { detached(); } } unbindEvents() { each(this._listeners, (listener, type)=>{ this.platform.removeEventListener(this, type, listener); }); this._listeners = {}; each(this._responsiveListeners, (listener, type)=>{ this.platform.removeEventListener(this, type, listener); }); this._responsiveListeners = undefined; } updateHoverStyle(items, mode, enabled) { const prefix = enabled ? 'set' : 'remove'; let meta, item, i, ilen; if (mode === 'dataset') { meta = this.getDatasetMeta(items[0].datasetIndex); meta.controller['_' + prefix + 'DatasetHoverStyle'](); } for(i = 0, ilen = items.length; i < ilen; ++i){ item = items[i]; const controller = item && this.getDatasetMeta(item.datasetIndex).controller; if (controller) { controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); } } } getActiveElements() { return this._active || []; } setActiveElements(activeElements) { const lastActive = this._active || []; const active = activeElements.map(({ datasetIndex , index })=>{ const meta = this.getDatasetMeta(datasetIndex); if (!meta) { throw new Error('No dataset found at index ' + datasetIndex); } return { datasetIndex, element: meta.data[index], index }; }); const changed = !_elementsEqual(active, lastActive); if (changed) { this._active = active; this._lastEvent = null; this._updateHoverStyles(active, lastActive); } } notifyPlugins(hook, args, filter) { return this._plugins.notify(this, hook, args, filter); } isPluginEnabled(pluginId) { return this._plugins._cache.filter((p)=>p.plugin.id === pluginId).length === 1; } _updateHoverStyles(active, lastActive, replay) { const hoverOptions = this.options.hover; const diff = (a, b)=>a.filter((x)=>!b.some((y)=>x.datasetIndex === y.datasetIndex && x.index === y.index)); const deactivated = diff(lastActive, active); const activated = replay ? active : diff(active, lastActive); if (deactivated.length) { this.updateHoverStyle(deactivated, hoverOptions.mode, false); } if (activated.length && hoverOptions.mode) { this.updateHoverStyle(activated, hoverOptions.mode, true); } } _eventHandler(e, replay) { const args = { event: e, replay, cancelable: true, inChartArea: this.isPointInArea(e) }; const eventFilter = (plugin)=>(plugin.options.events || this.options.events).includes(e.native.type); if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) { return; } const changed = this._handleEvent(e, replay, args.inChartArea); args.cancelable = false; this.notifyPlugins('afterEvent', args, eventFilter); if (changed || args.changed) { this.render(); } return this; } _handleEvent(e, replay, inChartArea) { const { _active: lastActive = [] , options } = this; const useFinalPosition = replay; const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition); const isClick = _isClickEvent(e); const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick); if (inChartArea) { this._lastEvent = null; callback(options.onHover, [ e, active, this ], this); if (isClick) { callback(options.onClick, [ e, active, this ], this); } } const changed = !_elementsEqual(active, lastActive); if (changed || replay) { this._active = active; this._updateHoverStyles(active, lastActive, replay); } this._lastEvent = lastEvent; return changed; } _getActiveElements(e, lastActive, inChartArea, useFinalPosition) { if (e.type === 'mouseout') { return []; } if (!inChartArea) { return lastActive; } const hoverOptions = this.options.hover; return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); } } function invalidatePlugins() { return each(chart_Chart.instances, (chart)=>chart._plugins.invalidate()); } function clipSelf(ctx, element, endAngle) { const { startAngle , x , y , outerRadius , innerRadius , options } = element; const { borderWidth , borderJoinStyle } = options; const outerAngleClip = Math.min(borderWidth / outerRadius, _normalizeAngle(startAngle - endAngle)); ctx.beginPath(); ctx.arc(x, y, outerRadius - borderWidth / 2, startAngle + outerAngleClip / 2, endAngle - outerAngleClip / 2); if (innerRadius > 0) { const innerAngleClip = Math.min(borderWidth / innerRadius, _normalizeAngle(startAngle - endAngle)); ctx.arc(x, y, innerRadius + borderWidth / 2, endAngle - innerAngleClip / 2, startAngle + innerAngleClip / 2, true); } else { const clipWidth = Math.min(borderWidth / 2, outerRadius * _normalizeAngle(startAngle - endAngle)); if (borderJoinStyle === 'round') { ctx.arc(x, y, clipWidth, endAngle - PI / 2, startAngle + PI / 2, true); } else if (borderJoinStyle === 'bevel') { const r = 2 * clipWidth * clipWidth; const endX = -r * Math.cos(endAngle + PI / 2) + x; const endY = -r * Math.sin(endAngle + PI / 2) + y; const startX = r * Math.cos(startAngle + PI / 2) + x; const startY = r * Math.sin(startAngle + PI / 2) + y; ctx.lineTo(endX, endY); ctx.lineTo(startX, startY); } } ctx.closePath(); ctx.moveTo(0, 0); ctx.rect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.clip('evenodd'); } function clipArc(ctx, element, endAngle) { const { startAngle , pixelMargin , x , y , outerRadius , innerRadius } = element; let angleMargin = pixelMargin / outerRadius; // Draw an inner border by clipping the arc and drawing a double-width border // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders ctx.beginPath(); ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); if (innerRadius > pixelMargin) { angleMargin = pixelMargin / innerRadius; ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); } else { ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI); } ctx.closePath(); ctx.clip(); } function toRadiusCorners(value) { return _readValueToProps(value, [ 'outerStart', 'outerEnd', 'innerStart', 'innerEnd' ]); } /** * Parse border radius from the provided options */ function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) { const o = toRadiusCorners(arc.options.borderRadius); const halfThickness = (outerRadius - innerRadius) / 2; const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2); // Outer limits are complicated. We want to compute the available angular distance at // a radius of outerRadius - borderRadius because for small angular distances, this term limits. // We compute at r = outerRadius - borderRadius because this circle defines the center of the border corners. // // If the borderRadius is large, that value can become negative. // This causes the outer borders to lose their radius entirely, which is rather unexpected. To solve that, if borderRadius > outerRadius // we know that the thickness term will dominate and compute the limits at that point const computeOuterLimit = (val)=>{ const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2; return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit)); }; return { outerStart: computeOuterLimit(o.outerStart), outerEnd: computeOuterLimit(o.outerEnd), innerStart: _limitValue(o.innerStart, 0, innerLimit), innerEnd: _limitValue(o.innerEnd, 0, innerLimit) }; } /** * Convert (r, πœƒ) to (x, y) */ function rThetaToXY(r, theta, x, y) { return { x: x + r * Math.cos(theta), y: y + r * Math.sin(theta) }; } /** * Path the arc, respecting border radius by separating into left and right halves. * * Start End * * 1--->a--->2 Outer * / \ * 8 3 * | | * | | * 7 4 * \ / * 6<---b<---5 Inner */ function pathArc(ctx, element, offset, spacing, end, circular) { const { x , y , startAngle: start , pixelMargin , innerRadius: innerR } = element; const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0); const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0; let spacingOffset = 0; const alpha = end - start; if (spacing) { // When spacing is present, it is the same for all items // So we adjust the start and end angle of the arc such that // the distance is the same as it would be without the spacing const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0; const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0; const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2; const adjustedAngle = avNogSpacingRadius !== 0 ? alpha * avNogSpacingRadius / (avNogSpacingRadius + spacing) : alpha; spacingOffset = (alpha - adjustedAngle) / 2; } const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius; const angleOffset = (alpha - beta) / 2; const startAngle = start + angleOffset + spacingOffset; const endAngle = end - angleOffset - spacingOffset; const { outerStart , outerEnd , innerStart , innerEnd } = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle); const outerStartAdjustedRadius = outerRadius - outerStart; const outerEndAdjustedRadius = outerRadius - outerEnd; const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius; const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius; const innerStartAdjustedRadius = innerRadius + innerStart; const innerEndAdjustedRadius = innerRadius + innerEnd; const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius; const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius; ctx.beginPath(); if (circular) { // The first arc segments from point 1 to point a to point 2 const outerMidAdjustedAngle = (outerStartAdjustedAngle + outerEndAdjustedAngle) / 2; ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerMidAdjustedAngle); ctx.arc(x, y, outerRadius, outerMidAdjustedAngle, outerEndAdjustedAngle); // The corner segment from point 2 to point 3 if (outerEnd > 0) { const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI); } // The line from point 3 to point 4 const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y); ctx.lineTo(p4.x, p4.y); // The corner segment from point 4 to point 5 if (innerEnd > 0) { const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI); } // The inner arc from point 5 to point b to point 6 const innerMidAdjustedAngle = (endAngle - innerEnd / innerRadius + (startAngle + innerStart / innerRadius)) / 2; ctx.arc(x, y, innerRadius, endAngle - innerEnd / innerRadius, innerMidAdjustedAngle, true); ctx.arc(x, y, innerRadius, innerMidAdjustedAngle, startAngle + innerStart / innerRadius, true); // The corner segment from point 6 to point 7 if (innerStart > 0) { const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI); } // The line from point 7 to point 8 const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y); ctx.lineTo(p8.x, p8.y); // The corner segment from point 8 to point 1 if (outerStart > 0) { const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y); ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle); } } else { ctx.moveTo(x, y); const outerStartX = Math.cos(outerStartAdjustedAngle) * outerRadius + x; const outerStartY = Math.sin(outerStartAdjustedAngle) * outerRadius + y; ctx.lineTo(outerStartX, outerStartY); const outerEndX = Math.cos(outerEndAdjustedAngle) * outerRadius + x; const outerEndY = Math.sin(outerEndAdjustedAngle) * outerRadius + y; ctx.lineTo(outerEndX, outerEndY); } ctx.closePath(); } function drawArc(ctx, element, offset, spacing, circular) { const { fullCircles , startAngle , circumference } = element; let endAngle = element.endAngle; if (fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); for(let i = 0; i < fullCircles; ++i){ ctx.fill(); } if (!isNaN(circumference)) { endAngle = startAngle + (circumference % TAU || TAU); } } pathArc(ctx, element, offset, spacing, endAngle, circular); ctx.fill(); return endAngle; } function drawBorder(ctx, element, offset, spacing, circular) { const { fullCircles , startAngle , circumference , options } = element; const { borderWidth , borderJoinStyle , borderDash , borderDashOffset , borderRadius } = options; const inner = options.borderAlign === 'inner'; if (!borderWidth) { return; } ctx.setLineDash(borderDash || []); ctx.lineDashOffset = borderDashOffset; if (inner) { ctx.lineWidth = borderWidth * 2; ctx.lineJoin = borderJoinStyle || 'round'; } else { ctx.lineWidth = borderWidth; ctx.lineJoin = borderJoinStyle || 'bevel'; } let endAngle = element.endAngle; if (fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); for(let i = 0; i < fullCircles; ++i){ ctx.stroke(); } if (!isNaN(circumference)) { endAngle = startAngle + (circumference % TAU || TAU); } } if (inner) { clipArc(ctx, element, endAngle); } if (options.selfJoin && endAngle - startAngle >= PI && borderRadius === 0 && borderJoinStyle !== 'miter') { clipSelf(ctx, element, endAngle); } if (!fullCircles) { pathArc(ctx, element, offset, spacing, endAngle, circular); ctx.stroke(); } } class ArcElement extends chart_Element { static id = 'arc'; static defaults = { borderAlign: 'center', borderColor: '#fff', borderDash: [], borderDashOffset: 0, borderJoinStyle: undefined, borderRadius: 0, borderWidth: 2, offset: 0, spacing: 0, angle: undefined, circular: true, selfJoin: false }; static defaultRoutes = { backgroundColor: 'backgroundColor' }; static descriptors = { _scriptable: true, _indexable: (name)=>name !== 'borderDash' }; circumference; endAngle; fullCircles; innerRadius; outerRadius; pixelMargin; startAngle; constructor(cfg){ super(); this.options = undefined; this.circumference = undefined; this.startAngle = undefined; this.endAngle = undefined; this.innerRadius = undefined; this.outerRadius = undefined; this.pixelMargin = 0; this.fullCircles = 0; if (cfg) { Object.assign(this, cfg); } } inRange(chartX, chartY, useFinalPosition) { const point = this.getProps([ 'x', 'y' ], useFinalPosition); const { angle , distance } = getAngleFromPoint(point, { x: chartX, y: chartY }); const { startAngle , endAngle , innerRadius , outerRadius , circumference } = this.getProps([ 'startAngle', 'endAngle', 'innerRadius', 'outerRadius', 'circumference' ], useFinalPosition); const rAdjust = (this.options.spacing + this.options.borderWidth) / 2; const _circumference = valueOrDefault(circumference, endAngle - startAngle); const nonZeroBetween = _angleBetween(angle, startAngle, endAngle) && startAngle !== endAngle; const betweenAngles = _circumference >= TAU || nonZeroBetween; const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust); return betweenAngles && withinRadius; } getCenterPoint(useFinalPosition) { const { x , y , startAngle , endAngle , innerRadius , outerRadius } = this.getProps([ 'x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius' ], useFinalPosition); const { offset , spacing } = this.options; const halfAngle = (startAngle + endAngle) / 2; const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2; return { x: x + Math.cos(halfAngle) * halfRadius, y: y + Math.sin(halfAngle) * halfRadius }; } tooltipPosition(useFinalPosition) { return this.getCenterPoint(useFinalPosition); } draw(ctx) { const { options , circumference } = this; const offset = (options.offset || 0) / 4; const spacing = (options.spacing || 0) / 2; const circular = options.circular; this.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0; this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0; if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) { return; } ctx.save(); const halfAngle = (this.startAngle + this.endAngle) / 2; ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); const fix = 1 - Math.sin(Math.min(PI, circumference || 0)); const radiusOffset = offset * fix; ctx.fillStyle = options.backgroundColor; ctx.strokeStyle = options.borderColor; drawArc(ctx, this, radiusOffset, spacing, circular); drawBorder(ctx, this, radiusOffset, spacing, circular); ctx.restore(); } } function setStyle(ctx, options, style = options) { ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle); ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash)); ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset); ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle); ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth); ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor); } function lineTo(ctx, previous, target) { ctx.lineTo(target.x, target.y); } function getLineMethod(options) { if (options.stepped) { return _steppedLineTo; } if (options.tension || options.cubicInterpolationMode === 'monotone') { return _bezierCurveTo; } return lineTo; } function pathVars(points, segment, params = {}) { const count = points.length; const { start: paramsStart = 0 , end: paramsEnd = count - 1 } = params; const { start: segmentStart , end: segmentEnd } = segment; const start = Math.max(paramsStart, segmentStart); const end = Math.min(paramsEnd, segmentEnd); const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd; return { count, start, loop: segment.loop, ilen: end < start && !outside ? count + end - start : end - start }; } function pathSegment(ctx, line, segment, params) { const { points , options } = line; const { count , start , loop , ilen } = pathVars(points, segment, params); const lineMethod = getLineMethod(options); let { move =true , reverse } = params || {}; let i, point, prev; for(i = 0; i <= ilen; ++i){ point = points[(start + (reverse ? ilen - i : i)) % count]; if (point.skip) { continue; } else if (move) { ctx.moveTo(point.x, point.y); move = false; } else { lineMethod(ctx, prev, point, reverse, options.stepped); } prev = point; } if (loop) { point = points[(start + (reverse ? ilen : 0)) % count]; lineMethod(ctx, prev, point, reverse, options.stepped); } return !!loop; } function fastPathSegment(ctx, line, segment, params) { const points = line.points; const { count , start , ilen } = pathVars(points, segment, params); const { move =true , reverse } = params || {}; let avgX = 0; let countX = 0; let i, point, prevX, minY, maxY, lastY; const pointIndex = (index)=>(start + (reverse ? ilen - index : index)) % count; const drawX = ()=>{ if (minY !== maxY) { ctx.lineTo(avgX, maxY); ctx.lineTo(avgX, minY); ctx.lineTo(avgX, lastY); } }; if (move) { point = points[pointIndex(0)]; ctx.moveTo(point.x, point.y); } for(i = 0; i <= ilen; ++i){ point = points[pointIndex(i)]; if (point.skip) { continue; } const x = point.x; const y = point.y; const truncX = x | 0; if (truncX === prevX) { if (y < minY) { minY = y; } else if (y > maxY) { maxY = y; } avgX = (countX * avgX + x) / ++countX; } else { drawX(); ctx.lineTo(x, y); prevX = truncX; countX = 0; minY = maxY = y; } lastY = y; } drawX(); } function _getSegmentMethod(line) { const opts = line.options; const borderDash = opts.borderDash && opts.borderDash.length; const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash; return useFastPath ? fastPathSegment : pathSegment; } function _getInterpolationMethod(options) { if (options.stepped) { return _steppedInterpolation; } if (options.tension || options.cubicInterpolationMode === 'monotone') { return _bezierInterpolation; } return _pointInLine; } function strokePathWithCache(ctx, line, start, count) { let path = line._path; if (!path) { path = line._path = new Path2D(); if (line.path(path, start, count)) { path.closePath(); } } setStyle(ctx, line.options); ctx.stroke(path); } function strokePathDirect(ctx, line, start, count) { const { segments , options } = line; const segmentMethod = _getSegmentMethod(line); for (const segment of segments){ setStyle(ctx, options, segment.style); ctx.beginPath(); if (segmentMethod(ctx, line, segment, { start, end: start + count - 1 })) { ctx.closePath(); } ctx.stroke(); } } const usePath2D = typeof Path2D === 'function'; function draw(ctx, line, start, count) { if (usePath2D && !line.options.segment) { strokePathWithCache(ctx, line, start, count); } else { strokePathDirect(ctx, line, start, count); } } class LineElement extends chart_Element { static id = 'line'; static defaults = { borderCapStyle: 'butt', borderDash: [], borderDashOffset: 0, borderJoinStyle: 'miter', borderWidth: 3, capBezierPoints: true, cubicInterpolationMode: 'default', fill: false, spanGaps: false, stepped: false, tension: 0 }; static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; static descriptors = { _scriptable: true, _indexable: (name)=>name !== 'borderDash' && name !== 'fill' }; constructor(cfg){ super(); this.animated = true; this.options = undefined; this._chart = undefined; this._loop = undefined; this._fullLoop = undefined; this._path = undefined; this._points = undefined; this._segments = undefined; this._decimated = false; this._pointsUpdated = false; this._datasetIndex = undefined; if (cfg) { Object.assign(this, cfg); } } updateControlPoints(chartArea, indexAxis) { const options = this.options; if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) { const loop = options.spanGaps ? this._loop : this._fullLoop; _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis); this._pointsUpdated = true; } } set points(points) { this._points = points; delete this._segments; delete this._path; this._pointsUpdated = false; } get points() { return this._points; } get segments() { return this._segments || (this._segments = _computeSegments(this, this.options.segment)); } first() { const segments = this.segments; const points = this.points; return segments.length && points[segments[0].start]; } last() { const segments = this.segments; const points = this.points; const count = segments.length; return count && points[segments[count - 1].end]; } interpolate(point, property) { const options = this.options; const value = point[property]; const points = this.points; const segments = _boundSegments(this, { property, start: value, end: value }); if (!segments.length) { return; } const result = []; const _interpolate = _getInterpolationMethod(options); let i, ilen; for(i = 0, ilen = segments.length; i < ilen; ++i){ const { start , end } = segments[i]; const p1 = points[start]; const p2 = points[end]; if (p1 === p2) { result.push(p1); continue; } const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); const interpolated = _interpolate(p1, p2, t, options.stepped); interpolated[property] = point[property]; result.push(interpolated); } return result.length === 1 ? result[0] : result; } pathSegment(ctx, segment, params) { const segmentMethod = _getSegmentMethod(this); return segmentMethod(ctx, this, segment, params); } path(ctx, start, count) { const segments = this.segments; const segmentMethod = _getSegmentMethod(this); let loop = this._loop; start = start || 0; count = count || this.points.length - start; for (const segment of segments){ loop &= segmentMethod(ctx, this, segment, { start, end: start + count - 1 }); } return !!loop; } draw(ctx, chartArea, start, count) { const options = this.options || {}; const points = this.points || []; if (points.length && options.borderWidth) { ctx.save(); draw(ctx, this, start, count); ctx.restore(); } if (this.animated) { this._pointsUpdated = false; this._path = undefined; } } } function inRange$1(el, pos, axis, useFinalPosition) { const options = el.options; const { [axis]: value } = el.getProps([ axis ], useFinalPosition); return Math.abs(pos - value) < options.radius + options.hitRadius; } class PointElement extends chart_Element { static id = 'point'; parsed; skip; stop; /** * @type {any} */ static defaults = { borderWidth: 1, hitRadius: 1, hoverBorderWidth: 1, hoverRadius: 4, pointStyle: 'circle', radius: 3, rotation: 0 }; /** * @type {any} */ static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; constructor(cfg){ super(); this.options = undefined; this.parsed = undefined; this.skip = undefined; this.stop = undefined; if (cfg) { Object.assign(this, cfg); } } inRange(mouseX, mouseY, useFinalPosition) { const options = this.options; const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2); } inXRange(mouseX, useFinalPosition) { return inRange$1(this, mouseX, 'x', useFinalPosition); } inYRange(mouseY, useFinalPosition) { return inRange$1(this, mouseY, 'y', useFinalPosition); } getCenterPoint(useFinalPosition) { const { x , y } = this.getProps([ 'x', 'y' ], useFinalPosition); return { x, y }; } size(options) { options = options || this.options || {}; let radius = options.radius || 0; radius = Math.max(radius, radius && options.hoverRadius || 0); const borderWidth = radius && options.borderWidth || 0; return (radius + borderWidth) * 2; } draw(ctx, area) { const options = this.options; if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) { return; } ctx.strokeStyle = options.borderColor; ctx.lineWidth = options.borderWidth; ctx.fillStyle = options.backgroundColor; drawPoint(ctx, options, this.x, this.y); } getRange() { const options = this.options || {}; // @ts-expect-error Fallbacks should never be hit in practice return options.radius + options.hitRadius; } } function getBarBounds(bar, useFinalPosition) { const { x , y , base , width , height } = bar.getProps([ 'x', 'y', 'base', 'width', 'height' ], useFinalPosition); let left, right, top, bottom, half; if (bar.horizontal) { half = height / 2; left = Math.min(x, base); right = Math.max(x, base); top = y - half; bottom = y + half; } else { half = width / 2; left = x - half; right = x + half; top = Math.min(y, base); bottom = Math.max(y, base); } return { left, top, right, bottom }; } function skipOrLimit(skip, value, min, max) { return skip ? 0 : _limitValue(value, min, max); } function parseBorderWidth(bar, maxW, maxH) { const value = bar.options.borderWidth; const skip = bar.borderSkipped; const o = toTRBL(value); return { t: skipOrLimit(skip.top, o.top, 0, maxH), r: skipOrLimit(skip.right, o.right, 0, maxW), b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), l: skipOrLimit(skip.left, o.left, 0, maxW) }; } function parseBorderRadius(bar, maxW, maxH) { const { enableBorderRadius } = bar.getProps([ 'enableBorderRadius' ]); const value = bar.options.borderRadius; const o = toTRBLCorners(value); const maxR = Math.min(maxW, maxH); const skip = bar.borderSkipped; const enableBorder = enableBorderRadius || isObject(value); return { topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR), topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR), bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR), bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR) }; } function boundingRects(bar) { const bounds = getBarBounds(bar); const width = bounds.right - bounds.left; const height = bounds.bottom - bounds.top; const border = parseBorderWidth(bar, width / 2, height / 2); const radius = parseBorderRadius(bar, width / 2, height / 2); return { outer: { x: bounds.left, y: bounds.top, w: width, h: height, radius }, inner: { x: bounds.left + border.l, y: bounds.top + border.t, w: width - border.l - border.r, h: height - border.t - border.b, radius: { topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)), topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)), bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)), bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)) } } }; } function inRange(bar, x, y, useFinalPosition) { const skipX = x === null; const skipY = y === null; const skipBoth = skipX && skipY; const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); return bounds && (skipX || _isBetween(x, bounds.left, bounds.right)) && (skipY || _isBetween(y, bounds.top, bounds.bottom)); } function hasRadius(radius) { return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight; } function addNormalRectPath(ctx, rect) { ctx.rect(rect.x, rect.y, rect.w, rect.h); } function inflateRect(rect, amount, refRect = {}) { const x = rect.x !== refRect.x ? -amount : 0; const y = rect.y !== refRect.y ? -amount : 0; const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; return { x: rect.x + x, y: rect.y + y, w: rect.w + w, h: rect.h + h, radius: rect.radius }; } class BarElement extends chart_Element { static id = 'bar'; static defaults = { borderSkipped: 'start', borderWidth: 0, borderRadius: 0, inflateAmount: 'auto', pointStyle: undefined }; static defaultRoutes = { backgroundColor: 'backgroundColor', borderColor: 'borderColor' }; constructor(cfg){ super(); this.options = undefined; this.horizontal = undefined; this.base = undefined; this.width = undefined; this.height = undefined; this.inflateAmount = undefined; if (cfg) { Object.assign(this, cfg); } } draw(ctx) { const { inflateAmount , options: { borderColor , backgroundColor } } = this; const { inner , outer } = boundingRects(this); const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; ctx.save(); if (outer.w !== inner.w || outer.h !== inner.h) { ctx.beginPath(); addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); ctx.clip(); addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); ctx.fillStyle = borderColor; ctx.fill('evenodd'); } ctx.beginPath(); addRectPath(ctx, inflateRect(inner, inflateAmount)); ctx.fillStyle = backgroundColor; ctx.fill(); ctx.restore(); } inRange(mouseX, mouseY, useFinalPosition) { return inRange(this, mouseX, mouseY, useFinalPosition); } inXRange(mouseX, useFinalPosition) { return inRange(this, mouseX, null, useFinalPosition); } inYRange(mouseY, useFinalPosition) { return inRange(this, null, mouseY, useFinalPosition); } getCenterPoint(useFinalPosition) { const { x , y , base , horizontal } = this.getProps([ 'x', 'y', 'base', 'horizontal' ], useFinalPosition); return { x: horizontal ? (x + base) / 2 : x, y: horizontal ? y : (y + base) / 2 }; } getRange(axis) { return axis === 'x' ? this.width / 2 : this.height / 2; } } var chart_elements = /*#__PURE__*/Object.freeze({ __proto__: null, ArcElement: ArcElement, BarElement: BarElement, LineElement: LineElement, PointElement: PointElement }); const BORDER_COLORS = [ 'rgb(54, 162, 235)', 'rgb(255, 99, 132)', 'rgb(255, 159, 64)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)', 'rgb(153, 102, 255)', 'rgb(201, 203, 207)' // grey ]; // Border colors with 50% transparency const BACKGROUND_COLORS = /* #__PURE__ */ BORDER_COLORS.map((color)=>color.replace('rgb(', 'rgba(').replace(')', ', 0.5)')); function getBorderColor(i) { return BORDER_COLORS[i % BORDER_COLORS.length]; } function getBackgroundColor(i) { return BACKGROUND_COLORS[i % BACKGROUND_COLORS.length]; } function colorizeDefaultDataset(dataset, i) { dataset.borderColor = getBorderColor(i); dataset.backgroundColor = getBackgroundColor(i); return ++i; } function colorizeDoughnutDataset(dataset, i) { dataset.backgroundColor = dataset.data.map(()=>getBorderColor(i++)); return i; } function colorizePolarAreaDataset(dataset, i) { dataset.backgroundColor = dataset.data.map(()=>getBackgroundColor(i++)); return i; } function getColorizer(chart) { let i = 0; return (dataset, datasetIndex)=>{ const controller = chart.getDatasetMeta(datasetIndex).controller; if (controller instanceof DoughnutController) { i = colorizeDoughnutDataset(dataset, i); } else if (controller instanceof PolarAreaController) { i = colorizePolarAreaDataset(dataset, i); } else if (controller) { i = colorizeDefaultDataset(dataset, i); } }; } function containsColorsDefinitions(descriptors) { let k; for(k in descriptors){ if (descriptors[k].borderColor || descriptors[k].backgroundColor) { return true; } } return false; } function containsColorsDefinition(descriptor) { return descriptor && (descriptor.borderColor || descriptor.backgroundColor); } function containsDefaultColorsDefenitions() { return defaults.borderColor !== 'rgba(0,0,0,0.1)' || defaults.backgroundColor !== 'rgba(0,0,0,0.1)'; } var plugin_colors = { id: 'colors', defaults: { enabled: true, forceOverride: false }, beforeLayout (chart, _args, options) { if (!options.enabled) { return; } const { data: { datasets } , options: chartOptions } = chart.config; const { elements } = chartOptions; const containsColorDefenition = containsColorsDefinitions(datasets) || containsColorsDefinition(chartOptions) || elements && containsColorsDefinitions(elements) || containsDefaultColorsDefenitions(); if (!options.forceOverride && containsColorDefenition) { return; } const colorizer = getColorizer(chart); datasets.forEach(colorizer); } }; function lttbDecimation(data, start, count, availableWidth, options) { const samples = options.samples || availableWidth; if (samples >= count) { return data.slice(start, start + count); } const decimated = []; const bucketWidth = (count - 2) / (samples - 2); let sampledIndex = 0; const endIndex = start + count - 1; let a = start; let i, maxAreaPoint, maxArea, area, nextA; decimated[sampledIndex++] = data[a]; for(i = 0; i < samples - 2; i++){ let avgX = 0; let avgY = 0; let j; const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start; const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start; const avgRangeLength = avgRangeEnd - avgRangeStart; for(j = avgRangeStart; j < avgRangeEnd; j++){ avgX += data[j].x; avgY += data[j].y; } avgX /= avgRangeLength; avgY /= avgRangeLength; const rangeOffs = Math.floor(i * bucketWidth) + 1 + start; const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start; const { x: pointAx , y: pointAy } = data[a]; maxArea = area = -1; for(j = rangeOffs; j < rangeTo; j++){ area = 0.5 * Math.abs((pointAx - avgX) * (data[j].y - pointAy) - (pointAx - data[j].x) * (avgY - pointAy)); if (area > maxArea) { maxArea = area; maxAreaPoint = data[j]; nextA = j; } } decimated[sampledIndex++] = maxAreaPoint; a = nextA; } decimated[sampledIndex++] = data[endIndex]; return decimated; } function minMaxDecimation(data, start, count, availableWidth) { let avgX = 0; let countX = 0; let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY; const decimated = []; const endIndex = start + count - 1; const xMin = data[start].x; const xMax = data[endIndex].x; const dx = xMax - xMin; for(i = start; i < start + count; ++i){ point = data[i]; x = (point.x - xMin) / dx * availableWidth; y = point.y; const truncX = x | 0; if (truncX === prevX) { if (y < minY) { minY = y; minIndex = i; } else if (y > maxY) { maxY = y; maxIndex = i; } avgX = (countX * avgX + point.x) / ++countX; } else { const lastIndex = i - 1; if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) { const intermediateIndex1 = Math.min(minIndex, maxIndex); const intermediateIndex2 = Math.max(minIndex, maxIndex); if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) { decimated.push({ ...data[intermediateIndex1], x: avgX }); } if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) { decimated.push({ ...data[intermediateIndex2], x: avgX }); } } if (i > 0 && lastIndex !== startIndex) { decimated.push(data[lastIndex]); } decimated.push(point); prevX = truncX; countX = 0; minY = maxY = y; minIndex = maxIndex = startIndex = i; } } return decimated; } function cleanDecimatedDataset(dataset) { if (dataset._decimated) { const data = dataset._data; delete dataset._decimated; delete dataset._data; Object.defineProperty(dataset, 'data', { configurable: true, enumerable: true, writable: true, value: data }); } } function cleanDecimatedData(chart) { chart.data.datasets.forEach((dataset)=>{ cleanDecimatedDataset(dataset); }); } function getStartAndCountOfVisiblePointsSimplified(meta, points) { const pointCount = points.length; let start = 0; let count; const { iScale } = meta; const { min , max , minDefined , maxDefined } = iScale.getUserBounds(); if (minDefined) { start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1); } if (maxDefined) { count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start; } else { count = pointCount - start; } return { start, count }; } var plugin_decimation = { id: 'decimation', defaults: { algorithm: 'min-max', enabled: false }, beforeElementsUpdate: (chart, args, options)=>{ if (!options.enabled) { cleanDecimatedData(chart); return; } const availableWidth = chart.width; chart.data.datasets.forEach((dataset, datasetIndex)=>{ const { _data , indexAxis } = dataset; const meta = chart.getDatasetMeta(datasetIndex); const data = _data || dataset.data; if (resolve([ indexAxis, chart.options.indexAxis ]) === 'y') { return; } if (!meta.controller.supportsDecimation) { return; } const xAxis = chart.scales[meta.xAxisID]; if (xAxis.type !== 'linear' && xAxis.type !== 'time') { return; } if (chart.options.parsing) { return; } let { start , count } = getStartAndCountOfVisiblePointsSimplified(meta, data); const threshold = options.threshold || 4 * availableWidth; if (count <= threshold) { cleanDecimatedDataset(dataset); return; } if (isNullOrUndef(_data)) { dataset._data = data; delete dataset.data; Object.defineProperty(dataset, 'data', { configurable: true, enumerable: true, get: function() { return this._decimated; }, set: function(d) { this._data = d; } }); } let decimated; switch(options.algorithm){ case 'lttb': decimated = lttbDecimation(data, start, count, availableWidth, options); break; case 'min-max': decimated = minMaxDecimation(data, start, count, availableWidth); break; default: throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`); } dataset._decimated = decimated; }); }, destroy (chart) { cleanDecimatedData(chart); } }; function _segments(line, target, property) { const segments = line.segments; const points = line.points; const tpoints = target.points; const parts = []; for (const segment of segments){ let { start , end } = segment; end = _findSegmentEnd(start, end, points); const bounds = _getBounds(property, points[start], points[end], segment.loop); if (!target.segments) { parts.push({ source: segment, target: bounds, start: points[start], end: points[end] }); continue; } const targetSegments = _boundSegments(target, bounds); for (const tgt of targetSegments){ const subBounds = _getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop); const fillSources = _boundSegment(segment, points, subBounds); for (const fillSource of fillSources){ parts.push({ source: fillSource, target: tgt, start: { [property]: _getEdge(bounds, subBounds, 'start', Math.max) }, end: { [property]: _getEdge(bounds, subBounds, 'end', Math.min) } }); } } } return parts; } function _getBounds(property, first, last, loop) { if (loop) { return; } let start = first[property]; let end = last[property]; if (property === 'angle') { start = _normalizeAngle(start); end = _normalizeAngle(end); } return { property, start, end }; } function _pointsFromSegments(boundary, line) { const { x =null , y =null } = boundary || {}; const linePoints = line.points; const points = []; line.segments.forEach(({ start , end })=>{ end = _findSegmentEnd(start, end, linePoints); const first = linePoints[start]; const last = linePoints[end]; if (y !== null) { points.push({ x: first.x, y }); points.push({ x: last.x, y }); } else if (x !== null) { points.push({ x, y: first.y }); points.push({ x, y: last.y }); } }); return points; } function _findSegmentEnd(start, end, points) { for(; end > start; end--){ const point = points[end]; if (!isNaN(point.x) && !isNaN(point.y)) { break; } } return end; } function _getEdge(a, b, prop, fn) { if (a && b) { return fn(a[prop], b[prop]); } return a ? a[prop] : b ? b[prop] : 0; } function _createBoundaryLine(boundary, line) { let points = []; let _loop = false; if (isArray(boundary)) { _loop = true; points = boundary; } else { points = _pointsFromSegments(boundary, line); } return points.length ? new LineElement({ points, options: { tension: 0 }, _loop, _fullLoop: _loop }) : null; } function _shouldApplyFill(source) { return source && source.fill !== false; } function _resolveTarget(sources, index, propagate) { const source = sources[index]; let fill = source.fill; const visited = [ index ]; let target; if (!propagate) { return fill; } while(fill !== false && visited.indexOf(fill) === -1){ if (!isNumberFinite(fill)) { return fill; } target = sources[fill]; if (!target) { return false; } if (target.visible) { return fill; } visited.push(fill); fill = target.fill; } return false; } function _decodeFill(line, index, count) { const fill = parseFillOption(line); if (isObject(fill)) { return isNaN(fill.value) ? false : fill; } let target = parseFloat(fill); if (isNumberFinite(target) && Math.floor(target) === target) { return decodeTargetIndex(fill[0], index, target, count); } return [ 'origin', 'start', 'end', 'stack', 'shape' ].indexOf(fill) >= 0 && fill; } function decodeTargetIndex(firstCh, index, target, count) { if (firstCh === '-' || firstCh === '+') { target = index + target; } if (target === index || target < 0 || target >= count) { return false; } return target; } function _getTargetPixel(fill, scale) { let pixel = null; if (fill === 'start') { pixel = scale.bottom; } else if (fill === 'end') { pixel = scale.top; } else if (isObject(fill)) { pixel = scale.getPixelForValue(fill.value); } else if (scale.getBasePixel) { pixel = scale.getBasePixel(); } return pixel; } function _getTargetValue(fill, scale, startValue) { let value; if (fill === 'start') { value = startValue; } else if (fill === 'end') { value = scale.options.reverse ? scale.min : scale.max; } else if (isObject(fill)) { value = fill.value; } else { value = scale.getBaseValue(); } return value; } function parseFillOption(line) { const options = line.options; const fillOption = options.fill; let fill = valueOrDefault(fillOption && fillOption.target, fillOption); if (fill === undefined) { fill = !!options.backgroundColor; } if (fill === false || fill === null) { return false; } if (fill === true) { return 'origin'; } return fill; } function _buildStackLine(source) { const { scale , index , line } = source; const points = []; const segments = line.segments; const sourcePoints = line.points; const linesBelow = getLinesBelow(scale, index); linesBelow.push(_createBoundaryLine({ x: null, y: scale.bottom }, line)); for(let i = 0; i < segments.length; i++){ const segment = segments[i]; for(let j = segment.start; j <= segment.end; j++){ addPointsBelow(points, sourcePoints[j], linesBelow); } } return new LineElement({ points, options: {} }); } function getLinesBelow(scale, index) { const below = []; const metas = scale.getMatchingVisibleMetas('line'); for(let i = 0; i < metas.length; i++){ const meta = metas[i]; if (meta.index === index) { break; } if (!meta.hidden) { below.unshift(meta.dataset); } } return below; } function addPointsBelow(points, sourcePoint, linesBelow) { const postponed = []; for(let j = 0; j < linesBelow.length; j++){ const line = linesBelow[j]; const { first , last , point } = findPoint(line, sourcePoint, 'x'); if (!point || first && last) { continue; } if (first) { postponed.unshift(point); } else { points.push(point); if (!last) { break; } } } points.push(...postponed); } function findPoint(line, sourcePoint, property) { const point = line.interpolate(sourcePoint, property); if (!point) { return {}; } const pointValue = point[property]; const segments = line.segments; const linePoints = line.points; let first = false; let last = false; for(let i = 0; i < segments.length; i++){ const segment = segments[i]; const firstValue = linePoints[segment.start][property]; const lastValue = linePoints[segment.end][property]; if (_isBetween(pointValue, firstValue, lastValue)) { first = pointValue === firstValue; last = pointValue === lastValue; break; } } return { first, last, point }; } class simpleArc { constructor(opts){ this.x = opts.x; this.y = opts.y; this.radius = opts.radius; } pathSegment(ctx, bounds, opts) { const { x , y , radius } = this; bounds = bounds || { start: 0, end: TAU }; ctx.arc(x, y, radius, bounds.end, bounds.start, true); return !opts.bounds; } interpolate(point) { const { x , y , radius } = this; const angle = point.angle; return { x: x + Math.cos(angle) * radius, y: y + Math.sin(angle) * radius, angle }; } } function _getTarget(source) { const { chart , fill , line } = source; if (isNumberFinite(fill)) { return getLineByIndex(chart, fill); } if (fill === 'stack') { return _buildStackLine(source); } if (fill === 'shape') { return true; } const boundary = computeBoundary(source); if (boundary instanceof simpleArc) { return boundary; } return _createBoundaryLine(boundary, line); } function getLineByIndex(chart, index) { const meta = chart.getDatasetMeta(index); const visible = meta && chart.isDatasetVisible(index); return visible ? meta.dataset : null; } function computeBoundary(source) { const scale = source.scale || {}; if (scale.getPointPositionForValue) { return computeCircularBoundary(source); } return computeLinearBoundary(source); } function computeLinearBoundary(source) { const { scale ={} , fill } = source; const pixel = _getTargetPixel(fill, scale); if (isNumberFinite(pixel)) { const horizontal = scale.isHorizontal(); return { x: horizontal ? pixel : null, y: horizontal ? null : pixel }; } return null; } function computeCircularBoundary(source) { const { scale , fill } = source; const options = scale.options; const length = scale.getLabels().length; const start = options.reverse ? scale.max : scale.min; const value = _getTargetValue(fill, scale, start); const target = []; if (options.grid.circular) { const center = scale.getPointPositionForValue(0, start); return new simpleArc({ x: center.x, y: center.y, radius: scale.getDistanceFromCenterForValue(value) }); } for(let i = 0; i < length; ++i){ target.push(scale.getPointPositionForValue(i, value)); } return target; } function _drawfill(ctx, source, area) { const target = _getTarget(source); const { chart , index , line , scale , axis } = source; const lineOpts = line.options; const fillOption = lineOpts.fill; const color = lineOpts.backgroundColor; const { above =color , below =color } = fillOption || {}; const meta = chart.getDatasetMeta(index); const clip = getDatasetClipArea(chart, meta); if (target && line.points.length) { clipArea(ctx, area); doFill(ctx, { line, target, above, below, area, scale, axis, clip }); unclipArea(ctx); } } function doFill(ctx, cfg) { const { line , target , above , below , area , scale , clip } = cfg; const property = line._loop ? 'angle' : cfg.axis; ctx.save(); let fillColor = below; if (below !== above) { if (property === 'x') { clipVertical(ctx, target, area.top); fill(ctx, { line, target, color: above, scale, property, clip }); ctx.restore(); ctx.save(); clipVertical(ctx, target, area.bottom); } else if (property === 'y') { clipHorizontal(ctx, target, area.left); fill(ctx, { line, target, color: below, scale, property, clip }); ctx.restore(); ctx.save(); clipHorizontal(ctx, target, area.right); fillColor = above; } } fill(ctx, { line, target, color: fillColor, scale, property, clip }); ctx.restore(); } function clipVertical(ctx, target, clipY) { const { segments , points } = target; let first = true; let lineLoop = false; ctx.beginPath(); for (const segment of segments){ const { start , end } = segment; const firstPoint = points[start]; const lastPoint = points[_findSegmentEnd(start, end, points)]; if (first) { ctx.moveTo(firstPoint.x, firstPoint.y); first = false; } else { ctx.lineTo(firstPoint.x, clipY); ctx.lineTo(firstPoint.x, firstPoint.y); } lineLoop = !!target.pathSegment(ctx, segment, { move: lineLoop }); if (lineLoop) { ctx.closePath(); } else { ctx.lineTo(lastPoint.x, clipY); } } ctx.lineTo(target.first().x, clipY); ctx.closePath(); ctx.clip(); } function clipHorizontal(ctx, target, clipX) { const { segments , points } = target; let first = true; let lineLoop = false; ctx.beginPath(); for (const segment of segments){ const { start , end } = segment; const firstPoint = points[start]; const lastPoint = points[_findSegmentEnd(start, end, points)]; if (first) { ctx.moveTo(firstPoint.x, firstPoint.y); first = false; } else { ctx.lineTo(clipX, firstPoint.y); ctx.lineTo(firstPoint.x, firstPoint.y); } lineLoop = !!target.pathSegment(ctx, segment, { move: lineLoop }); if (lineLoop) { ctx.closePath(); } else { ctx.lineTo(clipX, lastPoint.y); } } ctx.lineTo(clipX, target.first().y); ctx.closePath(); ctx.clip(); } function fill(ctx, cfg) { const { line , target , property , color , scale , clip } = cfg; const segments = _segments(line, target, property); for (const { source: src , target: tgt , start , end } of segments){ const { style: { backgroundColor =color } = {} } = src; const notShape = target !== true; ctx.save(); ctx.fillStyle = backgroundColor; clipBounds(ctx, scale, clip, notShape && _getBounds(property, start, end)); ctx.beginPath(); const lineLoop = !!line.pathSegment(ctx, src); let loop; if (notShape) { if (lineLoop) { ctx.closePath(); } else { interpolatedLineTo(ctx, target, end, property); } const targetLoop = !!target.pathSegment(ctx, tgt, { move: lineLoop, reverse: true }); loop = lineLoop && targetLoop; if (!loop) { interpolatedLineTo(ctx, target, start, property); } } ctx.closePath(); ctx.fill(loop ? 'evenodd' : 'nonzero'); ctx.restore(); } } function clipBounds(ctx, scale, clip, bounds) { const chartArea = scale.chart.chartArea; const { property , start , end } = bounds || {}; if (property === 'x' || property === 'y') { let left, top, right, bottom; if (property === 'x') { left = start; top = chartArea.top; right = end; bottom = chartArea.bottom; } else { left = chartArea.left; top = start; right = chartArea.right; bottom = end; } ctx.beginPath(); if (clip) { left = Math.max(left, clip.left); right = Math.min(right, clip.right); top = Math.max(top, clip.top); bottom = Math.min(bottom, clip.bottom); } ctx.rect(left, top, right - left, bottom - top); ctx.clip(); } } function interpolatedLineTo(ctx, target, point, property) { const interpolatedPoint = target.interpolate(point, property); if (interpolatedPoint) { ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); } } var index = { id: 'filler', afterDatasetsUpdate (chart, _args, options) { const count = (chart.data.datasets || []).length; const sources = []; let meta, i, line, source; for(i = 0; i < count; ++i){ meta = chart.getDatasetMeta(i); line = meta.dataset; source = null; if (line && line.options && line instanceof LineElement) { source = { visible: chart.isDatasetVisible(i), index: i, fill: _decodeFill(line, i, count), chart, axis: meta.controller.options.indexAxis, scale: meta.vScale, line }; } meta.$filler = source; sources.push(source); } for(i = 0; i < count; ++i){ source = sources[i]; if (!source || source.fill === false) { continue; } source.fill = _resolveTarget(sources, i, options.propagate); } }, beforeDraw (chart, _args, options) { const draw = options.drawTime === 'beforeDraw'; const metasets = chart.getSortedVisibleDatasetMetas(); const area = chart.chartArea; for(let i = metasets.length - 1; i >= 0; --i){ const source = metasets[i].$filler; if (!source) { continue; } source.line.updateControlPoints(area, source.axis); if (draw && source.fill) { _drawfill(chart.ctx, source, area); } } }, beforeDatasetsDraw (chart, _args, options) { if (options.drawTime !== 'beforeDatasetsDraw') { return; } const metasets = chart.getSortedVisibleDatasetMetas(); for(let i = metasets.length - 1; i >= 0; --i){ const source = metasets[i].$filler; if (_shouldApplyFill(source)) { _drawfill(chart.ctx, source, chart.chartArea); } } }, beforeDatasetDraw (chart, args, options) { const source = args.meta.$filler; if (!_shouldApplyFill(source) || options.drawTime !== 'beforeDatasetDraw') { return; } _drawfill(chart.ctx, source, chart.chartArea); }, defaults: { propagate: true, drawTime: 'beforeDatasetDraw' } }; const getBoxSize = (labelOpts, fontSize)=>{ let { boxHeight =fontSize , boxWidth =fontSize } = labelOpts; if (labelOpts.usePointStyle) { boxHeight = Math.min(boxHeight, fontSize); boxWidth = labelOpts.pointStyleWidth || Math.min(boxWidth, fontSize); } return { boxWidth, boxHeight, itemHeight: Math.max(fontSize, boxHeight) }; }; const itemsEqual = (a, b)=>a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index; class Legend extends chart_Element { constructor(config){ super(); this._added = false; this.legendHitBoxes = []; this._hoveredItem = null; this.doughnutMode = false; this.chart = config.chart; this.options = config.options; this.ctx = config.ctx; this.legendItems = undefined; this.columnSizes = undefined; this.lineWidths = undefined; this.maxHeight = undefined; this.maxWidth = undefined; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.height = undefined; this.width = undefined; this._margins = undefined; this.position = undefined; this.weight = undefined; this.fullSize = undefined; } update(maxWidth, maxHeight, margins) { this.maxWidth = maxWidth; this.maxHeight = maxHeight; this._margins = margins; this.setDimensions(); this.buildLabels(); this.fit(); } setDimensions() { if (this.isHorizontal()) { this.width = this.maxWidth; this.left = this._margins.left; this.right = this.width; } else { this.height = this.maxHeight; this.top = this._margins.top; this.bottom = this.height; } } buildLabels() { const labelOpts = this.options.labels || {}; let legendItems = callback(labelOpts.generateLabels, [ this.chart ], this) || []; if (labelOpts.filter) { legendItems = legendItems.filter((item)=>labelOpts.filter(item, this.chart.data)); } if (labelOpts.sort) { legendItems = legendItems.sort((a, b)=>labelOpts.sort(a, b, this.chart.data)); } if (this.options.reverse) { legendItems.reverse(); } this.legendItems = legendItems; } fit() { const { options , ctx } = this; if (!options.display) { this.width = this.height = 0; return; } const labelOpts = options.labels; const labelFont = toFont(labelOpts.font); const fontSize = labelFont.size; const titleHeight = this._computeTitleHeight(); const { boxWidth , itemHeight } = getBoxSize(labelOpts, fontSize); let width, height; ctx.font = labelFont.string; if (this.isHorizontal()) { width = this.maxWidth; height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10; } else { height = this.maxHeight; width = this._fitCols(titleHeight, labelFont, boxWidth, itemHeight) + 10; } this.width = Math.min(width, options.maxWidth || this.maxWidth); this.height = Math.min(height, options.maxHeight || this.maxHeight); } _fitRows(titleHeight, fontSize, boxWidth, itemHeight) { const { ctx , maxWidth , options: { labels: { padding } } } = this; const hitboxes = this.legendHitBoxes = []; const lineWidths = this.lineWidths = [ 0 ]; const lineHeight = itemHeight + padding; let totalHeight = titleHeight; ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; let row = -1; let top = -lineHeight; this.legendItems.forEach((legendItem, i)=>{ const itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width; if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) { totalHeight += lineHeight; lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; top += lineHeight; row++; } hitboxes[i] = { left: 0, top, row, width: itemWidth, height: itemHeight }; lineWidths[lineWidths.length - 1] += itemWidth + padding; }); return totalHeight; } _fitCols(titleHeight, labelFont, boxWidth, _itemHeight) { const { ctx , maxHeight , options: { labels: { padding } } } = this; const hitboxes = this.legendHitBoxes = []; const columnSizes = this.columnSizes = []; const heightLimit = maxHeight - titleHeight; let totalWidth = padding; let currentColWidth = 0; let currentColHeight = 0; let left = 0; let col = 0; this.legendItems.forEach((legendItem, i)=>{ const { itemWidth , itemHeight } = calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight); if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) { totalWidth += currentColWidth + padding; columnSizes.push({ width: currentColWidth, height: currentColHeight }); left += currentColWidth + padding; col++; currentColWidth = currentColHeight = 0; } hitboxes[i] = { left, top: currentColHeight, col, width: itemWidth, height: itemHeight }; currentColWidth = Math.max(currentColWidth, itemWidth); currentColHeight += itemHeight + padding; }); totalWidth += currentColWidth; columnSizes.push({ width: currentColWidth, height: currentColHeight }); return totalWidth; } adjustHitBoxes() { if (!this.options.display) { return; } const titleHeight = this._computeTitleHeight(); const { legendHitBoxes: hitboxes , options: { align , labels: { padding } , rtl } } = this; const rtlHelper = getRtlAdapter(rtl, this.left, this.width); if (this.isHorizontal()) { let row = 0; let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); for (const hitbox of hitboxes){ if (row !== hitbox.row) { row = hitbox.row; left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]); } hitbox.top += this.top + titleHeight + padding; hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width); left += hitbox.width + padding; } } else { let col = 0; let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); for (const hitbox of hitboxes){ if (hitbox.col !== col) { col = hitbox.col; top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height); } hitbox.top = top; hitbox.left += this.left + padding; hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width); top += hitbox.height + padding; } } } isHorizontal() { return this.options.position === 'top' || this.options.position === 'bottom'; } draw() { if (this.options.display) { const ctx = this.ctx; clipArea(ctx, this); this._draw(); unclipArea(ctx); } } _draw() { const { options: opts , columnSizes , lineWidths , ctx } = this; const { align , labels: labelOpts } = opts; const defaultColor = defaults.color; const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); const labelFont = toFont(labelOpts.font); const { padding } = labelOpts; const fontSize = labelFont.size; const halfFontSize = fontSize / 2; let cursor; this.drawTitle(); ctx.textAlign = rtlHelper.textAlign('left'); ctx.textBaseline = 'middle'; ctx.lineWidth = 0.5; ctx.font = labelFont.string; const { boxWidth , boxHeight , itemHeight } = getBoxSize(labelOpts, fontSize); const drawLegendBox = function(x, y, legendItem) { if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { return; } ctx.save(); const lineWidth = valueOrDefault(legendItem.lineWidth, 1); ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); ctx.lineWidth = lineWidth; ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); if (labelOpts.usePointStyle) { const drawOptions = { radius: boxHeight * Math.SQRT2 / 2, pointStyle: legendItem.pointStyle, rotation: legendItem.rotation, borderWidth: lineWidth }; const centerX = rtlHelper.xPlus(x, boxWidth / 2); const centerY = y + halfFontSize; drawPointLegend(ctx, drawOptions, centerX, centerY, labelOpts.pointStyleWidth && boxWidth); } else { const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth); const borderRadius = toTRBLCorners(legendItem.borderRadius); ctx.beginPath(); if (Object.values(borderRadius).some((v)=>v !== 0)) { addRoundedRectPath(ctx, { x: xBoxLeft, y: yBoxTop, w: boxWidth, h: boxHeight, radius: borderRadius }); } else { ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight); } ctx.fill(); if (lineWidth !== 0) { ctx.stroke(); } } ctx.restore(); }; const fillText = function(x, y, legendItem) { renderText(ctx, legendItem.text, x, y + itemHeight / 2, labelFont, { strikethrough: legendItem.hidden, textAlign: rtlHelper.textAlign(legendItem.textAlign) }); }; const isHorizontal = this.isHorizontal(); const titleHeight = this._computeTitleHeight(); if (isHorizontal) { cursor = { x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]), y: this.top + padding + titleHeight, line: 0 }; } else { cursor = { x: this.left + padding, y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height), line: 0 }; } overrideTextDirection(this.ctx, opts.textDirection); const lineHeight = itemHeight + padding; this.legendItems.forEach((legendItem, i)=>{ ctx.strokeStyle = legendItem.fontColor; ctx.fillStyle = legendItem.fontColor; const textWidth = ctx.measureText(legendItem.text).width; const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign)); const width = boxWidth + halfFontSize + textWidth; let x = cursor.x; let y = cursor.y; rtlHelper.setWidth(this.width); if (isHorizontal) { if (i > 0 && x + width + padding > this.right) { y = cursor.y += lineHeight; cursor.line++; x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]); } } else if (i > 0 && y + lineHeight > this.bottom) { x = cursor.x = x + columnSizes[cursor.line].width + padding; cursor.line++; y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height); } const realX = rtlHelper.x(x); drawLegendBox(realX, y, legendItem); x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl); fillText(rtlHelper.x(x), y, legendItem); if (isHorizontal) { cursor.x += width + padding; } else if (typeof legendItem.text !== 'string') { const fontLineHeight = labelFont.lineHeight; cursor.y += calculateLegendItemHeight(legendItem, fontLineHeight) + padding; } else { cursor.y += lineHeight; } }); restoreTextDirection(this.ctx, opts.textDirection); } drawTitle() { const opts = this.options; const titleOpts = opts.title; const titleFont = toFont(titleOpts.font); const titlePadding = toPadding(titleOpts.padding); if (!titleOpts.display) { return; } const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width); const ctx = this.ctx; const position = titleOpts.position; const halfFontSize = titleFont.size / 2; const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize; let y; let left = this.left; let maxWidth = this.width; if (this.isHorizontal()) { maxWidth = Math.max(...this.lineWidths); y = this.top + topPaddingPlusHalfFontSize; left = _alignStartEnd(opts.align, left, this.right - maxWidth); } else { const maxHeight = this.columnSizes.reduce((acc, size)=>Math.max(acc, size.height), 0); y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight()); } const x = _alignStartEnd(position, left, left + maxWidth); ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position)); ctx.textBaseline = 'middle'; ctx.strokeStyle = titleOpts.color; ctx.fillStyle = titleOpts.color; ctx.font = titleFont.string; renderText(ctx, titleOpts.text, x, y, titleFont); } _computeTitleHeight() { const titleOpts = this.options.title; const titleFont = toFont(titleOpts.font); const titlePadding = toPadding(titleOpts.padding); return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; } _getLegendItemAt(x, y) { let i, hitBox, lh; if (_isBetween(x, this.left, this.right) && _isBetween(y, this.top, this.bottom)) { lh = this.legendHitBoxes; for(i = 0; i < lh.length; ++i){ hitBox = lh[i]; if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width) && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) { return this.legendItems[i]; } } } return null; } handleEvent(e) { const opts = this.options; if (!isListened(e.type, opts)) { return; } const hoveredItem = this._getLegendItemAt(e.x, e.y); if (e.type === 'mousemove' || e.type === 'mouseout') { const previous = this._hoveredItem; const sameItem = itemsEqual(previous, hoveredItem); if (previous && !sameItem) { callback(opts.onLeave, [ e, previous, this ], this); } this._hoveredItem = hoveredItem; if (hoveredItem && !sameItem) { callback(opts.onHover, [ e, hoveredItem, this ], this); } } else if (hoveredItem) { callback(opts.onClick, [ e, hoveredItem, this ], this); } } } function calculateItemSize(boxWidth, labelFont, ctx, legendItem, _itemHeight) { const itemWidth = calculateItemWidth(legendItem, boxWidth, labelFont, ctx); const itemHeight = calculateItemHeight(_itemHeight, legendItem, labelFont.lineHeight); return { itemWidth, itemHeight }; } function calculateItemWidth(legendItem, boxWidth, labelFont, ctx) { let legendItemText = legendItem.text; if (legendItemText && typeof legendItemText !== 'string') { legendItemText = legendItemText.reduce((a, b)=>a.length > b.length ? a : b); } return boxWidth + labelFont.size / 2 + ctx.measureText(legendItemText).width; } function calculateItemHeight(_itemHeight, legendItem, fontLineHeight) { let itemHeight = _itemHeight; if (typeof legendItem.text !== 'string') { itemHeight = calculateLegendItemHeight(legendItem, fontLineHeight); } return itemHeight; } function calculateLegendItemHeight(legendItem, fontLineHeight) { const labelHeight = legendItem.text ? legendItem.text.length : 0; return fontLineHeight * labelHeight; } function isListened(type, opts) { if ((type === 'mousemove' || type === 'mouseout') && (opts.onHover || opts.onLeave)) { return true; } if (opts.onClick && (type === 'click' || type === 'mouseup')) { return true; } return false; } var plugin_legend = { id: 'legend', _element: Legend, start (chart, _args, options) { const legend = chart.legend = new Legend({ ctx: chart.ctx, options, chart }); layouts.configure(chart, legend, options); layouts.addBox(chart, legend); }, stop (chart) { layouts.removeBox(chart, chart.legend); delete chart.legend; }, beforeUpdate (chart, _args, options) { const legend = chart.legend; layouts.configure(chart, legend, options); legend.options = options; }, afterUpdate (chart) { const legend = chart.legend; legend.buildLabels(); legend.adjustHitBoxes(); }, afterEvent (chart, args) { if (!args.replay) { chart.legend.handleEvent(args.event); } }, defaults: { display: true, position: 'top', align: 'center', fullSize: true, reverse: false, weight: 1000, onClick (e, legendItem, legend) { const index = legendItem.datasetIndex; const ci = legend.chart; if (ci.isDatasetVisible(index)) { ci.hide(index); legendItem.hidden = true; } else { ci.show(index); legendItem.hidden = false; } }, onHover: null, onLeave: null, labels: { color: (ctx)=>ctx.chart.options.color, boxWidth: 40, padding: 10, generateLabels (chart) { const datasets = chart.data.datasets; const { labels: { usePointStyle , pointStyle , textAlign , color , useBorderRadius , borderRadius } } = chart.legend.options; return chart._getSortedDatasetMetas().map((meta)=>{ const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); const borderWidth = toPadding(style.borderWidth); return { text: datasets[meta.index].label, fillStyle: style.backgroundColor, fontColor: color, hidden: !meta.visible, lineCap: style.borderCapStyle, lineDash: style.borderDash, lineDashOffset: style.borderDashOffset, lineJoin: style.borderJoinStyle, lineWidth: (borderWidth.width + borderWidth.height) / 4, strokeStyle: style.borderColor, pointStyle: pointStyle || style.pointStyle, rotation: style.rotation, textAlign: textAlign || style.textAlign, borderRadius: useBorderRadius && (borderRadius || style.borderRadius), datasetIndex: meta.index }; }, this); } }, title: { color: (ctx)=>ctx.chart.options.color, display: false, position: 'center', text: '' } }, descriptors: { _scriptable: (name)=>!name.startsWith('on'), labels: { _scriptable: (name)=>![ 'generateLabels', 'filter', 'sort' ].includes(name) } } }; class Title extends chart_Element { constructor(config){ super(); this.chart = config.chart; this.options = config.options; this.ctx = config.ctx; this._padding = undefined; this.top = undefined; this.bottom = undefined; this.left = undefined; this.right = undefined; this.width = undefined; this.height = undefined; this.position = undefined; this.weight = undefined; this.fullSize = undefined; } update(maxWidth, maxHeight) { const opts = this.options; this.left = 0; this.top = 0; if (!opts.display) { this.width = this.height = this.right = this.bottom = 0; return; } this.width = this.right = maxWidth; this.height = this.bottom = maxHeight; const lineCount = isArray(opts.text) ? opts.text.length : 1; this._padding = toPadding(opts.padding); const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height; if (this.isHorizontal()) { this.height = textSize; } else { this.width = textSize; } } isHorizontal() { const pos = this.options.position; return pos === 'top' || pos === 'bottom'; } _drawArgs(offset) { const { top , left , bottom , right , options } = this; const align = options.align; let rotation = 0; let maxWidth, titleX, titleY; if (this.isHorizontal()) { titleX = _alignStartEnd(align, left, right); titleY = top + offset; maxWidth = right - left; } else { if (options.position === 'left') { titleX = left + offset; titleY = _alignStartEnd(align, bottom, top); rotation = PI * -0.5; } else { titleX = right - offset; titleY = _alignStartEnd(align, top, bottom); rotation = PI * 0.5; } maxWidth = bottom - top; } return { titleX, titleY, maxWidth, rotation }; } draw() { const ctx = this.ctx; const opts = this.options; if (!opts.display) { return; } const fontOpts = toFont(opts.font); const lineHeight = fontOpts.lineHeight; const offset = lineHeight / 2 + this._padding.top; const { titleX , titleY , maxWidth , rotation } = this._drawArgs(offset); renderText(ctx, opts.text, 0, 0, fontOpts, { color: opts.color, maxWidth, rotation, textAlign: _toLeftRightCenter(opts.align), textBaseline: 'middle', translation: [ titleX, titleY ] }); } } function createTitle(chart, titleOpts) { const title = new Title({ ctx: chart.ctx, options: titleOpts, chart }); layouts.configure(chart, title, titleOpts); layouts.addBox(chart, title); chart.titleBlock = title; } var plugin_title = { id: 'title', _element: Title, start (chart, _args, options) { createTitle(chart, options); }, stop (chart) { const titleBlock = chart.titleBlock; layouts.removeBox(chart, titleBlock); delete chart.titleBlock; }, beforeUpdate (chart, _args, options) { const title = chart.titleBlock; layouts.configure(chart, title, options); title.options = options; }, defaults: { align: 'center', display: false, font: { weight: 'bold' }, fullSize: true, padding: 10, position: 'top', text: '', weight: 2000 }, defaultRoutes: { color: 'color' }, descriptors: { _scriptable: true, _indexable: false } }; const chart_map = new WeakMap(); var plugin_subtitle = { id: 'subtitle', start (chart, _args, options) { const title = new Title({ ctx: chart.ctx, options, chart }); layouts.configure(chart, title, options); layouts.addBox(chart, title); chart_map.set(chart, title); }, stop (chart) { layouts.removeBox(chart, chart_map.get(chart)); chart_map.delete(chart); }, beforeUpdate (chart, _args, options) { const title = chart_map.get(chart); layouts.configure(chart, title, options); title.options = options; }, defaults: { align: 'center', display: false, font: { weight: 'normal' }, fullSize: true, padding: 0, position: 'top', text: '', weight: 1500 }, defaultRoutes: { color: 'color' }, descriptors: { _scriptable: true, _indexable: false } }; const positioners = { average (items) { if (!items.length) { return false; } let i, len; let xSet = new Set(); let y = 0; let count = 0; for(i = 0, len = items.length; i < len; ++i){ const el = items[i].element; if (el && el.hasValue()) { const pos = el.tooltipPosition(); xSet.add(pos.x); y += pos.y; ++count; } } if (count === 0 || xSet.size === 0) { return false; } const xAverage = [ ...xSet ].reduce((a, b)=>a + b) / xSet.size; return { x: xAverage, y: y / count }; }, nearest (items, eventPosition) { if (!items.length) { return false; } let x = eventPosition.x; let y = eventPosition.y; let minDistance = Number.POSITIVE_INFINITY; let i, len, nearestElement; for(i = 0, len = items.length; i < len; ++i){ const el = items[i].element; if (el && el.hasValue()) { const center = el.getCenterPoint(); const d = distanceBetweenPoints(eventPosition, center); if (d < minDistance) { minDistance = d; nearestElement = el; } } } if (nearestElement) { const tp = nearestElement.tooltipPosition(); x = tp.x; y = tp.y; } return { x, y }; } }; function pushOrConcat(base, toPush) { if (toPush) { if (isArray(toPush)) { Array.prototype.push.apply(base, toPush); } else { base.push(toPush); } } return base; } function splitNewlines(str) { if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { return str.split('\n'); } return str; } function createTooltipItem(chart, item) { const { element , datasetIndex , index } = item; const controller = chart.getDatasetMeta(datasetIndex).controller; const { label , value } = controller.getLabelAndValue(index); return { chart, label, parsed: controller.getParsed(index), raw: chart.data.datasets[datasetIndex].data[index], formattedValue: value, dataset: controller.getDataset(), dataIndex: index, datasetIndex, element }; } function getTooltipSize(tooltip, options) { const ctx = tooltip.chart.ctx; const { body , footer , title } = tooltip; const { boxWidth , boxHeight } = options; const bodyFont = toFont(options.bodyFont); const titleFont = toFont(options.titleFont); const footerFont = toFont(options.footerFont); const titleLineCount = title.length; const footerLineCount = footer.length; const bodyLineItemCount = body.length; const padding = toPadding(options.padding); let height = padding.height; let width = 0; let combinedBodyLength = body.reduce((count, bodyItem)=>count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; if (titleLineCount) { height += titleLineCount * titleFont.lineHeight + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom; } if (combinedBodyLength) { const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight; height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight + (combinedBodyLength - 1) * options.bodySpacing; } if (footerLineCount) { height += options.footerMarginTop + footerLineCount * footerFont.lineHeight + (footerLineCount - 1) * options.footerSpacing; } let widthPadding = 0; const maxLineWidth = function(line) { width = Math.max(width, ctx.measureText(line).width + widthPadding); }; ctx.save(); ctx.font = titleFont.string; each(tooltip.title, maxLineWidth); ctx.font = bodyFont.string; each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); widthPadding = options.displayColors ? boxWidth + 2 + options.boxPadding : 0; each(body, (bodyItem)=>{ each(bodyItem.before, maxLineWidth); each(bodyItem.lines, maxLineWidth); each(bodyItem.after, maxLineWidth); }); widthPadding = 0; ctx.font = footerFont.string; each(tooltip.footer, maxLineWidth); ctx.restore(); width += padding.width; return { width, height }; } function determineYAlign(chart, size) { const { y , height } = size; if (y < height / 2) { return 'top'; } else if (y > chart.height - height / 2) { return 'bottom'; } return 'center'; } function doesNotFitWithAlign(xAlign, chart, options, size) { const { x , width } = size; const caret = options.caretSize + options.caretPadding; if (xAlign === 'left' && x + width + caret > chart.width) { return true; } if (xAlign === 'right' && x - width - caret < 0) { return true; } } function determineXAlign(chart, options, size, yAlign) { const { x , width } = size; const { width: chartWidth , chartArea: { left , right } } = chart; let xAlign = 'center'; if (yAlign === 'center') { xAlign = x <= (left + right) / 2 ? 'left' : 'right'; } else if (x <= width / 2) { xAlign = 'left'; } else if (x >= chartWidth - width / 2) { xAlign = 'right'; } if (doesNotFitWithAlign(xAlign, chart, options, size)) { xAlign = 'center'; } return xAlign; } function determineAlignment(chart, options, size) { const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size); return { xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign), yAlign }; } function alignX(size, xAlign) { let { x , width } = size; if (xAlign === 'right') { x -= width; } else if (xAlign === 'center') { x -= width / 2; } return x; } function alignY(size, yAlign, paddingAndSize) { let { y , height } = size; if (yAlign === 'top') { y += paddingAndSize; } else if (yAlign === 'bottom') { y -= height + paddingAndSize; } else { y -= height / 2; } return y; } function getBackgroundPoint(options, size, alignment, chart) { const { caretSize , caretPadding , cornerRadius } = options; const { xAlign , yAlign } = alignment; const paddingAndSize = caretSize + caretPadding; const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); let x = alignX(size, xAlign); const y = alignY(size, yAlign, paddingAndSize); if (yAlign === 'center') { if (xAlign === 'left') { x += paddingAndSize; } else if (xAlign === 'right') { x -= paddingAndSize; } } else if (xAlign === 'left') { x -= Math.max(topLeft, bottomLeft) + caretSize; } else if (xAlign === 'right') { x += Math.max(topRight, bottomRight) + caretSize; } return { x: _limitValue(x, 0, chart.width - size.width), y: _limitValue(y, 0, chart.height - size.height) }; } function getAlignedX(tooltip, align, options) { const padding = toPadding(options.padding); return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - padding.right : tooltip.x + padding.left; } function getBeforeAfterBodyLines(callback) { return pushOrConcat([], splitNewlines(callback)); } function createTooltipContext(parent, tooltip, tooltipItems) { return createContext(parent, { tooltip, tooltipItems, type: 'tooltip' }); } function overrideCallbacks(callbacks, context) { const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks; return override ? callbacks.override(override) : callbacks; } const defaultCallbacks = { beforeTitle: noop, title (tooltipItems) { if (tooltipItems.length > 0) { const item = tooltipItems[0]; const labels = item.chart.data.labels; const labelCount = labels ? labels.length : 0; if (this && this.options && this.options.mode === 'dataset') { return item.dataset.label || ''; } else if (item.label) { return item.label; } else if (labelCount > 0 && item.dataIndex < labelCount) { return labels[item.dataIndex]; } } return ''; }, afterTitle: noop, beforeBody: noop, beforeLabel: noop, label (tooltipItem) { if (this && this.options && this.options.mode === 'dataset') { return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue; } let label = tooltipItem.dataset.label || ''; if (label) { label += ': '; } const value = tooltipItem.formattedValue; if (!isNullOrUndef(value)) { label += value; } return label; }, labelColor (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { borderColor: options.borderColor, backgroundColor: options.backgroundColor, borderWidth: options.borderWidth, borderDash: options.borderDash, borderDashOffset: options.borderDashOffset, borderRadius: 0 }; }, labelTextColor () { return this.options.bodyColor; }, labelPointStyle (tooltipItem) { const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); const options = meta.controller.getStyle(tooltipItem.dataIndex); return { pointStyle: options.pointStyle, rotation: options.rotation }; }, afterLabel: noop, afterBody: noop, beforeFooter: noop, footer: noop, afterFooter: noop }; function invokeCallbackWithFallback(callbacks, name, ctx, arg) { const result = callbacks[name].call(ctx, arg); if (typeof result === 'undefined') { return defaultCallbacks[name].call(ctx, arg); } return result; } class Tooltip extends chart_Element { static positioners = positioners; constructor(config){ super(); this.opacity = 0; this._active = []; this._eventPosition = undefined; this._size = undefined; this._cachedAnimations = undefined; this._tooltipItems = []; this.$animations = undefined; this.$context = undefined; this.chart = config.chart; this.options = config.options; this.dataPoints = undefined; this.title = undefined; this.beforeBody = undefined; this.body = undefined; this.afterBody = undefined; this.footer = undefined; this.xAlign = undefined; this.yAlign = undefined; this.x = undefined; this.y = undefined; this.height = undefined; this.width = undefined; this.caretX = undefined; this.caretY = undefined; this.labelColors = undefined; this.labelPointStyles = undefined; this.labelTextColors = undefined; } initialize(options) { this.options = options; this._cachedAnimations = undefined; this.$context = undefined; } _resolveAnimations() { const cached = this._cachedAnimations; if (cached) { return cached; } const chart = this.chart; const options = this.options.setContext(this.getContext()); const opts = options.enabled && chart.options.animation && options.animations; const animations = new Animations(this.chart, opts); if (opts._cacheable) { this._cachedAnimations = Object.freeze(animations); } return animations; } getContext() { return this.$context || (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems)); } getTitle(context, options) { const { callbacks } = options; const beforeTitle = invokeCallbackWithFallback(callbacks, 'beforeTitle', this, context); const title = invokeCallbackWithFallback(callbacks, 'title', this, context); const afterTitle = invokeCallbackWithFallback(callbacks, 'afterTitle', this, context); let lines = []; lines = pushOrConcat(lines, splitNewlines(beforeTitle)); lines = pushOrConcat(lines, splitNewlines(title)); lines = pushOrConcat(lines, splitNewlines(afterTitle)); return lines; } getBeforeBody(tooltipItems, options) { return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'beforeBody', this, tooltipItems)); } getBody(tooltipItems, options) { const { callbacks } = options; const bodyItems = []; each(tooltipItems, (context)=>{ const bodyItem = { before: [], lines: [], after: [] }; const scoped = overrideCallbacks(callbacks, context); pushOrConcat(bodyItem.before, splitNewlines(invokeCallbackWithFallback(scoped, 'beforeLabel', this, context))); pushOrConcat(bodyItem.lines, invokeCallbackWithFallback(scoped, 'label', this, context)); pushOrConcat(bodyItem.after, splitNewlines(invokeCallbackWithFallback(scoped, 'afterLabel', this, context))); bodyItems.push(bodyItem); }); return bodyItems; } getAfterBody(tooltipItems, options) { return getBeforeAfterBodyLines(invokeCallbackWithFallback(options.callbacks, 'afterBody', this, tooltipItems)); } getFooter(tooltipItems, options) { const { callbacks } = options; const beforeFooter = invokeCallbackWithFallback(callbacks, 'beforeFooter', this, tooltipItems); const footer = invokeCallbackWithFallback(callbacks, 'footer', this, tooltipItems); const afterFooter = invokeCallbackWithFallback(callbacks, 'afterFooter', this, tooltipItems); let lines = []; lines = pushOrConcat(lines, splitNewlines(beforeFooter)); lines = pushOrConcat(lines, splitNewlines(footer)); lines = pushOrConcat(lines, splitNewlines(afterFooter)); return lines; } _createItems(options) { const active = this._active; const data = this.chart.data; const labelColors = []; const labelPointStyles = []; const labelTextColors = []; let tooltipItems = []; let i, len; for(i = 0, len = active.length; i < len; ++i){ tooltipItems.push(createTooltipItem(this.chart, active[i])); } if (options.filter) { tooltipItems = tooltipItems.filter((element, index, array)=>options.filter(element, index, array, data)); } if (options.itemSort) { tooltipItems = tooltipItems.sort((a, b)=>options.itemSort(a, b, data)); } each(tooltipItems, (context)=>{ const scoped = overrideCallbacks(options.callbacks, context); labelColors.push(invokeCallbackWithFallback(scoped, 'labelColor', this, context)); labelPointStyles.push(invokeCallbackWithFallback(scoped, 'labelPointStyle', this, context)); labelTextColors.push(invokeCallbackWithFallback(scoped, 'labelTextColor', this, context)); }); this.labelColors = labelColors; this.labelPointStyles = labelPointStyles; this.labelTextColors = labelTextColors; this.dataPoints = tooltipItems; return tooltipItems; } update(changed, replay) { const options = this.options.setContext(this.getContext()); const active = this._active; let properties; let tooltipItems = []; if (!active.length) { if (this.opacity !== 0) { properties = { opacity: 0 }; } } else { const position = positioners[options.position].call(this, active, this._eventPosition); tooltipItems = this._createItems(options); this.title = this.getTitle(tooltipItems, options); this.beforeBody = this.getBeforeBody(tooltipItems, options); this.body = this.getBody(tooltipItems, options); this.afterBody = this.getAfterBody(tooltipItems, options); this.footer = this.getFooter(tooltipItems, options); const size = this._size = getTooltipSize(this, options); const positionAndSize = Object.assign({}, position, size); const alignment = determineAlignment(this.chart, options, positionAndSize); const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart); this.xAlign = alignment.xAlign; this.yAlign = alignment.yAlign; properties = { opacity: 1, x: backgroundPoint.x, y: backgroundPoint.y, width: size.width, height: size.height, caretX: position.x, caretY: position.y }; } this._tooltipItems = tooltipItems; this.$context = undefined; if (properties) { this._resolveAnimations().update(this, properties); } if (changed && options.external) { options.external.call(this, { chart: this.chart, tooltip: this, replay }); } } drawCaret(tooltipPoint, ctx, size, options) { const caretPosition = this.getCaretPosition(tooltipPoint, size, options); ctx.lineTo(caretPosition.x1, caretPosition.y1); ctx.lineTo(caretPosition.x2, caretPosition.y2); ctx.lineTo(caretPosition.x3, caretPosition.y3); } getCaretPosition(tooltipPoint, size, options) { const { xAlign , yAlign } = this; const { caretSize , cornerRadius } = options; const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(cornerRadius); const { x: ptX , y: ptY } = tooltipPoint; const { width , height } = size; let x1, x2, x3, y1, y2, y3; if (yAlign === 'center') { y2 = ptY + height / 2; if (xAlign === 'left') { x1 = ptX; x2 = x1 - caretSize; y1 = y2 + caretSize; y3 = y2 - caretSize; } else { x1 = ptX + width; x2 = x1 + caretSize; y1 = y2 - caretSize; y3 = y2 + caretSize; } x3 = x1; } else { if (xAlign === 'left') { x2 = ptX + Math.max(topLeft, bottomLeft) + caretSize; } else if (xAlign === 'right') { x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize; } else { x2 = this.caretX; } if (yAlign === 'top') { y1 = ptY; y2 = y1 - caretSize; x1 = x2 - caretSize; x3 = x2 + caretSize; } else { y1 = ptY + height; y2 = y1 + caretSize; x1 = x2 + caretSize; x3 = x2 - caretSize; } y3 = y1; } return { x1, x2, x3, y1, y2, y3 }; } drawTitle(pt, ctx, options) { const title = this.title; const length = title.length; let titleFont, titleSpacing, i; if (length) { const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); pt.x = getAlignedX(this, options.titleAlign, options); ctx.textAlign = rtlHelper.textAlign(options.titleAlign); ctx.textBaseline = 'middle'; titleFont = toFont(options.titleFont); titleSpacing = options.titleSpacing; ctx.fillStyle = options.titleColor; ctx.font = titleFont.string; for(i = 0; i < length; ++i){ ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2); pt.y += titleFont.lineHeight + titleSpacing; if (i + 1 === length) { pt.y += options.titleMarginBottom - titleSpacing; } } } } _drawColorBox(ctx, pt, i, rtlHelper, options) { const labelColor = this.labelColors[i]; const labelPointStyle = this.labelPointStyles[i]; const { boxHeight , boxWidth } = options; const bodyFont = toFont(options.bodyFont); const colorX = getAlignedX(this, 'left', options); const rtlColorX = rtlHelper.x(colorX); const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0; const colorY = pt.y + yOffSet; if (options.usePointStyle) { const drawOptions = { radius: Math.min(boxWidth, boxHeight) / 2, pointStyle: labelPointStyle.pointStyle, rotation: labelPointStyle.rotation, borderWidth: 1 }; const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2; const centerY = colorY + boxHeight / 2; ctx.strokeStyle = options.multiKeyBackground; ctx.fillStyle = options.multiKeyBackground; drawPoint(ctx, drawOptions, centerX, centerY); ctx.strokeStyle = labelColor.borderColor; ctx.fillStyle = labelColor.backgroundColor; drawPoint(ctx, drawOptions, centerX, centerY); } else { ctx.lineWidth = isObject(labelColor.borderWidth) ? Math.max(...Object.values(labelColor.borderWidth)) : labelColor.borderWidth || 1; ctx.strokeStyle = labelColor.borderColor; ctx.setLineDash(labelColor.borderDash || []); ctx.lineDashOffset = labelColor.borderDashOffset || 0; const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth); const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2); const borderRadius = toTRBLCorners(labelColor.borderRadius); if (Object.values(borderRadius).some((v)=>v !== 0)) { ctx.beginPath(); ctx.fillStyle = options.multiKeyBackground; addRoundedRectPath(ctx, { x: outerX, y: colorY, w: boxWidth, h: boxHeight, radius: borderRadius }); ctx.fill(); ctx.stroke(); ctx.fillStyle = labelColor.backgroundColor; ctx.beginPath(); addRoundedRectPath(ctx, { x: innerX, y: colorY + 1, w: boxWidth - 2, h: boxHeight - 2, radius: borderRadius }); ctx.fill(); } else { ctx.fillStyle = options.multiKeyBackground; ctx.fillRect(outerX, colorY, boxWidth, boxHeight); ctx.strokeRect(outerX, colorY, boxWidth, boxHeight); ctx.fillStyle = labelColor.backgroundColor; ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2); } } ctx.fillStyle = this.labelTextColors[i]; } drawBody(pt, ctx, options) { const { body } = this; const { bodySpacing , bodyAlign , displayColors , boxHeight , boxWidth , boxPadding } = options; const bodyFont = toFont(options.bodyFont); let bodyLineHeight = bodyFont.lineHeight; let xLinePadding = 0; const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); const fillLineOfText = function(line) { ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); pt.y += bodyLineHeight + bodySpacing; }; const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); let bodyItem, textColor, lines, i, j, ilen, jlen; ctx.textAlign = bodyAlign; ctx.textBaseline = 'middle'; ctx.font = bodyFont.string; pt.x = getAlignedX(this, bodyAlignForCalculation, options); ctx.fillStyle = options.bodyColor; each(this.beforeBody, fillLineOfText); xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + boxPadding : boxWidth + 2 + boxPadding : 0; for(i = 0, ilen = body.length; i < ilen; ++i){ bodyItem = body[i]; textColor = this.labelTextColors[i]; ctx.fillStyle = textColor; each(bodyItem.before, fillLineOfText); lines = bodyItem.lines; if (displayColors && lines.length) { this._drawColorBox(ctx, pt, i, rtlHelper, options); bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight); } for(j = 0, jlen = lines.length; j < jlen; ++j){ fillLineOfText(lines[j]); bodyLineHeight = bodyFont.lineHeight; } each(bodyItem.after, fillLineOfText); } xLinePadding = 0; bodyLineHeight = bodyFont.lineHeight; each(this.afterBody, fillLineOfText); pt.y -= bodySpacing; } drawFooter(pt, ctx, options) { const footer = this.footer; const length = footer.length; let footerFont, i; if (length) { const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width); pt.x = getAlignedX(this, options.footerAlign, options); pt.y += options.footerMarginTop; ctx.textAlign = rtlHelper.textAlign(options.footerAlign); ctx.textBaseline = 'middle'; footerFont = toFont(options.footerFont); ctx.fillStyle = options.footerColor; ctx.font = footerFont.string; for(i = 0; i < length; ++i){ ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2); pt.y += footerFont.lineHeight + options.footerSpacing; } } } drawBackground(pt, ctx, tooltipSize, options) { const { xAlign , yAlign } = this; const { x , y } = pt; const { width , height } = tooltipSize; const { topLeft , topRight , bottomLeft , bottomRight } = toTRBLCorners(options.cornerRadius); ctx.fillStyle = options.backgroundColor; ctx.strokeStyle = options.borderColor; ctx.lineWidth = options.borderWidth; ctx.beginPath(); ctx.moveTo(x + topLeft, y); if (yAlign === 'top') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + width - topRight, y); ctx.quadraticCurveTo(x + width, y, x + width, y + topRight); if (yAlign === 'center' && xAlign === 'right') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + width, y + height - bottomRight); ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height); if (yAlign === 'bottom') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x + bottomLeft, y + height); ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft); if (yAlign === 'center' && xAlign === 'left') { this.drawCaret(pt, ctx, tooltipSize, options); } ctx.lineTo(x, y + topLeft); ctx.quadraticCurveTo(x, y, x + topLeft, y); ctx.closePath(); ctx.fill(); if (options.borderWidth > 0) { ctx.stroke(); } } _updateAnimationTarget(options) { const chart = this.chart; const anims = this.$animations; const animX = anims && anims.x; const animY = anims && anims.y; if (animX || animY) { const position = positioners[options.position].call(this, this._active, this._eventPosition); if (!position) { return; } const size = this._size = getTooltipSize(this, options); const positionAndSize = Object.assign({}, position, this._size); const alignment = determineAlignment(chart, options, positionAndSize); const point = getBackgroundPoint(options, positionAndSize, alignment, chart); if (animX._to !== point.x || animY._to !== point.y) { this.xAlign = alignment.xAlign; this.yAlign = alignment.yAlign; this.width = size.width; this.height = size.height; this.caretX = position.x; this.caretY = position.y; this._resolveAnimations().update(this, point); } } } _willRender() { return !!this.opacity; } draw(ctx) { const options = this.options.setContext(this.getContext()); let opacity = this.opacity; if (!opacity) { return; } this._updateAnimationTarget(options); const tooltipSize = { width: this.width, height: this.height }; const pt = { x: this.x, y: this.y }; opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; const padding = toPadding(options.padding); const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length; if (options.enabled && hasTooltipContent) { ctx.save(); ctx.globalAlpha = opacity; this.drawBackground(pt, ctx, tooltipSize, options); overrideTextDirection(ctx, options.textDirection); pt.y += padding.top; this.drawTitle(pt, ctx, options); this.drawBody(pt, ctx, options); this.drawFooter(pt, ctx, options); restoreTextDirection(ctx, options.textDirection); ctx.restore(); } } getActiveElements() { return this._active || []; } setActiveElements(activeElements, eventPosition) { const lastActive = this._active; const active = activeElements.map(({ datasetIndex , index })=>{ const meta = this.chart.getDatasetMeta(datasetIndex); if (!meta) { throw new Error('Cannot find a dataset at index ' + datasetIndex); } return { datasetIndex, element: meta.data[index], index }; }); const changed = !_elementsEqual(lastActive, active); const positionChanged = this._positionChanged(active, eventPosition); if (changed || positionChanged) { this._active = active; this._eventPosition = eventPosition; this._ignoreReplayEvents = true; this.update(true); } } handleEvent(e, replay, inChartArea = true) { if (replay && this._ignoreReplayEvents) { return false; } this._ignoreReplayEvents = false; const options = this.options; const lastActive = this._active || []; const active = this._getActiveElements(e, lastActive, replay, inChartArea); const positionChanged = this._positionChanged(active, e); const changed = replay || !_elementsEqual(active, lastActive) || positionChanged; if (changed) { this._active = active; if (options.enabled || options.external) { this._eventPosition = { x: e.x, y: e.y }; this.update(true, replay); } } return changed; } _getActiveElements(e, lastActive, replay, inChartArea) { const options = this.options; if (e.type === 'mouseout') { return []; } if (!inChartArea) { return lastActive.filter((i)=>this.chart.data.datasets[i.datasetIndex] && this.chart.getDatasetMeta(i.datasetIndex).controller.getParsed(i.index) !== undefined); } const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay); if (options.reverse) { active.reverse(); } return active; } _positionChanged(active, e) { const { caretX , caretY , options } = this; const position = positioners[options.position].call(this, active, e); return position !== false && (caretX !== position.x || caretY !== position.y); } } var plugin_tooltip = { id: 'tooltip', _element: Tooltip, positioners, afterInit (chart, _args, options) { if (options) { chart.tooltip = new Tooltip({ chart, options }); } }, beforeUpdate (chart, _args, options) { if (chart.tooltip) { chart.tooltip.initialize(options); } }, reset (chart, _args, options) { if (chart.tooltip) { chart.tooltip.initialize(options); } }, afterDraw (chart) { const tooltip = chart.tooltip; if (tooltip && tooltip._willRender()) { const args = { tooltip }; if (chart.notifyPlugins('beforeTooltipDraw', { ...args, cancelable: true }) === false) { return; } tooltip.draw(chart.ctx); chart.notifyPlugins('afterTooltipDraw', args); } }, afterEvent (chart, args) { if (chart.tooltip) { const useFinalPosition = args.replay; if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) { args.changed = true; } } }, defaults: { enabled: true, external: null, position: 'average', backgroundColor: 'rgba(0,0,0,0.8)', titleColor: '#fff', titleFont: { weight: 'bold' }, titleSpacing: 2, titleMarginBottom: 6, titleAlign: 'left', bodyColor: '#fff', bodySpacing: 2, bodyFont: {}, bodyAlign: 'left', footerColor: '#fff', footerSpacing: 2, footerMarginTop: 6, footerFont: { weight: 'bold' }, footerAlign: 'left', padding: 6, caretPadding: 2, caretSize: 5, cornerRadius: 6, boxHeight: (ctx, opts)=>opts.bodyFont.size, boxWidth: (ctx, opts)=>opts.bodyFont.size, multiKeyBackground: '#fff', displayColors: true, boxPadding: 0, borderColor: 'rgba(0,0,0,0)', borderWidth: 0, animation: { duration: 400, easing: 'easeOutQuart' }, animations: { numbers: { type: 'number', properties: [ 'x', 'y', 'width', 'height', 'caretX', 'caretY' ] }, opacity: { easing: 'linear', duration: 200 } }, callbacks: defaultCallbacks }, defaultRoutes: { bodyFont: 'font', footerFont: 'font', titleFont: 'font' }, descriptors: { _scriptable: (name)=>name !== 'filter' && name !== 'itemSort' && name !== 'external', _indexable: false, callbacks: { _scriptable: false, _indexable: false }, animation: { _fallback: false }, animations: { _fallback: 'animation' } }, additionalOptionScopes: [ 'interaction' ] }; var plugins = /*#__PURE__*/Object.freeze({ __proto__: null, Colors: plugin_colors, Decimation: plugin_decimation, Filler: index, Legend: plugin_legend, SubTitle: plugin_subtitle, Title: plugin_title, Tooltip: plugin_tooltip }); const addIfString = (labels, raw, index, addedLabels)=>{ if (typeof raw === 'string') { index = labels.push(raw) - 1; addedLabels.unshift({ index, label: raw }); } else if (isNaN(raw)) { index = null; } return index; }; function findOrAddLabel(labels, raw, index, addedLabels) { const first = labels.indexOf(raw); if (first === -1) { return addIfString(labels, raw, index, addedLabels); } const last = labels.lastIndexOf(raw); return first !== last ? index : first; } const validIndex = (index, max)=>index === null ? null : _limitValue(Math.round(index), 0, max); function _getLabelForValue(value) { const labels = this.getLabels(); if (value >= 0 && value < labels.length) { return labels[value]; } return value; } class CategoryScale extends Scale { static id = 'category'; static defaults = { ticks: { callback: _getLabelForValue } }; constructor(cfg){ super(cfg); this._startValue = undefined; this._valueRange = 0; this._addedLabels = []; } init(scaleOptions) { const added = this._addedLabels; if (added.length) { const labels = this.getLabels(); for (const { index , label } of added){ if (labels[index] === label) { labels.splice(index, 1); } } this._addedLabels = []; } super.init(scaleOptions); } parse(raw, index) { if (isNullOrUndef(raw)) { return null; } const labels = this.getLabels(); index = isFinite(index) && labels[index] === raw ? index : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels); return validIndex(index, labels.length - 1); } determineDataLimits() { const { minDefined , maxDefined } = this.getUserBounds(); let { min , max } = this.getMinMax(true); if (this.options.bounds === 'ticks') { if (!minDefined) { min = 0; } if (!maxDefined) { max = this.getLabels().length - 1; } } this.min = min; this.max = max; } buildTicks() { const min = this.min; const max = this.max; const offset = this.options.offset; const ticks = []; let labels = this.getLabels(); labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1); this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); this._startValue = this.min - (offset ? 0.5 : 0); for(let value = min; value <= max; value++){ ticks.push({ value }); } return ticks; } getLabelForValue(value) { return _getLabelForValue.call(this, value); } configure() { super.configure(); if (!this.isHorizontal()) { this._reversePixels = !this._reversePixels; } } getPixelForValue(value) { if (typeof value !== 'number') { value = this.parse(value); } return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); } getPixelForTick(index) { const ticks = this.ticks; if (index < 0 || index > ticks.length - 1) { return null; } return this.getPixelForValue(ticks[index].value); } getValueForPixel(pixel) { return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange); } getBasePixel() { return this.bottom; } } function generateTicks$1(generationOptions, dataRange) { const ticks = []; const MIN_SPACING = 1e-14; const { bounds , step , min , max , precision , count , maxTicks , maxDigits , includeBounds } = generationOptions; const unit = step || 1; const maxSpaces = maxTicks - 1; const { min: rmin , max: rmax } = dataRange; const minDefined = !isNullOrUndef(min); const maxDefined = !isNullOrUndef(max); const countDefined = !isNullOrUndef(count); const minSpacing = (rmax - rmin) / (maxDigits + 1); let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit; let factor, niceMin, niceMax, numSpaces; if (spacing < MIN_SPACING && !minDefined && !maxDefined) { return [ { value: rmin }, { value: rmax } ]; } numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); if (numSpaces > maxSpaces) { spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit; } if (!isNullOrUndef(precision)) { factor = Math.pow(10, precision); spacing = Math.ceil(spacing * factor) / factor; } if (bounds === 'ticks') { niceMin = Math.floor(rmin / spacing) * spacing; niceMax = Math.ceil(rmax / spacing) * spacing; } else { niceMin = rmin; niceMax = rmax; } if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) { numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks)); spacing = (max - min) / numSpaces; niceMin = min; niceMax = max; } else if (countDefined) { niceMin = minDefined ? min : niceMin; niceMax = maxDefined ? max : niceMax; numSpaces = count - 1; spacing = (niceMax - niceMin) / numSpaces; } else { numSpaces = (niceMax - niceMin) / spacing; if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { numSpaces = Math.round(numSpaces); } else { numSpaces = Math.ceil(numSpaces); } } const decimalPlaces = Math.max(_decimalPlaces(spacing), _decimalPlaces(niceMin)); factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision); niceMin = Math.round(niceMin * factor) / factor; niceMax = Math.round(niceMax * factor) / factor; let j = 0; if (minDefined) { if (includeBounds && niceMin !== min) { ticks.push({ value: min }); if (niceMin < min) { j++; } if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) { j++; } } else if (niceMin < min) { j++; } } for(; j < numSpaces; ++j){ const tickValue = Math.round((niceMin + j * spacing) * factor) / factor; if (maxDefined && tickValue > max) { break; } ticks.push({ value: tickValue }); } if (maxDefined && includeBounds && niceMax !== max) { if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) { ticks[ticks.length - 1].value = max; } else { ticks.push({ value: max }); } } else if (!maxDefined || niceMax === max) { ticks.push({ value: niceMax }); } return ticks; } function relativeLabelSize(value, minSpacing, { horizontal , minRotation }) { const rad = toRadians(minRotation); const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001; const length = 0.75 * minSpacing * ('' + value).length; return Math.min(minSpacing / ratio, length); } class LinearScaleBase extends Scale { constructor(cfg){ super(cfg); this.start = undefined; this.end = undefined; this._startValue = undefined; this._endValue = undefined; this._valueRange = 0; } parse(raw, index) { if (isNullOrUndef(raw)) { return null; } if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { return null; } return +raw; } handleTickRangeOptions() { const { beginAtZero } = this.options; const { minDefined , maxDefined } = this.getUserBounds(); let { min , max } = this; const setMin = (v)=>min = minDefined ? min : v; const setMax = (v)=>max = maxDefined ? max : v; if (beginAtZero) { const minSign = sign(min); const maxSign = sign(max); if (minSign < 0 && maxSign < 0) { setMax(0); } else if (minSign > 0 && maxSign > 0) { setMin(0); } } if (min === max) { let offset = max === 0 ? 1 : Math.abs(max * 0.05); setMax(max + offset); if (!beginAtZero) { setMin(min - offset); } } this.min = min; this.max = max; } getTickLimit() { const tickOpts = this.options.ticks; let { maxTicksLimit , stepSize } = tickOpts; let maxTicks; if (stepSize) { maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1; if (maxTicks > 1000) { console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`); maxTicks = 1000; } } else { maxTicks = this.computeTickLimit(); maxTicksLimit = maxTicksLimit || 11; } if (maxTicksLimit) { maxTicks = Math.min(maxTicksLimit, maxTicks); } return maxTicks; } computeTickLimit() { return Number.POSITIVE_INFINITY; } buildTicks() { const opts = this.options; const tickOpts = opts.ticks; let maxTicks = this.getTickLimit(); maxTicks = Math.max(2, maxTicks); const numericGeneratorOptions = { maxTicks, bounds: opts.bounds, min: opts.min, max: opts.max, precision: tickOpts.precision, step: tickOpts.stepSize, count: tickOpts.count, maxDigits: this._maxDigits(), horizontal: this.isHorizontal(), minRotation: tickOpts.minRotation || 0, includeBounds: tickOpts.includeBounds !== false }; const dataRange = this._range || this; const ticks = generateTicks$1(numericGeneratorOptions, dataRange); if (opts.bounds === 'ticks') { _setMinAndMaxByKey(ticks, this, 'value'); } if (opts.reverse) { ticks.reverse(); this.start = this.max; this.end = this.min; } else { this.start = this.min; this.end = this.max; } return ticks; } configure() { const ticks = this.ticks; let start = this.min; let end = this.max; super.configure(); if (this.options.offset && ticks.length) { const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; start -= offset; end += offset; } this._startValue = start; this._endValue = end; this._valueRange = end - start; } getLabelForValue(value) { return formatNumber(value, this.chart.options.locale, this.options.ticks.format); } } class LinearScale extends LinearScaleBase { static id = 'linear'; static defaults = { ticks: { callback: Ticks.formatters.numeric } }; determineDataLimits() { const { min , max } = this.getMinMax(true); this.min = isNumberFinite(min) ? min : 0; this.max = isNumberFinite(max) ? max : 1; this.handleTickRangeOptions(); } computeTickLimit() { const horizontal = this.isHorizontal(); const length = horizontal ? this.width : this.height; const minRotation = toRadians(this.options.ticks.minRotation); const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001; const tickFont = this._resolveTickFontOptions(0); return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio)); } getPixelForValue(value) { return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange); } getValueForPixel(pixel) { return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; } } const log10Floor = (v)=>Math.floor(log10(v)); const changeExponent = (v, m)=>Math.pow(10, log10Floor(v) + m); function isMajor(tickVal) { const remain = tickVal / Math.pow(10, log10Floor(tickVal)); return remain === 1; } function steps(min, max, rangeExp) { const rangeStep = Math.pow(10, rangeExp); const start = Math.floor(min / rangeStep); const end = Math.ceil(max / rangeStep); return end - start; } function startExp(min, max) { const range = max - min; let rangeExp = log10Floor(range); while(steps(min, max, rangeExp) > 10){ rangeExp++; } while(steps(min, max, rangeExp) < 10){ rangeExp--; } return Math.min(rangeExp, log10Floor(min)); } function generateTicks(generationOptions, { min , max }) { min = finiteOrDefault(generationOptions.min, min); const ticks = []; const minExp = log10Floor(min); let exp = startExp(min, max); let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; const stepSize = Math.pow(10, exp); const base = minExp > exp ? Math.pow(10, minExp) : 0; const start = Math.round((min - base) * precision) / precision; const offset = Math.floor((min - base) / stepSize / 10) * stepSize * 10; let significand = Math.floor((start - offset) / Math.pow(10, exp)); let value = finiteOrDefault(generationOptions.min, Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision); while(value < max){ ticks.push({ value, major: isMajor(value), significand }); if (significand >= 10) { significand = significand < 15 ? 15 : 20; } else { significand++; } if (significand >= 20) { exp++; significand = 2; precision = exp >= 0 ? 1 : precision; } value = Math.round((base + offset + significand * Math.pow(10, exp)) * precision) / precision; } const lastTick = finiteOrDefault(generationOptions.max, value); ticks.push({ value: lastTick, major: isMajor(lastTick), significand }); return ticks; } class LogarithmicScale extends Scale { static id = 'logarithmic'; static defaults = { ticks: { callback: Ticks.formatters.logarithmic, major: { enabled: true } } }; constructor(cfg){ super(cfg); this.start = undefined; this.end = undefined; this._startValue = undefined; this._valueRange = 0; } parse(raw, index) { const value = LinearScaleBase.prototype.parse.apply(this, [ raw, index ]); if (value === 0) { this._zero = true; return undefined; } return isNumberFinite(value) && value > 0 ? value : null; } determineDataLimits() { const { min , max } = this.getMinMax(true); this.min = isNumberFinite(min) ? Math.max(0, min) : null; this.max = isNumberFinite(max) ? Math.max(0, max) : null; if (this.options.beginAtZero) { this._zero = true; } if (this._zero && this.min !== this._suggestedMin && !isNumberFinite(this._userMin)) { this.min = min === changeExponent(this.min, 0) ? changeExponent(this.min, -1) : changeExponent(this.min, 0); } this.handleTickRangeOptions(); } handleTickRangeOptions() { const { minDefined , maxDefined } = this.getUserBounds(); let min = this.min; let max = this.max; const setMin = (v)=>min = minDefined ? min : v; const setMax = (v)=>max = maxDefined ? max : v; if (min === max) { if (min <= 0) { setMin(1); setMax(10); } else { setMin(changeExponent(min, -1)); setMax(changeExponent(max, +1)); } } if (min <= 0) { setMin(changeExponent(max, -1)); } if (max <= 0) { setMax(changeExponent(min, +1)); } this.min = min; this.max = max; } buildTicks() { const opts = this.options; const generationOptions = { min: this._userMin, max: this._userMax }; const ticks = generateTicks(generationOptions, this); if (opts.bounds === 'ticks') { _setMinAndMaxByKey(ticks, this, 'value'); } if (opts.reverse) { ticks.reverse(); this.start = this.max; this.end = this.min; } else { this.start = this.min; this.end = this.max; } return ticks; } getLabelForValue(value) { return value === undefined ? '0' : formatNumber(value, this.chart.options.locale, this.options.ticks.format); } configure() { const start = this.min; super.configure(); this._startValue = log10(start); this._valueRange = log10(this.max) - log10(start); } getPixelForValue(value) { if (value === undefined || value === 0) { value = this.min; } if (value === null || isNaN(value)) { return NaN; } return this.getPixelForDecimal(value === this.min ? 0 : (log10(value) - this._startValue) / this._valueRange); } getValueForPixel(pixel) { const decimal = this.getDecimalForPixel(pixel); return Math.pow(10, this._startValue + decimal * this._valueRange); } } function getTickBackdropHeight(opts) { const tickOpts = opts.ticks; if (tickOpts.display && opts.display) { const padding = toPadding(tickOpts.backdropPadding); return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height; } return 0; } function measureLabelSize(ctx, font, label) { label = isArray(label) ? label : [ label ]; return { w: _longestText(ctx, font.string, label), h: label.length * font.lineHeight }; } function determineLimits(angle, pos, size, min, max) { if (angle === min || angle === max) { return { start: pos - size / 2, end: pos + size / 2 }; } else if (angle < min || angle > max) { return { start: pos - size, end: pos }; } return { start: pos, end: pos + size }; } function fitWithPointLabels(scale) { const orig = { l: scale.left + scale._padding.left, r: scale.right - scale._padding.right, t: scale.top + scale._padding.top, b: scale.bottom - scale._padding.bottom }; const limits = Object.assign({}, orig); const labelSizes = []; const padding = []; const valueCount = scale._pointLabels.length; const pointLabelOpts = scale.options.pointLabels; const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0; for(let i = 0; i < valueCount; i++){ const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i)); padding[i] = opts.padding; const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle); const plFont = toFont(opts.font); const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]); labelSizes[i] = textSize; const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle); const angle = Math.round(toDegrees(angleRadians)); const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); updateLimits(limits, orig, angleRadians, hLimits, vLimits); } scale.setCenterPoint(orig.l - limits.l, limits.r - orig.r, orig.t - limits.t, limits.b - orig.b); scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding); } function updateLimits(limits, orig, angle, hLimits, vLimits) { const sin = Math.abs(Math.sin(angle)); const cos = Math.abs(Math.cos(angle)); let x = 0; let y = 0; if (hLimits.start < orig.l) { x = (orig.l - hLimits.start) / sin; limits.l = Math.min(limits.l, orig.l - x); } else if (hLimits.end > orig.r) { x = (hLimits.end - orig.r) / sin; limits.r = Math.max(limits.r, orig.r + x); } if (vLimits.start < orig.t) { y = (orig.t - vLimits.start) / cos; limits.t = Math.min(limits.t, orig.t - y); } else if (vLimits.end > orig.b) { y = (vLimits.end - orig.b) / cos; limits.b = Math.max(limits.b, orig.b + y); } } function createPointLabelItem(scale, index, itemOpts) { const outerDistance = scale.drawingArea; const { extra , additionalAngle , padding , size } = itemOpts; const pointLabelPosition = scale.getPointPosition(index, outerDistance + extra + padding, additionalAngle); const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI))); const y = yForAngle(pointLabelPosition.y, size.h, angle); const textAlign = getTextAlignForAngle(angle); const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign); return { visible: true, x: pointLabelPosition.x, y, textAlign, left, top: y, right: left + size.w, bottom: y + size.h }; } function isNotOverlapped(item, area) { if (!area) { return true; } const { left , top , right , bottom } = item; const apexesInArea = _isPointInArea({ x: left, y: top }, area) || _isPointInArea({ x: left, y: bottom }, area) || _isPointInArea({ x: right, y: top }, area) || _isPointInArea({ x: right, y: bottom }, area); return !apexesInArea; } function buildPointLabelItems(scale, labelSizes, padding) { const items = []; const valueCount = scale._pointLabels.length; const opts = scale.options; const { centerPointLabels , display } = opts.pointLabels; const itemOpts = { extra: getTickBackdropHeight(opts) / 2, additionalAngle: centerPointLabels ? PI / valueCount : 0 }; let area; for(let i = 0; i < valueCount; i++){ itemOpts.padding = padding[i]; itemOpts.size = labelSizes[i]; const item = createPointLabelItem(scale, i, itemOpts); items.push(item); if (display === 'auto') { item.visible = isNotOverlapped(item, area); if (item.visible) { area = item; } } } return items; } function getTextAlignForAngle(angle) { if (angle === 0 || angle === 180) { return 'center'; } else if (angle < 180) { return 'left'; } return 'right'; } function leftForTextAlign(x, w, align) { if (align === 'right') { x -= w; } else if (align === 'center') { x -= w / 2; } return x; } function yForAngle(y, h, angle) { if (angle === 90 || angle === 270) { y -= h / 2; } else if (angle > 270 || angle < 90) { y -= h; } return y; } function drawPointLabelBox(ctx, opts, item) { const { left , top , right , bottom } = item; const { backdropColor } = opts; if (!isNullOrUndef(backdropColor)) { const borderRadius = toTRBLCorners(opts.borderRadius); const padding = toPadding(opts.backdropPadding); ctx.fillStyle = backdropColor; const backdropLeft = left - padding.left; const backdropTop = top - padding.top; const backdropWidth = right - left + padding.width; const backdropHeight = bottom - top + padding.height; if (Object.values(borderRadius).some((v)=>v !== 0)) { ctx.beginPath(); addRoundedRectPath(ctx, { x: backdropLeft, y: backdropTop, w: backdropWidth, h: backdropHeight, radius: borderRadius }); ctx.fill(); } else { ctx.fillRect(backdropLeft, backdropTop, backdropWidth, backdropHeight); } } } function drawPointLabels(scale, labelCount) { const { ctx , options: { pointLabels } } = scale; for(let i = labelCount - 1; i >= 0; i--){ const item = scale._pointLabelItems[i]; if (!item.visible) { continue; } const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i)); drawPointLabelBox(ctx, optsAtIndex, item); const plFont = toFont(optsAtIndex.font); const { x , y , textAlign } = item; renderText(ctx, scale._pointLabels[i], x, y + plFont.lineHeight / 2, plFont, { color: optsAtIndex.color, textAlign: textAlign, textBaseline: 'middle' }); } } function pathRadiusLine(scale, radius, circular, labelCount) { const { ctx } = scale; if (circular) { ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU); } else { let pointPosition = scale.getPointPosition(0, radius); ctx.moveTo(pointPosition.x, pointPosition.y); for(let i = 1; i < labelCount; i++){ pointPosition = scale.getPointPosition(i, radius); ctx.lineTo(pointPosition.x, pointPosition.y); } } } function drawRadiusLine(scale, gridLineOpts, radius, labelCount, borderOpts) { const ctx = scale.ctx; const circular = gridLineOpts.circular; const { color , lineWidth } = gridLineOpts; if (!circular && !labelCount || !color || !lineWidth || radius < 0) { return; } ctx.save(); ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.setLineDash(borderOpts.dash || []); ctx.lineDashOffset = borderOpts.dashOffset; ctx.beginPath(); pathRadiusLine(scale, radius, circular, labelCount); ctx.closePath(); ctx.stroke(); ctx.restore(); } function createPointLabelContext(parent, index, label) { return createContext(parent, { label, index, type: 'pointLabel' }); } class RadialLinearScale extends LinearScaleBase { static id = 'radialLinear'; static defaults = { display: true, animate: true, position: 'chartArea', angleLines: { display: true, lineWidth: 1, borderDash: [], borderDashOffset: 0.0 }, grid: { circular: false }, startAngle: 0, ticks: { showLabelBackdrop: true, callback: Ticks.formatters.numeric }, pointLabels: { backdropColor: undefined, backdropPadding: 2, display: true, font: { size: 10 }, callback (label) { return label; }, padding: 5, centerPointLabels: false } }; static defaultRoutes = { 'angleLines.color': 'borderColor', 'pointLabels.color': 'color', 'ticks.color': 'color' }; static descriptors = { angleLines: { _fallback: 'grid' } }; constructor(cfg){ super(cfg); this.xCenter = undefined; this.yCenter = undefined; this.drawingArea = undefined; this._pointLabels = []; this._pointLabelItems = []; } setDimensions() { const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2); const w = this.width = this.maxWidth - padding.width; const h = this.height = this.maxHeight - padding.height; this.xCenter = Math.floor(this.left + w / 2 + padding.left); this.yCenter = Math.floor(this.top + h / 2 + padding.top); this.drawingArea = Math.floor(Math.min(w, h) / 2); } determineDataLimits() { const { min , max } = this.getMinMax(false); this.min = isNumberFinite(min) && !isNaN(min) ? min : 0; this.max = isNumberFinite(max) && !isNaN(max) ? max : 0; this.handleTickRangeOptions(); } computeTickLimit() { return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); } generateTickLabels(ticks) { LinearScaleBase.prototype.generateTickLabels.call(this, ticks); this._pointLabels = this.getLabels().map((value, index)=>{ const label = callback(this.options.pointLabels.callback, [ value, index ], this); return label || label === 0 ? label : ''; }).filter((v, i)=>this.chart.getDataVisibility(i)); } fit() { const opts = this.options; if (opts.display && opts.pointLabels.display) { fitWithPointLabels(this); } else { this.setCenterPoint(0, 0, 0, 0); } } setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { this.xCenter += Math.floor((leftMovement - rightMovement) / 2); this.yCenter += Math.floor((topMovement - bottomMovement) / 2); this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement)); } getIndexAngle(index) { const angleMultiplier = TAU / (this._pointLabels.length || 1); const startAngle = this.options.startAngle || 0; return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); } getDistanceFromCenterForValue(value) { if (isNullOrUndef(value)) { return NaN; } const scalingFactor = this.drawingArea / (this.max - this.min); if (this.options.reverse) { return (this.max - value) * scalingFactor; } return (value - this.min) * scalingFactor; } getValueForDistanceFromCenter(distance) { if (isNullOrUndef(distance)) { return NaN; } const scaledDistance = distance / (this.drawingArea / (this.max - this.min)); return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance; } getPointLabelContext(index) { const pointLabels = this._pointLabels || []; if (index >= 0 && index < pointLabels.length) { const pointLabel = pointLabels[index]; return createPointLabelContext(this.getContext(), index, pointLabel); } } getPointPosition(index, distanceFromCenter, additionalAngle = 0) { const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle; return { x: Math.cos(angle) * distanceFromCenter + this.xCenter, y: Math.sin(angle) * distanceFromCenter + this.yCenter, angle }; } getPointPositionForValue(index, value) { return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); } getBasePosition(index) { return this.getPointPositionForValue(index || 0, this.getBaseValue()); } getPointLabelPosition(index) { const { left , top , right , bottom } = this._pointLabelItems[index]; return { left, top, right, bottom }; } drawBackground() { const { backgroundColor , grid: { circular } } = this.options; if (backgroundColor) { const ctx = this.ctx; ctx.save(); ctx.beginPath(); pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length); ctx.closePath(); ctx.fillStyle = backgroundColor; ctx.fill(); ctx.restore(); } } drawGrid() { const ctx = this.ctx; const opts = this.options; const { angleLines , grid , border } = opts; const labelCount = this._pointLabels.length; let i, offset, position; if (opts.pointLabels.display) { drawPointLabels(this, labelCount); } if (grid.display) { this.ticks.forEach((tick, index)=>{ if (index !== 0 || index === 0 && this.min < 0) { offset = this.getDistanceFromCenterForValue(tick.value); const context = this.getContext(index); const optsAtIndex = grid.setContext(context); const optsAtIndexBorder = border.setContext(context); drawRadiusLine(this, optsAtIndex, offset, labelCount, optsAtIndexBorder); } }); } if (angleLines.display) { ctx.save(); for(i = labelCount - 1; i >= 0; i--){ const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i)); const { color , lineWidth } = optsAtIndex; if (!lineWidth || !color) { continue; } ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.setLineDash(optsAtIndex.borderDash); ctx.lineDashOffset = optsAtIndex.borderDashOffset; offset = this.getDistanceFromCenterForValue(opts.reverse ? this.min : this.max); position = this.getPointPosition(i, offset); ctx.beginPath(); ctx.moveTo(this.xCenter, this.yCenter); ctx.lineTo(position.x, position.y); ctx.stroke(); } ctx.restore(); } } drawBorder() {} drawLabels() { const ctx = this.ctx; const opts = this.options; const tickOpts = opts.ticks; if (!tickOpts.display) { return; } const startAngle = this.getIndexAngle(0); let offset, width; ctx.save(); ctx.translate(this.xCenter, this.yCenter); ctx.rotate(startAngle); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; this.ticks.forEach((tick, index)=>{ if (index === 0 && this.min >= 0 && !opts.reverse) { return; } const optsAtIndex = tickOpts.setContext(this.getContext(index)); const tickFont = toFont(optsAtIndex.font); offset = this.getDistanceFromCenterForValue(this.ticks[index].value); if (optsAtIndex.showLabelBackdrop) { ctx.font = tickFont.string; width = ctx.measureText(tick.label).width; ctx.fillStyle = optsAtIndex.backdropColor; const padding = toPadding(optsAtIndex.backdropPadding); ctx.fillRect(-width / 2 - padding.left, -offset - tickFont.size / 2 - padding.top, width + padding.width, tickFont.size + padding.height); } renderText(ctx, tick.label, 0, -offset, tickFont, { color: optsAtIndex.color, strokeColor: optsAtIndex.textStrokeColor, strokeWidth: optsAtIndex.textStrokeWidth }); }); ctx.restore(); } drawTitle() {} } const INTERVALS = { millisecond: { common: true, size: 1, steps: 1000 }, second: { common: true, size: 1000, steps: 60 }, minute: { common: true, size: 60000, steps: 60 }, hour: { common: true, size: 3600000, steps: 24 }, day: { common: true, size: 86400000, steps: 30 }, week: { common: false, size: 604800000, steps: 4 }, month: { common: true, size: 2.628e9, steps: 12 }, quarter: { common: false, size: 7.884e9, steps: 4 }, year: { common: true, size: 3.154e10 } }; const UNITS = /* #__PURE__ */ Object.keys(INTERVALS); function sorter(a, b) { return a - b; } function parse(scale, input) { if (isNullOrUndef(input)) { return null; } const adapter = scale._adapter; const { parser , round , isoWeekday } = scale._parseOpts; let value = input; if (typeof parser === 'function') { value = parser(value); } if (!isNumberFinite(value)) { value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value); } if (value === null) { return null; } if (round) { value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) ? adapter.startOf(value, 'isoWeek', isoWeekday) : adapter.startOf(value, round); } return +value; } function determineUnitForAutoTicks(minUnit, min, max, capacity) { const ilen = UNITS.length; for(let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i){ const interval = INTERVALS[UNITS[i]]; const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER; if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { return UNITS[i]; } } return UNITS[ilen - 1]; } function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { for(let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--){ const unit = UNITS[i]; if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { return unit; } } return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; } function determineMajorUnit(unit) { for(let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i){ if (INTERVALS[UNITS[i]].common) { return UNITS[i]; } } } function addTick(ticks, time, timestamps) { if (!timestamps) { ticks[time] = true; } else if (timestamps.length) { const { lo , hi } = _lookup(timestamps, time); const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; ticks[timestamp] = true; } } function setMajorTicks(scale, ticks, map, majorUnit) { const adapter = scale._adapter; const first = +adapter.startOf(ticks[0].value, majorUnit); const last = ticks[ticks.length - 1].value; let major, index; for(major = first; major <= last; major = +adapter.add(major, 1, majorUnit)){ index = map[major]; if (index >= 0) { ticks[index].major = true; } } return ticks; } function ticksFromTimestamps(scale, values, majorUnit) { const ticks = []; const map = {}; const ilen = values.length; let i, value; for(i = 0; i < ilen; ++i){ value = values[i]; map[value] = i; ticks.push({ value, major: false }); } return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit); } class TimeScale extends Scale { static id = 'time'; static defaults = { bounds: 'data', adapters: {}, time: { parser: false, unit: false, round: false, isoWeekday: false, minUnit: 'millisecond', displayFormats: {} }, ticks: { source: 'auto', callback: false, major: { enabled: false } } }; constructor(props){ super(props); this._cache = { data: [], labels: [], all: [] }; this._unit = 'day'; this._majorUnit = undefined; this._offsets = {}; this._normalized = false; this._parseOpts = undefined; } init(scaleOpts, opts = {}) { const time = scaleOpts.time || (scaleOpts.time = {}); const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); adapter.init(opts); mergeIf(time.displayFormats, adapter.formats()); this._parseOpts = { parser: time.parser, round: time.round, isoWeekday: time.isoWeekday }; super.init(scaleOpts); this._normalized = opts.normalized; } parse(raw, index) { if (raw === undefined) { return null; } return parse(this, raw); } beforeLayout() { super.beforeLayout(); this._cache = { data: [], labels: [], all: [] }; } determineDataLimits() { const options = this.options; const adapter = this._adapter; const unit = options.time.unit || 'day'; let { min , max , minDefined , maxDefined } = this.getUserBounds(); function _applyBounds(bounds) { if (!minDefined && !isNaN(bounds.min)) { min = Math.min(min, bounds.min); } if (!maxDefined && !isNaN(bounds.max)) { max = Math.max(max, bounds.max); } } if (!minDefined || !maxDefined) { _applyBounds(this._getLabelBounds()); if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { _applyBounds(this.getMinMax(false)); } } min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; this.min = Math.min(min, max - 1); this.max = Math.max(min + 1, max); } _getLabelBounds() { const arr = this.getLabelTimestamps(); let min = Number.POSITIVE_INFINITY; let max = Number.NEGATIVE_INFINITY; if (arr.length) { min = arr[0]; max = arr[arr.length - 1]; } return { min, max }; } buildTicks() { const options = this.options; const timeOpts = options.time; const tickOpts = options.ticks; const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate(); if (options.bounds === 'ticks' && timestamps.length) { this.min = this._userMin || timestamps[0]; this.max = this._userMax || timestamps[timestamps.length - 1]; } const min = this.min; const max = this.max; const ticks = _filterBetween(timestamps, min, max); this._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min)) : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max)); this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined : determineMajorUnit(this._unit); this.initOffsets(timestamps); if (options.reverse) { ticks.reverse(); } return ticksFromTimestamps(this, ticks, this._majorUnit); } afterAutoSkip() { if (this.options.offsetAfterAutoskip) { this.initOffsets(this.ticks.map((tick)=>+tick.value)); } } initOffsets(timestamps = []) { let start = 0; let end = 0; let first, last; if (this.options.offset && timestamps.length) { first = this.getDecimalForValue(timestamps[0]); if (timestamps.length === 1) { start = 1 - first; } else { start = (this.getDecimalForValue(timestamps[1]) - first) / 2; } last = this.getDecimalForValue(timestamps[timestamps.length - 1]); if (timestamps.length === 1) { end = last; } else { end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; } } const limit = timestamps.length < 3 ? 0.5 : 0.25; start = _limitValue(start, 0, limit); end = _limitValue(end, 0, limit); this._offsets = { start, end, factor: 1 / (start + 1 + end) }; } _generate() { const adapter = this._adapter; const min = this.min; const max = this.max; const options = this.options; const timeOpts = options.time; const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min)); const stepSize = valueOrDefault(options.ticks.stepSize, 1); const weekday = minor === 'week' ? timeOpts.isoWeekday : false; const hasWeekday = isNumber(weekday) || weekday === true; const ticks = {}; let first = min; let time, count; if (hasWeekday) { first = +adapter.startOf(first, 'isoWeek', weekday); } first = +adapter.startOf(first, hasWeekday ? 'day' : minor); if (adapter.diff(max, min, minor) > 100000 * stepSize) { throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); } const timestamps = options.ticks.source === 'data' && this.getDataTimestamps(); for(time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++){ addTick(ticks, time, timestamps); } if (time === max || options.bounds === 'ticks' || count === 1) { addTick(ticks, time, timestamps); } return Object.keys(ticks).sort(sorter).map((x)=>+x); } getLabelForValue(value) { const adapter = this._adapter; const timeOpts = this.options.time; if (timeOpts.tooltipFormat) { return adapter.format(value, timeOpts.tooltipFormat); } return adapter.format(value, timeOpts.displayFormats.datetime); } format(value, format) { const options = this.options; const formats = options.time.displayFormats; const unit = this._unit; const fmt = format || formats[unit]; return this._adapter.format(value, fmt); } _tickFormatFunction(time, index, ticks, format) { const options = this.options; const formatter = options.ticks.callback; if (formatter) { return callback(formatter, [ time, index, ticks ], this); } const formats = options.time.displayFormats; const unit = this._unit; const majorUnit = this._majorUnit; const minorFormat = unit && formats[unit]; const majorFormat = majorUnit && formats[majorUnit]; const tick = ticks[index]; const major = majorUnit && majorFormat && tick && tick.major; return this._adapter.format(time, format || (major ? majorFormat : minorFormat)); } generateTickLabels(ticks) { let i, ilen, tick; for(i = 0, ilen = ticks.length; i < ilen; ++i){ tick = ticks[i]; tick.label = this._tickFormatFunction(tick.value, i, ticks); } } getDecimalForValue(value) { return value === null ? NaN : (value - this.min) / (this.max - this.min); } getPixelForValue(value) { const offsets = this._offsets; const pos = this.getDecimalForValue(value); return this.getPixelForDecimal((offsets.start + pos) * offsets.factor); } getValueForPixel(pixel) { const offsets = this._offsets; const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; return this.min + pos * (this.max - this.min); } _getLabelSize(label) { const ticksOpts = this.options.ticks; const tickLabelWidth = this.ctx.measureText(label).width; const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); const cosRotation = Math.cos(angle); const sinRotation = Math.sin(angle); const tickFontSize = this._resolveTickFontOptions(0).size; return { w: tickLabelWidth * cosRotation + tickFontSize * sinRotation, h: tickLabelWidth * sinRotation + tickFontSize * cosRotation }; } _getLabelCapacity(exampleTime) { const timeOpts = this.options.time; const displayFormats = timeOpts.displayFormats; const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [ exampleTime ], this._majorUnit), format); const size = this._getLabelSize(exampleLabel); const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1; return capacity > 0 ? capacity : 1; } getDataTimestamps() { let timestamps = this._cache.data || []; let i, ilen; if (timestamps.length) { return timestamps; } const metas = this.getMatchingVisibleMetas(); if (this._normalized && metas.length) { return this._cache.data = metas[0].controller.getAllParsedValues(this); } for(i = 0, ilen = metas.length; i < ilen; ++i){ timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this)); } return this._cache.data = this.normalize(timestamps); } getLabelTimestamps() { const timestamps = this._cache.labels || []; let i, ilen; if (timestamps.length) { return timestamps; } const labels = this.getLabels(); for(i = 0, ilen = labels.length; i < ilen; ++i){ timestamps.push(parse(this, labels[i])); } return this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps); } normalize(values) { return _arrayUnique(values.sort(sorter)); } } function chart_interpolate(table, val, reverse) { let lo = 0; let hi = table.length - 1; let prevSource, nextSource, prevTarget, nextTarget; if (reverse) { if (val >= table[lo].pos && val <= table[hi].pos) { ({ lo , hi } = _lookupByKey(table, 'pos', val)); } ({ pos: prevSource , time: prevTarget } = table[lo]); ({ pos: nextSource , time: nextTarget } = table[hi]); } else { if (val >= table[lo].time && val <= table[hi].time) { ({ lo , hi } = _lookupByKey(table, 'time', val)); } ({ time: prevSource , pos: prevTarget } = table[lo]); ({ time: nextSource , pos: nextTarget } = table[hi]); } const span = nextSource - prevSource; return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; } class TimeSeriesScale extends TimeScale { static id = 'timeseries'; static defaults = TimeScale.defaults; constructor(props){ super(props); this._table = []; this._minPos = undefined; this._tableRange = undefined; } initOffsets() { const timestamps = this._getTimestampsForTable(); const table = this._table = this.buildLookupTable(timestamps); this._minPos = chart_interpolate(table, this.min); this._tableRange = chart_interpolate(table, this.max) - this._minPos; super.initOffsets(timestamps); } buildLookupTable(timestamps) { const { min , max } = this; const items = []; const table = []; let i, ilen, prev, curr, next; for(i = 0, ilen = timestamps.length; i < ilen; ++i){ curr = timestamps[i]; if (curr >= min && curr <= max) { items.push(curr); } } if (items.length < 2) { return [ { time: min, pos: 0 }, { time: max, pos: 1 } ]; } for(i = 0, ilen = items.length; i < ilen; ++i){ next = items[i + 1]; prev = items[i - 1]; curr = items[i]; if (Math.round((next + prev) / 2) !== curr) { table.push({ time: curr, pos: i / (ilen - 1) }); } } return table; } _generate() { const min = this.min; const max = this.max; let timestamps = super.getDataTimestamps(); if (!timestamps.includes(min) || !timestamps.length) { timestamps.splice(0, 0, min); } if (!timestamps.includes(max) || timestamps.length === 1) { timestamps.push(max); } return timestamps.sort((a, b)=>a - b); } _getTimestampsForTable() { let timestamps = this._cache.all || []; if (timestamps.length) { return timestamps; } const data = this.getDataTimestamps(); const label = this.getLabelTimestamps(); if (data.length && label.length) { timestamps = this.normalize(data.concat(label)); } else { timestamps = data.length ? data : label; } timestamps = this._cache.all = timestamps; return timestamps; } getDecimalForValue(value) { return (chart_interpolate(this._table, value) - this._minPos) / this._tableRange; } getValueForPixel(pixel) { const offsets = this._offsets; const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end; return chart_interpolate(this._table, decimal * this._tableRange + this._minPos, true); } } var scales = /*#__PURE__*/Object.freeze({ __proto__: null, CategoryScale: CategoryScale, LinearScale: LinearScale, LogarithmicScale: LogarithmicScale, RadialLinearScale: RadialLinearScale, TimeScale: TimeScale, TimeSeriesScale: TimeSeriesScale }); const registerables = [ controllers, chart_elements, plugins, scales ]; //# sourceMappingURL=chart.js.map ;// ../assets/scripts/constants/colors.js const COLORS = { 'white': '#ffffff', 'red-50': '#ffebee', 'red-100': '#ffcdd2', 'red-200': '#ef9a9a', 'red-300': '#e57373', 'red-400': '#ef5350', 'red-500': '#f44336', 'red-600': '#e53935', 'red-700': '#d32f2f', 'red-800': '#c62828', 'red-900': '#b71c1c', 'red-a100': '#ff8a80', 'red-a200': '#ff5252', 'red-a400': '#ff1744', 'red-a700': '#d50000', 'pink-50': '#fce4ec', 'pink-100': '#f8bbd0', 'pink-200': '#f48fb1', 'pink-300': '#f06292', 'pink-400': '#ec407a', 'pink-500': '#e91e63', 'pink-600': '#d81b60', 'pink-700': '#c2185b', 'pink-800': '#ad1457', 'pink-900': '#880e4f', 'pink-a100': '#ff80ab', 'pink-a200': '#ff4081', 'pink-a400': '#f50057', 'pink-a700': '#c51162', 'purple-50': '#f3e5f5', 'purple-100': '#e1bee7', 'purple-200': '#ce93d8', 'purple-300': '#ba68c8', 'purple-400': '#ab47bc', 'purple-500': '#9c27b0', 'purple-600': '#8e24aa', 'purple-700': '#7b1fa2', 'purple-800': '#6a1b9a', 'purple-900': '#4a148c', 'purple-a100': '#ea80fc', 'purple-a200': '#e040fb', 'purple-a400': '#d500f9', 'purple-a700': '#aa00ff', 'deep-purple-50': '#ede7f6', 'deep-purple-100': '#d1c4e9', 'deep-purple-200': '#b39ddb', 'deep-purple-300': '#9575cd', 'deep-purple-400': '#7e57c2', 'deep-purple-500': '#673ab7', 'deep-purple-600': '#5e35b1', 'deep-purple-700': '#512da8', 'deep-purple-800': '#4527a0', 'deep-purple-900': '#311b92', 'deep-purple-a100': '#b388ff', 'deep-purple-a200': '#7c4dff', 'deep-purple-a400': '#651fff', 'deep-purple-a700': '#6200ea', 'indigo-50': '#e8eaf6', 'indigo-100': '#c5cae9', 'indigo-200': '#9fa8da', 'indigo-300': '#7986cb', 'indigo-400': '#5c6bc0', 'indigo-500': '#3f51b5', 'indigo-600': '#3949ab', 'indigo-700': '#303f9f', 'indigo-800': '#283593', 'indigo-900': '#1a237e', 'indigo-a100': '#8c9eff', 'indigo-a200': '#536dfe', 'indigo-a400': '#3d5afe', 'indigo-a700': '#304ffe', 'blue-50': '#e3f2fd', 'blue-100': '#bbdefb', 'blue-200': '#90caf9', 'blue-300': '#64b5f6', 'blue-400': '#42a5f5', 'blue-500': '#2196f3', 'blue-600': '#1e88e5', 'blue-700': '#1976d2', 'blue-800': '#1565c0', 'blue-900': '#0d47a1', 'blue-a100': '#82b1ff', 'blue-a200': '#448aff', 'blue-a400': '#2979ff', 'blue-a700': '#2962ff', 'light-blue-50': '#e1f5fe', 'light-blue-100': '#b3e5fc', 'light-blue-200': '#81d4fa', 'light-blue-300': '#4fc3f7', 'light-blue-400': '#29b6f6', 'light-blue-500': '#03a9f4', 'light-blue-600': '#039be5', 'light-blue-700': '#0288d1', 'light-blue-800': '#0277bd', 'light-blue-900': '#01579b', 'light-blue-a100': '#80d8ff', 'light-blue-a200': '#40c4ff', 'light-blue-a400': '#00b0ff', 'light-blue-a700': '#0091ea', 'cyan-50': '#e0f7fa', 'cyan-100': '#b2ebf2', 'cyan-200': '#80deea', 'cyan-300': '#4dd0e1', 'cyan-400': '#26c6da', 'cyan-500': '#00bcd4', 'cyan-600': '#00acc1', 'cyan-700': '#0097a7', 'cyan-800': '#00838f', 'cyan-900': '#006064', 'cyan-a100': '#84ffff', 'cyan-a200': '#18ffff', 'cyan-a400': '#00e5ff', 'cyan-a700': '#00b8d4', 'teal-50': '#e0f2f1', 'teal-100': '#b2dfdb', 'teal-200': '#80cbc4', 'teal-300': '#4db6ac', 'teal-400': '#26a69a', 'teal-500': '#009688', 'teal-600': '#00897b', 'teal-700': '#00796b', 'teal-800': '#00695c', 'teal-900': '#004d40', 'teal-a100': '#a7ffeb', 'teal-a200': '#64ffda', 'teal-a400': '#1de9b6', 'teal-a700': '#00bfa5', 'green-50': '#e8f5e9', 'green-100': '#c8e6c9', 'green-200': '#a5d6a7', 'green-300': '#81c784', 'green-400': '#66bb6a', 'green-500': '#4caf50', 'green-600': '#43a047', 'green-700': '#388e3c', 'green-800': '#2e7d32', 'green-900': '#1b5e20', 'green-a100': '#b9f6ca', 'green-a200': '#69f0ae', 'green-a400': '#00e676', 'green-a700': '#00c853', 'light-green-50': '#f1f8e9', 'light-green-100': '#dcedc8', 'light-green-200': '#c5e1a5', 'light-green-300': '#aed581', 'light-green-400': '#9ccc65', 'light-green-500': '#8bc34a', 'light-green-600': '#7cb342', 'light-green-700': '#689f38', 'light-green-800': '#558b2f', 'light-green-900': '#33691e', 'light-green-a100': '#ccff90', 'light-green-a200': '#b2ff59', 'light-green-a400': '#76ff03', 'light-green-a700': '#64dd17', 'lime-50': '#f9fbe7', 'lime-100': '#f0f4c3', 'lime-200': '#e6ee9c', 'lime-300': '#dce775', 'lime-400': '#d4e157', 'lime-500': '#cddc39', 'lime-600': '#c0ca33', 'lime-700': '#afb42b', 'lime-800': '#9e9d24', 'lime-900': '#827717', 'lime-a100': '#f4ff81', 'lime-a200': '#eeff41', 'lime-a400': '#c6ff00', 'lime-a700': '#aeea00', 'yellow-50': '#fffde7', 'yellow-100': '#fff9c4', 'yellow-200': '#fff59d', 'yellow-300': '#fff176', 'yellow-400': '#ffee58', 'yellow-500': '#ffeb3b', 'yellow-600': '#fdd835', 'yellow-700': '#fbc02d', 'yellow-800': '#f9a825', 'yellow-900': '#f57f17', 'yellow-a100': '#ffff8d', 'yellow-a200': '#ffff00', 'yellow-a400': '#ffea00', 'yellow-a700': '#ffd600', 'amber-50': '#fff8e1', 'amber-100': '#ffecb3', 'amber-200': '#ffe082', 'amber-300': '#ffd54f', 'amber-400': '#ffca28', 'amber-500': '#ffc107', 'amber-600': '#ffb300', 'amber-700': '#ffa000', 'amber-800': '#ff8f00', 'amber-900': '#ff6f00', 'amber-a100': '#ffe57f', 'amber-a200': '#ffd740', 'amber-a400': '#ffc400', 'amber-a700': '#ffab00', 'orange-50': '#fff3e0', 'orange-100': '#ffe0b2', 'orange-200': '#ffcc80', 'orange-300': '#ffb74d', 'orange-400': '#ffa726', 'orange-500': '#ff9800', 'orange-600': '#fb8c00', 'orange-700': '#f57c00', 'orange-800': '#ef6c00', 'orange-900': '#e65100', 'orange-a100': '#ffd180', 'orange-a200': '#ffab40', 'orange-a400': '#ff9100', 'orange-a700': '#ff6d00', 'deep-orange-50': '#fbe9e7', 'deep-orange-100': '#ffccbc', 'deep-orange-200': '#ffab91', 'deep-orange-300': '#ff8a65', 'deep-orange-400': '#ff7043', 'deep-orange-500': '#ff5722', 'deep-orange-600': '#f4511e', 'deep-orange-700': '#e64a19', 'deep-orange-800': '#d84315', 'deep-orange-900': '#bf360c', 'deep-orange-a100': '#ff9e80', 'deep-orange-a200': '#ff6e40', 'deep-orange-a400': '#ff3d00', 'deep-orange-a700': '#dd2c00', 'brown-50': '#efebe9', 'brown-100': '#d7ccc8', 'brown-200': '#bcaaa4', 'brown-300': '#a1887f', 'brown-400': '#8d6e63', 'brown-500': '#795548', 'brown-600': '#6d4c41', 'brown-700': '#5d4037', 'brown-800': '#4e342e', 'brown-900': '#3e2723', 'grey-50': '#fafafa', 'grey-100': '#f5f5f5', 'grey-200': '#eeeeee', 'grey-300': '#e0e0e0', 'grey-400': '#bdbdbd', 'grey-500': '#9e9e9e', 'grey-600': '#757575', 'grey-700': '#616161', 'grey-800': '#424242', 'grey-900': '#212121', 'blue-grey-50': '#eceff1', 'blue-grey-100': '#cfd8dc', 'blue-grey-200': '#b0bec5', 'blue-grey-300': '#90a4ae', 'blue-grey-400': '#78909c', 'blue-grey-500': '#607d8b', 'blue-grey-600': '#546e7a', 'blue-grey-700': '#455a64', 'blue-grey-800': '#37474f', 'blue-grey-900': '#263238' }; const GREYS = { 'grey-100': '#f9fafb', 'grey-200': '#f2f3f5', 'grey-300': '#e6eaf0', 'grey-400': '#d3d9e3', 'grey-500': '#b9c2d0', 'grey-600': '#7c8695', 'grey-700': '#72777a', 'grey-800': '#565a5c', 'grey-900': '#313435' }; ;// ../assets/scripts/components/Chart.js /** * Modern Chart Component * Replaces jQuery Sparkline with Chart.js */ // Register Chart.js components chart_Chart.register(...registerables); class ChartComponent { constructor() { this.charts = new Map(); // Store chart instances this.debounceTimer = null; this.init(); } init() { // Only disable resizing for small sparkline charts this.createSparklines(); this.createOtherCharts(); this.setupResizeHandler(); } /** * Create sparklines (only for dashboard page) */ createSparklines() { // Only create sparklines if we're on a page that has them const sparklineExists = document.getElementById('sparklinedash'); if (!sparklineExists) { return; } const sparklineConfigs = [{ id: 'sparklinedash', data: [0, 5, 6, 10, 9, 12, 4, 9], color: '#4caf50' }, { id: 'sparklinedash2', data: [0, 5, 6, 10, 9, 12, 4, 9], color: '#9675ce' }, { id: 'sparklinedash3', data: [0, 5, 6, 10, 9, 12, 4, 9], color: '#03a9f3' }, { id: 'sparklinedash4', data: [0, 5, 6, 10, 9, 12, 4, 9], color: '#f96262' }]; sparklineConfigs.forEach(config => { // Only create if the target element exists if (document.getElementById(config.id)) { this.createSparklineChart(config); } }); } /** * Create sparkline chart from configuration */ createSparklineChart(_ref) { let { id, data, color } = _ref; let canvas = document.getElementById(id); // Only proceed if we have a valid target element if (!canvas) { return; } // If element exists but isn't a canvas, replace it with canvas if (canvas.tagName !== 'CANVAS') { const parent = canvas.parentNode; if (!parent) { return; } // Create new canvas element const newCanvas = document.createElement('canvas'); newCanvas.id = id; newCanvas.width = 100; newCanvas.height = 20; newCanvas.style.width = '100px'; newCanvas.style.height = '20px'; // Replace the span with canvas parent.replaceChild(newCanvas, canvas); canvas = newCanvas; } else { // Set canvas dimensions to match original sparkline canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: data.map((_, i) => i), datasets: [{ data, backgroundColor: color, borderColor: color, borderWidth: 0, barPercentage: 0.6, categoryPercentage: 0.8 }] }, options: { responsive: false, maintainAspectRatio: false, animation: false, events: [], onResize: null, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: false } }, elements: { bar: { borderRadius: 1 } } } }); this.charts.set(id, chart); } /** * Create other chart types (only if they exist on the page) */ createOtherCharts() { // Determine if we're on the dashboard or charts page const isChartsPage = document.getElementById('area-chart') !== null; const isDashboard = !isChartsPage && document.getElementById('line-chart') !== null; // Create Monthly Stats chart with enhanced dual-line data (dashboard only) if (isDashboard) { this.createMonthlyStatsChart(); } // Charts page specific charts (only on charts page) if (isChartsPage) { this.createChartsPageCharts(); } // Only create charts if their target elements exist if (document.getElementById('sparkline')) { this.createLineChart('sparkline', [5, 6, 7, 9, 9, 5, 3, 2, 2, 4, 6, 7]); } if (document.getElementById('compositebar')) { this.createCompositeChart('compositebar', [4, 1, 5, 7, 9, 9, 8, 7, 6, 6, 4, 7, 8, 4, 3, 2, 2, 5, 6, 7]); } // Regular sparklines with custom colors (only on pages that have them) this.createCustomSparklines(); // Easy Pie Charts (only if they exist) this.createEasyPieCharts(); } /** * Create enhanced Monthly Stats chart with dual lines and more data */ createMonthlyStatsChart() { const canvas = document.getElementById('line-chart'); if (!canvas) return; const ctx = canvas.getContext('2d'); // Enhanced data for monthly stats const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; const salesData = [120, 135, 145, 165, 180, 195, 210, 225, 240, 220, 200, 185]; const profitData = [45, 52, 58, 62, 68, 75, 82, 88, 92, 85, 78, 72]; const chart = new chart_Chart(ctx, { type: 'line', data: { labels: months, datasets: [{ label: 'Sales ($K)', data: salesData, borderColor: '#4caf50', backgroundColor: 'rgba(76, 175, 80, 0.1)', borderWidth: 3, pointRadius: 5, pointHoverRadius: 7, pointBackgroundColor: '#4caf50', pointBorderColor: '#ffffff', pointBorderWidth: 2, tension: 0.4, fill: false }, { label: 'Profit ($K)', data: profitData, borderColor: '#2196f3', backgroundColor: 'rgba(33, 150, 243, 0.1)', borderWidth: 3, pointRadius: 5, pointHoverRadius: 7, pointBackgroundColor: '#2196f3', pointBorderColor: '#ffffff', pointBorderWidth: 2, tension: 0.4, fill: false }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'top', labels: { padding: 20, font: { size: 12, weight: '600' } } }, tooltip: { enabled: true, cornerRadius: 8, displayColors: true, intersect: false, mode: 'index', callbacks: { label(context) { return `${context.dataset.label}: $${context.parsed.y}K`; } } } }, scales: { x: { grid: { display: false }, ticks: { font: { size: 11 } } }, y: { beginAtZero: true, grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 }, callback(value) { return `$${value}K`; } } } }, interaction: { intersect: false, mode: 'index' } } }); this.charts.set('line-chart', chart); } /** * Create line chart (only if target exists) */ createLineChart(id, data) { let canvas = document.getElementById(id); // Only proceed if target element exists if (!canvas) { return; } // If element exists but isn't a canvas, replace it with canvas if (canvas.tagName !== 'CANVAS') { const parent = canvas.parentNode; if (!parent) { return; } // Create new canvas element const newCanvas = document.createElement('canvas'); newCanvas.id = id; newCanvas.width = 100; newCanvas.height = 20; newCanvas.style.width = '100px'; newCanvas.style.height = '20px'; // Replace element with canvas parent.replaceChild(newCanvas, canvas); canvas = newCanvas; } else { canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'line', data: { labels: data.map((_, i) => i), datasets: [{ data, borderColor: COLORS['blue-500'], backgroundColor: 'transparent', borderWidth: 1, pointRadius: 0, tension: 0.4 }] }, options: { responsive: false, maintainAspectRatio: false, animation: false, events: [], onResize: null, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: false } } } }); this.charts.set(id, chart); } /** * Create composite chart (only if target exists) */ createCompositeChart(id, data) { let canvas = document.getElementById(id); // Only proceed if target element exists if (!canvas) { return; } // If element exists but isn't a canvas, replace it with canvas if (canvas.tagName !== 'CANVAS') { const parent = canvas.parentNode; if (!parent) { return; } // Create new canvas element const newCanvas = document.createElement('canvas'); newCanvas.id = id; newCanvas.width = 100; newCanvas.height = 20; newCanvas.style.width = '100px'; newCanvas.style.height = '20px'; // Replace element with canvas parent.replaceChild(newCanvas, canvas); canvas = newCanvas; } else { canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: data.map((_, i) => i), datasets: [{ type: 'bar', data, backgroundColor: '#aaf', borderColor: '#aaf', borderWidth: 0 }, { type: 'line', data, borderColor: 'red', backgroundColor: 'transparent', borderWidth: 1, pointRadius: 0, tension: 0.4 }] }, options: { responsive: false, maintainAspectRatio: false, animation: false, events: [], onResize: null, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: false } } } }); this.charts.set(id, chart); } /** * Create custom sparklines for different elements (only if they exist) */ createCustomSparklines() { const sparklineElements = document.querySelectorAll('.sparkline'); const sparkbarElements = document.querySelectorAll('.sparkbar'); const sparktriElements = document.querySelectorAll('.sparktri'); const sparkdiscElements = document.querySelectorAll('.sparkdisc'); const sparkbullElements = document.querySelectorAll('.sparkbull'); const sparkboxElements = document.querySelectorAll('.sparkbox'); // Only create if we have elements if (sparklineElements.length === 0 && sparkbarElements.length === 0 && sparktriElements.length === 0 && sparkdiscElements.length === 0 && sparkbullElements.length === 0 && sparkboxElements.length === 0) { return; } const values = [5, 4, 5, -2, 0, 3, -5, 6, 7, 9, 9, 5, -3, -2, 2, -4]; const valuesAlt = [1, 1, 0, 1, -1, -1, 1, -1, 0, 0, 1, 1]; sparklineElements.forEach((element, index) => { this.createCustomLineChart(element, values, `sparkline-${index}`); }); sparkbarElements.forEach((element, index) => { this.createCustomBarChart(element, values, `sparkbar-${index}`); }); sparktriElements.forEach((element, index) => { this.createTristateChart(element, valuesAlt, `sparktri-${index}`); }); sparkdiscElements.forEach((element, index) => { this.createDiscreteChart(element, values, `sparkdisc-${index}`); }); sparkbullElements.forEach((element, index) => { this.createBulletChart(element, values, `sparkbull-${index}`); }); sparkboxElements.forEach((element, index) => { this.createBoxChart(element, values, `sparkbox-${index}`); }); } /** * Create custom line chart for sparkline elements */ createCustomLineChart(element, data, id) { // Create canvas if it doesn't exist let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'line', data: { labels: data.map((_, i) => i), datasets: [{ data, borderColor: COLORS['red-500'], backgroundColor: 'transparent', borderWidth: 2, pointRadius: 3, pointBackgroundColor: COLORS['red-500'], tension: 0.4 }] }, options: { responsive: false, maintainAspectRatio: false, animation: false, // Disable animations to prevent resize triggers events: [], // Disable all events to prevent resize onResize: null, // Explicitly disable resize callback scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: false } // Disable tooltip to prevent events } } }); this.charts.set(id, chart); } /** * Create custom bar chart for sparkbar elements */ createCustomBarChart(element, data, id) { // Create canvas if it doesn't exist let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: data.map((_, i) => i), datasets: [{ data, backgroundColor: data.map(val => val < 0 ? COLORS['deep-purple-500'] : '#39f'), borderColor: data.map(val => val < 0 ? COLORS['deep-purple-500'] : '#39f'), borderWidth: 1, barPercentage: 0.8 }] }, options: { responsive: false, maintainAspectRatio: false, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: true, callbacks: { label: context => `${context.parsed.y}Β°Celsius` } } } } }); this.charts.set(id, chart); } /** * Setup resize handler for charts */ setupResizeHandler() { // Setup responsive resize for large charts only window.addEventListener('resize', () => { this.debounceResize(); }); // Listen for sidebar toggle events window.addEventListener('sidebar:toggle', () => { this.debounceResize(); }); } /** * Debounced resize handler */ debounceResize() { if (this.debounceTimer) { clearTimeout(this.debounceTimer); } this.debounceTimer = setTimeout(() => { this.redrawLargeChartsOnly(); }, 150); } /** * Redraw only large charts, not sparklines */ redrawLargeChartsOnly() { const largeChartIds = ['line-chart', 'area-chart', 'scatter-chart', 'bar-chart', 'doughnut-chart', 'polar-chart', 'radar-chart', 'mixed-chart', 'bubble-chart']; largeChartIds.forEach(id => { const chart = this.charts.get(id); if (chart && chart.options.responsive) { chart.resize(); } }); } /** * Redraw all charts (used sparingly) */ redrawCharts() { this.charts.forEach(chart => { if (chart.options.responsive) { chart.resize(); } }); } /** * Update chart data */ updateChart(id, newData) { const chart = this.charts.get(id); if (chart) { chart.data.datasets[0].data = newData; chart.update(); } } /** * Create charts for the charts.html page */ createChartsPageCharts() { // Line Chart this.createLargeChart('line-chart', 'line', { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Dataset 1', data: [65, 59, 80, 81, 56, 55, 40], borderColor: 'rgb(75, 192, 192)', backgroundColor: 'rgba(75, 192, 192, 0.2)', tension: 0.4 }] }); // Area Chart this.createLargeChart('area-chart', 'line', { labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'], datasets: [{ label: 'Dataset 1', data: [65, 59, 80, 81, 56, 55, 40], borderColor: 'rgb(54, 162, 235)', backgroundColor: 'rgba(54, 162, 235, 0.4)', fill: true, tension: 0.4 }] }); // Scatter Chart with more data points this.createLargeChart('scatter-chart', 'scatter', { datasets: [{ label: 'Dataset 1', data: [{ x: -15, y: 8 }, { x: -12, y: 12 }, { x: -8, y: 3 }, { x: -5, y: 15 }, { x: -2, y: 7 }, { x: 0, y: 10 }, { x: 3, y: 18 }, { x: 6, y: 5 }, { x: 9, y: 22 }, { x: 12, y: 8 }, { x: 15, y: 14 }, { x: 18, y: 19 }, { x: -10, y: 0 }, { x: 10, y: 5 }, { x: 0.5, y: 5.5 }, { x: 7, y: 12 }, { x: -7, y: 17 }, { x: 4, y: 9 }, { x: 11, y: 16 }, { x: -3, y: 11 }], backgroundColor: 'rgba(255, 99, 132, 0.7)', borderColor: 'rgb(255, 99, 132)', borderWidth: 1 }, { label: 'Dataset 2', data: [{ x: -13, y: 4 }, { x: -9, y: 8 }, { x: -6, y: 13 }, { x: -1, y: 6 }, { x: 2, y: 11 }, { x: 5, y: 15 }, { x: 8, y: 2 }, { x: 13, y: 17 }, { x: 16, y: 9 }, { x: -4, y: 14 }, { x: 1, y: 20 }, { x: 14, y: 4 }], backgroundColor: 'rgba(54, 162, 235, 0.7)', borderColor: 'rgb(54, 162, 235)', borderWidth: 1 }] }); // Bar Chart this.createLargeChart('bar-chart', 'bar', { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: ['rgba(255, 99, 132, 0.6)', 'rgba(54, 162, 235, 0.6)', 'rgba(255, 205, 86, 0.6)', 'rgba(75, 192, 192, 0.6)', 'rgba(153, 102, 255, 0.6)', 'rgba(255, 159, 64, 0.6)'], borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 205, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)'], borderWidth: 1 }] }); // Doughnut Chart this.createLargeChart('doughnut-chart', 'doughnut', { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: 'My First Dataset', data: [300, 50, 100, 75, 120, 60], backgroundColor: ['rgba(255, 99, 132, 0.8)', 'rgba(54, 162, 235, 0.8)', 'rgba(255, 205, 86, 0.8)', 'rgba(75, 192, 192, 0.8)', 'rgba(153, 102, 255, 0.8)', 'rgba(255, 159, 64, 0.8)'], borderColor: ['rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 205, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)'], borderWidth: 2, hoverOffset: 10 }] }); // Polar Area Chart this.createLargeChart('polar-chart', 'polarArea', { labels: ['Red', 'Green', 'Yellow', 'Grey', 'Blue'], datasets: [{ label: 'My First Dataset', data: [11, 16, 7, 3, 14], backgroundColor: ['rgba(255, 99, 132, 0.7)', 'rgba(75, 192, 192, 0.7)', 'rgba(255, 205, 86, 0.7)', 'rgba(201, 203, 207, 0.7)', 'rgba(54, 162, 235, 0.7)'], borderColor: ['rgb(255, 99, 132)', 'rgb(75, 192, 192)', 'rgb(255, 205, 86)', 'rgb(201, 203, 207)', 'rgb(54, 162, 235)'], borderWidth: 2 }] }); // Radar Chart this.createLargeChart('radar-chart', 'radar', { labels: ['Speed', 'Reliability', 'Comfort', 'Safety', 'Efficiency', 'Innovation'], datasets: [{ label: 'Product A', data: [65, 59, 90, 81, 56, 55], fill: true, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(54, 162, 235)', borderWidth: 2, pointBackgroundColor: 'rgb(54, 162, 235)', pointBorderColor: '#fff', pointHoverBackgroundColor: '#fff', pointHoverBorderColor: 'rgb(54, 162, 235)' }, { label: 'Product B', data: [28, 48, 40, 95, 86, 27], fill: true, backgroundColor: 'rgba(255, 99, 132, 0.2)', borderColor: 'rgb(255, 99, 132)', borderWidth: 2, pointBackgroundColor: 'rgb(255, 99, 132)', pointBorderColor: '#fff', pointHoverBackgroundColor: '#fff', pointHoverBorderColor: 'rgb(255, 99, 132)' }] }); // Mixed Chart (Bar + Line) this.createLargeChart('mixed-chart', 'bar', { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], datasets: [{ type: 'bar', label: 'Sales', data: [12, 19, 3, 5, 2, 3], backgroundColor: 'rgba(54, 162, 235, 0.7)', borderColor: 'rgb(54, 162, 235)', borderWidth: 1 }, { type: 'line', label: 'Revenue', data: [18, 25, 8, 15, 12, 18], fill: false, borderColor: 'rgb(255, 99, 132)', backgroundColor: 'rgba(255, 99, 132, 0.2)', borderWidth: 3, tension: 0.4, pointRadius: 5, pointHoverRadius: 7 }] }); // Bubble Chart this.createLargeChart('bubble-chart', 'bubble', { datasets: [{ label: 'First Dataset', data: [{ x: 20, y: 30, r: 15 }, { x: 40, y: 10, r: 10 }, { x: 30, y: 40, r: 20 }, { x: 50, y: 35, r: 12 }, { x: 10, y: 50, r: 8 }, { x: 60, y: 20, r: 18 }, { x: 25, y: 25, r: 14 }], backgroundColor: 'rgba(54, 162, 235, 0.6)', borderColor: 'rgb(54, 162, 235)', borderWidth: 2 }, { label: 'Second Dataset', data: [{ x: 15, y: 45, r: 12 }, { x: 35, y: 15, r: 16 }, { x: 45, y: 25, r: 9 }, { x: 55, y: 45, r: 14 }, { x: 25, y: 35, r: 11 }], backgroundColor: 'rgba(255, 99, 132, 0.6)', borderColor: 'rgb(255, 99, 132)', borderWidth: 2 }] }); } /** * Create large chart for charts page */ createLargeChart(id, type, data) { const canvas = document.getElementById(id); if (!canvas) return; const ctx = canvas.getContext('2d'); // Define chart-specific options const chartOptions = this.getChartOptions(type); const chart = new chart_Chart(ctx, { type, data, options: chartOptions }); this.charts.set(id, chart); } /** * Get chart-specific options based on chart type */ getChartOptions(type) { const baseOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true, position: 'top', labels: { padding: 20, font: { size: 12, weight: '600' } } }, tooltip: { enabled: true, cornerRadius: 8, displayColors: true } } }; // Chart type specific configurations switch (type) { case 'doughnut': case 'pie': return { ...baseOptions, plugins: { ...baseOptions.plugins, legend: { ...baseOptions.plugins.legend, position: 'right' } }, interaction: { intersect: false } }; case 'polarArea': return { ...baseOptions, scales: { r: { pointLabels: { display: true, centerPointLabels: true, font: { size: 10 } }, grid: {} } } }; case 'radar': return { ...baseOptions, scales: { r: { angleLines: { display: true }, grid: {}, pointLabels: { font: { size: 11 } }, ticks: { display: true, font: { size: 10 } } } } }; case 'bubble': return { ...baseOptions, scales: { x: { type: 'linear', position: 'bottom', grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } }, y: { beginAtZero: true, grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } } }, plugins: { ...baseOptions.plugins, tooltip: { ...baseOptions.plugins.tooltip, callbacks: { label(context) { return `${context.dataset.label}: (${context.parsed.x}, ${context.parsed.y}), Size: ${context.parsed._custom}`; } } } } }; case 'scatter': return { ...baseOptions, scales: { x: { type: 'linear', position: 'bottom', grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } }, y: { grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } } } }; default: // For line, bar, area, mixed charts return { ...baseOptions, scales: { x: { grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } }, y: { beginAtZero: true, grid: { borderDash: [5, 5] }, ticks: { font: { size: 11 } } } } }; } } /** * Create tristate chart (for .sparktri elements) */ createTristateChart(element, data, id) { let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: data.map((_, i) => i), datasets: [{ data: data.map(val => Math.abs(val)), backgroundColor: data.map(val => { if (val > 0) return COLORS['light-blue-500']; if (val < 0) return '#f90'; return '#000'; }), borderColor: data.map(val => { if (val > 0) return COLORS['light-blue-500']; if (val < 0) return '#f90'; return '#000'; }), borderWidth: 1, barPercentage: 0.8 }] }, options: { responsive: false, maintainAspectRatio: false, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: true, callbacks: { label: context => `${context.parsed.y}Β°Celsius` } } } } }); this.charts.set(id, chart); } /** * Create discrete chart (for .sparkdisc elements) */ createDiscreteChart(element, data, id) { let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'scatter', data: { datasets: [{ data: data.map((val, index) => ({ x: index, y: val })), backgroundColor: '#9f0', borderColor: '#9f0', pointRadius: 2, showLine: false }] }, options: { responsive: false, maintainAspectRatio: false, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: true, callbacks: { label: context => `${context.parsed.y}Β°Celsius` } } } } }); this.charts.set(id, chart); } /** * Create bullet chart (for .sparkbull elements) */ createBulletChart(element, data, id) { let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); // Simplified bullet chart as horizontal bar const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: [''], datasets: [{ data: [Math.max(...data)], backgroundColor: COLORS['amber-500'], borderColor: COLORS['amber-500'], borderWidth: 1, barPercentage: 0.6 }] }, options: { responsive: false, maintainAspectRatio: false, indexAxis: 'y', scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: true, callbacks: { label: context => `${context.parsed.x}Β°Celsius` } } } } }); this.charts.set(id, chart); } /** * Create box chart (for .sparkbox elements) */ createBoxChart(element, data, id) { let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = 100; canvas.height = 20; canvas.style.width = '100px'; canvas.style.height = '20px'; element.appendChild(canvas); } const ctx = canvas.getContext('2d'); // Box plot simplified as bar chart showing quartiles const sortedData = [...data].sort((a, b) => a - b); const q1 = sortedData[Math.floor(sortedData.length * 0.25)]; const median = sortedData[Math.floor(sortedData.length * 0.5)]; const q3 = sortedData[Math.floor(sortedData.length * 0.75)]; const chart = new chart_Chart(ctx, { type: 'bar', data: { labels: ['Q1', 'Med', 'Q3'], datasets: [{ data: [q1, median, q3], backgroundColor: '#9f0', borderColor: '#9f0', borderWidth: 1, barPercentage: 0.8 }] }, options: { responsive: false, maintainAspectRatio: false, scales: { x: { display: false }, y: { display: false } }, plugins: { legend: { display: false }, tooltip: { enabled: true, callbacks: { label: context => `${context.parsed.y}Β°Celsius` } } } } }); this.charts.set(id, chart); } /** * Create Easy Pie Charts (replaces jQuery Easy Pie Chart) */ createEasyPieCharts() { const easyPieElements = document.querySelectorAll('.easy-pie-chart'); easyPieElements.forEach((element, index) => { const size = parseInt(element.dataset.size) || 80; const percent = parseInt(element.dataset.percent) || 0; const barColor = element.dataset.barColor || '#f44336'; // Create canvas for the pie chart let canvas = element.querySelector('canvas'); if (!canvas) { canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; canvas.style.width = `${size}px`; canvas.style.height = `${size}px`; element.appendChild(canvas); } // Create percentage display const percentDisplay = element.querySelector('span'); if (percentDisplay) { percentDisplay.textContent = `${percent}%`; percentDisplay.style.position = 'absolute'; percentDisplay.style.top = '50%'; percentDisplay.style.left = '50%'; percentDisplay.style.transform = 'translate(-50%, -50%)'; percentDisplay.style.fontSize = '14px'; percentDisplay.style.fontWeight = 'bold'; } // Set element position to relative for absolute positioning of text element.style.position = 'relative'; element.style.display = 'inline-block'; const ctx = canvas.getContext('2d'); const chart = new chart_Chart(ctx, { type: 'doughnut', data: { datasets: [{ data: [percent, 100 - percent], backgroundColor: [barColor, '#f0f0f0'], borderWidth: 0, cutout: '70%' }] }, options: { responsive: false, maintainAspectRatio: false, plugins: { legend: { display: false }, tooltip: { enabled: false } } } }); this.charts.set(`easy-pie-${index}`, chart); }); } /** * Destroy all charts */ destroy() { this.charts.forEach(chart => { chart.destroy(); }); this.charts.clear(); if (this.debounceTimer) { clearTimeout(this.debounceTimer); } } } /* harmony default export */ const components_Chart = (ChartComponent); ;// ../../node_modules/preact/dist/preact.module.js var n,l,u,i,t,r,o,f,e,c={},s=[],a=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function h(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n)}function y(l,u,i){var t,r,o,f={};for(o in u)"key"==o?t=u[o]:"ref"==o?r=u[o]:f[o]=u[o];if(arguments.length>2&&(f.children=arguments.length>3?n.call(arguments,2):i),"function"==typeof l&&null!=l.defaultProps)for(o in l.defaultProps)void 0===f[o]&&(f[o]=l.defaultProps[o]);return p(l,f,t,r,null)}function p(n,i,t,r,o){var f={type:n,props:i,key:t,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++u:o};return null==o&&null!=l.vnode&&l.vnode(f),f}function d(){return{current:null}}function _(n){return n.children}function k(n,l,u,i,t){var r;for(r in u)"children"===r||"key"===r||r in l||g(n,r,null,u[r],i);for(r in l)t&&"function"!=typeof l[r]||"children"===r||"key"===r||"value"===r||"checked"===r||u[r]===l[r]||g(n,r,l[r],u[r],i)}function b(n,l,u){"-"===l[0]?n.setProperty(l,null==u?"":u):n[l]=null==u?"":"number"!=typeof u||a.test(l)?u:u+"px"}function g(n,l,u,i,t){var r;n:if("style"===l)if("string"==typeof u)n.style.cssText=u;else{if("string"==typeof i&&(n.style.cssText=i=""),i)for(l in i)u&&l in u||b(n.style,l,"");if(u)for(l in u)i&&u[l]===i[l]||b(n.style,l,u[l])}else if("o"===l[0]&&"n"===l[1])r=l!==(l=l.replace(/Capture$/,"")),l=l.toLowerCase()in n?l.toLowerCase().slice(2):l.slice(2),n.l||(n.l={}),n.l[l+r]=u,u?i||n.addEventListener(l,r?w:m,r):n.removeEventListener(l,r?w:m,r);else if("dangerouslySetInnerHTML"!==l){if(t)l=l.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if("width"!==l&&"height"!==l&&"href"!==l&&"list"!==l&&"form"!==l&&"tabIndex"!==l&&"download"!==l&&l in n)try{n[l]=null==u?"":u;break n}catch(n){}"function"==typeof u||(null==u||!1===u&&-1==l.indexOf("-")?n.removeAttribute(l):n.setAttribute(l,u))}}function m(n){t=!0;try{return this.l[n.type+!1](l.event?l.event(n):n)}finally{t=!1}}function w(n){t=!0;try{return this.l[n.type+!0](l.event?l.event(n):n)}finally{t=!1}}function x(n,l){this.props=n,this.context=l}function A(n,l){if(null==l)return n.__?A(n.__,n.__.__k.indexOf(n)+1):null;for(var u;ll&&r.sort(function(n,l){return n.__v.__b-l.__v.__b}));$.__r=0}function H(n,l,u,i,t,r,o,f,e,a){var h,v,y,d,k,b,g,m=i&&i.__k||s,w=m.length;for(u.__k=[],h=0;h0?p(d.type,d.props,d.key,d.ref?d.ref:null,d.__v):d)){if(d.__=u,d.__b=u.__b+1,null===(y=m[h])||y&&d.key==y.key&&d.type===y.type)m[h]=void 0;else for(v=0;v=0;l--)if((u=n.__k[l])&&(i=L(u)))return i;return null}function M(n,u,i,t,r,o,f,e,c){var s,a,v,y,p,d,k,b,g,m,w,A,P,C,T,$=u.type;if(void 0!==u.constructor)return null;null!=i.__h&&(c=i.__h,e=u.__e=i.__e,u.__h=null,o=[e]),(s=l.__b)&&s(u);try{n:if("function"==typeof $){if(b=u.props,g=(s=$.contextType)&&t[s.__c],m=s?g?g.props.value:s.__:t,i.__c?k=(a=u.__c=i.__c).__=a.__E:("prototype"in $&&$.prototype.render?u.__c=a=new $(b,m):(u.__c=a=new x(b,m),a.constructor=$,a.render=B),g&&g.sub(a),a.props=b,a.state||(a.state={}),a.context=m,a.__n=t,v=a.__d=!0,a.__h=[],a._sb=[]),null==a.__s&&(a.__s=a.state),null!=$.getDerivedStateFromProps&&(a.__s==a.state&&(a.__s=h({},a.__s)),h(a.__s,$.getDerivedStateFromProps(b,a.__s))),y=a.props,p=a.state,a.__v=u,v)null==$.getDerivedStateFromProps&&null!=a.componentWillMount&&a.componentWillMount(),null!=a.componentDidMount&&a.__h.push(a.componentDidMount);else{if(null==$.getDerivedStateFromProps&&b!==y&&null!=a.componentWillReceiveProps&&a.componentWillReceiveProps(b,m),!a.__e&&null!=a.shouldComponentUpdate&&!1===a.shouldComponentUpdate(b,a.__s,m)||u.__v===i.__v){for(u.__v!==i.__v&&(a.props=b,a.state=a.__s,a.__d=!1),u.__e=i.__e,u.__k=i.__k,u.__k.forEach(function(n){n&&(n.__=u)}),w=0;w2&&(f.children=arguments.length>3?n.call(arguments,2):i),p(l.type,f,t||l.key,r||l.ref,null)}function G(n,l){var u={__c:l="__cC"+e++,__:n,Consumer:function(n,l){return n.children(l)},Provider:function(n){var u,i;return this.getChildContext||(u=[],(i={})[l]=this,this.getChildContext=function(){return i},this.shouldComponentUpdate=function(n){this.props.value!==n.value&&u.some(function(n){n.__e=!0,T(n)})},this.sub=function(n){u.push(n);var l=n.componentWillUnmount;n.componentWillUnmount=function(){u.splice(u.indexOf(n),1),l&&l.call(n)}}),n.children}};return u.Provider.__=u.Consumer.contextType=u}n=s.slice,l={__e:function(n,l,u,i){for(var t,r,o;l=l.__;)if((t=l.__c)&&!t.__)try{if((r=t.constructor)&&null!=r.getDerivedStateFromError&&(t.setState(r.getDerivedStateFromError(n)),o=t.__d),null!=t.componentDidCatch&&(t.componentDidCatch(n,i||{}),o=t.__d),o)return t.__E=t}catch(l){n=l}throw n}},u=0,i=function(n){return null!=n&&void 0===n.constructor},t=!1,x.prototype.setState=function(n,l){var u;u=null!=this.__s&&this.__s!==this.state?this.__s:this.__s=h({},this.state),"function"==typeof n&&(n=n(h({},u),this.props)),n&&h(u,n),null!=n&&this.__v&&(l&&this._sb.push(l),T(this))},x.prototype.forceUpdate=function(n){this.__v&&(this.__e=!0,n&&this.__h.push(n),T(this))},x.prototype.render=_,r=[],f="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,$.__r=0,e=0; //# sourceMappingURL=preact.module.js.map ;// ../../node_modules/preact/hooks/dist/hooks.module.js var hooks_module_t,hooks_module_r,hooks_module_u,hooks_module_i,hooks_module_o=0,hooks_module_f=[],hooks_module_c=[],hooks_module_e=l.__b,hooks_module_a=l.__r,hooks_module_v=l.diffed,hooks_module_l=l.__c,hooks_module_m=l.unmount;function hooks_module_d(t,u){l.__h&&l.__h(hooks_module_r,t,hooks_module_o||u),hooks_module_o=0;var i=hooks_module_r.__H||(hooks_module_r.__H={__:[],__h:[]});return t>=i.__.length&&i.__.push({__V:hooks_module_c}),i.__[t]}function hooks_module_p(n){return hooks_module_o=1,hooks_module_y(hooks_module_B,n)}function hooks_module_y(n,u,i){var o=hooks_module_d(hooks_module_t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):hooks_module_B(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}))}],o.__c=hooks_module_r,!hooks_module_r.u)){hooks_module_r.u=!0;var f=hooks_module_r.shouldComponentUpdate;hooks_module_r.shouldComponentUpdate=function(n,t,r){if(!o.__c.__H)return!0;var u=o.__c.__H.__.filter(function(n){return n.__c});if(u.every(function(n){return!n.__N}))return!f||f.call(this,n,t,r);var i=!1;return u.forEach(function(n){if(n.__N){var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0)}}),!(!i&&o.__c.props===n)&&(!f||f.call(this,n,t,r))}}return o.__N||o.__}function hooks_module_h(u,i){var o=hooks_module_d(hooks_module_t++,3);!l.__s&&hooks_module_z(o.__H,i)&&(o.__=u,o.i=i,hooks_module_r.__H.__h.push(o))}function hooks_module_s(u,i){var o=hooks_module_d(hooks_module_t++,4);!l.__s&&hooks_module_z(o.__H,i)&&(o.__=u,o.i=i,hooks_module_r.__h.push(o))}function hooks_module_(n){return hooks_module_o=5,hooks_module_F(function(){return{current:n}},[])}function hooks_module_A(n,t,r){hooks_module_o=6,hooks_module_s(function(){return"function"==typeof n?(n(t()),function(){return n(null)}):n?(n.current=t(),function(){return n.current=null}):void 0},null==r?r:r.concat(n))}function hooks_module_F(n,r){var u=hooks_module_d(hooks_module_t++,7);return hooks_module_z(u.__H,r)?(u.__V=n(),u.i=r,u.__h=n,u.__V):u.__}function hooks_module_T(n,t){return hooks_module_o=8,hooks_module_F(function(){return n},t)}function hooks_module_q(n){var u=hooks_module_r.context[n.__c],i=hooks_module_d(hooks_module_t++,9);return i.c=n,u?(null==i.__&&(i.__=!0,u.sub(hooks_module_r)),u.props.value):n.__}function hooks_module_x(t,r){l.useDebugValue&&l.useDebugValue(r?r(t):t)}function hooks_module_P(n){var u=hooks_module_d(hooks_module_t++,10),i=hooks_module_p();return u.__=n,hooks_module_r.componentDidCatch||(hooks_module_r.componentDidCatch=function(n,t){u.__&&u.__(n,t),i[1](n)}),[i[0],function(){i[1](void 0)}]}function V(){var n=hooks_module_d(hooks_module_t++,11);if(!n.__){for(var u=hooks_module_r.__v;null!==u&&!u.__m&&null!==u.__;)u=u.__;var i=u.__m||(u.__m=[0,0]);n.__="P"+i[0]+"-"+i[1]++}return n.__}function hooks_module_b(){for(var t;t=hooks_module_f.shift();)if(t.__P&&t.__H)try{t.__H.__h.forEach(hooks_module_k),t.__H.__h.forEach(hooks_module_w),t.__H.__h=[]}catch(r){t.__H.__h=[],l.__e(r,t.__v)}}l.__b=function(n){hooks_module_r=null,hooks_module_e&&hooks_module_e(n)},l.__r=function(n){hooks_module_a&&hooks_module_a(n),hooks_module_t=0;var i=(hooks_module_r=n.__c).__H;i&&(hooks_module_u===hooks_module_r?(i.__h=[],hooks_module_r.__h=[],i.__.forEach(function(n){n.__N&&(n.__=n.__N),n.__V=hooks_module_c,n.__N=n.i=void 0})):(i.__h.forEach(hooks_module_k),i.__h.forEach(hooks_module_w),i.__h=[])),hooks_module_u=hooks_module_r},l.diffed=function(t){hooks_module_v&&hooks_module_v(t);var o=t.__c;o&&o.__H&&(o.__H.__h.length&&(1!==hooks_module_f.push(o)&&hooks_module_i===l.requestAnimationFrame||((hooks_module_i=l.requestAnimationFrame)||hooks_module_j)(hooks_module_b)),o.__H.__.forEach(function(n){n.i&&(n.__H=n.i),n.__V!==hooks_module_c&&(n.__=n.__V),n.i=void 0,n.__V=hooks_module_c})),hooks_module_u=hooks_module_r=null},l.__c=function(t,r){r.some(function(t){try{t.__h.forEach(hooks_module_k),t.__h=t.__h.filter(function(n){return!n.__||hooks_module_w(n)})}catch(u){r.some(function(n){n.__h&&(n.__h=[])}),r=[],l.__e(u,t.__v)}}),hooks_module_l&&hooks_module_l(t,r)},l.unmount=function(t){hooks_module_m&&hooks_module_m(t);var r,u=t.__c;u&&u.__H&&(u.__H.__.forEach(function(n){try{hooks_module_k(n)}catch(n){r=n}}),u.__H=void 0,r&&l.__e(r,u.__v))};var hooks_module_g="function"==typeof requestAnimationFrame;function hooks_module_j(n){var t,r=function(){clearTimeout(u),hooks_module_g&&cancelAnimationFrame(t),setTimeout(n)},u=setTimeout(r,100);hooks_module_g&&(t=requestAnimationFrame(r))}function hooks_module_k(n){var t=hooks_module_r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),hooks_module_r=t}function hooks_module_w(n){var t=hooks_module_r;n.__c=n.__(),hooks_module_r=t}function hooks_module_z(n,t){return!n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function hooks_module_B(n,t){return"function"==typeof t?t(n):t} //# sourceMappingURL=hooks.module.js.map ;// ../../node_modules/preact/compat/dist/compat.module.js function compat_module_g(n,t){for(var e in t)n[e]=t[e];return n}function compat_module_C(n,t){for(var e in n)if("__source"!==e&&!(e in t))return!0;for(var r in t)if("__source"!==r&&n[r]!==t[r])return!0;return!1}function compat_module_E(n,t){return n===t&&(0!==n||1/n==1/t)||n!=n&&t!=t}function compat_module_w(n){this.props=n}function R(n,e){function r(n){var t=this.props.ref,r=t==n.ref;return!r&&t&&(t.call?t(null):t.current=null),e?!e(this.props,n)||!r:compat_module_C(this.props,n)}function u(e){return this.shouldComponentUpdate=r,y(n,e)}return u.displayName="Memo("+(n.displayName||n.name)+")",u.prototype.isReactComponent=!0,u.__f=!0,u}(compat_module_w.prototype=new x).isPureReactComponent=!0,compat_module_w.prototype.shouldComponentUpdate=function(n,t){return compat_module_C(this.props,n)||compat_module_C(this.state,t)};var compat_module_x=l.__b;l.__b=function(n){n.type&&n.type.__f&&n.ref&&(n.props.ref=n.ref,n.ref=null),compat_module_x&&compat_module_x(n)};var compat_module_N="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.forward_ref")||3911;function compat_module_k(n){function t(t){var e=compat_module_g({},t);return delete e.ref,n(e,t.ref||null)}return t.$$typeof=compat_module_N,t.render=t,t.prototype.isReactComponent=t.__f=!0,t.displayName="ForwardRef("+(n.displayName||n.name)+")",t}var compat_module_A=function(n,t){return null==n?null:j(j(n).map(t))},compat_module_O={map:compat_module_A,forEach:compat_module_A,count:function(n){return n?j(n).length:0},only:function(n){var t=j(n);if(1!==t.length)throw"Children.only";return t[0]},toArray:j},compat_module_T=l.__e;l.__e=function(n,t,e,r){if(n.then)for(var u,o=t;o=o.__;)if((u=o.__c)&&u.__c)return null==t.__e&&(t.__e=e.__e,t.__k=e.__k),u.__c(n,t);compat_module_T(n,t,e,r)};var compat_module_I=l.unmount;function compat_module_L(n,t,e){return n&&(n.__c&&n.__c.__H&&(n.__c.__H.__.forEach(function(n){"function"==typeof n.__c&&n.__c()}),n.__c.__H=null),null!=(n=compat_module_g({},n)).__c&&(n.__c.__P===e&&(n.__c.__P=t),n.__c=null),n.__k=n.__k&&n.__k.map(function(n){return compat_module_L(n,t,e)})),n}function U(n,t,e){return n&&(n.__v=null,n.__k=n.__k&&n.__k.map(function(n){return U(n,t,e)}),n.__c&&n.__c.__P===t&&(n.__e&&e.insertBefore(n.__e,n.__d),n.__c.__e=!0,n.__c.__P=e)),n}function compat_module_D(){this.__u=0,this.t=null,this.__b=null}function compat_module_F(n){var t=n.__.__c;return t&&t.__a&&t.__a(n)}function compat_module_M(n){var e,r,u;function o(o){if(e||(e=n()).then(function(n){r=n.default||n},function(n){u=n}),u)throw u;if(!r)throw e;return y(r,o)}return o.displayName="Lazy",o.__f=!0,o}function compat_module_V(){this.u=null,this.o=null}l.unmount=function(n){var t=n.__c;t&&t.__R&&t.__R(),t&&!0===n.__h&&(n.type=null),compat_module_I&&compat_module_I(n)},(compat_module_D.prototype=new x).__c=function(n,t){var e=t.__c,r=this;null==r.t&&(r.t=[]),r.t.push(e);var u=compat_module_F(r.__v),o=!1,i=function(){o||(o=!0,e.__R=null,u?u(l):l())};e.__R=i;var l=function(){if(!--r.__u){if(r.state.__a){var n=r.state.__a;r.__v.__k[0]=U(n,n.__c.__P,n.__c.__O)}var t;for(r.setState({__a:r.__b=null});t=r.t.pop();)t.forceUpdate()}},c=!0===t.__h;r.__u++||c||r.setState({__a:r.__b=r.__v.__k[0]}),n.then(i,i)},compat_module_D.prototype.componentWillUnmount=function(){this.t=[]},compat_module_D.prototype.render=function(n,e){if(this.__b){if(this.__v.__k){var r=document.createElement("div"),o=this.__v.__k[0].__c;this.__v.__k[0]=compat_module_L(this.__b,r,o.__O=o.__P)}this.__b=null}var i=e.__a&&y(_,null,n.fallback);return i&&(i.__h=null),[y(_,null,e.__a?null:n.children),i]};var W=function(n,t,e){if(++e[1]===e[0]&&n.o.delete(t),n.props.revealOrder&&("t"!==n.props.revealOrder[0]||!n.o.size))for(e=n.u;e;){for(;e.length>3;)e.pop()();if(e[1]>>1,1),e.i.removeChild(n)}}),D(y(compat_module_P,{context:e.context},n.__v),e.l)):e.l&&e.componentWillUnmount()}function compat_module_j(n,e){var r=y(compat_module_$,{__v:n,i:e});return r.containerInfo=e,r}(compat_module_V.prototype=new x).__a=function(n){var t=this,e=compat_module_F(t.__v),r=t.o.get(n);return r[0]++,function(u){var o=function(){t.props.revealOrder?(r.push(u),W(t,n,r)):u()};e?e(o):o()}},compat_module_V.prototype.render=function(n){this.u=null,this.o=new Map;var t=j(n.children);n.revealOrder&&"b"===n.revealOrder[0]&&t.reverse();for(var e=t.length;e--;)this.o.set(t[e],this.u=[1,0,this.u]);return n.children},compat_module_V.prototype.componentDidUpdate=compat_module_V.prototype.componentDidMount=function(){var n=this;this.o.forEach(function(t,e){W(n,e,t)})};var compat_module_z="undefined"!=typeof Symbol&&Symbol.for&&Symbol.for("react.element")||60103,compat_module_B=/^(?:accent|alignment|arabic|baseline|cap|clip(?!PathU)|color|dominant|fill|flood|font|glyph(?!R)|horiz|image|letter|lighting|marker(?!H|W|U)|overline|paint|pointer|shape|stop|strikethrough|stroke|text(?!L)|transform|underline|unicode|units|v|vector|vert|word|writing|x(?!C))[A-Z]/,compat_module_H="undefined"!=typeof document,Z=function(n){return("undefined"!=typeof Symbol&&"symbol"==typeof Symbol()?/fil|che|rad/i:/fil|che|ra/i).test(n)};function Y(n,t,e){return null==t.__k&&(t.textContent=""),D(n,t),"function"==typeof e&&e(),n?n.__c:null}function compat_module_q(n,t,e){return E(n,t),"function"==typeof e&&e(),n?n.__c:null}x.prototype.isReactComponent={},["componentWillMount","componentWillReceiveProps","componentWillUpdate"].forEach(function(t){Object.defineProperty(x.prototype,t,{configurable:!0,get:function(){return this["UNSAFE_"+t]},set:function(n){Object.defineProperty(this,t,{configurable:!0,writable:!0,value:n})}})});var compat_module_G=l.event;function J(){}function K(){return this.cancelBubble}function Q(){return this.defaultPrevented}l.event=function(n){return compat_module_G&&(n=compat_module_G(n)),n.persist=J,n.isPropagationStopped=K,n.isDefaultPrevented=Q,n.nativeEvent=n};var X,nn={configurable:!0,get:function(){return this.class}},tn=l.vnode;l.vnode=function(n){var t=n.type,e=n.props,u=e;if("string"==typeof t){var o=-1===t.indexOf("-");for(var i in u={},e){var l=e[i];compat_module_H&&"children"===i&&"noscript"===t||"value"===i&&"defaultValue"in e&&null==l||("defaultValue"===i&&"value"in e&&null==e.value?i="value":"download"===i&&!0===l?l="":/ondoubleclick/i.test(i)?i="ondblclick":/^onchange(textarea|input)/i.test(i+t)&&!Z(e.type)?i="oninput":/^onfocus$/i.test(i)?i="onfocusin":/^onblur$/i.test(i)?i="onfocusout":/^on(Ani|Tra|Tou|BeforeInp|Compo)/.test(i)?i=i.toLowerCase():o&&compat_module_B.test(i)?i=i.replace(/[A-Z0-9]/g,"-$&").toLowerCase():null===l&&(l=void 0),/^oninput$/i.test(i)&&(i=i.toLowerCase(),u[i]&&(i="oninputCapture")),u[i]=l)}"select"==t&&u.multiple&&Array.isArray(u.value)&&(u.value=j(e.children).forEach(function(n){n.props.selected=-1!=u.value.indexOf(n.props.value)})),"select"==t&&null!=u.defaultValue&&(u.value=j(e.children).forEach(function(n){n.props.selected=u.multiple?-1!=u.defaultValue.indexOf(n.props.value):u.defaultValue==n.props.value})),n.props=u,e.class!=e.className&&(nn.enumerable="className"in e,null!=e.className&&(u.class=e.className),Object.defineProperty(u,"className",nn))}n.$$typeof=compat_module_z,tn&&tn(n)};var en=l.__r;l.__r=function(n){en&&en(n),X=n.__c};var rn={ReactCurrentDispatcher:{current:{readContext:function(n){return X.__n[n.__c].props.value}}}},un="17.0.2";function on(n){return y.bind(null,n)}function ln(n){return!!n&&n.$$typeof===compat_module_z}function cn(n){return ln(n)?F.apply(null,arguments):n}function fn(n){return!!n.__k&&(D(null,n),!0)}function an(n){return n&&(n.base||1===n.nodeType&&n)||null}var sn=function(n,t){return n(t)},hn=function(n,t){return n(t)},vn=_;function dn(n){n()}function pn(n){return n}function mn(){return[!1,dn]}var yn=hooks_module_s;function _n(n,t){var e=t(),r=hooks_module_p({h:{__:e,v:t}}),u=r[0].h,o=r[1];return hooks_module_s(function(){u.__=e,u.v=t,compat_module_E(u.__,t())||o({h:u})},[n,e,t]),hooks_module_h(function(){return compat_module_E(u.__,u.v())||o({h:u}),n(function(){compat_module_E(u.__,u.v())||o({h:u})})},[n]),e}var bn={useState:hooks_module_p,useId:V,useReducer:hooks_module_y,useEffect:hooks_module_h,useLayoutEffect:hooks_module_s,useInsertionEffect:yn,useTransition:mn,useDeferredValue:pn,useSyncExternalStore:_n,startTransition:dn,useRef:hooks_module_,useImperativeHandle:hooks_module_A,useMemo:hooks_module_F,useCallback:hooks_module_T,useContext:hooks_module_q,useDebugValue:hooks_module_x,version:"17.0.2",Children:compat_module_O,render:Y,hydrate:compat_module_q,unmountComponentAtNode:fn,createPortal:compat_module_j,createElement:y,createContext:G,createFactory:on,cloneElement:cn,createRef:d,Fragment:_,isValidElement:ln,findDOMNode:an,Component:x,PureComponent:compat_module_w,memo:R,forwardRef:compat_module_k,flushSync:hn,unstable_batchedUpdates:sn,StrictMode:vn,Suspense:compat_module_D,SuspenseList:compat_module_V,lazy:compat_module_M,__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:rn}; //# sourceMappingURL=compat.module.js.map ;// ../../node_modules/@fullcalendar/core/internal-common.js const styleTexts = []; const styleEls = new Map(); function injectStyles(styleText) { styleTexts.push(styleText); styleEls.forEach((styleEl) => { appendStylesTo(styleEl, styleText); }); } function ensureElHasStyles(el) { if (el.isConnected && // sometimes true if SSR system simulates DOM el.getRootNode // sometimes undefined if SSR system simulates DOM ) { registerStylesRoot(el.getRootNode()); } } function registerStylesRoot(rootNode) { let styleEl = styleEls.get(rootNode); if (!styleEl || !styleEl.isConnected) { styleEl = rootNode.querySelector('style[data-fullcalendar]'); if (!styleEl) { styleEl = document.createElement('style'); styleEl.setAttribute('data-fullcalendar', ''); const nonce = getNonceValue(); if (nonce) { styleEl.nonce = nonce; } const parentEl = rootNode === document ? document.head : rootNode; const insertBefore = rootNode === document ? parentEl.querySelector('script,link[rel=stylesheet],link[as=style],style') : parentEl.firstChild; parentEl.insertBefore(styleEl, insertBefore); } styleEls.set(rootNode, styleEl); hydrateStylesRoot(styleEl); } } function hydrateStylesRoot(styleEl) { for (const styleText of styleTexts) { appendStylesTo(styleEl, styleText); } } function appendStylesTo(styleEl, styleText) { const { sheet } = styleEl; const ruleCnt = sheet.cssRules.length; styleText.split('}').forEach((styleStr, i) => { styleStr = styleStr.trim(); if (styleStr) { sheet.insertRule(styleStr + '}', ruleCnt + i); } }); } // nonce // ------------------------------------------------------------------------------------------------- let queriedNonceValue; function getNonceValue() { if (queriedNonceValue === undefined) { queriedNonceValue = queryNonceValue(); } return queriedNonceValue; } /* TODO: discourage meta tag and instead put nonce attribute on placeholder