| `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:
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.
<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>
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;
}
}]);
});
- 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
y: 10,
controlPointNextX: 0,
controlPointNextY: 10,
- steppedLine: true
+ steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
controlPointPreviousY: 0,
controlPointNextX: 5,
controlPointNextY: 0,
- steppedLine: true
+ steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
controlPointPreviousY: -10,
controlPointNextX: 15,
controlPointNextY: -10,
- steppedLine: true
+ steppedLine: 'after'
}
}));
points.push(new Chart.elements.Point({
controlPointPreviousY: -5,
controlPointNextX: 19,
controlPointNextY: -5,
- steppedLine: true
+ steppedLine: 'after'
}
}));
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]