From 01461682e199b491215711cd44f68658b457e9f1 Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Sat, 7 Jul 2018 04:06:02 +0800 Subject: [PATCH 1/6] Make legend appearance consistent with chart elements - Use the default value for each element type if a property is not set - Stroke after fill to move borders to the front - Support indexable and scriptable options - Use point's colors and border width when usePointStyle is true - Disable line styles when usePointStyle is true or the dataset type is not 'line' or 'radar' - Add getStyle method to provide style properties for dataset or data - Fix the existing tests and add more tests --- docs/configuration/legend.md | 5 +- src/controllers/controller.doughnut.js | 16 +- src/controllers/controller.line.js | 9 + src/controllers/controller.polarArea.js | 16 +- src/controllers/controller.radar.js | 9 + src/core/core.datasetController.js | 33 ++++ src/plugins/plugin.legend.js | 29 +-- test/specs/plugin.legend.tests.js | 252 ++++++++++++++++++++++-- 8 files changed, 316 insertions(+), 53 deletions(-) diff --git a/docs/configuration/legend.md b/docs/configuration/legend.md index f8ce7eb5a17..5caef61759d 100644 --- a/docs/configuration/legend.md +++ b/docs/configuration/legend.md @@ -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 } ``` diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index daa1ed1bdfd..a2dc3d309b9 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -50,20 +50,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 diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index c671d657933..20c7cad88fe 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -122,6 +122,15 @@ module.exports = DatasetController.extend({ }; }, + /** + * @private + */ + _resolveElementOptions: function(element, index) { + return index >= 0 + ? this._resolvePointOptions(element, index) + : this._resolveLineOptions(element); + }, + /** * @private */ diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 582a0a78bf7..88512f9f1d0 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -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 diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 1e32dd0a424..934dcb58732 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -108,6 +108,15 @@ module.exports = DatasetController.extend({ }; }, + /** + * @private + */ + _resolveElementOptions: function(element, index) { + return index >= 0 + ? this._resolvePointOptions(element, index) + : this._resolveLineOptions(element); + }, + /** * @private */ diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 45a2e894236..4655cf98523 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -293,6 +293,39 @@ 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 + * @params {number} index - data index + * @return {IStyleInterface} style object + */ + getStyle: function(index) { + var me = this; + var meta = me.getMeta(); + var element, style; + + if (meta.dataset && index === undefined) { + element = meta.dataset; + } else { + index = index || 0; + element = meta.data[index]; + } + style = me._resolveElementOptions(element || {}, index); + + if (style.fill === false || style.fill === null) { + style.backgroundColor = 'rgba(0,0,0,0)'; + } + + return style; + }, + + /** + * @private + */ + _resolveElementOptions: function() { + throw new Error('This method is not implemented.'); + }, + removeHoverStyle: function(element) { helpers.merge(element._model, element.$previousStyle || {}); delete element.$previousStyle; diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index d3fd5e35f04..b6101561dc8 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -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(); diff --git a/test/specs/plugin.legend.tests.js b/test/specs/plugin.legend.tests.js index 18829cac04a..06c8b2cf4c4 100644 --- a/test/specs/plugin.legend.tests.js +++ b/test/specs/plugin.legend.tests.js @@ -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({ From 9adc03f385534d2bbbd4eea41721b862da541756 Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Thu, 2 May 2019 03:56:01 +0800 Subject: [PATCH 2/6] Implement _resolveElementOptions in the base datasetController and refactor derived controllers --- src/controllers/controller.bar.js | 53 +++----------- src/controllers/controller.bubble.js | 53 ++++++-------- src/controllers/controller.doughnut.js | 57 ++++----------- src/controllers/controller.line.js | 94 ++++++++++--------------- src/controllers/controller.polarArea.js | 56 ++++----------- src/controllers/controller.radar.js | 69 +++++++----------- src/core/core.datasetController.js | 49 ++++++++++++- src/elements/element.arc.js | 2 + src/elements/element.line.js | 2 + src/elements/element.point.js | 2 + src/elements/element.rectangle.js | 2 + 11 files changed, 177 insertions(+), 262 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 7130a9d0905..193711a0d0c 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -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 + */ + _optionKeys: [ + 'backgroundColor', + 'borderColor', + 'borderSkipped', + 'borderWidth' + ], + initialize: function() { var me = this; var meta; @@ -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; } }); diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index d724432f446..b6fc0befb86 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -47,6 +47,22 @@ module.exports = DatasetController.extend({ */ dataElementType: elements.Point, + /** + * @private + */ + _optionKeys: [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'hoverBackgroundColor', + 'hoverBorderColor', + 'hoverBorderWidth', + 'hoverRadius', + 'hitRadius', + 'pointStyle', + 'rotation' + ], + /** * @protected */ @@ -125,14 +141,11 @@ module.exports = DatasetController.extend({ _resolveElementOptions: function(point, index) { var me = this; var chart = me.chart; - var datasets = chart.data.datasets; - var dataset = datasets[me.index]; + var dataset = me.getDataset(); var datasetOpts = me._config; 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._resolveElementOptions.apply(me, arguments); // Scriptable options var context = { @@ -142,34 +155,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, + datasetOpts.radius, + chart.options.elements.point.radius ], context, index); return values; diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index a2dc3d309b9..cdd25ac4784 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -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; @@ -125,6 +124,19 @@ module.exports = DatasetController.extend({ linkScales: helpers.noop, + /** + * @private + */ + _optionKeys: [ + '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; @@ -345,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 diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 20c7cad88fe..b07bc295c05 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -35,6 +35,21 @@ module.exports = DatasetController.extend({ dataElementType: elements.Point, + /** + * @private + */ + _optionKeys: [ + 'backgroundColor', + 'borderCapStyle', + 'borderColor', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'borderWidth', + 'cubicInterpolationMode', + 'fill' + ], + update: function(reset) { var me = this; var meta = me.getMeta(); @@ -59,7 +74,7 @@ module.exports = DatasetController.extend({ // Data line._children = points; // Model - line._model = me._resolveLineOptions(line); + line._model = me._resolveElementOptions(line); line.pivot(); } @@ -126,9 +141,27 @@ module.exports = DatasetController.extend({ * @private */ _resolveElementOptions: function(element, index) { - return index >= 0 - ? this._resolvePointOptions(element, index) - : this._resolveLineOptions(element); + var me = this; + var datasetOpts, custom, options, lineOptions, values; + + if (index >= 0) { + return me._resolvePointOptions(element, index); + } + + datasetOpts = me._config; + custom = element.custom || {}; + options = me.chart.options; + lineOptions = options.elements.line; + values = DatasetController.prototype._resolveElementOptions.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, lineOptions.tension); + values.steppedLine = resolve([custom.steppedLine, datasetOpts.steppedLine, lineOptions.stepped]); + + return values; }, /** @@ -180,59 +213,6 @@ module.exports = DatasetController.extend({ return values; }, - /** - * @private - */ - _resolveLineOptions: 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); - } - - // 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]); - - return values; - }, - calculatePointY: function(value, index, datasetIndex) { var me = this; var chart = me.chart; diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 88512f9f1d0..c250a6967e1 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -110,6 +110,19 @@ module.exports = DatasetController.extend({ linkScales: helpers.noop, + /** + * @private + */ + _optionKeys: [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'borderAlign', + 'hoverBackgroundColor', + 'hoverBorderColor', + 'hoverBorderWidth', + ], + update: function(reset) { var me = this; var dataset = me.getDataset(); @@ -235,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 */ diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 934dcb58732..f646c3bf0e8 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -33,6 +33,20 @@ module.exports = DatasetController.extend({ linkScales: helpers.noop, + /** + * @private + */ + _optionKeys: [ + 'backgroundColor', + 'borderWidth', + 'borderColor', + 'borderCapStyle', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'fill' + ], + update: function(reset) { var me = this; var meta = me.getMeta(); @@ -54,7 +68,7 @@ module.exports = DatasetController.extend({ line._children = points; line._loop = true; // Model - line._model = me._resolveLineOptions(line); + line._model = me._resolveElementOptions(line); line.pivot(); @@ -112,9 +126,18 @@ module.exports = DatasetController.extend({ * @private */ _resolveElementOptions: function(element, index) { - return index >= 0 - ? this._resolvePointOptions(element, index) - : this._resolveLineOptions(element); + var me = this; + var datasetOpts, values; + + if (index >= 0) { + return me._resolvePointOptions(element, index); + } + + datasetOpts = me._config; + values = DatasetController.prototype._resolveElementOptions.apply(me, arguments); + values.tension = valueOrDefault(datasetOpts.lineTension, me.chart.options.elements.line.tension); + + return values; }, /** @@ -166,44 +189,6 @@ module.exports = DatasetController.extend({ return values; }, - /** - * @private - */ - _resolveLineOptions: function(element) { - 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] - ]); - } - - values.tension = valueOrDefault(dataset.lineTension, options.tension); - - return values; - }, - updateBezierControlPoints: function() { var me = this; var meta = me.getMeta(); diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 4655cf98523..bba6229bf7c 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -94,6 +94,23 @@ helpers.extend(DatasetController.prototype, { */ dataElementType: null, + /** + * Element option keys to be resolved in _resolveElementOptions. + * A derived controller may override this to resolve controller-specific options. + * The keys defined here are for backward compatibility for legend styles. + * @private + */ + _optionKeys: [ + 'backgroundColor', + 'borderColor', + 'borderCapStyle', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'borderWidth', + 'pointStyle' + ], + initialize: function(chart, datasetIndex) { var me = this; me.chart = chart; @@ -310,6 +327,7 @@ helpers.extend(DatasetController.prototype, { index = index || 0; element = meta.data[index]; } + me._configure(); style = me._resolveElementOptions(element || {}, index); if (style.fill === false || style.fill === null) { @@ -322,8 +340,35 @@ helpers.extend(DatasetController.prototype, { /** * @private */ - _resolveElementOptions: function() { - throw new Error('This method is not implemented.'); + _resolveElementOptions: function(element, index) { + var me = this; + var chart = me.chart; + var datasetOpts = me._config; + var custom = element.custom || {}; + var type = index >= 0 ? me.dataElementType : me.datasetElementType; + var options = chart.options.elements[type.prototype._type]; + var keys = me._optionKeys; + var values = {}; + var i, ilen, key; + + // Scriptable options + var context = { + chart: chart, + dataIndex: index, + dataset: me.getDataset(), + datasetIndex: me.index + }; + + 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; }, removeHoverStyle: function(element) { diff --git a/src/elements/element.arc.js b/src/elements/element.arc.js index e3b8875b4dd..3dab9ad6277 100644 --- a/src/elements/element.arc.js +++ b/src/elements/element.arc.js @@ -92,6 +92,8 @@ function drawBorder(ctx, vm, arc) { } module.exports = Element.extend({ + _type: 'arc', + inLabelRange: function(mouseX) { var vm = this._view; diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 12c0f5a3664..8a801f6516f 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -26,6 +26,8 @@ defaults._set('global', { }); module.exports = Element.extend({ + _type: 'line', + draw: function() { var me = this; var vm = me._view; diff --git a/src/elements/element.point.js b/src/elements/element.point.js index 1e6b22357ec..9e1456a2d64 100644 --- a/src/elements/element.point.js +++ b/src/elements/element.point.js @@ -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; diff --git a/src/elements/element.rectangle.js b/src/elements/element.rectangle.js index 5e5a2eac459..d1ef58c13c3 100644 --- a/src/elements/element.rectangle.js +++ b/src/elements/element.rectangle.js @@ -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; From 7fa7e466001ec2e78fe9861358de9e455b66ebaf Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Thu, 2 May 2019 09:27:12 +0800 Subject: [PATCH 3/6] Add _type property to Element to avoid TypeError for custom elements --- src/core/core.datasetController.js | 2 +- src/core/core.element.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index bba6229bf7c..0580254e088 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -346,7 +346,7 @@ helpers.extend(DatasetController.prototype, { var datasetOpts = me._config; var custom = element.custom || {}; var type = index >= 0 ? me.dataElementType : me.datasetElementType; - var options = chart.options.elements[type.prototype._type]; + var options = chart.options.elements[type.prototype._type] || {}; var keys = me._optionKeys; var values = {}; var i, ilen, key; diff --git a/src/core/core.element.js b/src/core/core.element.js index ecfec2c994d..e4dc4feee31 100644 --- a/src/core/core.element.js +++ b/src/core/core.element.js @@ -58,6 +58,7 @@ var Element = function(configuration) { }; helpers.extend(Element.prototype, { + _type: undefined, initialize: function() { this.hidden = false; From 72ffd8aa349bf88650495a77f9a30b9d5ad2ec67 Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Thu, 2 May 2019 11:59:54 +0800 Subject: [PATCH 4/6] Further refactoring moving all _resolve*Options methods to the base controller and renaming --- src/controllers/controller.bar.js | 4 +- src/controllers/controller.bubble.js | 8 +-- src/controllers/controller.doughnut.js | 6 +- src/controllers/controller.line.js | 90 +++++++------------------ src/controllers/controller.polarArea.js | 4 +- src/controllers/controller.radar.js | 85 +++++++---------------- src/core/core.datasetController.js | 90 ++++++++++++++++++++----- 7 files changed, 133 insertions(+), 154 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 193711a0d0c..0736cf6e1e0 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -121,7 +121,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _dataElementOptions: [ 'backgroundColor', 'borderColor', 'borderSkipped', @@ -155,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); diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index b6fc0befb86..2cdbe0ae367 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -50,7 +50,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _dataElementOptions: [ 'backgroundColor', 'borderColor', 'borderWidth', @@ -86,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; @@ -138,14 +138,14 @@ module.exports = DatasetController.extend({ /** * @private */ - _resolveElementOptions: function(point, index) { + _resolveDataElementOptions: function(point, index) { var me = this; var chart = me.chart; var dataset = me.getDataset(); var datasetOpts = me._config; var custom = point.custom || {}; var data = dataset.data[index] || {}; - var values = DatasetController.prototype._resolveElementOptions.apply(me, arguments); + var values = DatasetController.prototype._resolveDataElementOptions.apply(me, arguments); // Scriptable options var context = { diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index cdd25ac4784..de418e7edbc 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -127,7 +127,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _dataElementOptions: [ 'backgroundColor', 'borderColor', 'borderWidth', @@ -190,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(); @@ -323,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; } diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index b07bc295c05..c7d2042444f 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -38,7 +38,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _datasetElementOptions: [ 'backgroundColor', 'borderCapStyle', 'borderColor', @@ -50,6 +50,23 @@ module.exports = DatasetController.extend({ '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(); @@ -74,7 +91,7 @@ module.exports = DatasetController.extend({ // Data line._children = points; // Model - line._model = me._resolveElementOptions(line); + line._model = me._resolveDatasetElementOptions(line); line.pivot(); } @@ -106,7 +123,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); @@ -140,19 +157,13 @@ module.exports = DatasetController.extend({ /** * @private */ - _resolveElementOptions: function(element, index) { + _resolveDatasetElementOptions: function(element) { var me = this; - var datasetOpts, custom, options, lineOptions, values; - - if (index >= 0) { - return me._resolvePointOptions(element, index); - } - - datasetOpts = me._config; - custom = element.custom || {}; - options = me.chart.options; - lineOptions = options.elements.line; - values = DatasetController.prototype._resolveElementOptions.apply(me, arguments); + var datasetOpts = me._config; + var custom = element.custom || {}; + 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 @@ -164,55 +175,6 @@ module.exports = DatasetController.extend({ return values; }, - /** - * @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; - }, - calculatePointY: function(value, index, datasetIndex) { var me = this; var chart = me.chart; diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index c250a6967e1..1e0e30ba2dd 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -113,7 +113,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _dataElementOptions: [ 'backgroundColor', 'borderColor', 'borderWidth', @@ -145,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); } }, diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index f646c3bf0e8..d83e472a739 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -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: { @@ -36,7 +35,7 @@ module.exports = DatasetController.extend({ /** * @private */ - _optionKeys: [ + _datasetElementOptions: [ 'backgroundColor', 'borderWidth', 'borderColor', @@ -47,6 +46,23 @@ module.exports = DatasetController.extend({ '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(); @@ -68,7 +84,7 @@ module.exports = DatasetController.extend({ line._children = points; line._loop = true; // Model - line._model = me._resolveElementOptions(line); + line._model = me._resolveDatasetElementOptions(line); line.pivot(); @@ -92,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; @@ -125,66 +141,11 @@ module.exports = DatasetController.extend({ /** * @private */ - _resolveElementOptions: function(element, index) { + _resolveDatasetElementOptions: function() { var me = this; - var datasetOpts, values; + var values = DatasetController.prototype._resolveDatasetElementOptions.apply(me, arguments); - if (index >= 0) { - return me._resolvePointOptions(element, index); - } - - datasetOpts = me._config; - values = DatasetController.prototype._resolveElementOptions.apply(me, arguments); - values.tension = valueOrDefault(datasetOpts.lineTension, me.chart.options.elements.line.tension); - - return values; - }, - - /** - * @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); - } + values.tension = valueOrDefault(me._config.lineTension, me.chart.options.elements.line.tension); return values; }, diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 0580254e088..d438a579357 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -95,18 +95,30 @@ helpers.extend(DatasetController.prototype, { dataElementType: null, /** - * Element option keys to be resolved in _resolveElementOptions. + * 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 */ - _optionKeys: [ + _datasetElementOptions: [ 'backgroundColor', - 'borderColor', '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' ], @@ -319,16 +331,16 @@ helpers.extend(DatasetController.prototype, { getStyle: function(index) { var me = this; var meta = me.getMeta(); - var element, style; + var dataset = meta.dataset; + var style; - if (meta.dataset && index === undefined) { - element = meta.dataset; + me._configure(); + if (dataset && index === undefined) { + style = me._resolveDatasetElementOptions(dataset || {}); } else { index = index || 0; - element = meta.data[index]; + style = me._resolveDataElementOptions(meta.data[index] || {}, index); } - me._configure(); - style = me._resolveElementOptions(element || {}, index); if (style.fill === false || style.fill === null) { style.backgroundColor = 'rgba(0,0,0,0)'; @@ -340,32 +352,76 @@ helpers.extend(DatasetController.prototype, { /** * @private */ - _resolveElementOptions: function(element, index) { + _resolveDatasetElementOptions: function(element) { var me = this; var chart = me.chart; var datasetOpts = me._config; var custom = element.custom || {}; - var type = index >= 0 ? me.dataElementType : me.datasetElementType; - var options = chart.options.elements[type.prototype._type] || {}; - var keys = me._optionKeys; + 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, - dataIndex: index, dataset: me.getDataset(), datasetIndex: me.index }; - for (i = 0, ilen = keys.length; i < ilen; ++i) { - key = keys[i]; + for (i = 0, ilen = elementOptions.length; i < ilen; ++i) { + key = elementOptions[i]; values[key] = resolve([ custom[key], datasetOpts[key], options[key] - ], context, index); + ], 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; From 9879c111b4475f17352ee9d3ad39e5554312706c Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Fri, 3 May 2019 00:23:49 +0800 Subject: [PATCH 5/6] Fix typo --- src/core/core.datasetController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index d438a579357..2f7826a7674 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -325,7 +325,7 @@ 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 - * @params {number} index - data index + * @param {number} index - data index * @return {IStyleInterface} style object */ getStyle: function(index) { From 66895aeeffc83036a99c3fc9ec492979d35e0123 Mon Sep 17 00:00:00 2001 From: Akihiko Kusanagi Date: Wed, 8 May 2019 00:27:49 +0800 Subject: [PATCH 6/6] Small optimization --- src/controllers/controller.bubble.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 2cdbe0ae367..8882969d48a 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -142,7 +142,6 @@ module.exports = DatasetController.extend({ var me = this; var chart = me.chart; var dataset = me.getDataset(); - var datasetOpts = me._config; var custom = point.custom || {}; var data = dataset.data[index] || {}; var values = DatasetController.prototype._resolveDataElementOptions.apply(me, arguments); @@ -159,7 +158,7 @@ module.exports = DatasetController.extend({ values.radius = resolve([ custom.radius, data.r, - datasetOpts.radius, + me._config.radius, chart.options.elements.point.radius ], context, index);