Refactoring of the line drawing function to make spanGaps work correctly. Added a lot more test conditions to the line element tests. Ensured that the line controller correctly calculated bezier control points when there was a point to be skipped

This commit is contained in:
Evert Timberg 2016-07-24 18:12:36 -04:00
parent e94d3c0730
commit 2016630daa
3 changed files with 951 additions and 128 deletions

View File

@ -247,7 +247,9 @@ module.exports = function(Chart) {
var me = this;
var meta = me.getMeta();
var area = me.chart.chartArea;
var points = meta.data || [];
// only consider points that are drawn in case the spanGaps option is ued
var points = (meta.data || []).filter(function(pt) { return !pt._model.skip; });
var i, ilen, point, model, controlPoints;
var needToCap = me.chart.options.elements.line.capBezierPoints;

View File

@ -19,107 +19,104 @@ module.exports = function(Chart) {
};
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 ctx = me._chart.ctx;
var first = me._children[0];
var last = me._children[me._children.length - 1];
var spanGaps = vm.spanGaps;
var scaleZero = vm.scaleZero;
var loop = me._loop;
function loopBackToStart(drawLineToCenter) {
if (!first._view.skip && !last._view.skip) {
// Draw a bezier line from last to first
var ctx = me._chart.ctx;
ctx.save();
// 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 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)
// If we are looping, adding the first point again
if (loop && points.length) {
points.push(points[0]);
}
// 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);
} else {
ctx.lineTo(previousPoint._view.x, me._view.scaleZero);
ctx.moveTo(nextPoint._view.x, me._view.scaleZero);
}
}, 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);
});
}
}, me);
previous = lastDrawnIndex === -1 ? previous : points[lastDrawnIndex];
// 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 (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 {
// Line to next point
lineToPoint(previous, current);
}
lastDrawnIndex = index;
}
}
}
if (!loop) {
ctx.lineTo(points[points.length - 1]._view.x, scaleZero);
}
ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
@ -127,8 +124,8 @@ module.exports = function(Chart) {
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
@ -140,26 +137,38 @@ module.exports = function(Chart) {
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();

View File

@ -126,6 +126,253 @@ describe('Line element tests', function() {
}]);
});
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();
@ -204,7 +451,7 @@ describe('Line element tests', function() {
var expected = [{
name: 'save',
args: [],
args: []
}, {
name: 'beginPath',
args: []
@ -226,9 +473,6 @@ describe('Line element tests', function() {
}, {
name: 'lineTo',
args: [19, 2]
}, {
name: 'lineTo',
args: [0, 2]
}, {
name: 'setFillStyle',
args: ['rgb(0, 0, 0)']
@ -275,7 +519,7 @@ describe('Line element tests', function() {
args: [15, -10, 19, -5, 19, -5]
}, {
name: 'stroke',
args: [],
args: []
}, {
name: 'restore',
args: []
@ -283,7 +527,7 @@ describe('Line element tests', function() {
expect(mockContext.getCalls()).toEqual(expected);
});
it ('should skip points correctly', function() {
it('should skip points correctly', function() {
var mockContext = window.createMockContext();
// Create our points
@ -368,20 +612,17 @@ describe('Line element tests', function() {
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: [5, 2]
}, {
name: 'lineTo',
args: [0, 2]
args: [19, 2]
}, {
name: 'lineTo',
args: [19, -5]
}, {
name: 'lineTo',
args: [19, 2]
}, {
name: 'setFillStyle',
args: ['rgba(0,0,0,0.1)']
@ -401,7 +642,7 @@ describe('Line element tests', function() {
]
}, {
name: 'setLineDashOffset',
args: [0.0]
args: [0]
}, {
name: 'setLineJoin',
args: ['miter']
@ -421,14 +662,441 @@ describe('Line element tests', function() {
name: 'bezierCurveTo',
args: [0, 10, 5, 0, 5, 0]
}, {
name: 'moveTo',
args: [19, -5]
}, {
name: 'moveTo',
args: [19, -5]
name: 'moveTo',
args: [19, -5]
}, {
name: 'stroke',
args: [],
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({
_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
}
});
line.draw();
var expected = [{
name: 'save',
args: []
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [0, 2]
}, {
name: 'lineTo',
args: [5, 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: [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: [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 the last 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
}
}));
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,
// 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: 'bezierCurveTo',
args: [5, 0, 15, -10, 15, -10]
}, {
name: 'lineTo',
args: [15, 2]
}, {
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, 15, -10, 15, -10]
}, {
name: 'stroke',
args: []
}, {
name: 'restore',
args: []
@ -727,9 +1395,156 @@ describe('Line element tests', function() {
}, {
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]
@ -873,9 +1688,6 @@ describe('Line element tests', function() {
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [0, 10]
}, {
name: 'moveTo',
args: [5, 0]
@ -992,7 +1804,7 @@ describe('Line element tests', function() {
args: [3, 2]
}, {
name: 'lineTo',
args: [3, 2]
args: [0, 10]
}, {
name: 'setFillStyle',
args: ['rgba(0,0,0,0.1)']
@ -1036,7 +1848,7 @@ describe('Line element tests', function() {
args: [5, 0, 15, -10, 15, -10]
}, {
name: 'moveTo',
args: [19, -5]
args: [0, 10]
}, {
name: 'stroke',
args: [],
@ -1045,4 +1857,4 @@ describe('Line element tests', function() {
args: []
}]);
});
});
});