]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
New fill modes for lines (#3460)
authorEvert Timberg <evert.timberg+github@gmail.com>
Fri, 14 Oct 2016 11:19:47 +0000 (06:19 -0500)
committerGitHub <noreply@github.com>
Fri, 14 Oct 2016 11:19:47 +0000 (06:19 -0500)
New fill modes for lines allowing the user to customize where the fill goes to

docs/01-Chart-Configuration.md
src/elements/element.line.js
test/element.line.tests.js

index 1aeaab940fbdd358857b358666a7ed86bc31995e..ef0a5b57f46459a18d2abda890fc66d6fb7b9583 100644 (file)
@@ -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
index d81e7861cd520841e676069a110b2a3454da0176..b63ece78c900d9da1c097e2339bf464350c3afc5 100644 (file)
@@ -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;
index 38a56fe3e97ccd2443cb55ab6ecdca3da3e16f92..0f495c9d1fab29d494998614496994307951f96d 100644 (file)
@@ -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();