From 05523b01b0207fd6d6ce00a45d8c6f773df4137d Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Fri, 13 Nov 2015 22:04:38 -0500 Subject: [PATCH 01/13] Refactor the line drawing code. Tests are broken. --- src/elements/element.line.js | 186 +++++++++++++++-------------------- 1 file changed, 78 insertions(+), 108 deletions(-) diff --git a/src/elements/element.line.js b/src/elements/element.line.js index f094dea6e..85d84e929 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -31,6 +31,37 @@ Chart.elements.Line = Chart.Element.extend({ + lineToNextPoint: function(previousPoint, point, nextPoint) { + var ctx = this._chart.ctx; + + if (point._view.skip) { + if (this.loop) { + // Go to center + ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); + } else { + ctx.lineTo(previousPoint._view.x, this._view.scaleZero); + ctx.moveTo(next._view.x, this._view.scaleZero); + } + } else if (previousPoint._view.skip) { + ctx.lineTo(point._view.x, point._view.y); + } else { + // Line between points + //if (point !== nextPoint) { + ctx.bezierCurveTo( + previousPoint._view.controlPointNextX, + previousPoint._view.controlPointNextY, + point._view.controlPointPreviousX, + point._view.controlPointPreviousY, + point._view.x, + point._view.y + ); + //} else { + // Drawing to the last point in the line + + //} + } + }, + draw: function() { var vm = this._view; @@ -40,78 +71,51 @@ ctx.save(); - // Draw the background first (so the border is always on top) - helpers.each(this._children, function(point, index) { - - var previous = helpers.previousItem(this._children, index); - var next = helpers.nextItem(this._children, index); - - // First point moves to it's starting position no matter what - if (!index) { - ctx.moveTo(point._view.x, vm.scaleZero); - } - - // Skip this point, draw to scaleZero, move to next point, and draw to next point - if (point._view.skip && !this.loop) { - ctx.lineTo(previous._view.x, vm.scaleZero); - ctx.moveTo(next._view.x, vm.scaleZero); - return; - } - - // The previous line was skipped, so just draw a normal straight line to the point - if (previous._view.skip) { - ctx.lineTo(point._view.x, point._view.y); - return; - } - - // Draw a bezier to point - if (vm.tension > 0 && index) { - //ctx.lineTo(point._view.x, point._view.y); - ctx.bezierCurveTo( - previous._view.controlPointNextX, - previous._view.controlPointNextY, - point._view.controlPointPreviousX, - point._view.controlPointPreviousY, - point._view.x, - point._view.y - ); - return; - } - - // Draw a straight line to the point - ctx.lineTo(point._view.x, point._view.y); - - }, this); - - // For radial scales, loop back around to the first point - if (this._loop) { - // Draw a bezier line - if (vm.tension > 0 && !first._view.skip) { - ctx.bezierCurveTo( - last._view.controlPointNextX, - last._view.controlPointNextY, - first._view.controlPointPreviousX, - first._view.controlPointPreviousY, - first._view.x, - first._view.y - ); - return; - } - // Draw a straight line - ctx.lineTo(first._view.x, first._view.y); - } - // If we had points and want to fill this line, do so. if (this._children.length > 0 && vm.fill) { - //Round off the line by going to the base of the chart, back to the start, then fill. - ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero); - ctx.lineTo(this._children[0]._view.x, vm.scaleZero); + // Draw the background first (so the border is always on top) + ctx.beginPath(); + + helpers.each(this._children, function(point, index) { + var previous = helpers.previousItem(this._children, index/*, this._loop*/); + var next = helpers.nextItem(this._children, index/*, this._loop*/); + + // First point moves to it's starting position no matter what + if (index === 0) { + ctx.moveTo(point._view.x, vm.scaleZero); + ctx.lineTo(point._view.x, point._view.y); + } else { + this.lineToNextPoint(previous, point, next); + } + }, this); + + // For radial scales, loop back around to the first point + if (this._loop) { + if (!first._view.skip) { + // Draw a bezier line + ctx.bezierCurveTo( + last._view.controlPointNextX, + last._view.controlPointNextY, + first._view.controlPointPreviousX, + first._view.controlPointPreviousY, + first._view.x, + first._view.y + ); + } else { + // Go to center + ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); + } + } else { + //Round off the line by going to the base of the chart, back to the start, then fill. + ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero); + ctx.lineTo(this._children[0]._view.x, vm.scaleZero); + } + ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor; ctx.closePath(); ctx.fill(); } - // Now draw the line between all the points with any borders ctx.lineCap = vm.borderCapStyle || Chart.defaults.global.elements.line.borderCapStyle; @@ -130,49 +134,16 @@ var previous = helpers.previousItem(this._children, index); var next = helpers.nextItem(this._children, index); - if (!index) { - ctx.moveTo(point._view.x, vm.scaleZero); - } - - // Skip this point and move to the next points zeroPoint - if (point._view.skip && !this.loop) { - ctx.moveTo(next._view.x, vm.scaleZero); - return; - } - - // Previous point was skipped, just move to the point - if (previous._view.skip) { + if (index === 0) { ctx.moveTo(point._view.x, point._view.y); - return; + } else { + this.lineToNextPoint(previous, point, next); } - - // If First point, move to the point ahead of time (so a line doesn't get drawn up the left axis) - if (!index) { - ctx.moveTo(point._view.x, point._view.y); - } - - // Draw a bezier line to the point - if (vm.tension > 0 && index) { - ctx.bezierCurveTo( - previous._view.controlPointNextX, - previous._view.controlPointNextY, - point._view.controlPointPreviousX, - point._view.controlPointPreviousY, - point._view.x, - point._view.y - ); - return; - } - - // Draw a straight line to the point - ctx.lineTo(point._view.x, point._view.y); - }, this); - if (this._loop && !first._view.skip) { - - // Draw a bezier line to the first point - if (vm.tension > 0) { + if (this._loop) { + if (!first._view.skip) { + // Draw a bezier line ctx.bezierCurveTo( last._view.controlPointNextX, last._view.controlPointNextY, @@ -181,11 +152,10 @@ first._view.x, first._view.y ); - return; + } else { + // Go to center + ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); } - - // Draw a straight line to the first point - ctx.lineTo(first._view.x, first._view.y); } ctx.stroke(); From 108c4fcd56363f77b9ab13892b876479d246958d Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Fri, 13 Nov 2015 22:15:23 -0500 Subject: [PATCH 02/13] Simplify code for capping bezier control points. Cap the X direction as well. --- src/controllers/controller.line.js | 24 ++++-------------------- src/controllers/controller.radar.js | 24 ++++-------------------- 2 files changed, 8 insertions(+), 40 deletions(-) diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index 954686e06..c22df9f97 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -251,28 +251,12 @@ point._model.tension ); - point._model.controlPointPreviousX = controlPoints.previous.x; - point._model.controlPointNextX = controlPoints.next.x; - // Prevent the bezier going outside of the bounds of the graph + point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.bottom); - // 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) { - point._model.controlPointNextY = this.chart.chartArea.top; - } else { - point._model.controlPointNextY = controlPoints.next.y; - } - - // Cap inner bezier handles to the upper/lower scale bounds - if (controlPoints.previous.y > this.chart.chartArea.bottom) { - point._model.controlPointPreviousY = this.chart.chartArea.bottom; - } else if (controlPoints.previous.y < this.chart.chartArea.top) { - point._model.controlPointPreviousY = this.chart.chartArea.top; - } else { - point._model.controlPointPreviousY = controlPoints.previous.y; - } + point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); // Now pivot the point for animation point.pivot(); diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index b8bcf1441..5e452820d 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -197,28 +197,12 @@ point._model.tension ); - point._model.controlPointPreviousX = controlPoints.previous.x; - point._model.controlPointNextX = controlPoints.next.x; - // Prevent the bezier going outside of the bounds of the graph + point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.bottom); - // 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) { - point._model.controlPointNextY = this.chart.chartArea.top; - } else { - point._model.controlPointNextY = controlPoints.next.y; - } - - // Cap inner bezier handles to the upper/lower scale bounds - if (controlPoints.previous.y > this.chart.chartArea.bottom) { - point._model.controlPointPreviousY = this.chart.chartArea.bottom; - } else if (controlPoints.previous.y < this.chart.chartArea.top) { - point._model.controlPointPreviousY = this.chart.chartArea.top; - } else { - point._model.controlPointPreviousY = controlPoints.previous.y; - } + point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); + point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); // Now pivot the point for animation point.pivot(); From 0e02d216aa8eb4714bb20e1b8ad4d3e498ee2ead Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Fri, 13 Nov 2015 22:42:33 -0500 Subject: [PATCH 03/13] Cleanup --- src/elements/element.line.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 85d84e929..a00300ffe 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -46,19 +46,18 @@ ctx.lineTo(point._view.x, point._view.y); } else { // Line between points - //if (point !== nextPoint) { - ctx.bezierCurveTo( - previousPoint._view.controlPointNextX, - previousPoint._view.controlPointNextY, - point._view.controlPointPreviousX, - point._view.controlPointPreviousY, - point._view.x, - point._view.y - ); - //} else { - // Drawing to the last point in the line + if (point._index === 1) { + console.log("bezierCurveTo(" + previousPoint._view.controlPointNextX + ", " + previousPoint._view.controlPointNextY + ", " + point._view.controlPointPreviousX + ", " + point._view.controlPointPreviousY + ", " + point._view.x + ", " + point._view.y + ")"); + } - //} + ctx.bezierCurveTo( + previousPoint._view.controlPointNextX, + previousPoint._view.controlPointNextY, + point._view.controlPointPreviousX, + point._view.controlPointPreviousY, + point._view.x, + point._view.y + ); } }, From f6ac7d9369d9a261cd9208aacafe2301fdf2b490 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Fri, 13 Nov 2015 22:42:42 -0500 Subject: [PATCH 04/13] Typo --- src/controllers/controller.line.js | 2 +- src/controllers/controller.radar.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/controller.line.js b/src/controllers/controller.line.js index c22df9f97..2f2ef279d 100644 --- a/src/controllers/controller.line.js +++ b/src/controllers/controller.line.js @@ -253,7 +253,7 @@ // Prevent the bezier going outside of the bounds of the graph point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); - point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.bottom); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top); point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); diff --git a/src/controllers/controller.radar.js b/src/controllers/controller.radar.js index 5e452820d..639c87722 100644 --- a/src/controllers/controller.radar.js +++ b/src/controllers/controller.radar.js @@ -199,7 +199,7 @@ // Prevent the bezier going outside of the bounds of the graph point._model.controlPointPreviousX = Math.max(Math.min(controlPoints.previous.x, this.chart.chartArea.right), this.chart.chartArea.left); - point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.bottom); + point._model.controlPointPreviousY = Math.max(Math.min(controlPoints.previous.y, this.chart.chartArea.bottom), this.chart.chartArea.top); point._model.controlPointNextX = Math.max(Math.min(controlPoints.next.x, this.chart.chartArea.right), this.chart.chartArea.left); point._model.controlPointNextY = Math.max(Math.min(controlPoints.next.y, this.chart.chartArea.bottom), this.chart.chartArea.top); From 01fe5355949d82353463a09aa0e50124c2730ca7 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 21:57:22 -0500 Subject: [PATCH 05/13] Refactor the lineToNextPoint functionality to give the correct draw line behaviour. Makes the code a little cleaner too. --- src/elements/element.line.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/elements/element.line.js b/src/elements/element.line.js index a00300ffe..d31d8657f 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -31,25 +31,15 @@ Chart.elements.Line = Chart.Element.extend({ - lineToNextPoint: function(previousPoint, point, nextPoint) { + lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) { var ctx = this._chart.ctx; if (point._view.skip) { - if (this.loop) { - // Go to center - ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); - } else { - ctx.lineTo(previousPoint._view.x, this._view.scaleZero); - ctx.moveTo(next._view.x, this._view.scaleZero); - } + skipHandler.call(this, previousPoint, point, nextPoint); } else if (previousPoint._view.skip) { - ctx.lineTo(point._view.x, point._view.y); + previousSkipHandler.call(this, previousPoint, point, nextPoint); } else { // Line between points - if (point._index === 1) { - console.log("bezierCurveTo(" + previousPoint._view.controlPointNextX + ", " + previousPoint._view.controlPointNextY + ", " + point._view.controlPointPreviousX + ", " + point._view.controlPointPreviousY + ", " + point._view.x + ", " + point._view.y + ")"); - } - ctx.bezierCurveTo( previousPoint._view.controlPointNextX, previousPoint._view.controlPointNextY, @@ -84,7 +74,18 @@ ctx.moveTo(point._view.x, vm.scaleZero); ctx.lineTo(point._view.x, point._view.y); } else { - this.lineToNextPoint(previous, point, next); + this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { + if (this.loop) { + // Go to center + ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); + } else { + ctx.lineTo(previousPoint._view.x, this._view.scaleZero); + ctx.moveTo(nextPoint._view.x, this._view.scaleZero); + } + }, function(previousPoint, point, nextPoint) { + // If we skipped the last point, draw a line to ourselves so that the fill is nice + ctx.lineTo(point._view.x, point._view.y); + }); } }, this); @@ -136,7 +137,12 @@ if (index === 0) { ctx.moveTo(point._view.x, point._view.y); } else { - this.lineToNextPoint(previous, point, next); + this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { + ctx.moveTo(nextPoint._view.x, this._view.scaleZero); + }, function(previousPoint, point, nextPoint) { + // If we skipped the last point, move up to our point preventing a line from being drawn + ctx.moveTo(point._view.x, point._view.y); + }); } }, this); From 3bd9120a3a10d5ce510c5ccc66a66a485eeb78ae Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 22:06:37 -0500 Subject: [PATCH 06/13] some duplicate code cleanup --- src/elements/element.line.js | 48 +++++++++++++++--------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/src/elements/element.line.js b/src/elements/element.line.js index d31d8657f..dc1f1d635 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -52,12 +52,30 @@ }, draw: function() { + var _this = this; var vm = this._view; var ctx = this._chart.ctx; var first = this._children[0]; var last = this._children[this._children.length - 1]; + function loopBackToStart() { + if (!first._view.skip) { + // Draw a bezier line from last to first + ctx.bezierCurveTo( + last._view.controlPointNextX, + last._view.controlPointNextY, + first._view.controlPointPreviousX, + first._view.controlPointPreviousY, + first._view.x, + first._view.y + ); + } else { + // Go to center + ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y); + } + } + ctx.save(); // If we had points and want to fill this line, do so. @@ -91,20 +109,7 @@ // For radial scales, loop back around to the first point if (this._loop) { - if (!first._view.skip) { - // Draw a bezier line - ctx.bezierCurveTo( - last._view.controlPointNextX, - last._view.controlPointNextY, - first._view.controlPointPreviousX, - first._view.controlPointPreviousY, - first._view.x, - first._view.y - ); - } else { - // Go to center - ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); - } + loopBackToStart(); } else { //Round off the line by going to the base of the chart, back to the start, then fill. ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero); @@ -147,20 +152,7 @@ }, this); if (this._loop) { - if (!first._view.skip) { - // Draw a bezier line - ctx.bezierCurveTo( - last._view.controlPointNextX, - last._view.controlPointNextY, - first._view.controlPointPreviousX, - first._view.controlPointPreviousY, - first._view.x, - first._view.y - ); - } else { - // Go to center - ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); - } + loopBackToStart(); } ctx.stroke(); From 55c7d6872aafad0748d305bb3cae28d79d9ab470 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 22:49:08 -0500 Subject: [PATCH 07/13] Prevent NaN results when previous, point, and next are all the same --- src/core/core.helpers.js | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/core/core.helpers.js b/src/core/core.helpers.js index 1f19a5c0a..50d5c51ec 100644 --- a/src/core/core.helpers.js +++ b/src/core/core.helpers.js @@ -321,27 +321,29 @@ aliasPixel = helpers.aliasPixel = function(pixelWidth) { return (pixelWidth % 2 === 0) ? 0 : 0.5; }, - splineCurve = helpers.splineCurve = function(FirstPoint, MiddlePoint, AfterPoint, t) { + splineCurve = helpers.splineCurve = function(firstPoint, middlePoint, afterPoint, t) { //Props to Rob Spencer at scaled innovation for his post on splining between points //http://scaledinnovation.com/analytics/splines/aboutSplines.html // This function must also respect "skipped" points - var previous = FirstPoint, - current = MiddlePoint, - next = AfterPoint; + var previous = firstPoint.skip ? middlePoint : firstPoint, + current = middlePoint, + next = afterPoint.skip ? middlePoint : afterPoint; - if (previous.skip) { - previous = current; - } - if (next.skip) { - next = current; - } + var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)); + var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)); + + var s01 = d01 / (d01 + d12); + var s12 = d12 / (d01 + d12); + + // If all points are the same, s01 & s02 will be inf + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + + var fa = t * s01; // scaling factor for triangle Ta + var fb = t * s12; - var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)), - d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)), - fa = t * d01 / (d01 + d12), // scaling factor for triangle Ta - fb = t * d12 / (d01 + d12); return { previous: { x: current.x - fa * (next.x - previous.x), From d61745a31155843fd0583f3c6c0a08673e0d4a93 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 22:49:53 -0500 Subject: [PATCH 08/13] Handle transitioning NaNs --- src/core/core.element.js | 5 ++--- src/scales/scale.radialLinear.js | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/core.element.js b/src/core/core.element.js index 594269619..d9c0d35a6 100644 --- a/src/core/core.element.js +++ b/src/core/core.element.js @@ -38,7 +38,7 @@ // Init if doesn't exist else if (!this._view[key]) { - if (typeof value === 'number') { + if (typeof value === 'number' && isNaN(this._view[key]) === false) { this._view[key] = value * ease; } else { this._view[key] = value || null; @@ -61,14 +61,13 @@ } // Number transitions else if (typeof value === 'number') { - var startVal = this._start[key] !== undefined ? this._start[key] : 0; + var startVal = this._start[key] !== undefined && isNaN(this._start[key]) === false ? this._start[key] : 0; this._view[key] = ((this._model[key] - startVal) * ease) + startVal; } // Everything else else { this._view[key] = value; } - }, this); if (ease === 1) { diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 15fdb3626..4d622cc98 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -272,7 +272,10 @@ return index * angleMultiplier - (Math.PI / 2); }, getDistanceFromCenterForValue: function(value) { - if (value === null) return 0; // null always in center + if (value === null || value === undefined || isNaN(value)) { + return 0; // null always in center + } + // Take into account half font size + the yPadding of the top value var scalingFactor = this.drawingArea / (this.max - this.min); if (this.options.reverse) { From 37249e4375dde042d573f1a18aabe188aa2de1fa Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 22:52:10 -0500 Subject: [PATCH 09/13] Fix an incorrect test setup --- test/controller.line.tests.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/controller.line.tests.js b/test/controller.line.tests.js index cdfb9bdc9..b8e8695e2 100644 --- a/test/controller.line.tests.js +++ b/test/controller.line.tests.js @@ -192,7 +192,7 @@ describe('Line controller tests', function() { chartArea: { bottom: 200, left: xScale.left, - right: 200, + right: xScale.left + 200, top: 0 }, data: data, From 9c78de10bad228bd3a7c91da4f2b0242d978734f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sat, 14 Nov 2015 23:16:07 -0500 Subject: [PATCH 10/13] Fix line tests. Still need to add tests of the skip code. --- test/element.line.tests.js | 328 +++++++++---------------------------- 1 file changed, 81 insertions(+), 247 deletions(-) diff --git a/test/element.line.tests.js b/test/element.line.tests.js index 2b4028fbe..a31077232 100644 --- a/test/element.line.tests.js +++ b/test/element.line.tests.js @@ -22,6 +22,8 @@ describe('Line element tests', function() { _view: { x: 0, y: 10, + controlPointNextX: 0, + controlPointNextY: 10 } })); points.push(new Chart.elements.Point({ @@ -30,6 +32,10 @@ describe('Line element tests', function() { _view: { x: 5, y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0 } })); points.push(new Chart.elements.Point({ @@ -38,6 +44,10 @@ describe('Line element tests', function() { _view: { x: 15, y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 } })); points.push(new Chart.elements.Point({ @@ -46,6 +56,10 @@ describe('Line element tests', function() { _view: { x: 19, y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 } })); @@ -68,21 +82,6 @@ describe('Line element tests', function() { expect(mockContext.getCalls()).toEqual([{ name: 'save', args: [], - }, { - name: 'moveTo', - args: [0, 0] - }, { - name: 'lineTo', - args: [0, 10] - }, { - name: 'lineTo', - args: [5, 0] - }, { - name: 'lineTo', - args: [15, -10] - }, { - name: 'lineTo', - args: [19, -5] }, { name: 'setLineCap', args: ['butt'] @@ -106,24 +105,18 @@ describe('Line element tests', function() { }, { name: 'beginPath', args: [] - }, { - name: 'moveTo', - args: [0, 0] }, { name: 'moveTo', args: [0, 10] }, { - name: 'lineTo', - args: [0, 10] + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] }, { - name: 'lineTo', - args: [5, 0] + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] }, { - name: 'lineTo', - args: [15, -10] - }, { - name: 'lineTo', - args: [19, -5] + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] }, { name: 'stroke', args: [], @@ -143,7 +136,9 @@ describe('Line element tests', function() { _index: 0, _view: { x: 0, - y: 10 + y: 10, + controlPointNextX: 0, + controlPointNextY: 10 } })); points.push(new Chart.elements.Point({ @@ -151,7 +146,11 @@ describe('Line element tests', function() { _index: 1, _view: { x: 5, - y: 0 + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0 } })); points.push(new Chart.elements.Point({ @@ -159,7 +158,11 @@ describe('Line element tests', function() { _index: 2, _view: { x: 15, - y: -10 + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 } })); points.push(new Chart.elements.Point({ @@ -167,7 +170,11 @@ describe('Line element tests', function() { _index: 3, _view: { x: 19, - y: -5 + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 } })); @@ -198,6 +205,9 @@ describe('Line element tests', function() { var expected = [{ name: 'save', args: [], + }, { + name: 'beginPath', + args: [] }, { name: 'moveTo', args: [0, 2] @@ -205,14 +215,14 @@ describe('Line element tests', function() { name: 'lineTo', args: [0, 10] }, { - name: 'lineTo', - args: [5, 0] + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] }, { - name: 'lineTo', - args: [15, -10] + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] }, { - name: 'lineTo', - args: [19, -5] + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] }, { name: 'lineTo', args: [19, 2] @@ -251,24 +261,18 @@ describe('Line element tests', function() { }, { name: 'beginPath', args: [] - }, { - name: 'moveTo', - args: [0, 2] }, { name: 'moveTo', args: [0, 10] }, { - name: 'lineTo', - args: [0, 10] + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] }, { - name: 'lineTo', - args: [5, 0] + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] }, { - name: 'lineTo', - args: [15, -10] - }, { - name: 'lineTo', - args: [19, -5] + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] }, { name: 'stroke', args: [], @@ -289,7 +293,11 @@ describe('Line element tests', function() { _index: 0, _view: { x: 0, - y: 10 + y: 10, + controlPointPreviousX: 0, + controlPointPreviousY: 10, + controlPointNextX: 0, + controlPointNextY: 10 } })); points.push(new Chart.elements.Point({ @@ -297,7 +305,11 @@ describe('Line element tests', function() { _index: 1, _view: { x: 5, - y: 0 + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0 } })); points.push(new Chart.elements.Point({ @@ -305,7 +317,11 @@ describe('Line element tests', function() { _index: 2, _view: { x: 15, - y: -10 + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 } })); points.push(new Chart.elements.Point({ @@ -313,7 +329,11 @@ describe('Line element tests', function() { _index: 3, _view: { x: 19, - y: -5 + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 } })); @@ -337,24 +357,6 @@ describe('Line element tests', function() { expect(mockContext.getCalls()).toEqual([{ name: 'save', args: [], - }, { - name: 'moveTo', - args: [0, 0] - }, { - name: 'lineTo', - args: [0, 10] - }, { - name: 'lineTo', - args: [5, 0] - }, { - name: 'lineTo', - args: [15, -10] - }, { - name: 'lineTo', - args: [19, -5] - }, { - name: 'lineTo', - args: [0, 10] }, { name: 'setLineCap', args: ['butt'] @@ -378,27 +380,21 @@ describe('Line element tests', function() { }, { name: 'beginPath', args: [] - }, { - name: 'moveTo', - args: [0, 0] }, { name: 'moveTo', args: [0, 10] }, { - name: 'lineTo', - args: [0, 10] + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] }, { - name: 'lineTo', - args: [5, 0] + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] }, { - name: 'lineTo', - args: [15, -10] + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] }, { - name: 'lineTo', - args: [19, -5] - }, { - name: 'lineTo', - args: [0, 10] + name: 'bezierCurveTo', + args: [19, -5, 0, 10, 0, 10] }, { name: 'stroke', args: [], @@ -407,166 +403,4 @@ describe('Line element tests', function() { args: [] }]); }); - - it('should draw with bezier curves if tension > 0', function() { - var mockContext = window.createMockContext(); - - // Create our points - var points = []; - points.push(new Chart.elements.Point({ - _datasetindex: 2, - _index: 0, - _view: { - x: 0, - y: 10, - controlPointNextX: 1, - controlPointNextY: 1, - controlPointPreviousX: 0, - controlPointPreviousY: 0, - } - })); - points.push(new Chart.elements.Point({ - _datasetindex: 2, - _index: 1, - _view: { - x: 5, - y: 0, - controlPointNextX: 6, - controlPointNextY: 7, - controlPointPreviousX: 4, - controlPointPreviousY: 3, - } - })); - points.push(new Chart.elements.Point({ - _datasetindex: 2, - _index: 2, - _view: { - x: 15, - y: -10, - controlPointNextX: 16, - controlPointNextY: 17, - controlPointPreviousX: 14, - controlPointPreviousY: 13, - } - })); - points.push(new Chart.elements.Point({ - _datasetindex: 2, - _index: 3, - _view: { - x: 19, - y: -5, - controlPointNextX: 20, - controlPointNextY: 21, - controlPointPreviousX: 18, - controlPointPreviousY: 17, - } - })); - - var line = new Chart.elements.Line({ - _datasetindex: 2, - _chart: { - ctx: mockContext, - }, - _children: points, - // Need to provide some settings - _view: { - fill: true, - scaleZero: 2, // for filling lines - tension: 0.5, // have bezier curves - - borderCapStyle: 'round', - borderColor: 'rgb(255, 255, 0)', - borderDash: [2, 2], - borderDashOffset: 1.5, - borderJoinStyle: 'bevel', - borderWidth: 4, - backgroundColor: 'rgb(0, 0, 0)' - } - }); - - line.draw(); - - var expected = [{ - name: 'save', - args: [], - }, { - name: 'moveTo', - args: [0, 2] - }, { - name: 'lineTo', - args: [0, 10] - }, { - name: 'bezierCurveTo', - args: [1, 1, 4, 3, 5, 0] - }, { - name: 'bezierCurveTo', - args: [6, 7, 14, 13, 15, -10] - }, { - name: 'bezierCurveTo', - args: [16, 17, 18, 17, 19, -5] - }, { - name: 'lineTo', - args: [19, 2] - }, { - name: 'lineTo', - args: [0, 2] - }, { - name: 'setFillStyle', - args: ['rgb(0, 0, 0)'] - }, { - name: 'closePath', - args: [] - }, { - name: 'fill', - args: [] - }, { - name: 'setLineCap', - args: ['round'] - }, { - name: 'setLineDash', - args: [ - [2, 2] - ] - }, { - name: 'setLineDashOffset', - args: [1.5] - }, { - name: 'setLineJoin', - args: ['bevel'] - }, { - name: 'setLineWidth', - args: [4] - }, { - name: 'setStrokeStyle', - args: ['rgb(255, 255, 0)'] - }, { - name: 'beginPath', - args: [] - }, { - name: 'moveTo', - args: [0, 2] - }, { - name: 'moveTo', - args: [0, 10] - }, { - name: 'lineTo', - args: [0, 10] - }, { - name: 'bezierCurveTo', - args: [1, 1, 4, 3, 5, 0] - }, { - name: 'bezierCurveTo', - args: [6, 7, 14, 13, 15, -10] - }, { - name: 'bezierCurveTo', - args: [16, 17, 18, 17, 19, -5] - }, { - name: 'stroke', - args: [], - }, { - name: 'restore', - args: [] - }]; - expect(mockContext.getCalls()).toEqual(expected); - }); }); From 045d8f6c2a00fb9375afb7cc0566a7eec0d7297f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 15 Nov 2015 11:16:17 -0500 Subject: [PATCH 11/13] Keep this as NaN so point._view.skip is set correctly --- src/scales/scale.radialLinear.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 4d622cc98..19f310ec2 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -272,7 +272,7 @@ return index * angleMultiplier - (Math.PI / 2); }, getDistanceFromCenterForValue: function(value) { - if (value === null || value === undefined || isNaN(value)) { + if (value === null) { return 0; // null always in center } From 0495e45ff7767092fe9a61c79b5c0e49f69a7d0f Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 15 Nov 2015 11:16:41 -0500 Subject: [PATCH 12/13] Can now skip in all cases (start, mid, end) whether or not there is a look --- src/elements/element.line.js | 32 +- test/element.line.tests.js | 646 ++++++++++++++++++++++++++++++++++- 2 files changed, 665 insertions(+), 13 deletions(-) diff --git a/src/elements/element.line.js b/src/elements/element.line.js index dc1f1d635..00ae696cf 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -29,7 +29,6 @@ fill: true, // do we fill in the area between the line and its base axis }; - Chart.elements.Line = Chart.Element.extend({ lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) { var ctx = this._chart.ctx; @@ -59,8 +58,8 @@ var first = this._children[0]; var last = this._children[this._children.length - 1]; - function loopBackToStart() { - if (!first._view.skip) { + function loopBackToStart(drawLineToCenter) { + if (!first._view.skip && !last._view.skip) { // Draw a bezier line from last to first ctx.bezierCurveTo( last._view.controlPointNextX, @@ -70,7 +69,7 @@ first._view.x, first._view.y ); - } else { + } else if (drawLineToCenter) { // Go to center ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y); } @@ -84,16 +83,27 @@ ctx.beginPath(); helpers.each(this._children, function(point, index) { - var previous = helpers.previousItem(this._children, index/*, this._loop*/); - var next = helpers.nextItem(this._children, index/*, this._loop*/); + var previous = helpers.previousItem(this._children, index); + var next = helpers.nextItem(this._children, index); // First point moves to it's starting position no matter what if (index === 0) { - ctx.moveTo(point._view.x, vm.scaleZero); - ctx.lineTo(point._view.x, point._view.y); + if (this._loop) { + ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y); + } else { + ctx.moveTo(point._view.x, vm.scaleZero); + } + + if (point._view.skip) { + if (!this._loop) { + ctx.moveTo(next._view.x, this._view.scaleZero); + } + } else { + ctx.lineTo(point._view.x, point._view.y); + } } else { this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { - if (this.loop) { + if (this._loop) { // Go to center ctx.lineTo(this._view.scaleZero.x, this._view.scaleZero.y); } else { @@ -109,7 +119,7 @@ // For radial scales, loop back around to the first point if (this._loop) { - loopBackToStart(); + loopBackToStart(true); } else { //Round off the line by going to the base of the chart, back to the start, then fill. ctx.lineTo(this._children[this._children.length - 1]._view.x, vm.scaleZero); @@ -143,7 +153,7 @@ ctx.moveTo(point._view.x, point._view.y); } else { this.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) { - ctx.moveTo(nextPoint._view.x, this._view.scaleZero); + ctx.moveTo(nextPoint._view.x, nextPoint._view.y); }, function(previousPoint, point, nextPoint) { // If we skipped the last point, move up to our point preventing a line from being drawn ctx.moveTo(point._view.x, point._view.y); diff --git a/test/element.line.tests.js b/test/element.line.tests.js index a31077232..926345feb 100644 --- a/test/element.line.tests.js +++ b/test/element.line.tests.js @@ -283,6 +283,159 @@ describe('Line element tests', function() { expect(mockContext.getCalls()).toEqual(expected); }); + it ('should skip points correctly', function() { + var mockContext = window.createMockContext(); + + // Create our points + var points = []; + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 0, + _view: { + x: 0, + y: 10, + controlPointNextX: 0, + controlPointNextY: 10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 1, + _view: { + x: 5, + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 2, + _view: { + x: 15, + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10, + skip: true + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 3, + _view: { + x: 19, + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 + } + })); + + var line = new Chart.elements.Line({ + _datasetindex: 2, + _chart: { + ctx: mockContext, + }, + _children: points, + // Need to provide some settings + _view: { + fill: true, + scaleZero: 2, // for filling lines + tension: 0.0, // no bezier curve for now + } + }); + + line.draw(); + + var expected = [{ + name: 'save', + args: [] + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [0, 2] + }, { + name: 'lineTo', + args: [0, 10] + }, { + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] + }, { + name: 'lineTo', + args: [5, 2] + }, { + name: 'moveTo', + args: [19, 2] + }, { + name: 'lineTo', + args: [19, -5] + }, { + name: 'lineTo', + args: [19, 2] + }, { + name: 'lineTo', + args: [0, 2] + }, { + name: 'setFillStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'closePath', + args: [] + }, { + name: 'fill', + args: [] + }, { + name: 'setLineCap', + args: ['butt'] + }, { + name: 'setLineDash', + args: [ + [] + ] + }, { + name: 'setLineDashOffset', + args: [0.0] + }, { + name: 'setLineJoin', + args: ['miter'] + }, { + name: 'setLineWidth', + args: [3] + }, { + name: 'setStrokeStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [0, 10] + }, { + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] + }, { + name: 'moveTo', + args: [19, -5] + }, { + name: 'moveTo', + args: [19, -5] + }, { + name: 'stroke', + args: [], + }, { + name: 'restore', + args: [] + }]; + expect(mockContext.getCalls()).toEqual(expected); + }); + it('should be able to draw with a loop back to the beginning point', function() { var mockContext = window.createMockContext(); @@ -346,9 +499,12 @@ describe('Line element tests', function() { _loop: true, // want the line to loop back to the first point // Need to provide some settings _view: { - fill: false, // don't want to fill + fill: true, // don't want to fill tension: 0.0, // no bezier curve for now - scaleZero: 0, + scaleZero: { + x: 3, + y: 2 + }, } }); @@ -357,6 +513,36 @@ describe('Line element tests', function() { expect(mockContext.getCalls()).toEqual([{ name: 'save', args: [], + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [0, 10] + }, { + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] + }, { + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] + }, { + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] + }, { + name: 'bezierCurveTo', + args: [19, -5, 0, 10, 0, 10] + }, { + name: 'setFillStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'closePath', + args: [] + }, { + name: 'fill', + args: [] }, { name: 'setLineCap', args: ['butt'] @@ -403,4 +589,460 @@ describe('Line element tests', function() { args: [] }]); }); + + it('should be able to draw with a loop back to the beginning point when there is a skip in the middle of the dataset', function() { + var mockContext = window.createMockContext(); + + // Create our points + var points = []; + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 0, + _view: { + x: 0, + y: 10, + controlPointPreviousX: 0, + controlPointPreviousY: 10, + controlPointNextX: 0, + controlPointNextY: 10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 1, + _view: { + x: 5, + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0, + skip: true + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 2, + _view: { + x: 15, + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 3, + _view: { + x: 19, + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 + } + })); + + var line = new Chart.elements.Line({ + _datasetindex: 2, + _chart: { + ctx: mockContext, + }, + _children: points, + _loop: true, // want the line to loop back to the first point + // Need to provide some settings + _view: { + fill: true, // don't want to fill + tension: 0.0, // no bezier curve for now + scaleZero: { + x: 3, + y: 2 + }, + } + }); + + line.draw(); + + expect(mockContext.getCalls()).toEqual([{ + name: 'save', + args: [], + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [0, 10] + }, { + name: 'lineTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [15, -10] + }, { + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] + }, { + name: 'bezierCurveTo', + args: [19, -5, 0, 10, 0, 10] + }, { + name: 'setFillStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'closePath', + args: [] + }, { + name: 'fill', + args: [] + }, { + name: 'setLineCap', + args: ['butt'] + }, { + name: 'setLineDash', + args: [ + [] + ] + }, { + name: 'setLineDashOffset', + args: [0.0] + }, { + name: 'setLineJoin', + args: ['miter'] + }, { + name: 'setLineWidth', + args: [3] + }, { + name: 'setStrokeStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [0, 10] + }, { + name: 'moveTo', + args: [15, -10] + }, { + name: 'moveTo', + args: [15, -10] + }, { + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] + }, { + name: 'bezierCurveTo', + args: [19, -5, 0, 10, 0, 10] + }, { + name: 'stroke', + args: [], + }, { + name: 'restore', + args: [] + }]); + }); + + it('should be able to draw with a loop back to the beginning point when the first point is skipped', function() { + var mockContext = window.createMockContext(); + + // Create our points + var points = []; + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 0, + _view: { + x: 0, + y: 10, + controlPointPreviousX: 0, + controlPointPreviousY: 10, + controlPointNextX: 0, + controlPointNextY: 10, + skip: true + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 1, + _view: { + x: 5, + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0, + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 2, + _view: { + x: 15, + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 3, + _view: { + x: 19, + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5 + } + })); + + var line = new Chart.elements.Line({ + _datasetindex: 2, + _chart: { + ctx: mockContext, + }, + _children: points, + _loop: true, // want the line to loop back to the first point + // Need to provide some settings + _view: { + fill: true, // don't want to fill + tension: 0.0, // no bezier curve for now + scaleZero: { + x: 3, + y: 2 + }, + } + }); + + line.draw(); + + expect(mockContext.getCalls()).toEqual([{ + name: 'save', + args: [], + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [5, 0] + }, { + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] + }, { + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] + }, { + name: 'lineTo', + args: [3, 2] + }, { + name: 'setFillStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'closePath', + args: [] + }, { + name: 'fill', + args: [] + }, { + name: 'setLineCap', + args: ['butt'] + }, { + name: 'setLineDash', + args: [ + [] + ] + }, { + name: 'setLineDashOffset', + args: [0.0] + }, { + name: 'setLineJoin', + args: ['miter'] + }, { + name: 'setLineWidth', + args: [3] + }, { + name: 'setStrokeStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [0, 10] + }, { + name: 'moveTo', + args: [5, 0] + }, { + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] + }, { + name: 'bezierCurveTo', + args: [15, -10, 19, -5, 19, -5] + }, { + name: 'stroke', + args: [], + }, { + name: 'restore', + args: [] + }]); + }); + + it('should be able to draw with a loop back to the beginning point when the last point is skipped', function() { + var mockContext = window.createMockContext(); + + // Create our points + var points = []; + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 0, + _view: { + x: 0, + y: 10, + controlPointPreviousX: 0, + controlPointPreviousY: 10, + controlPointNextX: 0, + controlPointNextY: 10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 1, + _view: { + x: 5, + y: 0, + controlPointPreviousX: 5, + controlPointPreviousY: 0, + controlPointNextX: 5, + controlPointNextY: 0, + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 2, + _view: { + x: 15, + y: -10, + controlPointPreviousX: 15, + controlPointPreviousY: -10, + controlPointNextX: 15, + controlPointNextY: -10 + } + })); + points.push(new Chart.elements.Point({ + _datasetindex: 2, + _index: 3, + _view: { + x: 19, + y: -5, + controlPointPreviousX: 19, + controlPointPreviousY: -5, + controlPointNextX: 19, + controlPointNextY: -5, + skip: true + } + })); + + var line = new Chart.elements.Line({ + _datasetindex: 2, + _chart: { + ctx: mockContext, + }, + _children: points, + _loop: true, // want the line to loop back to the first point + // Need to provide some settings + _view: { + fill: true, // don't want to fill + tension: 0.0, // no bezier curve for now + scaleZero: { + x: 3, + y: 2 + }, + } + }); + + line.draw(); + + expect(mockContext.getCalls()).toEqual([{ + name: 'save', + args: [], + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [0, 10] + }, { + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] + }, { + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] + }, { + name: 'lineTo', + args: [3, 2] + }, { + name: 'lineTo', + args: [3, 2] + }, { + name: 'setFillStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'closePath', + args: [] + }, { + name: 'fill', + args: [] + }, { + name: 'setLineCap', + args: ['butt'] + }, { + name: 'setLineDash', + args: [ + [] + ] + }, { + name: 'setLineDashOffset', + args: [0.0] + }, { + name: 'setLineJoin', + args: ['miter'] + }, { + name: 'setLineWidth', + args: [3] + }, { + name: 'setStrokeStyle', + args: ['rgba(0,0,0,0.1)'] + }, { + name: 'beginPath', + args: [] + }, { + name: 'moveTo', + args: [0, 10] + }, { + name: 'bezierCurveTo', + args: [0, 10, 5, 0, 5, 0] + }, { + name: 'bezierCurveTo', + args: [5, 0, 15, -10, 15, -10] + }, { + name: 'moveTo', + args: [19, -5] + }, { + name: 'stroke', + args: [], + }, { + name: 'restore', + args: [] + }]); + }); }); From 3a193e2117660271fd549ab63bdc0711d52d6462 Mon Sep 17 00:00:00 2001 From: Evert Timberg Date: Sun, 15 Nov 2015 11:17:02 -0500 Subject: [PATCH 13/13] Update samples --- samples/line-skip-points.html | 175 +++++++++++++++++++++++++++++++++ samples/radar-skip-points.html | 152 ++++++++++++++++++++++++++++ samples/radar.html | 4 +- 3 files changed, 329 insertions(+), 2 deletions(-) create mode 100644 samples/line-skip-points.html create mode 100644 samples/radar-skip-points.html diff --git a/samples/line-skip-points.html b/samples/line-skip-points.html new file mode 100644 index 000000000..a0a9e6e11 --- /dev/null +++ b/samples/line-skip-points.html @@ -0,0 +1,175 @@ + + + + + Line Chart + + + + + + +
+ +
+
+
+ + + + + +
+

Legend

+
+
+
+ + + + diff --git a/samples/radar-skip-points.html b/samples/radar-skip-points.html new file mode 100644 index 000000000..14c5072a5 --- /dev/null +++ b/samples/radar-skip-points.html @@ -0,0 +1,152 @@ + + + + + Radar Chart + + + + + +
+ +
+ + + + + +
+

Legend

+
+ +
+
+ + + + diff --git a/samples/radar.html b/samples/radar.html index da45b3e8f..eab9a8655 100644 --- a/samples/radar.html +++ b/samples/radar.html @@ -41,7 +41,7 @@ label: "My First dataset", backgroundColor: "rgba(220,220,220,0.2)", pointBackgroundColor: "rgba(220,220,220,1)", - data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()] + data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()] }, { label: 'Hidden dataset', hidden: true, @@ -52,7 +52,7 @@ pointBackgroundColor: "rgba(151,187,205,1)", hoverPointBackgroundColor: "#fff", pointHighlightStroke: "rgba(151,187,205,1)", - data: [null, randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()] + data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()] },] }, options: {