From 416a6ac1bd0ab70012d11bfd2c37751fa3db286f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Mon, 21 Sep 2015 20:59:53 -0400 Subject: [PATCH 1/6] Remove unneeded functions from core controller. Updated dataset controllers to have a separate function to update the meta data for each dataset --- src/controllers/controller.bar.js | 8 ++- src/controllers/controller.doughnut.js | 30 +++++----- src/controllers/controller.line.js | 18 +++--- src/controllers/controller.polarArea.js | 19 ++++++- src/controllers/controller.radar.js | 19 ++++++- src/core/core.controller.js | 74 ++++++------------------- test/controller.bar.tests.js | 2 + test/controller.doughnut.tests.js | 2 + 8 files changed, 89 insertions(+), 83 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 6f9724e8b..6b3962281 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -107,9 +107,7 @@ this.update(true); }, - update: function(reset) { - var numBars = this.getBarCount(); - + buildOrUpdateElements: function buildOrUpdateElements() { var numData = this.getDataset().data.length; var numRectangles = this.getDataset().metaData.length; @@ -123,6 +121,10 @@ this.addElementAndReset(index); } } + }, + + update: function update(reset) { + var numBars = this.getBarCount(); helpers.each(this.getDataset().metaData, function(rectangle, index) { this.updateElement(rectangle, index, reset, numBars); diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index d4586b4fc..da3386e31 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -84,20 +84,7 @@ this.update(true); }, - update: function(reset) { - - this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0); - this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); - this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length; - - this.getDataset().total = 0; - helpers.each(this.getDataset().data, function(value) { - this.getDataset().total += Math.abs(value); - }, this); - - this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index); - this.innerRadius = this.outerRadius - this.chart.radiusLength; - + buildOrUpdateElements: function buildOrUpdateElements() { // Make sure we have metaData for each data point var numData = this.getDataset().data.length; var numArcs = this.getDataset().metaData.length; @@ -112,6 +99,21 @@ this.addElementAndReset(index); } } + }, + + update: function update(reset) { + + this.chart.outerRadius = Math.max((helpers.min([this.chart.chart.width, this.chart.chart.height]) / 2) - this.chart.options.elements.arc.borderWidth / 2, 0); + this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0); + this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.chart.data.datasets.length; + + this.getDataset().total = 0; + helpers.each(this.getDataset().data, function(value) { + this.getDataset().total += Math.abs(value); + }, this); + + 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) { this.updateElement(arc, index, reset); diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 608b5d704..6014a9306 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -101,14 +101,7 @@ this.update(true); }, - update: function(reset) { - var line = this.getDataset().metaDataset; - var points = this.getDataset().metaData; - - var yScale = this.getScaleForId(this.getDataset().yAxisID); - var xScale = this.getScaleForId(this.getDataset().xAxisID); - var scaleBase; - + buildOrUpdateElements: function buildOrUpdateElements() { // Handle the number of data points changing var numData = this.getDataset().data.length; var numPoints = this.getDataset().metaData.length; @@ -123,6 +116,15 @@ this.addElementAndReset(index); } } + }, + + update: function update(reset) { + var line = this.getDataset().metaDataset; + var points = this.getDataset().metaData; + + var yScale = this.getScaleForId(this.getDataset().yAxisID); + var xScale = this.getScaleForId(this.getDataset().xAxisID); + var scaleBase; if (yScale.min < 0 && yScale.max < 0) { scaleBase = yScale.getPixelForValue(yScale.max); diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index d832f09d1..3776184ad 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -79,7 +79,24 @@ this.update(true); }, - update: function(reset) { + buildOrUpdateElements: function buildOrUpdateElements() { + // Handle the number of data points changing + var numData = this.getDataset().data.length; + var numPoints = this.getDataset().metaData.length; + + // Make sure that we handle number of datapoints changing + if (numData < numPoints) { + // Remove excess bars for data points that have been removed + this.getDataset().metaData.splice(numData, numPoints - numData) + } else if (numData > numPoints) { + // Add new elements + for (var index = numPoints; index < numData; ++index) { + this.addElementAndReset(index); + } + } + }, + + update: function update(reset) { Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height); //this.chart.scale.setScaleSize(); diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index ce597d720..85cf5a459 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -95,7 +95,24 @@ this.update(true); }, - update: function(reset) { + buildOrUpdateElements: function buildOrUpdateElements() { + // Handle the number of data points changing + var numData = this.getDataset().data.length; + var numPoints = this.getDataset().metaData.length; + + // Make sure that we handle number of datapoints changing + if (numData < numPoints) { + // Remove excess bars for data points that have been removed + this.getDataset().metaData.splice(numData, numPoints - numData) + } else if (numData > numPoints) { + // Add new elements + for (var index = numPoints; index < numData; ++index) { + this.addElementAndReset(index); + } + } + }, + + update: function update(reset) { var line = this.getDataset().metaDataset; var points = this.getDataset().metaData; diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 614b0579d..3cf57687d 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -75,52 +75,6 @@ return this; }, - addDataset: function addDataset(dataset, index) { - if (index !== undefined) { - this.data.datasets.splice(index, 0, dataset); - } else { - this.data.datasets.push(dataset); - } - - this.buildOrUpdateControllers(); - dataset.controller.reset(); // so that animation looks ok - this.update(); - }, - removeDataset: function removeDataset(index) { - this.data.datasets.splice(index, 1); - this.buildOrUpdateControllers(); - this.update(); - }, - - // Add data to the given dataset - // @param data: the data to add - // @param {Number} datasetIndex : the index of the dataset to add to - // @param {Number} index : the index of the data - addData: function addData(data, datasetIndex, index) { - if (datasetIndex < this.data.datasets.length) { - if (index === undefined) { - index = this.data.datasets[datasetIndex].data.length; - } - - var addElementArgs = [index]; - for (var i = 3; i < arguments.length; ++i) { - addElementArgs.push(arguments[i]); - } - - this.data.datasets[datasetIndex].data.splice(index, 0, data); - this.data.datasets[datasetIndex].controller.addElementAndReset.apply(this.data.datasets[datasetIndex].controller, addElementArgs); - this.update(); - } - }, - - removeData: function removeData(datasetIndex, index) { - if (datasetIndex < this.data.datasets.length) { - this.data.datasets[datasetIndex].data.splice(index, 1); - this.data.datasets[datasetIndex].controller.removeElement(index); - this.update(); - } - }, - resize: function resize(silent) { this.stop(); var canvas = this.chart.canvas; @@ -210,7 +164,7 @@ Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height); }, - buildOrUpdateControllers: function() { + buildOrUpdateControllers: function buildOrUpdateControllers(resetNewControllers) { helpers.each(this.data.datasets, function(dataset, datasetIndex) { var type = dataset.type || this.config.type; if (dataset.controller) { @@ -218,6 +172,10 @@ return; } dataset.controller = new Chart.controllers[type](this, datasetIndex); + + if (resetNewControllers) { + dataset.controller.reset(); + } }, this); }, @@ -227,10 +185,18 @@ }, this); }, - update: function update(animationDuration, lazy) { - // This will loop through any data and do the appropriate element update for the type Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height); + + // Make sure dataset controllers are updated and new controllers are reset + this.buildOrUpdateControllers(true); + + // Make sure all dataset controllers have correct meta data counts + helpers.each(this.data.datasets, function(dataset, datasetIndex) { + dataset.controller.buildOrUpdateElements(); + }, this); + + // 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); @@ -288,10 +254,6 @@ this.tooltip.transition(easingDecimal).draw(); }, - - - - // 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) { @@ -333,9 +295,9 @@ for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) { for (var elementIndex = 0; elementIndex < this.data.datasets[datasetIndex].metaData.length; elementIndex++) { if (this.data.datasets[datasetIndex].metaData[elementIndex].inLabelRange(eventPosition.x, eventPosition.y)) { - helpers.each(this.data.datasets[datasetIndex].metaData, function(element, index) { - elementsArray.push(element); - }, this); + helpers.each(this.data.datasets[datasetIndex].metaData, function(element, index) { + elementsArray.push(element); + }, this); } } } diff --git a/test/controller.bar.tests.js b/test/controller.bar.tests.js index df27506a1..c20dd7cf8 100644 --- a/test/controller.bar.tests.js +++ b/test/controller.bar.tests.js @@ -194,6 +194,7 @@ describe('Bar controller tests', function() { var controller = new Chart.controllers.bar(chart, 1); chart.data.datasets[1].data = [1, 2]; // remove 2 items + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[1].metaData.length).toBe(2); @@ -236,6 +237,7 @@ describe('Bar controller tests', function() { }); chart.data.datasets[1].data = [1, 2, 3]; + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[1].metaData.length).toBe(3); // should add a new meta data item diff --git a/test/controller.doughnut.tests.js b/test/controller.doughnut.tests.js index cef606263..d4ff2ff51 100644 --- a/test/controller.doughnut.tests.js +++ b/test/controller.doughnut.tests.js @@ -205,6 +205,7 @@ describe('Doughnut controller tests', function() { // Change the amount of data and ensure that arcs are updated accordingly chart.data.datasets[0].data = [1, 2]; // remove 2 elements from dataset 0 + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[0].metaData.length).toBe(2); @@ -213,6 +214,7 @@ describe('Doughnut controller tests', function() { // Add data chart.data.datasets[0].data = [1, 2, 3, 4]; + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[0].metaData.length).toBe(4); From 4e536c523e1af2d6093d7984627d386ebdeb9f6f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Mon, 21 Sep 2015 21:00:09 -0400 Subject: [PATCH 2/6] Test missed in last check-in --- test/controller.line.tests.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/controller.line.tests.js b/test/controller.line.tests.js index 154435c70..462dfacc5 100644 --- a/test/controller.line.tests.js +++ b/test/controller.line.tests.js @@ -574,14 +574,14 @@ describe('Line controller tests', function() { var controller = new Chart.controllers.line(chart, 0); chart.data.datasets[0].data = [1, 2]; // remove 2 items - + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[0].metaData.length).toBe(2); expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true); expect(chart.data.datasets[0].metaData[1] instanceof Chart.elements.Point).toBe(true); chart.data.datasets[0].data = [1, 2, 3, 4, 5]; // add 3 items - + controller.buildOrUpdateElements(); controller.update(); expect(chart.data.datasets[0].metaData.length).toBe(5); expect(chart.data.datasets[0].metaData[0] instanceof Chart.elements.Point).toBe(true); From 029aad4f350b8559cddcea26254eb09b01f5e61f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Mon, 21 Sep 2015 21:00:58 -0400 Subject: [PATCH 3/6] Update samples to no longer use old functions and instead modify the data directly --- samples/bar.html | 14 ++++++++++---- samples/combo-time-scale.html | 12 ++++++++---- samples/doughnut.html | 14 ++++++++++---- samples/line-logarithmic.html | 12 ++++++++---- samples/line-scale-override.html | 14 ++++++++++---- samples/line-time-scale.html | 12 ++++++++---- samples/line-x-axis-filter.html | 14 ++++++++++---- samples/line.html | 16 ++++++++++------ samples/pie.html | 6 ++++-- samples/polar-area.html | 18 ++++++++++-------- samples/radar.html | 22 +++++++++++++--------- 11 files changed, 101 insertions(+), 53 deletions(-) diff --git a/samples/bar.html b/samples/bar.html index 526fd8e5a..bb8c884c7 100644 --- a/samples/bar.html +++ b/samples/bar.html @@ -106,7 +106,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myBar.addDataset(newDataset, 1); + barChartData.datasets.push(newDataset); + window.myBar.update(); updateLegend(); }); @@ -115,15 +116,18 @@ barChartData.labels.push('data #' + barChartData.labels.length); for (var index = 0; index < barChartData.datasets.length; ++index) { - window.myBar.addData(randomScalingFactor(), index); + //window.myBar.addData(randomScalingFactor(), index); + barChartData.datasets[index].data.push(randomScalingFactor()); } + window.myBar.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myBar.removeDataset(0); + barChartData.datasets.splice(0, 1); + window.myBar.update(); updateLegend(); }); @@ -131,8 +135,10 @@ barChartData.labels.splice(-1, 1); // remove the label first barChartData.datasets.forEach(function(dataset, datasetIndex) { - window.myBar.removeData(datasetIndex, -1); + dataset.data.pop(); }); + + window.myBar.update(); updateLegend(); }); diff --git a/samples/combo-time-scale.html b/samples/combo-time-scale.html index 548202e2c..081683eed 100644 --- a/samples/combo-time-scale.html +++ b/samples/combo-time-scale.html @@ -145,7 +145,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); updateLegend(); }); @@ -157,15 +158,17 @@ ); for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); + config.data.datasets[index].data.push(randomScalingFactor()); } + window.myLine.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); updateLegend(); }); @@ -173,9 +176,10 @@ config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + config.data.datasets[datasetIndex].data.pop(); }); + window.myLine.update(); updateLegend(); }); diff --git a/samples/doughnut.html b/samples/doughnut.html index ae6bbc9e5..728c8847a 100644 --- a/samples/doughnut.html +++ b/samples/doughnut.html @@ -144,7 +144,8 @@ newDataset.backgroundColor.push(randomColor(0.7)); } - window.myDoughnut.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myDoughnut.update(); updateLegend(); }); @@ -153,15 +154,18 @@ config.data.labels.push('data #' + config.data.labels.length); $.each(config.data.datasets, function(index, dataset) { - window.myDoughnut.addData(randomScalingFactor(), index, dataset.data.length, randomColor(0.7)); + dataset.data.push(randomScalingFactor()); + dataset.backgroundColor.push(randomColor(0.7)); }); + window.myDoughnut.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myDoughnut.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myDoughnut.update(); updateLegend(); }); @@ -169,9 +173,11 @@ config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myDoughnut.removeData(datasetIndex, -1); + dataset.data.pop(); + dataset.backgroundColor.pop(); }); + window.myDoughnut.update(); updateLegend(); }); diff --git a/samples/line-logarithmic.html b/samples/line-logarithmic.html index 21159e6ee..613499010 100644 --- a/samples/line-logarithmic.html +++ b/samples/line-logarithmic.html @@ -126,7 +126,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); updateLegend(); }); @@ -135,15 +136,17 @@ config.data.labels.push('dataset #' + config.data.labels.length); for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); + config.data.datasets[index].data.push(randomScalingFactor()); } + window.myLine.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); updateLegend(); }); @@ -151,9 +154,10 @@ config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + dataset.data.pop(); }); + window.myLine.update(); updateLegend(); }); diff --git a/samples/line-scale-override.html b/samples/line-scale-override.html index 6603b5c04..a92b14a1b 100644 --- a/samples/line-scale-override.html +++ b/samples/line-scale-override.html @@ -101,7 +101,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); }); $('#addData').click(function() { @@ -109,21 +110,26 @@ config.data.labels.push('dataset #' + config.data.labels.length); for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); + config.data.datasets[index].data.push(randomScalingFactor()); } + + window.myLine.update(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); }); $('#removeData').click(function() { config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + dataset.data.pop(); }); + + window.myLine.update(); }); diff --git a/samples/line-time-scale.html b/samples/line-time-scale.html index 3fc97b52b..124c9d9c7 100644 --- a/samples/line-time-scale.html +++ b/samples/line-time-scale.html @@ -144,7 +144,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); updateLegend(); }); @@ -158,15 +159,17 @@ ); for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); + config.data.datasets[index].data.push(randomScalingFactor()); } + window.myLine.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); updateLegend(); }); @@ -174,9 +177,10 @@ config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + dataset.data.pop(); }); + window.myLine.update(); updateLegend(); }); diff --git a/samples/line-x-axis-filter.html b/samples/line-x-axis-filter.html index 71a1b8844..05d18d73d 100644 --- a/samples/line-x-axis-filter.html +++ b/samples/line-x-axis-filter.html @@ -108,7 +108,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); }); $('#addData').click(function() { @@ -116,21 +117,26 @@ config.data.labels.push('dataset #' + config.data.labels.length); for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); + config.data.datasets[index].data.push(randomScalingFactor()); } + + window.myLine.update(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); }); $('#removeData').click(function() { config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + dataset.data.pop(); }); + + window.myLine.update(); }); diff --git a/samples/line.html b/samples/line.html index 192702888..6d6816e51 100644 --- a/samples/line.html +++ b/samples/line.html @@ -125,7 +125,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myLine.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myLine.update(); updateLegend(); }); @@ -133,16 +134,18 @@ if (config.data.datasets.length > 0) { config.data.labels.push('dataset #' + config.data.labels.length); - for (var index = 0; index < config.data.datasets.length; ++index) { - window.myLine.addData(randomScalingFactor(), index); - } + $.each(config.data.datasets, function(i, dataset) { + dataset.data.push(randomScalingFactor()); + }); + window.myLine.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myLine.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myLine.update(); updateLegend(); }); @@ -150,9 +153,10 @@ config.data.labels.splice(-1, 1); // remove the label first config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myLine.removeData(datasetIndex, -1); + dataset.data.pop(); }); + window.myLine.update(); updateLegend(); }); diff --git a/samples/pie.html b/samples/pie.html index 571efb037..3d05fc20c 100644 --- a/samples/pie.html +++ b/samples/pie.html @@ -108,11 +108,13 @@ data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()] }; - window.myPie.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myPie.update(); }); $('#removeDataset').click(function() { - window.myPie.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myPie.update(); }); diff --git a/samples/polar-area.html b/samples/polar-area.html index 89915530b..678aac69c 100644 --- a/samples/polar-area.html +++ b/samples/polar-area.html @@ -93,23 +93,25 @@ if (config.data.datasets.length > 0) { config.data.labels.push('dataset #' + config.data.labels.length); - for (var index = 0; index < config.data.datasets.length; ++index) { - config.data.datasets[index].backgroundColor.push(randomColor()); - window.myPolarArea.addData(randomScalingFactor(), index); - } + $.each(config.data.datasets, function(i, dataset) { + dataset.backgroundColor.push(randomColor()); + dataset.data.push(randomScalingFactor()); + }); + window.myPolarArea.update(); updateLegend(); } }); $('#removeData').click(function() { - config.data.labels.splice(-1, 1); // remove the label first + config.data.labels.pop(); // remove the label first - config.data.datasets.forEach(function(dataset, datasetIndex) { - dataset.backgroundColor.splice(-1, 1); - window.myPolarArea.removeData(datasetIndex, -1); + $.each(config.data.datasets, function(i, dataset) { + dataset.backgroundColor.pop(); + dataset.data.pop(); }); + window.myPolarArea.update(); updateLegend(); }); diff --git a/samples/radar.html b/samples/radar.html index 80b544e0d..c9b559aef 100644 --- a/samples/radar.html +++ b/samples/radar.html @@ -16,7 +16,7 @@ - ]
+

Legend

@@ -97,7 +97,8 @@ newDataset.data.push(randomScalingFactor()); } - window.myRadar.addDataset(newDataset); + config.data.datasets.push(newDataset); + window.myRadar.update(); updateLegend(); }); @@ -105,26 +106,29 @@ if (config.data.datasets.length > 0) { config.data.labels.push('dataset #' + config.data.labels.length); - for (var index = 0; index < config.data.datasets.length; ++index) { - window.myRadar.addData(randomScalingFactor(), index); - } + $.each(config.data.datasets, function (i, dataset) { + dataset.data.push(randomScalingFactor()); + }); + window.myRadar.update(); updateLegend(); } }); $('#removeDataset').click(function() { - window.myRadar.removeDataset(0); + config.data.datasets.splice(0, 1); + window.myRadar.update(); updateLegend(); }); $('#removeData').click(function() { - config.data.labels.splice(-1, 1); // remove the label first + config.data.labels.pop(); // remove the label first - config.data.datasets.forEach(function(dataset, datasetIndex) { - window.myRadar.removeData(datasetIndex, -1); + $.each(config.data.datasets, function(i, dataset) { + dataset.data.pop(); }); + window.myRadar.update(); updateLegend(); }); From 4a093196b8a522824aa9bd791046a4efe47902ad Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Tue, 22 Sep 2015 19:22:55 -0400 Subject: [PATCH 4/6] Don't increase canvas css size during a retina scale. Reset the canvas style exactly as it was set before during destroy. Ensure coordinates are translated over correctly into model coordinates. Fixed a bug during destroy when unscaling the canvas --- src/core/core.controller.js | 12 ++++++++---- src/core/core.helpers.js | 13 ++++++++++--- src/core/core.js | 4 ++++ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 3cf57687d..c8098d93f 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -258,7 +258,7 @@ // @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); + var eventPosition = helpers.getRelativePosition(e, this.chart); var elementsArray = []; helpers.each(this.data.datasets, function(dataset, datasetIndex) { @@ -274,7 +274,7 @@ }, getElementsAtEvent: function(e) { - var eventPosition = helpers.getRelativePosition(e); + var eventPosition = helpers.getRelativePosition(e, this.chart); var elementsArray = []; helpers.each(this.data.datasets, function(dataset, datasetIndex) { @@ -289,7 +289,7 @@ }, getDatasetAtEvent: function(e) { - var eventPosition = helpers.getRelativePosition(e); + var eventPosition = helpers.getRelativePosition(e, this.chart); var elementsArray = []; for (var datasetIndex = 0; datasetIndex < this.data.datasets.length; datasetIndex++) { @@ -321,9 +321,13 @@ // if we scaled the canvas in response to a devicePixelRatio !== 1, we need to undo that transform here if (this.chart.originalDevicePixelRatio !== undefined) { - canvas.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio); + this.chart.ctx.scale(1 / this.chart.originalDevicePixelRatio, 1 / this.chart.originalDevicePixelRatio); } + // Reset to the old style since it may have been changed by the device pixel ratio changes + canvas.style.width = this.chart.originalCanvasStyleWidth; + canvas.style.height = this.chart.originalCanvasStyleHeight; + delete Chart.instances[this.id]; }, diff --git a/src/core/core.helpers.js b/src/core/core.helpers.js index c4ea7940f..db3c70be4 100644 --- a/src/core/core.helpers.js +++ b/src/core/core.helpers.js @@ -635,7 +635,7 @@ }; })(), //-- DOM methods - getRelativePosition = helpers.getRelativePosition = function(evt) { + getRelativePosition = helpers.getRelativePosition = function(evt, chart) { var mouseX, mouseY; var e = evt.originalEvent || evt, canvas = evt.currentTarget || evt.srcElement, @@ -653,8 +653,11 @@ // Scale mouse coordinates into canvas coordinates // by following the pattern laid out by 'jerryj' in the comments of // http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/ - mouseX = Math.round((mouseX - boundingRect.left) / (boundingRect.right - boundingRect.left) * canvas.width); - mouseY = Math.round((mouseY - boundingRect.top) / (boundingRect.bottom - boundingRect.top) * canvas.height); + + // We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However + // the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here + mouseX = Math.round((mouseX - boundingRect.left) / (boundingRect.right - boundingRect.left) * canvas.width / chart.currentDevicePixelRatio); + mouseY = Math.round((mouseY - boundingRect.top) / (boundingRect.bottom - boundingRect.top) * canvas.height / chart.currentDevicePixelRatio); return { x: mouseX, @@ -755,12 +758,16 @@ var ctx = chart.ctx; var width = chart.canvas.width; var height = chart.canvas.height; + chart.currentDevicePixelRatio = window.devicePixelRatio || 1; if (window.devicePixelRatio !== 1) { ctx.canvas.height = height * window.devicePixelRatio; ctx.canvas.width = width * window.devicePixelRatio; ctx.scale(window.devicePixelRatio, window.devicePixelRatio); + ctx.canvas.style.width = width + 'px'; + ctx.canvas.style.height = height + 'px'; + // Store the device pixel ratio so that we can go backwards in `destroy`. // The devicePixelRatio changes with zoom, so there are no guarantees that it is the same // when destroy is called diff --git a/src/core/core.js b/src/core/core.js index 512b4f42e..d930c024f 100755 --- a/src/core/core.js +++ b/src/core/core.js @@ -50,6 +50,10 @@ this.aspectRatio = config.aspectRatio !== undefined ? config.aspectRatio : 2; } + // Store the original style of the element so we can set it back + this.originalCanvasStyleWidth = context.canvas.style.width; + this.originalCanvasStyleHeight = context.canvas.style.height; + // High pixel density displays - multiply the size of the canvas height/width by the device pixel ratio, then scale. Chart.helpers.retinaScale(this); From d7ab51f29b933659ca2058110e35219d3d002068 Mon Sep 17 00:00:00 2001 From: Ben Woodford Date: Thu, 24 Sep 2015 15:54:10 +0100 Subject: [PATCH 5/6] Only rotate label while rotation is < maxRotation Checking for <= maxRotation results in a labelRotation of 1 if maxRotation is 0, which doesn't make any sense (and also causes the text to be right aligned not centred) --- src/scales/scale.category.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scales/scale.category.js b/src/scales/scale.category.js index 939d32404..5ba78e2d6 100644 --- a/src/scales/scale.category.js +++ b/src/scales/scale.category.js @@ -147,7 +147,7 @@ var datasetWidth = Math.floor(this.getPixelForValue(0, 1) - this.getPixelForValue(0, 0)) - 6; //Max label rotation can be set or default to 90 - also act as a loop counter - while (this.labelWidth > datasetWidth && this.labelRotation <= this.options.labels.maxRotation) { + while (this.labelWidth > datasetWidth && this.labelRotation < this.options.labels.maxRotation) { cosRotation = Math.cos(helpers.toRadians(this.labelRotation)); sinRotation = Math.sin(helpers.toRadians(this.labelRotation)); From b0679a80aeb951efc887b639323bb71dab470978 Mon Sep 17 00:00:00 2001 From: Ben Woodford Date: Thu, 24 Sep 2015 16:02:58 +0100 Subject: [PATCH 6/6] Fixed label padding not affecting x-axis label --- src/scales/scale.category.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scales/scale.category.js b/src/scales/scale.category.js index 5ba78e2d6..188bf83aa 100644 --- a/src/scales/scale.category.js +++ b/src/scales/scale.category.js @@ -303,7 +303,7 @@ if (this.options.labels.show) { this.ctx.save(); - this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 : this.top + 8); + this.ctx.translate(xLabelValue, (isRotated) ? this.top + 12 + this.options.labels.padding : this.top + this.options.labels.padding); this.ctx.rotate(helpers.toRadians(this.labelRotation) * -1); this.ctx.font = this.font; this.ctx.textAlign = (isRotated) ? "right" : "center";