Skip to content

Commit 1e3d6e5

Browse files
authored
Bugfix: span gaps over null values beyond scale limits (#11984)
* Bugfix: spanGaps not working near min and max limits * Fix error when meta.dataset.options = null * Add tests for correct setting of line controller properties _drawStart and _drawCount * Fix spacing in controller line tests * Add tension to test * Add a better test case * Avoid the use of FindLastIndex * Avoid taking 0 for null value and improve naming
1 parent 57b5c5b commit 1e3d6e5

File tree

2 files changed

+110
-7
lines changed

2 files changed

+110
-7
lines changed

src/helpers/helpers.extras.ts

+23-7
Original file line numberDiff line numberDiff line change
@@ -91,25 +91,41 @@ export function _getStartAndCountOfVisiblePoints(meta: ChartMeta<'line' | 'scatt
9191
let count = pointCount;
9292

9393
if (meta._sorted) {
94-
const {iScale, _parsed} = meta;
94+
const {iScale, vScale, _parsed} = meta;
95+
const spanGaps = meta.dataset ? meta.dataset.options ? meta.dataset.options.spanGaps : null : null;
9596
const axis = iScale.axis;
9697
const {min, max, minDefined, maxDefined} = iScale.getUserBounds();
9798

9899
if (minDefined) {
99-
start = _limitValue(Math.min(
100+
start = Math.min(
100101
// @ts-expect-error Need to type _parsed
101102
_lookupByKey(_parsed, axis, min).lo,
102103
// @ts-expect-error Need to fix types on _lookupByKey
103-
animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo),
104-
0, pointCount - 1);
104+
animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo);
105+
if (spanGaps) {
106+
const distanceToDefinedLo = (_parsed
107+
.slice(0, start + 1)
108+
.reverse()
109+
.findIndex(
110+
point => point[vScale.axis] || point[vScale.axis] === 0));
111+
start -= Math.max(0, distanceToDefinedLo);
112+
}
113+
start = _limitValue(start, 0, pointCount - 1);
105114
}
106115
if (maxDefined) {
107-
count = _limitValue(Math.max(
116+
let end = Math.max(
108117
// @ts-expect-error Need to type _parsed
109118
_lookupByKey(_parsed, iScale.axis, max, true).hi + 1,
110119
// @ts-expect-error Need to fix types on _lookupByKey
111-
animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1),
112-
start, pointCount) - start;
120+
animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max), true).hi + 1);
121+
if (spanGaps) {
122+
const distanceToDefinedHi = (_parsed
123+
.slice(end - 1)
124+
.findIndex(
125+
point => point[vScale.axis] || point[vScale.axis] === 0));
126+
end += Math.max(0, distanceToDefinedHi);
127+
}
128+
count = _limitValue(end, start, pointCount) - start;
113129
} else {
114130
count = pointCount - start;
115131
}

test/specs/controller.line.tests.js

+87
Original file line numberDiff line numberDiff line change
@@ -1071,6 +1071,93 @@ describe('Chart.controllers.line', function() {
10711071
expect(visiblePoints.length).toBe(6);
10721072
}, 500);
10731073

1074+
it('should correctly calc _drawStart and _drawCount when first points beyond scale limits are null and spanGaps=true', async() => {
1075+
var chart = window.acquireChart({
1076+
type: 'line',
1077+
data: {
1078+
labels: [0, 10, 20, 30, 40, 50],
1079+
datasets: [{
1080+
data: [3, null, 2, 3, null, 1.5],
1081+
spanGaps: true,
1082+
tension: 0.4
1083+
}]
1084+
},
1085+
options: {
1086+
scales: {
1087+
x: {
1088+
type: 'linear',
1089+
min: 11,
1090+
max: 40,
1091+
}
1092+
}
1093+
}
1094+
});
1095+
1096+
chart.update();
1097+
var controller = chart.getDatasetMeta(0).controller;
1098+
1099+
expect(controller._drawStart).toBe(0);
1100+
expect(controller._drawCount).toBe(6);
1101+
}, 500);
1102+
1103+
it('should correctly calc _drawStart and _drawCount when all points beyond scale limits are null and spanGaps=true', async() => {
1104+
var chart = window.acquireChart({
1105+
type: 'line',
1106+
data: {
1107+
labels: [0, 10, 20, 30, 40, 50],
1108+
datasets: [{
1109+
data: [null, null, 2, 3, null, null],
1110+
spanGaps: true,
1111+
tension: 0.4
1112+
}]
1113+
},
1114+
options: {
1115+
scales: {
1116+
x: {
1117+
type: 'linear',
1118+
min: 11,
1119+
max: 40,
1120+
}
1121+
}
1122+
}
1123+
});
1124+
1125+
chart.update();
1126+
var controller = chart.getDatasetMeta(0).controller;
1127+
1128+
expect(controller._drawStart).toBe(1);
1129+
expect(controller._drawCount).toBe(4);
1130+
}, 500);
1131+
1132+
it('should correctly calc _drawStart and _drawCount when spanGaps=false', async() => {
1133+
var chart = window.acquireChart({
1134+
type: 'line',
1135+
data: {
1136+
labels: [0, 10, 20, 30, 40, 50],
1137+
datasets: [{
1138+
data: [3, null, 2, 3, null, 1.5],
1139+
spanGaps: false,
1140+
tension: 0.4
1141+
}]
1142+
},
1143+
options: {
1144+
scales: {
1145+
x: {
1146+
type: 'linear',
1147+
min: 11,
1148+
max: 40,
1149+
}
1150+
}
1151+
}
1152+
});
1153+
1154+
chart.update();
1155+
var controller = chart.getDatasetMeta(0).controller;
1156+
1157+
expect(controller._drawStart).toBe(1);
1158+
expect(controller._drawCount).toBe(4);
1159+
}, 500);
1160+
10741161
it('should not override tooltip title and label callbacks', async() => {
10751162
const chart = window.acquireChart({
10761163
type: 'line',

0 commit comments

Comments
 (0)