Dashed line for missing data in Chart.JS (spanGaps style) - chart.js

I have a chart with data points that are null. Chart.js does the correct thing and skips those data points but I would like to have a 'dashed' line fill in the missing parts. For example, in the below code the line should be solid as in the CodePen link, but should be dashed from "Blue" to "Yellow". I know the spanGaps option is available but I would like to apply a different style to it.
Does anyone have any thoughts on how to accomplish this? I am using Chart.js 2.x
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["Red", "Blue", "Orange", "Yellow"],
datasets: [{
label: '# of Votes',
data: [12, 19, null, 3]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
}
}
});
CodePen

The Plugin Core API offers a range of hooks that may be used for performing custom code. You can use the beforeDraw hook to draw lines of different style between different datapoints using text directly on the canvas using CanvasRenderingContext2D.
Please take a look at the runnable code snippet below:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
ctx.save();
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let dataset = chart.data.datasets[0];
var valueFrom = null;
var valueFromIndex = 0;
var xFrom = null;
let yFrom = null;
ctx.strokeStyle = dataset.borderColor;
dataset.data.forEach((value, index) => {
if (value != null) {
var x = xAxis.getPixelForTick(index);
var y = yAxis.getPixelForValue(value);
if (valueFrom != null) {
ctx.lineWidth = dataset.borderWidth;
if (index - valueFromIndex > 1) {
ctx.setLineDash([5, 5]);
} else {
ctx.setLineDash([]);
}
ctx.beginPath();
ctx.moveTo(xFrom, yFrom);
ctx.lineTo(x, y);
ctx.stroke();
}
valueFrom = value;
valueFromIndex = index;
xFrom = x;
yFrom = y;
}
});
ctx.restore();
}
}],
data: {
labels: ["A", "B", "C", "D", "E", "F", "G"],
datasets: [{
label: 'My Dataset',
data: [12, 19, null, 3, 6, null, 8],
backgroundColor: 'rgba(255, 99, 132, 0.6)',
borderColor: 'rgb(255, 99, 132)',
borderWidth: 3,
showLine: false,
}]
},
options: {
animation: {
duration: 0
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>

Related

Chart.js V3 Fill Below 0

I'm looking for a way to fill everything below 0 on my graph as a nice shade of red. After scouring SO and the documentation, I haven't been able to find a way to do this. I tried creating a dataset filled with decimal.MinValue and setting everything below 0 as filled, but it shifted the entire graph down to the min regardless of whether the dataset was set to be hidden or not. Any advise would be greatly appreciated. Thank you.
You can use a custom inline plugin for this:
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [100, 19, 3, 5, -10, 3],
borderColor: 'red',
backgroundColor: 'red'
},
{
label: '# of Votes2',
data: [20, 10, 4, 3, -30, 32],
borderColor: 'blue',
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
backgrounds: {
hbars: [{
from: 0,
to: 'MIN',
color: "rgb(230, 195, 195)"
}]
}
}
},
plugins: [{
id: 'backgrounds',
beforeDraw: (chart, args, options) => {
const {
canvas,
ctx,
chartArea,
scales: {
y
}
} = chart;
let from = 0;
let to = 0;
options.hbars.forEach((hBar) => {
from = hBar.from;
to = hBar.to;
from = from === 'MIN' ? y.min : from;
from = from === 'MAX' ? y.max : from;
to = to === 'MIN' ? y.min : to;
to = to === 'MAX' ? y.max : to;
ctx.save(canvas.width, canvas.height);
ctx.fillStyle = hBar.color;
ctx.fillRect(chartArea.left, y.getPixelForValue(from), chartArea.right - chartArea.left, y.getPixelForValue(to) - y.getPixelForValue(hBar.from));
ctx.restore();
})
}
}]
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.4.0/chart.js"></script>
</body>

Adding line over stacked line chart with ChartJS

I'm trying to recreate this below chart with a stacked option on my background lines
But my attempts were unsuccessful with this image below as result
$(function() {
var areaChartCanvas = $('#areaChart').get(0).getContext('2d')
var areaChartData = {
labels: ['', '', ''],
datasets: [{
backgroundColor: 'transparent',
borderColor: 'black',
pointRadius: false,
data: [32, 12, 28],
type: 'line'
}, {
backgroundColor: 'red',
pointRadius: false,
data: [20, 20, 20]
}, {
backgroundColor: 'orange',
pointRadius: false,
data: [40, 40, 40]
}, {
backgroundColor: 'cyan',
pointRadius: false,
data: [60, 60, 60]
}]
}
var areaChartOptions = {
maintainAspectRatio: false,
responsive: true,
legend: {
display: false
},
scales: {
xAxes: [{
gridLines: {
display: true,
}
}],
yAxes: [{
gridLines: {
display: true,
},
stacked: true
}]
}
}
var areaChart = new Chart(areaChartCanvas, {
type: 'line',
data: areaChartData,
options: areaChartOptions
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="areaChart" style="height:250px"></canvas>
ideally, I want to be able to create 'AREAS' with different colors that will be stacked according to the interval I pass to it.
e.g:
cyan - 20
orange - 20
red - 20
but currently, I'm doing
cyan - 60
orange - 40
red - 20
If I understand you correctly, I thought about different approach and extends the chart with Plugin[1] (Inspired by https://stackoverflow.com/a/49303362/863110)
Chart.pluginService.register({
beforeDraw: function (chart, easing) {
if (chart.config.options.fillColor) {
var ctx = chart.chart.ctx;
var chartArea = chart.chartArea;
ctx.save();
let delta = 0;
const chartHeight = chartArea.bottom - chartArea.top;
const bottomBarHeight = chart.height - chartHeight - chartArea.top;
chart.config.options.fillColor.map(color => {
const colorHeight = chartHeight * (color[0] / 100);
const colorBottom = chartArea.bottom + colorHeight;
ctx.fillStyle = color[1];
const x = chartArea.left,
y = chart.height - bottomBarHeight - colorHeight - delta,
width = chartArea.right - chartArea.left,
height = colorHeight;
delta += height;
ctx.fillRect(x, y, width, height);
ctx.restore();
})
}
}
});
var chartData = {
labels: ['a', 'b', 'c', 'd'],
datasets: [{
label: 'value',
borderColor: 'blue',
data: [30, 50, 25, 10]
}]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myBar = new Chart(ctx, {
type: 'line',
data: chartData,
options: {
scales: {
yAxes: [{ ticks: { max: 60 } }]
},
legend: { display: false },
fillColor: [
[20, 'red'],
[20, 'blue'],
[20, 'green'],
[20, 'pink'],
[20, 'yellow'],
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart" height="300" width="500"></canvas>
https://jsbin.com/lisuvuq/2/edit?js,output
[1] - With Plugin you can custom the chart's behaviour. When you use Plugin you get an API so you can "listen" to life cycle events of the chart (beforeDraw for example) and call your own code. The API calls your function and gives you data about the chart so you can use it in your code.In this example, we're using the API to (1) Run a code before the chart been drawing (2) Using the data to calculate the areas of the different colors. (3) Draw additional shapes (ctx.fillRect) based on the calculation.

How to remove colored label square

I have this red square near the label:
How to remove this?
This is my chart imoplementation
var ctx = document.getElementById(chart').getContext("2d");
var myChart = new Chart(ctx, {
type: 'bar',
responsive: true,
data: {
labels: ["test"]
datasets: [{
label: "Sfarzoso",
fill: false,
borderColor: '#000',
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
data: ["1"]
backgroundColor: ["#fff5f7"]
}]
},
});
How can i achieve such result?
You need to add options object and indicate not to display the legend
var options = {
legend: {
display: false
}
};
Then use the options in the constructor of your chart
var myChart = new Chart(ctx, {
type: 'bar',
responsive: true,
/* include options in the constructor */
options: options,
... }
See sample below
Documentation about options available are on their website: https://www.chartjs.org/docs/latest/getting-started/
var ctx = document.getElementById('chart').getContext("2d");
// add options object - indicate not to display the legend
var options = {
legend: {
display: false
}
};
var myChart = new Chart(ctx, {
type: 'bar',
responsive: true,
/* include options in the constructor */
options: options,
data: {
labels: ["test"],
datasets: [{
label: "Sfarzoso",
fill: false,
borderColor: '#000',
borderWidth: 2,
borderDash: [],
borderDashOffset: 0.0,
data: ["1"],
backgroundColor: ["#fff5f7"]
}]
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js"></script>
<canvas id="chart"></canvas>

ChartJS with Dynamic Colors

I saw your post regarding,
Instead of just "Stock" at the left, is there anyway to put a separate label for each bar, eg 18, 82, 22, 80 going down the y-axis?
Below is the link which I'm referring ...
ChartJS bar chart with legend which corresponds to each bar
You are looking for something like the following:
var chart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: [18, 82, 22, 80],
datasets: [{
data: [1, 2, 3, 4],
backgroundColor: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff'],
borderColor: ['#ff6384', '#36a2eb', '#ffce56', '#4bc0c0', '#9966ff']
}]
},
options: {
scales: {
xAxes: [{
ticks: {
beginAtZero: true
}
}]
},
legend: {
labels: {
generateLabels: function(chart) {
var labels = chart.data.labels;
var dataset = chart.data.datasets[0];
var legend = labels.map(function(label, index) {
return {
datasetIndex: 0,
text: label,
fillStyle: dataset.backgroundColor[index],
strokeStyle: dataset.borderColor[index],
lineWidth: 1
}
});
return legend;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>

How to render Chart.js 2.x tooltips on top of everything

I'm using Chart.js 2.6.0 and I have been working on an example to render custom graphics. You can see a live demo at: https://jsfiddle.net/arminzia/bm4ezdur/.
Basically I'm rendering circles on top of each bar to denote the value. here's the code:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
responsive: true,
maintainAspectRatio: false,
data: {
labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
datasets: [{
data: [16, 87, 56, 35, 88, 60, 12],
backgroundColor: "#4082c4"
}]
},
options: {
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index] + '$';
var centerX = bar._model.x;
var centerY = bar._model.y - 10;
var radius = 22;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'white';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#4082c4';
ctx.stroke();
ctx.fillStyle = '#4082c4';
ctx.font = "bold 14px Calibri";
ctx.fillText(data, bar._model.x, bar._model.y);
});
});
}
},
legend: {
"display": false
},
tooltips: {
"enabled": true
},
scales: {
yAxes: [{
display: true,
gridLines: {
display : true
},
ticks: {
display: true,
beginAtZero:true,
max: 140
}
}],
xAxes: [{
barThickness: 40,
gridLines: {
display : false
},
ticks: {
beginAtZero:true
}
}]
}
}
});
Now the problem is, tooltips are being hidden under these circles. I've been struggling with this for too long and haven't found any solution or anything useful from the docs.
How can I force tooltips to be rendered on top of these circles? On top of everything actually, something like z-index: 1000.
Forgot to update this post. The answer is to use External (Custom) Tooltips. That's basically rendering HTML elements to create tooltips. Read more on the docs here.