]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Make legend appearance consistent with chart elements (#5621)
authorAkihiko Kusanagi <nagi@nagi-p.com>
Thu, 9 May 2019 13:33:19 +0000 (21:33 +0800)
committerSimon Brunel <simonbrunel@users.noreply.github.com>
Thu, 9 May 2019 13:33:19 +0000 (15:33 +0200)
15 files changed:
docs/configuration/legend.md
src/controllers/controller.bar.js
src/controllers/controller.bubble.js
src/controllers/controller.doughnut.js
src/controllers/controller.line.js
src/controllers/controller.polarArea.js
src/controllers/controller.radar.js
src/core/core.datasetController.js
src/core/core.element.js
src/elements/element.arc.js
src/elements/element.line.js
src/elements/element.point.js
src/elements/element.rectangle.js
src/plugins/plugin.legend.js
test/specs/plugin.legend.tests.js

index f8ce7eb5a1788755d81e3cfece2dd0e1f27e84d0..5caef61759d80628f9bab0a2dedea6ab92283198 100644 (file)
@@ -82,7 +82,10 @@ Items passed to the legend `onClick` function are the ones returned from `labels
     strokeStyle: Color,
 
     // Point style of the legend box (only used if usePointStyle is true)
-    pointStyle: string
+    pointStyle: string | Image,
+
+    // Rotation of the point in degrees (only used if usePointStyle is true)
+    rotation: number
 }
 ```
 
index 7130a9d0905b2536ad75f20a6922dcca795f9ad5..0736cf6e1e08ba5aa53e95c20b33d7f0ca2f2fc8 100644 (file)
@@ -5,8 +5,6 @@ var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
 
-var resolve = helpers.options.resolve;
-
 defaults._set('bar', {
        hover: {
                mode: 'label'
@@ -120,6 +118,16 @@ module.exports = DatasetController.extend({
 
        dataElementType: elements.Rectangle,
 
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderSkipped',
+               'borderWidth'
+       ],
+
        initialize: function() {
                var me = this;
                var meta;
@@ -147,7 +155,7 @@ module.exports = DatasetController.extend({
                var me = this;
                var meta = me.getMeta();
                var dataset = me.getDataset();
-               var options = me._resolveElementOptions(rectangle, index);
+               var options = me._resolveDataElementOptions(rectangle, index);
 
                rectangle._xScale = me.getScaleForId(meta.xAxisID);
                rectangle._yScale = me.getScaleForId(meta.yAxisID);
@@ -372,46 +380,5 @@ module.exports = DatasetController.extend({
                }
 
                helpers.canvas.unclipArea(chart.ctx);
-       },
-
-       /**
-        * @private
-        */
-       _resolveElementOptions: function(rectangle, index) {
-               var me = this;
-               var chart = me.chart;
-               var datasets = chart.data.datasets;
-               var dataset = datasets[me.index];
-               var datasetOpts = me._config;
-               var custom = rectangle.custom || {};
-               var options = chart.options.elements.rectangle;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataIndex: index,
-                       dataset: dataset,
-                       datasetIndex: me.index
-               };
-
-               var keys = [
-                       'backgroundColor',
-                       'borderColor',
-                       'borderSkipped',
-                       'borderWidth'
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
-               return values;
        }
 });
index d724432f446736d4248f15ce26adb66e48251655..8882969d48a399d808bb5517e85bfc4f92bbc97f 100644 (file)
@@ -47,6 +47,22 @@ module.exports = DatasetController.extend({
         */
        dataElementType: elements.Point,
 
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+               'hoverRadius',
+               'hitRadius',
+               'pointStyle',
+               'rotation'
+       ],
+
        /**
         * @protected
         */
@@ -70,7 +86,7 @@ module.exports = DatasetController.extend({
                var custom = point.custom || {};
                var xScale = me.getScaleForId(meta.xAxisID);
                var yScale = me.getScaleForId(meta.yAxisID);
-               var options = me._resolveElementOptions(point, index);
+               var options = me._resolveDataElementOptions(point, index);
                var data = me.getDataset().data[index];
                var dsIndex = me.index;
 
@@ -122,17 +138,13 @@ module.exports = DatasetController.extend({
        /**
         * @private
         */
-       _resolveElementOptions: function(point, index) {
+       _resolveDataElementOptions: function(point, index) {
                var me = this;
                var chart = me.chart;
-               var datasets = chart.data.datasets;
-               var dataset = datasets[me.index];
-               var datasetOpts = me._config;
+               var dataset = me.getDataset();
                var custom = point.custom || {};
-               var options = chart.options.elements.point;
-               var data = dataset.data[index];
-               var values = {};
-               var i, ilen, key;
+               var data = dataset.data[index] || {};
+               var values = DatasetController.prototype._resolveDataElementOptions.apply(me, arguments);
 
                // Scriptable options
                var context = {
@@ -142,34 +154,12 @@ module.exports = DatasetController.extend({
                        datasetIndex: me.index
                };
 
-               var keys = [
-                       'backgroundColor',
-                       'borderColor',
-                       'borderWidth',
-                       'hoverBackgroundColor',
-                       'hoverBorderColor',
-                       'hoverBorderWidth',
-                       'hoverRadius',
-                       'hitRadius',
-                       'pointStyle',
-                       'rotation'
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
                // Custom radius resolution
                values.radius = resolve([
                        custom.radius,
-                       data ? data.r : undefined,
-                       dataset.radius,
-                       options.radius
+                       data.r,
+                       me._config.radius,
+                       chart.options.elements.point.radius
                ], context, index);
 
                return values;
index daa1ed1bdfda2ade27fbf4b3deec42037919de7e..de418e7edbc7eb09ec4577b9c73bb0892fcbabdb 100644 (file)
@@ -5,7 +5,6 @@ var defaults = require('../core/core.defaults');
 var elements = require('../elements/index');
 var helpers = require('../helpers/index');
 
-var resolve = helpers.options.resolve;
 var valueOrDefault = helpers.valueOrDefault;
 
 var PI = Math.PI;
@@ -50,20 +49,14 @@ defaults._set('doughnut', {
                                if (data.labels.length && data.datasets.length) {
                                        return data.labels.map(function(label, i) {
                                                var meta = chart.getDatasetMeta(0);
-                                               var ds = data.datasets[0];
-                                               var arc = meta.data[i];
-                                               var custom = arc && arc.custom || {};
-                                               var arcOpts = chart.options.elements.arc;
-                                               var fill = resolve([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
-                                               var stroke = resolve([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
-                                               var bw = resolve([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+                                               var style = meta.controller.getStyle(i);
 
                                                return {
                                                        text: label,
-                                                       fillStyle: fill,
-                                                       strokeStyle: stroke,
-                                                       lineWidth: bw,
-                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
 
                                                        // Extra data used for toggling the correct item
                                                        index: i
@@ -131,6 +124,19 @@ module.exports = DatasetController.extend({
 
        linkScales: helpers.noop,
 
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
        // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly
        getRingIndex: function(datasetIndex) {
                var ringIndex = 0;
@@ -184,7 +190,7 @@ module.exports = DatasetController.extend({
                }
 
                for (i = 0, ilen = arcs.length; i < ilen; ++i) {
-                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+                       arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
                }
 
                chart.borderWidth = me.getMaxBorderWidth();
@@ -317,7 +323,7 @@ module.exports = DatasetController.extend({
                        arc = arcs[i];
                        if (controller) {
                                controller._configure();
-                               options = controller._resolveElementOptions(arc, i);
+                               options = controller._resolveDataElementOptions(arc, i);
                        } else {
                                options = arc._options;
                        }
@@ -351,49 +357,6 @@ module.exports = DatasetController.extend({
                model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
        },
 
-       /**
-        * @private
-        */
-       _resolveElementOptions: function(arc, index) {
-               var me = this;
-               var chart = me.chart;
-               var dataset = me.getDataset();
-               var datasetOpts = me._config;
-               var custom = arc.custom || {};
-               var options = chart.options.elements.arc;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataIndex: index,
-                       dataset: dataset,
-                       datasetIndex: me.index
-               };
-
-               var keys = [
-                       'backgroundColor',
-                       'borderColor',
-                       'borderWidth',
-                       'borderAlign',
-                       'hoverBackgroundColor',
-                       'hoverBorderColor',
-                       'hoverBorderWidth',
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
-               return values;
-       },
-
        /**
         * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly
         * @private
index 759db4c7e72a4501ba65689965af827224fd1ce3..b7f06816d2b15e09aa609a160831cd8c2bd85445 100644 (file)
@@ -35,6 +35,38 @@ module.exports = DatasetController.extend({
 
        dataElementType: elements.Point,
 
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth',
+               'cubicInterpolationMode',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
        update: function(reset) {
                var me = this;
                var meta = me.getMeta();
@@ -61,7 +93,7 @@ module.exports = DatasetController.extend({
                        // Data
                        line._children = points;
                        // Model
-                       line._model = me._resolveLineOptions(line);
+                       line._model = me._resolveDatasetElementOptions(line);
 
                        line.pivot();
                }
@@ -93,7 +125,7 @@ module.exports = DatasetController.extend({
                var lineModel = meta.dataset._model;
                var x, y;
 
-               var options = me._resolvePointOptions(point, index);
+               var options = me._resolveDataElementOptions(point, index);
 
                x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);
                y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);
@@ -127,101 +159,20 @@ module.exports = DatasetController.extend({
        /**
         * @private
         */
-       _resolvePointOptions: function(element, index) {
-               var me = this;
-               var chart = me.chart;
-               var dataset = chart.data.datasets[me.index];
-               var datasetOpts = me._config;
-               var custom = element.custom || {};
-               var options = chart.options.elements.point;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataIndex: index,
-                       dataset: dataset,
-                       datasetIndex: me.index
-               };
-
-               var ELEMENT_OPTIONS = {
-                       backgroundColor: 'pointBackgroundColor',
-                       borderColor: 'pointBorderColor',
-                       borderWidth: 'pointBorderWidth',
-                       hitRadius: 'pointHitRadius',
-                       hoverBackgroundColor: 'pointHoverBackgroundColor',
-                       hoverBorderColor: 'pointHoverBorderColor',
-                       hoverBorderWidth: 'pointHoverBorderWidth',
-                       hoverRadius: 'pointHoverRadius',
-                       pointStyle: 'pointStyle',
-                       radius: 'pointRadius',
-                       rotation: 'pointRotation'
-               };
-               var keys = Object.keys(ELEMENT_OPTIONS);
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[ELEMENT_OPTIONS[key]],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
-               return values;
-       },
-
-       /**
-        * @private
-        */
-       _resolveLineOptions: function(element) {
+       _resolveDatasetElementOptions: function(element) {
                var me = this;
-               var chart = me.chart;
-               var datasetIndex = me.index;
-               var dataset = chart.data.datasets[datasetIndex];
                var datasetOpts = me._config;
                var custom = element.custom || {};
-               var options = chart.options;
-               var elementOptions = options.elements.line;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataset: dataset,
-                       datasetIndex: datasetIndex
-               };
-
-               var keys = [
-                       'backgroundColor',
-                       'borderCapStyle',
-                       'borderColor',
-                       'borderDash',
-                       'borderDashOffset',
-                       'borderJoinStyle',
-                       'borderWidth',
-                       'cubicInterpolationMode',
-                       'fill'
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               elementOptions[key]
-                       ], context);
-               }
+               var options = me.chart.options;
+               var lineOptions = options.elements.line;
+               var values = DatasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
 
                // The default behavior of lines is to break at null values, according
                // to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-216718158
                // This option gives lines the ability to span gaps
                values.spanGaps = valueOrDefault(datasetOpts.spanGaps, options.spanGaps);
-               values.tension = valueOrDefault(datasetOpts.lineTension, elementOptions.tension);
-               values.steppedLine = resolve([custom.steppedLine, datasetOpts.steppedLine, elementOptions.stepped]);
+               values.tension = valueOrDefault(datasetOpts.lineTension, lineOptions.tension);
+               values.steppedLine = resolve([custom.steppedLine, datasetOpts.steppedLine, lineOptions.stepped]);
 
                return values;
        },
index 582a0a78bf77bf79b7e1a76294c83655b91d3d06..1e0e30ba2dd6264ef09b2143d6234020225c3c64 100644 (file)
@@ -59,20 +59,14 @@ defaults._set('polarArea', {
                                if (data.labels.length && data.datasets.length) {
                                        return data.labels.map(function(label, i) {
                                                var meta = chart.getDatasetMeta(0);
-                                               var ds = data.datasets[0];
-                                               var arc = meta.data[i];
-                                               var custom = arc.custom || {};
-                                               var arcOpts = chart.options.elements.arc;
-                                               var fill = resolve([custom.backgroundColor, ds.backgroundColor, arcOpts.backgroundColor], undefined, i);
-                                               var stroke = resolve([custom.borderColor, ds.borderColor, arcOpts.borderColor], undefined, i);
-                                               var bw = resolve([custom.borderWidth, ds.borderWidth, arcOpts.borderWidth], undefined, i);
+                                               var style = meta.controller.getStyle(i);
 
                                                return {
                                                        text: label,
-                                                       fillStyle: fill,
-                                                       strokeStyle: stroke,
-                                                       lineWidth: bw,
-                                                       hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
+                                                       fillStyle: style.backgroundColor,
+                                                       strokeStyle: style.borderColor,
+                                                       lineWidth: style.borderWidth,
+                                                       hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,
 
                                                        // Extra data used for toggling the correct item
                                                        index: i
@@ -116,6 +110,19 @@ module.exports = DatasetController.extend({
 
        linkScales: helpers.noop,
 
+       /**
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'borderAlign',
+               'hoverBackgroundColor',
+               'hoverBorderColor',
+               'hoverBorderWidth',
+       ],
+
        update: function(reset) {
                var me = this;
                var dataset = me.getDataset();
@@ -138,7 +145,7 @@ module.exports = DatasetController.extend({
                }
 
                for (i = 0, ilen = arcs.length; i < ilen; ++i) {
-                       arcs[i]._options = me._resolveElementOptions(arcs[i], i);
+                       arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);
                        me.updateElement(arcs[i], i, reset);
                }
        },
@@ -241,49 +248,6 @@ module.exports = DatasetController.extend({
                model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);
        },
 
-       /**
-        * @private
-        */
-       _resolveElementOptions: function(arc, index) {
-               var me = this;
-               var chart = me.chart;
-               var dataset = me.getDataset();
-               var datasetOpts = me._config;
-               var custom = arc.custom || {};
-               var options = chart.options.elements.arc;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataIndex: index,
-                       dataset: dataset,
-                       datasetIndex: me.index
-               };
-
-               var keys = [
-                       'backgroundColor',
-                       'borderColor',
-                       'borderWidth',
-                       'borderAlign',
-                       'hoverBackgroundColor',
-                       'hoverBorderColor',
-                       'hoverBorderWidth',
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
-               return values;
-       },
-
        /**
         * @private
         */
index 1e32dd0a424c21f835fb2cdd80c65655eb5369fe..d83e472a73999fdcad052e4efb5ea196aac641a6 100644 (file)
@@ -6,7 +6,6 @@ var elements = require('../elements/index');
 var helpers = require('../helpers/index');
 
 var valueOrDefault = helpers.valueOrDefault;
-var resolve = helpers.options.resolve;
 
 defaults._set('radar', {
        scale: {
@@ -33,6 +32,37 @@ module.exports = DatasetController.extend({
 
        linkScales: helpers.noop,
 
+       /**
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderWidth',
+               'borderColor',
+               'borderCapStyle',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'fill'
+       ],
+
+       /**
+        * @private
+        */
+       _dataElementOptions: {
+               backgroundColor: 'pointBackgroundColor',
+               borderColor: 'pointBorderColor',
+               borderWidth: 'pointBorderWidth',
+               hitRadius: 'pointHitRadius',
+               hoverBackgroundColor: 'pointHoverBackgroundColor',
+               hoverBorderColor: 'pointHoverBorderColor',
+               hoverBorderWidth: 'pointHoverBorderWidth',
+               hoverRadius: 'pointHoverRadius',
+               pointStyle: 'pointStyle',
+               radius: 'pointRadius',
+               rotation: 'pointRotation'
+       },
+
        update: function(reset) {
                var me = this;
                var meta = me.getMeta();
@@ -54,7 +84,7 @@ module.exports = DatasetController.extend({
                line._children = points;
                line._loop = true;
                // Model
-               line._model = me._resolveLineOptions(line);
+               line._model = me._resolveDatasetElementOptions(line);
 
                line.pivot();
 
@@ -78,7 +108,7 @@ module.exports = DatasetController.extend({
                var dataset = me.getDataset();
                var scale = me.chart.scale;
                var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);
-               var options = me._resolvePointOptions(point, index);
+               var options = me._resolveDataElementOptions(point, index);
                var lineModel = me.getMeta().dataset._model;
                var x = reset ? scale.xCenter : pointPosition.x;
                var y = reset ? scale.yCenter : pointPosition.y;
@@ -111,86 +141,11 @@ module.exports = DatasetController.extend({
        /**
         * @private
         */
-       _resolvePointOptions: function(element, index) {
-               var me = this;
-               var chart = me.chart;
-               var dataset = chart.data.datasets[me.index];
-               var datasetOpts = me._config;
-               var custom = element.custom || {};
-               var options = chart.options.elements.point;
-               var values = {};
-               var i, ilen, key;
-
-               // Scriptable options
-               var context = {
-                       chart: chart,
-                       dataIndex: index,
-                       dataset: dataset,
-                       datasetIndex: me.index
-               };
-
-               var ELEMENT_OPTIONS = {
-                       backgroundColor: 'pointBackgroundColor',
-                       borderColor: 'pointBorderColor',
-                       borderWidth: 'pointBorderWidth',
-                       hitRadius: 'pointHitRadius',
-                       hoverBackgroundColor: 'pointHoverBackgroundColor',
-                       hoverBorderColor: 'pointHoverBorderColor',
-                       hoverBorderWidth: 'pointHoverBorderWidth',
-                       hoverRadius: 'pointHoverRadius',
-                       pointStyle: 'pointStyle',
-                       radius: 'pointRadius',
-                       rotation: 'pointRotation'
-               };
-               var keys = Object.keys(ELEMENT_OPTIONS);
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[ELEMENT_OPTIONS[key]],
-                               datasetOpts[key],
-                               options[key]
-                       ], context, index);
-               }
-
-               return values;
-       },
-
-       /**
-        * @private
-        */
-       _resolveLineOptions: function(element) {
+       _resolveDatasetElementOptions: function() {
                var me = this;
-               var chart = me.chart;
-               var dataset = chart.data.datasets[me.index];
-               var datasetOpts = me._config;
-               var custom = element.custom || {};
-               var options = chart.options.elements.line;
-               var values = {};
-               var i, ilen, key;
-
-               var keys = [
-                       'backgroundColor',
-                       'borderWidth',
-                       'borderColor',
-                       'borderCapStyle',
-                       'borderDash',
-                       'borderDashOffset',
-                       'borderJoinStyle',
-                       'fill'
-               ];
-
-               for (i = 0, ilen = keys.length; i < ilen; ++i) {
-                       key = keys[i];
-                       values[key] = resolve([
-                               custom[key],
-                               datasetOpts[key],
-                               options[key]
-                       ]);
-               }
+               var values = DatasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);
 
-               values.tension = valueOrDefault(dataset.lineTension, options.tension);
+               values.tension = valueOrDefault(me._config.lineTension, me.chart.options.elements.line.tension);
 
                return values;
        },
index 45a2e894236f5580db5ea59e5a36a04eba0fc4fa..2f7826a7674d66641b60d6be1bd3b25377a2bad3 100644 (file)
@@ -94,6 +94,35 @@ helpers.extend(DatasetController.prototype, {
         */
        dataElementType: null,
 
+       /**
+        * Dataset element option keys to be resolved in _resolveDatasetElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _datasetElementOptions: [
+               'backgroundColor',
+               'borderCapStyle',
+               'borderColor',
+               'borderDash',
+               'borderDashOffset',
+               'borderJoinStyle',
+               'borderWidth'
+       ],
+
+       /**
+        * Data element option keys to be resolved in _resolveDataElementOptions.
+        * A derived controller may override this to resolve controller-specific options.
+        * The keys defined here are for backward compatibility for legend styles.
+        * @private
+        */
+       _dataElementOptions: [
+               'backgroundColor',
+               'borderColor',
+               'borderWidth',
+               'pointStyle'
+       ],
+
        initialize: function(chart, datasetIndex) {
                var me = this;
                me.chart = chart;
@@ -293,6 +322,111 @@ helpers.extend(DatasetController.prototype, {
                }
        },
 
+       /**
+        * Returns a set of predefined style properties that should be used to represent the dataset
+        * or the data if the index is specified
+        * @param {number} index - data index
+        * @return {IStyleInterface} style object
+        */
+       getStyle: function(index) {
+               var me = this;
+               var meta = me.getMeta();
+               var dataset = meta.dataset;
+               var style;
+
+               me._configure();
+               if (dataset && index === undefined) {
+                       style = me._resolveDatasetElementOptions(dataset || {});
+               } else {
+                       index = index || 0;
+                       style = me._resolveDataElementOptions(meta.data[index] || {}, index);
+               }
+
+               if (style.fill === false || style.fill === null) {
+                       style.backgroundColor = 'rgba(0,0,0,0)';
+               }
+
+               return style;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDatasetElementOptions: function(element) {
+               var me = this;
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var custom = element.custom || {};
+               var options = chart.options.elements[me.datasetElementType.prototype._type] || {};
+               var elementOptions = me._datasetElementOptions;
+               var values = {};
+               var i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index
+               };
+
+               for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                       key = elementOptions[i];
+                       values[key] = resolve([
+                               custom[key],
+                               datasetOpts[key],
+                               options[key]
+                       ], context);
+               }
+
+               return values;
+       },
+
+       /**
+        * @private
+        */
+       _resolveDataElementOptions: function(element, index) {
+               var me = this;
+               var chart = me.chart;
+               var datasetOpts = me._config;
+               var custom = element.custom || {};
+               var options = chart.options.elements[me.dataElementType.prototype._type] || {};
+               var elementOptions = me._dataElementOptions;
+               var values = {};
+               var keys, i, ilen, key;
+
+               // Scriptable options
+               var context = {
+                       chart: chart,
+                       dataIndex: index,
+                       dataset: me.getDataset(),
+                       datasetIndex: me.index
+               };
+
+               if (helpers.isArray(elementOptions)) {
+                       for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {
+                               key = elementOptions[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index);
+                       }
+               } else {
+                       keys = Object.keys(elementOptions);
+                       for (i = 0, ilen = keys.length; i < ilen; ++i) {
+                               key = keys[i];
+                               values[key] = resolve([
+                                       custom[key],
+                                       datasetOpts[elementOptions[key]],
+                                       datasetOpts[key],
+                                       options[key]
+                               ], context, index);
+                       }
+               }
+
+               return values;
+       },
+
        removeHoverStyle: function(element) {
                helpers.merge(element._model, element.$previousStyle || {});
                delete element.$previousStyle;
index ecfec2c994da2deae0dba015a643769e8465abc5..e4dc4feee319ff00f139ec0b6fb265f129729eb6 100644 (file)
@@ -58,6 +58,7 @@ var Element = function(configuration) {
 };
 
 helpers.extend(Element.prototype, {
+       _type: undefined,
 
        initialize: function() {
                this.hidden = false;
index e3b8875b4ddcc7a99b6b4d5e6a1e09f9d2376bd1..3dab9ad6277a670285a965b233487ae9ce7580cb 100644 (file)
@@ -92,6 +92,8 @@ function drawBorder(ctx, vm, arc) {
 }
 
 module.exports = Element.extend({
+       _type: 'arc',
+
        inLabelRange: function(mouseX) {
                var vm = this._view;
 
index 12c0f5a3664048c16a8ad4933db4bd4cb99207ca..8a801f6516fe54c98b09d1570dde38f1e5ed30d3 100644 (file)
@@ -26,6 +26,8 @@ defaults._set('global', {
 });
 
 module.exports = Element.extend({
+       _type: 'line',
+
        draw: function() {
                var me = this;
                var vm = me._view;
index 1e6b22357ec7b8376346498a46b3c59c87457abd..9e1456a2d642446aaaac4c740af5a14774d53499 100644 (file)
@@ -35,6 +35,8 @@ function yRange(mouseY) {
 }
 
 module.exports = Element.extend({
+       _type: 'point',
+
        inRange: function(mouseX, mouseY) {
                var vm = this._view;
                return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;
index 5e5a2eac459963bebcb1b0f99ee75564a80fe074..d1ef58c13c33440c190206fe5659ad8fe248b09b 100644 (file)
@@ -131,6 +131,8 @@ function inRange(vm, x, y) {
 }
 
 module.exports = Element.extend({
+       _type: 'rectangle',
+
        draw: function() {
                var ctx = this._chart.ctx;
                var vm = this._view;
index d3fd5e35f0491a83c23eeb1c2dd4211b24a2fcb8..b6101561dc8fdab7f71a671b447918db0a8821ae 100644 (file)
@@ -49,18 +49,25 @@ defaults._set('global', {
                        // lineWidth :
                        generateLabels: function(chart) {
                                var data = chart.data;
+                               var options = chart.options.legend || {};
+                               var usePointStyle = options.labels && options.labels.usePointStyle;
+
                                return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) {
+                                       var meta = chart.getDatasetMeta(i);
+                                       var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
+
                                        return {
                                                text: dataset.label,
-                                               fillStyle: (!helpers.isArray(dataset.backgroundColor) ? dataset.backgroundColor : dataset.backgroundColor[0]),
+                                               fillStyle: style.backgroundColor,
                                                hidden: !chart.isDatasetVisible(i),
-                                               lineCap: dataset.borderCapStyle,
-                                               lineDash: dataset.borderDash,
-                                               lineDashOffset: dataset.borderDashOffset,
-                                               lineJoin: dataset.borderJoinStyle,
-                                               lineWidth: dataset.borderWidth,
-                                               strokeStyle: dataset.borderColor,
-                                               pointStyle: dataset.pointStyle,
+                                               lineCap: style.borderCapStyle,
+                                               lineDash: style.borderDash,
+                                               lineDashOffset: style.borderDashOffset,
+                                               lineJoin: style.borderJoinStyle,
+                                               lineWidth: style.borderWidth,
+                                               strokeStyle: style.borderColor,
+                                               pointStyle: style.pointStyle,
+                                               rotation: style.rotation,
 
                                                // Below is extra data used for toggling the datasets
                                                datasetIndex: i
@@ -377,7 +384,7 @@ var Legend = Element.extend({
                                        ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
                                }
 
-                               if (opts.labels && opts.labels.usePointStyle) {
+                               if (labelOpts && labelOpts.usePointStyle) {
                                        // Recalculate x and y for drawPoint() because its expecting
                                        // x and y to be center of figure (instead of top left)
                                        var radius = boxWidth * Math.SQRT2 / 2;
@@ -385,13 +392,13 @@ var Legend = Element.extend({
                                        var centerY = y + fontSize / 2;
 
                                        // Draw pointStyle as legend symbol
-                                       helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
+                                       helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY, legendItem.rotation);
                                } else {
                                        // Draw box as legend symbol
+                                       ctx.fillRect(x, y, boxWidth, fontSize);
                                        if (lineWidth !== 0) {
                                                ctx.strokeRect(x, y, boxWidth, fontSize);
                                        }
-                                       ctx.fillRect(x, y, boxWidth, fontSize);
                                }
 
                                ctx.restore();
index 18829cac04ac38b05f5c400834448157e917fa3b..06c8b2cf4c464ecdf54f4f1bd581c065f33e78cf 100644 (file)
@@ -24,7 +24,7 @@ describe('Legend block tests', function() {
                });
        });
 
-       it('should update correctly', function() {
+       it('should update bar chart correctly', function() {
                var chart = window.acquireChart({
                        type: 'bar',
                        data: {
@@ -55,29 +55,31 @@ describe('Legend block tests', function() {
                        text: 'dataset1',
                        fillStyle: '#f31',
                        hidden: false,
-                       lineCap: 'butt',
-                       lineDash: [2, 2],
-                       lineDashOffset: 5.5,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
                        lineJoin: undefined,
-                       lineWidth: undefined,
-                       strokeStyle: undefined,
+                       lineWidth: 0,
+                       strokeStyle: 'rgba(0,0,0,0.1)',
                        pointStyle: undefined,
+                       rotation: undefined,
                        datasetIndex: 0
                }, {
                        text: 'dataset2',
-                       fillStyle: undefined,
+                       fillStyle: 'rgba(0,0,0,0.1)',
                        hidden: true,
                        lineCap: undefined,
                        lineDash: undefined,
                        lineDashOffset: undefined,
-                       lineJoin: 'miter',
-                       lineWidth: undefined,
-                       strokeStyle: undefined,
+                       lineJoin: undefined,
+                       lineWidth: 0,
+                       strokeStyle: 'rgba(0,0,0,0.1)',
                        pointStyle: undefined,
+                       rotation: undefined,
                        datasetIndex: 1
                }, {
                        text: 'dataset3',
-                       fillStyle: undefined,
+                       fillStyle: 'rgba(0,0,0,0.1)',
                        hidden: false,
                        lineCap: undefined,
                        lineDash: undefined,
@@ -85,7 +87,78 @@ describe('Legend block tests', function() {
                        lineJoin: undefined,
                        lineWidth: 10,
                        strokeStyle: 'green',
-                       pointStyle: 'crossRot',
+                       pointStyle: undefined,
+                       rotation: undefined,
+                       datasetIndex: 2
+               }]);
+       });
+
+       it('should update line chart correctly', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'dataset1',
+                                       backgroundColor: '#f31',
+                                       borderCapStyle: 'round',
+                                       borderDash: [2, 2],
+                                       borderDashOffset: 5.5,
+                                       data: []
+                               }, {
+                                       label: 'dataset2',
+                                       hidden: true,
+                                       borderJoinStyle: 'round',
+                                       data: []
+                               }, {
+                                       label: 'dataset3',
+                                       borderWidth: 10,
+                                       borderColor: 'green',
+                                       pointStyle: 'crossRot',
+                                       fill: false,
+                                       data: []
+                               }],
+                               labels: []
+                       }
+               });
+
+               expect(chart.legend.legendItems).toEqual([{
+                       text: 'dataset1',
+                       fillStyle: '#f31',
+                       hidden: false,
+                       lineCap: 'round',
+                       lineDash: [2, 2],
+                       lineDashOffset: 5.5,
+                       lineJoin: 'miter',
+                       lineWidth: 3,
+                       strokeStyle: 'rgba(0,0,0,0.1)',
+                       pointStyle: undefined,
+                       rotation: undefined,
+                       datasetIndex: 0
+               }, {
+                       text: 'dataset2',
+                       fillStyle: 'rgba(0,0,0,0.1)',
+                       hidden: true,
+                       lineCap: 'butt',
+                       lineDash: [],
+                       lineDashOffset: 0,
+                       lineJoin: 'round',
+                       lineWidth: 3,
+                       strokeStyle: 'rgba(0,0,0,0.1)',
+                       pointStyle: undefined,
+                       rotation: undefined,
+                       datasetIndex: 1
+               }, {
+                       text: 'dataset3',
+                       fillStyle: 'rgba(0,0,0,0)',
+                       hidden: false,
+                       lineCap: 'butt',
+                       lineDash: [],
+                       lineDashOffset: 0,
+                       lineJoin: 'miter',
+                       lineWidth: 10,
+                       strokeStyle: 'green',
+                       pointStyle: undefined,
+                       rotation: undefined,
                        datasetIndex: 2
                }]);
        });
@@ -132,17 +205,18 @@ describe('Legend block tests', function() {
                        text: 'dataset1',
                        fillStyle: '#f31',
                        hidden: false,
-                       lineCap: 'butt',
-                       lineDash: [2, 2],
-                       lineDashOffset: 5.5,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
                        lineJoin: undefined,
-                       lineWidth: undefined,
-                       strokeStyle: undefined,
+                       lineWidth: 0,
+                       strokeStyle: 'rgba(0,0,0,0.1)',
                        pointStyle: undefined,
+                       rotation: undefined,
                        datasetIndex: 0
                }, {
                        text: 'dataset3',
-                       fillStyle: undefined,
+                       fillStyle: 'rgba(0,0,0,0.1)',
                        hidden: false,
                        lineCap: undefined,
                        lineDash: undefined,
@@ -150,7 +224,8 @@ describe('Legend block tests', function() {
                        lineJoin: undefined,
                        lineWidth: 10,
                        strokeStyle: 'green',
-                       pointStyle: 'crossRot',
+                       pointStyle: undefined,
+                       rotation: undefined,
                        datasetIndex: 2
                }]);
        });
@@ -217,6 +292,145 @@ describe('Legend block tests', function() {
                });
        });
 
+       it('should pick up the first item when the property is an array', function() {
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       label: 'dataset1',
+                                       backgroundColor: ['#f31', '#666', '#14e'],
+                                       borderWidth: [5, 10, 15],
+                                       borderColor: ['red', 'green', 'blue'],
+                                       data: []
+                               }],
+                               labels: []
+                       }
+               });
+
+               expect(chart.legend.legendItems).toEqual([{
+                       text: 'dataset1',
+                       fillStyle: '#f31',
+                       hidden: false,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
+                       lineJoin: undefined,
+                       lineWidth: 5,
+                       strokeStyle: 'red',
+                       pointStyle: undefined,
+                       rotation: undefined,
+                       datasetIndex: 0
+               }]);
+       });
+
+       it('should use the value for the first item when the property is a function', function() {
+               var helpers = window.Chart.helpers;
+               var chart = window.acquireChart({
+                       type: 'bar',
+                       data: {
+                               datasets: [{
+                                       label: 'dataset1',
+                                       backgroundColor: function(ctx) {
+                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
+                                               return helpers.color({r: value * 10, g: 0, b: 0}).rgbString();
+                                       },
+                                       borderWidth: function(ctx) {
+                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
+                                               return value;
+                                       },
+                                       borderColor: function(ctx) {
+                                               var value = ctx.dataset.data[ctx.dataIndex] || 0;
+                                               return helpers.color({r: 255 - value * 10, g: 0, b: 0}).rgbString();
+                                       },
+                                       data: [5, 10, 15, 20]
+                               }],
+                               labels: ['A', 'B', 'C', 'D']
+                       }
+               });
+
+               expect(chart.legend.legendItems).toEqual([{
+                       text: 'dataset1',
+                       fillStyle: 'rgb(50, 0, 0)',
+                       hidden: false,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
+                       lineJoin: undefined,
+                       lineWidth: 5,
+                       strokeStyle: 'rgb(205, 0, 0)',
+                       pointStyle: undefined,
+                       rotation: undefined,
+                       datasetIndex: 0
+               }]);
+       });
+
+       it('should draw correctly when usePointStyle is true', function() {
+               var chart = window.acquireChart({
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'dataset1',
+                                       backgroundColor: '#f31',
+                                       borderCapStyle: 'butt',
+                                       borderDash: [2, 2],
+                                       borderDashOffset: 5.5,
+                                       borderWidth: 0,
+                                       borderColor: '#f31',
+                                       pointStyle: 'crossRot',
+                                       pointBackgroundColor: 'rgba(0,0,0,0.1)',
+                                       pointBorderWidth: 5,
+                                       pointBorderColor: 'green',
+                                       data: []
+                               }, {
+                                       label: 'dataset2',
+                                       backgroundColor: '#f31',
+                                       borderJoinStyle: 'miter',
+                                       borderWidth: 2,
+                                       borderColor: '#f31',
+                                       pointStyle: 'crossRot',
+                                       pointRotation: 15,
+                                       data: []
+                               }],
+                               labels: []
+                       },
+                       options: {
+                               legend: {
+                                       labels: {
+                                               usePointStyle: true
+                                       }
+                               }
+                       }
+               });
+
+               expect(chart.legend.legendItems).toEqual([{
+                       text: 'dataset1',
+                       fillStyle: 'rgba(0,0,0,0.1)',
+                       hidden: false,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
+                       lineJoin: undefined,
+                       lineWidth: 5,
+                       strokeStyle: 'green',
+                       pointStyle: 'crossRot',
+                       rotation: undefined,
+                       datasetIndex: 0
+               }, {
+                       text: 'dataset2',
+                       fillStyle: '#f31',
+                       hidden: false,
+                       lineCap: undefined,
+                       lineDash: undefined,
+                       lineDashOffset: undefined,
+                       lineJoin: undefined,
+                       lineWidth: 2,
+                       strokeStyle: '#f31',
+                       pointStyle: 'crossRot',
+                       rotation: 15,
+                       datasetIndex: 1
+               }]);
+       });
+
        describe('config update', function() {
                it ('should update the options', function() {
                        var chart = acquireChart({