From: Jukka Kurkela Date: Mon, 13 Sep 2021 20:31:34 +0000 (+0300) Subject: Fix segment styling with gaps (#9644) X-Git-Tag: v3.6.0~32 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=183a1a9f674fd0d0694446cc1431e62215fcb3b7;p=thirdparty%2FChart.js.git Fix segment styling with gaps (#9644) --- diff --git a/docs/charts/line.md b/docs/charts/line.md index fd674a519..fc245fcb0 100644 --- a/docs/charts/line.md +++ b/docs/charts/line.md @@ -163,6 +163,10 @@ If left untouched (`undefined`), the global `options.elements.line.cubicInterpol Line segment styles can be overridden by scriptable options in the `segment` object. Currently all of the `border*` and `backgroundColor` options are supported. The segment styles are resolved for each section of the line between each point. `undefined` fallbacks to main line styles. +:::tip +To be able to style gaps, you need the [`spanGaps`](#line-styling) option enabled. +::: + Context for the scriptable segment contains the following properties: * `type`: `'segment'` diff --git a/docs/samples/line/segments.md b/docs/samples/line/segments.md index b1b6a8735..287730cfe 100644 --- a/docs/samples/line/segments.md +++ b/docs/samples/line/segments.md @@ -29,7 +29,8 @@ const config = { segment: { borderColor: ctx => skipped(ctx, 'rgb(0,0,0,0.2)') || down(ctx, 'rgb(192,75,75)'), borderDash: ctx => skipped(ctx, [6, 6]), - } + }, + spanGaps: true }] }, options: genericOptions diff --git a/src/elements/element.line.js b/src/elements/element.line.js index 55752c6c1..87eb9f583 100644 --- a/src/elements/element.line.js +++ b/src/elements/element.line.js @@ -230,7 +230,7 @@ function strokePathDirect(ctx, line, start, count) { const usePath2D = typeof Path2D === 'function'; function draw(ctx, line, start, count) { - if (usePath2D && line.segments.length === 1) { + if (usePath2D && !line.options.segment) { strokePathWithCache(ctx, line, start, count); } else { strokePathDirect(ctx, line, start, count); diff --git a/src/helpers/helpers.segment.js b/src/helpers/helpers.segment.js index dd9f4da9f..8106c0629 100644 --- a/src/helpers/helpers.segment.js +++ b/src/helpers/helpers.segment.js @@ -276,12 +276,35 @@ function splitByStyles(line, segments, points, segmentOptions) { */ function doSplitByStyles(line, segments, points, segmentOptions) { const baseStyle = readStyle(line.options); + const {_datasetIndex: datasetIndex, options: {spanGaps}} = line; const count = points.length; const result = []; + let prevStyle = baseStyle; let start = segments[0].start; let i = start; + + function addStyle(s, e, l, st) { + const dir = spanGaps ? -1 : 1; + if (s === e) { + return; + } + // Style can not start/end on a skipped point, adjust indices accordingly + s += count; + while (points[s % count].skip) { + s -= dir; + } + while (points[e % count].skip) { + e += dir; + } + if (s % count !== e % count) { + result.push({start: s % count, end: e % count, loop: l, style: st}); + prevStyle = st; + start = e % count; + } + } + for (const segment of segments) { - let prevStyle = baseStyle; + start = spanGaps ? start : segment.start; let prev = points[start % count]; let style; for (i = start + 1; i <= segment.end; i++) { @@ -292,19 +315,16 @@ function doSplitByStyles(line, segments, points, segmentOptions) { p1: pt, p0DataIndex: (i - 1) % count, p1DataIndex: i % count, - datasetIndex: line._datasetIndex + datasetIndex })); if (styleChanged(style, prevStyle)) { - result.push({start: start, end: i - 1, loop: segment.loop, style: prevStyle}); - prevStyle = style; - start = i - 1; + addStyle(start, i - 1, segment.loop, prevStyle); } prev = pt; prevStyle = style; } if (start < i - 1) { - result.push({start, end: i - 1, loop: segment.loop, style}); - start = i - 1; + addStyle(start, i - 1, segment.loop, prevStyle); } } diff --git a/test/fixtures/controller.line/segments/gap.js b/test/fixtures/controller.line/segments/gap.js index fd08a4d55..db0652caa 100644 --- a/test/fixtures/controller.line/segments/gap.js +++ b/test/fixtures/controller.line/segments/gap.js @@ -9,7 +9,8 @@ module.exports = { segment: { borderColor: ctx => ctx.p0.skip || ctx.p1.skip ? 'red' : undefined, borderDash: ctx => ctx.p0.skip || ctx.p1.skip ? [5, 5] : undefined - } + }, + spanGaps: true }] }, options: { diff --git a/test/fixtures/controller.line/segments/spanGaps.js b/test/fixtures/controller.line/segments/spanGaps.js new file mode 100644 index 000000000..816d5bec8 --- /dev/null +++ b/test/fixtures/controller.line/segments/spanGaps.js @@ -0,0 +1,31 @@ +module.exports = { + config: { + type: 'line', + data: { + labels: ['a', 'b', 'c', 'd', 'e', 'f'], + datasets: [{ + data: [1, 3, null, null, 2, 1], + segment: { + borderColor: ctx => ctx.p1.parsed.x > 2 ? 'red' : undefined, + borderDash: ctx => ctx.p1.parsed.x > 3 ? [6, 6] : undefined, + }, + spanGaps: true + }, { + data: [0, 2, null, null, 1, 0], + segment: { + borderColor: ctx => ctx.p1.parsed.x > 2 ? 'red' : undefined, + borderDash: ctx => ctx.p1.parsed.x > 3 ? [6, 6] : undefined, + }, + spanGaps: false + }] + }, + options: { + borderColor: 'black', + radius: 0, + scales: { + x: {display: false}, + y: {display: false} + } + } + } +}; diff --git a/test/fixtures/controller.line/segments/spanGaps.png b/test/fixtures/controller.line/segments/spanGaps.png new file mode 100644 index 000000000..90b964a64 Binary files /dev/null and b/test/fixtures/controller.line/segments/spanGaps.png differ diff --git a/test/fixtures/plugin.filler/line/segments/gap.js b/test/fixtures/plugin.filler/line/segments/gap.js index 6dfb83156..1038a0b11 100644 --- a/test/fixtures/plugin.filler/line/segments/gap.js +++ b/test/fixtures/plugin.filler/line/segments/gap.js @@ -10,7 +10,8 @@ module.exports = { fill: true, segment: { backgroundColor: ctx => ctx.p0.skip || ctx.p1.skip ? 'red' : undefined, - } + }, + spanGaps: true }] }, options: {