Reputation: 37500
I have a WebSocket
that receives data at a rate of ~50hz. Each time an update is pushed to the browser, it turns the JSON data it's had published to it into some pretty charts.
$(document).ready(function() {
console.log('Connecting web socket for status publishing')
allRawDataPublisher = new ReconnectingWebSocket("ws://" + location.host + '/raw/allrawdata');
var rawUnprocessedData = [];
for (i = 0; i < 256; i++)
{
rawUnprocessedData.push({x:i, y:0});
}
var unprocessedRawChart = new CanvasJS.Chart("rawUnprocessedData",{
title :{ text: "Raw Unprocessed Data"},
axisX: { title: "Bin"},
axisY: { title: "SNR"},
data: [{ type: "line", dataPoints : rawUnprocessedData},{ type: "line", dataPoints : noiseFloorData}]
});
var updateChart = function (dps, newData, chart) {
for (i = 0; i < 256; i++)
{
dps[i].y = newData[i];
}
chart.render();
};
allRawDataPublisher.onmessage = function (message) {
jsonPayload = JSON.parse(message.data);
var dataElements = jsonPayload["Raw Data Packet"]
updateChart(rawUnprocessedData, dataElements["RAW_DATA"].Val, unprocessedRawChart)
};
unprocessedRawChart.render();
});
This works great when my laptop is plugged into a power socket but if I unplug the power, my laptop drops it's processing power (and the same issue occurs on lower-specc'd tablets, phones etc). When there's less processing power available, the browser (Chrome) completely locks up.
I'm guessing the javascript is receiving updates faster than the browser can render them and consequently locking the tab up.
If the browser is unable to update at the requested rate, I would like it to drop new data until it's ready to render a new update. Is there a standard way to check the browser has had enough time to render an update and drop new frames if that's not the case?
*[Edit]
I did some digging with Chrome's profiler which confirms that (as expected) it's re-drawing the chart that is taking the bulk of the processing power.
Upvotes: 3
Views: 248
Reputation: 22959
You can do work between frames by using window.requestAnimationFrame
.
The callback passed to this function will be called at a maximum of 60 times a second - or whichever number matches the refresh rate of your display.
It's also guaranteed to be called before the next repaint - and after the previous repaint has finished.
From MDN window.requestAnimationFrame()
The window.requestAnimationFrame() method tells the browser that you wish to perform an animation and requests that the browser call a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.
Here's an example on how it's used:
function renderChart () {
// pull data from your array and do rendering here
console.log('rendering...')
requestAnimationFrame(renderChart)
}
requestAnimationFrame(renderChart)
However, it's better to render changes to your graph in batches, instead of doing rendering work for every single datum that comes through or on every frame.
Here's a Fiddle using Chart.js code that:
Array
every 100ms (10 Hz)const values = []
const ctx = document.getElementById('chartContainer').getContext('2d');
const chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['start'],
datasets: [{
label: 'mm of rain',
data: [1],
borderWidth: 1
}]
}
});
// Push 1 item every 100ms (10 Hz), simulates
// your data coming through at a faster
// rate than you can render
setInterval(() => {
values.push(Math.random())
}, 100)
// Pull last 4 items every 1 second (1 Hz)
setInterval(() => {
// splice last 4 items, add them to the chart's data
values.splice(values.length - 4, 4)
.forEach((value, index) => {
chart.data.labels.push(index)
chart.data.datasets[0].data.push(value)
})
// finally, command the chart to update once!
chart.update()
}, 1000)
Do note that the above concept needs to handle exceptions appropriately, otherwise the values
Array
will start accumulating so much data that the process runs out of memory.
You also have to be careful in the way you render your batches. If your value render rate is slower than the rate at which you fill the values
Array
, you will eventually run into memory issues.
Last but not least: I'm not really convinced you ever need to update a piece of data faster than 2 Hz, as I doubt the human brain can make useful interpretations at such a fast rate.
Upvotes: 2