From a3a2f8ea09ac0f19e9cb02b83a7ffeaefb04da6c Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 18 Jun 2015 18:04:28 -0400 Subject: [PATCH 1/3] Line chart addData and removeData implementations + sample file updates --- samples/line.html | 34 ++++++++++- src/controllers/controller.line.js | 94 +++++++++++++++++++++--------- 2 files changed, 96 insertions(+), 32 deletions(-) diff --git a/samples/line.html b/samples/line.html index b4d9bc4ee..f4962480f 100644 --- a/samples/line.html +++ b/samples/line.html @@ -21,6 +21,8 @@ + + diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index fa5518b43..34680dc06 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -76,13 +76,32 @@ }); }, 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 + 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(); + }, + removeElement: function(index) { + this.getDataset().metaData.splice(index, 1); + }, reset: function() { this.update(true); }, update: function(reset) { - var line = this.getDataset().metaDataset; var points = this.getDataset().metaData; @@ -98,7 +117,6 @@ scaleBase = yScale.getPixelForValue(0); } - // Update Line helpers.extend(line, { // Utility @@ -126,33 +144,52 @@ // Update Points helpers.each(points, function(point, index) { - helpers.extend(point, { - // Utility - _chart: this.chart.chart, - _xScale: xScale, - _yScale: yScale, - _datasetIndex: this.index, - _index: index, - - // Desired view properties - _model: { - x: xScale.getPointPixelForValue(this.getDataset().data[index], index, this.index), - y: reset ? scaleBase : yScale.getPointPixelForValue(this.getDataset().data[index], index, this.index), - // Appearance - tension: point.custom && point.custom.tension ? point.custom.tension : this.chart.options.elements.line.tension, - radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius), - backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor), - borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor), - borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth), - skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null, - - // Tooltip - hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius), - }, - - }); + this.updateElement(point, index, reset); }, this); + this.updateBezierControlPoints(); + }, + + updateElement: function(point, index, reset) { + 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); + } else if (yScale.min > 0 && yScale.max > 0) { + scaleBase = yScale.getPixelForValue(yScale.min); + } else { + scaleBase = yScale.getPixelForValue(0); + } + + helpers.extend(point, { + // Utility + _chart: this.chart.chart, + _xScale: xScale, + _yScale: yScale, + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: { + x: xScale.getPointPixelForValue(this.getDataset().data[index], index, this.index), + y: reset ? scaleBase : yScale.getPointPixelForValue(this.getDataset().data[index], index, this.index), + // Appearance + tension: point.custom && point.custom.tension ? point.custom.tension : this.chart.options.elements.line.tension, + radius: point.custom && point.custom.radius ? point.custom.radius : helpers.getValueAtIndexOrDefault(this.getDataset().radius, index, this.chart.options.elements.point.radius), + backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor), + borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor), + borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth), + skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null, + + // Tooltip + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius), + }, + }); + }, + + updateBezierControlPoints: function() { // Update bezier control points helpers.each(this.getDataset().metaData, function(point, index) { var controlPoints = helpers.splineCurve( @@ -167,7 +204,7 @@ // Prevent the bezier going outside of the bounds of the graph - // Cap puter bezier handles to the upper/lower scale bounds + // Cap outer bezier handles to the upper/lower scale bounds if (controlPoints.next.y > this.chart.chartArea.bottom) { point._model.controlPointNextY = this.chart.chartArea.bottom; } else if (controlPoints.next.y < this.chart.chartArea.top) { @@ -188,7 +225,6 @@ // Now pivot the point for animation point.pivot(); }, this); - }, draw: function(ease) { From 73af6a31b6ec1ab3cda00a8a905c4a046d7eb086 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 18 Jun 2015 18:28:45 -0400 Subject: [PATCH 2/3] add support for addData and removeData to the radar chart. Needed to update the radialLinear scale so that the number of values is not cached. --- samples/radar.html | 35 +++++++++++-- src/controllers/controller.radar.js | 77 +++++++++++++++++++---------- src/scales/scale.radialLinear.js | 20 ++++---- 3 files changed, 92 insertions(+), 40 deletions(-) diff --git a/samples/radar.html b/samples/radar.html index fd1214cbb..0605c76e7 100644 --- a/samples/radar.html +++ b/samples/radar.html @@ -14,6 +14,8 @@ + + diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index e7577887f..ce597d720 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -70,6 +70,26 @@ }); }, 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 + 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(); + }, + removeElement: function(index) { + this.getDataset().metaData.splice(index, 1); + }, reset: function() { this.update(true); @@ -123,34 +143,40 @@ // Update Points helpers.each(points, function(point, index) { - var pointPosition = scale.getPointPositionForValue(index, this.getDataset().data[index]); - - helpers.extend(point, { - // Utility - _datasetIndex: this.index, - _index: index, - - // Desired view properties - _model: { - x: reset ? scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales - y: reset ? scale.yCenter : pointPosition.y, - - // Appearance - tension: point.custom && point.custom.tension ? point.custom.tension : this.chart.options.elements.line.tension, - radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius), - backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor), - borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor), - borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth), - skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null, - - // Tooltip - hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius), - }, - }); + this.updateElement(point, index, reset); }, this); // Update bezier control points + this.updateBezierControlPoints(); + }, + updateElement: function(point, index, reset) { + var pointPosition = this.chart.scale.getPointPositionForValue(index, this.getDataset().data[index]); + + helpers.extend(point, { + // Utility + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: { + x: reset ? this.chart.scale.xCenter : pointPosition.x, // value not used in dataset scale, but we want a consistent API between scales + y: reset ? this.chart.scale.yCenter : pointPosition.y, + + // Appearance + tension: point.custom && point.custom.tension ? point.custom.tension : this.chart.options.elements.line.tension, + radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.getDataset().pointRadius, index, this.chart.options.elements.point.radius), + backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBackgroundColor, index, this.chart.options.elements.point.backgroundColor), + borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderColor, index, this.chart.options.elements.point.borderColor), + borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().pointBorderWidth, index, this.chart.options.elements.point.borderWidth), + skip: point.custom && point.custom.skip ? point.custom.skip : this.getDataset().data[index] === null, + + // Tooltip + hitRadius: point.custom && point.custom.hitRadius ? point.custom.hitRadius : helpers.getValueAtIndexOrDefault(this.getDataset().hitRadius, index, this.chart.options.elements.point.hitRadius), + }, + }); + }, + updateBezierControlPoints: function() { helpers.each(this.getDataset().metaData, function(point, index) { var controlPoints = helpers.splineCurve( helpers.previousItem(this.getDataset().metaData, index, true)._model, @@ -164,7 +190,7 @@ // Prevent the bezier going outside of the bounds of the graph - // Cap puter bezier handles to the upper/lower scale bounds + // Cap outer bezier handles to the upper/lower scale bounds if (controlPoints.next.y > this.chart.chartArea.bottom) { point._model.controlPointNextY = this.chart.chartArea.bottom; } else if (controlPoints.next.y < this.chart.chartArea.top) { @@ -185,7 +211,6 @@ // Now pivot the point for animation point.pivot(); }, this); - }, draw: function(ease) { diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 15169aa86..0a1a26b45 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -73,10 +73,12 @@ this.xCenter = this.chart.width / 2; this.yCenter = this.chart.height / 2; this.size = helpers.min([this.height, this.width]); - this.valuesCount = this.data.labels.length; this.labels = this.data.labels; this.drawingArea = (this.options.display) ? (this.size / 2) - (this.options.labels.fontSize / 2 + this.options.labels.backdropPaddingY) : (this.size / 2); }, + getValueCount: function() { + return this.data.labels.length; + }, update: function() { if (!this.options.lineArc) { this.setScaleSize(); @@ -201,7 +203,7 @@ }, this); }, getCircumference: function() { - return ((Math.PI * 2) / this.valuesCount); + return ((Math.PI * 2) / this.getValueCount()); }, setScaleSize: function() { /* @@ -252,13 +254,13 @@ radiusReductionLeft, maxWidthRadius; this.ctx.font = helpers.fontString(this.options.pointLabels.fontSize, this.options.pointLabels.fontStyle, this.options.pointLabels.fontFamily); - for (i = 0; i < this.valuesCount; i++) { + for (i = 0; i < this.getValueCount(); i++) { // 5px to space the text slightly out - similar to what we do in the draw function. pointPosition = this.getPointPosition(i, largestPossibleRadius); textWidth = this.ctx.measureText(helpers.template(this.options.labels.template, { value: this.labels[i] })).width + 5; - if (i === 0 || i === this.valuesCount / 2) { + if (i === 0 || i === this.getValueCount() / 2) { // If we're at index zero, or exactly the middle, we're at exactly the top/bottom // of the radar chart, so text will be aligned centrally, so we'll half it and compare // w/left and right text sizes @@ -271,13 +273,13 @@ furthestLeft = pointPosition.x - halfTextWidth; furthestLeftIndex = i; } - } else if (i < this.valuesCount / 2) { + } else if (i < this.getValueCount() / 2) { // Less than half the values means we'll left align the text if (pointPosition.x + textWidth > furthestRight) { furthestRight = pointPosition.x + textWidth; furthestRightIndex = i; } - } else if (i > this.valuesCount / 2) { + } else if (i > this.getValueCount() / 2) { // More than half the values means we'll right align the text if (pointPosition.x - textWidth < furthestLeft) { furthestLeft = pointPosition.x - textWidth; @@ -319,7 +321,7 @@ }, getIndexAngle: function(index) { - var angleMultiplier = (Math.PI * 2) / this.valuesCount; + var angleMultiplier = (Math.PI * 2) / this.getValueCount(); // Start from the top instead of right, so remove a quarter of the circle return index * angleMultiplier - (Math.PI / 2); @@ -362,7 +364,7 @@ } else { // Draw straight lines connecting each index ctx.beginPath(); - for (var i = 0; i < this.valuesCount; i++) { + for (var i = 0; i < this.getValueCount(); i++) { var pointPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.ticks[index])); if (i === 0) { ctx.moveTo(pointPosition.x, pointPosition.y); @@ -401,7 +403,7 @@ ctx.lineWidth = this.options.angleLines.lineWidth; ctx.strokeStyle = this.options.angleLines.color; - for (var i = this.valuesCount - 1; i >= 0; i--) { + for (var i = this.getValueCount() - 1; i >= 0; i--) { if (this.options.angleLines.show) { var outerPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.max)); ctx.beginPath(); From 891655b3cea3ac48becc637a578222136297e248 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Thu, 18 Jun 2015 18:51:00 -0400 Subject: [PATCH 3/3] Polar area charts now support addData and removeData. Fixed an issue with the animateRotate and animateScale options for polar area charts. --- samples/polar-area.html | 29 +++++++- src/controllers/controller.polarArea.js | 94 +++++++++++++++---------- 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/samples/polar-area.html b/samples/polar-area.html index 73d5c6049..a8c74d16b 100644 --- a/samples/polar-area.html +++ b/samples/polar-area.html @@ -8,10 +8,12 @@ -
+
+ + diff --git a/src/controllers/controller.polarArea.js b/src/controllers/controller.polarArea.js index 733ab9dc6..4fe948bf8 100644 --- a/src/controllers/controller.polarArea.js +++ b/src/controllers/controller.polarArea.js @@ -16,6 +16,7 @@ //Boolean - Whether to animate the rotation of the chart animateRotate: true, + animateScale: true, }; Chart.controllers.polarArea = function(chart, datasetIndex) { @@ -56,6 +57,23 @@ }); }, 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 + this.updateElement(arc, index, true); + + // Add to the points array + this.getDataset().metaData.splice(index, 0, arc); + }, + removeElement: function(index) { + this.getDataset().metaData.splice(index, 1); + }, reset: function() { this.update(true); @@ -82,14 +100,44 @@ this.innerRadius = this.outerRadius - this.chart.radiusLength; helpers.each(this.getDataset().metaData, function(arc, index) { + this.updateElement(arc, index, reset); + }, this); + }, + updateElement: function(arc, index, reset) { + var circumference = 1 / this.getDataset().data.length * 2; + var startAngle = (-0.5 * Math.PI) + (Math.PI * circumference) * index; + var endAngle = startAngle + (circumference * Math.PI); - var resetModel = { + var resetModel = { + x: this.chart.chart.width / 2, + y: this.chart.chart.height / 2, + innerRadius: 0, + outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle, + endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle, + + backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), + hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor), + borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), + borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), + + label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) + }; + + helpers.extend(arc, { + // Utility + _chart: this.chart.chart, + _datasetIndex: this.index, + _index: index, + + // Desired view properties + _model: reset ? resetModel : { x: this.chart.chart.width / 2, y: this.chart.chart.height / 2, innerRadius: 0, - outerRadius: 0, - startAngle: Math.PI * -0.5, - endAngle: Math.PI * -0.5, + outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), + startAngle: startAngle, + endAngle: endAngle, backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor), @@ -97,40 +145,10 @@ borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) - }; + }, + }); - var circumference = 1 / this.getDataset().data.length * 2; - var startAngle = (-0.5 * Math.PI) + (Math.PI * circumference) * index; - var endAngle = startAngle + (circumference * Math.PI); - - console.log() - - helpers.extend(arc, { - // Utility - _chart: this.chart.chart, - _datasetIndex: this.index, - _index: index, - - // Desired view properties - _model: reset ? resetModel : { - x: this.chart.chart.width / 2, - y: this.chart.chart.height / 2, - innerRadius: 0, - outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]), - startAngle: startAngle, - endAngle: endAngle, - - backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor), - hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor), - borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth), - borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor), - - label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index]) - }, - }); - - arc.pivot(); - }, this); + arc.pivot(); }, draw: function(ease) { @@ -141,8 +159,6 @@ }, this); }, - - setHoverStyle: function(arc) { var dataset = this.chart.data.datasets[arc._datasetIndex]; var index = arc._index;