Versatile clipping for lines (#6660)

This commit is contained in:
Jukka Kurkela
2019-10-31 23:16:46 +02:00
committed by Evert Timberg
parent ad26311058
commit 201fe46f4a
16 changed files with 362 additions and 6 deletions

View File

@@ -51,6 +51,7 @@ The line chart allows a number of properties to be specified for each dataset. T
| [`borderJoinStyle`](#line-styling) | `string` | Yes | - | `'miter'`
| [`borderWidth`](#line-styling) | `number` | Yes | - | `3`
| [`cubicInterpolationMode`](#cubicinterpolationmode) | `string` | Yes | - | `'default'`
| [`clip`](#line-styling) | <code>number&#124;object</code> | - | - | `borderWidth / 2`
| [`fill`](#line-styling) | <code>boolean&#124;string</code> | Yes | - | `true`
| [`hoverBackgroundColor`](#line-styling) | [`Color`](../general/colors.md) | Yes | - | `undefined`
| [`hoverBorderCapStyle`](#line-styling) | `string` | Yes | - | `undefined`
@@ -117,6 +118,7 @@ The style of the line can be controlled with the following properties:
| `borderDashOffset` | Offset for line dashes. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineDashOffset).
| `borderJoinStyle` | Line joint style. See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/lineJoin).
| `borderWidth` | The line width (in pixels).
| `clip` | How to clip relative to chartArea. Positive value allows overflow, negative value clips that many pixels inside chartArea. `0` = clip at chartArea. Clipping can also be configured per side: `clip: {left: 5, top: false, right: -2, bottom: 0}`
| `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.

View File

@@ -29,6 +29,51 @@ defaults._set('line', {
}
});
function scaleClip(scale, halfBorderWidth) {
var tickOpts = scale && scale.options.ticks || {};
var reverse = tickOpts.reverse;
var min = tickOpts.min === undefined ? halfBorderWidth : 0;
var max = tickOpts.max === undefined ? halfBorderWidth : 0;
return {
start: reverse ? max : min,
end: reverse ? min : max
};
}
function defaultClip(xScale, yScale, borderWidth) {
var halfBorderWidth = borderWidth / 2;
var x = scaleClip(xScale, halfBorderWidth);
var y = scaleClip(yScale, halfBorderWidth);
return {
top: y.end,
right: x.end,
bottom: y.start,
left: x.start
};
}
function toClip(value) {
var t, r, b, l;
if (helpers.isObject(value)) {
t = value.top;
r = value.right;
b = value.bottom;
l = value.left;
} else {
t = r = b = l = value;
}
return {
top: t,
right: r,
bottom: b,
left: l
};
}
module.exports = DatasetController.extend({
datasetElementType: elements.Line,
@@ -173,6 +218,7 @@ module.exports = DatasetController.extend({
values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps);
values.tension = valueOrDefault(config.lineTension, lineOptions.tension);
values.steppedLine = resolve([custom.steppedLine, config.steppedLine, lineOptions.stepped]);
values.clip = toClip(valueOrDefault(config.clip, defaultClip(me._xScale, me._yScale, values.borderWidth)));
return values;
},
@@ -275,18 +321,19 @@ module.exports = DatasetController.extend({
var meta = me.getMeta();
var points = meta.data || [];
var area = chart.chartArea;
var canvas = chart.canvas;
var i = 0;
var ilen = points.length;
var halfBorderWidth;
var clip;
if (me._showLine) {
halfBorderWidth = (meta.dataset._model.borderWidth || 0) / 2;
clip = meta.dataset._model.clip;
helpers.canvas.clipArea(chart.ctx, {
left: area.left - halfBorderWidth,
right: area.right + halfBorderWidth,
top: area.top - halfBorderWidth,
bottom: area.bottom + halfBorderWidth
left: clip.left === false ? 0 : area.left - clip.left,
right: clip.right === false ? canvas.width : area.right + clip.right,
top: clip.top === false ? 0 : area.top - clip.top,
bottom: clip.bottom === false ? canvas.height : area.bottom + clip.bottom
});
meta.dataset.draw();

View File

@@ -0,0 +1,38 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"ticks": {
"max": 3,
"display": false
}
}],
"yAxes": [{"ticks": {"display": false}}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

View File

@@ -0,0 +1,38 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"ticks": {
"min": -2,
"display": false
}
}],
"yAxes": [{"ticks": {"display": false}}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -0,0 +1,39 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"ticks": {
"min": -2,
"max": 3,
"display": false
}
}],
"yAxes": [{"ticks": {"display": false}}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -0,0 +1,38 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{"ticks": {"display": false}}],
"yAxes": [{
"ticks": {
"max": 6,
"display": false
}
}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,38 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{"ticks": {"display": false}}],
"yAxes": [{
"ticks": {
"min": 2,
"display": false
}
}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,39 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [{
"borderColor": "red",
"data": [{"x":-5,"y":5},{"x":-4,"y":6},{"x":-3,"y":7},{"x":-2,"y":6},{"x":-1,"y":5},{"x":0,"y":4},{"x":1,"y":3},{"x":2,"y":2},{"x":3,"y":5},{"x":4,"y":7},{"x":5,"y":9}],
"fill": false,
"showLine": true,
"borderWidth": 20,
"pointRadius": 0
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{"ticks": {"display": false}}],
"yAxes": [{
"ticks": {
"min": 2,
"max": 6,
"display": false
}
}]
},
"layout": {
"padding": 24
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,77 @@
{
"config": {
"type": "scatter",
"data": {
"datasets": [
{
"showLine": true,
"borderColor": "red",
"data": [{"x":-4,"y":-4},{"x":4,"y":4}],
"clip": false
},
{
"showLine": true,
"borderColor": "green",
"data": [{"x":-4,"y":-5},{"x":4,"y":3}],
"clip": 5
},
{
"showLine": true,
"borderColor": "blue",
"data": [{"x":-4,"y":-3},{"x":4,"y":5}],
"clip": -5
},
{
"showLine": true,
"borderColor": "brown",
"data": [{"x":-3,"y":-3},{"x":-1,"y":3},{"x":1,"y":-2},{"x":2,"y":3}],
"clip": {
"top": 8,
"left": false,
"right": -20,
"bottom": -20
}
}
]
},
"options": {
"responsive": false,
"legend": false,
"title": false,
"scales": {
"xAxes": [{
"ticks": {
"min": -2,
"max": 2,
"display": false
}
}],
"yAxes": [{
"ticks": {
"min": -2,
"max": 2,
"display": false
}
}]
},
"layout": {
"padding": 24
},
"elements": {
"line": {
"fill": false,
"borderWidth": 20
},
"point": {
"radius": 0
}
}
}
},
"options": {
"canvas": {
"height": 256,
"width": 512
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB