chartkick 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5791c4748533e3fa0eaa1b2e1c6fbbffc726f8ab663f4590edfd0b9555894909
4
- data.tar.gz: fb3e99507dcdf7934cf1bfc25052ba14f8c109af05379a45b47fda728c2eb3b7
3
+ metadata.gz: 7f0229f1e93dc1d2b672317f7147394f8a17e4fb42bb1ab2c979a1ac5b67a0e7
4
+ data.tar.gz: c8229ee28b9bbcfbc61c971a39e67415295cdd8043b25cfac1fa5ef992981cf9
5
5
  SHA512:
6
- metadata.gz: e417d6dcc2ae547cd63c7ded309329b112cfc9b6195c29c08d6192e3dbba4c630695815cc65f3d23e3b3833bdafc46bb04809b708362de8d98ee5f04568fbca3
7
- data.tar.gz: 730f4f49ced271c3f7e15e3a3e57d5f3f81c08d5a2bd0de3792ec6e2747c433bd37b185bd38db2dfaede7aa0c5ab0ad63255d30a675379e7035182df898bf836
6
+ metadata.gz: dce86c2e3bcf36e4c1c104e1446076cc7086563cefb12968355f236bece5460034b4e076ed98fc64f9453f6abc10b6c38287caeaef84ba0bd00566f3de0b6fe1
7
+ data.tar.gz: a2774bde5c45e347d532720b14c9ee4ed04136d379796355339e6ba5b56194a98916bee56308a3e16252afdea50110a843e4e63b783db9712d20cfaf502f8113
@@ -1,3 +1,7 @@
1
+ ## 3.4.2 (2020-10-20)
2
+
3
+ - Updated Chart.js to 2.9.4
4
+
1
5
  ## 3.4.1 (2020-10-06)
2
6
 
3
7
  - Relaxed validation for `width` and `height` options
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2019 Andrew Kane
1
+ Copyright (c) 2013-2020 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -505,6 +505,26 @@ Download [chartkick.js](https://raw.githubusercontent.com/ankane/chartkick/maste
505
505
  <script src="chartkick.js"></script>
506
506
  ```
507
507
 
508
+ Then include the charting library.
509
+
510
+ Chart.js - download [Chart.bundle.js](https://unpkg.com/chart.js@2/dist/Chart.bundle.js)
511
+
512
+ ```html
513
+ <script src="Chart.bundle.js"></script>
514
+ ```
515
+
516
+ Google Charts
517
+
518
+ ```html
519
+ <script src="https://www.gstatic.com/charts/loader.js"></script>
520
+ ```
521
+
522
+ Highcharts - download [highcharts.js](https://code.highcharts.com/highcharts.js)
523
+
524
+ ```html
525
+ <script src="highcharts.js"></script>
526
+ ```
527
+
508
528
  ### Multiple Libraries
509
529
 
510
530
  If more than one charting library is loaded, choose between them with:
@@ -1,3 +1,3 @@
1
1
  module Chartkick
2
- VERSION = "3.4.1"
2
+ VERSION = "3.4.2"
3
3
  end
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Chart.js Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013-2019 Andrew Kane
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ Copyright (c) JS Foundation and other contributors
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * Chart.js v2.9.3
2
+ * Chart.js v2.9.4
3
3
  * https://www.chartjs.org
4
- * (c) 2019 Chart.js Contributors
4
+ * (c) 2020 Chart.js Contributors
5
5
  * Released under the MIT License
6
6
  */
7
7
  (function (global, factory) {
@@ -2107,18647 +2107,18668 @@ if (typeof window !== 'undefined') {
2107
2107
 
2108
2108
  var chartjsColor = Color;
2109
2109
 
2110
- /**
2111
- * @namespace Chart.helpers
2112
- */
2113
- var helpers = {
2114
- /**
2115
- * An empty function that can be used, for example, for optional callback.
2116
- */
2117
- noop: function() {},
2118
-
2119
- /**
2120
- * Returns a unique id, sequentially generated from a global variable.
2121
- * @returns {number}
2122
- * @function
2123
- */
2124
- uid: (function() {
2125
- var id = 0;
2126
- return function() {
2127
- return id++;
2128
- };
2129
- }()),
2110
+ function isValidKey(key) {
2111
+ return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
2112
+ }
2113
+
2114
+ /**
2115
+ * @namespace Chart.helpers
2116
+ */
2117
+ var helpers = {
2118
+ /**
2119
+ * An empty function that can be used, for example, for optional callback.
2120
+ */
2121
+ noop: function() {},
2122
+
2123
+ /**
2124
+ * Returns a unique id, sequentially generated from a global variable.
2125
+ * @returns {number}
2126
+ * @function
2127
+ */
2128
+ uid: (function() {
2129
+ var id = 0;
2130
+ return function() {
2131
+ return id++;
2132
+ };
2133
+ }()),
2134
+
2135
+ /**
2136
+ * Returns true if `value` is neither null nor undefined, else returns false.
2137
+ * @param {*} value - The value to test.
2138
+ * @returns {boolean}
2139
+ * @since 2.7.0
2140
+ */
2141
+ isNullOrUndef: function(value) {
2142
+ return value === null || typeof value === 'undefined';
2143
+ },
2144
+
2145
+ /**
2146
+ * Returns true if `value` is an array (including typed arrays), else returns false.
2147
+ * @param {*} value - The value to test.
2148
+ * @returns {boolean}
2149
+ * @function
2150
+ */
2151
+ isArray: function(value) {
2152
+ if (Array.isArray && Array.isArray(value)) {
2153
+ return true;
2154
+ }
2155
+ var type = Object.prototype.toString.call(value);
2156
+ if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
2157
+ return true;
2158
+ }
2159
+ return false;
2160
+ },
2161
+
2162
+ /**
2163
+ * Returns true if `value` is an object (excluding null), else returns false.
2164
+ * @param {*} value - The value to test.
2165
+ * @returns {boolean}
2166
+ * @since 2.7.0
2167
+ */
2168
+ isObject: function(value) {
2169
+ return value !== null && Object.prototype.toString.call(value) === '[object Object]';
2170
+ },
2171
+
2172
+ /**
2173
+ * Returns true if `value` is a finite number, else returns false
2174
+ * @param {*} value - The value to test.
2175
+ * @returns {boolean}
2176
+ */
2177
+ isFinite: function(value) {
2178
+ return (typeof value === 'number' || value instanceof Number) && isFinite(value);
2179
+ },
2180
+
2181
+ /**
2182
+ * Returns `value` if defined, else returns `defaultValue`.
2183
+ * @param {*} value - The value to return if defined.
2184
+ * @param {*} defaultValue - The value to return if `value` is undefined.
2185
+ * @returns {*}
2186
+ */
2187
+ valueOrDefault: function(value, defaultValue) {
2188
+ return typeof value === 'undefined' ? defaultValue : value;
2189
+ },
2190
+
2191
+ /**
2192
+ * Returns value at the given `index` in array if defined, else returns `defaultValue`.
2193
+ * @param {Array} value - The array to lookup for value at `index`.
2194
+ * @param {number} index - The index in `value` to lookup for value.
2195
+ * @param {*} defaultValue - The value to return if `value[index]` is undefined.
2196
+ * @returns {*}
2197
+ */
2198
+ valueAtIndexOrDefault: function(value, index, defaultValue) {
2199
+ return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
2200
+ },
2201
+
2202
+ /**
2203
+ * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
2204
+ * value returned by `fn`. If `fn` is not a function, this method returns undefined.
2205
+ * @param {function} fn - The function to call.
2206
+ * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
2207
+ * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
2208
+ * @returns {*}
2209
+ */
2210
+ callback: function(fn, args, thisArg) {
2211
+ if (fn && typeof fn.call === 'function') {
2212
+ return fn.apply(thisArg, args);
2213
+ }
2214
+ },
2215
+
2216
+ /**
2217
+ * Note(SB) for performance sake, this method should only be used when loopable type
2218
+ * is unknown or in none intensive code (not called often and small loopable). Else
2219
+ * it's preferable to use a regular for() loop and save extra function calls.
2220
+ * @param {object|Array} loopable - The object or array to be iterated.
2221
+ * @param {function} fn - The function to call for each item.
2222
+ * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
2223
+ * @param {boolean} [reverse] - If true, iterates backward on the loopable.
2224
+ */
2225
+ each: function(loopable, fn, thisArg, reverse) {
2226
+ var i, len, keys;
2227
+ if (helpers.isArray(loopable)) {
2228
+ len = loopable.length;
2229
+ if (reverse) {
2230
+ for (i = len - 1; i >= 0; i--) {
2231
+ fn.call(thisArg, loopable[i], i);
2232
+ }
2233
+ } else {
2234
+ for (i = 0; i < len; i++) {
2235
+ fn.call(thisArg, loopable[i], i);
2236
+ }
2237
+ }
2238
+ } else if (helpers.isObject(loopable)) {
2239
+ keys = Object.keys(loopable);
2240
+ len = keys.length;
2241
+ for (i = 0; i < len; i++) {
2242
+ fn.call(thisArg, loopable[keys[i]], keys[i]);
2243
+ }
2244
+ }
2245
+ },
2246
+
2247
+ /**
2248
+ * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
2249
+ * @see https://stackoverflow.com/a/14853974
2250
+ * @param {Array} a0 - The array to compare
2251
+ * @param {Array} a1 - The array to compare
2252
+ * @returns {boolean}
2253
+ */
2254
+ arrayEquals: function(a0, a1) {
2255
+ var i, ilen, v0, v1;
2256
+
2257
+ if (!a0 || !a1 || a0.length !== a1.length) {
2258
+ return false;
2259
+ }
2260
+
2261
+ for (i = 0, ilen = a0.length; i < ilen; ++i) {
2262
+ v0 = a0[i];
2263
+ v1 = a1[i];
2264
+
2265
+ if (v0 instanceof Array && v1 instanceof Array) {
2266
+ if (!helpers.arrayEquals(v0, v1)) {
2267
+ return false;
2268
+ }
2269
+ } else if (v0 !== v1) {
2270
+ // NOTE: two different object instances will never be equal: {x:20} != {x:20}
2271
+ return false;
2272
+ }
2273
+ }
2274
+
2275
+ return true;
2276
+ },
2277
+
2278
+ /**
2279
+ * Returns a deep copy of `source` without keeping references on objects and arrays.
2280
+ * @param {*} source - The value to clone.
2281
+ * @returns {*}
2282
+ */
2283
+ clone: function(source) {
2284
+ if (helpers.isArray(source)) {
2285
+ return source.map(helpers.clone);
2286
+ }
2287
+
2288
+ if (helpers.isObject(source)) {
2289
+ var target = Object.create(source);
2290
+ var keys = Object.keys(source);
2291
+ var klen = keys.length;
2292
+ var k = 0;
2293
+
2294
+ for (; k < klen; ++k) {
2295
+ target[keys[k]] = helpers.clone(source[keys[k]]);
2296
+ }
2297
+
2298
+ return target;
2299
+ }
2300
+
2301
+ return source;
2302
+ },
2303
+
2304
+ /**
2305
+ * The default merger when Chart.helpers.merge is called without merger option.
2306
+ * Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.
2307
+ * @private
2308
+ */
2309
+ _merger: function(key, target, source, options) {
2310
+ if (!isValidKey(key)) {
2311
+ // We want to ensure we do not copy prototypes over
2312
+ // as this can pollute global namespaces
2313
+ return;
2314
+ }
2315
+
2316
+ var tval = target[key];
2317
+ var sval = source[key];
2318
+
2319
+ if (helpers.isObject(tval) && helpers.isObject(sval)) {
2320
+ helpers.merge(tval, sval, options);
2321
+ } else {
2322
+ target[key] = helpers.clone(sval);
2323
+ }
2324
+ },
2325
+
2326
+ /**
2327
+ * Merges source[key] in target[key] only if target[key] is undefined.
2328
+ * @private
2329
+ */
2330
+ _mergerIf: function(key, target, source) {
2331
+ if (!isValidKey(key)) {
2332
+ // We want to ensure we do not copy prototypes over
2333
+ // as this can pollute global namespaces
2334
+ return;
2335
+ }
2336
+
2337
+ var tval = target[key];
2338
+ var sval = source[key];
2339
+
2340
+ if (helpers.isObject(tval) && helpers.isObject(sval)) {
2341
+ helpers.mergeIf(tval, sval);
2342
+ } else if (!target.hasOwnProperty(key)) {
2343
+ target[key] = helpers.clone(sval);
2344
+ }
2345
+ },
2346
+
2347
+ /**
2348
+ * Recursively deep copies `source` properties into `target` with the given `options`.
2349
+ * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
2350
+ * @param {object} target - The target object in which all sources are merged into.
2351
+ * @param {object|object[]} source - Object(s) to merge into `target`.
2352
+ * @param {object} [options] - Merging options:
2353
+ * @param {function} [options.merger] - The merge method (key, target, source, options)
2354
+ * @returns {object} The `target` object.
2355
+ */
2356
+ merge: function(target, source, options) {
2357
+ var sources = helpers.isArray(source) ? source : [source];
2358
+ var ilen = sources.length;
2359
+ var merge, i, keys, klen, k;
2360
+
2361
+ if (!helpers.isObject(target)) {
2362
+ return target;
2363
+ }
2364
+
2365
+ options = options || {};
2366
+ merge = options.merger || helpers._merger;
2367
+
2368
+ for (i = 0; i < ilen; ++i) {
2369
+ source = sources[i];
2370
+ if (!helpers.isObject(source)) {
2371
+ continue;
2372
+ }
2373
+
2374
+ keys = Object.keys(source);
2375
+ for (k = 0, klen = keys.length; k < klen; ++k) {
2376
+ merge(keys[k], target, source, options);
2377
+ }
2378
+ }
2379
+
2380
+ return target;
2381
+ },
2382
+
2383
+ /**
2384
+ * Recursively deep copies `source` properties into `target` *only* if not defined in target.
2385
+ * IMPORTANT: `target` is not cloned and will be updated with `source` properties.
2386
+ * @param {object} target - The target object in which all sources are merged into.
2387
+ * @param {object|object[]} source - Object(s) to merge into `target`.
2388
+ * @returns {object} The `target` object.
2389
+ */
2390
+ mergeIf: function(target, source) {
2391
+ return helpers.merge(target, source, {merger: helpers._mergerIf});
2392
+ },
2393
+
2394
+ /**
2395
+ * Applies the contents of two or more objects together into the first object.
2396
+ * @param {object} target - The target object in which all objects are merged into.
2397
+ * @param {object} arg1 - Object containing additional properties to merge in target.
2398
+ * @param {object} argN - Additional objects containing properties to merge in target.
2399
+ * @returns {object} The `target` object.
2400
+ */
2401
+ extend: Object.assign || function(target) {
2402
+ return helpers.merge(target, [].slice.call(arguments, 1), {
2403
+ merger: function(key, dst, src) {
2404
+ dst[key] = src[key];
2405
+ }
2406
+ });
2407
+ },
2408
+
2409
+ /**
2410
+ * Basic javascript inheritance based on the model created in Backbone.js
2411
+ */
2412
+ inherits: function(extensions) {
2413
+ var me = this;
2414
+ var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {
2415
+ return me.apply(this, arguments);
2416
+ };
2417
+
2418
+ var Surrogate = function() {
2419
+ this.constructor = ChartElement;
2420
+ };
2421
+
2422
+ Surrogate.prototype = me.prototype;
2423
+ ChartElement.prototype = new Surrogate();
2424
+ ChartElement.extend = helpers.inherits;
2425
+
2426
+ if (extensions) {
2427
+ helpers.extend(ChartElement.prototype, extensions);
2428
+ }
2429
+
2430
+ ChartElement.__super__ = me.prototype;
2431
+ return ChartElement;
2432
+ },
2433
+
2434
+ _deprecated: function(scope, value, previous, current) {
2435
+ if (value !== undefined) {
2436
+ console.warn(scope + ': "' + previous +
2437
+ '" is deprecated. Please use "' + current + '" instead');
2438
+ }
2439
+ }
2440
+ };
2441
+
2442
+ var helpers_core = helpers;
2443
+
2444
+ // DEPRECATIONS
2445
+
2446
+ /**
2447
+ * Provided for backward compatibility, use Chart.helpers.callback instead.
2448
+ * @function Chart.helpers.callCallback
2449
+ * @deprecated since version 2.6.0
2450
+ * @todo remove at version 3
2451
+ * @private
2452
+ */
2453
+ helpers.callCallback = helpers.callback;
2454
+
2455
+ /**
2456
+ * Provided for backward compatibility, use Array.prototype.indexOf instead.
2457
+ * Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+
2458
+ * @function Chart.helpers.indexOf
2459
+ * @deprecated since version 2.7.0
2460
+ * @todo remove at version 3
2461
+ * @private
2462
+ */
2463
+ helpers.indexOf = function(array, item, fromIndex) {
2464
+ return Array.prototype.indexOf.call(array, item, fromIndex);
2465
+ };
2466
+
2467
+ /**
2468
+ * Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.
2469
+ * @function Chart.helpers.getValueOrDefault
2470
+ * @deprecated since version 2.7.0
2471
+ * @todo remove at version 3
2472
+ * @private
2473
+ */
2474
+ helpers.getValueOrDefault = helpers.valueOrDefault;
2475
+
2476
+ /**
2477
+ * Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.
2478
+ * @function Chart.helpers.getValueAtIndexOrDefault
2479
+ * @deprecated since version 2.7.0
2480
+ * @todo remove at version 3
2481
+ * @private
2482
+ */
2483
+ helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
2130
2484
 
2131
- /**
2132
- * Returns true if `value` is neither null nor undefined, else returns false.
2133
- * @param {*} value - The value to test.
2134
- * @returns {boolean}
2135
- * @since 2.7.0
2136
- */
2137
- isNullOrUndef: function(value) {
2138
- return value === null || typeof value === 'undefined';
2139
- },
2485
+ /**
2486
+ * Easing functions adapted from Robert Penner's easing equations.
2487
+ * @namespace Chart.helpers.easingEffects
2488
+ * @see http://www.robertpenner.com/easing/
2489
+ */
2490
+ var effects = {
2491
+ linear: function(t) {
2492
+ return t;
2493
+ },
2494
+
2495
+ easeInQuad: function(t) {
2496
+ return t * t;
2497
+ },
2498
+
2499
+ easeOutQuad: function(t) {
2500
+ return -t * (t - 2);
2501
+ },
2502
+
2503
+ easeInOutQuad: function(t) {
2504
+ if ((t /= 0.5) < 1) {
2505
+ return 0.5 * t * t;
2506
+ }
2507
+ return -0.5 * ((--t) * (t - 2) - 1);
2508
+ },
2509
+
2510
+ easeInCubic: function(t) {
2511
+ return t * t * t;
2512
+ },
2513
+
2514
+ easeOutCubic: function(t) {
2515
+ return (t = t - 1) * t * t + 1;
2516
+ },
2517
+
2518
+ easeInOutCubic: function(t) {
2519
+ if ((t /= 0.5) < 1) {
2520
+ return 0.5 * t * t * t;
2521
+ }
2522
+ return 0.5 * ((t -= 2) * t * t + 2);
2523
+ },
2524
+
2525
+ easeInQuart: function(t) {
2526
+ return t * t * t * t;
2527
+ },
2528
+
2529
+ easeOutQuart: function(t) {
2530
+ return -((t = t - 1) * t * t * t - 1);
2531
+ },
2532
+
2533
+ easeInOutQuart: function(t) {
2534
+ if ((t /= 0.5) < 1) {
2535
+ return 0.5 * t * t * t * t;
2536
+ }
2537
+ return -0.5 * ((t -= 2) * t * t * t - 2);
2538
+ },
2539
+
2540
+ easeInQuint: function(t) {
2541
+ return t * t * t * t * t;
2542
+ },
2543
+
2544
+ easeOutQuint: function(t) {
2545
+ return (t = t - 1) * t * t * t * t + 1;
2546
+ },
2547
+
2548
+ easeInOutQuint: function(t) {
2549
+ if ((t /= 0.5) < 1) {
2550
+ return 0.5 * t * t * t * t * t;
2551
+ }
2552
+ return 0.5 * ((t -= 2) * t * t * t * t + 2);
2553
+ },
2554
+
2555
+ easeInSine: function(t) {
2556
+ return -Math.cos(t * (Math.PI / 2)) + 1;
2557
+ },
2558
+
2559
+ easeOutSine: function(t) {
2560
+ return Math.sin(t * (Math.PI / 2));
2561
+ },
2562
+
2563
+ easeInOutSine: function(t) {
2564
+ return -0.5 * (Math.cos(Math.PI * t) - 1);
2565
+ },
2566
+
2567
+ easeInExpo: function(t) {
2568
+ return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));
2569
+ },
2570
+
2571
+ easeOutExpo: function(t) {
2572
+ return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;
2573
+ },
2574
+
2575
+ easeInOutExpo: function(t) {
2576
+ if (t === 0) {
2577
+ return 0;
2578
+ }
2579
+ if (t === 1) {
2580
+ return 1;
2581
+ }
2582
+ if ((t /= 0.5) < 1) {
2583
+ return 0.5 * Math.pow(2, 10 * (t - 1));
2584
+ }
2585
+ return 0.5 * (-Math.pow(2, -10 * --t) + 2);
2586
+ },
2587
+
2588
+ easeInCirc: function(t) {
2589
+ if (t >= 1) {
2590
+ return t;
2591
+ }
2592
+ return -(Math.sqrt(1 - t * t) - 1);
2593
+ },
2594
+
2595
+ easeOutCirc: function(t) {
2596
+ return Math.sqrt(1 - (t = t - 1) * t);
2597
+ },
2598
+
2599
+ easeInOutCirc: function(t) {
2600
+ if ((t /= 0.5) < 1) {
2601
+ return -0.5 * (Math.sqrt(1 - t * t) - 1);
2602
+ }
2603
+ return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
2604
+ },
2605
+
2606
+ easeInElastic: function(t) {
2607
+ var s = 1.70158;
2608
+ var p = 0;
2609
+ var a = 1;
2610
+ if (t === 0) {
2611
+ return 0;
2612
+ }
2613
+ if (t === 1) {
2614
+ return 1;
2615
+ }
2616
+ if (!p) {
2617
+ p = 0.3;
2618
+ }
2619
+ if (a < 1) {
2620
+ a = 1;
2621
+ s = p / 4;
2622
+ } else {
2623
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
2624
+ }
2625
+ return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
2626
+ },
2627
+
2628
+ easeOutElastic: function(t) {
2629
+ var s = 1.70158;
2630
+ var p = 0;
2631
+ var a = 1;
2632
+ if (t === 0) {
2633
+ return 0;
2634
+ }
2635
+ if (t === 1) {
2636
+ return 1;
2637
+ }
2638
+ if (!p) {
2639
+ p = 0.3;
2640
+ }
2641
+ if (a < 1) {
2642
+ a = 1;
2643
+ s = p / 4;
2644
+ } else {
2645
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
2646
+ }
2647
+ return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;
2648
+ },
2649
+
2650
+ easeInOutElastic: function(t) {
2651
+ var s = 1.70158;
2652
+ var p = 0;
2653
+ var a = 1;
2654
+ if (t === 0) {
2655
+ return 0;
2656
+ }
2657
+ if ((t /= 0.5) === 2) {
2658
+ return 1;
2659
+ }
2660
+ if (!p) {
2661
+ p = 0.45;
2662
+ }
2663
+ if (a < 1) {
2664
+ a = 1;
2665
+ s = p / 4;
2666
+ } else {
2667
+ s = p / (2 * Math.PI) * Math.asin(1 / a);
2668
+ }
2669
+ if (t < 1) {
2670
+ return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));
2671
+ }
2672
+ return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;
2673
+ },
2674
+ easeInBack: function(t) {
2675
+ var s = 1.70158;
2676
+ return t * t * ((s + 1) * t - s);
2677
+ },
2678
+
2679
+ easeOutBack: function(t) {
2680
+ var s = 1.70158;
2681
+ return (t = t - 1) * t * ((s + 1) * t + s) + 1;
2682
+ },
2683
+
2684
+ easeInOutBack: function(t) {
2685
+ var s = 1.70158;
2686
+ if ((t /= 0.5) < 1) {
2687
+ return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
2688
+ }
2689
+ return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
2690
+ },
2691
+
2692
+ easeInBounce: function(t) {
2693
+ return 1 - effects.easeOutBounce(1 - t);
2694
+ },
2695
+
2696
+ easeOutBounce: function(t) {
2697
+ if (t < (1 / 2.75)) {
2698
+ return 7.5625 * t * t;
2699
+ }
2700
+ if (t < (2 / 2.75)) {
2701
+ return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;
2702
+ }
2703
+ if (t < (2.5 / 2.75)) {
2704
+ return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;
2705
+ }
2706
+ return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;
2707
+ },
2708
+
2709
+ easeInOutBounce: function(t) {
2710
+ if (t < 0.5) {
2711
+ return effects.easeInBounce(t * 2) * 0.5;
2712
+ }
2713
+ return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;
2714
+ }
2715
+ };
2716
+
2717
+ var helpers_easing = {
2718
+ effects: effects
2719
+ };
2720
+
2721
+ // DEPRECATIONS
2722
+
2723
+ /**
2724
+ * Provided for backward compatibility, use Chart.helpers.easing.effects instead.
2725
+ * @function Chart.helpers.easingEffects
2726
+ * @deprecated since version 2.7.0
2727
+ * @todo remove at version 3
2728
+ * @private
2729
+ */
2730
+ helpers_core.easingEffects = effects;
2140
2731
 
2141
- /**
2142
- * Returns true if `value` is an array (including typed arrays), else returns false.
2143
- * @param {*} value - The value to test.
2144
- * @returns {boolean}
2145
- * @function
2146
- */
2147
- isArray: function(value) {
2148
- if (Array.isArray && Array.isArray(value)) {
2149
- return true;
2150
- }
2151
- var type = Object.prototype.toString.call(value);
2152
- if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
2153
- return true;
2154
- }
2155
- return false;
2156
- },
2732
+ var PI = Math.PI;
2733
+ var RAD_PER_DEG = PI / 180;
2734
+ var DOUBLE_PI = PI * 2;
2735
+ var HALF_PI = PI / 2;
2736
+ var QUARTER_PI = PI / 4;
2737
+ var TWO_THIRDS_PI = PI * 2 / 3;
2738
+
2739
+ /**
2740
+ * @namespace Chart.helpers.canvas
2741
+ */
2742
+ var exports$1 = {
2743
+ /**
2744
+ * Clears the entire canvas associated to the given `chart`.
2745
+ * @param {Chart} chart - The chart for which to clear the canvas.
2746
+ */
2747
+ clear: function(chart) {
2748
+ chart.ctx.clearRect(0, 0, chart.width, chart.height);
2749
+ },
2750
+
2751
+ /**
2752
+ * Creates a "path" for a rectangle with rounded corners at position (x, y) with a
2753
+ * given size (width, height) and the same `radius` for all corners.
2754
+ * @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.
2755
+ * @param {number} x - The x axis of the coordinate for the rectangle starting point.
2756
+ * @param {number} y - The y axis of the coordinate for the rectangle starting point.
2757
+ * @param {number} width - The rectangle's width.
2758
+ * @param {number} height - The rectangle's height.
2759
+ * @param {number} radius - The rounded amount (in pixels) for the four corners.
2760
+ * @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?
2761
+ */
2762
+ roundedRect: function(ctx, x, y, width, height, radius) {
2763
+ if (radius) {
2764
+ var r = Math.min(radius, height / 2, width / 2);
2765
+ var left = x + r;
2766
+ var top = y + r;
2767
+ var right = x + width - r;
2768
+ var bottom = y + height - r;
2769
+
2770
+ ctx.moveTo(x, top);
2771
+ if (left < right && top < bottom) {
2772
+ ctx.arc(left, top, r, -PI, -HALF_PI);
2773
+ ctx.arc(right, top, r, -HALF_PI, 0);
2774
+ ctx.arc(right, bottom, r, 0, HALF_PI);
2775
+ ctx.arc(left, bottom, r, HALF_PI, PI);
2776
+ } else if (left < right) {
2777
+ ctx.moveTo(left, y);
2778
+ ctx.arc(right, top, r, -HALF_PI, HALF_PI);
2779
+ ctx.arc(left, top, r, HALF_PI, PI + HALF_PI);
2780
+ } else if (top < bottom) {
2781
+ ctx.arc(left, top, r, -PI, 0);
2782
+ ctx.arc(left, bottom, r, 0, PI);
2783
+ } else {
2784
+ ctx.arc(left, top, r, -PI, PI);
2785
+ }
2786
+ ctx.closePath();
2787
+ ctx.moveTo(x, y);
2788
+ } else {
2789
+ ctx.rect(x, y, width, height);
2790
+ }
2791
+ },
2792
+
2793
+ drawPoint: function(ctx, style, radius, x, y, rotation) {
2794
+ var type, xOffset, yOffset, size, cornerRadius;
2795
+ var rad = (rotation || 0) * RAD_PER_DEG;
2796
+
2797
+ if (style && typeof style === 'object') {
2798
+ type = style.toString();
2799
+ if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
2800
+ ctx.save();
2801
+ ctx.translate(x, y);
2802
+ ctx.rotate(rad);
2803
+ ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
2804
+ ctx.restore();
2805
+ return;
2806
+ }
2807
+ }
2808
+
2809
+ if (isNaN(radius) || radius <= 0) {
2810
+ return;
2811
+ }
2812
+
2813
+ ctx.beginPath();
2814
+
2815
+ switch (style) {
2816
+ // Default includes circle
2817
+ default:
2818
+ ctx.arc(x, y, radius, 0, DOUBLE_PI);
2819
+ ctx.closePath();
2820
+ break;
2821
+ case 'triangle':
2822
+ ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
2823
+ rad += TWO_THIRDS_PI;
2824
+ ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
2825
+ rad += TWO_THIRDS_PI;
2826
+ ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
2827
+ ctx.closePath();
2828
+ break;
2829
+ case 'rectRounded':
2830
+ // NOTE: the rounded rect implementation changed to use `arc` instead of
2831
+ // `quadraticCurveTo` since it generates better results when rect is
2832
+ // almost a circle. 0.516 (instead of 0.5) produces results with visually
2833
+ // closer proportion to the previous impl and it is inscribed in the
2834
+ // circle with `radius`. For more details, see the following PRs:
2835
+ // https://github.com/chartjs/Chart.js/issues/5597
2836
+ // https://github.com/chartjs/Chart.js/issues/5858
2837
+ cornerRadius = radius * 0.516;
2838
+ size = radius - cornerRadius;
2839
+ xOffset = Math.cos(rad + QUARTER_PI) * size;
2840
+ yOffset = Math.sin(rad + QUARTER_PI) * size;
2841
+ ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
2842
+ ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
2843
+ ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
2844
+ ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
2845
+ ctx.closePath();
2846
+ break;
2847
+ case 'rect':
2848
+ if (!rotation) {
2849
+ size = Math.SQRT1_2 * radius;
2850
+ ctx.rect(x - size, y - size, 2 * size, 2 * size);
2851
+ break;
2852
+ }
2853
+ rad += QUARTER_PI;
2854
+ /* falls through */
2855
+ case 'rectRot':
2856
+ xOffset = Math.cos(rad) * radius;
2857
+ yOffset = Math.sin(rad) * radius;
2858
+ ctx.moveTo(x - xOffset, y - yOffset);
2859
+ ctx.lineTo(x + yOffset, y - xOffset);
2860
+ ctx.lineTo(x + xOffset, y + yOffset);
2861
+ ctx.lineTo(x - yOffset, y + xOffset);
2862
+ ctx.closePath();
2863
+ break;
2864
+ case 'crossRot':
2865
+ rad += QUARTER_PI;
2866
+ /* falls through */
2867
+ case 'cross':
2868
+ xOffset = Math.cos(rad) * radius;
2869
+ yOffset = Math.sin(rad) * radius;
2870
+ ctx.moveTo(x - xOffset, y - yOffset);
2871
+ ctx.lineTo(x + xOffset, y + yOffset);
2872
+ ctx.moveTo(x + yOffset, y - xOffset);
2873
+ ctx.lineTo(x - yOffset, y + xOffset);
2874
+ break;
2875
+ case 'star':
2876
+ xOffset = Math.cos(rad) * radius;
2877
+ yOffset = Math.sin(rad) * radius;
2878
+ ctx.moveTo(x - xOffset, y - yOffset);
2879
+ ctx.lineTo(x + xOffset, y + yOffset);
2880
+ ctx.moveTo(x + yOffset, y - xOffset);
2881
+ ctx.lineTo(x - yOffset, y + xOffset);
2882
+ rad += QUARTER_PI;
2883
+ xOffset = Math.cos(rad) * radius;
2884
+ yOffset = Math.sin(rad) * radius;
2885
+ ctx.moveTo(x - xOffset, y - yOffset);
2886
+ ctx.lineTo(x + xOffset, y + yOffset);
2887
+ ctx.moveTo(x + yOffset, y - xOffset);
2888
+ ctx.lineTo(x - yOffset, y + xOffset);
2889
+ break;
2890
+ case 'line':
2891
+ xOffset = Math.cos(rad) * radius;
2892
+ yOffset = Math.sin(rad) * radius;
2893
+ ctx.moveTo(x - xOffset, y - yOffset);
2894
+ ctx.lineTo(x + xOffset, y + yOffset);
2895
+ break;
2896
+ case 'dash':
2897
+ ctx.moveTo(x, y);
2898
+ ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
2899
+ break;
2900
+ }
2901
+
2902
+ ctx.fill();
2903
+ ctx.stroke();
2904
+ },
2905
+
2906
+ /**
2907
+ * Returns true if the point is inside the rectangle
2908
+ * @param {object} point - The point to test
2909
+ * @param {object} area - The rectangle
2910
+ * @returns {boolean}
2911
+ * @private
2912
+ */
2913
+ _isPointInArea: function(point, area) {
2914
+ var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.
2915
+
2916
+ return point.x > area.left - epsilon && point.x < area.right + epsilon &&
2917
+ point.y > area.top - epsilon && point.y < area.bottom + epsilon;
2918
+ },
2919
+
2920
+ clipArea: function(ctx, area) {
2921
+ ctx.save();
2922
+ ctx.beginPath();
2923
+ ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
2924
+ ctx.clip();
2925
+ },
2926
+
2927
+ unclipArea: function(ctx) {
2928
+ ctx.restore();
2929
+ },
2930
+
2931
+ lineTo: function(ctx, previous, target, flip) {
2932
+ var stepped = target.steppedLine;
2933
+ if (stepped) {
2934
+ if (stepped === 'middle') {
2935
+ var midpoint = (previous.x + target.x) / 2.0;
2936
+ ctx.lineTo(midpoint, flip ? target.y : previous.y);
2937
+ ctx.lineTo(midpoint, flip ? previous.y : target.y);
2938
+ } else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {
2939
+ ctx.lineTo(previous.x, target.y);
2940
+ } else {
2941
+ ctx.lineTo(target.x, previous.y);
2942
+ }
2943
+ ctx.lineTo(target.x, target.y);
2944
+ return;
2945
+ }
2946
+
2947
+ if (!target.tension) {
2948
+ ctx.lineTo(target.x, target.y);
2949
+ return;
2950
+ }
2951
+
2952
+ ctx.bezierCurveTo(
2953
+ flip ? previous.controlPointPreviousX : previous.controlPointNextX,
2954
+ flip ? previous.controlPointPreviousY : previous.controlPointNextY,
2955
+ flip ? target.controlPointNextX : target.controlPointPreviousX,
2956
+ flip ? target.controlPointNextY : target.controlPointPreviousY,
2957
+ target.x,
2958
+ target.y);
2959
+ }
2960
+ };
2961
+
2962
+ var helpers_canvas = exports$1;
2963
+
2964
+ // DEPRECATIONS
2965
+
2966
+ /**
2967
+ * Provided for backward compatibility, use Chart.helpers.canvas.clear instead.
2968
+ * @namespace Chart.helpers.clear
2969
+ * @deprecated since version 2.7.0
2970
+ * @todo remove at version 3
2971
+ * @private
2972
+ */
2973
+ helpers_core.clear = exports$1.clear;
2974
+
2975
+ /**
2976
+ * Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.
2977
+ * @namespace Chart.helpers.drawRoundedRectangle
2978
+ * @deprecated since version 2.7.0
2979
+ * @todo remove at version 3
2980
+ * @private
2981
+ */
2982
+ helpers_core.drawRoundedRectangle = function(ctx) {
2983
+ ctx.beginPath();
2984
+ exports$1.roundedRect.apply(exports$1, arguments);
2985
+ };
2157
2986
 
2158
- /**
2159
- * Returns true if `value` is an object (excluding null), else returns false.
2160
- * @param {*} value - The value to test.
2161
- * @returns {boolean}
2162
- * @since 2.7.0
2163
- */
2164
- isObject: function(value) {
2165
- return value !== null && Object.prototype.toString.call(value) === '[object Object]';
2166
- },
2987
+ var defaults = {
2988
+ /**
2989
+ * @private
2990
+ */
2991
+ _set: function(scope, values) {
2992
+ return helpers_core.merge(this[scope] || (this[scope] = {}), values);
2993
+ }
2994
+ };
2995
+
2996
+ // TODO(v3): remove 'global' from namespace. all default are global and
2997
+ // there's inconsistency around which options are under 'global'
2998
+ defaults._set('global', {
2999
+ defaultColor: 'rgba(0,0,0,0.1)',
3000
+ defaultFontColor: '#666',
3001
+ defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
3002
+ defaultFontSize: 12,
3003
+ defaultFontStyle: 'normal',
3004
+ defaultLineHeight: 1.2,
3005
+ showLines: true
3006
+ });
3007
+
3008
+ var core_defaults = defaults;
2167
3009
 
2168
- /**
2169
- * Returns true if `value` is a finite number, else returns false
2170
- * @param {*} value - The value to test.
2171
- * @returns {boolean}
2172
- */
2173
- isFinite: function(value) {
2174
- return (typeof value === 'number' || value instanceof Number) && isFinite(value);
2175
- },
3010
+ var valueOrDefault = helpers_core.valueOrDefault;
3011
+
3012
+ /**
3013
+ * Converts the given font object into a CSS font string.
3014
+ * @param {object} font - A font object.
3015
+ * @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font
3016
+ * @private
3017
+ */
3018
+ function toFontString(font) {
3019
+ if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) {
3020
+ return null;
3021
+ }
3022
+
3023
+ return (font.style ? font.style + ' ' : '')
3024
+ + (font.weight ? font.weight + ' ' : '')
3025
+ + font.size + 'px '
3026
+ + font.family;
3027
+ }
3028
+
3029
+ /**
3030
+ * @alias Chart.helpers.options
3031
+ * @namespace
3032
+ */
3033
+ var helpers_options = {
3034
+ /**
3035
+ * Converts the given line height `value` in pixels for a specific font `size`.
3036
+ * @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').
3037
+ * @param {number} size - The font size (in pixels) used to resolve relative `value`.
3038
+ * @returns {number} The effective line height in pixels (size * 1.2 if value is invalid).
3039
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height
3040
+ * @since 2.7.0
3041
+ */
3042
+ toLineHeight: function(value, size) {
3043
+ var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
3044
+ if (!matches || matches[1] === 'normal') {
3045
+ return size * 1.2;
3046
+ }
3047
+
3048
+ value = +matches[2];
3049
+
3050
+ switch (matches[3]) {
3051
+ case 'px':
3052
+ return value;
3053
+ case '%':
3054
+ value /= 100;
3055
+ break;
3056
+ }
3057
+
3058
+ return size * value;
3059
+ },
3060
+
3061
+ /**
3062
+ * Converts the given value into a padding object with pre-computed width/height.
3063
+ * @param {number|object} value - If a number, set the value to all TRBL component,
3064
+ * else, if and object, use defined properties and sets undefined ones to 0.
3065
+ * @returns {object} The padding values (top, right, bottom, left, width, height)
3066
+ * @since 2.7.0
3067
+ */
3068
+ toPadding: function(value) {
3069
+ var t, r, b, l;
3070
+
3071
+ if (helpers_core.isObject(value)) {
3072
+ t = +value.top || 0;
3073
+ r = +value.right || 0;
3074
+ b = +value.bottom || 0;
3075
+ l = +value.left || 0;
3076
+ } else {
3077
+ t = r = b = l = +value || 0;
3078
+ }
3079
+
3080
+ return {
3081
+ top: t,
3082
+ right: r,
3083
+ bottom: b,
3084
+ left: l,
3085
+ height: t + b,
3086
+ width: l + r
3087
+ };
3088
+ },
3089
+
3090
+ /**
3091
+ * Parses font options and returns the font object.
3092
+ * @param {object} options - A object that contains font options to be parsed.
3093
+ * @return {object} The font object.
3094
+ * @todo Support font.* options and renamed to toFont().
3095
+ * @private
3096
+ */
3097
+ _parseFont: function(options) {
3098
+ var globalDefaults = core_defaults.global;
3099
+ var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);
3100
+ var font = {
3101
+ family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),
3102
+ lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),
3103
+ size: size,
3104
+ style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),
3105
+ weight: null,
3106
+ string: ''
3107
+ };
3108
+
3109
+ font.string = toFontString(font);
3110
+ return font;
3111
+ },
3112
+
3113
+ /**
3114
+ * Evaluates the given `inputs` sequentially and returns the first defined value.
3115
+ * @param {Array} inputs - An array of values, falling back to the last value.
3116
+ * @param {object} [context] - If defined and the current value is a function, the value
3117
+ * is called with `context` as first argument and the result becomes the new input.
3118
+ * @param {number} [index] - If defined and the current value is an array, the value
3119
+ * at `index` become the new input.
3120
+ * @param {object} [info] - object to return information about resolution in
3121
+ * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
3122
+ * @since 2.7.0
3123
+ */
3124
+ resolve: function(inputs, context, index, info) {
3125
+ var cacheable = true;
3126
+ var i, ilen, value;
3127
+
3128
+ for (i = 0, ilen = inputs.length; i < ilen; ++i) {
3129
+ value = inputs[i];
3130
+ if (value === undefined) {
3131
+ continue;
3132
+ }
3133
+ if (context !== undefined && typeof value === 'function') {
3134
+ value = value(context);
3135
+ cacheable = false;
3136
+ }
3137
+ if (index !== undefined && helpers_core.isArray(value)) {
3138
+ value = value[index];
3139
+ cacheable = false;
3140
+ }
3141
+ if (value !== undefined) {
3142
+ if (info && !cacheable) {
3143
+ info.cacheable = false;
3144
+ }
3145
+ return value;
3146
+ }
3147
+ }
3148
+ }
3149
+ };
2176
3150
 
2177
- /**
2178
- * Returns `value` if defined, else returns `defaultValue`.
2179
- * @param {*} value - The value to return if defined.
2180
- * @param {*} defaultValue - The value to return if `value` is undefined.
2181
- * @returns {*}
2182
- */
2183
- valueOrDefault: function(value, defaultValue) {
2184
- return typeof value === 'undefined' ? defaultValue : value;
2185
- },
3151
+ /**
3152
+ * @alias Chart.helpers.math
3153
+ * @namespace
3154
+ */
3155
+ var exports$2 = {
3156
+ /**
3157
+ * Returns an array of factors sorted from 1 to sqrt(value)
3158
+ * @private
3159
+ */
3160
+ _factorize: function(value) {
3161
+ var result = [];
3162
+ var sqrt = Math.sqrt(value);
3163
+ var i;
3164
+
3165
+ for (i = 1; i < sqrt; i++) {
3166
+ if (value % i === 0) {
3167
+ result.push(i);
3168
+ result.push(value / i);
3169
+ }
3170
+ }
3171
+ if (sqrt === (sqrt | 0)) { // if value is a square number
3172
+ result.push(sqrt);
3173
+ }
3174
+
3175
+ result.sort(function(a, b) {
3176
+ return a - b;
3177
+ }).pop();
3178
+ return result;
3179
+ },
3180
+
3181
+ log10: Math.log10 || function(x) {
3182
+ var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
3183
+ // Check for whole powers of 10,
3184
+ // which due to floating point rounding error should be corrected.
3185
+ var powerOf10 = Math.round(exponent);
3186
+ var isPowerOf10 = x === Math.pow(10, powerOf10);
3187
+
3188
+ return isPowerOf10 ? powerOf10 : exponent;
3189
+ }
3190
+ };
3191
+
3192
+ var helpers_math = exports$2;
3193
+
3194
+ // DEPRECATIONS
3195
+
3196
+ /**
3197
+ * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
3198
+ * @namespace Chart.helpers.log10
3199
+ * @deprecated since version 2.9.0
3200
+ * @todo remove at version 3
3201
+ * @private
3202
+ */
3203
+ helpers_core.log10 = exports$2.log10;
2186
3204
 
2187
- /**
2188
- * Returns value at the given `index` in array if defined, else returns `defaultValue`.
2189
- * @param {Array} value - The array to lookup for value at `index`.
2190
- * @param {number} index - The index in `value` to lookup for value.
2191
- * @param {*} defaultValue - The value to return if `value[index]` is undefined.
2192
- * @returns {*}
2193
- */
2194
- valueAtIndexOrDefault: function(value, index, defaultValue) {
2195
- return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);
2196
- },
3205
+ var getRtlAdapter = function(rectX, width) {
3206
+ return {
3207
+ x: function(x) {
3208
+ return rectX + rectX + width - x;
3209
+ },
3210
+ setWidth: function(w) {
3211
+ width = w;
3212
+ },
3213
+ textAlign: function(align) {
3214
+ if (align === 'center') {
3215
+ return align;
3216
+ }
3217
+ return align === 'right' ? 'left' : 'right';
3218
+ },
3219
+ xPlus: function(x, value) {
3220
+ return x - value;
3221
+ },
3222
+ leftForLtr: function(x, itemWidth) {
3223
+ return x - itemWidth;
3224
+ },
3225
+ };
3226
+ };
3227
+
3228
+ var getLtrAdapter = function() {
3229
+ return {
3230
+ x: function(x) {
3231
+ return x;
3232
+ },
3233
+ setWidth: function(w) { // eslint-disable-line no-unused-vars
3234
+ },
3235
+ textAlign: function(align) {
3236
+ return align;
3237
+ },
3238
+ xPlus: function(x, value) {
3239
+ return x + value;
3240
+ },
3241
+ leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars
3242
+ return x;
3243
+ },
3244
+ };
3245
+ };
3246
+
3247
+ var getAdapter = function(rtl, rectX, width) {
3248
+ return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();
3249
+ };
3250
+
3251
+ var overrideTextDirection = function(ctx, direction) {
3252
+ var style, original;
3253
+ if (direction === 'ltr' || direction === 'rtl') {
3254
+ style = ctx.canvas.style;
3255
+ original = [
3256
+ style.getPropertyValue('direction'),
3257
+ style.getPropertyPriority('direction'),
3258
+ ];
3259
+
3260
+ style.setProperty('direction', direction, 'important');
3261
+ ctx.prevTextDirection = original;
3262
+ }
3263
+ };
3264
+
3265
+ var restoreTextDirection = function(ctx) {
3266
+ var original = ctx.prevTextDirection;
3267
+ if (original !== undefined) {
3268
+ delete ctx.prevTextDirection;
3269
+ ctx.canvas.style.setProperty('direction', original[0], original[1]);
3270
+ }
3271
+ };
3272
+
3273
+ var helpers_rtl = {
3274
+ getRtlAdapter: getAdapter,
3275
+ overrideTextDirection: overrideTextDirection,
3276
+ restoreTextDirection: restoreTextDirection,
3277
+ };
2197
3278
 
2198
- /**
2199
- * Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the
2200
- * value returned by `fn`. If `fn` is not a function, this method returns undefined.
2201
- * @param {function} fn - The function to call.
2202
- * @param {Array|undefined|null} args - The arguments with which `fn` should be called.
2203
- * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
2204
- * @returns {*}
2205
- */
2206
- callback: function(fn, args, thisArg) {
2207
- if (fn && typeof fn.call === 'function') {
2208
- return fn.apply(thisArg, args);
2209
- }
2210
- },
3279
+ var helpers$1 = helpers_core;
3280
+ var easing = helpers_easing;
3281
+ var canvas = helpers_canvas;
3282
+ var options = helpers_options;
3283
+ var math = helpers_math;
3284
+ var rtl = helpers_rtl;
3285
+ helpers$1.easing = easing;
3286
+ helpers$1.canvas = canvas;
3287
+ helpers$1.options = options;
3288
+ helpers$1.math = math;
3289
+ helpers$1.rtl = rtl;
2211
3290
 
2212
- /**
2213
- * Note(SB) for performance sake, this method should only be used when loopable type
2214
- * is unknown or in none intensive code (not called often and small loopable). Else
2215
- * it's preferable to use a regular for() loop and save extra function calls.
2216
- * @param {object|Array} loopable - The object or array to be iterated.
2217
- * @param {function} fn - The function to call for each item.
2218
- * @param {object} [thisArg] - The value of `this` provided for the call to `fn`.
2219
- * @param {boolean} [reverse] - If true, iterates backward on the loopable.
2220
- */
2221
- each: function(loopable, fn, thisArg, reverse) {
2222
- var i, len, keys;
2223
- if (helpers.isArray(loopable)) {
2224
- len = loopable.length;
2225
- if (reverse) {
2226
- for (i = len - 1; i >= 0; i--) {
2227
- fn.call(thisArg, loopable[i], i);
2228
- }
2229
- } else {
2230
- for (i = 0; i < len; i++) {
2231
- fn.call(thisArg, loopable[i], i);
2232
- }
2233
- }
2234
- } else if (helpers.isObject(loopable)) {
2235
- keys = Object.keys(loopable);
2236
- len = keys.length;
2237
- for (i = 0; i < len; i++) {
2238
- fn.call(thisArg, loopable[keys[i]], keys[i]);
2239
- }
2240
- }
2241
- },
3291
+ function interpolate(start, view, model, ease) {
3292
+ var keys = Object.keys(model);
3293
+ var i, ilen, key, actual, origin, target, type, c0, c1;
3294
+
3295
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
3296
+ key = keys[i];
3297
+
3298
+ target = model[key];
3299
+
3300
+ // if a value is added to the model after pivot() has been called, the view
3301
+ // doesn't contain it, so let's initialize the view to the target value.
3302
+ if (!view.hasOwnProperty(key)) {
3303
+ view[key] = target;
3304
+ }
3305
+
3306
+ actual = view[key];
3307
+
3308
+ if (actual === target || key[0] === '_') {
3309
+ continue;
3310
+ }
3311
+
3312
+ if (!start.hasOwnProperty(key)) {
3313
+ start[key] = actual;
3314
+ }
3315
+
3316
+ origin = start[key];
3317
+
3318
+ type = typeof target;
3319
+
3320
+ if (type === typeof origin) {
3321
+ if (type === 'string') {
3322
+ c0 = chartjsColor(origin);
3323
+ if (c0.valid) {
3324
+ c1 = chartjsColor(target);
3325
+ if (c1.valid) {
3326
+ view[key] = c1.mix(c0, ease).rgbString();
3327
+ continue;
3328
+ }
3329
+ }
3330
+ } else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) {
3331
+ view[key] = origin + (target - origin) * ease;
3332
+ continue;
3333
+ }
3334
+ }
3335
+
3336
+ view[key] = target;
3337
+ }
3338
+ }
3339
+
3340
+ var Element = function(configuration) {
3341
+ helpers$1.extend(this, configuration);
3342
+ this.initialize.apply(this, arguments);
3343
+ };
3344
+
3345
+ helpers$1.extend(Element.prototype, {
3346
+ _type: undefined,
3347
+
3348
+ initialize: function() {
3349
+ this.hidden = false;
3350
+ },
3351
+
3352
+ pivot: function() {
3353
+ var me = this;
3354
+ if (!me._view) {
3355
+ me._view = helpers$1.extend({}, me._model);
3356
+ }
3357
+ me._start = {};
3358
+ return me;
3359
+ },
3360
+
3361
+ transition: function(ease) {
3362
+ var me = this;
3363
+ var model = me._model;
3364
+ var start = me._start;
3365
+ var view = me._view;
3366
+
3367
+ // No animation -> No Transition
3368
+ if (!model || ease === 1) {
3369
+ me._view = helpers$1.extend({}, model);
3370
+ me._start = null;
3371
+ return me;
3372
+ }
3373
+
3374
+ if (!view) {
3375
+ view = me._view = {};
3376
+ }
3377
+
3378
+ if (!start) {
3379
+ start = me._start = {};
3380
+ }
3381
+
3382
+ interpolate(start, view, model, ease);
3383
+
3384
+ return me;
3385
+ },
3386
+
3387
+ tooltipPosition: function() {
3388
+ return {
3389
+ x: this._model.x,
3390
+ y: this._model.y
3391
+ };
3392
+ },
3393
+
3394
+ hasValue: function() {
3395
+ return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);
3396
+ }
3397
+ });
3398
+
3399
+ Element.extend = helpers$1.inherits;
3400
+
3401
+ var core_element = Element;
2242
3402
 
2243
- /**
2244
- * Returns true if the `a0` and `a1` arrays have the same content, else returns false.
2245
- * @see https://stackoverflow.com/a/14853974
2246
- * @param {Array} a0 - The array to compare
2247
- * @param {Array} a1 - The array to compare
2248
- * @returns {boolean}
2249
- */
2250
- arrayEquals: function(a0, a1) {
2251
- var i, ilen, v0, v1;
3403
+ var exports$3 = core_element.extend({
3404
+ chart: null, // the animation associated chart instance
3405
+ currentStep: 0, // the current animation step
3406
+ numSteps: 60, // default number of steps
3407
+ easing: '', // the easing to use for this animation
3408
+ render: null, // render function used by the animation service
3409
+
3410
+ onAnimationProgress: null, // user specified callback to fire on each step of the animation
3411
+ onAnimationComplete: null, // user specified callback to fire when the animation finishes
3412
+ });
3413
+
3414
+ var core_animation = exports$3;
3415
+
3416
+ // DEPRECATIONS
3417
+
3418
+ /**
3419
+ * Provided for backward compatibility, use Chart.Animation instead
3420
+ * @prop Chart.Animation#animationObject
3421
+ * @deprecated since version 2.6.0
3422
+ * @todo remove at version 3
3423
+ */
3424
+ Object.defineProperty(exports$3.prototype, 'animationObject', {
3425
+ get: function() {
3426
+ return this;
3427
+ }
3428
+ });
3429
+
3430
+ /**
3431
+ * Provided for backward compatibility, use Chart.Animation#chart instead
3432
+ * @prop Chart.Animation#chartInstance
3433
+ * @deprecated since version 2.6.0
3434
+ * @todo remove at version 3
3435
+ */
3436
+ Object.defineProperty(exports$3.prototype, 'chartInstance', {
3437
+ get: function() {
3438
+ return this.chart;
3439
+ },
3440
+ set: function(value) {
3441
+ this.chart = value;
3442
+ }
3443
+ });
2252
3444
 
2253
- if (!a0 || !a1 || a0.length !== a1.length) {
2254
- return false;
2255
- }
3445
+ core_defaults._set('global', {
3446
+ animation: {
3447
+ duration: 1000,
3448
+ easing: 'easeOutQuart',
3449
+ onProgress: helpers$1.noop,
3450
+ onComplete: helpers$1.noop
3451
+ }
3452
+ });
3453
+
3454
+ var core_animations = {
3455
+ animations: [],
3456
+ request: null,
3457
+
3458
+ /**
3459
+ * @param {Chart} chart - The chart to animate.
3460
+ * @param {Chart.Animation} animation - The animation that we will animate.
3461
+ * @param {number} duration - The animation duration in ms.
3462
+ * @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions
3463
+ */
3464
+ addAnimation: function(chart, animation, duration, lazy) {
3465
+ var animations = this.animations;
3466
+ var i, ilen;
3467
+
3468
+ animation.chart = chart;
3469
+ animation.startTime = Date.now();
3470
+ animation.duration = duration;
3471
+
3472
+ if (!lazy) {
3473
+ chart.animating = true;
3474
+ }
3475
+
3476
+ for (i = 0, ilen = animations.length; i < ilen; ++i) {
3477
+ if (animations[i].chart === chart) {
3478
+ animations[i] = animation;
3479
+ return;
3480
+ }
3481
+ }
3482
+
3483
+ animations.push(animation);
3484
+
3485
+ // If there are no animations queued, manually kickstart a digest, for lack of a better word
3486
+ if (animations.length === 1) {
3487
+ this.requestAnimationFrame();
3488
+ }
3489
+ },
3490
+
3491
+ cancelAnimation: function(chart) {
3492
+ var index = helpers$1.findIndex(this.animations, function(animation) {
3493
+ return animation.chart === chart;
3494
+ });
3495
+
3496
+ if (index !== -1) {
3497
+ this.animations.splice(index, 1);
3498
+ chart.animating = false;
3499
+ }
3500
+ },
3501
+
3502
+ requestAnimationFrame: function() {
3503
+ var me = this;
3504
+ if (me.request === null) {
3505
+ // Skip animation frame requests until the active one is executed.
3506
+ // This can happen when processing mouse events, e.g. 'mousemove'
3507
+ // and 'mouseout' events will trigger multiple renders.
3508
+ me.request = helpers$1.requestAnimFrame.call(window, function() {
3509
+ me.request = null;
3510
+ me.startDigest();
3511
+ });
3512
+ }
3513
+ },
3514
+
3515
+ /**
3516
+ * @private
3517
+ */
3518
+ startDigest: function() {
3519
+ var me = this;
3520
+
3521
+ me.advance();
3522
+
3523
+ // Do we have more stuff to animate?
3524
+ if (me.animations.length > 0) {
3525
+ me.requestAnimationFrame();
3526
+ }
3527
+ },
3528
+
3529
+ /**
3530
+ * @private
3531
+ */
3532
+ advance: function() {
3533
+ var animations = this.animations;
3534
+ var animation, chart, numSteps, nextStep;
3535
+ var i = 0;
3536
+
3537
+ // 1 animation per chart, so we are looping charts here
3538
+ while (i < animations.length) {
3539
+ animation = animations[i];
3540
+ chart = animation.chart;
3541
+ numSteps = animation.numSteps;
3542
+
3543
+ // Make sure that currentStep starts at 1
3544
+ // https://github.com/chartjs/Chart.js/issues/6104
3545
+ nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;
3546
+ animation.currentStep = Math.min(nextStep, numSteps);
3547
+
3548
+ helpers$1.callback(animation.render, [chart, animation], chart);
3549
+ helpers$1.callback(animation.onAnimationProgress, [animation], chart);
3550
+
3551
+ if (animation.currentStep >= numSteps) {
3552
+ helpers$1.callback(animation.onAnimationComplete, [animation], chart);
3553
+ chart.animating = false;
3554
+ animations.splice(i, 1);
3555
+ } else {
3556
+ ++i;
3557
+ }
3558
+ }
3559
+ }
3560
+ };
2256
3561
 
2257
- for (i = 0, ilen = a0.length; i < ilen; ++i) {
2258
- v0 = a0[i];
2259
- v1 = a1[i];
3562
+ var resolve = helpers$1.options.resolve;
3563
+
3564
+ var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
3565
+
3566
+ /**
3567
+ * Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',
3568
+ * 'unshift') and notify the listener AFTER the array has been altered. Listeners are
3569
+ * called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.
3570
+ */
3571
+ function listenArrayEvents(array, listener) {
3572
+ if (array._chartjs) {
3573
+ array._chartjs.listeners.push(listener);
3574
+ return;
3575
+ }
3576
+
3577
+ Object.defineProperty(array, '_chartjs', {
3578
+ configurable: true,
3579
+ enumerable: false,
3580
+ value: {
3581
+ listeners: [listener]
3582
+ }
3583
+ });
3584
+
3585
+ arrayEvents.forEach(function(key) {
3586
+ var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);
3587
+ var base = array[key];
3588
+
3589
+ Object.defineProperty(array, key, {
3590
+ configurable: true,
3591
+ enumerable: false,
3592
+ value: function() {
3593
+ var args = Array.prototype.slice.call(arguments);
3594
+ var res = base.apply(this, args);
3595
+
3596
+ helpers$1.each(array._chartjs.listeners, function(object) {
3597
+ if (typeof object[method] === 'function') {
3598
+ object[method].apply(object, args);
3599
+ }
3600
+ });
3601
+
3602
+ return res;
3603
+ }
3604
+ });
3605
+ });
3606
+ }
3607
+
3608
+ /**
3609
+ * Removes the given array event listener and cleanup extra attached properties (such as
3610
+ * the _chartjs stub and overridden methods) if array doesn't have any more listeners.
3611
+ */
3612
+ function unlistenArrayEvents(array, listener) {
3613
+ var stub = array._chartjs;
3614
+ if (!stub) {
3615
+ return;
3616
+ }
3617
+
3618
+ var listeners = stub.listeners;
3619
+ var index = listeners.indexOf(listener);
3620
+ if (index !== -1) {
3621
+ listeners.splice(index, 1);
3622
+ }
3623
+
3624
+ if (listeners.length > 0) {
3625
+ return;
3626
+ }
3627
+
3628
+ arrayEvents.forEach(function(key) {
3629
+ delete array[key];
3630
+ });
3631
+
3632
+ delete array._chartjs;
3633
+ }
3634
+
3635
+ // Base class for all dataset controllers (line, bar, etc)
3636
+ var DatasetController = function(chart, datasetIndex) {
3637
+ this.initialize(chart, datasetIndex);
3638
+ };
3639
+
3640
+ helpers$1.extend(DatasetController.prototype, {
3641
+
3642
+ /**
3643
+ * Element type used to generate a meta dataset (e.g. Chart.element.Line).
3644
+ * @type {Chart.core.element}
3645
+ */
3646
+ datasetElementType: null,
3647
+
3648
+ /**
3649
+ * Element type used to generate a meta data (e.g. Chart.element.Point).
3650
+ * @type {Chart.core.element}
3651
+ */
3652
+ dataElementType: null,
3653
+
3654
+ /**
3655
+ * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
3656
+ * A derived controller may override this to resolve controller-specific options.
3657
+ * The keys defined here are for backward compatibility for legend styles.
3658
+ * @private
3659
+ */
3660
+ _datasetElementOptions: [
3661
+ 'backgroundColor',
3662
+ 'borderCapStyle',
3663
+ 'borderColor',
3664
+ 'borderDash',
3665
+ 'borderDashOffset',
3666
+ 'borderJoinStyle',
3667
+ 'borderWidth'
3668
+ ],
3669
+
3670
+ /**
3671
+ * Data element option keys to be resolved in _resolveDataElementOptions.
3672
+ * A derived controller may override this to resolve controller-specific options.
3673
+ * The keys defined here are for backward compatibility for legend styles.
3674
+ * @private
3675
+ */
3676
+ _dataElementOptions: [
3677
+ 'backgroundColor',
3678
+ 'borderColor',
3679
+ 'borderWidth',
3680
+ 'pointStyle'
3681
+ ],
3682
+
3683
+ initialize: function(chart, datasetIndex) {
3684
+ var me = this;
3685
+ me.chart = chart;
3686
+ me.index = datasetIndex;
3687
+ me.linkScales();
3688
+ me.addElements();
3689
+ me._type = me.getMeta().type;
3690
+ },
3691
+
3692
+ updateIndex: function(datasetIndex) {
3693
+ this.index = datasetIndex;
3694
+ },
3695
+
3696
+ linkScales: function() {
3697
+ var me = this;
3698
+ var meta = me.getMeta();
3699
+ var chart = me.chart;
3700
+ var scales = chart.scales;
3701
+ var dataset = me.getDataset();
3702
+ var scalesOpts = chart.options.scales;
3703
+
3704
+ if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {
3705
+ meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;
3706
+ }
3707
+ if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {
3708
+ meta.yAxisID = dataset.yAxisID || scalesOpts.yAxes[0].id;
3709
+ }
3710
+ },
3711
+
3712
+ getDataset: function() {
3713
+ return this.chart.data.datasets[this.index];
3714
+ },
3715
+
3716
+ getMeta: function() {
3717
+ return this.chart.getDatasetMeta(this.index);
3718
+ },
3719
+
3720
+ getScaleForId: function(scaleID) {
3721
+ return this.chart.scales[scaleID];
3722
+ },
3723
+
3724
+ /**
3725
+ * @private
3726
+ */
3727
+ _getValueScaleId: function() {
3728
+ return this.getMeta().yAxisID;
3729
+ },
3730
+
3731
+ /**
3732
+ * @private
3733
+ */
3734
+ _getIndexScaleId: function() {
3735
+ return this.getMeta().xAxisID;
3736
+ },
3737
+
3738
+ /**
3739
+ * @private
3740
+ */
3741
+ _getValueScale: function() {
3742
+ return this.getScaleForId(this._getValueScaleId());
3743
+ },
3744
+
3745
+ /**
3746
+ * @private
3747
+ */
3748
+ _getIndexScale: function() {
3749
+ return this.getScaleForId(this._getIndexScaleId());
3750
+ },
3751
+
3752
+ reset: function() {
3753
+ this._update(true);
3754
+ },
3755
+
3756
+ /**
3757
+ * @private
3758
+ */
3759
+ destroy: function() {
3760
+ if (this._data) {
3761
+ unlistenArrayEvents(this._data, this);
3762
+ }
3763
+ },
3764
+
3765
+ createMetaDataset: function() {
3766
+ var me = this;
3767
+ var type = me.datasetElementType;
3768
+ return type && new type({
3769
+ _chart: me.chart,
3770
+ _datasetIndex: me.index
3771
+ });
3772
+ },
3773
+
3774
+ createMetaData: function(index) {
3775
+ var me = this;
3776
+ var type = me.dataElementType;
3777
+ return type && new type({
3778
+ _chart: me.chart,
3779
+ _datasetIndex: me.index,
3780
+ _index: index
3781
+ });
3782
+ },
3783
+
3784
+ addElements: function() {
3785
+ var me = this;
3786
+ var meta = me.getMeta();
3787
+ var data = me.getDataset().data || [];
3788
+ var metaData = meta.data;
3789
+ var i, ilen;
3790
+
3791
+ for (i = 0, ilen = data.length; i < ilen; ++i) {
3792
+ metaData[i] = metaData[i] || me.createMetaData(i);
3793
+ }
3794
+
3795
+ meta.dataset = meta.dataset || me.createMetaDataset();
3796
+ },
3797
+
3798
+ addElementAndReset: function(index) {
3799
+ var element = this.createMetaData(index);
3800
+ this.getMeta().data.splice(index, 0, element);
3801
+ this.updateElement(element, index, true);
3802
+ },
3803
+
3804
+ buildOrUpdateElements: function() {
3805
+ var me = this;
3806
+ var dataset = me.getDataset();
3807
+ var data = dataset.data || (dataset.data = []);
3808
+
3809
+ // In order to correctly handle data addition/deletion animation (an thus simulate
3810
+ // real-time charts), we need to monitor these data modifications and synchronize
3811
+ // the internal meta data accordingly.
3812
+ if (me._data !== data) {
3813
+ if (me._data) {
3814
+ // This case happens when the user replaced the data array instance.
3815
+ unlistenArrayEvents(me._data, me);
3816
+ }
3817
+
3818
+ if (data && Object.isExtensible(data)) {
3819
+ listenArrayEvents(data, me);
3820
+ }
3821
+ me._data = data;
3822
+ }
3823
+
3824
+ // Re-sync meta data in case the user replaced the data array or if we missed
3825
+ // any updates and so make sure that we handle number of datapoints changing.
3826
+ me.resyncElements();
3827
+ },
3828
+
3829
+ /**
3830
+ * Returns the merged user-supplied and default dataset-level options
3831
+ * @private
3832
+ */
3833
+ _configure: function() {
3834
+ var me = this;
3835
+ me._config = helpers$1.merge(Object.create(null), [
3836
+ me.chart.options.datasets[me._type],
3837
+ me.getDataset(),
3838
+ ], {
3839
+ merger: function(key, target, source) {
3840
+ if (key !== '_meta' && key !== 'data') {
3841
+ helpers$1._merger(key, target, source);
3842
+ }
3843
+ }
3844
+ });
3845
+ },
3846
+
3847
+ _update: function(reset) {
3848
+ var me = this;
3849
+ me._configure();
3850
+ me._cachedDataOpts = null;
3851
+ me.update(reset);
3852
+ },
3853
+
3854
+ update: helpers$1.noop,
3855
+
3856
+ transition: function(easingValue) {
3857
+ var meta = this.getMeta();
3858
+ var elements = meta.data || [];
3859
+ var ilen = elements.length;
3860
+ var i = 0;
3861
+
3862
+ for (; i < ilen; ++i) {
3863
+ elements[i].transition(easingValue);
3864
+ }
3865
+
3866
+ if (meta.dataset) {
3867
+ meta.dataset.transition(easingValue);
3868
+ }
3869
+ },
3870
+
3871
+ draw: function() {
3872
+ var meta = this.getMeta();
3873
+ var elements = meta.data || [];
3874
+ var ilen = elements.length;
3875
+ var i = 0;
3876
+
3877
+ if (meta.dataset) {
3878
+ meta.dataset.draw();
3879
+ }
3880
+
3881
+ for (; i < ilen; ++i) {
3882
+ elements[i].draw();
3883
+ }
3884
+ },
3885
+
3886
+ /**
3887
+ * Returns a set of predefined style properties that should be used to represent the dataset
3888
+ * or the data if the index is specified
3889
+ * @param {number} index - data index
3890
+ * @return {IStyleInterface} style object
3891
+ */
3892
+ getStyle: function(index) {
3893
+ var me = this;
3894
+ var meta = me.getMeta();
3895
+ var dataset = meta.dataset;
3896
+ var style;
3897
+
3898
+ me._configure();
3899
+ if (dataset && index === undefined) {
3900
+ style = me._resolveDatasetElementOptions(dataset || {});
3901
+ } else {
3902
+ index = index || 0;
3903
+ style = me._resolveDataElementOptions(meta.data[index] || {}, index);
3904
+ }
3905
+
3906
+ if (style.fill === false || style.fill === null) {
3907
+ style.backgroundColor = style.borderColor;
3908
+ }
3909
+
3910
+ return style;
3911
+ },
3912
+
3913
+ /**
3914
+ * @private
3915
+ */
3916
+ _resolveDatasetElementOptions: function(element, hover) {
3917
+ var me = this;
3918
+ var chart = me.chart;
3919
+ var datasetOpts = me._config;
3920
+ var custom = element.custom || {};
3921
+ var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
3922
+ var elementOptions = me._datasetElementOptions;
3923
+ var values = {};
3924
+ var i, ilen, key, readKey;
3925
+
3926
+ // Scriptable options
3927
+ var context = {
3928
+ chart: chart,
3929
+ dataset: me.getDataset(),
3930
+ datasetIndex: me.index,
3931
+ hover: hover
3932
+ };
3933
+
3934
+ for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
3935
+ key = elementOptions[i];
3936
+ readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
3937
+ values[key] = resolve([
3938
+ custom[readKey],
3939
+ datasetOpts[readKey],
3940
+ options[readKey]
3941
+ ], context);
3942
+ }
3943
+
3944
+ return values;
3945
+ },
3946
+
3947
+ /**
3948
+ * @private
3949
+ */
3950
+ _resolveDataElementOptions: function(element, index) {
3951
+ var me = this;
3952
+ var custom = element && element.custom;
3953
+ var cached = me._cachedDataOpts;
3954
+ if (cached && !custom) {
3955
+ return cached;
3956
+ }
3957
+ var chart = me.chart;
3958
+ var datasetOpts = me._config;
3959
+ var options = chart.options.elements[me.dataElementType.prototype._type] || {};
3960
+ var elementOptions = me._dataElementOptions;
3961
+ var values = {};
3962
+
3963
+ // Scriptable options
3964
+ var context = {
3965
+ chart: chart,
3966
+ dataIndex: index,
3967
+ dataset: me.getDataset(),
3968
+ datasetIndex: me.index
3969
+ };
3970
+
3971
+ // `resolve` sets cacheable to `false` if any option is indexed or scripted
3972
+ var info = {cacheable: !custom};
3973
+
3974
+ var keys, i, ilen, key;
3975
+
3976
+ custom = custom || {};
3977
+
3978
+ if (helpers$1.isArray(elementOptions)) {
3979
+ for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
3980
+ key = elementOptions[i];
3981
+ values[key] = resolve([
3982
+ custom[key],
3983
+ datasetOpts[key],
3984
+ options[key]
3985
+ ], context, index, info);
3986
+ }
3987
+ } else {
3988
+ keys = Object.keys(elementOptions);
3989
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
3990
+ key = keys[i];
3991
+ values[key] = resolve([
3992
+ custom[key],
3993
+ datasetOpts[elementOptions[key]],
3994
+ datasetOpts[key],
3995
+ options[key]
3996
+ ], context, index, info);
3997
+ }
3998
+ }
3999
+
4000
+ if (info.cacheable) {
4001
+ me._cachedDataOpts = Object.freeze(values);
4002
+ }
4003
+
4004
+ return values;
4005
+ },
4006
+
4007
+ removeHoverStyle: function(element) {
4008
+ helpers$1.merge(element._model, element.$previousStyle || {});
4009
+ delete element.$previousStyle;
4010
+ },
4011
+
4012
+ setHoverStyle: function(element) {
4013
+ var dataset = this.chart.data.datasets[element._datasetIndex];
4014
+ var index = element._index;
4015
+ var custom = element.custom || {};
4016
+ var model = element._model;
4017
+ var getHoverColor = helpers$1.getHoverColor;
4018
+
4019
+ element.$previousStyle = {
4020
+ backgroundColor: model.backgroundColor,
4021
+ borderColor: model.borderColor,
4022
+ borderWidth: model.borderWidth
4023
+ };
4024
+
4025
+ model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);
4026
+ model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);
4027
+ model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);
4028
+ },
4029
+
4030
+ /**
4031
+ * @private
4032
+ */
4033
+ _removeDatasetHoverStyle: function() {
4034
+ var element = this.getMeta().dataset;
4035
+
4036
+ if (element) {
4037
+ this.removeHoverStyle(element);
4038
+ }
4039
+ },
4040
+
4041
+ /**
4042
+ * @private
4043
+ */
4044
+ _setDatasetHoverStyle: function() {
4045
+ var element = this.getMeta().dataset;
4046
+ var prev = {};
4047
+ var i, ilen, key, keys, hoverOptions, model;
4048
+
4049
+ if (!element) {
4050
+ return;
4051
+ }
4052
+
4053
+ model = element._model;
4054
+ hoverOptions = this._resolveDatasetElementOptions(element, true);
4055
+
4056
+ keys = Object.keys(hoverOptions);
4057
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
4058
+ key = keys[i];
4059
+ prev[key] = model[key];
4060
+ model[key] = hoverOptions[key];
4061
+ }
4062
+
4063
+ element.$previousStyle = prev;
4064
+ },
4065
+
4066
+ /**
4067
+ * @private
4068
+ */
4069
+ resyncElements: function() {
4070
+ var me = this;
4071
+ var meta = me.getMeta();
4072
+ var data = me.getDataset().data;
4073
+ var numMeta = meta.data.length;
4074
+ var numData = data.length;
4075
+
4076
+ if (numData < numMeta) {
4077
+ meta.data.splice(numData, numMeta - numData);
4078
+ } else if (numData > numMeta) {
4079
+ me.insertElements(numMeta, numData - numMeta);
4080
+ }
4081
+ },
4082
+
4083
+ /**
4084
+ * @private
4085
+ */
4086
+ insertElements: function(start, count) {
4087
+ for (var i = 0; i < count; ++i) {
4088
+ this.addElementAndReset(start + i);
4089
+ }
4090
+ },
4091
+
4092
+ /**
4093
+ * @private
4094
+ */
4095
+ onDataPush: function() {
4096
+ var count = arguments.length;
4097
+ this.insertElements(this.getDataset().data.length - count, count);
4098
+ },
4099
+
4100
+ /**
4101
+ * @private
4102
+ */
4103
+ onDataPop: function() {
4104
+ this.getMeta().data.pop();
4105
+ },
4106
+
4107
+ /**
4108
+ * @private
4109
+ */
4110
+ onDataShift: function() {
4111
+ this.getMeta().data.shift();
4112
+ },
4113
+
4114
+ /**
4115
+ * @private
4116
+ */
4117
+ onDataSplice: function(start, count) {
4118
+ this.getMeta().data.splice(start, count);
4119
+ this.insertElements(start, arguments.length - 2);
4120
+ },
4121
+
4122
+ /**
4123
+ * @private
4124
+ */
4125
+ onDataUnshift: function() {
4126
+ this.insertElements(0, arguments.length);
4127
+ }
4128
+ });
4129
+
4130
+ DatasetController.extend = helpers$1.inherits;
4131
+
4132
+ var core_datasetController = DatasetController;
2260
4133
 
2261
- if (v0 instanceof Array && v1 instanceof Array) {
2262
- if (!helpers.arrayEquals(v0, v1)) {
2263
- return false;
2264
- }
2265
- } else if (v0 !== v1) {
2266
- // NOTE: two different object instances will never be equal: {x:20} != {x:20}
2267
- return false;
2268
- }
2269
- }
4134
+ var TAU = Math.PI * 2;
4135
+
4136
+ core_defaults._set('global', {
4137
+ elements: {
4138
+ arc: {
4139
+ backgroundColor: core_defaults.global.defaultColor,
4140
+ borderColor: '#fff',
4141
+ borderWidth: 2,
4142
+ borderAlign: 'center'
4143
+ }
4144
+ }
4145
+ });
4146
+
4147
+ function clipArc(ctx, arc) {
4148
+ var startAngle = arc.startAngle;
4149
+ var endAngle = arc.endAngle;
4150
+ var pixelMargin = arc.pixelMargin;
4151
+ var angleMargin = pixelMargin / arc.outerRadius;
4152
+ var x = arc.x;
4153
+ var y = arc.y;
4154
+
4155
+ // Draw an inner border by cliping the arc and drawing a double-width border
4156
+ // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
4157
+ ctx.beginPath();
4158
+ ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);
4159
+ if (arc.innerRadius > pixelMargin) {
4160
+ angleMargin = pixelMargin / arc.innerRadius;
4161
+ ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);
4162
+ } else {
4163
+ ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
4164
+ }
4165
+ ctx.closePath();
4166
+ ctx.clip();
4167
+ }
4168
+
4169
+ function drawFullCircleBorders(ctx, vm, arc, inner) {
4170
+ var endAngle = arc.endAngle;
4171
+ var i;
4172
+
4173
+ if (inner) {
4174
+ arc.endAngle = arc.startAngle + TAU;
4175
+ clipArc(ctx, arc);
4176
+ arc.endAngle = endAngle;
4177
+ if (arc.endAngle === arc.startAngle && arc.fullCircles) {
4178
+ arc.endAngle += TAU;
4179
+ arc.fullCircles--;
4180
+ }
4181
+ }
4182
+
4183
+ ctx.beginPath();
4184
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);
4185
+ for (i = 0; i < arc.fullCircles; ++i) {
4186
+ ctx.stroke();
4187
+ }
4188
+
4189
+ ctx.beginPath();
4190
+ ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);
4191
+ for (i = 0; i < arc.fullCircles; ++i) {
4192
+ ctx.stroke();
4193
+ }
4194
+ }
4195
+
4196
+ function drawBorder(ctx, vm, arc) {
4197
+ var inner = vm.borderAlign === 'inner';
4198
+
4199
+ if (inner) {
4200
+ ctx.lineWidth = vm.borderWidth * 2;
4201
+ ctx.lineJoin = 'round';
4202
+ } else {
4203
+ ctx.lineWidth = vm.borderWidth;
4204
+ ctx.lineJoin = 'bevel';
4205
+ }
4206
+
4207
+ if (arc.fullCircles) {
4208
+ drawFullCircleBorders(ctx, vm, arc, inner);
4209
+ }
4210
+
4211
+ if (inner) {
4212
+ clipArc(ctx, arc);
4213
+ }
4214
+
4215
+ ctx.beginPath();
4216
+ ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);
4217
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
4218
+ ctx.closePath();
4219
+ ctx.stroke();
4220
+ }
4221
+
4222
+ var element_arc = core_element.extend({
4223
+ _type: 'arc',
4224
+
4225
+ inLabelRange: function(mouseX) {
4226
+ var vm = this._view;
4227
+
4228
+ if (vm) {
4229
+ return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));
4230
+ }
4231
+ return false;
4232
+ },
4233
+
4234
+ inRange: function(chartX, chartY) {
4235
+ var vm = this._view;
4236
+
4237
+ if (vm) {
4238
+ var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
4239
+ var angle = pointRelativePosition.angle;
4240
+ var distance = pointRelativePosition.distance;
4241
+
4242
+ // Sanitise angle range
4243
+ var startAngle = vm.startAngle;
4244
+ var endAngle = vm.endAngle;
4245
+ while (endAngle < startAngle) {
4246
+ endAngle += TAU;
4247
+ }
4248
+ while (angle > endAngle) {
4249
+ angle -= TAU;
4250
+ }
4251
+ while (angle < startAngle) {
4252
+ angle += TAU;
4253
+ }
4254
+
4255
+ // Check if within the range of the open/close angle
4256
+ var betweenAngles = (angle >= startAngle && angle <= endAngle);
4257
+ var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);
4258
+
4259
+ return (betweenAngles && withinRadius);
4260
+ }
4261
+ return false;
4262
+ },
4263
+
4264
+ getCenterPoint: function() {
4265
+ var vm = this._view;
4266
+ var halfAngle = (vm.startAngle + vm.endAngle) / 2;
4267
+ var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;
4268
+ return {
4269
+ x: vm.x + Math.cos(halfAngle) * halfRadius,
4270
+ y: vm.y + Math.sin(halfAngle) * halfRadius
4271
+ };
4272
+ },
4273
+
4274
+ getArea: function() {
4275
+ var vm = this._view;
4276
+ return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));
4277
+ },
4278
+
4279
+ tooltipPosition: function() {
4280
+ var vm = this._view;
4281
+ var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);
4282
+ var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;
4283
+
4284
+ return {
4285
+ x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),
4286
+ y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)
4287
+ };
4288
+ },
4289
+
4290
+ draw: function() {
4291
+ var ctx = this._chart.ctx;
4292
+ var vm = this._view;
4293
+ var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
4294
+ var arc = {
4295
+ x: vm.x,
4296
+ y: vm.y,
4297
+ innerRadius: vm.innerRadius,