We have an application which renders ~50 (high)charts simultaneously on a dashboard. The thing is the browser freezes when the charts are getting rendered. (I tried using boost and virtual scroll). What makes it worse is that our users generally have datalabels on.
A fiddle with experiments: http://jsfiddle.net/z9msdftt/1/
var to;
$('#charts').scroll((e) => {
clearTimeout(to);
to = setTimeout(() => {
var offset = Math.floor($('#charts').scrollTop() / 400);
var start = new Date();
[...Array(5)].forEach((_, i) => {
renderChart(offset + i);
});
var end = new Date();
$('#counter').html('Time rendering: ' + (end - start) + 'ms');
}, 50);
});
Is there a way I can speed this up maybe by:
Doing an initial server rendering of the SVG and then handle further interactions on the client side (isomorphic render)
Or
Using webworkers to do calculations parallely and then rendering the charts.
Any help, would be greatly appreciated.
You can try Highcharts boost.js to speed up rendering process.
This speed problem is general in all SVG based chart libraries. Performance decreases after adding a couple hundreds of points to the chart or adding multiple charts to the same page.
boost.js is using HTML5 canvas technology by drawing the graph on a HTML5 canvas then copying the content of the chart to a SVG.
Related
We are investigating multiple new web development stacks in an effort to get away from VB.NET. I have created a page using Svelte 3 architecture to replicate what we have on one existing .NET-based page. We use Highcharts for our charting library. I am able to get the charts to show up. However, other logic we use to get list of all charts on the page always returns an empty array:
export const DestroyChartReferenceByClassName = (className) => {
var cssClassName = className;
jquery(Highcharts.charts).each(function (i, chart) {
if (typeof chart !== 'undefined') {
if (chart.container.classList.contains(cssClassName)) {
chart.destroy();
}
}
});
};
When I call this method it runs without errors. However, Highcharts.charts is an empty array. What is the preferred method to iterate over the Highchart charts on a Svelte page?
Consider the following toy example: jsfiddle
chart: {
events: {
render: myfunc
}
},
...
function myfunc() {
var chart = this;
chart.series.forEach(function(s) {
s.setState('inactive', true);
});
chart.series[0].setState('hover');
}
The intended behavior is to set the state of the first series as hover while setting all other series as inactive after load and redraw events.
The code works as intended after load
However, it doesn't work after redraw (via the select box). After selecting an option in the box, the series are rendered as normal instead of as inactive UNLESS any series had been previously hovered. That is, the code works if you interact with any series AND THEN select an option in the box, but it doesn't work if you select an option in the box immediately after the loading without interacting on the series.
Surprisingly, after some inspection in the console, I noted that in any case the intended states are properly passed to the series object. So, why the states are not properly rendered?
*NOTE: In my actual application the hovered series is not necessarily the first one, but it varies depending on the output of other function. I'm aware that "myfunc" could be simplified in the current example, but for general purposes please suggest an answer keeping the basic structure if possible.
This seems to be related to this issue from HighChart's GitHub. In your case, HighCharts is correctly updating the series' state. However, while rendering it fails to set the proper opacity value associated with the 'inactive' state. The workaround is to explicitly set the opacity of the series to the same value it should have in the 'inactive' state.
// F U N C T I O N S E T S T A T E
function myfunc() {
var chart = this;
chart.series.forEach(function(s) {
//explicit opacity
s.opacity = 0.2;
s.setState('inactive', true);
});
chart.series[0].setState('hover');
}
Thank you for sharing this issue, it seems that it is a regression after the last release.
In the previous version it used to work fine: https://jsfiddle.net/BlackLabel/Lbpvdwam/
<script src="https://code.highcharts.com/8.1.0/highcharts.js"></script>
<script src="https://code.highcharts.com/8.1.0/highcharts-more.js"></script>
I reported it on Highcharts Github issue channel where you can follow this thread: https://github.com/highcharts/highcharts/issues/13719
If you don't need any new features/bugfixes use the previous version as a temporary workaround.
I am trying to show the loading animation during a function call that takes some time. The function call is searching a large array that is already loaded. After the search, matching items are inserted into a table. The table is cleared prior to starting the search.
The problem is the animation only displays during the brief moment when the page updates.
Here is my code:
var interval = setInterval(function ()
{
$.mobile.loading('show');
clearInterval(interval);
}, 1);
DoSearch(term, function ()
{
var interval = setInterval(function ()
{
$.mobile.loading('hide');
clearInterval(interval);
}, 1000);
});
//The search function looks like this (detail omitted for brevity):
function DoSearch(term)
{
$("table#tableICD tbody").html('');
// also tried:
/*$("table#tableICD tbody")
.html('')
.table()
.closest("table#tableICD")
.table("refresh")
.trigger("create");*/
var tr = '';
$.each(codes, function (key, value)
{
// determine which items match and add them as table rows to 'tr'
});
$("table#tableICD tbody")
.append(tr)
.closest("table#tableICD")
.table("refresh")
.trigger("create");
callback();
}
The search works properly and adds the rows to the table. I have two unexpected behaviors:
The table does not clear until the search is complete. I have tried adding .table("refresh").trigger("create") to the line where I set the tbody html to an empty string. This does not help. (see commented line in the code)
As I mentioned, the animation displays briefly while the screen is refreshing. (Notice I set the interval to 1000 in the second setInterval function just so I could even see it.)
The suggestions I have read so far are to use setInterval instead of straight calling $.mobile.loading, which I have done and placing the search in a function and using a callback, which I have also done.
Any ideas?
Let me give you a few suggestions; they will probably not solve all your issues but they may help you found a solution.
jQuery Mobile is buggy, and for some features, we will never know were they intended to work like that or are they just plain bugs
You can call $.mobile.loading('show') on its own only in pageshow jQuery Mobile event. In any other case, you need to do it in interval or timeout.
It is better to do it in timeout, mostly because you are using less code. Here an example I made several years ago: http://jsfiddle.net/Gajotres/Zr7Gf/
$(document).on('pagebeforecreate', '[data-role="page"]', function(){
setTimeout(function(){
$.mobile.loading('show');
},1);
});
$(document).on('pageshow', '[data-role="page"]', function(){
// You do not need timeout for pageshow. I'm using it so you can see loader is actualy working
setTimeout(function(){
$.mobile.loading('hide');
},300);
});
It's difficult to enhance any jQuery Markup in real time after a page was loaded. So my advice is to first generate new table content, then clean it, and then update markup using .table("refresh").
Do table refresh only once, never do it several times in the row. It is very resourced heavy method and it will last a very long time if you run it for every row
If you are searching on keypress in the input box then showing it in the table; that is the least efficient method in jQuery Mobile. jQM is that slow, it is much better to use listview component which is least resource extensive.
I want to get minortickmark value when i click on minortickmark in axis of barchart. I am getting all tickmark positions using getMinorTickPositions() in barchart. I have searched all js code in highcharts i am unable to find it.can anyone please help me. here is my code.
$('.highcharts-axis').hover(function(event) {
alert(this.x);
getAxisValue();
return false;
});
function getAxisValue(){
var chart = $('#container').highcharts();
var data= chart.xAxis[0].getMinorTickPositions();
//alert(chart.value());
alert(data);
};
In general to add click event to minor ticks will require some JS and Highcharts skills. I will try to guide you a little:
chart.xAxis[0].minorTicks - this is where all minor ticks are stored
to add click event to minorTick, use: chart.xAxis[0].minorTicks['value'].mark.on('click', callback)
now in callback you can do your stuff for specific minor tick
I'm evaluating highcharts for a client project and have run into a problem rendering a polar chart with phantomjs. The charts lines come out as a thick grey blob! I thought this was due to animation but thats turned off. Will try and post an image but anyone have any thoughts on what else could be causing this? If I print preview from chrome it also looks ok.
Here's the image.
This was created as part of a report which I built using the rasterize.js script included with phantomjs. All the other charts work fine, the polar chart is the only one not coming out. If I use the highcharts export server script with phantomjs it works fine - but that only allows for 1 chart to be exported to PDF. I need to export a whole web page as a PDF including some charts.
There's another workaround on the project's bug tracking:
https://github.com/ariya/phantomjs/issues/10364#issuecomment-14992612
All you need to do is to remove all page elements with low opacity before rendering to file:
diff --git a/examples/rasterize.js b/examples/rasterize.js
index fcd74cd..dcc81d4 100644
--- a/examples/rasterize.js
+++ b/examples/rasterize.js
## -19,6 +19,16 ## if (phantom.args.length < 2 || phantom.args.length > 3) {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
+ // Remove all low-opacity paths. see PhantomJS issue #364
+ page.evaluate(function () {
+ var paths = document.getElementsByTagName("path");
+ for (var i = paths.length - 1; i >= 0; i--) {
+ var path = paths[i];
+ var strokeOpacity = path.getAttribute('stroke-opacity');
+ if (strokeOpacity != null && strokeOpacity < 0.2)
+ path.parentNode.removeChild(path);
+ }
+ });
page.render(output);
phantom.exit();
}, 200);
You can use that to grab graphs even if you don't have access to the source of the page containing the graph.