From 51aa9b4a27704a6b14ab888c2aad38e929c1239b Mon Sep 17 00:00:00 2001 From: Simon Brunel Date: Thu, 21 Apr 2016 17:11:52 +0200 Subject: [PATCH] Allow multiple charts sharing the same data Meta info are now scoped by chart and moved under the dataset._meta map { chart.id -> meta }. Meta for a specific chart (and dataset) can be accessed using chart.getDatasetMeta(datasetIndex) or from the dataset controller using getMeta(). Note that helpers.uid() now generates an int (instead of a string) to make lookups in the _meta map faster. --- src/controllers/controller.bar.js | 60 +++++++++--------- src/controllers/controller.bubble.js | 28 ++++----- src/controllers/controller.doughnut.js | 24 ++++---- src/controllers/controller.line.js | 54 ++++++++--------- src/controllers/controller.polarArea.js | 22 +++---- src/controllers/controller.radar.js | 42 ++++++------- src/core/core.controller.js | 81 ++++++++++++++++--------- src/core/core.datasetController.js | 21 ++++--- src/core/core.helpers.js | 2 +- src/core/core.legend.js | 5 +- src/core/core.tooltip.js | 10 +-- src/scales/scale.linear.js | 10 +-- src/scales/scale.logarithmic.js | 10 +-- 13 files changed, 199 insertions(+), 170 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index d0761f5b4..a19a26ad0 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -47,17 +47,17 @@ module.exports = function(Chart) { }, addElements: function() { - this.getDataset().metaData = this.getDataset().metaData || []; + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Rectangle({ + meta.data[index] = meta.data[index] || new Chart.elements.Rectangle({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); }, this); }, + addElementAndReset: function(index) { - this.getDataset().metaData = this.getDataset().metaData || []; var rectangle = new Chart.elements.Rectangle({ _chart: this.chart.chart, _datasetIndex: this.index, @@ -66,22 +66,23 @@ module.exports = function(Chart) { var numBars = this.getBarCount(); + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, rectangle); this.updateElement(rectangle, index, true, numBars); - this.getDataset().metaData.splice(index, 0, rectangle); }, update: function update(reset) { var numBars = this.getBarCount(); - helpers.each(this.getDataset().metaData, function(rectangle, index) { + helpers.each(this.getMeta().data, function(rectangle, index) { this.updateElement(rectangle, index, reset, numBars); }, this); }, updateElement: function updateElement(rectangle, index, reset, numBars) { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var yScalePoint; @@ -125,9 +126,9 @@ module.exports = function(Chart) { }, calculateBarBase: function(datasetIndex, index) { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var base = 0; @@ -138,14 +139,16 @@ module.exports = function(Chart) { if (value < 0) { for (var i = 0; i < datasetIndex; i++) { var negDS = this.chart.data.datasets[i]; - if (helpers.isDatasetVisible(negDS) && negDS.yAxisID === yScale.id && negDS.bar) { + var negDSMeta = this.chart.getDatasetMeta(i); + if (helpers.isDatasetVisible(negDS) && negDSMeta.yAxisID === yScale.id && negDS.bar) { base += negDS.data[index] < 0 ? negDS.data[index] : 0; } } } else { for (var j = 0; j < datasetIndex; j++) { var posDS = this.chart.data.datasets[j]; - if (helpers.isDatasetVisible(posDS) && posDS.yAxisID === yScale.id && posDS.bar) { + var posDSMeta = this.chart.getDatasetMeta(j); + if (helpers.isDatasetVisible(posDS) && posDSMeta.yAxisID === yScale.id && posDS.bar) { base += posDS.data[index] > 0 ? posDS.data[index] : 0; } } @@ -169,9 +172,9 @@ module.exports = function(Chart) { }, getRuler: function() { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var datasetCount = this.getBarCount(); var tickWidth = (function() { @@ -184,12 +187,12 @@ module.exports = function(Chart) { var categoryWidth = tickWidth * xScale.options.categoryPercentage; var categorySpacing = (tickWidth - (tickWidth * xScale.options.categoryPercentage)) / 2; var fullBarWidth = categoryWidth / datasetCount; - + if (xScale.ticks.length !== this.chart.data.labels.length) { var perc = xScale.ticks.length / this.chart.data.labels.length; fullBarWidth = fullBarWidth * perc; } - + var barWidth = fullBarWidth * xScale.options.barPercentage; var barSpacing = fullBarWidth - (fullBarWidth * xScale.options.barPercentage); @@ -205,7 +208,7 @@ module.exports = function(Chart) { }, calculateBarWidth: function() { - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var xScale = this.getScaleForId(this.getMeta().xAxisID); var ruler = this.getRuler(); return xScale.options.stacked ? ruler.categoryWidth : ruler.barWidth; }, @@ -224,9 +227,9 @@ module.exports = function(Chart) { }, calculateBarX: function(index, datasetIndex) { - - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var barIndex = this.getBarIndex(datasetIndex); var ruler = this.getRuler(); @@ -246,9 +249,9 @@ module.exports = function(Chart) { }, calculateBarY: function(index, datasetIndex) { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); var value = this.getDataset().data[index]; @@ -259,7 +262,8 @@ module.exports = function(Chart) { for (var i = 0; i < datasetIndex; i++) { var ds = this.chart.data.datasets[i]; - if (helpers.isDatasetVisible(ds) && ds.bar && ds.yAxisID === yScale.id) { + var dsMeta = this.chart.getDatasetMeta(i); + if (helpers.isDatasetVisible(ds) && ds.bar && dsMeta.yAxisID === yScale.id) { if (ds.data[index] < 0) { sumNeg += ds.data[index] || 0; } else { @@ -273,8 +277,6 @@ module.exports = function(Chart) { } else { return yScale.getPixelForValue(sumPos + value); } - - return yScale.getPixelForValue(value); } return yScale.getPixelForValue(value); @@ -282,7 +284,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(rectangle, index) { + helpers.each(this.getMeta().data, function(rectangle, index) { var d = this.getDataset().data[index]; if (d !== null && d !== undefined && !isNaN(d)) { rectangle.transition(easingDecimal).draw(); diff --git a/src/controllers/controller.bubble.js b/src/controllers/controller.bubble.js index 940a592a7..82ff94bc1 100644 --- a/src/controllers/controller.bubble.js +++ b/src/controllers/controller.bubble.js @@ -40,11 +40,9 @@ module.exports = function(Chart) { Chart.controllers.bubble = Chart.DatasetController.extend({ addElements: function() { - - this.getDataset().metaData = this.getDataset().metaData || []; - + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[index] || new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index @@ -52,25 +50,22 @@ module.exports = function(Chart) { }, this); }, addElementAndReset: function(index) { - this.getDataset().metaData = this.getDataset().metaData || []; var point = new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, point); this.updateElement(point, index, true); - - // Add to the points array - this.getDataset().metaData.splice(index, 0, point); }, update: function update(reset) { - var points = this.getDataset().metaData; - - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var points = meta.data; + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -89,8 +84,9 @@ module.exports = function(Chart) { }, updateElement: function(point, index, reset) { - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -137,7 +133,7 @@ module.exports = function(Chart) { var easingDecimal = ease || 1; // Transition and Draw the Points - helpers.each(this.getDataset().metaData, function(point, index) { + helpers.each(this.getMeta().data, function(point, index) { point.transition(easingDecimal); point.draw(); }); diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index d43234375..e9cd0acab 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -34,12 +34,12 @@ module.exports = function(Chart) { }, legend: { labels: { - generateLabels: function(data) { + generateLabels: function(chart) { + var data = chart.data; if (data.labels.length && data.datasets.length) { - return data.labels.map(function(label, i) { var ds = data.datasets[0]; - var arc = ds.metaData[i]; + var arc = chart.getDatasetMeta(0).data[i]; var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); @@ -111,17 +111,17 @@ module.exports = function(Chart) { }, addElements: function() { - this.getDataset().metaData = this.getDataset().metaData || []; + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + meta.data[index] = meta.data[index] || new Chart.elements.Arc({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); }, this); }, + addElementAndReset: function(index, colorForNewElement) { - this.getDataset().metaData = this.getDataset().metaData || []; var arc = new Chart.elements.Arc({ _chart: this.chart.chart, _datasetIndex: this.index, @@ -132,11 +132,9 @@ module.exports = function(Chart) { this.getDataset().backgroundColor.splice(index, 0, colorForNewElement); } - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, arc); this.updateElement(arc, index, true); - - // Add to the points array - this.getDataset().metaData.splice(index, 0, arc); }, getVisibleDatasetCount: function getVisibleDatasetCount() { @@ -199,7 +197,7 @@ module.exports = function(Chart) { this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.getRingIndex(this.index)); this.innerRadius = this.outerRadius - this.chart.radiusLength; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { this.updateElement(arc, index, reset); }, this); }, @@ -243,7 +241,7 @@ module.exports = function(Chart) { if (index === 0) { arc._model.startAngle = this.chart.options.rotation; } else { - arc._model.startAngle = this.getDataset().metaData[index - 1]._model.endAngle; + arc._model.startAngle = this.getMeta().data[index - 1]._model.endAngle; } arc._model.endAngle = arc._model.startAngle + arc._model.circumference; @@ -254,7 +252,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { arc.transition(easingDecimal).draw(); }); }, diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index a62b285ac..b4e9553ee 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -26,48 +26,45 @@ module.exports = function(Chart) { Chart.controllers.line = Chart.DatasetController.extend({ addElements: function() { - - this.getDataset().metaData = this.getDataset().metaData || []; - - this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + var meta = this.getMeta(); + meta.dataset = meta.dataset || new Chart.elements.Line({ _chart: this.chart.chart, _datasetIndex: this.index, - _points: this.getDataset().metaData + _points: meta.data }); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[index] || new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); }, this); }, + addElementAndReset: function(index) { - this.getDataset().metaData = this.getDataset().metaData || []; var point = new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, point); this.updateElement(point, index, true); - // Add to the points array - this.getDataset().metaData.splice(index, 0, point); - // Make sure bezier control points are updated if (this.chart.options.showLines && this.chart.options.elements.line.tension !== 0) this.updateBezierControlPoints(); }, update: function update(reset) { - var line = this.getDataset().metaDataset; - var points = this.getDataset().metaData; + var meta = this.getMeta(); + var line = meta.dataset; + var points = meta.data; - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -165,8 +162,9 @@ module.exports = function(Chart) { }, updateElement: function(point, index, reset) { - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); + var meta = this.getMeta(); + var yScale = this.getScaleForId(meta.yAxisID); + var xScale = this.getScaleForId(meta.xAxisID); var scaleBase; if (yScale.min < 0 && yScale.max < 0) { @@ -213,9 +211,9 @@ module.exports = function(Chart) { }, calculatePointY: function(value, index, datasetIndex, isCombo) { - - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var yScale = this.getScaleForId(this.getDataset().yAxisID); + var meta = this.getMeta(); + var xScale = this.getScaleForId(meta.xAxisID); + var yScale = this.getScaleForId(meta.yAxisID); if (yScale.options.stacked) { @@ -245,12 +243,13 @@ module.exports = function(Chart) { updateBezierControlPoints: function() { // Update bezier control points - helpers.each(this.getDataset().metaData, function(point, index) { + var meta = this.getMeta(); + helpers.each(meta.data, function(point, index) { var controlPoints = helpers.splineCurve( - helpers.previousItem(this.getDataset().metaData, index)._model, + helpers.previousItem(meta.data, index)._model, point._model, - helpers.nextItem(this.getDataset().metaData, index)._model, - this.getDataset().metaDataset._model.tension + helpers.nextItem(meta.data, index)._model, + meta.dataset._model.tension ); // Prevent the bezier going outside of the bounds of the graph @@ -266,19 +265,20 @@ module.exports = function(Chart) { }, draw: function(ease) { + var meta = this.getMeta(); var easingDecimal = ease || 1; // Transition Point Locations - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.transition(easingDecimal); }); // Transition and Draw the line if (this.chart.options.showLines) - this.getDataset().metaDataset.transition(easingDecimal).draw(); + meta.dataset.transition(easingDecimal).draw(); // Draw the points - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.draw(); }); }, diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 7fb605a1a..1f4090047 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -35,11 +35,12 @@ module.exports = function(Chart) { }, legend: { labels: { - generateLabels: function(data) { + generateLabels: function(chart) { + var data = chart.data; if (data.labels.length && data.datasets.length) { return data.labels.map(function(label, i) { var ds = data.datasets[0]; - var arc = ds.metaData[i]; + var arc = chart.getDatasetMeta(0).data[i]; var fill = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(ds.backgroundColor, i, this.chart.options.elements.arc.backgroundColor); var stroke = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(ds.borderColor, i, this.chart.options.elements.arc.borderColor); var bw = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(ds.borderWidth, i, this.chart.options.elements.arc.borderWidth); @@ -94,29 +95,28 @@ module.exports = function(Chart) { linkScales: function() { // no scales for doughnut }, + addElements: function() { - this.getDataset().metaData = this.getDataset().metaData || []; + var meta = this.getMeta(); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({ + meta.data[index] = meta.data[index] || new Chart.elements.Arc({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); }, this); }, + addElementAndReset: function(index) { - this.getDataset().metaData = this.getDataset().metaData || []; var arc = new Chart.elements.Arc({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, arc); this.updateElement(arc, index, true); - - // Add to the points array - this.getDataset().metaData.splice(index, 0, arc); }, getVisibleDatasetCount: function getVisibleDatasetCount() { return helpers.where(this.chart.data.datasets, function(ds) { @@ -138,7 +138,7 @@ module.exports = function(Chart) { this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index); this.innerRadius = this.outerRadius - this.chart.radiusLength; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { this.updateElement(arc, index, reset); }, this); }, @@ -204,7 +204,7 @@ module.exports = function(Chart) { draw: function(ease) { var easingDecimal = ease || 1; - helpers.each(this.getDataset().metaData, function(arc, index) { + helpers.each(this.getMeta().data, function(arc, index) { arc.transition(easingDecimal).draw(); }); }, diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 9e1302c67..26268cba5 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -22,18 +22,17 @@ module.exports = function(Chart) { }, addElements: function() { + var meta = this.getMeta(); - this.getDataset().metaData = this.getDataset().metaData || []; - - this.getDataset().metaDataset = this.getDataset().metaDataset || new Chart.elements.Line({ + meta.dataset = meta.dataset || new Chart.elements.Line({ _chart: this.chart.chart, _datasetIndex: this.index, - _points: this.getDataset().metaData, + _points: meta.data, _loop: true }); helpers.each(this.getDataset().data, function(value, index) { - this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Point({ + meta.data[index] = meta.data[index] || new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index, @@ -45,27 +44,24 @@ module.exports = function(Chart) { }, this); }, addElementAndReset: function(index) { - this.getDataset().metaData = this.getDataset().metaData || []; var point = new Chart.elements.Point({ _chart: this.chart.chart, _datasetIndex: this.index, _index: index }); - // Reset the point + // Add to the points array and reset it + this.getMeta().data.splice(index, 0, point); this.updateElement(point, index, true); - // Add to the points array - this.getDataset().metaData.splice(index, 0, point); - // Make sure bezier control points are updated this.updateBezierControlPoints(); }, update: function update(reset) { - - var line = this.getDataset().metaDataset; - var points = this.getDataset().metaData; + var meta = this.getMeta(); + var line = meta.dataset; + var points = meta.data; var scale = this.chart.scale; var scaleBase; @@ -78,11 +74,11 @@ module.exports = function(Chart) { scaleBase = scale.getPointPositionForValue(0, 0); } - helpers.extend(this.getDataset().metaDataset, { + helpers.extend(meta.dataset, { // Utility _datasetIndex: this.index, // Data - _children: this.getDataset().metaData, + _children: points, // Model _model: { // Appearance @@ -103,7 +99,7 @@ module.exports = function(Chart) { } }); - this.getDataset().metaDataset.pivot(); + meta.dataset.pivot(); // Update Points helpers.each(points, function(point, index) { @@ -144,11 +140,12 @@ module.exports = function(Chart) { point._model.skip = point.custom && point.custom.skip ? point.custom.skip : (isNaN(point._model.x) || isNaN(point._model.y)); }, updateBezierControlPoints: function() { - helpers.each(this.getDataset().metaData, function(point, index) { + var meta = this.getMeta(); + helpers.each(meta.data, function(point, index) { var controlPoints = helpers.splineCurve( - helpers.previousItem(this.getDataset().metaData, index, true)._model, + helpers.previousItem(meta.data, index, true)._model, point._model, - helpers.nextItem(this.getDataset().metaData, index, true)._model, + helpers.nextItem(meta.data, index, true)._model, point._model.tension ); @@ -165,18 +162,19 @@ module.exports = function(Chart) { }, draw: function(ease) { + var meta = this.getMeta(); var easingDecimal = ease || 1; // Transition Point Locations - helpers.each(this.getDataset().metaData, function(point, index) { + helpers.each(meta.data, function(point, index) { point.transition(easingDecimal); }); // Transition and Draw the line - this.getDataset().metaDataset.transition(easingDecimal).draw(); + meta.dataset.transition(easingDecimal).draw(); // Draw the points - helpers.each(this.getDataset().metaData, function(point) { + helpers.each(meta.data, function(point) { point.draw(); }); }, diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 3791b105d..a7bb5d16e 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -212,14 +212,15 @@ module.exports = function(Chart) { dataset.type = this.config.type; } + var meta = this.getDatasetMeta(datasetIndex); var type = dataset.type; types.push(type); - if (dataset.controller) { - dataset.controller.updateIndex(datasetIndex); + if (meta.controller) { + meta.controller.updateIndex(datasetIndex); } else { - dataset.controller = new Chart.controllers[type](this, datasetIndex); - newControllers.push(dataset.controller); + meta.controller = new Chart.controllers[type](this, datasetIndex); + newControllers.push(meta.controller); } }, this); @@ -237,8 +238,8 @@ module.exports = function(Chart) { resetElements: function resetElements() { helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.controller.reset(); - }); + this.getDatasetMeta(datasetIndex).controller.reset(); + }, this); }, update: function update(animationDuration, lazy) { @@ -252,8 +253,8 @@ module.exports = function(Chart) { // Make sure all dataset controllers have correct meta data counts helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.controller.buildOrUpdateElements(); - }); + this.getDatasetMeta(datasetIndex).controller.buildOrUpdateElements(); + }, this); Chart.layoutService.update(this, this.chart.width, this.chart.height); @@ -264,8 +265,9 @@ module.exports = function(Chart) { // This will loop through any data and do the appropriate element update for the type helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.controller.update(); - }); + this.getDatasetMeta(datasetIndex).controller.update(); + }, this); + this.render(animationDuration, lazy); Chart.pluginService.notifyPlugins('afterUpdate', [this]); @@ -325,9 +327,9 @@ module.exports = function(Chart) { // Draw each dataset via its respective controller (reversed to support proper line stacking) helpers.each(this.data.datasets, function(dataset, datasetIndex) { if (helpers.isDatasetVisible(dataset)) { - dataset.controller.draw(ease); + this.getDatasetMeta(datasetIndex).controller.draw(ease); } - }, null, true); + }, this, true); // Restore from the clipping operation this.chart.ctx.restore(); @@ -341,20 +343,20 @@ module.exports = function(Chart) { // Get the single element that was clicked on // @return : An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw getElementAtEvent: function(e) { - var eventPosition = helpers.getRelativePosition(e, this.chart); var elementsArray = []; helpers.each(this.data.datasets, function(dataset, datasetIndex) { + var meta = this.getDatasetMeta(datasetIndex); if (helpers.isDatasetVisible(dataset)) { - helpers.each(dataset.metaData, function(element, index) { + helpers.each(meta.data, function(element, index) { if (element.inRange(eventPosition.x, eventPosition.y)) { elementsArray.push(element); return elementsArray; } }); } - }); + }, this); return elementsArray; }, @@ -366,14 +368,15 @@ module.exports = function(Chart) { var found = (function() { if (this.data.datasets) { for (var i = 0; i < this.data.datasets.length; i++) { + var meta = this.getDatasetMeta(i); if (helpers.isDatasetVisible(this.data.datasets[i])) { - for (var j = 0; j < this.data.datasets[i].metaData.length; j++) { - if (this.data.datasets[i].metaData[j].inRange(eventPosition.x, eventPosition.y)) { - return this.data.datasets[i].metaData[j]; + for (var j = 0; j < meta.data.length; j++) { + if (meta.data[j].inRange(eventPosition.x, eventPosition.y)) { + return meta.data[j]; } } } - } + }; } }).call(this); @@ -381,11 +384,12 @@ module.exports = function(Chart) { return elementsArray; } - helpers.each(this.data.datasets, function(dataset, dsIndex) { + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + var meta = this.getDatasetMeta(datasetIndex); if (helpers.isDatasetVisible(dataset)) { - elementsArray.push(dataset.metaData[found._index]); + elementsArray.push(meta.data[found._index]); } - }); + }, this); return elementsArray; }, @@ -394,12 +398,32 @@ module.exports = function(Chart) { var elementsArray = this.getElementAtEvent(e); if (elementsArray.length > 0) { - elementsArray = this.data.datasets[elementsArray[0]._datasetIndex].metaData; + elementsArray = this.getDatasetMeta(elementsArray[0]._datasetIndex).data; } return elementsArray; }, + getDatasetMeta: function(datasetIndex) { + var dataset = this.data.datasets[datasetIndex]; + if (!dataset._meta) { + dataset._meta = {}; + } + + var meta = dataset._meta[this.id]; + if (!meta) { + meta = dataset._meta[this.id] = { + data: [], + dataset: null, + controller: null, + xAxisID: null, + yAxisID: null + }; + } + + return meta; + }, + generateLegend: function generateLegend() { return this.options.legendCallback(this); }, @@ -489,20 +513,17 @@ module.exports = function(Chart) { } } - var dataset; - var index; - // Remove styling for last active (even if it may still be active) if (this.lastActive.length) { switch (this.options.hover.mode) { case 'single': - this.data.datasets[this.lastActive[0]._datasetIndex].controller.removeHoverStyle(this.lastActive[0], this.lastActive[0]._datasetIndex, this.lastActive[0]._index); + this.getDatasetMeta(this.lastActive[0]._datasetIndex).controller.removeHoverStyle(this.lastActive[0], this.lastActive[0]._datasetIndex, this.lastActive[0]._index); break; case 'label': case 'dataset': for (var i = 0; i < this.lastActive.length; i++) { if (this.lastActive[i]) - this.data.datasets[this.lastActive[i]._datasetIndex].controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index); + this.getDatasetMeta(this.lastActive[i]._datasetIndex).controller.removeHoverStyle(this.lastActive[i], this.lastActive[i]._datasetIndex, this.lastActive[i]._index); } break; default: @@ -514,13 +535,13 @@ module.exports = function(Chart) { if (this.active.length && this.options.hover.mode) { switch (this.options.hover.mode) { case 'single': - this.data.datasets[this.active[0]._datasetIndex].controller.setHoverStyle(this.active[0]); + this.getDatasetMeta(this.active[0]._datasetIndex).controller.setHoverStyle(this.active[0]); break; case 'label': case 'dataset': for (var j = 0; j < this.active.length; j++) { if (this.active[j]) - this.data.datasets[this.active[j]._datasetIndex].controller.setHoverStyle(this.active[j]); + this.getDatasetMeta(this.active[j]._datasetIndex).controller.setHoverStyle(this.active[j]); } break; default: diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index e8157798a..61c4d9e35 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -21,12 +21,14 @@ module.exports = function(Chart) { }, linkScales: function() { - if (!this.getDataset().xAxisID) { - this.getDataset().xAxisID = this.chart.options.scales.xAxes[0].id; - } + var meta = this.getMeta(); + var dataset = this.getDataset(); - if (!this.getDataset().yAxisID) { - this.getDataset().yAxisID = this.chart.options.scales.yAxes[0].id; + if (meta.xAxisID === null) { + meta.xAxisID = dataset.xAxisID || this.chart.options.scales.xAxes[0].id; + } + if (meta.yAxisID === null) { + meta.yAxisID = dataset.yAxisID || this.chart.options.scales.yAxes[0].id; } }, @@ -34,6 +36,10 @@ module.exports = function(Chart) { return this.chart.data.datasets[this.index]; }, + getMeta: function() { + return this.chart.getDatasetMeta(this.index); + }, + getScaleForId: function(scaleID) { return this.chart.scales[scaleID]; }, @@ -44,13 +50,14 @@ module.exports = function(Chart) { buildOrUpdateElements: function buildOrUpdateElements() { // Handle the number of data points changing + var meta = this.getMeta(); var numData = this.getDataset().data.length; - var numMetaData = this.getDataset().metaData.length; + var numMetaData = meta.data.length; // Make sure that we handle number of datapoints changing if (numData < numMetaData) { // Remove excess bars for data points that have been removed - this.getDataset().metaData.splice(numData, numMetaData - numData); + meta.data.splice(numData, numMetaData - numData); } else if (numData > numMetaData) { // Add new elements for (var index = numMetaData; index < numData; ++index) { diff --git a/src/core/core.helpers.js b/src/core/core.helpers.js index 35955869b..eb808258d 100644 --- a/src/core/core.helpers.js +++ b/src/core/core.helpers.js @@ -272,7 +272,7 @@ module.exports = function(Chart) { helpers.uid = (function() { var id = 0; return function() { - return "chart-" + id++; + return id++; }; })(); helpers.warn = function(str) { diff --git a/src/core/core.legend.js b/src/core/core.legend.js index c54e2ef14..ca042ccc4 100644 --- a/src/core/core.legend.js +++ b/src/core/core.legend.js @@ -34,7 +34,8 @@ module.exports = function(Chart) { // lineDashOffset : // lineJoin : // lineWidth : - generateLabels: function(data) { + generateLabels: function(chart) { + var data = chart.data; return helpers.isArray(data.datasets) ? data.datasets.map(function(dataset, i) { return { text: dataset.label, @@ -138,7 +139,7 @@ module.exports = function(Chart) { beforeBuildLabels: helpers.noop, buildLabels: function() { - this.legendItems = this.options.labels.generateLabels.call(this, this.chart.data); + this.legendItems = this.options.labels.generateLabels.call(this, this.chart); if(this.options.reverse){ this.legendItems.reverse(); } diff --git a/src/core/core.tooltip.js b/src/core/core.tooltip.js index 4b742d3a8..cb7136402 100644 --- a/src/core/core.tooltip.js +++ b/src/core/core.tooltip.js @@ -239,7 +239,9 @@ module.exports = function(Chart) { if (!helpers.isDatasetVisible(dataset)) { return; } - var currentElement = dataset.metaData[element._index]; + + var meta = this._chartInstance.getDatasetMeta(datasetIndex); + var currentElement = meta.data[element._index]; if (currentElement) { var yScale = element._yScale || element._scale; // handle radar || polarArea charts @@ -250,7 +252,7 @@ module.exports = function(Chart) { datasetIndex: datasetIndex }); } - }, null); + }, this); helpers.each(this._active, function(active) { if (active) { @@ -490,7 +492,7 @@ module.exports = function(Chart) { if (vm.title.length) { ctx.textAlign = vm._titleAlign; ctx.textBaseline = "top"; - + var titleColor = helpers.color(vm.titleColor); ctx.fillStyle = titleColor.alpha(opacity * titleColor.alpha()).rgbString(); ctx.font = helpers.fontString(vm.titleFontSize, vm._titleFontStyle, vm._titleFontFamily); @@ -557,7 +559,7 @@ module.exports = function(Chart) { ctx.textAlign = vm._footerAlign; ctx.textBaseline = "top"; - + var footerColor = helpers.color(vm.footerColor); ctx.fillStyle = footerColor.alpha(opacity * footerColor.alpha()).rgbString(); ctx.font = helpers.fontString(vm.footerFontSize, vm._footerFontStyle, vm._footerFontFamily); diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index 3cf2b020d..dafca9085 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -46,7 +46,8 @@ module.exports = function(Chart) { var hasPositiveValues = false; var hasNegativeValues = false; - helpers.each(this.chart.data.datasets, function(dataset) { + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + var meta = this.chart.getDatasetMeta(datasetIndex); if (valuesPerType[dataset.type] === undefined) { valuesPerType[dataset.type] = { positiveValues: [], @@ -58,7 +59,7 @@ module.exports = function(Chart) { var positiveValues = valuesPerType[dataset.type].positiveValues; var negativeValues = valuesPerType[dataset.type].negativeValues; - if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { helpers.each(dataset.data, function(rawValue, index) { var value = +this.getRightValue(rawValue); @@ -93,8 +94,9 @@ module.exports = function(Chart) { }, this); } else { - helpers.each(this.chart.data.datasets, function(dataset) { - if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + var meta = this.chart.getDatasetMeta(datasetIndex); + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { helpers.each(dataset.data, function(rawValue, index) { var value = +this.getRightValue(rawValue); if (isNaN(value)) { diff --git a/src/scales/scale.logarithmic.js b/src/scales/scale.logarithmic.js index 070a08d61..36d81f6a1 100644 --- a/src/scales/scale.logarithmic.js +++ b/src/scales/scale.logarithmic.js @@ -30,8 +30,9 @@ module.exports = function(Chart) { if (this.options.stacked) { var valuesPerType = {}; - helpers.each(this.chart.data.datasets, function(dataset) { - if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + var meta = this.chart.getDatasetMeta(datasetIndex); + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { if (valuesPerType[dataset.type] === undefined) { valuesPerType[dataset.type] = []; } @@ -63,8 +64,9 @@ module.exports = function(Chart) { }, this); } else { - helpers.each(this.chart.data.datasets, function(dataset) { - if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? dataset.xAxisID === this.id : dataset.yAxisID === this.id)) { + helpers.each(this.chart.data.datasets, function(dataset, datasetIndex) { + var meta = this.chart.getDatasetMeta(datasetIndex); + if (helpers.isDatasetVisible(dataset) && (this.isHorizontal() ? meta.xAxisID === this.id : meta.yAxisID === this.id)) { helpers.each(dataset.data, function(rawValue, index) { var value = +this.getRightValue(rawValue); if (isNaN(value)) { -- 2.47.3