mirror of
https://github.com/chartjs/Chart.js.git
synced 2026-03-03 06:54:02 +01:00
New fill modes for lines (#3460)
New fill modes for lines allowing the user to customize where the fill goes to
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -15,7 +15,7 @@ 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({
|
||||
@@ -23,9 +23,18 @@ module.exports = function(Chart) {
|
||||
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();
|
||||
|
||||
@@ -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) {
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user