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;
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,
first._view.x,
first._view.y
);
- } else {
+ } else if (drawLineToCenter) {
// Go to center
ctx.lineTo(_this._view.scaleZero.x, _this._view.scaleZero.y);
}
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 {
// 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);
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);
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();
_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
+ },
}
});
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']
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: []
+ }]);
+ });
});