I currently have to plot in the neighborhood of 8000 - 32000 points (4 lines * 8000 points) I am getting my data via a JSON request and that works perfectly actually the data is returned to me in less than a second. However whenever I get to the $.plot point it freezes IE8 and it takes forever to load that many points. Here is my code:
var data = [];
function onDataReceived(seriesData) {
var p = $.plot(placeholder, seriesData.seriesData, options);
}
$.ajax({
url: '/Charts/LineChart?DataTypesToGraph=' + dataTypes + '&DatePull=' + chartDate + '&AssetID=' + $('#AssetID').val(),
method: 'GET',
async: true,
cache: true,
dataType: 'json',
success: onDataReceived
});
How can I speed up my $.plot to make it load a lot faster. Also is there a way I can do it so it does not freeze IE8?
Thanks so much!
You're seeing a 'freeze' because Flot doesn't (yet) support incremental drawing; it renders the entire plot before giving control back to the browser. There's no way around that besides hacking the code, but there are two things you can do to help:
You're probably using Excanvas; try switching to Flashcanvas. In my experience it works just as well with Flot, and delivers dramatically better performance. The $31 necessary to license the 'pro' version is not going to break most budgets.
You have 8000 points per line, and most displays max out at 1920 pixels wide, with the average being more like 1280. If you're showing the whole line, without some sort of zoom/pan, then you're rendering 4-6 times more data than is actually visible onscreen. Some server-side filtering/aggregation to bring the number of points down to 2k would dramatically improve performance.
But no matter what you do, you're never going to get great performance on IE8 with large datasets. It's an almost four-year-old browser, released before the JavaScript performance wars, using an emulated canvas; you can only do so much.
Related
Discovering the Web Audio Api I wanted to draw a waveform for sound files. Now, I am aware of the image dimension limitations in some browsers, and I tried to look them up, but they seem to be ever changing (or at least memory differences like Chrome Desktop vs Chrome Mobile).
I tried to look up how to test if an image, or a Canvas / 2D Context can be of a certain size with almost no success. However, when testing this thing in Firefox I did get an error in the console so I tried the following method:
wfWidth = source.buffer.duration*100;
document.getElementById("waveform").width = wfWidth;
wfCtx = document.getElementById("waveform").getContext("2d");
var success = false;
while(success == false)
{
try {
var temp = wfCtx.getImageData(0,0,10,10); // this produced an error further down the code, so I use this as my test case.
success = true;
} catch(err) {
wfWidth = wfWidth / 2;
document.getElementById("waveform").width = wfWidth;
wfCtx = document.getElementById("waveform").getContext("2d");
}
console.log(success);
}
This does seem to work in Firefox as the console first outputs false showing that the canvas is too big and then true after halving the width of the canvas and the waveform is shown.
However, in Google Chrome on Desktop the canvas seems to be of a certain size (as indicated by a scroll bar) but it is totally blank. When I right-click to save image, it is a 0 byte txt file. On Chrome Mobile (android) I get this little square sad face. Guess that method of checking doesn't work in Chrome.
What would be the best way to test if the canvas is, well, valid, and resize if it is not?
I know the title is not that explanatory but here is the story: I am developing a browser game, mostly using JavaScript and the Mapbox library.
Everything works well on desktop, Android and iOS but one problem appears on iOS: after letting the game run for a few minutes the phone suddenly begins to have graphic artifacts and display most of the text scrambled.
Here are some photos of what the phone begins too look like:
My question is: what exactly in my code can cause this? A memory leak? (LE: it turned out to actually be a memory leak)
The real question is: How comes that you can almost brick the entire phone by simply browsing a web page? Shouldn't Safari stop this, or at least the iOS ?
This is not a problem with this specific device, as this problem can be reproduced on different iPhone devices. (I'm not so sure about different iOS versions).
How I can reproduce the error:
Open the game (inside Safari).
Let it run for 3-4 minutes.
Slide down the notification center and everything goes crazy.
I have added a YouTube video showing how I can reproduce the error (on my iPhone 5C).
It seems that the issue first appears in the notification center (if you swipe down the menu from the top).
As for now, this problem seems to only occur on iPhone 5C iOS 9.2.1 (13D15). It also occurs on the new iOS 9.3 version.
In order to fix this issue I have to:
Close the Safari application (in which the game tab is open).
Lock the phone. After unlocking it everything is back to normal.
Some details about the game itself:
The game shows a Mapbox map and some units over it (markers).
A Node.js server runs at 1 tick/second and after each tick the updated game state is sent to the browser through Socket.io.
Every time the browser receives the game state it updates the markers accordingly.
*The game might also update markers if you zoom in or out or if you select them.
EDIT2:
Found the memory leak (as expected). After fixing this leak (check for undefined _icon) the issue no longer occurs. This means, that somewhere along those lines the Safari/iOS bug is triggered.
Here is what exactly was being called each tick, for each unit that was clustered (was hidden and grouped with others inside a MarkerCluster):
var $icon = $(marker._icon); // marker._icon is undefined because of the clustering
$icon.html('');
$icon.append($('<img class="markerIcon" src="' + options.iconUrl + '" />'));
var iconX = 10;
var iconY = -10;
var iconOffset = 0;
for(var v in this.icons) {
this.icons[v].css('z-index', + $icon.css('z-index') + 1);
this.icons[v].css('transform', 'translate3d(' + iconX + 'px,'
+ (iconY + iconOffset) + 'px,' + '0px)');
iconOffset += 20;
this.icons[v].appendTo($icon);
}
// Fire rate icons
this.attackRateCircle = $('<div class="circle"></div>');
this.attackRateCircle.circleProgress({
value: 0,
size: 16,
fill: { color: "#b5deff" },
emptyFill: 'rgba(0, 0, 0, 0.5)',
startAngle: -Math.PI / 2,
thickness: 4,
animation: false,
});
this.attackRateCircle.hide();
// Create and display the healthbar
this.healthBar = $('<div>').addClass('healthBar ');
this.healthBar.css('z-index', $icon.css('z-index'));
this.healthBarFill = $('<span class="fill">');
this.healthBar.append(this.healthBarFill);
$icon.append(this.healthBar);
$icon.append(this.attackRateCircle);
And this is the icons array:
this.icons = {
attack_order: $('<img src="img/attack.png" class="status_icon">'),
attack: $('<img src="img/damage.png" class="status_icon icon_damage">'),
hit: $('<img src="img/hit.png" class="status_icon icon_hit">'),
};
circleProgress call is from this library: https://github.com/kottenator/jquery-circle-progress
DEMO
Yay, I have been able to create a jsFiddle that reproduces the bug: https://jsfiddle.net/cte55cz7/14/
Open on Safari on iPhone 5C and wait a couple of minutes. On iPhone 6 and iPad mini the page crashes (as expected due to the memory leak)
Here's the same code in a HasteBin, for anyone who doesn't want to run it.
This memory leaks is probably due to how 'WebKit’s JS Engine' works [safari webkit-javascript llvm]
and really looks like to be a virtual memory buffer-overflow, having a direct impact on the remaining RAM (shared and used also by iOS to store User Interface graphical elements)
Relatively to the piece of code:
"[...]finding jQuery memory leaks is easy. Check the size of $.cache. If it’s too large, inspect it and see which entries stay and why. [...]" (http://javascript.info/tutorial/memory-leaks)
Let me expect that it is relative to this for loop :
for(var v in this.icons) {
this.icons[v].css('z-index', + $icon.css('z-index') + 1);
this.icons[v].css('transform', 'translate3d(' + iconX + 'px,'
+ (iconY + iconOffset) + 'px,' + '0px)');
iconOffset += 20;
this.icons[v].appendTo($icon);
}
Assuming inspection is done, and also assuming the fact that you find the entries, you may want to clean the data manually with removeData()
or you may use first $elem.detach() and then put $(elem).remove() in setTimeout.
I'm currently trying to make a frequency analyzer using web technologies, especially Meteor.
For now, I tried to use the Google Charts library that create SVG pictures. The chart needs to be refreshed about 10 times by second and the performance aren't satisfying. It takes all the CPU resource.
I'm a bit new to web development (especially in graphical and performances issues) so if you could point into the right direction to make my research, I'd appreciate it.
I ended up using the library CanvasJs which appears to be one of the fastest. There is an option interactivityEnabled: false to disable interactions with the chart which increase performance.
Even if there is yet no direct Meteor integration, just put the js file in the ./client/compatibility and it works fine.
You could very easily accomplish this with ZingChart. We don't have a Meteor integration (yet), but the demo below should be a good start for you. Run the snippet below to see it live.
I'm on the ZingChart team! Let me know if you have questions.
var MAXVALUES = 100;
var myConfig = {
type: "line",
series : [
{
values : []
}
]
};
zingchart.render({
id : 'myChart',
data : myConfig,
height: 400,
width: 600
});
var myValues = [];
setInterval(function(){
myValues.push( Math.floor(Math.random() * 10 ) );
if(myValues.length == MAXVALUES+1){
myValues.shift();
}
console.log(myValues)
zingchart.exec('myChart', 'setseriesvalues', {
values : [myValues]
})
},60)
<script src="http://cdn.zingchart.com/zingchart.min.js"></script>
<div id='myChart'></div>
Use the canvas element. You should be able to get 60 per second and if it's a audio source the Audio API provides a DSP for spectral analysis.
Here is an example audio spectrum visualizer
The following code works fine in every other browser except IE7. In fact, with this enabled on the page no scripts will work until I have commented it out.
$(document).ready(function () {
var pathname = $(location).attr('href');
if(pathname.indexOf('sess') === -1){
var path = pathname;
}else{
var path = pathname.replace(/sess[^&]*&?/, "");
}
$.ajax({
type: "POST",
url: "ajax/save_page.php",
data: 'last_page='+path
});
});
I have checked for errant commas and can't find any. If I pass a literal value through the Ajax call and comment out the rest of the function everything begins to work as it should but I need the whole function to work.
Ok, I'm beginning to realise that it isn't going to work on IE7 but I need the script to carry on working as it is without excluding IE7 users completely so I used..
if(navigator.appVersion.indexOf("MSIE 7.")!=-1)
to determine if the browser is IE7 and if so exclude that bit of script. Hopefully the user will be able to persuade their admin to upgrade them to a different browser when they realise that it isn't working as well as it could.
But, for the record, I agree that in an ideal world we shouldn't be supporting IE7 etc but in the real world a lot of people still use it and a lot can't do anything about it. I work within the medical and dental industries and a lot of hospitals etc (about 50%) are still using XP with IE7 with no immediate plans for upgrading despite knowing that XP is no longer supported by Microsoft.
Revision to solution
Ok, I have revised my solution, I am using php sessions now for passing around the sess variable that was previously in the url so I no longer have to try and take it out of the url whilst leaving the rest of the params intact.
So now I am using
var path = window.location.href;
$.ajax({
type: "POST",
url: "ajax/save_page.php",
data: 'last_page='+path
});
Which works fine in all of the browsers I am testing it in including IE7
I'm currently working on a WordPress addition which loads full post content (normally it shows exceprts) when asked to. I did my code like this:
$(".readMore").click(function() {
var url = $(this).attr("href");
$(this).parent("p").parent("div").children("div.text").slideUp("slow", function () {
$(this).load(url + " .text", function(){
$(this).slideDown("slow");
});
});
$(this).parent("p").fadeOut();
return false; });
And it works. But I don't want images to be loaded. I tried .text:not(img), but it didn't worked. How can I do this?
The trick, of course, is preventing the images from being downloaded unnecessarily by the user's browser; not displaying them is easy.
I only have two browsers were it's easy and convenient to tell what's downloading: Chrome and Firefox+Firebug. In my tests, Martin's solution using *:not(img) results in the images being downloaded (although not displayed) in both Chrome and Firefox+Firebug. (I emphasize "Firefox+Firebug" because Firebug can change the behavior of Firefox on occasion, and so it may well be changing its behavior here, although I don't think it is; more on that below.)
It took some tweaking, but this seems to do the trick (more on testing below):
$.ajax({
url: url,
success: function(data) {
var div = $("<div>").html(data);
if (stripImages) {
// Find the images, remove them, and explicitly
// clear the `src` property from each of them
div.find("img").remove().each(function() {
this.src = "";
});
}
$(targetSelector).append(div.children());
},
error: function(jxhr, status, err) {
display("ajax error, status = " + status + ", err = " + err);
}
});
Live example The "Include big image" checkbox includes a large file from NASA's Astronomy Picture of the Day (APOD).
The key there was setting the src of the img elements to "". On Chrome, just removing the elements was enough to prevent Chrome starting the download of the images, but on Firefox+Firebug it not only started downloading them, but continued even when the download took considerable time. Clearing the src causes Firefox to abort the download (I can see this in the Firebug Net console).
So what about IE? Or Firefox without Firebug? I only did unscientific testing of those, but it's promising: If I run my live example of Martin's solution on either IE or Firefox without Firebug in a VM, I see the VM's network interface working hard, suggesting that it's downloading that big APOD picture. In contrast, if I run my solution above in that same environment (with caches cleared, etc., etc.), I don't see the VM network interface doing that work, suggesting that the download is either not being started or is being aborted early on.
.text *:not(img) will select every descendant from .text that is not an image, so in theory it should work.