I've got a problem with chartJS. I'm calling a function to create a new chart. The creation works, but I would like to destroy any previous charts, so that I get a new one when calling a function.
This is my code at the moment:
var chartID;
function addData(chartType,data) {
for (var i = 0; i < data.length; i++) {
dataLabels.push(data[i][0]);
dataPoints.push(data[i][1]);
//console.log(data[i][1]);
}
if(chartID){
console.log('destroy');
chartID.destroy();
}
var ctx = document.getElementById('chart01').getContext('2d');
chartID = new Chart(ctx, {
type: chartType,
data: {
labels: dataLabels,
datasets: [{
label: 'Labels',
data: dataPoints,
backgroundColor: '#333'
}]
},
options: {
maintainAspectRatio: false,
aspectRatio: 1
}
});
}
Even I had the same issue earlier. I simply added a condition to check the chart variable is empty or not.
if(chartID != null){
chartID.destroy();
}
Include this at the top of the function. It'll work fine as you are declaring chartID globally. This way you don't need to redeclare the chart again.
Try this:
const chartCanvas = document.getElementById('myChart');
if( window.lineChart != undefined){
window.lineChart.destroy();
}
window.lineChart = new Chart(chartCanvas,{
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [
{
label: 'Cases',
data: [23,42,22,45,56,77,33,22,46,77,32,44],
fill: false,
// backgroundColor: 'red',
borderColor: ['rgb(255, 255, 0)'],
lineTension: 0.2,
borderWidth: 1.5
}
]
},
options:{
title: {
display: true,
text: "Temperature variation",
fontFamily: 'Arial',
fontSize: 16
},
legend: {
display: true,
position: "right",
labels: {
boxWidth:10
}
},
//stacked - start with 0 as minimum value for y-axis
scales:{
yAxes: [{
stacked: true,
gridLines:{
display: true,
color: '#FFFFFF',
lineWidth: 1,
zeroLineColor: 'blue',
zeroLineWidth: 2,
drawBorder: false // this to remove the ghost line that appears
// when you add zeroLine x-axis
}
}],
xAxes: [{
gridLines:{
display: true,
zeroLineColor: 'blue',
zeroLineWidth: 1,
color: 'transparent'
}
}]
}
}
});
----------------- Added code sample above ------------------
I had some issues with ChartJs. Somehow, it created a new chart with the previous chart still in the canvas which shows up when you hover.
This worked for me:
if( window.chartID!= undefined){
window.chartID.destroy();
}
chartID = new Chart(ctx, {...});
I am creating multiple charts on click.
but before creating chart I just destroy any previous charts
so , thats how it looks
var chartStatus
// on one onclick
if (chartStatus) { chartStatus.destroy(); }
chartStatus = new Chart(document.getElementById("co2Chart"), co2Config);
// on another onclick
if (chartStatus) { chartStatus.destroy(); }
chartStatus = new Chart(document.getElementById("tempChart"), tempConfig);
Related
I've got a line chart that has a tooltip on each data point. The data are prices so I want to add a euro sign before them but this seems harder than it sounds.
My code:
const labelsjaar = [
'jan',
'feb',
'mrt',
'apr',
'mei',
'jun',
'jul',
'aug',
'sept',
'okt',
'nov',
'dec',
];
const datajaar = {
labels: labelsjaar,
datasets: [{
label: 'Omzet',
backgroundColor: 'rgb(230 0 126)',
borderColor: 'rgb(230 0 126)',
data: [0,0,0,0,0,0,0,24,177,590.44,801.38,98.62],
}]
};
Chart.defaults.font.family = 'Panton';
Chart.defaults.font.size = 16;
const configjaar = {
type: 'line',
data: datajaar,
options: {
maintainAspectRatio: false,
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function (tooltipItems, data) {
var i = tooltipItems.index;
return data.labels[i] + ': ' + data.datasets[0].data[i] + ' €';
}
}
}
}
};
const myChartjaar = new Chart(
document.getElementById('myChartjaar'),
configjaar
);
I found this solution online:
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label: function (tooltipItems, data) {
var i = tooltipItems.index;
return data.labels[i] + ': ' + data.datasets[0].data[i] + ' €';
}
}
}
But my tooltips remain unchanged, there is no euro sign to be seen.
What am I doing wrong?
A jsfiddle of my chart can be seen here: https://jsfiddle.net/r4nw91bo/
After the comment below that I was looking at the wrong documentation I tried the following:
const labeltext = (tooltipItems) => {
tooltipItems.forEach(function(tooltipItem) {
tooltiplabel = '€' + tooltipItem.parsed.y.toLocaleString();
});
return tooltiplabel;
};
const configjaar = {
type: 'line',
data: datajaar,
options: {
plugins:{
tooltip:{
callbacks: {
label: labeltext,
}
}
},
maintainAspectRatio: false,
}
};
But this gives me the error: tooltipItems.forEach is not a function. If instead of label I use footer or title it works perfectly, but I don't want to add a title or a footer to my tooltip, I want to replace the existing content with my added € sign.
I also tried using their example for adding a dollar sign like this:
const configjaar = {
type: 'line',
data: datajaar,
options: {
plugins:{
tooltip:{
callbacks: {
label: function(context) {
const label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(context.parsed.y);
}
return label;
}
}
}
},
maintainAspectRatio: false,
}
};
But on hover of a data point this gives an error: Assignment to constant variable.
This is because you are using V2 syntax in V3, V3 has some major breaking changes over V2. Please read the migration guide for all of them.
For your callback to work you need to define it in options.plugins.tooltip.callbacks.label
EDIT:
Like the error says you are getting you can't reassign a constant variable since its a constant. If you change it to a let it works fine:
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'
}]
},
options: {
plugins: {
tooltip: {
callbacks: {
label: function(context) {
let label = context.dataset.label || '';
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(context.parsed.y);
}
return label;
}
}
}
},
}
}
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/3.6.0/chart.js"></script>
</body>
I want to plot an area fill line chart with multiple series, using javascript & RGraph, for a period between two dates, but I do not have data points for every date; how do I do this with RGraph?
I cannot miss out dates in the data I pass to RGraph because although some of the series do not have that data, it might be that other series do (e.g. ABC has data for January and March, and XYZ has data for January and April).
I must have all dates for the year, which is represented with a horizontal axis showing just the month/period labels.
I have boiled this down to a simplified example below, and with a jsFiddle example on https://jsfiddle.net/Abeeee/25m1sc7d/1/
Both the code below and the JSFiddle show two charts controlled by the drawAll() function, which has a variable x in it. I want the second chart (cvs2) which uses x=null to not include plotting that null but simply draw the red line/area between 100 and 200, resulting a similar chart to the first one (cvs1).
<!DOCTYPE HTML>
<html>
<head>
<script src='https://www.rgraph.net/libraries/RGraph.common.core.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.dynamic.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.effects.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.key.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.common.tooltips.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.drawing.rect.js'></script>
<script src='https://www.rgraph.net/libraries/RGraph.line.js'></script>
<script src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js'>
</script>
</head>
<body>
<canvas id='cvs1' width='900' height='300' style='border:solid 1pt red'>
[No canvas support]
</canvas>
<hr>
<canvas id='cvs2' width='900' height='300' style='border:solid 1pt blue'>
[No canvas support]
</canvas>
<script type='text/Javascript'>
drawAll();
$(window).resize(function() {
drawAll();
});
function drawAll() {
var x=150;
var data = [[0, 50, 100, x, 200],[10,20,30,40,50]];
drawChart('cvs1', data);
x=null;
var data = [[0, 50, 100, x, 200],[10,20,30,40,50]];
drawChart('cvs2', data);
}
function drawChart(canvasId, data) {
var canvas = document.getElementById(canvasId);
RGraph.Reset(canvas);
canvas.width = $(window).width() * 0.9;
var text_size = Math.min(10, ($(window).width() / 1000) * 20 );
var linewidth = $(window).width() > 500 ? 2 : 1;
linewidth = $(window).width() > 750 ? 3 : linewidth;
var line = new RGraph.Line(canvasId, data);
line.set('chart.text.size', text_size);
line.Set('chart.background.barcolor1', 'rgba(255,255,255,1)');
line.Set('chart.background.barcolor2', 'rgba(255,255,255,1)');
line.Set('chart.background.grid.color', 'rgba(238,238,238,1)');
line.Set('chart.colors', [ 'red', 'green', 'blue']);
line.Set('chart.linewidth', 1);
line.Set('chart.hmargin', 15);
line.Set('chart.labels', ['Q1\n2017','Q2','Q3','Q4','Q1\n2018']);
line.Set('chart.gutter.left',40);
line.Set('chart.gutter.right',10);
line.Set('chart.gutter.bottom',50);
line.Set('chart.filled', true);
line.Set('chart.filled.accumulative',true);
line.Set('chart.key', ['ABC', 'DEF']);
line.Set('chart.tickmarks.dot.color','white');
line.Set('chart.backgroundGridAutofitNumvlines',data.length);
line.Set('key.position','gutter'); // or graph
line.Set('chart.ymin',0);
line.Set('chart.ymax',250);
line.Set('chart.numyticks',5);
line.Set('chart.key.position.x',50);
line.Set('chart.key.position.y',10);
line.draw();
}
</script>
</body>
</html>
So, how do you tell RGraph to just draw the points with data and ignore those without whilst keeping all the date points?
Thanks
Abe
You can use null values in your data. The behaviour is slightly different for a single dataset vs multiple data sets though:
var data = [4,8,6,3,5,4,2,null,8,6,3,5,8,null,4,9,8];
Well it seems that RGraph doesn't do it, so I've resorted to ChartJS and on the whole it works - see https://jsfiddle.net/Abeeee/6xrk1m23/41/
<script type='text/JavaScript' src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.js'></script>
<div style="width:100%; height:300px">
<canvas id="canvas" style='width:100%; height:300px'></canvas>
</div>
<button id='on'>
Span Gaps=true
</button>
<button id='off'>
Span Gaps=false
</button>
var config = {
type: 'line',
data: {
labels: ['Jan\n2018', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
datasets: [{
label: 'Red',
borderColor: '#FF0000',
backgroundColor: '#FF0000',
data: [
10, 20, 30, 40, 50, 60, undefined, 80, 90, 100, 90, 80
],
}, {
label: 'Blue',
borderColor: '#0000FF',
backgroundColor: '#0000FF',
data: [
10, 20, undefined, 40, 50, 60, 70, 80, 92, undefined, 90, 80
],
}]
},
options: {
spanGaps: true,
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'Chart.js Line Chart - Stacked Area'
},
tooltips: {
mode: 'index',
},
hover: {
mode: 'index'
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'Month'
}
}],
yAxes: [{
stacked: true,
scaleLabel: {
display: true,
labelString: 'Value'
}
}]
}
}
};
var ctx1 = document.getElementById('canvas').getContext('2d');
var myChart = new Chart(ctx1, config);
$("#on").on("click", function() {
myChart.options.spanGaps=true;
myChart.update();
});
$("#off").on("click", function() {
myChart.options.spanGaps=false;
myChart.update();
});
Use the buttons to switch spanGaps on and off.
Note, I say on the whole, as it fixes my problem (of underlying data gaps), but it seems to fail to span if the dataset is sitting on top of another (a ChartJS bug perhaps?)
Just wondering if there is any way to set the horizontal bar labels for y-axis using chart.js. Here is how I set up the chart:
<div class="box-body">
<canvas id="chart" style="position: relative; height: 300px;"></canvas>
</div>
Javascript:
var ctx = document.getElementById('chart').getContext("2d");
var options = {
layout: {
padding: {
top: 5,
}
},
responsive: true,
animation: {
animateScale: true,
animateRotate: true
},
};
var opt = {
type: "horizontalBar",
data: {
labels: label,
datasets: [{
data: price,
}]
},
options: options
};
if (chart) chart.destroy();
chart= new Chart(ctx, opt);
chart.update();
As you all can see, the first and third labels are too long and cut off. Is there a way to make the label multi-line?
If you want to have full control over how long labels are broken down across lines you can specify the breaking point by providing labels in a nested array. For example:
var chart = new Chart(ctx, {
...
data: {
labels: [["Label1 Line1:","Label1 Line2"],["Label2 Line1","Label2 Line2"]],
datasets: [{
...
});
You can use the following chart plugin :
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
add this followed by your chart options
ᴜꜱᴀɢᴇ :
add a new line character (\n) to your label, wherever you wish to add a line break.
ᴅᴇᴍᴏ
var chart = new Chart(ctx, {
type: 'horizontalBar',
data: {
labels: ['Jan\n2017', 'Feb', 'Mar', 'Apr'],
datasets: [{
label: 'BAR',
data: [1, 2, 3, 4],
backgroundColor: 'rgba(0, 119, 290, 0.7)'
}]
},
options: {
scales: {
xAxes: [{
ticks: {
beginAtZero: true
}
}]
}
},
plugins: [{
beforeInit: function(chart) {
chart.data.labels.forEach(function(e, i, a) {
if (/\n/.test(e)) {
a[i] = e.split(/\n/);
}
});
}
}]
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx"></canvas>
I am using primeng chart component which uses chartjs. We are using chartjs 2.5.0 alongside primeng 4.0 and angular 4.
I created a dynamic chart and I put the data into chart after it came to us through some services. The problem is, after a while chartjs will put a gap at first and end of the chart.
Here is our options for chartjs:
this.options = {
responsive: true,
tooltips: {
mode: 'index',
intersect: false, // all points in chart to show tooltip
callbacks: { // adding labels as title in tooltip
title: function(tooltipItems, data) {
let date = tooltipItems[0].xLabel;
return me._rhDatePipe.transform(date, 'time');
}
}
},
hover : {
mode: 'index',
intersect: false
},
scales: {
xAxes: [{
type: 'time',
display: false, // preventing labels from being displayed
max: 20
}],
yAxes: [{
ticks: {
maxTicksLimit: 3
}
}]
}
}
and here is our first data settings:
this.data = {
labels: this.labels, // current time as label
datasets: [
{
label: me._messageService.translate('chart-label-buy'),
data: this.buyingData,
fill: false,
borderColor: "#2453db",
lineTension: 0,
borderWidth: 1.5,
radius: 0 // removing dot points on chart
},
{
label: me._messageService.translate('chart-label-sale'),
data: this.sellingData,
fill: false,
borderColor: "#f44336",
borderWidth: 1.5,
lineTension: 0,
radius: 0 // removing dot points on chart
},
{
label: me._messageService.translate('chart-label-last-trade'),
data: this.lastPriceData,
fill: false,
borderColor: "#000000",
lineTension: 0,
borderWidth: 1.5,
radius: 0 // removing dot points on chart
}
]
}
and here is the loop which will update the chart:
if(sortedKeysList != null) {
for(let key in sortedKeysList) {
let currentTime: number = sortedKeysList[key];
// just add new points
if(!this.currentTimes.includes(currentTime)) {
let date = new Date(currentTime);
this.labels.push(date);
this.currentTimes.push(currentTime);
this.buyingData.push(this.bestLimitsChart[currentTime].buy);
this.sellingData.push(this.bestLimitsChart[currentTime].sale);
if(this.bestLimitsChart[currentTime].price != 0)
this.lastPriceData.push(this.bestLimitsChart[currentTime].price);
else
this.lastPriceData.push(null);
this.updateChart();
}
}
}
and the picture of chart:
I do not know what is going on. Any helps will greatly appreciated.
I finally found the problem,
for other people facing this issue, you can add unit to your axis:
xAxes: [{
type: 'time',
time: {
displayFormats: {
minute: 'h:mm', // formatting data in labels
},
unit: 'minute' // destroy first and end gaps
},
display: false, // preventing labels from being displayed
}],
similar issue on github:
https://github.com/chartjs/Chart.js/issues/2277#issuecomment-314662961
Can we show a message using highcharts.When the data is not available? we have to show a message Example : No Data Available. If we have data hide : No Data Available message . in highcharts dynamically
Highcharts.chart('container', {
chart: {
type: 'bubble',
plotBorderWidth: 0,
zoomType: 'xy'
},
});
Include no-data-to-display.js file in your page. It comes bundled with highcharts. You can get it here otherwise: https://code.highcharts.com/modules/no-data-to-display.js
Default message is "No data to display". If you would like to modify it, you can do this:
Highcharts.setOptions({
lang: {
noData: 'Personalized no data message'
}
});
You can use Highcharts Chart Renderer
Here's an example in JSFiddle
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
series: []
}, function(chart) { // on complete
chart.renderer.text('No Data Available', 140, 120)
.css({
color: '#4572A7',
fontSize: '16px'
})
.add();
});
Some of these other answers seem kind of crazy... here's a super basic solution I wanted to share:
Highcharts.setOptions({lang: {noData: "Your custom message"}})
var chart = Highcharts.chart('container', {
series: [{
data: []
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/no-data-to-display.js"></script>
<div id="container" style="height: 250px"></div>
Hope this helps someone
Based on your comment (if we have data still showing no data available message so,can we hide in highcharts if we have data).I think you are using fustaki's solution and don't want to use no-data-to-display.js module. Yes there is problem as mentioned .You can still use the same code by modifying it i.e add condition inside continuing function to check if series is empty or not, based on this render message.
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
xAxis: {
categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
},
series: []
}, function(chart) { // on complete
if (chart.series.length < 1) { // check series is empty
chart.renderer.text('No Data Available', 140, 120)
.css({
color: '#4572A7',
fontSize: '16px'
})
.add();
}
});
Fiddle demo
For me with latest version it works like this:
const Highcharts = require('highcharts');
import NoDataToDisplay from 'highcharts/modules/no-data-to-display';
NoDataToDisplay(Highcharts);
Highcharts.setOptions({
lang: {
noData: 'No data is available in the chart'
}
});
With the current version (v7.1.2) and connected no-data-to-display module (v7.1.2) you can show your 'no data' message when you create a chart object as Patrik said by setting lang.noData option.
To be able to change this message after the chart is created you need to call method
yourChartObject.showNoData('you new message')
<script src="https://code.highcharts.com/modules/no-data-to-display.js"></script>
Highcharts.chart('container', {
lang: {
noData: "No data found"
},
noData: {
style: {
fontWeight: 'bold',
fontSize: '15px'
}
},
.
.
});
and then after series you should add:
lang: {
noData: 'Nessun dato presente'
},
noData: {
style: {
fontWeight: 'bold',
fontSize: '15px',
color: '#303030'
}
},
and it will work just fine