chartkick 3.2.1 → 3.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chartkick might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 93ec8731d7c59fefb8a68177487d611056e7b97ad239d71fb40e2fbe3ecb3765
4
- data.tar.gz: 188133762bb0f53b70bd5a4bde03f8fef59233affae22f007908b1f9effd7272
3
+ metadata.gz: f70f9ad5ba0fe8ecf0c71ee091f2a16286d4fc954cd66bb4ef7374f754ddb5dc
4
+ data.tar.gz: 39aada894a02bed115039097a4471470797631d1fc166d068db9baf53fdb9cd2
5
5
  SHA512:
6
- metadata.gz: d88b8cd9d7a5afef0a372a52c2b50e6833a445f3824ad14d00645d558546db8c1b3396c6a4c970510404eaa33bbae0bf816a582f77576d065f1e17e7ab5b7e59
7
- data.tar.gz: 63bc3b1d692d0fcaff545e326b632fd2f59cc71ff41bf414fa6df2568c7a712b7cdc1a53dd4a50244c5a80bce313c5ef6f37c72e4828f29bfc74be64850e2046
6
+ metadata.gz: 4628b22ac39ba250e9d3c6bb7aa911aa3f711d0e7be9fb8d6a01f6d8d97ddb85c081dc3562a88cf5009becd60e52e31496004a3dbceb48566fa607aa5185b22e
7
+ data.tar.gz: 4225aa0a1c64507f2d182d40038afe951249fdcc29a584bde42660ed9e65c7397eb7a7ef627350508558915fc2b3b7dbdc046ce2931f0f76a4cdbd11d6da155b
@@ -1,3 +1,8 @@
1
+ ## 3.2.2
2
+
3
+ - Updated Chartkick.js to 3.1.3
4
+ - Updated Chart.js to 2.9.1
5
+
1
6
  ## 3.2.1
2
7
 
3
8
  - Updated Chartkick.js to 3.1.1
@@ -1,3 +1,3 @@
1
1
  module Chartkick
2
- VERSION = "3.2.1"
2
+ VERSION = "3.2.2"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Chart.js v2.8.0
2
+ * Chart.js v2.9.1
3
3
  * https://www.chartjs.org
4
4
  * (c) 2019 Chart.js Contributors
5
5
  * Released under the MIT License
@@ -7,8 +7,8 @@
7
7
  (function (global, factory) {
8
8
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
9
9
  typeof define === 'function' && define.amd ? define(factory) :
10
- (global.Chart = factory());
11
- }(this, (function () { 'use strict';
10
+ (global = global || self, global.Chart = factory());
11
+ }(this, function () { 'use strict';
12
12
 
13
13
  /* MIT license */
14
14
 
@@ -1950,14 +1950,12 @@ var helpers = {
1950
1950
  * @param {object} argN - Additional objects containing properties to merge in target.
1951
1951
  * @returns {object} The `target` object.
1952
1952
  */
1953
- extend: function(target) {
1954
- var setFn = function(value, key) {
1955
- target[key] = value;
1956
- };
1957
- for (var i = 1, ilen = arguments.length; i < ilen; ++i) {
1958
- helpers.each(arguments[i], setFn);
1959
- }
1960
- return target;
1953
+ extend: Object.assign || function(target) {
1954
+ return helpers.merge(target, [].slice.call(arguments, 1), {
1955
+ merger: function(key, dst, src) {
1956
+ dst[key] = src[key];
1957
+ }
1958
+ });
1961
1959
  },
1962
1960
 
1963
1961
  /**
@@ -1983,6 +1981,13 @@ var helpers = {
1983
1981
 
1984
1982
  ChartElement.__super__ = me.prototype;
1985
1983
  return ChartElement;
1984
+ },
1985
+
1986
+ _deprecated: function(scope, value, previous, current) {
1987
+ if (value !== undefined) {
1988
+ console.warn(scope + ': "' + previous +
1989
+ '" is deprecated. Please use "' + current + '" instead');
1990
+ }
1986
1991
  }
1987
1992
  };
1988
1993
 
@@ -2344,7 +2349,11 @@ var exports$1 = {
2344
2349
  if (style && typeof style === 'object') {
2345
2350
  type = style.toString();
2346
2351
  if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
2347
- ctx.drawImage(style, x - style.width / 2, y - style.height / 2, style.width, style.height);
2352
+ ctx.save();
2353
+ ctx.translate(x, y);
2354
+ ctx.rotate(rad);
2355
+ ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
2356
+ ctx.restore();
2348
2357
  return;
2349
2358
  }
2350
2359
  }
@@ -2536,6 +2545,8 @@ var defaults = {
2536
2545
  }
2537
2546
  };
2538
2547
 
2548
+ // TODO(v3): remove 'global' from namespace. all default are global and
2549
+ // there's inconsistency around which options are under 'global'
2539
2550
  defaults._set('global', {
2540
2551
  defaultColor: 'rgba(0,0,0,0.1)',
2541
2552
  defaultFontColor: '#666',
@@ -2660,9 +2671,12 @@ var helpers_options = {
2660
2671
  * is called with `context` as first argument and the result becomes the new input.
2661
2672
  * @param {number} [index] - If defined and the current value is an array, the value
2662
2673
  * at `index` become the new input.
2674
+ * @param {object} [info] - object to return information about resolution in
2675
+ * @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.
2663
2676
  * @since 2.7.0
2664
2677
  */
2665
- resolve: function(inputs, context, index) {
2678
+ resolve: function(inputs, context, index, info) {
2679
+ var cacheable = true;
2666
2680
  var i, ilen, value;
2667
2681
 
2668
2682
  for (i = 0, ilen = inputs.length; i < ilen; ++i) {
@@ -2672,24 +2686,161 @@ var helpers_options = {
2672
2686
  }
2673
2687
  if (context !== undefined && typeof value === 'function') {
2674
2688
  value = value(context);
2689
+ cacheable = false;
2675
2690
  }
2676
2691
  if (index !== undefined && helpers_core.isArray(value)) {
2677
2692
  value = value[index];
2693
+ cacheable = false;
2678
2694
  }
2679
2695
  if (value !== undefined) {
2696
+ if (info && !cacheable) {
2697
+ info.cacheable = false;
2698
+ }
2680
2699
  return value;
2681
2700
  }
2682
2701
  }
2683
2702
  }
2684
2703
  };
2685
2704
 
2705
+ /**
2706
+ * @alias Chart.helpers.math
2707
+ * @namespace
2708
+ */
2709
+ var exports$2 = {
2710
+ /**
2711
+ * Returns an array of factors sorted from 1 to sqrt(value)
2712
+ * @private
2713
+ */
2714
+ _factorize: function(value) {
2715
+ var result = [];
2716
+ var sqrt = Math.sqrt(value);
2717
+ var i;
2718
+
2719
+ for (i = 1; i < sqrt; i++) {
2720
+ if (value % i === 0) {
2721
+ result.push(i);
2722
+ result.push(value / i);
2723
+ }
2724
+ }
2725
+ if (sqrt === (sqrt | 0)) { // if value is a square number
2726
+ result.push(sqrt);
2727
+ }
2728
+
2729
+ result.sort(function(a, b) {
2730
+ return a - b;
2731
+ }).pop();
2732
+ return result;
2733
+ },
2734
+
2735
+ log10: Math.log10 || function(x) {
2736
+ var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.
2737
+ // Check for whole powers of 10,
2738
+ // which due to floating point rounding error should be corrected.
2739
+ var powerOf10 = Math.round(exponent);
2740
+ var isPowerOf10 = x === Math.pow(10, powerOf10);
2741
+
2742
+ return isPowerOf10 ? powerOf10 : exponent;
2743
+ }
2744
+ };
2745
+
2746
+ var helpers_math = exports$2;
2747
+
2748
+ // DEPRECATIONS
2749
+
2750
+ /**
2751
+ * Provided for backward compatibility, use Chart.helpers.math.log10 instead.
2752
+ * @namespace Chart.helpers.log10
2753
+ * @deprecated since version 2.9.0
2754
+ * @todo remove at version 3
2755
+ * @private
2756
+ */
2757
+ helpers_core.log10 = exports$2.log10;
2758
+
2759
+ var getRtlAdapter = function(rectX, width) {
2760
+ return {
2761
+ x: function(x) {
2762
+ return rectX + rectX + width - x;
2763
+ },
2764
+ setWidth: function(w) {
2765
+ width = w;
2766
+ },
2767
+ textAlign: function(align) {
2768
+ if (align === 'center') {
2769
+ return align;
2770
+ }
2771
+ return align === 'right' ? 'left' : 'right';
2772
+ },
2773
+ xPlus: function(x, value) {
2774
+ return x - value;
2775
+ },
2776
+ leftForLtr: function(x, itemWidth) {
2777
+ return x - itemWidth;
2778
+ },
2779
+ };
2780
+ };
2781
+
2782
+ var getLtrAdapter = function() {
2783
+ return {
2784
+ x: function(x) {
2785
+ return x;
2786
+ },
2787
+ setWidth: function(w) { // eslint-disable-line no-unused-vars
2788
+ },
2789
+ textAlign: function(align) {
2790
+ return align;
2791
+ },
2792
+ xPlus: function(x, value) {
2793
+ return x + value;
2794
+ },
2795
+ leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars
2796
+ return x;
2797
+ },
2798
+ };
2799
+ };
2800
+
2801
+ var getAdapter = function(rtl, rectX, width) {
2802
+ return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();
2803
+ };
2804
+
2805
+ var overrideTextDirection = function(ctx, direction) {
2806
+ var style, original;
2807
+ if (direction === 'ltr' || direction === 'rtl') {
2808
+ style = ctx.canvas.style;
2809
+ original = [
2810
+ style.getPropertyValue('direction'),
2811
+ style.getPropertyPriority('direction'),
2812
+ ];
2813
+
2814
+ style.setProperty('direction', direction, 'important');
2815
+ ctx.prevTextDirection = original;
2816
+ }
2817
+ };
2818
+
2819
+ var restoreTextDirection = function(ctx) {
2820
+ var original = ctx.prevTextDirection;
2821
+ if (original !== undefined) {
2822
+ delete ctx.prevTextDirection;
2823
+ ctx.canvas.style.setProperty('direction', original[0], original[1]);
2824
+ }
2825
+ };
2826
+
2827
+ var helpers_rtl = {
2828
+ getRtlAdapter: getAdapter,
2829
+ overrideTextDirection: overrideTextDirection,
2830
+ restoreTextDirection: restoreTextDirection,
2831
+ };
2832
+
2686
2833
  var helpers$1 = helpers_core;
2687
2834
  var easing = helpers_easing;
2688
2835
  var canvas = helpers_canvas;
2689
2836
  var options = helpers_options;
2837
+ var math = helpers_math;
2838
+ var rtl = helpers_rtl;
2690
2839
  helpers$1.easing = easing;
2691
2840
  helpers$1.canvas = canvas;
2692
2841
  helpers$1.options = options;
2842
+ helpers$1.math = math;
2843
+ helpers$1.rtl = rtl;
2693
2844
 
2694
2845
  function interpolate(start, view, model, ease) {
2695
2846
  var keys = Object.keys(model);
@@ -2746,6 +2897,7 @@ var Element = function(configuration) {
2746
2897
  };
2747
2898
 
2748
2899
  helpers$1.extend(Element.prototype, {
2900
+ _type: undefined,
2749
2901
 
2750
2902
  initialize: function() {
2751
2903
  this.hidden = false;
@@ -2754,7 +2906,7 @@ helpers$1.extend(Element.prototype, {
2754
2906
  pivot: function() {
2755
2907
  var me = this;
2756
2908
  if (!me._view) {
2757
- me._view = helpers$1.clone(me._model);
2909
+ me._view = helpers$1.extend({}, me._model);
2758
2910
  }
2759
2911
  me._start = {};
2760
2912
  return me;
@@ -2768,7 +2920,7 @@ helpers$1.extend(Element.prototype, {
2768
2920
 
2769
2921
  // No animation -> No Transition
2770
2922
  if (!model || ease === 1) {
2771
- me._view = model;
2923
+ me._view = helpers$1.extend({}, model);
2772
2924
  me._start = null;
2773
2925
  return me;
2774
2926
  }
@@ -2802,7 +2954,7 @@ Element.extend = helpers$1.inherits;
2802
2954
 
2803
2955
  var core_element = Element;
2804
2956
 
2805
- var exports$2 = core_element.extend({
2957
+ var exports$3 = core_element.extend({
2806
2958
  chart: null, // the animation associated chart instance
2807
2959
  currentStep: 0, // the current animation step
2808
2960
  numSteps: 60, // default number of steps
@@ -2813,7 +2965,7 @@ var exports$2 = core_element.extend({
2813
2965
  onAnimationComplete: null, // user specified callback to fire when the animation finishes
2814
2966
  });
2815
2967
 
2816
- var core_animation = exports$2;
2968
+ var core_animation = exports$3;
2817
2969
 
2818
2970
  // DEPRECATIONS
2819
2971
 
@@ -2823,7 +2975,7 @@ var core_animation = exports$2;
2823
2975
  * @deprecated since version 2.6.0
2824
2976
  * @todo remove at version 3
2825
2977
  */
2826
- Object.defineProperty(exports$2.prototype, 'animationObject', {
2978
+ Object.defineProperty(exports$3.prototype, 'animationObject', {
2827
2979
  get: function() {
2828
2980
  return this;
2829
2981
  }
@@ -2835,7 +2987,7 @@ Object.defineProperty(exports$2.prototype, 'animationObject', {
2835
2987
  * @deprecated since version 2.6.0
2836
2988
  * @todo remove at version 3
2837
2989
  */
2838
- Object.defineProperty(exports$2.prototype, 'chartInstance', {
2990
+ Object.defineProperty(exports$3.prototype, 'chartInstance', {
2839
2991
  get: function() {
2840
2992
  return this.chart;
2841
2993
  },
@@ -3053,12 +3205,42 @@ helpers$1.extend(DatasetController.prototype, {
3053
3205
  */
3054
3206
  dataElementType: null,
3055
3207
 
3208
+ /**
3209
+ * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
3210
+ * A derived controller may override this to resolve controller-specific options.
3211
+ * The keys defined here are for backward compatibility for legend styles.
3212
+ * @private
3213
+ */
3214
+ _datasetElementOptions: [
3215
+ 'backgroundColor',
3216
+ 'borderCapStyle',
3217
+ 'borderColor',
3218
+ 'borderDash',
3219
+ 'borderDashOffset',
3220
+ 'borderJoinStyle',
3221
+ 'borderWidth'
3222
+ ],
3223
+
3224
+ /**
3225
+ * Data element option keys to be resolved in _resolveDataElementOptions.
3226
+ * A derived controller may override this to resolve controller-specific options.
3227
+ * The keys defined here are for backward compatibility for legend styles.
3228
+ * @private
3229
+ */
3230
+ _dataElementOptions: [
3231
+ 'backgroundColor',
3232
+ 'borderColor',
3233
+ 'borderWidth',
3234
+ 'pointStyle'
3235
+ ],
3236
+
3056
3237
  initialize: function(chart, datasetIndex) {
3057
3238
  var me = this;
3058
3239
  me.chart = chart;
3059
3240
  me.index = datasetIndex;
3060
3241
  me.linkScales();
3061
3242
  me.addElements();
3243
+ me._type = me.getMeta().type;
3062
3244
  },
3063
3245
 
3064
3246
  updateIndex: function(datasetIndex) {
@@ -3068,13 +3250,16 @@ helpers$1.extend(DatasetController.prototype, {
3068
3250
  linkScales: function() {
3069
3251
  var me = this;
3070
3252
  var meta = me.getMeta();
3253
+ var chart = me.chart;
3254
+ var scales = chart.scales;
3071
3255
  var dataset = me.getDataset();
3256
+ var scalesOpts = chart.options.scales;
3072
3257
 
3073
- if (meta.xAxisID === null || !(meta.xAxisID in me.chart.scales)) {
3074
- meta.xAxisID = dataset.xAxisID || me.chart.options.scales.xAxes[0].id;
3258
+ if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {
3259
+ meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;
3075
3260
  }
3076
- if (meta.yAxisID === null || !(meta.yAxisID in me.chart.scales)) {
3077
- meta.yAxisID = dataset.yAxisID || me.chart.options.scales.yAxes[0].id;
3261
+ if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {
3262
+ meta.yAxisID = dataset.yAxisID || scalesOpts.yAxes[0].id;
3078
3263
  }
3079
3264
  },
3080
3265
 
@@ -3119,7 +3304,7 @@ helpers$1.extend(DatasetController.prototype, {
3119
3304
  },
3120
3305
 
3121
3306
  reset: function() {
3122
- this.update(true);
3307
+ this._update(true);
3123
3308
  },
3124
3309
 
3125
3310
  /**
@@ -3195,6 +3380,31 @@ helpers$1.extend(DatasetController.prototype, {
3195
3380
  me.resyncElements();
3196
3381
  },
3197
3382
 
3383
+ /**
3384
+ * Returns the merged user-supplied and default dataset-level options
3385
+ * @private
3386
+ */
3387
+ _configure: function() {
3388
+ var me = this;
3389
+ me._config = helpers$1.merge({}, [
3390
+ me.chart.options.datasets[me._type],
3391
+ me.getDataset(),
3392
+ ], {
3393
+ merger: function(key, target, source) {
3394
+ if (key !== '_meta' && key !== 'data') {
3395
+ helpers$1._merger(key, target, source);
3396
+ }
3397
+ }
3398
+ });
3399
+ },
3400
+
3401
+ _update: function(reset) {
3402
+ var me = this;
3403
+ me._configure();
3404
+ me._cachedDataOpts = null;
3405
+ me.update(reset);
3406
+ },
3407
+
3198
3408
  update: helpers$1.noop,
3199
3409
 
3200
3410
  transition: function(easingValue) {
@@ -3227,6 +3437,127 @@ helpers$1.extend(DatasetController.prototype, {
3227
3437
  }
3228
3438
  },
3229
3439
 
3440
+ /**
3441
+ * Returns a set of predefined style properties that should be used to represent the dataset
3442
+ * or the data if the index is specified
3443
+ * @param {number} index - data index
3444
+ * @return {IStyleInterface} style object
3445
+ */
3446
+ getStyle: function(index) {
3447
+ var me = this;
3448
+ var meta = me.getMeta();
3449
+ var dataset = meta.dataset;
3450
+ var style;
3451
+
3452
+ me._configure();
3453
+ if (dataset && index === undefined) {
3454
+ style = me._resolveDatasetElementOptions(dataset || {});
3455
+ } else {
3456
+ index = index || 0;
3457
+ style = me._resolveDataElementOptions(meta.data[index] || {}, index);
3458
+ }
3459
+
3460
+ if (style.fill === false || style.fill === null) {
3461
+ style.backgroundColor = 'rgba(0,0,0,0)';
3462
+ }
3463
+
3464
+ return style;
3465
+ },
3466
+
3467
+ /**
3468
+ * @private
3469
+ */
3470
+ _resolveDatasetElementOptions: function(element, hover) {
3471
+ var me = this;
3472
+ var chart = me.chart;
3473
+ var datasetOpts = me._config;
3474
+ var custom = element.custom || {};
3475
+ var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
3476
+ var elementOptions = me._datasetElementOptions;
3477
+ var values = {};
3478
+ var i, ilen, key, readKey;
3479
+
3480
+ // Scriptable options
3481
+ var context = {
3482
+ chart: chart,
3483
+ dataset: me.getDataset(),
3484
+ datasetIndex: me.index,
3485
+ hover: hover
3486
+ };
3487
+
3488
+ for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
3489
+ key = elementOptions[i];
3490
+ readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;
3491
+ values[key] = resolve([
3492
+ custom[readKey],
3493
+ datasetOpts[readKey],
3494
+ options[readKey]
3495
+ ], context);
3496
+ }
3497
+
3498
+ return values;
3499
+ },
3500
+
3501
+ /**
3502
+ * @private
3503
+ */
3504
+ _resolveDataElementOptions: function(element, index) {
3505
+ var me = this;
3506
+ var custom = element && element.custom;
3507
+ var cached = me._cachedDataOpts;
3508
+ if (cached && !custom) {
3509
+ return cached;
3510
+ }
3511
+ var chart = me.chart;
3512
+ var datasetOpts = me._config;
3513
+ var options = chart.options.elements[me.dataElementType.prototype._type] || {};
3514
+ var elementOptions = me._dataElementOptions;
3515
+ var values = {};
3516
+
3517
+ // Scriptable options
3518
+ var context = {
3519
+ chart: chart,
3520
+ dataIndex: index,
3521
+ dataset: me.getDataset(),
3522
+ datasetIndex: me.index
3523
+ };
3524
+
3525
+ // `resolve` sets cacheable to `false` if any option is indexed or scripted
3526
+ var info = {cacheable: !custom};
3527
+
3528
+ var keys, i, ilen, key;
3529
+
3530
+ custom = custom || {};
3531
+
3532
+ if (helpers$1.isArray(elementOptions)) {
3533
+ for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
3534
+ key = elementOptions[i];
3535
+ values[key] = resolve([
3536
+ custom[key],
3537
+ datasetOpts[key],
3538
+ options[key]
3539
+ ], context, index, info);
3540
+ }
3541
+ } else {
3542
+ keys = Object.keys(elementOptions);
3543
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
3544
+ key = keys[i];
3545
+ values[key] = resolve([
3546
+ custom[key],
3547
+ datasetOpts[elementOptions[key]],
3548
+ datasetOpts[key],
3549
+ options[key]
3550
+ ], context, index, info);
3551
+ }
3552
+ }
3553
+
3554
+ if (info.cacheable) {
3555
+ me._cachedDataOpts = Object.freeze(values);
3556
+ }
3557
+
3558
+ return values;
3559
+ },
3560
+
3230
3561
  removeHoverStyle: function(element) {
3231
3562
  helpers$1.merge(element._model, element.$previousStyle || {});
3232
3563
  delete element.$previousStyle;
@@ -3250,6 +3581,42 @@ helpers$1.extend(DatasetController.prototype, {
3250
3581
  model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);
3251
3582
  },
3252
3583
 
3584
+ /**
3585
+ * @private
3586
+ */
3587
+ _removeDatasetHoverStyle: function() {
3588
+ var element = this.getMeta().dataset;
3589
+
3590
+ if (element) {
3591
+ this.removeHoverStyle(element);
3592
+ }
3593
+ },
3594
+
3595
+ /**
3596
+ * @private
3597
+ */
3598
+ _setDatasetHoverStyle: function() {
3599
+ var element = this.getMeta().dataset;
3600
+ var prev = {};
3601
+ var i, ilen, key, keys, hoverOptions, model;
3602
+
3603
+ if (!element) {
3604
+ return;
3605
+ }
3606
+
3607
+ model = element._model;
3608
+ hoverOptions = this._resolveDatasetElementOptions(element, true);
3609
+
3610
+ keys = Object.keys(hoverOptions);
3611
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
3612
+ key = keys[i];
3613
+ prev[key] = model[key];
3614
+ model[key] = hoverOptions[key];
3615
+ }
3616
+
3617
+ element.$previousStyle = prev;
3618
+ },
3619
+
3253
3620
  /**
3254
3621
  * @private
3255
3622
  */
@@ -3318,6 +3685,8 @@ DatasetController.extend = helpers$1.inherits;
3318
3685
 
3319
3686
  var core_datasetController = DatasetController;
3320
3687
 
3688
+ var TAU = Math.PI * 2;
3689
+
3321
3690
  core_defaults._set('global', {
3322
3691
  elements: {
3323
3692
  arc: {
@@ -3329,7 +3698,84 @@ core_defaults._set('global', {
3329
3698
  }
3330
3699
  });
3331
3700
 
3701
+ function clipArc(ctx, arc) {
3702
+ var startAngle = arc.startAngle;
3703
+ var endAngle = arc.endAngle;
3704
+ var pixelMargin = arc.pixelMargin;
3705
+ var angleMargin = pixelMargin / arc.outerRadius;
3706
+ var x = arc.x;
3707
+ var y = arc.y;
3708
+
3709
+ // Draw an inner border by cliping the arc and drawing a double-width border
3710
+ // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
3711
+ ctx.beginPath();
3712
+ ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);
3713
+ if (arc.innerRadius > pixelMargin) {
3714
+ angleMargin = pixelMargin / arc.innerRadius;
3715
+ ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);
3716
+ } else {
3717
+ ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);
3718
+ }
3719
+ ctx.closePath();
3720
+ ctx.clip();
3721
+ }
3722
+
3723
+ function drawFullCircleBorders(ctx, vm, arc, inner) {
3724
+ var endAngle = arc.endAngle;
3725
+ var i;
3726
+
3727
+ if (inner) {
3728
+ arc.endAngle = arc.startAngle + TAU;
3729
+ clipArc(ctx, arc);
3730
+ arc.endAngle = endAngle;
3731
+ if (arc.endAngle === arc.startAngle && arc.fullCircles) {
3732
+ arc.endAngle += TAU;
3733
+ arc.fullCircles--;
3734
+ }
3735
+ }
3736
+
3737
+ ctx.beginPath();
3738
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);
3739
+ for (i = 0; i < arc.fullCircles; ++i) {
3740
+ ctx.stroke();
3741
+ }
3742
+
3743
+ ctx.beginPath();
3744
+ ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);
3745
+ for (i = 0; i < arc.fullCircles; ++i) {
3746
+ ctx.stroke();
3747
+ }
3748
+ }
3749
+
3750
+ function drawBorder(ctx, vm, arc) {
3751
+ var inner = vm.borderAlign === 'inner';
3752
+
3753
+ if (inner) {
3754
+ ctx.lineWidth = vm.borderWidth * 2;
3755
+ ctx.lineJoin = 'round';
3756
+ } else {
3757
+ ctx.lineWidth = vm.borderWidth;
3758
+ ctx.lineJoin = 'bevel';
3759
+ }
3760
+
3761
+ if (arc.fullCircles) {
3762
+ drawFullCircleBorders(ctx, vm, arc, inner);
3763
+ }
3764
+
3765
+ if (inner) {
3766
+ clipArc(ctx, arc);
3767
+ }
3768
+
3769
+ ctx.beginPath();
3770
+ ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);
3771
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
3772
+ ctx.closePath();
3773
+ ctx.stroke();
3774
+ }
3775
+
3332
3776
  var element_arc = core_element.extend({
3777
+ _type: 'arc',
3778
+
3333
3779
  inLabelRange: function(mouseX) {
3334
3780
  var vm = this._view;
3335
3781
 
@@ -3344,20 +3790,20 @@ var element_arc = core_element.extend({
3344
3790
 
3345
3791
  if (vm) {
3346
3792
  var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});
3347
- var angle = pointRelativePosition.angle;
3793
+ var angle = pointRelativePosition.angle;
3348
3794
  var distance = pointRelativePosition.distance;
3349
3795
 
3350
3796
  // Sanitise angle range
3351
3797
  var startAngle = vm.startAngle;
3352
3798
  var endAngle = vm.endAngle;
3353
3799
  while (endAngle < startAngle) {
3354
- endAngle += 2.0 * Math.PI;
3800
+ endAngle += TAU;
3355
3801
  }
3356
3802
  while (angle > endAngle) {
3357
- angle -= 2.0 * Math.PI;
3803
+ angle -= TAU;
3358
3804
  }
3359
3805
  while (angle < startAngle) {
3360
- angle += 2.0 * Math.PI;
3806
+ angle += TAU;
3361
3807
  }
3362
3808
 
3363
3809
  // Check if within the range of the open/close angle
@@ -3398,51 +3844,44 @@ var element_arc = core_element.extend({
3398
3844
  draw: function() {
3399
3845
  var ctx = this._chart.ctx;
3400
3846
  var vm = this._view;
3401
- var sA = vm.startAngle;
3402
- var eA = vm.endAngle;
3403
3847
  var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
3404
- var angleMargin;
3848
+ var arc = {
3849
+ x: vm.x,
3850
+ y: vm.y,
3851
+ innerRadius: vm.innerRadius,
3852
+ outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),
3853
+ pixelMargin: pixelMargin,
3854
+ startAngle: vm.startAngle,
3855
+ endAngle: vm.endAngle,
3856
+ fullCircles: Math.floor(vm.circumference / TAU)
3857
+ };
3858
+ var i;
3405
3859
 
3406
3860
  ctx.save();
3407
3861
 
3862
+ ctx.fillStyle = vm.backgroundColor;
3863
+ ctx.strokeStyle = vm.borderColor;
3864
+
3865
+ if (arc.fullCircles) {
3866
+ arc.endAngle = arc.startAngle + TAU;
3867
+ ctx.beginPath();
3868
+ ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
3869
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
3870
+ ctx.closePath();
3871
+ for (i = 0; i < arc.fullCircles; ++i) {
3872
+ ctx.fill();
3873
+ }
3874
+ arc.endAngle = arc.startAngle + vm.circumference % TAU;
3875
+ }
3876
+
3408
3877
  ctx.beginPath();
3409
- ctx.arc(vm.x, vm.y, Math.max(vm.outerRadius - pixelMargin, 0), sA, eA);
3410
- ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
3878
+ ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);
3879
+ ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);
3411
3880
  ctx.closePath();
3412
-
3413
- ctx.fillStyle = vm.backgroundColor;
3414
3881
  ctx.fill();
3415
3882
 
3416
3883
  if (vm.borderWidth) {
3417
- if (vm.borderAlign === 'inner') {
3418
- // Draw an inner border by cliping the arc and drawing a double-width border
3419
- // Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
3420
- ctx.beginPath();
3421
- angleMargin = pixelMargin / vm.outerRadius;
3422
- ctx.arc(vm.x, vm.y, vm.outerRadius, sA - angleMargin, eA + angleMargin);
3423
- if (vm.innerRadius > pixelMargin) {
3424
- angleMargin = pixelMargin / vm.innerRadius;
3425
- ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, eA + angleMargin, sA - angleMargin, true);
3426
- } else {
3427
- ctx.arc(vm.x, vm.y, pixelMargin, eA + Math.PI / 2, sA - Math.PI / 2);
3428
- }
3429
- ctx.closePath();
3430
- ctx.clip();
3431
-
3432
- ctx.beginPath();
3433
- ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
3434
- ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
3435
- ctx.closePath();
3436
-
3437
- ctx.lineWidth = vm.borderWidth * 2;
3438
- ctx.lineJoin = 'round';
3439
- } else {
3440
- ctx.lineWidth = vm.borderWidth;
3441
- ctx.lineJoin = 'bevel';
3442
- }
3443
-
3444
- ctx.strokeStyle = vm.borderColor;
3445
- ctx.stroke();
3884
+ drawBorder(ctx, vm, arc);
3446
3885
  }
3447
3886
 
3448
3887
  ctx.restore();
@@ -3471,6 +3910,8 @@ core_defaults._set('global', {
3471
3910
  });
3472
3911
 
3473
3912
  var element_line = core_element.extend({
3913
+ _type: 'line',
3914
+
3474
3915
  draw: function() {
3475
3916
  var me = this;
3476
3917
  var vm = me._view;
@@ -3480,11 +3921,27 @@ var element_line = core_element.extend({
3480
3921
  var globalDefaults = core_defaults.global;
3481
3922
  var globalOptionLineElements = globalDefaults.elements.line;
3482
3923
  var lastDrawnIndex = -1;
3483
- var index, current, previous, currentVM;
3924
+ var closePath = me._loop;
3925
+ var index, previous, currentVM;
3926
+
3927
+ if (!points.length) {
3928
+ return;
3929
+ }
3484
3930
 
3485
- // If we are looping, adding the first point again
3486
- if (me._loop && points.length) {
3487
- points.push(points[0]);
3931
+ if (me._loop) {
3932
+ for (index = 0; index < points.length; ++index) {
3933
+ previous = helpers$1.previousItem(points, index);
3934
+ // If the line has an open path, shift the point array
3935
+ if (!points[index]._view.skip && previous._view.skip) {
3936
+ points = points.slice(index).concat(points.slice(0, index));
3937
+ closePath = spanGaps;
3938
+ break;
3939
+ }
3940
+ }
3941
+ // If the line has a close path, add the first point again
3942
+ if (closePath) {
3943
+ points.push(points[0]);
3944
+ }
3488
3945
  }
3489
3946
 
3490
3947
  ctx.save();
@@ -3504,35 +3961,34 @@ var element_line = core_element.extend({
3504
3961
 
3505
3962
  // Stroke Line
3506
3963
  ctx.beginPath();
3507
- lastDrawnIndex = -1;
3508
3964
 
3509
- for (index = 0; index < points.length; ++index) {
3510
- current = points[index];
3511
- previous = helpers$1.previousItem(points, index);
3512
- currentVM = current._view;
3965
+ // First point moves to it's starting position no matter what
3966
+ currentVM = points[0]._view;
3967
+ if (!currentVM.skip) {
3968
+ ctx.moveTo(currentVM.x, currentVM.y);
3969
+ lastDrawnIndex = 0;
3970
+ }
3513
3971
 
3514
- // First point moves to it's starting position no matter what
3515
- if (index === 0) {
3516
- if (!currentVM.skip) {
3517
- ctx.moveTo(currentVM.x, currentVM.y);
3518
- lastDrawnIndex = index;
3519
- }
3520
- } else {
3521
- previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
3972
+ for (index = 1; index < points.length; ++index) {
3973
+ currentVM = points[index]._view;
3974
+ previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : points[lastDrawnIndex];
3522
3975
 
3523
- if (!currentVM.skip) {
3524
- if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
3525
- // There was a gap and this is the first point after the gap
3526
- ctx.moveTo(currentVM.x, currentVM.y);
3527
- } else {
3528
- // Line to next point
3529
- helpers$1.canvas.lineTo(ctx, previous._view, current._view);
3530
- }
3531
- lastDrawnIndex = index;
3976
+ if (!currentVM.skip) {
3977
+ if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {
3978
+ // There was a gap and this is the first point after the gap
3979
+ ctx.moveTo(currentVM.x, currentVM.y);
3980
+ } else {
3981
+ // Line to next point
3982
+ helpers$1.canvas.lineTo(ctx, previous._view, currentVM);
3532
3983
  }
3984
+ lastDrawnIndex = index;
3533
3985
  }
3534
3986
  }
3535
3987
 
3988
+ if (closePath) {
3989
+ ctx.closePath();
3990
+ }
3991
+
3536
3992
  ctx.stroke();
3537
3993
  ctx.restore();
3538
3994
  }
@@ -3569,6 +4025,8 @@ function yRange(mouseY) {
3569
4025
  }
3570
4026
 
3571
4027
  var element_point = core_element.extend({
4028
+ _type: 'point',
4029
+
3572
4030
  inRange: function(mouseX, mouseY) {
3573
4031
  var vm = this._view;
3574
4032
  return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
@@ -3751,6 +4209,8 @@ function inRange(vm, x, y) {
3751
4209
  }
3752
4210
 
3753
4211
  var element_rectangle = core_element.extend({
4212
+ _type: 'rectangle',
4213
+
3754
4214
  draw: function() {
3755
4215
  var ctx = this._chart.ctx;
3756
4216
  var vm = this._view;
@@ -3840,7 +4300,8 @@ elements.Line = Line;
3840
4300
  elements.Point = Point;
3841
4301
  elements.Rectangle = Rectangle;
3842
4302
 
3843
- var resolve$1 = helpers$1.options.resolve;
4303
+ var deprecated = helpers$1._deprecated;
4304
+ var valueOrDefault$3 = helpers$1.valueOrDefault;
3844
4305
 
3845
4306
  core_defaults._set('bar', {
3846
4307
  hover: {
@@ -3850,8 +4311,6 @@ core_defaults._set('bar', {
3850
4311
  scales: {
3851
4312
  xAxes: [{
3852
4313
  type: 'category',
3853
- categoryPercentage: 0.8,
3854
- barPercentage: 0.9,
3855
4314
  offset: true,
3856
4315
  gridLines: {
3857
4316
  offsetGridLines: true
@@ -3864,22 +4323,30 @@ core_defaults._set('bar', {
3864
4323
  }
3865
4324
  });
3866
4325
 
4326
+ core_defaults._set('global', {
4327
+ datasets: {
4328
+ bar: {
4329
+ categoryPercentage: 0.8,
4330
+ barPercentage: 0.9
4331
+ }
4332
+ }
4333
+ });
4334
+
3867
4335
  /**
3868
4336
  * Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.
3869
4337
  * @private
3870
4338
  */
3871
4339
  function computeMinSampleSize(scale, pixels) {
3872
- var min = scale.isHorizontal() ? scale.width : scale.height;
3873
- var ticks = scale.getTicks();
4340
+ var min = scale._length;
3874
4341
  var prev, curr, i, ilen;
3875
4342
 
3876
4343
  for (i = 1, ilen = pixels.length; i < ilen; ++i) {
3877
4344
  min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));
3878
4345
  }
3879
4346
 
3880
- for (i = 0, ilen = ticks.length; i < ilen; ++i) {
4347
+ for (i = 0, ilen = scale.getTicks().length; i < ilen; ++i) {
3881
4348
  curr = scale.getPixelForTick(i);
3882
- min = i > 0 ? Math.min(min, curr - prev) : min;
4349
+ min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;
3883
4350
  prev = curr;
3884
4351
  }
3885
4352
 
@@ -3896,10 +4363,13 @@ function computeFitCategoryTraits(index, ruler, options) {
3896
4363
  var thickness = options.barThickness;
3897
4364
  var count = ruler.stackCount;
3898
4365
  var curr = ruler.pixels[index];
4366
+ var min = helpers$1.isNullOrUndef(thickness)
4367
+ ? computeMinSampleSize(ruler.scale, ruler.pixels)
4368
+ : -1;
3899
4369
  var size, ratio;
3900
4370
 
3901
4371
  if (helpers$1.isNullOrUndef(thickness)) {
3902
- size = ruler.min * options.categoryPercentage;
4372
+ size = min * options.categoryPercentage;
3903
4373
  ratio = options.barPercentage;
3904
4374
  } else {
3905
4375
  // When bar thickness is enforced, category and bar percentages are ignored.
@@ -3955,15 +4425,37 @@ var controller_bar = core_datasetController.extend({
3955
4425
 
3956
4426
  dataElementType: elements.Rectangle,
3957
4427
 
4428
+ /**
4429
+ * @private
4430
+ */
4431
+ _dataElementOptions: [
4432
+ 'backgroundColor',
4433
+ 'borderColor',
4434
+ 'borderSkipped',
4435
+ 'borderWidth',
4436
+ 'barPercentage',
4437
+ 'barThickness',
4438
+ 'categoryPercentage',
4439
+ 'maxBarThickness',
4440
+ 'minBarLength'
4441
+ ],
4442
+
3958
4443
  initialize: function() {
3959
4444
  var me = this;
3960
- var meta;
4445
+ var meta, scaleOpts;
3961
4446
 
3962
4447
  core_datasetController.prototype.initialize.apply(me, arguments);
3963
4448
 
3964
4449
  meta = me.getMeta();
3965
4450
  meta.stack = me.getDataset().stack;
3966
4451
  meta.bar = true;
4452
+
4453
+ scaleOpts = me._getIndexScale().options;
4454
+ deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage');
4455
+ deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness');
4456
+ deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage');
4457
+ deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength');
4458
+ deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness');
3967
4459
  },
3968
4460
 
3969
4461
  update: function(reset) {
@@ -3982,7 +4474,7 @@ var controller_bar = core_datasetController.extend({
3982
4474
  var me = this;
3983
4475
  var meta = me.getMeta();
3984
4476
  var dataset = me.getDataset();
3985
- var options = me._resolveElementOptions(rectangle, index);
4477
+ var options = me._resolveDataElementOptions(rectangle, index);
3986
4478
 
3987
4479
  rectangle._xScale = me.getScaleForId(meta.xAxisID);
3988
4480
  rectangle._yScale = me.getScaleForId(meta.yAxisID);
@@ -3997,7 +4489,11 @@ var controller_bar = core_datasetController.extend({
3997
4489
  label: me.chart.data.labels[index]
3998
4490
  };
3999
4491
 
4000
- me._updateElementGeometry(rectangle, index, reset);
4492
+ if (helpers$1.isArray(dataset.data[index])) {
4493
+ rectangle._model.borderSkipped = null;
4494
+ }
4495
+
4496
+ me._updateElementGeometry(rectangle, index, reset, options);
4001
4497
 
4002
4498
  rectangle.pivot();
4003
4499
  },
@@ -4005,15 +4501,15 @@ var controller_bar = core_datasetController.extend({
4005
4501
  /**
4006
4502
  * @private
4007
4503
  */
4008
- _updateElementGeometry: function(rectangle, index, reset) {
4504
+ _updateElementGeometry: function(rectangle, index, reset, options) {
4009
4505
  var me = this;
4010
4506
  var model = rectangle._model;
4011
4507
  var vscale = me._getValueScale();
4012
4508
  var base = vscale.getBasePixel();
4013
4509
  var horizontal = vscale.isHorizontal();
4014
4510
  var ruler = me._ruler || me.getRuler();
4015
- var vpixels = me.calculateBarValuePixels(me.index, index);
4016
- var ipixels = me.calculateBarIndexPixels(me.index, index, ruler);
4511
+ var vpixels = me.calculateBarValuePixels(me.index, index, options);
4512
+ var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options);
4017
4513
 
4018
4514
  model.horizontal = horizontal;
4019
4515
  model.base = reset ? base : vpixels.base;
@@ -4031,21 +4527,27 @@ var controller_bar = core_datasetController.extend({
4031
4527
  */
4032
4528
  _getStacks: function(last) {
4033
4529
  var me = this;
4034
- var chart = me.chart;
4035
4530
  var scale = me._getIndexScale();
4531
+ var metasets = scale._getMatchingVisibleMetas(me._type);
4036
4532
  var stacked = scale.options.stacked;
4037
- var ilen = last === undefined ? chart.data.datasets.length : last + 1;
4533
+ var ilen = metasets.length;
4038
4534
  var stacks = [];
4039
4535
  var i, meta;
4040
4536
 
4041
4537
  for (i = 0; i < ilen; ++i) {
4042
- meta = chart.getDatasetMeta(i);
4043
- if (meta.bar && chart.isDatasetVisible(i) &&
4044
- (stacked === false ||
4045
- (stacked === true && stacks.indexOf(meta.stack) === -1) ||
4046
- (stacked === undefined && (meta.stack === undefined || stacks.indexOf(meta.stack) === -1)))) {
4538
+ meta = metasets[i];
4539
+ // stacked | meta.stack
4540
+ // | found | not found | undefined
4541
+ // false | x | x | x
4542
+ // true | | x |
4543
+ // undefined | | x | x
4544
+ if (stacked === false || stacks.indexOf(meta.stack) === -1 ||
4545
+ (stacked === undefined && meta.stack === undefined)) {
4047
4546
  stacks.push(meta.stack);
4048
4547
  }
4548
+ if (meta.index === last) {
4549
+ break;
4550
+ }
4049
4551
  }
4050
4552
 
4051
4553
  return stacks;
@@ -4083,28 +4585,18 @@ var controller_bar = core_datasetController.extend({
4083
4585
  getRuler: function() {
4084
4586
  var me = this;
4085
4587
  var scale = me._getIndexScale();
4086
- var stackCount = me.getStackCount();
4087
- var datasetIndex = me.index;
4088
- var isHorizontal = scale.isHorizontal();
4089
- var start = isHorizontal ? scale.left : scale.top;
4090
- var end = start + (isHorizontal ? scale.width : scale.height);
4091
4588
  var pixels = [];
4092
- var i, ilen, min;
4589
+ var i, ilen;
4093
4590
 
4094
4591
  for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {
4095
- pixels.push(scale.getPixelForValue(null, i, datasetIndex));
4592
+ pixels.push(scale.getPixelForValue(null, i, me.index));
4096
4593
  }
4097
4594
 
4098
- min = helpers$1.isNullOrUndef(scale.options.barThickness)
4099
- ? computeMinSampleSize(scale, pixels)
4100
- : -1;
4101
-
4102
4595
  return {
4103
- min: min,
4104
4596
  pixels: pixels,
4105
- start: start,
4106
- end: end,
4107
- stackCount: stackCount,
4597
+ start: scale._startPixel,
4598
+ end: scale._endPixel,
4599
+ stackCount: me.getStackCount(),
4108
4600
  scale: scale
4109
4601
  };
4110
4602
  },
@@ -4113,31 +4605,35 @@ var controller_bar = core_datasetController.extend({
4113
4605
  * Note: pixel values are not clamped to the scale area.
4114
4606
  * @private
4115
4607
  */
4116
- calculateBarValuePixels: function(datasetIndex, index) {
4608
+ calculateBarValuePixels: function(datasetIndex, index, options) {
4117
4609
  var me = this;
4118
4610
  var chart = me.chart;
4119
- var meta = me.getMeta();
4120
4611
  var scale = me._getValueScale();
4121
4612
  var isHorizontal = scale.isHorizontal();
4122
4613
  var datasets = chart.data.datasets;
4123
- var value = +scale.getRightValue(datasets[datasetIndex].data[index]);
4124
- var minBarLength = scale.options.minBarLength;
4614
+ var metasets = scale._getMatchingVisibleMetas(me._type);
4615
+ var value = scale._parseValue(datasets[datasetIndex].data[index]);
4616
+ var minBarLength = options.minBarLength;
4125
4617
  var stacked = scale.options.stacked;
4126
- var stack = meta.stack;
4127
- var start = 0;
4128
- var i, imeta, ivalue, base, head, size;
4618
+ var stack = me.getMeta().stack;
4619
+ var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;
4620
+ var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;
4621
+ var ilen = metasets.length;
4622
+ var i, imeta, ivalue, base, head, size, stackLength;
4129
4623
 
4130
4624
  if (stacked || (stacked === undefined && stack !== undefined)) {
4131
- for (i = 0; i < datasetIndex; ++i) {
4132
- imeta = chart.getDatasetMeta(i);
4625
+ for (i = 0; i < ilen; ++i) {
4626
+ imeta = metasets[i];
4627
+
4628
+ if (imeta.index === datasetIndex) {
4629
+ break;
4630
+ }
4133
4631
 
4134
- if (imeta.bar &&
4135
- imeta.stack === stack &&
4136
- imeta.controller._getValueScaleId() === scale.id &&
4137
- chart.isDatasetVisible(i)) {
4632
+ if (imeta.stack === stack) {
4633
+ stackLength = scale._parseValue(datasets[imeta.index].data[index]);
4634
+ ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;
4138
4635
 
4139
- ivalue = +scale.getRightValue(datasets[i].data[index]);
4140
- if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) {
4636
+ if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {
4141
4637
  start += ivalue;
4142
4638
  }
4143
4639
  }
@@ -4145,12 +4641,12 @@ var controller_bar = core_datasetController.extend({
4145
4641
  }
4146
4642
 
4147
4643
  base = scale.getPixelForValue(start);
4148
- head = scale.getPixelForValue(start + value);
4644
+ head = scale.getPixelForValue(start + length);
4149
4645
  size = head - base;
4150
4646
 
4151
4647
  if (minBarLength !== undefined && Math.abs(size) < minBarLength) {
4152
4648
  size = minBarLength;
4153
- if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) {
4649
+ if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) {
4154
4650
  head = base - minBarLength;
4155
4651
  } else {
4156
4652
  head = base + minBarLength;
@@ -4168,9 +4664,8 @@ var controller_bar = core_datasetController.extend({
4168
4664
  /**
4169
4665
  * @private
4170
4666
  */
4171
- calculateBarIndexPixels: function(datasetIndex, index, ruler) {
4667
+ calculateBarIndexPixels: function(datasetIndex, index, ruler, options) {
4172
4668
  var me = this;
4173
- var options = ruler.scale.options;
4174
4669
  var range = options.barThickness === 'flex'
4175
4670
  ? computeFlexCategoryTraits(index, ruler, options)
4176
4671
  : computeFitCategoryTraits(index, ruler, options);
@@ -4178,7 +4673,7 @@ var controller_bar = core_datasetController.extend({
4178
4673
  var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);
4179
4674
  var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
4180
4675
  var size = Math.min(
4181
- helpers$1.valueOrDefault(options.maxBarThickness, Infinity),
4676
+ valueOrDefault$3(options.maxBarThickness, Infinity),
4182
4677
  range.chunk * range.ratio);
4183
4678
 
4184
4679
  return {
@@ -4201,7 +4696,8 @@ var controller_bar = core_datasetController.extend({
4201
4696
  helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);
4202
4697
 
4203
4698
  for (; i < ilen; ++i) {
4204
- if (!isNaN(scale.getRightValue(dataset.data[i]))) {
4699
+ var val = scale._parseValue(dataset.data[i]);
4700
+ if (!isNaN(val.min) && !isNaN(val.max)) {
4205
4701
  rects[i].draw();
4206
4702
  }
4207
4703
  }
@@ -4212,46 +4708,25 @@ var controller_bar = core_datasetController.extend({
4212
4708
  /**
4213
4709
  * @private
4214
4710
  */
4215
- _resolveElementOptions: function(rectangle, index) {
4711
+ _resolveDataElementOptions: function() {
4216
4712
  var me = this;
4217
- var chart = me.chart;
4218
- var datasets = chart.data.datasets;
4219
- var dataset = datasets[me.index];
4220
- var custom = rectangle.custom || {};
4221
- var options = chart.options.elements.rectangle;
4222
- var values = {};
4223
- var i, ilen, key;
4713
+ var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments));
4714
+ var indexOpts = me._getIndexScale().options;
4715
+ var valueOpts = me._getValueScale().options;
4224
4716
 
4225
- // Scriptable options
4226
- var context = {
4227
- chart: chart,
4228
- dataIndex: index,
4229
- dataset: dataset,
4230
- datasetIndex: me.index
4231
- };
4232
-
4233
- var keys = [
4234
- 'backgroundColor',
4235
- 'borderColor',
4236
- 'borderSkipped',
4237
- 'borderWidth'
4238
- ];
4239
-
4240
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
4241
- key = keys[i];
4242
- values[key] = resolve$1([
4243
- custom[key],
4244
- dataset[key],
4245
- options[key]
4246
- ], context, index);
4247
- }
4717
+ values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage);
4718
+ values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness);
4719
+ values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage);
4720
+ values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness);
4721
+ values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength);
4248
4722
 
4249
4723
  return values;
4250
4724
  }
4725
+
4251
4726
  });
4252
4727
 
4253
- var valueOrDefault$3 = helpers$1.valueOrDefault;
4254
- var resolve$2 = helpers$1.options.resolve;
4728
+ var valueOrDefault$4 = helpers$1.valueOrDefault;
4729
+ var resolve$1 = helpers$1.options.resolve;
4255
4730
 
4256
4731
  core_defaults._set('bubble', {
4257
4732
  hover: {
@@ -4292,6 +4767,22 @@ var controller_bubble = core_datasetController.extend({
4292
4767
  */
4293
4768
  dataElementType: elements.Point,
4294
4769
 
4770
+ /**
4771
+ * @private
4772
+ */
4773
+ _dataElementOptions: [
4774
+ 'backgroundColor',
4775
+ 'borderColor',
4776
+ 'borderWidth',
4777
+ 'hoverBackgroundColor',
4778
+ 'hoverBorderColor',
4779
+ 'hoverBorderWidth',
4780
+ 'hoverRadius',
4781
+ 'hitRadius',
4782
+ 'pointStyle',
4783
+ 'rotation'
4784
+ ],
4785
+
4295
4786
  /**
4296
4787
  * @protected
4297
4788
  */
@@ -4315,7 +4806,7 @@ var controller_bubble = core_datasetController.extend({
4315
4806
  var custom = point.custom || {};
4316
4807
  var xScale = me.getScaleForId(meta.xAxisID);
4317
4808
  var yScale = me.getScaleForId(meta.yAxisID);
4318
- var options = me._resolveElementOptions(point, index);
4809
+ var options = me._resolveDataElementOptions(point, index);
4319
4810
  var data = me.getDataset().data[index];
4320
4811
  var dsIndex = me.index;
4321
4812
 
@@ -4358,25 +4849,22 @@ var controller_bubble = core_datasetController.extend({
4358
4849
  radius: model.radius
4359
4850
  };
4360
4851
 
4361
- model.backgroundColor = valueOrDefault$3(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
4362
- model.borderColor = valueOrDefault$3(options.hoverBorderColor, getHoverColor(options.borderColor));
4363
- model.borderWidth = valueOrDefault$3(options.hoverBorderWidth, options.borderWidth);
4852
+ model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
4853
+ model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
4854
+ model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
4364
4855
  model.radius = options.radius + options.hoverRadius;
4365
4856
  },
4366
4857
 
4367
4858
  /**
4368
4859
  * @private
4369
4860
  */
4370
- _resolveElementOptions: function(point, index) {
4861
+ _resolveDataElementOptions: function(point, index) {
4371
4862
  var me = this;
4372
4863
  var chart = me.chart;
4373
- var datasets = chart.data.datasets;
4374
- var dataset = datasets[me.index];
4864
+ var dataset = me.getDataset();
4375
4865
  var custom = point.custom || {};
4376
- var options = chart.options.elements.point;
4377
- var data = dataset.data[index];
4378
- var values = {};
4379
- var i, ilen, key;
4866
+ var data = dataset.data[index] || {};
4867
+ var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments);
4380
4868
 
4381
4869
  // Scriptable options
4382
4870
  var context = {
@@ -4386,42 +4874,28 @@ var controller_bubble = core_datasetController.extend({
4386
4874
  datasetIndex: me.index
4387
4875
  };
4388
4876
 
4389
- var keys = [
4390
- 'backgroundColor',
4391
- 'borderColor',
4392
- 'borderWidth',
4393
- 'hoverBackgroundColor',
4394
- 'hoverBorderColor',
4395
- 'hoverBorderWidth',
4396
- 'hoverRadius',
4397
- 'hitRadius',
4398
- 'pointStyle',
4399
- 'rotation'
4400
- ];
4401
-
4402
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
4403
- key = keys[i];
4404
- values[key] = resolve$2([
4405
- custom[key],
4406
- dataset[key],
4407
- options[key]
4408
- ], context, index);
4877
+ // In case values were cached (and thus frozen), we need to clone the values
4878
+ if (me._cachedDataOpts === values) {
4879
+ values = helpers$1.extend({}, values);
4409
4880
  }
4410
4881
 
4411
4882
  // Custom radius resolution
4412
- values.radius = resolve$2([
4883
+ values.radius = resolve$1([
4413
4884
  custom.radius,
4414
- data ? data.r : undefined,
4415
- dataset.radius,
4416
- options.radius
4885
+ data.r,
4886
+ me._config.radius,
4887
+ chart.options.elements.point.radius
4417
4888
  ], context, index);
4418
4889
 
4419
4890
  return values;
4420
4891
  }
4421
4892
  });
4422
4893
 
4423
- var resolve$3 = helpers$1.options.resolve;
4424
- var valueOrDefault$4 = helpers$1.valueOrDefault;
4894
+ var valueOrDefault$5 = helpers$1.valueOrDefault;
4895
+
4896
+ var PI$1 = Math.PI;
4897
+ var DOUBLE_PI$1 = PI$1 * 2;
4898
+ var HALF_PI$1 = PI$1 / 2;
4425
4899
 
4426
4900
  core_defaults._set('doughnut', {
4427
4901
  animation: {
@@ -4434,25 +4908,25 @@ core_defaults._set('doughnut', {
4434
4908
  mode: 'single'
4435
4909
  },
4436
4910
  legendCallback: function(chart) {
4437
- var text = [];
4438
- text.push('<ul class="' + chart.id + '-legend">');
4439
-
4911
+ var list = document.createElement('ul');
4440
4912
  var data = chart.data;
4441
4913
  var datasets = data.datasets;
4442
4914
  var labels = data.labels;
4915
+ var i, ilen, listItem, listItemSpan;
4443
4916
 
4917
+ list.setAttribute('class', chart.id + '-legend');
4444
4918
  if (datasets.length) {
4445
- for (var i = 0; i < datasets[0].data.length; ++i) {
4446
- text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
4919
+ for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
4920
+ listItem = list.appendChild(document.createElement('li'));
4921
+ listItemSpan = listItem.appendChild(document.createElement('span'));
4922
+ listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
4447
4923
  if (labels[i]) {
4448
- text.push(labels[i]);
4924
+ listItem.appendChild(document.createTextNode(labels[i]));
4449
4925
  }
4450
- text.push('</li>');
4451
4926
  }
4452
4927
  }
4453
4928
 
4454
- text.push('</ul>');
4455
- return text.join('');
4929
+ return list.outerHTML;
4456
4930
  },
4457
4931
  legend: {
4458
4932
  labels: {
@@ -4461,20 +4935,14 @@ core_defaults._set('doughnut', {
4461
4935
  if (data.labels.length && data.datasets.length) {
4462
4936
  return data.labels.map(function(label, i) {
4463
4937
  var meta = chart.getDatasetMeta(0);
4464
- var ds = data.datasets[0];
4465
- var arc = meta.data[i];
4466
- var custom = arc && arc.custom || {};
4467
- var arcOpts = chart.options.elements.arc;
4468
- var fill = resolve$3([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
4469
- var stroke = resolve$3([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
4470
- var bw = resolve$3([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
4938
+ var style = meta.controller.getStyle(i);
4471
4939
 
4472
4940
  return {
4473
4941
  text: label,
4474
- fillStyle: fill,
4475
- strokeStyle: stroke,
4476
- lineWidth: bw,
4477
- hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
4942
+ fillStyle: style.backgroundColor,
4943
+ strokeStyle: style.borderColor,
4944
+ lineWidth: style.borderWidth,
4945
+ hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
4478
4946
 
4479
4947
  // Extra data used for toggling the correct item
4480
4948
  index: i
@@ -4506,10 +4974,10 @@ core_defaults._set('doughnut', {
4506
4974
  cutoutPercentage: 50,
4507
4975
 
4508
4976
  // The rotation of the chart, where the first data arc begins.
4509
- rotation: Math.PI * -0.5,
4977
+ rotation: -HALF_PI$1,
4510
4978
 
4511
4979
  // The total circumference of the chart.
4512
- circumference: Math.PI * 2.0,
4980
+ circumference: DOUBLE_PI$1,
4513
4981
 
4514
4982
  // Need to override these to give a nice default
4515
4983
  tooltips: {
@@ -4542,6 +5010,19 @@ var controller_doughnut = core_datasetController.extend({
4542
5010
 
4543
5011
  linkScales: helpers$1.noop,
4544
5012
 
5013
+ /**
5014
+ * @private
5015
+ */
5016
+ _dataElementOptions: [
5017
+ 'backgroundColor',
5018
+ 'borderColor',
5019
+ 'borderWidth',
5020
+ 'borderAlign',
5021
+ 'hoverBackgroundColor',
5022
+ 'hoverBorderColor',
5023
+ 'hoverBorderWidth',
5024
+ ],
5025
+
4545
5026
  // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
4546
5027
  getRingIndex: function(datasetIndex) {
4547
5028
  var ringIndex = 0;
@@ -4560,46 +5041,52 @@ var controller_doughnut = core_datasetController.extend({
4560
5041
  var chart = me.chart;
4561
5042
  var chartArea = chart.chartArea;
4562
5043
  var opts = chart.options;
4563
- var availableWidth = chartArea.right - chartArea.left;
4564
- var availableHeight = chartArea.bottom - chartArea.top;
4565
- var minSize = Math.min(availableWidth, availableHeight);
4566
- var offset = {x: 0, y: 0};
5044
+ var ratioX = 1;
5045
+ var ratioY = 1;
5046
+ var offsetX = 0;
5047
+ var offsetY = 0;
4567
5048
  var meta = me.getMeta();
4568
5049
  var arcs = meta.data;
4569
- var cutoutPercentage = opts.cutoutPercentage;
5050
+ var cutout = opts.cutoutPercentage / 100 || 0;
4570
5051
  var circumference = opts.circumference;
4571
5052
  var chartWeight = me._getRingWeight(me.index);
4572
- var i, ilen;
5053
+ var maxWidth, maxHeight, i, ilen;
4573
5054
 
4574
- // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
4575
- if (circumference < Math.PI * 2.0) {
4576
- var startAngle = opts.rotation % (Math.PI * 2.0);
4577
- startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
5055
+ // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
5056
+ if (circumference < DOUBLE_PI$1) {
5057
+ var startAngle = opts.rotation % DOUBLE_PI$1;
5058
+ startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0;
4578
5059
  var endAngle = startAngle + circumference;
4579
- var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
4580
- var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
4581
- var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
4582
- var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
4583
- var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
4584
- var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
4585
- var cutout = cutoutPercentage / 100.0;
4586
- var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
4587
- var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
4588
- var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
4589
- minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
4590
- offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
5060
+ var startX = Math.cos(startAngle);
5061
+ var startY = Math.sin(startAngle);
5062
+ var endX = Math.cos(endAngle);
5063
+ var endY = Math.sin(endAngle);
5064
+ var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1;
5065
+ var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1;
5066
+ var contains180 = startAngle === -PI$1 || endAngle >= PI$1;
5067
+ var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1;
5068
+ var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
5069
+ var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
5070
+ var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
5071
+ var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
5072
+ ratioX = (maxX - minX) / 2;
5073
+ ratioY = (maxY - minY) / 2;
5074
+ offsetX = -(maxX + minX) / 2;
5075
+ offsetY = -(maxY + minY) / 2;
4591
5076
  }
4592
5077
 
4593
5078
  for (i = 0, ilen = arcs.length; i < ilen; ++i) {
4594
- arcs[i]._options = me._resolveElementOptions(arcs[i], i);
5079
+ arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
4595
5080
  }
4596
5081
 
4597
5082
  chart.borderWidth = me.getMaxBorderWidth();
4598
- chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
4599
- chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
5083
+ maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;
5084
+ maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;
5085
+ chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
5086
+ chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);
4600
5087
  chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
4601
- chart.offsetX = offset.x * chart.outerRadius;
4602
- chart.offsetY = offset.y * chart.outerRadius;
5088
+ chart.offsetX = offsetX * chart.outerRadius;
5089
+ chart.offsetY = offsetY * chart.outerRadius;
4603
5090
 
4604
5091
  meta.total = me.calculateTotal();
4605
5092
 
@@ -4622,7 +5109,7 @@ var controller_doughnut = core_datasetController.extend({
4622
5109
  var startAngle = opts.rotation; // non reset case handled later
4623
5110
  var endAngle = opts.rotation; // non reset case handled later
4624
5111
  var dataset = me.getDataset();
4625
- var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
5112
+ var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI$1);
4626
5113
  var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
4627
5114
  var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
4628
5115
  var options = arc._options || {};
@@ -4688,7 +5175,7 @@ var controller_doughnut = core_datasetController.extend({
4688
5175
  calculateCircumference: function(value) {
4689
5176
  var total = this.getMeta().total;
4690
5177
  if (total > 0 && !isNaN(value)) {
4691
- return (Math.PI * 2.0) * (Math.abs(value) / total);
5178
+ return DOUBLE_PI$1 * (Math.abs(value) / total);
4692
5179
  }
4693
5180
  return 0;
4694
5181
  },
@@ -4720,7 +5207,12 @@ var controller_doughnut = core_datasetController.extend({
4720
5207
 
4721
5208
  for (i = 0, ilen = arcs.length; i < ilen; ++i) {
4722
5209
  arc = arcs[i];
4723
- options = controller ? controller._resolveElementOptions(arc, i) : arc._options;
5210
+ if (controller) {
5211
+ controller._configure();
5212
+ options = controller._resolveDataElementOptions(arc, i);
5213
+ } else {
5214
+ options = arc._options;
5215
+ }
4724
5216
  if (options.borderAlign !== 'inner') {
4725
5217
  borderWidth = options.borderWidth;
4726
5218
  hoverWidth = options.hoverBorderWidth;
@@ -4746,51 +5238,9 @@ var controller_doughnut = core_datasetController.extend({
4746
5238
  borderWidth: model.borderWidth,
4747
5239
  };
4748
5240
 
4749
- model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
4750
- model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));
4751
- model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);
4752
- },
4753
-
4754
- /**
4755
- * @private
4756
- */
4757
- _resolveElementOptions: function(arc, index) {
4758
- var me = this;
4759
- var chart = me.chart;
4760
- var dataset = me.getDataset();
4761
- var custom = arc.custom || {};
4762
- var options = chart.options.elements.arc;
4763
- var values = {};
4764
- var i, ilen, key;
4765
-
4766
- // Scriptable options
4767
- var context = {
4768
- chart: chart,
4769
- dataIndex: index,
4770
- dataset: dataset,
4771
- datasetIndex: me.index
4772
- };
4773
-
4774
- var keys = [
4775
- 'backgroundColor',
4776
- 'borderColor',
4777
- 'borderWidth',
4778
- 'borderAlign',
4779
- 'hoverBackgroundColor',
4780
- 'hoverBorderColor',
4781
- 'hoverBorderWidth',
4782
- ];
4783
-
4784
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
4785
- key = keys[i];
4786
- values[key] = resolve$3([
4787
- custom[key],
4788
- dataset[key],
4789
- options[key]
4790
- ], context, index);
4791
- }
4792
-
4793
- return values;
5241
+ model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
5242
+ model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
5243
+ model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
4794
5244
  },
4795
5245
 
4796
5246
  /**
@@ -4813,7 +5263,7 @@ var controller_doughnut = core_datasetController.extend({
4813
5263
  * @private
4814
5264
  */
4815
5265
  _getRingWeight: function(dataSetIndex) {
4816
- return Math.max(valueOrDefault$4(this.chart.data.datasets[dataSetIndex].weight, 1), 0);
5266
+ return Math.max(valueOrDefault$5(this.chart.data.datasets[dataSetIndex].weight, 1), 0);
4817
5267
  },
4818
5268
 
4819
5269
  /**
@@ -4840,8 +5290,6 @@ core_defaults._set('horizontalBar', {
4840
5290
  yAxes: [{
4841
5291
  type: 'category',
4842
5292
  position: 'left',
4843
- categoryPercentage: 0.8,
4844
- barPercentage: 0.9,
4845
5293
  offset: true,
4846
5294
  gridLines: {
4847
5295
  offsetGridLines: true
@@ -4861,6 +5309,15 @@ core_defaults._set('horizontalBar', {
4861
5309
  }
4862
5310
  });
4863
5311
 
5312
+ core_defaults._set('global', {
5313
+ datasets: {
5314
+ horizontalBar: {
5315
+ categoryPercentage: 0.8,
5316
+ barPercentage: 0.9
5317
+ }
5318
+ }
5319
+ });
5320
+
4864
5321
  var controller_horizontalBar = controller_bar.extend({
4865
5322
  /**
4866
5323
  * @private
@@ -4877,8 +5334,8 @@ var controller_horizontalBar = controller_bar.extend({
4877
5334
  }
4878
5335
  });
4879
5336
 
4880
- var valueOrDefault$5 = helpers$1.valueOrDefault;
4881
- var resolve$4 = helpers$1.options.resolve;
5337
+ var valueOrDefault$6 = helpers$1.valueOrDefault;
5338
+ var resolve$2 = helpers$1.options.resolve;
4882
5339
  var isPointInArea = helpers$1.canvas._isPointInArea;
4883
5340
 
4884
5341
  core_defaults._set('line', {
@@ -4901,40 +5358,71 @@ core_defaults._set('line', {
4901
5358
  }
4902
5359
  });
4903
5360
 
4904
- function lineEnabled(dataset, options) {
4905
- return valueOrDefault$5(dataset.showLine, options.showLines);
4906
- }
4907
-
4908
5361
  var controller_line = core_datasetController.extend({
4909
5362
 
4910
5363
  datasetElementType: elements.Line,
4911
5364
 
4912
5365
  dataElementType: elements.Point,
4913
5366
 
5367
+ /**
5368
+ * @private
5369
+ */
5370
+ _datasetElementOptions: [
5371
+ 'backgroundColor',
5372
+ 'borderCapStyle',
5373
+ 'borderColor',
5374
+ 'borderDash',
5375
+ 'borderDashOffset',
5376
+ 'borderJoinStyle',
5377
+ 'borderWidth',
5378
+ 'cubicInterpolationMode',
5379
+ 'fill'
5380
+ ],
5381
+
5382
+ /**
5383
+ * @private
5384
+ */
5385
+ _dataElementOptions: {
5386
+ backgroundColor: 'pointBackgroundColor',
5387
+ borderColor: 'pointBorderColor',
5388
+ borderWidth: 'pointBorderWidth',
5389
+ hitRadius: 'pointHitRadius',
5390
+ hoverBackgroundColor: 'pointHoverBackgroundColor',
5391
+ hoverBorderColor: 'pointHoverBorderColor',
5392
+ hoverBorderWidth: 'pointHoverBorderWidth',
5393
+ hoverRadius: 'pointHoverRadius',
5394
+ pointStyle: 'pointStyle',
5395
+ radius: 'pointRadius',
5396
+ rotation: 'pointRotation'
5397
+ },
5398
+
4914
5399
  update: function(reset) {
4915
5400
  var me = this;
4916
5401
  var meta = me.getMeta();
4917
5402
  var line = meta.dataset;
4918
5403
  var points = meta.data || [];
4919
- var scale = me.getScaleForId(meta.yAxisID);
4920
- var dataset = me.getDataset();
4921
- var showLine = lineEnabled(dataset, me.chart.options);
5404
+ var options = me.chart.options;
5405
+ var config = me._config;
5406
+ var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines);
4922
5407
  var i, ilen;
4923
5408
 
5409
+ me._xScale = me.getScaleForId(meta.xAxisID);
5410
+ me._yScale = me.getScaleForId(meta.yAxisID);
5411
+
4924
5412
  // Update Line
4925
5413
  if (showLine) {
4926
5414
  // Compatibility: If the properties are defined with only the old name, use those values
4927
- if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
4928
- dataset.lineTension = dataset.tension;
5415
+ if (config.tension !== undefined && config.lineTension === undefined) {
5416
+ config.lineTension = config.tension;
4929
5417
  }
4930
5418
 
4931
5419
  // Utility
4932
- line._scale = scale;
5420
+ line._scale = me._yScale;
4933
5421
  line._datasetIndex = me.index;
4934
5422
  // Data
4935
5423
  line._children = points;
4936
5424
  // Model
4937
- line._model = me._resolveLineOptions(line);
5425
+ line._model = me._resolveDatasetElementOptions(line);
4938
5426
 
4939
5427
  line.pivot();
4940
5428
  }
@@ -4961,12 +5449,12 @@ var controller_line = core_datasetController.extend({
4961
5449
  var dataset = me.getDataset();
4962
5450
  var datasetIndex = me.index;
4963
5451
  var value = dataset.data[index];
4964
- var yScale = me.getScaleForId(meta.yAxisID);
4965
- var xScale = me.getScaleForId(meta.xAxisID);
5452
+ var xScale = me._xScale;
5453
+ var yScale = me._yScale;
4966
5454
  var lineModel = meta.dataset._model;
4967
5455
  var x, y;
4968
5456
 
4969
- var options = me._resolvePointOptions(point, index);
5457
+ var options = me._resolveDataElementOptions(point, index);
4970
5458
 
4971
5459
  x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
4972
5460
  y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
@@ -4990,7 +5478,7 @@ var controller_line = core_datasetController.extend({
4990
5478
  backgroundColor: options.backgroundColor,
4991
5479
  borderColor: options.borderColor,
4992
5480
  borderWidth: options.borderWidth,
4993
- tension: valueOrDefault$5(custom.tension, lineModel ? lineModel.tension : 0),
5481
+ tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),
4994
5482
  steppedLine: lineModel ? lineModel.steppedLine : false,
4995
5483
  // Tooltip
4996
5484
  hitRadius: options.hitRadius
@@ -5000,91 +5488,20 @@ var controller_line = core_datasetController.extend({
5000
5488
  /**
5001
5489
  * @private
5002
5490
  */
5003
- _resolvePointOptions: function(element, index) {
5004
- var me = this;
5005
- var chart = me.chart;
5006
- var dataset = chart.data.datasets[me.index];
5007
- var custom = element.custom || {};
5008
- var options = chart.options.elements.point;
5009
- var values = {};
5010
- var i, ilen, key;
5011
-
5012
- // Scriptable options
5013
- var context = {
5014
- chart: chart,
5015
- dataIndex: index,
5016
- dataset: dataset,
5017
- datasetIndex: me.index
5018
- };
5019
-
5020
- var ELEMENT_OPTIONS = {
5021
- backgroundColor: 'pointBackgroundColor',
5022
- borderColor: 'pointBorderColor',
5023
- borderWidth: 'pointBorderWidth',
5024
- hitRadius: 'pointHitRadius',
5025
- hoverBackgroundColor: 'pointHoverBackgroundColor',
5026
- hoverBorderColor: 'pointHoverBorderColor',
5027
- hoverBorderWidth: 'pointHoverBorderWidth',
5028
- hoverRadius: 'pointHoverRadius',
5029
- pointStyle: 'pointStyle',
5030
- radius: 'pointRadius',
5031
- rotation: 'pointRotation'
5032
- };
5033
- var keys = Object.keys(ELEMENT_OPTIONS);
5034
-
5035
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
5036
- key = keys[i];
5037
- values[key] = resolve$4([
5038
- custom[key],
5039
- dataset[ELEMENT_OPTIONS[key]],
5040
- dataset[key],
5041
- options[key]
5042
- ], context, index);
5043
- }
5044
-
5045
- return values;
5046
- },
5047
-
5048
- /**
5049
- * @private
5050
- */
5051
- _resolveLineOptions: function(element) {
5491
+ _resolveDatasetElementOptions: function(element) {
5052
5492
  var me = this;
5053
- var chart = me.chart;
5054
- var dataset = chart.data.datasets[me.index];
5493
+ var config = me._config;
5055
5494
  var custom = element.custom || {};
5056
- var options = chart.options;
5057
- var elementOptions = options.elements.line;
5058
- var values = {};
5059
- var i, ilen, key;
5060
-
5061
- var keys = [
5062
- 'backgroundColor',
5063
- 'borderWidth',
5064
- 'borderColor',
5065
- 'borderCapStyle',
5066
- 'borderDash',
5067
- 'borderDashOffset',
5068
- 'borderJoinStyle',
5069
- 'fill',
5070
- 'cubicInterpolationMode'
5071
- ];
5072
-
5073
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
5074
- key = keys[i];
5075
- values[key] = resolve$4([
5076
- custom[key],
5077
- dataset[key],
5078
- elementOptions[key]
5079
- ]);
5080
- }
5495
+ var options = me.chart.options;
5496
+ var lineOptions = options.elements.line;
5497
+ var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
5081
5498
 
5082
5499
  // The default behavior of lines is to break at null values, according
5083
5500
  // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
5084
5501
  // This option gives lines the ability to span gaps
5085
- values.spanGaps = valueOrDefault$5(dataset.spanGaps, options.spanGaps);
5086
- values.tension = valueOrDefault$5(dataset.lineTension, elementOptions.tension);
5087
- values.steppedLine = resolve$4([custom.steppedLine, dataset.steppedLine, elementOptions.stepped]);
5502
+ values.spanGaps = valueOrDefault$6(config.spanGaps, options.spanGaps);
5503
+ values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension);
5504
+ values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]);
5088
5505
 
5089
5506
  return values;
5090
5507
  },
@@ -5092,18 +5509,24 @@ var controller_line = core_datasetController.extend({
5092
5509
  calculatePointY: function(value, index, datasetIndex) {
5093
5510
  var me = this;
5094
5511
  var chart = me.chart;
5095
- var meta = me.getMeta();
5096
- var yScale = me.getScaleForId(meta.yAxisID);
5512
+ var yScale = me._yScale;
5097
5513
  var sumPos = 0;
5098
5514
  var sumNeg = 0;
5099
- var i, ds, dsMeta;
5515
+ var rightValue = +yScale.getRightValue(value);
5516
+ var metasets = chart._getSortedVisibleDatasetMetas();
5517
+ var ilen = metasets.length;
5518
+ var i, ds, dsMeta, stackedRightValue;
5100
5519
 
5101
5520
  if (yScale.options.stacked) {
5102
- for (i = 0; i < datasetIndex; i++) {
5103
- ds = chart.data.datasets[i];
5104
- dsMeta = chart.getDatasetMeta(i);
5105
- if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id && chart.isDatasetVisible(i)) {
5106
- var stackedRightValue = Number(yScale.getRightValue(ds.data[index]));
5521
+ for (i = 0; i < ilen; ++i) {
5522
+ dsMeta = metasets[i];
5523
+ if (dsMeta.index === datasetIndex) {
5524
+ break;
5525
+ }
5526
+
5527
+ ds = chart.data.datasets[dsMeta.index];
5528
+ if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {
5529
+ stackedRightValue = +yScale.getRightValue(ds.data[index]);
5107
5530
  if (stackedRightValue < 0) {
5108
5531
  sumNeg += stackedRightValue || 0;
5109
5532
  } else {
@@ -5112,13 +5535,11 @@ var controller_line = core_datasetController.extend({
5112
5535
  }
5113
5536
  }
5114
5537
 
5115
- var rightValue = Number(yScale.getRightValue(value));
5116
5538
  if (rightValue < 0) {
5117
5539
  return yScale.getPixelForValue(sumNeg + rightValue);
5118
5540
  }
5119
5541
  return yScale.getPixelForValue(sumPos + rightValue);
5120
5542
  }
5121
-
5122
5543
  return yScale.getPixelForValue(value);
5123
5544
  },
5124
5545
 
@@ -5183,16 +5604,16 @@ var controller_line = core_datasetController.extend({
5183
5604
  var meta = me.getMeta();
5184
5605
  var points = meta.data || [];
5185
5606
  var area = chart.chartArea;
5607
+ var i = 0;
5186
5608
  var ilen = points.length;
5187
5609
  var halfBorderWidth;
5188
- var i = 0;
5189
5610
 
5190
- if (lineEnabled(me.getDataset(), chart.options)) {
5611
+ if (me._showLine) {
5191
5612
  halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
5192
5613
 
5193
5614
  helpers$1.canvas.clipArea(chart.ctx, {
5194
- left: area.left,
5195
- right: area.right,
5615
+ left: area.left - halfBorderWidth,
5616
+ right: area.right + halfBorderWidth,
5196
5617
  top: area.top - halfBorderWidth,
5197
5618
  bottom: area.bottom + halfBorderWidth
5198
5619
  });
@@ -5223,14 +5644,14 @@ var controller_line = core_datasetController.extend({
5223
5644
  radius: model.radius
5224
5645
  };
5225
5646
 
5226
- model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
5227
- model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));
5228
- model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);
5229
- model.radius = valueOrDefault$5(options.hoverRadius, options.radius);
5647
+ model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
5648
+ model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));
5649
+ model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);
5650
+ model.radius = valueOrDefault$6(options.hoverRadius, options.radius);
5230
5651
  },
5231
5652
  });
5232
5653
 
5233
- var resolve$5 = helpers$1.options.resolve;
5654
+ var resolve$3 = helpers$1.options.resolve;
5234
5655
 
5235
5656
  core_defaults._set('polarArea', {
5236
5657
  scale: {
@@ -5257,25 +5678,25 @@ core_defaults._set('polarArea', {
5257
5678
 
5258
5679
  startAngle: -0.5 * Math.PI,
5259
5680
  legendCallback: function(chart) {
5260
- var text = [];
5261
- text.push('<ul class="' + chart.id + '-legend">');
5262
-
5681
+ var list = document.createElement('ul');
5263
5682
  var data = chart.data;
5264
5683
  var datasets = data.datasets;
5265
5684
  var labels = data.labels;
5685
+ var i, ilen, listItem, listItemSpan;
5266
5686
 
5687
+ list.setAttribute('class', chart.id + '-legend');
5267
5688
  if (datasets.length) {
5268
- for (var i = 0; i < datasets[0].data.length; ++i) {
5269
- text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
5689
+ for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {
5690
+ listItem = list.appendChild(document.createElement('li'));
5691
+ listItemSpan = listItem.appendChild(document.createElement('span'));
5692
+ listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];
5270
5693
  if (labels[i]) {
5271
- text.push(labels[i]);
5694
+ listItem.appendChild(document.createTextNode(labels[i]));
5272
5695
  }
5273
- text.push('</li>');
5274
5696
  }
5275
5697
  }
5276
5698
 
5277
- text.push('</ul>');
5278
- return text.join('');
5699
+ return list.outerHTML;
5279
5700
  },
5280
5701
  legend: {
5281
5702
  labels: {
@@ -5284,20 +5705,14 @@ core_defaults._set('polarArea', {
5284
5705
  if (data.labels.length && data.datasets.length) {
5285
5706
  return data.labels.map(function(label, i) {
5286
5707
  var meta = chart.getDatasetMeta(0);
5287
- var ds = data.datasets[0];
5288
- var arc = meta.data[i];
5289
- var custom = arc.custom || {};
5290
- var arcOpts = chart.options.elements.arc;
5291
- var fill = resolve$5([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
5292
- var stroke = resolve$5([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
5293
- var bw = resolve$5([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
5708
+ var style = meta.controller.getStyle(i);
5294
5709
 
5295
5710
  return {
5296
5711
  text: label,
5297
- fillStyle: fill,
5298
- strokeStyle: stroke,
5299
- lineWidth: bw,
5300
- hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
5712
+ fillStyle: style.backgroundColor,
5713
+ strokeStyle: style.borderColor,
5714
+ lineWidth: style.borderWidth,
5715
+ hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
5301
5716
 
5302
5717
  // Extra data used for toggling the correct item
5303
5718
  index: i
@@ -5341,6 +5756,33 @@ var controller_polarArea = core_datasetController.extend({
5341
5756
 
5342
5757
  linkScales: helpers$1.noop,
5343
5758
 
5759
+ /**
5760
+ * @private
5761
+ */
5762
+ _dataElementOptions: [
5763
+ 'backgroundColor',
5764
+ 'borderColor',
5765
+ 'borderWidth',
5766
+ 'borderAlign',
5767
+ 'hoverBackgroundColor',
5768
+ 'hoverBorderColor',
5769
+ 'hoverBorderWidth',
5770
+ ],
5771
+
5772
+ /**
5773
+ * @private
5774
+ */
5775
+ _getIndexScaleId: function() {
5776
+ return this.chart.scale.id;
5777
+ },
5778
+
5779
+ /**
5780
+ * @private
5781
+ */
5782
+ _getValueScaleId: function() {
5783
+ return this.chart.scale.id;
5784
+ },
5785
+
5344
5786
  update: function(reset) {
5345
5787
  var me = this;
5346
5788
  var dataset = me.getDataset();
@@ -5363,7 +5805,7 @@ var controller_polarArea = core_datasetController.extend({
5363
5805
  }
5364
5806
 
5365
5807
  for (i = 0, ilen = arcs.length; i < ilen; ++i) {
5366
- arcs[i]._options = me._resolveElementOptions(arcs[i], i);
5808
+ arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
5367
5809
  me.updateElement(arcs[i], i, reset);
5368
5810
  }
5369
5811
  },
@@ -5466,48 +5908,6 @@ var controller_polarArea = core_datasetController.extend({
5466
5908
  model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
5467
5909
  },
5468
5910
 
5469
- /**
5470
- * @private
5471
- */
5472
- _resolveElementOptions: function(arc, index) {
5473
- var me = this;
5474
- var chart = me.chart;
5475
- var dataset = me.getDataset();
5476
- var custom = arc.custom || {};
5477
- var options = chart.options.elements.arc;
5478
- var values = {};
5479
- var i, ilen, key;
5480
-
5481
- // Scriptable options
5482
- var context = {
5483
- chart: chart,
5484
- dataIndex: index,
5485
- dataset: dataset,
5486
- datasetIndex: me.index
5487
- };
5488
-
5489
- var keys = [
5490
- 'backgroundColor',
5491
- 'borderColor',
5492
- 'borderWidth',
5493
- 'borderAlign',
5494
- 'hoverBackgroundColor',
5495
- 'hoverBorderColor',
5496
- 'hoverBorderWidth',
5497
- ];
5498
-
5499
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
5500
- key = keys[i];
5501
- values[key] = resolve$5([
5502
- custom[key],
5503
- dataset[key],
5504
- options[key]
5505
- ], context, index);
5506
- }
5507
-
5508
- return values;
5509
- },
5510
-
5511
5911
  /**
5512
5912
  * @private
5513
5913
  */
@@ -5529,7 +5929,7 @@ var controller_polarArea = core_datasetController.extend({
5529
5929
  datasetIndex: me.index
5530
5930
  };
5531
5931
 
5532
- return resolve$5([
5932
+ return resolve$3([
5533
5933
  me.chart.options.elements.arc.angle,
5534
5934
  (2 * Math.PI) / count
5535
5935
  ], context, index);
@@ -5544,10 +5944,10 @@ core_defaults._set('pie', {
5544
5944
  // Pie charts are Doughnut chart with different defaults
5545
5945
  var controller_pie = controller_doughnut;
5546
5946
 
5547
- var valueOrDefault$6 = helpers$1.valueOrDefault;
5548
- var resolve$6 = helpers$1.options.resolve;
5947
+ var valueOrDefault$7 = helpers$1.valueOrDefault;
5549
5948
 
5550
5949
  core_defaults._set('radar', {
5950
+ spanGaps: false,
5551
5951
  scale: {
5552
5952
  type: 'radialLinear'
5553
5953
  },
@@ -5559,25 +5959,69 @@ core_defaults._set('radar', {
5559
5959
  });
5560
5960
 
5561
5961
  var controller_radar = core_datasetController.extend({
5562
-
5563
5962
  datasetElementType: elements.Line,
5564
5963
 
5565
5964
  dataElementType: elements.Point,
5566
5965
 
5567
5966
  linkScales: helpers$1.noop,
5568
5967
 
5968
+ /**
5969
+ * @private
5970
+ */
5971
+ _datasetElementOptions: [
5972
+ 'backgroundColor',
5973
+ 'borderWidth',
5974
+ 'borderColor',
5975
+ 'borderCapStyle',
5976
+ 'borderDash',
5977
+ 'borderDashOffset',
5978
+ 'borderJoinStyle',
5979
+ 'fill'
5980
+ ],
5981
+
5982
+ /**
5983
+ * @private
5984
+ */
5985
+ _dataElementOptions: {
5986
+ backgroundColor: 'pointBackgroundColor',
5987
+ borderColor: 'pointBorderColor',
5988
+ borderWidth: 'pointBorderWidth',
5989
+ hitRadius: 'pointHitRadius',
5990
+ hoverBackgroundColor: 'pointHoverBackgroundColor',
5991
+ hoverBorderColor: 'pointHoverBorderColor',
5992
+ hoverBorderWidth: 'pointHoverBorderWidth',
5993
+ hoverRadius: 'pointHoverRadius',
5994
+ pointStyle: 'pointStyle',
5995
+ radius: 'pointRadius',
5996
+ rotation: 'pointRotation'
5997
+ },
5998
+
5999
+ /**
6000
+ * @private
6001
+ */
6002
+ _getIndexScaleId: function() {
6003
+ return this.chart.scale.id;
6004
+ },
6005
+
6006
+ /**
6007
+ * @private
6008
+ */
6009
+ _getValueScaleId: function() {
6010
+ return this.chart.scale.id;
6011
+ },
6012
+
5569
6013
  update: function(reset) {
5570
6014
  var me = this;
5571
6015
  var meta = me.getMeta();
5572
6016
  var line = meta.dataset;
5573
6017
  var points = meta.data || [];
5574
6018
  var scale = me.chart.scale;
5575
- var dataset = me.getDataset();
6019
+ var config = me._config;
5576
6020
  var i, ilen;
5577
6021
 
5578
6022
  // Compatibility: If the properties are defined with only the old name, use those values
5579
- if ((dataset.tension !== undefined) && (dataset.lineTension === undefined)) {
5580
- dataset.lineTension = dataset.tension;
6023
+ if (config.tension !== undefined && config.lineTension === undefined) {
6024
+ config.lineTension = config.tension;
5581
6025
  }
5582
6026
 
5583
6027
  // Utility
@@ -5587,7 +6031,7 @@ var controller_radar = core_datasetController.extend({
5587
6031
  line._children = points;
5588
6032
  line._loop = true;
5589
6033
  // Model
5590
- line._model = me._resolveLineOptions(line);
6034
+ line._model = me._resolveDatasetElementOptions(line);
5591
6035
 
5592
6036
  line.pivot();
5593
6037
 
@@ -5611,7 +6055,7 @@ var controller_radar = core_datasetController.extend({
5611
6055
  var dataset = me.getDataset();
5612
6056
  var scale = me.chart.scale;
5613
6057
  var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
5614
- var options = me._resolvePointOptions(point, index);
6058
+ var options = me._resolveDataElementOptions(point, index);
5615
6059
  var lineModel = me.getMeta().dataset._model;
5616
6060
  var x = reset ? scale.xCenter : pointPosition.x;
5617
6061
  var y = reset ? scale.yCenter : pointPosition.y;
@@ -5634,7 +6078,7 @@ var controller_radar = core_datasetController.extend({
5634
6078
  backgroundColor: options.backgroundColor,
5635
6079
  borderColor: options.borderColor,
5636
6080
  borderWidth: options.borderWidth,
5637
- tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),
6081
+ tension: valueOrDefault$7(custom.tension, lineModel ? lineModel.tension : 0),
5638
6082
 
5639
6083
  // Tooltip
5640
6084
  hitRadius: options.hitRadius
@@ -5644,84 +6088,14 @@ var controller_radar = core_datasetController.extend({
5644
6088
  /**
5645
6089
  * @private
5646
6090
  */
5647
- _resolvePointOptions: function(element, index) {
5648
- var me = this;
5649
- var chart = me.chart;
5650
- var dataset = chart.data.datasets[me.index];
5651
- var custom = element.custom || {};
5652
- var options = chart.options.elements.point;
5653
- var values = {};
5654
- var i, ilen, key;
5655
-
5656
- // Scriptable options
5657
- var context = {
5658
- chart: chart,
5659
- dataIndex: index,
5660
- dataset: dataset,
5661
- datasetIndex: me.index
5662
- };
5663
-
5664
- var ELEMENT_OPTIONS = {
5665
- backgroundColor: 'pointBackgroundColor',
5666
- borderColor: 'pointBorderColor',
5667
- borderWidth: 'pointBorderWidth',
5668
- hitRadius: 'pointHitRadius',
5669
- hoverBackgroundColor: 'pointHoverBackgroundColor',
5670
- hoverBorderColor: 'pointHoverBorderColor',
5671
- hoverBorderWidth: 'pointHoverBorderWidth',
5672
- hoverRadius: 'pointHoverRadius',
5673
- pointStyle: 'pointStyle',
5674
- radius: 'pointRadius',
5675
- rotation: 'pointRotation'
5676
- };
5677
- var keys = Object.keys(ELEMENT_OPTIONS);
5678
-
5679
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
5680
- key = keys[i];
5681
- values[key] = resolve$6([
5682
- custom[key],
5683
- dataset[ELEMENT_OPTIONS[key]],
5684
- dataset[key],
5685
- options[key]
5686
- ], context, index);
5687
- }
5688
-
5689
- return values;
5690
- },
5691
-
5692
- /**
5693
- * @private
5694
- */
5695
- _resolveLineOptions: function(element) {
6091
+ _resolveDatasetElementOptions: function() {
5696
6092
  var me = this;
5697
- var chart = me.chart;
5698
- var dataset = chart.data.datasets[me.index];
5699
- var custom = element.custom || {};
5700
- var options = chart.options.elements.line;
5701
- var values = {};
5702
- var i, ilen, key;
5703
-
5704
- var keys = [
5705
- 'backgroundColor',
5706
- 'borderWidth',
5707
- 'borderColor',
5708
- 'borderCapStyle',
5709
- 'borderDash',
5710
- 'borderDashOffset',
5711
- 'borderJoinStyle',
5712
- 'fill'
5713
- ];
5714
-
5715
- for (i = 0, ilen = keys.length; i < ilen; ++i) {
5716
- key = keys[i];
5717
- values[key] = resolve$6([
5718
- custom[key],
5719
- dataset[key],
5720
- options[key]
5721
- ]);
5722
- }
6093
+ var config = me._config;
6094
+ var options = me.chart.options;
6095
+ var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
5723
6096
 
5724
- values.tension = valueOrDefault$6(dataset.lineTension, options.tension);
6097
+ values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps);
6098
+ values.tension = valueOrDefault$7(config.lineTension, options.elements.line.tension);
5725
6099
 
5726
6100
  return values;
5727
6101
  },
@@ -5733,6 +6107,13 @@ var controller_radar = core_datasetController.extend({
5733
6107
  var points = meta.data || [];
5734
6108
  var i, ilen, model, controlPoints;
5735
6109
 
6110
+ // Only consider points that are drawn in case the spanGaps option is used
6111
+ if (meta.dataset._model.spanGaps) {
6112
+ points = points.filter(function(pt) {
6113
+ return !pt._model.skip;
6114
+ });
6115
+ }
6116
+
5736
6117
  function capControlPoint(pt, min, max) {
5737
6118
  return Math.max(Math.min(pt, max), min);
5738
6119
  }
@@ -5766,10 +6147,10 @@ var controller_radar = core_datasetController.extend({
5766
6147
  radius: model.radius
5767
6148
  };
5768
6149
 
5769
- model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
5770
- model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));
5771
- model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);
5772
- model.radius = valueOrDefault$6(options.hoverRadius, options.radius);
6150
+ model.backgroundColor = valueOrDefault$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));
6151
+ model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor));
6152
+ model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth);
6153
+ model.radius = valueOrDefault$7(options.hoverRadius, options.radius);
5773
6154
  }
5774
6155
  });
5775
6156
 
@@ -5791,8 +6172,6 @@ core_defaults._set('scatter', {
5791
6172
  }]
5792
6173
  },
5793
6174
 
5794
- showLines: false,
5795
-
5796
6175
  tooltips: {
5797
6176
  callbacks: {
5798
6177
  title: function() {
@@ -5805,6 +6184,14 @@ core_defaults._set('scatter', {
5805
6184
  }
5806
6185
  });
5807
6186
 
6187
+ core_defaults._set('global', {
6188
+ datasets: {
6189
+ scatter: {
6190
+ showLine: false
6191
+ }
6192
+ }
6193
+ });
6194
+
5808
6195
  // Scatter charts use line controllers
5809
6196
  var controller_scatter = controller_line;
5810
6197
 
@@ -5847,17 +6234,13 @@ function getRelativePosition(e, chart) {
5847
6234
  * @param {function} handler - the callback to execute for each visible item
5848
6235
  */
5849
6236
  function parseVisibleItems(chart, handler) {
5850
- var datasets = chart.data.datasets;
5851
- var meta, i, j, ilen, jlen;
5852
-
5853
- for (i = 0, ilen = datasets.length; i < ilen; ++i) {
5854
- if (!chart.isDatasetVisible(i)) {
5855
- continue;
5856
- }
6237
+ var metasets = chart._getSortedVisibleDatasetMetas();
6238
+ var metadata, i, j, ilen, jlen, element;
5857
6239
 
5858
- meta = chart.getDatasetMeta(i);
5859
- for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
5860
- var element = meta.data[j];
6240
+ for (i = 0, ilen = metasets.length; i < ilen; ++i) {
6241
+ metadata = metasets[i].data;
6242
+ for (j = 0, jlen = metadata.length; j < jlen; ++j) {
6243
+ element = metadata[j];
5861
6244
  if (!element._view.skip) {
5862
6245
  handler(element);
5863
6246
  }
@@ -5942,15 +6325,12 @@ function indexMode(chart, e, options) {
5942
6325
  return [];
5943
6326
  }
5944
6327
 
5945
- chart.data.datasets.forEach(function(dataset, datasetIndex) {
5946
- if (chart.isDatasetVisible(datasetInde