]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Allow specifying spanGaps as number (max distance) (#6993)
authorJukka Kurkela <jukka.kurkela@gmail.com>
Tue, 21 Jan 2020 23:33:27 +0000 (01:33 +0200)
committerEvert Timberg <evert.timberg+github@gmail.com>
Tue, 21 Jan 2020 23:33:27 +0000 (18:33 -0500)
docs/charts/line.md
samples/samples.js
samples/scales/time/line-max-span.html [new file with mode: 0644]
src/controllers/controller.line.js
src/helpers/helpers.segment.js

index 77fc1356e3e1572ac5c7c479c849fa4d998a5dca..12b8838c642ae14c07f5a2804f9f303315f68652 100644 (file)
@@ -77,7 +77,7 @@ The line chart allows a number of properties to be specified for each dataset. T
 | [`pointRotation`](#point-styling) | `number` | Yes | Yes | `0`
 | [`pointStyle`](#point-styling) | <code>string&#124;Image</code> | Yes | Yes | `'circle'`
 | [`showLine`](#line-styling) | `boolean` | - | - | `undefined`
-| [`spanGaps`](#line-styling) | `boolean` | - | - | `undefined`
+| [`spanGaps`](#line-styling) | <code>boolean&#124;number</code> | - | - | `undefined`
 | [`steppedLine`](#stepped-line) | <code>boolean&#124;string</code> | - | - | `false`
 | [`xAxisID`](#general) | `string` | - | - | first x axis
 | [`yAxisID`](#general) | `string` | - | - | first y axis
@@ -124,7 +124,7 @@ The style of the line can be controlled with the following properties:
 | `fill` | How to fill the area under the line. See [area charts](area.md).
 | `lineTension` | Bezier curve tension of the line. Set to 0 to draw straightlines. This option is ignored if monotone cubic interpolation is used.
 | `showLine` | If false, the line is not drawn for this dataset.
-| `spanGaps` | If true, lines will be drawn between points with no or null data. If false, points with `NaN` data will create a break in the line.
+| `spanGaps` | If true, lines will be drawn between points with no or null data. If false, points with `NaN` data will create a break in the line. Can also be a number specifying the maximum gap length to span. The unit of the value depends on the scale used.
 
 If the value is `undefined`, `showLine` and `spanGaps` fallback to the associated [chart configuration options](#configuration-options). The rest of the values fallback to the associated [`elements.line.*`](../configuration/elements.md#line-configuration) options.
 
index 53084d5475494789f8fcbbb9bd395679aa8be435..518b7696c5c936c662479d6a0a5a869f91b824b3 100644 (file)
                }, {
                        title: 'Line (point data)',
                        path: 'scales/time/line-point-data.html'
+               }, {
+                       title: 'Line (break on 2 day gap)',
+                       path: 'scales/time/line-max-span.html'
                }, {
                        title: 'Time Series',
                        path: 'scales/time/financial.html'
diff --git a/samples/scales/time/line-max-span.html b/samples/scales/time/line-max-span.html
new file mode 100644 (file)
index 0000000..64c0038
--- /dev/null
@@ -0,0 +1,150 @@
+<!doctype html>
+<html>
+
+<head>
+       <title>Time Scale Point Data</title>
+       <script src="https://cdn.jsdelivr.net/npm/moment@2.24.0/moment.min.js"></script>
+       <script src="../../../dist/Chart.min.js"></script>
+       <script src="../../utils.js"></script>
+       <style>
+               canvas {
+                       -moz-user-select: none;
+                       -webkit-user-select: none;
+                       -ms-user-select: none;
+               }
+       </style>
+</head>
+
+<body>
+       <div style="width:75%;">
+               <canvas id="canvas"></canvas>
+       </div>
+       <br>
+       <br>
+       <button id="randomizeData">Randomize Data</button>
+       <button id="addData">Add Data</button>
+       <button id="removeData">Remove Data</button>
+       <script>
+               function newDate(days) {
+                       return moment().add(days, 'd').toDate();
+               }
+
+               function newDateString(days) {
+                       return moment().add(days, 'd').format();
+               }
+
+               var color = Chart.helpers.color;
+               var config = {
+                       type: 'line',
+                       data: {
+                               datasets: [{
+                                       label: 'Dataset with string point data',
+                                       backgroundColor: color(window.chartColors.red).alpha(0.5).rgbString(),
+                                       borderColor: window.chartColors.red,
+                                       fill: false,
+                                       data: [{
+                                               x: newDateString(0),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDateString(2),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDateString(4),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDateString(6),
+                                               y: randomScalingFactor()
+                                       }],
+                               }, {
+                                       label: 'Dataset with date object point data',
+                                       backgroundColor: color(window.chartColors.blue).alpha(0.5).rgbString(),
+                                       borderColor: window.chartColors.blue,
+                                       fill: false,
+                                       data: [{
+                                               x: newDate(0),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDate(2),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDate(5),
+                                               y: randomScalingFactor()
+                                       }, {
+                                               x: newDate(6),
+                                               y: randomScalingFactor()
+                                       }]
+                               }]
+                       },
+                       options: {
+                               spanGaps: 1000 * 60 * 60 * 24 * 2, // 2 days
+                               responsive: true,
+                               title: {
+                                       display: true,
+                                       text: 'Chart.js Time - spanGaps: 172800000 (2 days in ms)'
+                               },
+                               scales: {
+                                       x: {
+                                               type: 'time',
+                                               display: true,
+                                               scaleLabel: {
+                                                       display: true,
+                                                       labelString: 'Date'
+                                               },
+                                               ticks: {
+                                                       major: {
+                                                               fontStyle: 'bold',
+                                                               fontColor: '#FF0000'
+                                                       }
+                                               }
+                                       },
+                                       y: {
+                                               display: true,
+                                               scaleLabel: {
+                                                       display: true,
+                                                       labelString: 'value'
+                                               }
+                                       }
+                               }
+                       }
+               };
+
+               window.onload = function() {
+                       var ctx = document.getElementById('canvas').getContext('2d');
+                       window.myLine = new Chart(ctx, config);
+               };
+
+               document.getElementById('randomizeData').addEventListener('click', function() {
+                       config.data.datasets.forEach(function(dataset) {
+                               dataset.data.forEach(function(dataObj) {
+                                       dataObj.y = randomScalingFactor();
+                               });
+                       });
+
+                       window.myLine.update();
+               });
+               document.getElementById('addData').addEventListener('click', function() {
+                       if (config.data.datasets.length > 0) {
+                               config.data.datasets[0].data.push({
+                                       x: newDateString(config.data.datasets[0].data.length + 2),
+                                       y: randomScalingFactor()
+                               });
+                               config.data.datasets[1].data.push({
+                                       x: newDate(config.data.datasets[1].data.length + 2),
+                                       y: randomScalingFactor()
+                               });
+
+                               window.myLine.update();
+                       }
+               });
+
+               document.getElementById('removeData').addEventListener('click', function() {
+                       config.data.datasets.forEach(function(dataset) {
+                               dataset.data.pop();
+                       });
+
+                       window.myLine.update();
+               });
+       </script>
+</body>
+
+</html>
index ddb4aa0d785a6056612dbf1350907d425498e17e..32e069a77944629052748d2fdecdac7a9e536575 100644 (file)
@@ -98,6 +98,9 @@ export default DatasetController.extend({
                const firstOpts = me._resolveDataElementOptions(start, mode);
                const sharedOptions = me._getSharedOptions(mode, points[start], firstOpts);
                const includeOptions = me._includeOptions(mode, sharedOptions);
+               const spanGaps = valueOrDefault(me._config.spanGaps, me.chart.options.spanGaps);
+               const maxGapLength = helpers.math.isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
+               let prevParsed;
 
                for (let i = 0; i < points.length; ++i) {
                        const index = start + i;
@@ -108,7 +111,8 @@ export default DatasetController.extend({
                        const properties = {
                                x,
                                y,
-                               skip: isNaN(x) || isNaN(y)
+                               skip: isNaN(x) || isNaN(y),
+                               stop: i > 0 && (parsed.x - prevParsed.x) > maxGapLength
                        };
 
                        if (includeOptions) {
@@ -116,6 +120,8 @@ export default DatasetController.extend({
                        }
 
                        me._updateElement(point, index, properties, mode);
+
+                       prevParsed = parsed;
                }
 
                me._updateSharedOptions(sharedOptions, mode);
index bd0099b2fafe62bdbfadcc97ebdcd15423bcbafb..012cb74813618e2432dcf1a4463fae95a550f78c 100644 (file)
@@ -179,11 +179,11 @@ function solidSegments(points, start, max, loop) {
 
        for (end = start + 1; end <= max; ++end) {
                const cur = points[end % count];
-               if (cur.skip) {
+               if (cur.skip || cur.stop) {
                        if (!prev.skip) {
                                loop = false;
                                result.push({start: start % count, end: (end - 1) % count, loop});
-                               start = last = null;
+                               start = last = cur.stop ? end : null;
                        }
                } else {
                        last = end;
@@ -218,7 +218,7 @@ export function _computeSegments(line) {
        const loop = !!line._loop;
        const {start, end} = findStartAndEnd(points, count, loop, spanGaps);
 
-       if (spanGaps) {
+       if (spanGaps === true) {
                return [{start, end, loop}];
        }