Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New fill modes for lines #3460

Merged
merged 4 commits into from
Oct 14, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/01-Chart-Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ borderDash | Array | `[]` | Default line dash. See [MDN](https://developer.mozil
borderDashOffset | Number | 0.0 | Default line dash offset. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset)
borderJoinStyle | String | 'miter' | Default line join style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin)
capBezierPoints | Boolean | true | If true, bezier control points are kept inside the chart. If false, no restriction is enforced.
fill | Boolean | true | If true, the line is filled.
fill | Boolean or String | true | If true, the fill is assumed to be to zero. String values are 'zero', 'top', and 'bottom' to fill to different locations. If `false`, no fill is added
stepped | Boolean | false | If true, the line is shown as a stepped line and 'tension' will be ignored

#### Point Configuration
Expand Down
25 changes: 17 additions & 8 deletions src/elements/element.line.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,26 @@ module.exports = function(Chart) {
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
capBezierPoints: true,
fill: true // do we fill in the area between the line and its base axis
fill: true, // do we fill in the area between the line and its base axis
};

Chart.elements.Line = Chart.Element.extend({
draw: function() {
var me = this;
var vm = me._view;
var spanGaps = vm.spanGaps;
var scaleZero = vm.scaleZero;
var fillPoint = vm.scaleZero;
var loop = me._loop;

// Handle different fill modes for cartesian lines
if (!loop) {
if (vm.fill === 'top') {
fillPoint = vm.scaleTop;
} else if (vm.fill === 'bottom') {
fillPoint = vm.scaleBottom;
}
}

var ctx = me._chart.ctx;
ctx.save();

Expand Down Expand Up @@ -71,9 +80,9 @@ module.exports = function(Chart) {
// First point moves to it's starting position no matter what
if (index === 0) {
if (loop) {
ctx.moveTo(scaleZero.x, scaleZero.y);
ctx.moveTo(fillPoint.x, fillPoint.y);
} else {
ctx.moveTo(currentVM.x, scaleZero);
ctx.moveTo(currentVM.x, fillPoint);
}

if (!currentVM.skip) {
Expand All @@ -87,9 +96,9 @@ module.exports = function(Chart) {
// 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);
ctx.lineTo(fillPoint.x, fillPoint.y);
} else {
ctx.lineTo(previous._view.x, scaleZero);
ctx.lineTo(previous._view.x, fillPoint);
}
}
} else {
Expand All @@ -102,7 +111,7 @@ module.exports = function(Chart) {
} else if (loop) {
ctx.lineTo(currentVM.x, currentVM.y);
} else {
ctx.lineTo(currentVM.x, scaleZero);
ctx.lineTo(currentVM.x, fillPoint);
ctx.lineTo(currentVM.x, currentVM.y);
}
} else {
Expand All @@ -115,7 +124,7 @@ module.exports = function(Chart) {
}

if (!loop && lastDrawnIndex !== -1) {
ctx.lineTo(points[lastDrawnIndex]._view.x, scaleZero);
ctx.lineTo(points[lastDrawnIndex]._view.x, fillPoint);
}

ctx.fillStyle = vm.backgroundColor || globalDefaults.defaultColor;
Expand Down
312 changes: 312 additions & 0 deletions test/element.line.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,318 @@ describe('Line element tests', function() {
expect(mockContext.getCalls()).toEqual(expected);
});

it('should draw with fillMode top', 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
}
}));

var line = new Chart.elements.Line({
_datasetindex: 2,
_chart: {
ctx: mockContext,
},
_children: points,
// Need to provide some settings
_view: {
fill: 'top',
scaleZero: 2, // for filling lines
scaleTop: -2,
scaleBottom: 10,
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 draw with fillMode bottom', 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
}
}));

var line = new Chart.elements.Line({
_datasetindex: 2,
_chart: {
ctx: mockContext,
},
_children: points,
// Need to provide some settings
_view: {
fill: 'bottom',
scaleZero: 2, // for filling lines
scaleTop: -2,
scaleBottom: 10,
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, 10]
}, {
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, 10]
}, {
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();

Expand Down