My data array has null values in chart.js. Is there a way to draw a line between the two segments to maintain visual progress? - frontend

As shown in the screenshot, there are days where I have a null value... I would like to connect the dataset with a line regardless of a particular day being null. Is this possible in chart.js 2.x?

You can set spangaps to true:
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, null, 2, 3],
borderColor: 'pink',
fill: false,
spanGaps: true
},
{
label: '# of Points',
data: [7, null, null, 8, 3, 7],
borderColor: 'orange',
fill: false,
spanGaps: true
}
]
},
options: {}
}
const 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/2.9.4/Chart.js"></script>
</body>

Related

Determine The Area Of A Point based on Background Color in Chart JS

As shown in the pictures below, I have a chart created with 'Chart JS'. This chart contains linear lines with various curves. I painted the areas between these lines with 'background color' in various colors.
My question is, when I create a random point on this chart, I just want to create an if statement based on colors.
For example,
There is the point called A and the variable called B.
If A point is in the yellow area, then B is 1.
If A point is in the light gray area, then B is 2.
Something like this.
Here is Picture:
Here is sample code:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>
<script type="text/javascript">
var x_A = new Array(2, 2, 2.5, 2.5, 2);
var y_A = new Array(2.5 , 3 , 3.5, 2.5 , 2.5);
var c_A = [];
for (var i = 0; i < x_A.length; i++) {
var obj = { x: x_A[i], y: y_A[i] };
c_A.push(obj);
}
var x_B = new Array(0, 1.5, 1.5, 0);
var y_B = new Array(0, 2, 0.5, 0);
var c_B = [];
for (var i = 0; i < x_B.length; i++) {
var obj = { x: x_B[i], y: y_B[i] };
c_B.push(obj);
}
var x_C = new Array(1.5, 1.5, 2, 2, 1.5);
var y_C = new Array(0.5, 2, 3, 2.5, 0.5);
var c_C = [];
for (var i = 0; i < x_C.length; i++) {
var obj = { x: x_C[i], y: y_C[i] };
c_C.push(obj);
}
var r_A = 'rgba(220, 20, 60,1)';
var r_B = 'rgba(255, 255, 56,1)';
var r_C = 'rgba(34, 139, 34,1)';
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'X',
showLine: true,
fill: true,
pointRadius: 7,
data: [{
x: 1,
y: 0.9
}],
borderWidth: 1,
pointBackgroundColor: "#000000",
lineTension: 0,
},
{
label:'Zone A',
showLine: true,
fill: true,
backgroundColor: r_A,
pointRadius: 0,
data: c_A,
borderWidth: 1,
borderColor: "#000000",
lineTension: 0,
},
{
label: 'Zone B',
showLine: true,
fill: true,
backgroundColor: r_B,
pointRadius: 0,
data: c_B,
borderWidth: 1,
borderColor: "#000000",
lineTension: 0,
},
{
label: 'Zone C',
showLine: true,
fill: true,
backgroundColor: r_C,
pointRadius: 0,
data: c_C,
borderWidth: 1,
borderColor: "#000000",
lineTension: 0,
},
]
},
options: {
title: {
display: false,
},
tooltips: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom',
gridLines:
{
display: false
},
scaleLabel: {
display: true
}
}],
yAxes: [{
gridLines:
{
display: false
},
scaleLabel: {
display: true,
}
}]
}
}
});
</script>
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
<html>
<body>
<div class="w3-row">
<div class="w3-col s3"><p></p></div>
<div class="w3-col s6" align="center"><canvas id="myChart" height="220"></canvas></div>
</div>
<div class="w3-row" align="center"><h2>Color Zone where the point X is located: </h2></div>
</body>
</html>
Here is CodePen:
My Sample Example: CodePen

Chartjs export chart without html

I'm trying to export a chart created with chartjs without an actual site it's just a node backend app that creates the chart, I then need to export it and send it to slack api.
I figured I would try to create a virtual dom and then export from there but is it not working. I'm open to other approaches or fixes to this code. I'm getting an error that says window is undefined, but if I console.log(window) it says it's a window object, and everything looks normal.
const JSDOM = require("jsdom");
const Chart = require("chart.js");
const dom = new JSDOM.JSDOM(`<!DOCTYPE html><canvas id="myChart" width="400" height="400"></canvas>`);
const canvas = dom.window.document.getElementById('myChart');
const ctx = canvas.getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Standing costs', 'Running costs'],
datasets: [{
label: 'Washing and cleaning',
data: [0, 8],
backgroundColor: '#22aa99'
}, {
label: 'Traffic tickets',
data: [0, 2],
backgroundColor: '#994499'
}, {
label: 'Tolls',
data: [0, 1],
backgroundColor: '#316395'
}, {
label: 'Parking',
data: [5, 2],
backgroundColor: '#b82e2e'
}, {
label: 'Car tax',
data: [0, 1],
backgroundColor: '#66aa00'
}, {
label: 'Repairs and improvements',
data: [0, 2],
backgroundColor: '#dd4477'
}, {
label: 'Maintenance',
data: [6, 1],
backgroundColor: '#0099c6'
}, {
label: 'Inspection',
data: [0, 2],
backgroundColor: '#990099'
}, {
label: 'Loan interest',
data: [0, 3],
backgroundColor: '#109618'
}, {
label: 'Depreciation of the vehicle',
data: [0, 2],
backgroundColor: '#109618'
}, {
label: 'Fuel',
data: [0, 1],
backgroundColor: '#dc3912'
}, {
label: 'Insurance and Breakdown cover',
data: [4, 0],
backgroundColor: '#3366cc'
}]
},
options: {
onAnimationComplete: animationDone,
responsive: false,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
});
function animationDone() {
return canvas.toDataUrl("image/jpg");
}
I just want an image file or url that I can send to slack api.
Use chartjs-node-canvas, this is a Node JS renderer for Chart.js using canvas.
It provides and alternative to chartjs-node that does not require jsdom (or the global variables that this requires) and allows chartJS as a peer dependency, so you can manage its version yourself.
This is how it will work with your code:
const { CanvasRenderService } = require('chartjs-node-canvas');
const width = 400;
const height = 400;
const chartCallback = (ChartJS) => {
// Global config example: https://www.chartjs.org/docs/latest/configuration/
ChartJS.defaults.global.elements.rectangle.borderWidth = 2;
// Global plugin example: https://www.chartjs.org/docs/latest/developers/plugins.html
ChartJS.plugins.register({
// plugin implementation
});
// New chart type example: https://www.chartjs.org/docs/latest/developers/charts.html
ChartJS.controllers.MyType = ChartJS.DatasetController.extend({
// chart implementation
});
};
const canvasRenderService = new CanvasRenderService(width, height, chartCallback);
(async () => {
const configuration = {
type: 'line',
data: {
labels: ['Standing costs', 'Running costs'],
datasets: [{
label: 'Washing and cleaning',
data: [0, 8],
backgroundColor: '#22aa99'
}, {
label: 'Traffic tickets',
data: [0, 2],
backgroundColor: '#994499'
}, {
label: 'Tolls',
data: [0, 1],
backgroundColor: '#316395'
}, {
label: 'Parking',
data: [5, 2],
backgroundColor: '#b82e2e'
}, {
label: 'Car tax',
data: [0, 1],
backgroundColor: '#66aa00'
}, {
label: 'Repairs and improvements',
data: [0, 2],
backgroundColor: '#dd4477'
}, {
label: 'Maintenance',
data: [6, 1],
backgroundColor: '#0099c6'
}, {
label: 'Inspection',
data: [0, 2],
backgroundColor: '#990099'
}, {
label: 'Loan interest',
data: [0, 3],
backgroundColor: '#109618'
}, {
label: 'Depreciation of the vehicle',
data: [0, 2],
backgroundColor: '#109618'
}, {
label: 'Fuel',
data: [0, 1],
backgroundColor: '#dc3912'
}, {
label: 'Insurance and Breakdown cover',
data: [4, 0],
backgroundColor: '#3366cc'
}]
},
options: {
responsive: false,
legend: {
position: 'right'
},
scales: {
xAxes: [{
stacked: true
}],
yAxes: [{
stacked: true
}]
}
}
};
const dataUrl = await canvasRenderService.renderToDataURL(configuration);
})();
dataUrl variable will contain the image you can pass to Slack API

Aligning labels in highchart donut

I'm trying to make a highchart donut with a legend on the side,
I'm really struggling to get the data labels to be more centered. At the moment each of them are in a different place,
an image of intended result:
https://codepen.io/mattdavidson/pen/qgqZyV
Highcharts.chart('container', {
credits: { enabled: false },
chart: { height: 300, width: 500, animation: false },
title: {
align: 'center',
verticalAlign: 'middle',
text: 10,
y: 25,
x: 55,
style: { color: '#333333', fontSize: '72px', fontWeight:'bold'},
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
format: '{point.y}',
distance: -25,
style: { fontSize: '32px', textOutline: 0 },
},
animation: false,
showInLegend: true,
},
},
legend: {
layout: 'vertical',
verticalAlign: 'middle',
align: 'left',
symbolHeight: 25,
symbolRadius: 5,
itemMarginTop: 10,
itemMarginBottom: 10,
},
series: [
{
type: 'pie',
innerSize: '55%',
colors: ['rgb(212,33,71)', 'rgb(250,189,43)', 'rgb(60,168,74)'],
data: [['Category 1', 4], ['Category 2', 5], ['Category 3', 1]],
},
],
});
There is an issue reported on Highcharts github about donut labels position. Check it here: https://github.com/highcharts/highcharts/issues/9005.
I've changed some options and added custom text using Highcharts.SVGRenderer#text (dynamic sum of all values) on the donut center. Perhaps it will help you: https://jsfiddle.net/BlackLabel/2jmqext9/.
Code:
Highcharts.chart('container', {
credits: {
enabled: false
},
chart: {
height: 300,
width: 500,
animation: false,
events: {
load: function() {
var chart = this,
offsetLeft = -20,
offsetTop = 10,
x = chart.plotLeft + chart.plotWidth / 2 + offsetLeft,
y = chart.plotTop + chart.plotHeight / 2 + offsetTop,
value = 0;
chart.series[0].yData.forEach(function(point) {
value += point;
});
chart.renderer.text(value, x, y).add().css({
fontSize: '30px'
}).toFront();
}
}
},
plotOptions: {
pie: {
dataLabels: {
enabled: true,
color: '#fff',
format: '{point.y}',
distance: -25,
style: {
fontSize: '20px',
textOutline: 0
},
},
animation: false,
showInLegend: true,
},
},
legend: {
layout: 'vertical',
verticalAlign: 'middle',
align: 'left',
symbolHeight: 15,
symbolRadius: 5,
symbolPadding: 10,
itemMarginTop: 10,
itemMarginBottom: 10,
itemStyle: {
fontSize: '15px'
}
},
series: [{
type: 'pie',
innerSize: '55%',
colors: ['rgb(212,33,71)', 'rgb(250,189,43)', 'rgb(60,168,74)'],
data: [
['Category 1', 4],
['Category 2', 2],
['Category 3', 12]
],
}, ],
});

Error ReferenceError: CanvasGradient is not defined

I am trying to create a line chart using chartjs-node package. Below is the code. When I give the data of dataset as a small set like data: [20, 15, 60, 60, 65, 30, 70], it works fine. But if I change it to a list that I want to populate as in dataFirst dataset below, I get the error "ReferenceError: CanvasGradient is not defined". I donot understand the reason. Please help. Thanks.
public createChart(cData) {
const chartNode = new chart(1000, 800);
const dataFirst = {
label: 'Heat Sink',
data: cData,
lineTension: 0.3,
fill: false,
borderColor: 'red',
backgroundColor: 'transparent',
pointBorderColor: 'red',
pointBackgroundColor: 'lightgreen',
pointRadius: 5,
pointHoverRadius: 15,
pointHitRadius: 30,
pointBorderWidth: 2,
pointStyle: 'rect',
};
const dataSecond = {
label: 'TVK Channel 9',
data: [20, 15, 60, 60, 65, 30, 70],
lineTension: 0.3,
fill: false,
borderColor: 'purple',
backgroundColor: 'transparent',
pointBorderColor: 'purple',
pointBackgroundColor: 'lightgreen',
pointRadius: 5,
pointHitRadius: 30,
pointBorderWidth: 2,
};
const chartOptions = {
legend: {
display: true,
position: 'top',
labels: {
boxWidth: 80,
fontColor: 'black',
},
},
};
const speedData = {
labels: ['0s', '10s', '20s', '30s', '40s', '50s', '60s'],
datasets: [dataFirst, dataSecond],
};
const chartJsOptions = {
type: 'line',
data: speedData,
options: chartOptions,
};
I found the solution. The number of labels should match the number of data points.
In canvas for node implementation you need to export CanvasGradient class yourself. According to this issue: https://github.com/Automattic/node-canvas/issues/990
You can do this:
["CanvasRenderingContext2D", "CanvasPattern", "CanvasGradient"].forEach(obj => {
console.log(obj, canvas[obj])
global[obj] = canvas[obj]
})

Flot chart with Threshold and Fillbetween

I'm looking for advice on how I should/can configure Flotcharts using the Fillbetween and Threshold pluggins to create a chart that accomplishes the following:
Plot a line chart. (done)
Set some threshold values. (done)
Set and fill values that are outside of the threshold values. (not quite done)
Here's what I've accomplished so far,
https://jsfiddle.net/gstoa/utv4kvw2/
$(function() {
var values = {
'avgBottom': [
[1, -2],
[2, -2],
[3, -2],
[4, -2],
[5, -2]
],
'avgTop': [
[1, 3],
[2, 3],
[3, 3],
[4, 3],
[5, 3]
],
'values': [
[1, .5],
[2, -3],
[3, .8],
[4, 4.5],
[5, 6.6]
]
};
var dataset = [{
data: values['values'],
lines: {
show: true
},
color: "rgb(50,50,255)"
}, {
id: 'avgBottom',
data: values['avgBottom'],
lines: {
show: true,
lineWidth: 0,
fill: false
},
color: "rgb(50,50,255)"
}, {
id: 'values',
data: values['values'],
lines: {
show: true,
lineWidth: 0.5,
fill: 0.2,
shadowSize: 0
},
color: "rgb(50,50,255)",
fillBetween: 'avgBottom'
}, {
id: 'avgTop',
data: values['avgTop'],
lines: {
show: true,
lineWidth: 0,
fill: 0.2
},
color: "rgb(50,50,255)",
fillBetween: 'values'
}];
$.plot($("#placeholder"), dataset, {
xaxis: {
tickDecimals: 0
},
series: {
lines: {
show: true,
fill: true
},
points: {
show: false,
radius: 4
},
color: "#62CB31",
// threshold: {
// below: -2,
// color: "rgb(255,0,0)"
// }
},
yaxis: {
tickFormatter: function(v) {
return v;
}
}
});
$.plot($("#placeholder"), [d1, d2, d3]);
});
I'd like this line chart to look like the following:
Any advice is greatly appreciated.
To do this, I had to switch from the fillbetween to the fillbelow flot plugin. I then had to modify the source of the fillbelow plugin to look at a new fillColor property of the series (I've got a pull request to merge these changes back into the main branch).
All in all, your new data set looks like the code snippet below (this JSFiddle demonstrates how to get the chart to look like your example image).
var dataset = [{
id: 'topValues',
data: values['values'],
lines: {
show: true,
},
color: "rgb(50,50,255)",
fillBelowTo: 'avgTop',
fillBelowUseSeriesObjectFillColor: false,
fillColor: "#FF0000"
}, {
id: 'avgTop',
data: values['avgTop'],
lines: {
show: true,
lineWidth: 0,
fill: true
},
color: "rgb(50,50,255)"
}, {
id: 'bottomValues',
data: values['values'],
lines: {
show: true,
lineWidth: 0,
shadowSize: 0
},
color: "rgb(50,50,255)"
}, {
id: 'avgBottom',
data: values['avgBottom'],
lines: {
show: true,
lineWidth: 0,
fill: true,
},
fillBelowTo: 'bottomValues',
fillBelowUseSeriesObjectFillColor: false,
fillColor: "#FF0000",
color: "rgb(50,50,255)"
}];
The fillBelowTo property acts similarly to the fillBetween
property of the fillbetween plugin - it denotes to which series you'd
like to fill below to.
The fillBelowUseSeriesObjectFillColor
property (set to false) tells us to not use the lines.fillColor
color and instead use the fillColor value. If fillBelowUseSeriesObjectFillColor was true, the lines.fillColor color would be used (which in this case would be blue).

Resources