};
Chart.elements.Line = Chart.Element.extend({
- lineToNextPoint: function(previousPoint, point, nextPoint, skipHandler, previousSkipHandler) {
- var me = this;
- var ctx = me._chart.ctx;
- var spanGaps = me._view ? me._view.spanGaps : false;
-
- if (point._view.skip && !spanGaps) {
- skipHandler.call(me, previousPoint, point, nextPoint);
- } else if (previousPoint._view.skip && !spanGaps) {
- previousSkipHandler.call(me, previousPoint, point, nextPoint);
- } else if (point._view.steppedLine === true) {
- ctx.lineTo(point._view.x, previousPoint._view.y);
- ctx.lineTo(point._view.x, point._view.y);
- } else if (point._view.tension === 0) {
- ctx.lineTo(point._view.x, point._view.y);
- } else {
- // Line between points
- ctx.bezierCurveTo(
- previousPoint._view.controlPointNextX,
- previousPoint._view.controlPointNextY,
- point._view.controlPointPreviousX,
- point._view.controlPointPreviousY,
- point._view.x,
- point._view.y
- );
- }
- },
-
draw: function() {
var me = this;
-
var vm = me._view;
+ var spanGaps = vm.spanGaps;
+ var scaleZero = vm.scaleZero;
+ var loop = me._loop;
+
var ctx = me._chart.ctx;
- var first = me._children[0];
- var last = me._children[me._children.length - 1];
+ ctx.save();
- function loopBackToStart(drawLineToCenter) {
- if (!first._view.skip && !last._view.skip) {
- // Draw a bezier line from last to first
+ // Helper function to draw a line to a point
+ function lineToPoint(previousPoint, point) {
+ var vm = point._view;
+ if (point._view.steppedLine === true) {
+ ctx.lineTo(point._view.x, previousPoint._view.y);
+ ctx.lineTo(point._view.x, point._view.y);
+ } else if (point._view.tension === 0) {
+ ctx.lineTo(vm.x, vm.y);
+ } else {
ctx.bezierCurveTo(
- last._view.controlPointNextX,
- last._view.controlPointNextY,
- first._view.controlPointPreviousX,
- first._view.controlPointPreviousY,
- first._view.x,
- first._view.y
+ previousPoint._view.controlPointNextX,
+ previousPoint._view.controlPointNextY,
+ vm.controlPointPreviousX,
+ vm.controlPointPreviousY,
+ vm.x,
+ vm.y
);
- } else if (drawLineToCenter) {
- // Go to center
- ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
}
}
- ctx.save();
+ var points = me._children.slice(); // clone array
+ var lastDrawnIndex = -1;
+
+ // If we are looping, adding the first point again
+ if (loop && points.length) {
+ points.push(points[0]);
+ }
- // If we had points and want to fill this line, do so.
- if (me._children.length > 0 && vm.fill) {
- // Draw the background first (so the border is always on top)
+ // Fill Line
+ if (points.length && vm.fill) {
ctx.beginPath();
- helpers.each(me._children, function(point, index) {
- var previous = helpers.previousItem(me._children, index);
- var next = helpers.nextItem(me._children, index);
+ for (var index = 0; index < points.length; ++index) {
+ var current = points[index];
+ var previous = helpers.previousItem(points, index);
+
+ var currentVM = current._view;
// First point moves to it's starting position no matter what
if (index === 0) {
- if (me._loop) {
- ctx.moveTo(vm.scaleZero.x, vm.scaleZero.y);
+ if (loop) {
+ ctx.moveTo(scaleZero.x, scaleZero.y);
} else {
- ctx.moveTo(point._view.x, vm.scaleZero);
+ ctx.moveTo(currentVM.x, scaleZero);
}
- if (point._view.skip) {
- if (!me._loop) {
- ctx.moveTo(next._view.x, me._view.scaleZero);
- }
- } else {
- ctx.lineTo(point._view.x, point._view.y);
+ if (!currentVM.skip) {
+ lastDrawnIndex = index;
+ ctx.lineTo(currentVM.x, currentVM.y);
}
} else {
- me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
- if (me._loop) {
- // Go to center
- ctx.lineTo(me._view.scaleZero.x, me._view.scaleZero.y);
+ previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
+
+ if (currentVM.skip) {
+ // Only do this if this is the first point that is skipped
+ if (!spanGaps && lastDrawnIndex === (index - 1)) {
+ if (loop) {
+ ctx.lineTo(scaleZero.x, scaleZero.y);
+ } else {
+ ctx.lineTo(previous._view.x, scaleZero);
+ }
+ }
+ } else {
+ if (lastDrawnIndex !== (index - 1)) {
+ // There was a gap and this is the first point after the gap. If we've never drawn a point, this is a special case.
+ // If the first data point is NaN, then there is no real gap to skip
+ if (spanGaps && lastDrawnIndex !== -1) {
+ // We are spanning the gap, so simple draw a line to this point
+ lineToPoint(previous, current)
+ } else {
+ if (loop) {
+ ctx.lineTo(currentVM.x, currentVM.y);
+ } else {
+ ctx.lineTo(currentVM.x, scaleZero);
+ ctx.lineTo(currentVM.x, currentVM.y);
+ }
+ }
} else {
- ctx.lineTo(previousPoint._view.x, me._view.scaleZero);
- ctx.moveTo(nextPoint._view.x, me._view.scaleZero);
+ // Line to next point
+ lineToPoint(previous, current);
}
- }, function(previousPoint, point) {
- // 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);
- });
+ lastDrawnIndex = index;
+ }
}
- }, me);
+ }
- // For radial scales, loop back around to the first point
- if (me._loop) {
- loopBackToStart(true);
- } else {
- //Round off the line by going to the base of the chart, back to the start, then fill.
- ctx.lineTo(me._children[me._children.length - 1]._view.x, vm.scaleZero);
- ctx.lineTo(me._children[0]._view.x, vm.scaleZero);
+ if (!loop) {
+ ctx.lineTo(points[points.length - 1]._view.x, scaleZero);
}
ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
ctx.fill();
}
+ // Stroke Line Options
var globalOptionLineElements = globalDefaults.elements.line;
- // Now draw the line between all the points with any borders
ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;
// IE 9 and 10 do not support line dash
ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;
ctx.lineWidth = vm.borderWidth || globalOptionLineElements.borderWidth;
ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;
+
+ // Stroke Line
ctx.beginPath();
+ lastDrawnIndex = -1;
- helpers.each(me._children, function(point, index) {
- var previous = helpers.previousItem(me._children, index);
- var next = helpers.nextItem(me._children, index);
+ for (var index = 0; index < points.length; ++index) {
+ var current = points[index];
+ var previous = helpers.previousItem(points, index);
+ var currentVM = current._view;
+ // First point moves to it's starting position no matter what
if (index === 0) {
- ctx.moveTo(point._view.x, point._view.y);
+ if (currentVM.skip) {
+
+ } else {
+ ctx.moveTo(currentVM.x, currentVM.y);
+ lastDrawnIndex = index;
+ }
} else {
- me.lineToNextPoint(previous, point, next, function(previousPoint, point, nextPoint) {
- ctx.moveTo(nextPoint._view.x, nextPoint._view.y);
- }, function(previousPoint, point) {
- // 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);
- });
- }
- }, me);
+ previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
- if (me._loop && me._children.length > 0) {
- loopBackToStart();
+ if (!currentVM.skip) {
+ if (lastDrawnIndex !== (index - 1) && !spanGaps) {
+ // There was a gap and this is the first point after the gap
+ ctx.moveTo(currentVM.x, currentVM.y);
+ } else {
+ // Line to next point
+ lineToPoint(previous, current);
+ }
+ lastDrawnIndex = index;
+ }
+ }
}
ctx.stroke();
}]);
});
+ it('should draw with straight lines for a tension of 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: 0,
+ controlPointNextY: 10,
+ tension: 0
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 1,
+ _view: {
+ x: 5,
+ y: 0,
+ controlPointPreviousX: 5,
+ controlPointPreviousY: 0,
+ controlPointNextX: 5,
+ controlPointNextY: 0,
+ tension: 0
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 2,
+ _view: {
+ x: 15,
+ y: -10,
+ controlPointPreviousX: 15,
+ controlPointPreviousY: -10,
+ controlPointNextX: 15,
+ controlPointNextY: -10,
+ tension: 0
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 3,
+ _view: {
+ x: 19,
+ y: -5,
+ controlPointPreviousX: 19,
+ controlPointPreviousY: -5,
+ controlPointNextX: 19,
+ controlPointNextY: -5,
+ tension: 0
+ }
+ }));
+
+ var line = new Chart.elements.Line({
+ _datasetindex: 2,
+ _chart: {
+ ctx: mockContext,
+ },
+ _children: points,
+ // Need to provide some settings
+ _view: {
+ fill: false, // don't want to fill
+ tension: 0.0, // no bezier curve for now
+ scaleZero: 0
+ }
+ });
+
+ line.draw();
+
+ expect(mockContext.getCalls()).toEqual([{
+ name: 'save',
+ 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: 'lineTo',
+ args: [5, 0]
+ }, {
+ name: 'lineTo',
+ args: [15, -10]
+ }, {
+ name: 'lineTo',
+ args: [19, -5]
+ }, {
+ name: 'stroke',
+ args: [],
+ }, {
+ name: 'restore',
+ args: []
+ }]);
+ });
+
+ it('should draw stepped lines', 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,
+ steppedLine: true
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 1,
+ _view: {
+ x: 5,
+ y: 0,
+ controlPointPreviousX: 5,
+ controlPointPreviousY: 0,
+ controlPointNextX: 5,
+ controlPointNextY: 0,
+ steppedLine: true
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 2,
+ _view: {
+ x: 15,
+ y: -10,
+ controlPointPreviousX: 15,
+ controlPointPreviousY: -10,
+ controlPointNextX: 15,
+ controlPointNextY: -10,
+ steppedLine: true
+ }
+ }));
+ points.push(new Chart.elements.Point({
+ _datasetindex: 2,
+ _index: 3,
+ _view: {
+ x: 19,
+ y: -5,
+ controlPointPreviousX: 19,
+ controlPointPreviousY: -5,
+ controlPointNextX: 19,
+ controlPointNextY: -5,
+ steppedLine: true
+ }
+ }));
+
+ var line = new Chart.elements.Line({
+ _datasetindex: 2,
+ _chart: {
+ ctx: mockContext,
+ },
+ _children: points,
+ // Need to provide some settings
+ _view: {
+ fill: false, // don't want to fill
+ tension: 0.0, // no bezier curve for now
+ scaleZero: 0
+ }
+ });
+
+ line.draw();
+
+ expect(mockContext.getCalls()).toEqual([{
+ name: 'save',
+ 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: 'lineTo',
+ args: [5, 10]
+ }, {
+ name: 'lineTo',
+ args: [5, 0]
+ }, {
+ name: 'lineTo',
+ args: [15, 0]
+ }, {
+ name: 'lineTo',
+ args: [15, -10]
+ }, {
+ name: 'lineTo',
+ args: [19, -10]
+ }, {
+ name: 'lineTo',
+ args: [19, -5]
+ }, {
+ name: 'stroke',
+ args: [],
+ }, {
+ name: 'restore',
+ args: []
+ }]);
+ });
+
it('should draw with custom settings', function() {
var mockContext = window.createMockContext();
x: 0,
y: 10,
controlPointNextX: 0,
- controlPointNextY: 10
+ 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
+ }
+ }));
+
+ 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
+
+ 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: 'beginPath',
+ args: []
+ }, {
+ name: 'moveTo',
+ args: [0, 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: 'lineTo',
+ args: [19, 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, 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: 'stroke',
+ args: []
+ }, {
+ name: 'restore',
+ args: []
+ }];
+ 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: 'lineTo',
+ args: [19, 2]
+ }, {
+ name: 'lineTo',
+ args: [19, -5]
+ }, {
+ name: 'lineTo',
+ args: [19, 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]
+ }, {
+ 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: 'stroke',
+ args: []
+ }, {
+ name: 'restore',
+ args: []
+ }];
+ expect(mockContext.getCalls()).toEqual(expected);
+ });
+
+ it('should skip points correctly when spanGaps is true', 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
+ spanGaps: true
+ }
+ });
+
+ 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: 'bezierCurveTo',
+ args: [5, 0, 19, -5, 19, -5]
+ }, {
+ name: 'lineTo',
+ args: [19, 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]
+ }, {
+ 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, 19, -5, 19, -5]
+ }, {
+ name: 'stroke',
+ args: []
+ }, {
+ name: 'restore',
+ args: []
+ }];
+ expect(mockContext.getCalls()).toEqual(expected);
+ });
+
+ it('should skip the first point 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,
+ skip: true
}
}));
points.push(new Chart.elements.Point({
fill: true,
scaleZero: 2, // for filling lines
tension: 0.0, // no bezier curve for now
-
- borderCapStyle: 'round',
- borderColor: 'rgb(255, 255, 0)',
- borderDash: [2, 2],
- borderDashOffset: 1.5,
- borderJoinStyle: 'bevel',
- borderWidth: 4,
- backgroundColor: 'rgb(0, 0, 0)'
}
});
var expected = [{
name: 'save',
- args: [],
+ args: []
}, {
name: 'beginPath',
args: []
args: [0, 2]
}, {
name: 'lineTo',
- args: [0, 10]
+ args: [5, 2]
}, {
- 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: [19, 2]
- }, {
- name: 'lineTo',
- args: [0, 2]
}, {
name: 'setFillStyle',
- args: ['rgb(0, 0, 0)']
+ args: ['rgba(0,0,0,0.1)']
}, {
name: 'closePath',
args: []
args: []
}, {
name: 'setLineCap',
- args: ['round']
+ args: ['butt']
}, {
name: 'setLineDash',
args: [
- [2, 2]
+ []
]
}, {
name: 'setLineDashOffset',
- args: [1.5]
+ args: [0]
}, {
name: 'setLineJoin',
- args: ['bevel']
+ args: ['miter']
}, {
name: 'setLineWidth',
- args: [4]
+ args: [3]
}, {
name: 'setStrokeStyle',
- args: ['rgb(255, 255, 0)']
+ args: ['rgba(0,0,0,0.1)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
- args: [0, 10]
- }, {
- name: 'bezierCurveTo',
- args: [0, 10, 5, 0, 5, 0]
+ args: [5, 0]
}, {
name: 'bezierCurveTo',
args: [5, 0, 15, -10, 15, -10]
args: [15, -10, 19, -5, 19, -5]
}, {
name: 'stroke',
- args: [],
+ args: []
}, {
name: 'restore',
args: []
expect(mockContext.getCalls()).toEqual(expected);
});
- it ('should skip points correctly', function() {
+ it('should skip the last point correctly', function() {
var mockContext = window.createMockContext();
// Create our points
controlPointPreviousX: 15,
controlPointPreviousY: -10,
controlPointNextX: 15,
- controlPointNextY: -10,
- skip: true
+ controlPointNextY: -10
}
}));
points.push(new Chart.elements.Point({
controlPointPreviousX: 19,
controlPointPreviousY: -5,
controlPointNextX: 19,
- controlPointNextY: -5
+ controlPointNextY: -5,
+ skip: true
}
}));
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: 'bezierCurveTo',
+ args: [5, 0, 15, -10, 15, -10]
}, {
- name: 'lineTo',
- args: [19, 2]
+ name: 'lineTo',
+ args: [15, 2]
}, {
name: 'lineTo',
- args: [0, 2]
+ args: [19, 2]
}, {
name: 'setFillStyle',
args: ['rgba(0,0,0,0.1)']
]
}, {
name: 'setLineDashOffset',
- args: [0.0]
+ args: [0]
}, {
name: 'setLineJoin',
args: ['miter']
name: 'bezierCurveTo',
args: [0, 10, 5, 0, 5, 0]
}, {
- name: 'moveTo',
- args: [19, -5]
- }, {
- name: 'moveTo',
- args: [19, -5]
+ name: 'bezierCurveTo',
+ args: [5, 0, 15, -10, 15, -10]
}, {
name: 'stroke',
- args: [],
+ args: []
}, {
name: 'restore',
args: []
}, {
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 span gaps is true and 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
+ },
+ spanGaps: true
+ }
+ });
+
+ line.draw();
+
+ expect(mockContext.getCalls()).toEqual([{
+ name: 'save',
+ args: [],
+ }, {
+ name: 'beginPath',
+ args: []
}, {
name: 'moveTo',
- args: [15, -10]
+ args: [3, 2]
+ }, {
+ name: 'lineTo',
+ args: [0, 10]
+ }, {
+ name: 'bezierCurveTo',
+ args: [0, 10, 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']
+ }, {
+ 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, 15, -10, 15, -10]
}, {
name: 'bezierCurveTo',
args: [15, -10, 19, -5, 19, -5]
}, {
name: 'beginPath',
args: []
- }, {
- name: 'moveTo',
- args: [0, 10]
}, {
name: 'moveTo',
args: [5, 0]
args: [3, 2]
}, {
name: 'lineTo',
- args: [3, 2]
+ args: [0, 10]
}, {
name: 'setFillStyle',
args: ['rgba(0,0,0,0.1)']
args: [5, 0, 15, -10, 15, -10]
}, {
name: 'moveTo',
- args: [19, -5]
+ args: [0, 10]
}, {
name: 'stroke',
args: [],
args: []
}]);
});
-});
+});
\ No newline at end of file