c3.js set onClick property in chart generated from another function - javascript

My goal is to get 3 charts, with the most recently selected series in the first chart updating the second chart, and the most recently selected series in the second chart updating the third chart.
I start by setting up 3 divs:
<div id="chart1"></div>
<div id="chart2"></div>
<div id="chart3"></div>
I then generate 3 charts like so (essentially the same, but with different detail levels in the source data):
var chart1 = c3.generate({
bindto: document.getElementById('chart1'),
data: {
x: 'date',
url: 'file1.csv'
},
axis: {
x: {
type: 'timeseries',
tick: {
format: '%Y-%m-%d',
count: 8
},
label: "Date"
},
y: {
label: "Y Label"
}
},
// irrelevant options removed
legend: {
item: {
onclick: (id) => {
chart1.toggle(id);
chart_options2.data.url = 'file2_'+ id +'.csv';
if(chart1.data.shown(id).length == 1 ){
generateChart2(id);
}
}
}
}
});
var chart2 = c3.generate({
bindto: document.getElementById('chart2'),
// etc.
var chart3 = c3.generate({
bindto: document.getElementById('chart3'),
// etc.
The function generateChart2() will use the id of the selected series in chart1 to generate a new chart in the place of chart2. Likewise I have a similar function generateChart3() which will use the id of the selected series in chart2 to generate a new chart in the place of chart3. These functions look like this:
function generateChart2(id) {
c3.generate(chart_options2);
};
With chart_options being identical to the original set up options, except for the updated file source (see chart_options2.data.url = 'file2_'+ id +'.csv'; above).
Initially, these all seem to work ok. The problem arises when a new chart2 is created using the generateChart2() function, and the onclick property no longer seems to work for certain things. Testing with console.log, the onclick still seems to be called, and I can update the chart options var, but I can't use any of the other commands:
onclick: function (id) {
console.log('test'); // returns 'test'
chart2.toggle(id); // doesn't work
chart_options3.data.url = 'file3_'+ id +'.csv'; // works
if(chart2.data.shown(id).length == 1 ){
generateChart3(id); // doesn't work
}
I suspect it has something to do with the namespace, or how I'm using the chart names, or how I'm calling the function. I've spent a couple of days looking at this problem, but all my research hasn't really made it much clearer which direction I should be looking in.
EDIT: I found a workaround, which makes sense for my use case, but doesn't help me learn what I was doing wrong. Now instead of reusing c3.generate to dynamically create a new chart every time a series is selected in the previous chart, I am using unload() and load(). This seems to be working well, but I would very much appreciate an explanation or clarification of what I was doing wrong the first time. Updated code:
onclick: function (id) {
chart1.toggle(id);
if(chart1.data.shown(id).length == 1 ){
chart2.unload();
setTimeout(function () {
chart2.load({
url: 'file2_'+ id +'.csv'
});
}, 1000);
}
}

Related

Make events run multiple times, Highcharts

I have a Highchart in which under the options object I have events object as ashown below.
var options = {
chart: {
renderTo: 'container',
type: 'line',
animation: Highcharts.svg, // don't animate in old IE
marginRight: 10,
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
So what I want is that I need events data to update dynamically and load the Highcharts only once.
How can I make the Following section dynamic so that the values in it change dynamically. Keeping in mind that Highcharts container have to be defined and load only once.
events: {
load: function() {
var series = this.series[0],
chart = this;
...// Some Code
}
}
One of the official Highcharts demos shows how to achieve it. Take a look at it:
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
}, 1000);
https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/dynamic-update/
Highcharts also offers other options to update the chart with new data, API:
https://api.highcharts.com/class-reference/Highcharts.Chart#addSeries
https://api.highcharts.com/class-reference/Highcharts.Series#update
https://api.highcharts.com/class-reference/Highcharts.Series#setData

HighChart and HighStock showing x-axis and y-axis length differently for same chart

I am using same chart in 2 different places and the data is being loaded dynamically.
In one of the place i am using HighChart and for other i use HighStock to get the Navigator,Scrollbar facility.
What i'm trying to achieve is i am loading data asynchronously and the chart shows loading text/a loader until it gets data from the server.This works perfectly fine for HighChart. But when it comes to HighStock things are not working. It shows data differently than what i am expecting it to be.
Let me explain, The chart is initialized first and when it fetches data from server i tried to log the value of xAxis here, it shows 1 for HighChart which is correct but for HighStock the statement show 2 xAxis.
//HighChart
var MyChart = {
initHighcharts: function() {
this.chart = new Highcharts.Chart({
// Chart related configuration
},
series: []
});
this.chart.showLoading();
},
updateChart: function(data) {
console.log('x axis', this.chart.xAxis);// Here i get 1 xAxis
// Load data here
this.chart.redraw();
this.chart.hideLoading();
},
};
MyChart.initHighcharts();
setTimeout(function() {
var data = someData;
MyChart.updateChart(data);
}, 2000);
I don't understand what goes wrong here when i change the HighChart to HighStock.The only piece of information i changed here is
this.chart = new Highcharts.StockChart({
//HighStock chart
var MyChart = {
initHighcharts: function() {
this.chart = new Highcharts.StockChart({
// Chart related configuration
},
series: []
});
this.chart.showLoading();
},
updateChart: function(data) {
console.log('x axis', this.chart.xAxis);// Here i get 2 xAxis
// Load data here
this.chart.redraw();
this.chart.hideLoading();
},
};
MyChart.initHighcharts();
setTimeout(function() {
var data = someData;
MyChart.updateChart(data);
}, 2000)
Here are the two fiddle that show the error i am facing,
HighChart Fiddle
HighStock Fiddle
I have logged the length of xAxis, Please open console window to see the xAxis value. Am i doing something wrong here?
Any help is much appreciated!!
Thanks

Incorrect data point value in highcharts navigator series when extending min and max date

I recently updated highstock in which I used a chart that displayed values with an "extended range", i.e. where the min and max date is set outside the boundaries of the chart data.
After the update (which fixed some other bugs) I noticed that the last data point in the navigator series at the bottom is not correct according to the data in the actual series. As can be seen, there's an additional data point at the far right in the bottom that doesn't exist in the actual series.
This can be viewed at http://jsfiddle.net/ab96pnjf/ as well
The code that creates the chart is the following
$(function () {
var fromdate = new Date('2011-04-01');
var todate = new Date('2012-05-21');
var series = [{
color: 'red',
data: MSFT,
name: 'MSFT'
}];
$('#container').highcharts('StockChart', {
navigator: {
series: {
data: series[0].data,
color: '#4572A7',
fillOpacity: 0.05
}
},
xAxis: {
ordinal: false,
min: fromdate.getTime(),
max: todate.getTime()
},
legend: {
enabled: true
},
series: series
});
});
Now, if I change the navigator.series property to
navigator: {
series: series
}
the navigator chart is correct, as in the values are cut off at the right when there is no more data available. This is what I want; the only problem is that the color is the same as the series, and I want it to use my custom color, as in the first example.
So how do I configure HighStock to cut off the last value in the navigator chart while at the same time being able to use a custom color for the series?
Hm, well I have a "quick fix" to this problem, as I am not sure how I would configure highcharts to do it for me.
Using jQuery I can extract the line in the navigator, since highcharts (at least) applies a class to the series. It sets the class name for all series including the one in the "main area", but the last one is the navigator series it seems, or every odd series if there is more than one highcharts chart in the document.
$(function () {
// ... as previous
$('#container').highcharts('StockChart', {
navigator: {
series: series
},
// ... as previous
});
// added code to apply a custom style to the navigator line diagram
var navseries = $('.highcharts-series:last').children();
// can be undefined if the series has no data points
if (navseries) {
navseries.css('stroke', '#4572A7');
navseries.css('strokeWidth', 1);
navseries.css('fillOpacity', 0.05);
}
});

SetTimeout for multiple real-time flot charts

I want to be able to have multiple real-time flot charts. I have it working with one flot chart where everything is updated real time via this function:
function updateOnce(plot)
{
plot.setData([{ label: 'G-force', data: getRandomData(), lines: { show: true } }]);
plot.setupGrid();//sensorPlots[i]
plot.draw();
setTimeout(function () { updateOnce(plot); }, 30);
}
Now the problem I have is that I am dynamically generating the plot and adding it to an array. How could I setup this type of function to iterate every the array and run this function for every plot in the array without affecting the others?
I've tried this:
function updateOnce()
{
$.each(sensorPlots, function (i, val) {
val.setData([{ label: 'G-force', data: getRandomData(), lines: { show: true } }]);
val.setupGrid();//sensorPlots[i]
val.draw();
setTimeout(updateOnce, 30);
});
}
sensorPlots is an array filled with `plots`
but then this causes my graph to move faster and faster with every plot that I add.
The problem seems to be that you are declaring a new timeout for every plot every time the timeout function is run. This will lead to the function being called with exponentially increasing frequency which is very bad... What if you do it like this:
function updateOnce() {
$.each(sensorPlots, function (i, val) {
val.setData([{ label: 'G-force', data: getRandomData(), lines: { show: true}}]);
val.setupGrid();//sensorPlots[i]
val.draw();
});
setTimeout(updateOnce, 30);
}
updateOnce();

Pie chart using flot

I am using Jquery Flot to create a pie chart based on three different values, pause, nopause and sleeping. Initially it draws th pie chart correctly but after some redraw it gives me the following error.
Could not draw pie with labels contained inside canvas
My code is
Lecturer.socket.onmessage = function (message) {
var str = message.data;
var msg = str.split(":");
if(msg[0] == 'pause'){
var pause = parseInt(msg[1]);
var noPause = parseInt(msg[2]);
var sleeping = parseInt(msg[3]);
var data = [
{label: "Pause", data:pause},
{label: "No Pause", data:noPause},
{label: "Sleeping", data:sleeping}
];
var options = {
series: {
pie: {show: true}
},
legend: {
show: false
}
};
$.plot($("#pie-placeholder"), data, options);
}
};
HTML is
<div id="live-placeholder" class="flot"></div>
All the require js libraries are included. What I m doing wrong? Any Help ?
Thanks
You've got two problems:
1.) your placeholder div id doesn't match the $.plot call. live-placeholder != pie-placeholder.
2.) You don't need to calculate the percents yourself. Flot will do it internally.
See a working fiddle here.

Categories

Resources