Javascript ChartJS updating chart and canvas permanently - javascript

I made a chart in chartJS and I would like to update it using new data based on what the user chooses from a drop down list, using the same canvas. The problem is when i do the update function, the chart updates with the new data but it keeps coming back to the original chart after a while. How can i solve this? Here's the code, thank you for any help:
/* Original Chart */
var ctx3 = document.getElementById("canvas3").getContext("2d");
var canvas3 = new Chart(ctx3, {
type: 'line',
data: {
labels: stationRentalsLabels,
datasets: [{
label: 'Wypożyczenia',
fillColor: "rgba(220,280,220,0.5)",
strokeColor: "rgba(220,220,220,1)",
backgroundColor: "rgba(153,255,51,0.4)",
data: stationRentalsData
}]
}
});
/* event listener on drop-down list, when triggered, update chart */
select.addEventListener('change', function() {
updateChart()
});
/* Update Chart */
function updateChart() {
var stationRentalsHoursTemp = [];
var stationRentalName = [];
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
for (var i = 0; i < stationRentalsHours.length; i++) {
if (determineHour == stationRentalsHours[i]) {
stationRentalsHoursTemp.push(stationRentalsData[i])
stationRentalName.push(stationRentalsLabels[i]);
}
}
/* Updated Chart */
var ctx3 = document.getElementById("canvas3").getContext("2d");
var canvas3 = new Chart(ctx3, {
type: 'line',
data: {
labels: stationRentalName,
datasets: [{
label: 'Wypożyczenia',
fillColor: "rgba(220,280,220,0.5)",
strokeColor: "rgba(220,220,220,1)",
backgroundColor: "rgba(153,255,51,0.4)",
data: stationRentalsHoursTemp
}]
}
});
}

You are creating new chart on update function in the same div as before but in order to do that you need to destroy the previous instance of the chart by calling the destroy function before calling the updateChart function.
canvas3.destroy();
Another approach to solving your problem is by replacing the data not the chart itself when the updateChart function is called by calling the update function(Not initializing a new chart)
function updateChart() {
var stationRentalsHoursTemp = [];
var stationRentalName = [];
var determineHour = selectNumber.options[selectNumber.selectedIndex].innerHTML;
for (var i = 0; i < stationRentalsHours.length; i++) {
if (determineHour == stationRentalsHours[i]) {
stationRentalsHoursTemp.push(stationRentalsData[i])
stationRentalName.push(stationRentalsLabels[i]);
}
}
// just update the label and dataset not the entire chart
canvas3.data.labels = stationRentalName;
canvas3.data.datasets[0].data = stationRentalsHoursTemp;
canvas3.update();
}

Related

Drawing images on top of graph doesn't work with ChartJS

I'm trying to label a pie chart with icons that I'd draw on with the drawImage() function, but it's not working. Here's my code:
var config = {
type: 'pie',
data: {
datasets: [{
data: [
"1",
"2"
]
}],
labels: [
"1",
"2"
]
}
};
var ctx = document.getElementById('Chart1').getContext('2d');
var myChart = new Chart(ctx, config);
var image = new Image();
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC';
image.onload = () => {
ctx.drawImage(image, 0, 0, 100, 100)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="Chart1"></canvas>
I want it to draw the image on top of the chart, but it's not working, any ideas?
The issue is that chartJs constantly updates the canvas by clearing it and re-rendering the whole thing, like on hovering and mouse movement to add the labels and do some animations, so anything you add to the canvas will be lost.
The workaround in the github discussion regarding the same issue is the way to go. You just need to create a new chart type extending the existing chart type you want to use where you can override the draw method of the new chart type to do the extra stuff you want, the syntax for extending the charts has changed since the github discussion, so we'll use the new one:
Chart.defaults.pieWithExtraStuff = Chart.defaults.pie; // the name of the new chart type is "pieWithExtraStuff"
Chart.controllers.pieWithExtraStuff = Chart.controllers.pie.extend({ // creating the controller for our "pieWithExtraStuff" chart by extending from the default pie chart controller
draw: function(ease) { // override the draw method to add the extra stuff
Chart.controllers.pie.prototype.draw.call(this, ease); // call the parent draw method (inheritance in javascript, whatcha gonna do?)
var ctx = this.chart.ctx; // get the context
if (this.labelIconImage) { // if the image is loaded
ctx.drawImage(this.labelIconImage, 0, 0, 100, 100); // draw it
}
},
initialize: function(chart, datasetIndex) { // override initialize too to preload the image, the image doesn't need to be outside as it is only used by this chart
Chart.controllers.pie.prototype.initialize.call(this, chart, datasetIndex);
var image = new Image();
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC';
image.onload = () => { // when the image loads
this.labelIconImage = image; // save it as a property so it can be accessed from the draw method
chart.render(); // and force re-render to include it
};
}
});
var config = {
type: "pieWithExtraStuff", // use our own chart type, otherwise what's the point?
data: { /* ... */ }
};
var ctx = document.getElementById('Chart1').getContext('2d');
var myChart = new Chart(ctx, config);
Now whenever the pieWithExtraStuff chart re-renders, it will also draw the image.
Demo:
Chart.defaults.pieWithExtraStuff = Chart.defaults.pie;
Chart.controllers.pieWithExtraStuff = Chart.controllers.pie.extend({
draw: function(ease) {
Chart.controllers.pie.prototype.draw.call(this, ease);
var ctx = this.chart.ctx;
if (this.labelIconImage) {
ctx.drawImage(this.labelIconImage, 0, 0, 100, 100);
}
},
initialize: function(chart, datasetIndex) {
Chart.controllers.pie.prototype.initialize.call(this, chart, datasetIndex);
var image = new Image();
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAA1BMVEX/AAAZ4gk3AAAASElEQVR4nO3BgQAAAADDoPlTX+AIVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwDcaiAAFXD1ujAAAAAElFTkSuQmCC';
image.onload = () => {
this.labelIconImage = image;
chart.render();
};
}
});
var config = {
type: "pieWithExtraStuff",
data: {
datasets: [{
data: [
"1",
"2"
]
}],
labels: [
"1",
"2"
]
}
};
var ctx = document.getElementById('Chart1').getContext('2d');
var myChart = new Chart(ctx, config);
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="Chart1"></canvas>

Pass context to options on React ChartJS 2

I'm using React ChartJS 2 to create some graphs but I want to show a label in top of them with the percentage and when I hover over them the real number. I found you can do something like this using the context on the options object.
var options = {
tooltips: {
enabled: false
},
plugins: {
datalabels: {
formatter: (value, ctx) => {
let datasets = ctx.chart.data.datasets;
if (datasets.indexOf(ctx.dataset) === datasets.length - 1) {
let sum = datasets[0].data.reduce((a, b) => a + b, 0);
let percentage = Math.round((value / sum) * 100) + '%';
return percentage;
} else {
return percentage;
}
},
color: '#fff',
}
}
};
var ctx = document.getElementById("pie-chart").getContext('2d');
var myChart = new Chart(ctx, {
type: 'pie',
data: {
datasets: data
},
options: options
});
Like this, but my problem is that I cannot get a way to use the context inside the options.
Does someone knows how to do this?
You don't have to manually pass the context to the datalabels' formatter function since the plugin takes care of this itself.
Here's a working example of the pie graph with the options specified above.
But if you want to access the chart's context in some other functions you want to pass to the options, then you can get it through the chart instance by using this.chart.ctx.
var options = {
animation: {
onComplete: function () {
var chartInstance = this.chart;
var ctx = chartInstance.ctx; // chart context
}
}
};

show maximum labels in chart.js

I am creating a project using JavaScript. In my project i am integrating google charts, In my chart i want to show only five labels.I don't know how can i do this.Here is code:
var N = 10;
// Array filled with N values at '0'
var zero_array = [];
for (i = 0; i < N; i++)
zero_array.push(0);
// The data of the chart, describe the differents sets of data you want with points, colors...
var data = {
labels: zero_array,
datasets: [
{
showXLabels: 5,
label: zero_array, // Name of the line
data: zero_array, // data to represent
// The following makes the line way less ugly
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
}
]
};
// We wait for everything to be loaded
window.onload = function main() {
// Get the context of the canvas
var ctx = document.getElementById("line_example").getContext("2d");
// Create the Chart object
var line_example_chart = new Chart(ctx).Line(data);
// Used for the labels on the X axis
var label_idx = 1;
// Function to execute to remove then add a new random value to the chart
function rand_value() {
// Generate a random integer
var rand_val = Math.floor(Math.random() * 100);
// Remove the point at the far left of the chart
line_example_chart.removeData();
// Add the random value at the far right of the chart
line_example_chart.addData([rand_val], label_idx++);
}
// Run rand_value() every 2 seconds
window.setInterval(rand_value, 2000);
}
plunker link:
https://plnkr.co/edit/fat6hRS4lFnAEjoiSORW?p=preview
please help.
Looking at your code, just change N to 5:
var N = 5;
https://plnkr.co/edit/eJP4G6bYuGB5NaYvcQGX?p=preview
Please update below line and you can see only 5 nodes in your chart
var N = 5;

How to display only last point on highcharts and that point should travel with chart line?

I have a area chart which is having a dynamic point that will be added to chart.I got this http://jsfiddle.net/rjpjwve0/
but it looks like the point gets displayed first and then after a delay the chart draws back. Now i want to display the last point which will be a animated point and it should travel with chart without delay in rendering.
Could any one help me to achieve this.
I put together a test, and it seems to work well.
I updated the load event to add a second series, using the same series.data[len -1] values; then in the setInterval portion, we update that new point at each iteration.
That way, by updating the existing marker rather than destroying one marker and creating another, the animation works as desired.
Code:
events: {
load: function () {
var series = this.series[0],
len = series.data.length;
//-------------------------------------
//added this part ->
this.addSeries({
id: 'end point',
type: 'scatter',
marker: {
enabled:true,
symbol:'circle',
radius:5,
fillColor:'white',
lineColor: 'black',
lineWidth:2
},
data: [[
series.data[len - 1].x,
series.data[len - 1].y
]]
});
var series2 = this.get('end point');
//-------------------------------------
setInterval(function () {
var x = (new Date()).getTime(),
y = Math.random();
len = series.data.length;
series.addPoint([x,y], true, true);
//and added this line -->
series2.data[0].update([x,y]);
}, 1000);
}
}
Fiddle:
http://jsfiddle.net/jlbriggs/a6pshutt/
You can try this :
series: [{
name: 'Random data',
marker : {
enabled : false,
lineWidth: 0,
radius: 0
},
data: (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -19; i <= 0; i += 1) {
data.push({
x: time + i * 1000,
y: Math.random()
});
}
return data;
}())
}]
Its works.
Greg.

Highcharts - rewrite data from one chart to another

In my example, the data is generated randomly. After click on button, zoom type should be changed.
$(function() {
var chartOptions={
chart:{
zoomType : 'x',
events : {
load : function() {
var series = this.series[0];
var chart = this;
setInterval(function() {
var x = (new Date()).getTime(),
y = Math.round(Math.random() * 100);
series.addPoint([x, y]);
chart.redraw();
}, 1000);
}
}
},
series : [{
name : 'AAPL',
data : [null]
}]
};
$('#container').highcharts('StockChart', chartOptions);
$('#button').click(function() {
var chart1 = $('#container').highcharts();
//alert(chart1.series[0].yData);
chartOptions.chart.zoomType = 'y';
$('#container').highcharts(chartOptions);
});
});
After click button, the old chart disappears but the new one is not generated.
Firebug shows TypeError: e is undefined and in the line series.addPoint([x, y]); shows series is undefined.
chartOptions is global so in the click handler, one property (zoomType) is changed and the rest should be the same.
alert(chart1.series[0].yData); shows the propery y data. So I tried:
$('#button').click(function() {
var chart1 = $('#container').highcharts();
//alert(chart1.series[0].yData);
chartOptions.chart.zoomType = 'y';
var chart2 = $('#container').highcharts(chartOptions);
chart2.series[0].setData(chart1.series[0].data);
chart2.redraw();
});
Then firebug shows chart2.series is undefined.
You cannot update zoom type in highcharts, without destroy() chart and create new instance. In other words, you should use
chart1.destroy()
var chart2 = $('#container').highcharts(chartOptions);
In case when you would like set range on any axis (zoom chart) you can use setExtremes() function http://api.highcharts.com/highstock#Axis.setExtremes()
When chartOptions or chart2.series is undefinded you need to use $.extend({},chartoptions)
$('#container').highcharts($.extend({},chartoptions);

Categories