Line chart out of axis boundary after extended the chart draw function - chart.js

I referred to "How to change line segment color of a line graph in Chart.js" and extended the chart to redraw the line segment with a different color.
But after adding plugin "chartjs-plugin-zoom" to support zoom in/out the chart, I could see the line chart is out of axis boundary. See the following code.
https://jsfiddle.net/sd9rx84g/2/
var ctx = document.getElementById('myChart').getContext('2d');
//adding custom chart type
Chart.defaults.multicolorLine = Chart.defaults.line;
Chart.controllers.multicolorLine = Chart.controllers.line.extend({
draw: function(ease) {
var
startIndex = 0,
meta = this.getMeta(),
points = meta.data || [],
colors = this.getDataset().colors,
area = this.chart.chartArea,
originalDatasets = meta.dataset._children
.filter(function(data) {
return !isNaN(data._view.y);
});
function _setColor(newColor, meta) {
meta.dataset._view.borderColor = newColor;
}
if (!colors) {
Chart.controllers.line.prototype.draw.call(this, ease);
return;
}
for (var i = 2; i <= colors.length; i++) {
if (colors[i-1] !== colors[i]) {
_setColor(colors[i-1], meta);
meta.dataset._children = originalDatasets.slice(startIndex, i);
meta.dataset.draw();
startIndex = i - 1;
}
}
meta.dataset._children = originalDatasets.slice(startIndex);
meta.dataset.draw();
meta.dataset._children = originalDatasets;
points.forEach(function(point) {
point.draw(area);
});
}
});
var chart = new Chart(ctx, {
// The type of chart we want to create
type: 'multicolorLine',
// The data for our dataset
data: {
labels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"],
datasets: [{
label: "My First dataset",
borderColor: 'rgb(255, 99, 132)',
data: [35, 10, 5, 2, 20, 30, 45, 0, 10, 5, 2, 20, 30, 45],
//first color is not important
colors: ['', 'red', 'green', 'blue', 'red', 'brown', 'black']
}]
},
// Configuration options go here
options: {
plugins: {
zoom: {
pan: {
// pan options and/or events
enabled: true,
mode: 'xy'
},
zoom: {
enabled: true,
drag: false,
mode: 'x',
speed: 1
}
}
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.9.3"></script>
<script src="https://cdn.jsdelivr.net/npm/hammerjs#2.0.8"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom#0.7.7"></script>
<canvas id="myChart"></canvas>
line chart out of axis boundary
How can I resolve this issue?
Thanks
Forrest

Related

Align doughnut/pie charts vertically in the container

I have three doughnut charts side by side like so:
The problem is, the number of items is different between the charts, causing the legend have different height and in turn the charts are not in line. Is it possible to align the charts to the top of the container?
You will need to use an custom plugin for this that makes an html legend:
const getOrCreateLegendList = (chart, id) => {
const legendContainer = document.getElementById(id);
let listContainer = legendContainer.querySelector('ul');
if (!listContainer) {
listContainer = document.createElement('ul');
listContainer.style.display = 'flex';
listContainer.style.flexDirection = 'row';
listContainer.style.margin = 0;
listContainer.style.padding = 0;
legendContainer.appendChild(listContainer);
}
return listContainer;
};
const htmlLegendPlugin = {
id: 'htmlLegend',
afterUpdate(chart, args, options) {
const ul = getOrCreateLegendList(chart, options.containerID);
// Remove old legend items
while (ul.firstChild) {
ul.firstChild.remove();
}
// Reuse the built-in legendItems generator
const items = chart.options.plugins.legend.labels.generateLabels(chart);
items.forEach(item => {
const li = document.createElement('li');
li.style.alignItems = 'center';
li.style.cursor = 'pointer';
li.style.display = 'flex';
li.style.flexDirection = 'row';
li.style.marginLeft = '10px';
li.onclick = () => {
const {
type
} = chart.config;
if (type === 'pie' || type === 'doughnut') {
// Pie and doughnut charts only have a single dataset and visibility is per item
chart.toggleDataVisibility(item.index);
} else {
chart.setDatasetVisibility(item.datasetIndex, !chart.isDatasetVisible(item.datasetIndex));
}
chart.update();
};
// Color box
const boxSpan = document.createElement('span');
boxSpan.style.background = item.fillStyle;
boxSpan.style.borderColor = item.strokeStyle;
boxSpan.style.borderWidth = item.lineWidth + 'px';
boxSpan.style.display = 'inline-block';
boxSpan.style.height = '20px';
boxSpan.style.marginRight = '10px';
boxSpan.style.width = '20px';
// Text
const textContainer = document.createElement('p');
textContainer.style.color = item.fontColor;
textContainer.style.margin = 0;
textContainer.style.padding = 0;
textContainer.style.textDecoration = item.hidden ? 'line-through' : '';
const text = document.createTextNode(item.text);
textContainer.appendChild(text);
li.appendChild(boxSpan);
li.appendChild(textContainer);
ul.appendChild(li);
});
}
};
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink',
backgroundColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange',
backgroundColor: 'orange'
}
]
},
options: {
plugins: {
legend: {
display: false,
},
htmlLegend: {
// ID of the container to put the legend in
containerID: 'legend-container',
}
}
},
plugins: [htmlLegendPlugin],
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<div id="legend-container"></div>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.js"></script>
</body>

How to hide Chart.js data labels for small screens

I am trying to hide data labels generated by the data labels plugin for small screens.
I thought that I could use the onResize property of chartjs and set display to false when the width got small. This is much like the hide labels solution found here.
Unfortunately, I've not been able to get this to work. I have the following CodePen that doesn't work.
var moneyFormat = wNumb({
decimals: 0,
thousand: ',',
prefix: '$',
negativeBefore: '-'
});
var percentFormat = wNumb({
decimals: 0,
suffix: '%',
negativeBefore: '-'
});
/*
* Unregister chartjs-plugins-datalabels - not really necessary for this use case
*/
Chart.plugins.unregister(ChartDataLabels);
var doughnutdata = {
labels: ['Housing',
'Food',
'Transportation',
'Clothing',
'Healthcare',
'Childcare',
'Misc'],
datasets: [
{
backgroundColor: [
'#9B2A00',
'#5B5C90',
'#6B8294',
'#1A6300',
'#BE0000',
'#B8A853',
'#64A856'
],
borderColor: [
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF',
'#FFFFFF'
],
data: [88480, 57680, 40050, 18430, 23860, 25840, 17490]
}
]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {
labels: {
boxWidth: 20
}
},
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var index = tooltipItem.index;
return data.labels[index] + ': ' + moneyFormat.to(data.datasets[0].data[index]) + '';
}
}
},
plugins: {
datalabels: {
anchor: 'end',
backgroundColor: function (context) {
return context.dataset.backgroundColor;
},
borderColor: 'white',
borderRadius: 25,
borderWidth: 1,
color: 'white',
font: {
size: 10
},
formatter: function (value, pieID) {
var sum = 0;
var dataArr = pieID.chart.data.datasets[0].data;
dataArr.map(function (data) {
sum += data;
});
var percentage = percentFormat.to((value * 100 / sum));
return percentage;
}
}
}
};
var doughnutID = document.getElementById('doughnutchart').getContext('2d');
var pieChart = new Chart(doughnutID, {
plugins: [ChartDataLabels],
type: 'doughnut',
data: doughnutdata,
options: chartOptions,
onResize: function(chart, size) {
var showLabels = (size.width < 500) ? false : true;
chart.options = {
plugins: {
datalabels: {
display: showLabels
}
}
};
}
});
Any ideas concerning what I'm doing wrong (and fixes) would be greatly appreciated.
Responsiveness can be implemented using scriptable options and in your case, you would use a function for the display option that returns false if the chart is smaller than a specific size. (Example):
options: {
plugins: {
datalabels: {
display: function(context) {
return context.chart.width > 500;
}
}
}
}
As usual, as soon as I post a question I come up with an answer. One solution using inline plugin definitions is given at the following CodePen. If you put a browser into developer mode and shrink the window to less than 540 px, the data labels will vanish.
The code is shown below:
"use strict";
/* global Chart */
/* global wNumb */
/* global ChartDataLabels */
/*
* Unregister chartjs-plugins-datalabels - not really necessary for this use case
*/
Chart.plugins.unregister(ChartDataLabels);
var moneyFormat = wNumb({
decimals: 0,
thousand: ",",
prefix: "$",
negativeBefore: "-"
});
var percentFormat = wNumb({
decimals: 0,
suffix: "%",
negativeBefore: "-"
});
var doughnutdata = {
labels: [
"Housing",
"Food",
"Transportation",
"Clothing",
"Healthcare",
"Childcare",
"Misc"
],
datasets: [
{
backgroundColor: [
"#9B2A00",
"#5B5C90",
"#6B8294",
"#1A6300",
"#BE0000",
"#B8A853",
"#64A856"
],
borderColor: [
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF",
"#FFFFFF"
],
data: [88480, 57680, 40050, 18430, 23860, 25840, 17490]
}
]
};
var chartOptions = {
responsive: true,
maintainAspectRatio: true,
legend: {
labels: {
boxWidth: 20
}
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var index = tooltipItem.index;
return (
data.labels[index] +
": " +
moneyFormat.to(data.datasets[0].data[index]) +
""
);
}
}
},
plugins: {
datalabels: {
anchor: "end",
backgroundColor: function(context) {
return context.dataset.backgroundColor;
},
borderColor: "white",
borderRadius: 25,
borderWidth: 1,
color: "white",
font: {
size: 10
},
formatter: function(value, pieID) {
var sum = 0;
var dataArr = pieID.chart.data.datasets[0].data;
dataArr.map(function(data) {
sum += data;
});
var percentage = percentFormat.to(value * 100 / sum);
return percentage;
}
}
}
};
var doughnutID = document.getElementById("doughnutchart").getContext("2d");
var pieChart = new Chart(doughnutID, {
plugins: [
ChartDataLabels,
{
beforeLayout: function(chart) {
var showLabels = (chart.width) > 500 ? true : false;
chart.options.plugins.datalabels.display = showLabels;
}
},
{
onresize: function(chart) {
var showLabels = (chart.width) > 500 ? true : false;
chart.options.plugins.datalabels.display = showLabels;
}
}
],
type: "doughnut",
data: doughnutdata,
options: chartOptions
});
I hope that this is useful.

ChartJS line-chart set background-opacity

I've tried multiple examples but i'm unable to get my line-chart to have background-transparency, as of now, it's blue, but the color i'm trying to set is orange (rgba(255, 145, 68, 0.2)).
TL;DR: How do I set the fill-opacity on my line-chart graph?
I've followed countless of tutorials, but all of them seem to set the background-color in dataset, which is not what I want, since i'm using dynamic data. The code is in a TypeScript component with tons of functionality built upon it, so it's quite hard to extract the code and make it work in a jsfiddle.
When i set fill:true under elements: { line: { the graph will get the fill as shown in the image below. But i'm unable to set the background-opacity here,
I've tried these attributes: backgroundColor, fillColor
Here's the code atleast:
import {
Component
} from '../../decorators/component.decorator';
import * as EsChart from '../../../../node_modules/chart.js/dist/Chart.bundle.js';
import * as angular from 'angular';
#Component({
templateUrl: 'app/dashboard-components/es-line-chart/es-line-chart.component.html',
bindings: {
esLineChartId: '#',
chartTitle: '#',
labels: '#',
esScaleMax: '#',
esScaleMaxSecond: '#',
esScaleStepW: '#',
esScaleStepWSecond: '#',
esScaleMin: '#',
esScaleMinSecond: '#',
lowerOkValue: '#',
targetValue: '#',
upperOkValue: '#',
chartDataValueSuffix: '#',
datasets: '#',
esXLabelSkips: '#'
}
})
export default class LineChartComponent {
$ctrl: any = this;
getChartOptions(lineChartData, secondYAxis, xLabelSkips) {
return {
type: 'line',
data: lineChartData,
options: {
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: this.$ctrl.chartTitle
},
legend: {
display: true,
labels: {
boxWidth: 12
}
},
tooltips: {
enabled: true,
mode: 'index',
intersect: false,
filter: function(tooltipItem, data) {
return !data.datasets[tooltipItem.datasetIndex].tooltipHidden;
},
callbacks: {
label: function(tooltipItem, data) {
var currentDataset = data.datasets[tooltipItem.datasetIndex];
var label = currentDataset.label + ': ';
label += currentDataset.data[tooltipItem.index] + (currentDataset.dataSuffix ? " " + currentDataset.dataSuffix : "");
return label;
}
}
},
elements: {
line: {
tension: 0, // disables bezier curves
borderWidth: 3, // Line stroke width in pixels
fill: true,
fillColor: "rgba(255, 145, 68, 0.2)",
strokeColor: "rgba(255, 145, 68, 0.2)",
pointColor: "rgba(255, 145, 68, 1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(255, 145, 68, 1)"
},
point: { // disable the circles/points in the chart lines
radius: 0,
hitRadius: 0,
hoverRadius: 0
},
},
scales: {
xAxes: [{
display: true,
type: 'category',
ticks: {
autoSkip: xLabelSkips,
maxRotation: 45
},
afterFit: (scale) => {
scale.height = 100;
}
}],
yAxes: [{
id: 'y-axis-0',
display: true,
position: 'left',
ticks: {
stepSize: this.$ctrl.esScaleStepW ? eval(this.$ctrl.esScaleStepW) : 0.5, // grid lines on yAxis with value distance of stepSize
suggestedMin: (eval(this.$ctrl.esScaleMin)),
suggestedMax: (eval(this.$ctrl.esScaleMax))
}
},
{
id: 'y-axis-1',
display: secondYAxis,
position: 'right',
ticks: {
stepSize: this.$ctrl.esScaleStepWSecond ? eval(this.$ctrl.esScaleStepWSecond) : 0.5, // grid lines on yAxis with value distance of stepSize
suggestedMin: (eval(this.$ctrl.esScaleMinSecond)),
suggestedMax: (eval(this.$ctrl.esScaleMaxSecond))
}
}
]
}
}
};
}
getExtraDatasets(datasetType: string, dataLabel: string, fillValue: number, chartSpan: number) {
var dataFill = [];
for (var i = 0; i < chartSpan; i++) {
dataFill.push(fillValue);
}
return {
label: dataLabel,
borderColor: datasetType === "limit" ? 'rgba(205, 8, 4, 1)' : datasetType === "target" ? 'rgba(20, 180, 2, 1)' : 'rgba(0, 0, 0, 0.5)',
borderWidth: 0.5,
//tooltipHidden: true,
data: dataFill
};
}
removeEmptyDatasets() {
//var test = "[{label: 'Verklig cykeltid',borderColor: 'rgba(60, 141, 188, 0.75)',borderWidth: 4,data: },{label: 'Kalkylerad cykeltid',borderColor: 'rgba(205, 108, 104, 0.75)',borderWidth: 4,data: [59]}]";
this.$ctrl.datasets = this.$ctrl.datasets.replace(/data: *,/g, "data: [],");
this.$ctrl.datasets = this.$ctrl.datasets.replace(/data: *}/g, "data: []}");
this.$ctrl.datasets = this.$ctrl.datasets.replace(/: *,/g, ": 0,");
this.$ctrl.datasets = this.$ctrl.datasets.replace(/: *}/g, ": 0}");
var sets = this.$ctrl.datasets.match(/\{[^\{\}]*\}/g);
for (var i = 0; i < sets.length; i++) {
if (sets[i].match(/data: *\[\]/g)) {
//console.log("no data", sets[i]);
sets[i] = "";
}
}
this.$ctrl.datasets = ("[" + (sets.join()).replace(/^,|,$/g, "") + "]");
}
$onInit() {
var canvas = $("#" + this.$ctrl.esLineChartId + " .lineChart").get(0).getContext("2d");
this.removeEmptyDatasets();
//console.log(this.$ctrl.datasets);
var lineChartData = {
labels: this.$ctrl.labels ? eval(this.$ctrl.labels) : [],
datasets: this.$ctrl.datasets ? eval(this.$ctrl.datasets) : []
};
if (this.$ctrl.upperOkValue) {
lineChartData.datasets = lineChartData.datasets.concat(this.getExtraDatasets("limit", "Övre gräns", eval(this.$ctrl.upperOkValue), (lineChartData.labels).length));
}
if (this.$ctrl.targetValue) {
lineChartData.datasets = lineChartData.datasets.concat(this.getExtraDatasets("target", "Målvärde", eval(this.$ctrl.targetValue), (lineChartData.labels).length));
}
if (this.$ctrl.lowerOkValue) {
lineChartData.datasets = lineChartData.datasets.concat(this.getExtraDatasets("limit", "Undre gräns", eval(this.$ctrl.lowerOkValue), (lineChartData.labels).length));
}
var secondYAxis = false;
for (var i = 0; i < (lineChartData.datasets).length; i++) {
// set backgroundColor to be the same as borderColor so that tooltip and legend items look better
(lineChartData.datasets[i]).backgroundColor = (lineChartData.datasets[i]).borderColor;
// Activate the second y axis if a dataset uses it
if ((lineChartData.datasets[i]).yAxisID == 'y-axis-1') {
secondYAxis = true;
}
// Use standard data suffix if defined and no special data suffix is defined for the dataset
if (!((lineChartData.datasets[i]).dataSuffix) && (this.$ctrl.chartDataValueSuffix)) {
(lineChartData.datasets[i]).dataSuffix = this.$ctrl.chartDataValueSuffix;
}
}
var xLabelSkips = this.$ctrl.esXLabelSkips ? eval(this.$ctrl.esXLabelSkips) : false;
var chartOptions = this.getChartOptions(lineChartData, secondYAxis, xLabelSkips);
var lineChart = new EsChart(canvas, chartOptions);
}
}
resources i've followed:
http://tobiasahlin.com/blog/chartjs-charts-to-get-you-started/
https://www.chartjs.org/docs/latest/configuration/elements.html
https://canvasjs.com/docs/charts/chart-options/data/fill-opacity/
Image:

Chart JS Fill Between two lines

I am looking for a way to fill between two lines with Chart.js so that it would look like this. I have looked and everything seems to talk about filling between two lines across zero. I also need other lines to fill all the way down like normal. Is this something chart.js can do?
Here is a solution that uses a plugin to fill between two datasets. Supports all line styles and fill shading between multiple lines. To fill between a dataset, use the custom param fillBetweenSet to tell a dataset to fill the area between another dataset.
Fiddle - https://jsfiddle.net/ke5n5LnL/26/
Preview:
Code:
<html>
<div>
<canvas id="demo"></canvas>
</div>
</html>
<script>
var fillBetweenLinesPlugin = {
afterDatasetsDraw: function (chart) {
var ctx = chart.chart.ctx;
var xaxis = chart.scales['x-axis-0'];
var yaxis = chart.scales['y-axis-0'];
var datasets = chart.data.datasets;
ctx.save();
for (var d = 0; d < datasets.length; d++) {
var dataset = datasets[d];
if (dataset.fillBetweenSet == undefined) {
continue;
}
// get meta for both data sets
var meta1 = chart.getDatasetMeta(d);
var meta2 = chart.getDatasetMeta(dataset.fillBetweenSet);
// do not draw fill if one of the datasets is hidden
if (meta1.hidden || meta2.hidden) continue;
// create fill areas in pairs
for (var p = 0; p < meta1.data.length-1;p++) {
// if null skip
if (dataset.data[p] == null || dataset.data[p+1] == null) continue;
ctx.beginPath();
// trace line 1
var curr = meta1.data[p];
var next = meta1.data[p+1];
ctx.moveTo(curr._view.x, curr._view.y);
ctx.lineTo(curr._view.x, curr._view.y);
if (curr._view.steppedLine === true) {
ctx.lineTo(next._view.x, curr._view.y);
ctx.lineTo(next._view.x, next._view.y);
}
else if (next._view.tension === 0) {
ctx.lineTo(next._view.x, next._view.y);
}
else {
ctx.bezierCurveTo(
curr._view.controlPointNextX,
curr._view.controlPointNextY,
next._view.controlPointPreviousX,
next._view.controlPointPreviousY,
next._view.x,
next._view.y
);
}
// connect dataset1 to dataset2
var curr = meta2.data[p+1];
var next = meta2.data[p];
ctx.lineTo(curr._view.x, curr._view.y);
// trace BACKWORDS set2 to complete the box
if (curr._view.steppedLine === true) {
ctx.lineTo(curr._view.x, next._view.y);
ctx.lineTo(next._view.x, next._view.y);
}
else if (next._view.tension === 0) {
ctx.lineTo(next._view.x, next._view.y);
}
else {
// reverse bezier
ctx.bezierCurveTo(
curr._view.controlPointPreviousX,
curr._view.controlPointPreviousY,
next._view.controlPointNextX,
next._view.controlPointNextY,
next._view.x,
next._view.y
);
}
// close the loop and fill with shading
ctx.closePath();
ctx.fillStyle = dataset.fillBetweenColor || "rgba(0,0,0,0.1)";
ctx.fill();
} // end for p loop
}
} // end afterDatasetsDraw
}; // end fillBetweenLinesPlugin
Chart.pluginService.register(fillBetweenLinesPlugin);
var chartData = {
labels: [1, 2, 3, 4, 5,6,7,8],
datasets: [
{
label: "Set 1",
data: [10, 20, null, 40, 30,null,20,40],
borderColor: "#F00",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(255,0,0, 0.2)"
},
{
label: "Set 2",
data: [60, 40, 10, 50, 60,null,50,20],
borderColor: "#00F",
fill: false,
steppedLine: false,
tension: 0.5
},
{
label: "Set 2",
data: [40, 50, 30, 30, 20,null,60,40],
borderColor: "#0D0",
fill: false,
steppedLine: false,
tension: 0,
fillBetweenSet: 1,
fillBetweenColor: "rgba(5,5,255, 0.2)"
}
]
};
var chartOptions = {
responsive: true,
title: {
display: true,
text: 'Demo Fill between lines'
}
};
var chartDemo = new Chart($('#demo').get(0), {
type: 'line',
data: chartData,
options: chartOptions
});
</script>
Setting fill property to +1 of a dataset will set the backgroundColor from this line to the next line in dataset.
datasets: [{
label: 'Systolic Guideline',
data: [],
fill: '+1',
borderColor: '#FFC108',
backgroundColor: 'rgba(255,193,8,0.2)'
},
{
label: 'Diastolic Guideline',
data: [],
fill: true,
borderColor: '#FFC108',
backgroundColor: 'rgba(0,0,0,0)'
}]
On chart.js v2.0 you have this feature now inside. See https://www.chartjs.org/samples/latest/charts/area/line-datasets.html

In ChartJS is it possible to change the line style between different points?

Using ChartJs (v2.2.2) can you change the line style between the last 2 points on a graph. e.g. have a solid line all the way and then dashed at the end? see picture below
The borderDashproperty (scroll to Line Configuration) is the key to your problem.
The thing is, the full chart is drawn with a border dash, you cannot choose where it starts and where it ends.
A simple workaround is to create two identical datasets. One dotted and one with a plain line. Then you remvoe the last data of your plain one, and they both will be displayed as how you want it.
You can see the full code in this jsFiddle, and here is its result :
Note :
Since there are two datasets now, the legend will display both of them. Setting the display to false fixes it (more or less).
The declaration order doesn't matter since the plain line will always overwrite the dotted one.
Having a bezier curve (tension property > 0) can create a display problem since the data is not the same in both datasets.
You can create a scatter chart and draw the lines directly on the canvas using the Plugin Core API. The API offers a range of hooks that can be used for performing custom code. The advantage of this approach is that you can customize the style of every single connection line (width, color, dash pattern etc.).
const labels = [1, 2, 3, 4, 5, 6];
const values = [12, 19, 3, 5, 2, 3];
const data = labels.map((label, index) => ({ x: label, y: values[index]}));
var lineChart = new Chart(document.getElementById("chart"), {
type: "scatter",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
chart.config.data.datasets[0].data.forEach((value, index) => {
if (index > 0) {
var valueFrom = data[index - 1];
var xFrom = xAxis.getPixelForValue(valueFrom.x);
var yFrom = yAxis.getPixelForValue(valueFrom.y);
var xTo = xAxis.getPixelForValue(value.x);
var yTo = yAxis.getPixelForValue(value.y);
ctx.save();
ctx.strokeStyle = '#922893';
ctx.lineWidth = 2;
if (index + 1 == data.length) {
ctx.setLineDash([5, 10]);
}
ctx.beginPath();
ctx.moveTo(xFrom, yFrom);
ctx.lineTo(xTo, yTo);
ctx.stroke();
ctx.restore();
}
});
}
}],
data: {
datasets: [{
label: "My Dataset",
data: data,
borderColor: '#922893',
pointBackgroundColor: "transparent"
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
stepSize: 1
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="90"></canvas>
const labels = [1, 2, 3, 4, 5, 6];
const values = [12, 19, 3, 5, 2, 3];
const data = labels.map((label, index) => ({ x: label, y: values[index]}));
var lineChart = new Chart(document.getElementById("chart"), {
type: "scatter",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-1'];
var yAxis = chart.scales['y-axis-1'];
chart.config.data.datasets[0].data.forEach((value, index) => {
if (index > 0) {
var valueFrom = data[index - 1];
var xFrom = xAxis.getPixelForValue(valueFrom.x);
var yFrom = yAxis.getPixelForValue(valueFrom.y);
var xTo = xAxis.getPixelForValue(value.x);
var yTo = yAxis.getPixelForValue(value.y);
ctx.save();
ctx.strokeStyle = '#922893';
ctx.lineWidth = 2;
if (index + 1 == data.length) {
ctx.setLineDash([5, 10]);
}
ctx.beginPath();
ctx.moveTo(xFrom, yFrom);
ctx.lineTo(xTo, yTo);
ctx.stroke();
ctx.restore();
}
});
}
}],
data: {
datasets: [{
label: "My Dataset",
data: data,
borderColor: '#922893',
pointBackgroundColor: "transparent"
}]
},
options: {
legend: {
display: false
},
scales: {
xAxes: [{
ticks: {
stepSize: 1
}
}],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="90"></canvas>