Enhancement: adds step-after functionality, true defaults to step-before (#4065)

* Adds step-after functionality, true defaults to step-before

* Update stepped line sample to include all variations of steppedLine configurations

* Update documentation on steppedLine values

* Add tests for new steppedLine values 'before' and 'after'
This commit is contained in:
Eric Nikolay Katz
2017-04-16 16:13:13 -04:00
committed by Evert Timberg
parent 19d6df21e3
commit 205cedc0ef
4 changed files with 244 additions and 87 deletions

View File

@@ -70,7 +70,7 @@ All point* properties can be specified as an array. If these are set to an array
| `pointHoverRadius` | `Number/Number[]` | The radius of the point when hovered.
| `showLine` | `Boolean` | If false, the line is not drawn for this dataset.
| `spanGaps` | `Boolean` | 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
| `steppedLine` | `Boolean` | If true, the line is shown as a stepped line and 'lineTension' will be ignored.
| `steppedLine` | `Boolean/String` | If the line is shown as a stepped line. [more...](#stepped-line)
### cubicInterpolationMode
The following interpolation modes are supported:
@@ -106,6 +106,15 @@ The style of point. Options are:
If the option is an image, that image is drawn on the canvas using [drawImage](https://developer.mozilla.org/en/docs/Web/API/CanvasRenderingContext2D/drawImage).
### Stepped Line
The following values are supported for `steppedLine`:
* `false`: No Step Interpolation (default)
* `true`: Step-before Interpolation (eq. 'before')
* `'before'`: Step-before Interpolation
* `'after'`: Step-after Interpolation
If the `steppedLine` value is set to anything other than false, `lineTension` will be ignored.
## Configuration Options
The line chart defines the following configuration options. These options are merged with the global chart configuration options, `Chart.defaults.global`, to form the options passed to the chart.

View File

@@ -5,88 +5,98 @@
<title>Stepped Line Chart</title>
<script src="../../../dist/Chart.bundle.js"></script>
<script src="../../utils.js"></script>
<style>
canvas{
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
</style>
<style>
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
.chart-container {
width: 500px;
margin-left: 40px;
margin-right: 40px;
margin-bottom: 40px;
}
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
}
</style>
</head>
<body>
<div style="width:75%;">
<canvas id="canvas"></canvas>
</div>
<div class="container">
</div>
<script>
var config = {
type: 'line',
data: {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [{
label: "My First dataset",
borderColor: window.chartColors.red,
backgroundColor: window.chartColors.red,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
],
fill: false,
steppedLine: true,
}, {
label: "My Second dataset",
steppedLine: true,
borderColor: window.chartColors.blue,
backgroundColor: window.chartColors.blue,
data: [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
],
fill: false,
}]
},
options: {
responsive: true,
title:{
display:true,
text:'Chart.js Line Chart'
},
tooltips: {
mode: 'index',
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Value'
},
}]
}
}
};
function createConfig(details, data) {
return {
type: 'line',
data: {
labels: ['Day 1', 'Day 2', 'Day 3', 'Day 4', 'Day 5', 'Day 6'],
datasets: [{
label: 'steppedLine: ' + ((typeof(details.steppedLine) === 'boolean') ? details.steppedLine : `'${details.steppedLine}'`),
steppedLine: details.steppedLine,
data: data,
borderColor: details.color,
fill: false,
}]
},
options: {
responsive: true,
title: {
display: true,
text: details.label,
}
}
};
}
window.onload = function() {
var ctx = document.getElementById("canvas").getContext("2d");
window.myLine = new Chart(ctx, config);
};
window.onload = function() {
var container = document.querySelector('.container');
var data = [
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor(),
randomScalingFactor()
];
var steppedLineSettings = [{
steppedLine: false,
label: 'No Step Interpolation',
color: window.chartColors.red
}, {
steppedLine: true,
label: 'Step Before Interpolation',
color: window.chartColors.green
}, {
steppedLine: 'before',
label: 'Step Before Interpolation',
color: window.chartColors.green
}, {
steppedLine: 'after',
label: 'Step After Interpolation',
color: window.chartColors.purple
}];
steppedLineSettings.forEach(function(details) {
var div = document.createElement('div');
div.classList.add('chart-container');
var canvas = document.createElement('canvas');
div.appendChild(canvas);
container.appendChild(div);
var ctx = canvas.getContext('2d');
var config = createConfig(details, data);
new Chart(ctx, config);
});
};
</script>
</body>

View File

@@ -123,7 +123,11 @@ module.exports = function(Chart) {
helpers.lineTo = function(ctx, previous, target, flip) {
if (target.steppedLine) {
ctx.lineTo(target.x, previous.y);
if (target.steppedLine === 'after') {
ctx.lineTo(previous.x, target.y);
} else {
ctx.lineTo(target.x, previous.y);
}
ctx.lineTo(target.x, target.y);
return;
}

View File

@@ -243,7 +243,141 @@ describe('Chart.elements.Line', function() {
}]);
});
it('should draw stepped lines', function() {
it('should draw stepped lines, with "before" interpolation', function() {
// Both `true` and `'before'` should draw the same steppedLine
var beforeInterpolations = [true, 'before'];
beforeInterpolations.forEach(function(mode) {
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,
steppedLine: mode
}
}));
points.push(new Chart.elements.Point({
_datasetindex: 2,
_index: 1,
_view: {
x: 5,
y: 0,
controlPointPreviousX: 5,
controlPointPreviousY: 0,
controlPointNextX: 5,
controlPointNextY: 0,
steppedLine: mode
}
}));
points.push(new Chart.elements.Point({
_datasetindex: 2,
_index: 2,
_view: {
x: 15,
y: -10,
controlPointPreviousX: 15,
controlPointPreviousY: -10,
controlPointNextX: 15,
controlPointNextY: -10,
steppedLine: mode
}
}));
points.push(new Chart.elements.Point({
_datasetindex: 2,
_index: 3,
_view: {
x: 19,
y: -5,
controlPointPreviousX: 19,
controlPointPreviousY: -5,
controlPointNextX: 19,
controlPointNextY: -5,
steppedLine: mode
}
}));
var line = new Chart.elements.Line({
_datasetindex: 2,
_chart: {
ctx: mockContext,
},
_children: points,
// Need to provide some settings
_view: {
fill: false, // don't want to fill
tension: 0, // no bezier curve for now
}
});
line.draw();
expect(mockContext.getCalls()).toEqual([{
name: 'save',
args: [],
}, {
name: 'setLineCap',
args: ['butt']
}, {
name: 'setLineDash',
args: [
[]
]
}, {
name: 'setLineDashOffset',
args: [0.0]
}, {
name: 'setLineJoin',
args: ['miter']
}, {
name: 'setLineWidth',
args: [3]
}, {
name: 'setStrokeStyle',
args: ['rgba(0,0,0,0.1)']
}, {
name: 'beginPath',
args: []
}, {
name: 'moveTo',
args: [0, 10]
}, {
name: 'lineTo',
args: [5, 10]
}, {
name: 'lineTo',
args: [5, 0]
}, {
name: 'lineTo',
args: [15, 0]
}, {
name: 'lineTo',
args: [15, -10]
}, {
name: 'lineTo',
args: [19, -10]
}, {
name: 'lineTo',
args: [19, -5]
}, {
name: 'stroke',
args: [],
}, {
name: 'restore',
args: []
}]);
});
});
it('should draw stepped lines, with "after" interpolation', function() {
var mockContext = window.createMockContext();
// Create our points
@@ -256,7 +390,7 @@ describe('Chart.elements.Line', function() {
y: 10,
controlPointNextX: 0,
controlPointNextY: 10,
steppedLine: true
steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
@@ -269,7 +403,7 @@ describe('Chart.elements.Line', function() {
controlPointPreviousY: 0,
controlPointNextX: 5,
controlPointNextY: 0,
steppedLine: true
steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
@@ -282,7 +416,7 @@ describe('Chart.elements.Line', function() {
controlPointPreviousY: -10,
controlPointNextX: 15,
controlPointNextY: -10,
steppedLine: true
steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
@@ -295,7 +429,7 @@ describe('Chart.elements.Line', function() {
controlPointPreviousY: -5,
controlPointNextX: 19,
controlPointNextY: -5,
steppedLine: true
steppedLine: 'after'
}
}));
@@ -345,19 +479,19 @@ describe('Chart.elements.Line', function() {
args: [0, 10]
}, {
name: 'lineTo',
args: [5, 10]
args: [0, 0]
}, {
name: 'lineTo',
args: [5, 0]
}, {
name: 'lineTo',
args: [15, 0]
args: [5, -10]
}, {
name: 'lineTo',
args: [15, -10]
}, {
name: 'lineTo',
args: [19, -10]
args: [15, -5]
}, {
name: 'lineTo',
args: [19, -5]