SetTimeout for multiple real-time flot charts - javascript

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();

Related

How to synchronise shared tooltip and crosshair in highcharts?

I have a couple of charts, some with a single series, others with multiple series. I show shared tooltips for charts with multiple series. I show a vertical crosshair on each chart.
Now I would like to synchronise the charts. Moving the mouse in one chart should show the described features (crosshair and toolip) on the correct place in all charts, with updated data.
As you can see in fiddle, this does not work completely. The x position is synchronised correctly. Tooltips are updated. But mouseover on the second chart shows a tooltip in the first chart with only one y value instead of two. [Edit: I've found a way to update crosshairs; but it does not not work in every chart, when I set
tooltip: {
shared: true,
maybe there is a better solution?]
https://jsfiddle.net/hbaed859/1/
let highlightFunction = function (point) {
Highcharts.charts.forEach(chart => {
chart.series.forEach(s => {
if (point.series.name != s.name) {
s.points.forEach(p => {
if (p.index === point.index) {
p.setState('hover')
p.series.chart.tooltip.refresh(p)
// shows tooltip, but ignores "shared: true"
chart.xAxis[0].drawCrosshair(null, p);
...
chart = Highcharts.chart('chart1', {
series: [{
point: {
events: {
mouseOver(e) {
let point = this;
highlightFunction(point)
}
...
[edit] ... and the method is nice for small datasets, for large one it needs too long to recalculute the crossjair positions for all the charts.
You are really close to achieve the wanted result. Use the hideCrosshair method for crosshair visibility and add points from all chart's series to the tooltip.refresh method call. Optimized code below:
function setHighlightState() {
const point = this;
Highcharts.charts.forEach(chart => {
if (point.series.chart !== chart) {
const matchedPoints = [];
chart.series.forEach(s => {
const matchedPoint = s.points[point.index];
matchedPoints.push(matchedPoint);
matchedPoint.setState('hover');
});
chart.tooltip.refresh(matchedPoints)
chart.xAxis[0].drawCrosshair(null, matchedPoints[0]);
}
});
}
function hideHighlightState() {
const point = this;
Highcharts.charts.forEach(chart => {
if (point.series.chart !== chart) {
chart.series.forEach(s => {
s.points[point.index].setState('');
});
chart.tooltip.hide();
chart.xAxis[0].hideCrosshair();
}
});
}
Live demo: https://jsfiddle.net/BlackLabel/nwj3co0a/
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis#hideCrosshair

Histogram type highcharts access to series

I have a histogram type highcharts, and I need inside the chart event update function get access to series[0].data for changing points color. I can see series[0].data array with all my points in google dev tools, but actually get an empty array in JS code. After the updated color of points does not change. Example: jsfiddle
There is no such event as chart.events.update. Use the render instead - API: https://api.highcharts.com/highcharts/chart.events.render
Demo: https://jsfiddle.net/BlackLabel/csdnh6e3/
chart: {
events: {
render: function() {
console.log('data :', this.series[0].data);
this.series[0].data.forEach(data => data.update({
color: '#0f5'
}, false)); // after the update() color of points does not change
}
}
},

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

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);
}
}

Dynamic x-axis on a real-time flot chart?

Is there a way to update the x-axis on a real time flot chart?
I want something like this -> (http://www.flotcharts.org/flot/examples/realtime/index.html)
but as you can see, there are no values on the x-axis..
So, is there a way to shift the x-axis values as the chart shifts?
Thanks in advance!
You first need to show the x axis:
var plot = $.plot("#placeholder", [ getRandomData() ], {
xaxis: {
show: true
}
});
Then on every data update you need to update the grid as well:
function update() {
plot.setData([getRandomData()]);
plot.setupGrid(); // updating the grid
plot.draw();
setTimeout(update, updateInterval);
}
Check this plunker for example.

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);
}
});

Categories

Resources