I'm presenting a simple animation using img.src replace and the <canvas> tag. At present it's only expected to work in FireFox (FF 3.5.3, Mac OS X 10.5.5), so cross-browser compatibility isn't (yet) an issue.
When the page is first loaded, or loaded into an new window or tab, all seems to work as expected, and the cache behavior on a simple reload does not seem to be an issue; however, if I try to force a reload with shift-reload, I get a problem. Even though the images have been pre-loaded, the preloaded images for the animation don't seem to be available to the browser which then tries to load each new img.src from the server.
Am I looking at a browser bug here, or is there something buggy in my code that I can't see? This is my first shot at implementing a js class, so there might be a lot here that I don't understand.
Any insight from the assembled wise here would be welcome. You can see what I'm talking about at:
http://neolography.com/staging/mrfm/spin-sim.html
Thanks,
Jon
When you shift reload you're telling the browser to reload - not from the cache.
So it shouldn't be a surprise that you're getting the images from the server.
Images can be preloaded in javascript with the following code:
img = new Image();
img.src = "your/image/path";
If you want the images loaded before you use them that might help.
I had a look at your code and you have the following in document.ready()
function countLoadedImages() {
loadedImgs++;
if (loadedImgs == images.length){
$("#loading-image").hide();
$("#controls").fadeIn(100);
}
}
animation = new simAnim("snap", "stripchart", 800, deriveFrameData(spindata));
the animation = new simAnim line is executed regardless if all 100 images are loaded or not...
One possibility to fix this would be to move that line inside the countLoadedImages function like so:
function countLoadedImages() {
loadedImgs++;
if (loadedImgs == images.length){
$("#loading-image").hide();
$("#controls").fadeIn(100);
animation = new simAnim("snap", "stripchart", 800, deriveFrameData(spindata));
}
}
this way that function will be executed once all the images have loaded
Thanks to ekhaled, who tried. I'm now satisfied that this is a browser bug:
Mozilla bug #504184
I have a stripped down example at http://neolography.com/staging/shift-reload/shift-reload-testcase.html which I will leave up. I encourage all to vote for this bug in the mozilla bug tracker so that it will get fixed.
j
Related
Some websites have lots of images, so lazyloading seems appropiate to reduce load times and data consumption. But what if you also need to support printing for that website?
I mean, you can try to detect the print event and then load the images, with something like this:
HTML
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
Note: this is a one by one pixels gif dummy image.
JavaScript
window.addEventListener('DOMContentLoaded', () => {
img = document.querySelector('img');
var isPrinting = window.matchMedia('print');
isPrinting.addListener((media) => {
if (media.matches) {
img.src = 'http://unsplash.it/500/300/?image=705';
}
})
});
Note: if you try this in a code playground, remove the DOMContentLoaded event (or simply fork these: JSFiddle | Codepen).
Note: I didn't event bother with the onbeforeprint and onafterprint for obvious reasons.
This will work fine if the image is cached, but then again that's precisely not the point. The image/s should all load and then appear in the printing screen.
Do you have any ideas? Has anyone successfully implemented a print-ready lazyloading plugin?
Update
I've tried redirecting the user after the print dialog is detected, to a flagged version of the website a.k.a website.com?print=true where lazyloading is deactivated and all images load normally.
This method is improved by applying the window.print() method in this flagged print-ready version of the page, opening a new print dialog once all images are finished loading, and showing a "wait for it" message in the meantime at the top of the page.
Important note: this method was tested in Chrome, it does not work in Firefox nor Edge (hence why this is not an answer, but a testimony).
It works in Chrome beacuse the print dialog closes when you redirect to another website (in this case same url but flagged). In Edge and Firefox the print dialog is an actual window and it does not close it, making it pretty unusable.
Based on your desired functionality, I'm not quite sure what you want to do is feasible. As a developer we don't really have control over a users browser. Here are my thoughts as to why this isn't fully possible.
Hooking the event to go and load your missing images won't let you guarantee images will make it from the server into your page. More specifically, the PDF generated for your print preview is going to get generated before your image(s) is done loading, the img.src = "..." is asynchronous. You'd run into similar issues with onbeforeprint as well, unfortunately. Sometimes it works, sometimes it does not (example, your fiddle worked when testing in safari, but did not in Chrome)
You cannot stall or stop the print call -- you can't force the browser to wait for your image to finish loading in the lazy loading context. (I read something about using alerts to achieve this once, but it seemed really hacky to me, was more of a deterrent to printing than stalling)
You cannot force img.src to get that data synchronously in a lazy-load context. There are some methods of doing this, but they are clever hacks -- referenced as pure evil and may not work in always. I found another link with a similar approach
So we have a problem, if the images are not loaded by the time print event is fired, we cannot force the browser to wait until they are done. Sure, we can hook and go get those images on print, but as above points out, we cannot wait for those resources to load before the print preview pops up.
Potential solution (inspired by links in point three as well as this link)
You could almost get away with doing a synchronous XMLHttpRequest. Syncrhonous XMLHTTPRequests will not let you change the responseType, they are always strings. However, you could convert the string value to an arrayBuffer encode it to a base-64 encoded string, and set the src to a dataURL (see the link that referenced clever hacks) -- however, when I tried this I got an error in the jsfiddle -- so it would be possible, if things were configured correctly, in theory. I'm hesitant to say yes you can, since I wasn't able to get the fiddle working with the following (but it's a route you could explore!).
var xhr = new XMLHttpRequest();
xhr.open("GET","http://unsplash.it/500/300/?image=705",false);
xhr.send(null);
if (request.status === 200) {
//we cannot change the resposne type in synchronous XMLHTTPRequests
//we can convert the string into a dataURL though
var arr = new Uint8Array(this.response);
// Convert the int array to a binary string
// We have to use apply() as we are converting an *array*
// and String.fromCharCode() takes one or more single values, not
// an array.
var raw = String.fromCharCode.apply(null,arr);
// This is supported in modern browsers
var b64=btoa(raw);
var dataURL="data:image/jpeg;base64,"+b64;
img.src = dataURL;
}
Work around to enhance the user experience
Something you could do is have some text that only displays in the print version of your page (via #print css media) that says "images are still loading, cancel your print request and try again" and when the images are finished loading, remove that "still waiting on resources try again message" from the DOM. Farther, you could wrap your main content inside an element that inverses the display to none when content is not loaded, so all you see is that message in the print preview dialog.
Going off of the code you posted this could look something like the following (see updated jsfiddle):
CSS
.printing-not-ready-message{
display:none;
}
#media print{
.printing-not-ready-message{
display:block;
}
.do-not-print-content{
display:none;
}
}
HTML
<div class="printing-not-ready-message">
Images are still loading please cancel your preview and try again shortly.
</div>
<div class="do-not-print-content">
<h1>Welcome to my Lazy Page</h1>
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7">
<p>Insert some comment about picture</p>
</div>
JavaScript
window.addEventListener('DOMContentLoaded', () => {
img = document.querySelector('img');
var isPrinting = window.matchMedia('print');
isPrinting.addListener((media) => {
if (media.matches) {
img.src = 'http://unsplash.it/500/300/?image=705';
//depending on how the lazy loading is done, the following might
//exist in some other call, should happen after all images are loaded.
//There is only 1 image in this example so this code can be called here.
img.onload = ()=>{
document.querySelector(".printing-not-ready-message").remove();
document.querySelector(".do-not-print-content").className=""
}
}
})
});
I'm the author of the vanilla-lazyload script and I've recently developed a feature that makes print of all images possible!
Tested cross browser using this repo code which is live here.
Take a look and let me know what you think!
I'm open to pull requests on GitHub of course.
I wrote a lazy loading jquery plugin that supports showing images on print using the window.onbeforeprint events and mediaQueryListeners.
https://github.com/msigley/Unveil-EX/
//declare custom onbeforeprint method
const customOnBeforePrint = () => {
const smoothScroll = (h) => {
let i = h || 0;
if (i < 200) {
setTimeout(() => {
window.scrollTo(window.scrollY, window.scrollY + i);
smoothScroll(i + 10);
}, 10);
}
};
let height = document.body.scrollHeight;
let newHeight;
while (true) {
smoothScroll(100);
if (newHeight === height) break;
height = newHeight;
}
};
//override the onbeforeprint method
window.onbeforeprint = customOnBeforePrint;
Copy&Paste that block into devtool's console and then try to click print button. That workaround is working for me.
For whoever is in the same boat as I was: when using the browser native loading="lazy", you can simply remove that attribute when printing is going to happen. Below is my jQuery implementation.
window.onbeforeprint = function () {
$('img').each(function () {
$(this).removeAttr('loading')
});
}
Chrome will then just load all images and they will show up when printing.
I'm developing a plugin for a website building program, and am building the preview page for it. It's sort of a parallax scrolling plugin and the issue I'm having is that in Safari, when you scroll down to a certain point, it wont allow you to scroll any further. It's fine in firefox and chrome, but I saw the same issue in opera. I've managed to narrow it down to the function that's causing it, but I have no idea why or how to fix it.
When I comment out this function, the page scrolls fine, but it doesn't remove the empty divs like I need it to do:
function removeStuff() {
$('.conP').each(function(){
var divDad = $(this),
divses = $(this).children();
if (divses.hasClass('empty'))
divDad.remove();
});
}
here's the preview page where the issue can be observed:
http://reveriesrefined.com/myftp/dack_stev/
//////////EDIT:
I've simplified the code to this:
$('.conP_%id% > .empty').parent().remove();
however, it's still causing scrolling issues in safari and opera, but not the other browsers.
Any help is VERY VERY appreciated!
Actually, I found the issue already. Somehow even though commenting out the function mentioned above seemed to solve it, it was actually a line of code in another function.
I had this function:
function autoPlay() {
var backDiv = $('#outterLax div:first');
backDiv.hide();
$('.conP').hide();
backDiv.remove();
$('#outterLax').append(backDiv);
backDiv.show();
}
but the line:
$('.conP').hide();
was unnecessary as that was already being accomplished elsewhere in my code.
I am simply trying to change the SRC attribute of an image via javascript like so:
document.getElementById('fooImage').src = img;
Where img is a variable that has a link to the file.
In all other browsers (Chrome, Firefox, Safari) this works. In IE (7+) this also works too sometimes.
Using IE's built-in developer tools, I can see that the image's SRC tag is set. Is there something else in the locals window that could help me debug why the image doesn't actually show on screen?
I've also tried using jQuery to do this and same outcome:
$("#fooImage").attr("src", img);
An ideas?
In debugging this I would hard code it first...
document.getElementById('fooImage').src = "myimage.png";
I've used the following in my website and it works like this...
var imgCounter = document.getElementById('formtimer');
imgCounter.src = "graphics/odometers/1.png";
Some other things to check:
Make sure your ID= tag is not in the <DIV section but inside the <IMG section... for example <div class="style1"><img src="yourpicture" id="someid">. If `id='someid' is in the div tag then you can't change the picture / the picture won't show up.
are you using window.onload?, body onload? the proper way to use the first is..
window.onload = function () { YourFunctionHere(); };
Try a different test image. I had issues in the past with showing png's, I changed it to a gif or jpg and it worked. I don't understand how that was "way back" but it doesn't seem to be an issue anymore but hey... something to try.
try a full url
using https?
try sticking the image somewhere else in your program and see what happens.
try adding this to your HTML (put your website in place of mine - lookup BASE href on google for more info)
<BASE href="http://perrycs/" />
Make sure the image isn't hidden behind a layer (I know it works in some browsers)
tell us the website so we can check it out and get more info to help you in debugging this, seeing context (surrounding code) helps...
Given that it works in other browsers, searching on this topic it seems that often the problem is how IE caches images (ref. Epascarello's comment). Your code is the same as what I have - it works fine except in IE10.
I too, faced this conundrum. Then discovered that it works in 'Page Inspector', so after some digging discovered that (in Internet Explorer) by going to Tools.Internet Options.Advanced
uncheck the 'Disable script debugging (Internet Explorer)' and the one below it.
I found that with IE9 after changing an image.src with
var strVar="C:Users/x/Desktop/caution.png"
image.src=strVar
and calling an alert(image.src) I would get something like this n the alertbox:
file:///C:Users/x/Desktop/"C:Users/x/Desktop/caution.png"
So I tried
image.src=strVar.replace(/\"/g,"")
to remove qoutemarks
and it worked!
alert(image.src)
file:///C:Users/x/Desktop/caution.png
I have a problem.
A strange problem.
I have this part of code:
Actions.loadWizzard = function(href)
{
alert(1);
var wizardTimer;
var wizardTimer2;
if (navigationObject.getLocation(href) === "ProductInformationWizzard") {
navigationObject.newPage("loading");
wizardTimer = setTimeout("navigationObject.newPage('contentProductInformationWizzard');", 3000);
wizardTimer2 = setTimeout("window.productInformationWizzardObject.init()", 1000);
} else if (navigationObject.getLocation(href) === "contentAdviceWizzard") {
navigationObject.newPage("loading");
wizardTimer2 = setTimeout("window.adviceWizzardObject.init()", 10000);
}
return;
};
And on the normal browser it works excactly as it should work.
As a WRT though (or phonegap app) it doesn't.
It doesn't give me the alert (used for debugging). It doesn't use the setTimeout. evaluates instantly or something. And the loading page is not shown.
yeah, sometimes it shows up once.
Another problem is that the loading div has a GIF img. It;s like a loading img.
But the thing is just static. It's like normal image instead of a animated GIF.
How is this possible.
Some notes to the code:
navigationObject.newPage(page);
This hides the current div i'm viewing and shows the div i pass to it.
window.adviceWizzardObject.init();
This makes an ajax request to a jsonrpc server and then evaluates the data json retreived and set's up the wizard.
Thanks in advance,
Erik
It does work,
But becouse of some caching or something the old versions were loaded or something like that.
Restarting my phone solved the problem.
is anybody familiar with greyBox JavaScript plugin?
orangoo.com/labs/GreyBox/
it's for slideshows and stuff.. I can't get it to work in FF/Safari; it works great in IE, but FF/Safari won't play ball..
orensanz.org/photos.html
would very much appreciate some suggestions..
supposedly there's a google group (forum) for this thing (can't post url.. this thing limits how many urls u can include in a post, it's linked to from their home pg (url above.. oh brother..) but when you link to it you land on a pg that says they've been booted out b/c they violated google's terms of service....;-)
thank you..
It looks to me as if there's a race condition in some of that Javascript code. If the image isn't in cache, then this looks to me like it'll never make the image box visible:
if(gb_type == "image") {
if(img_holder.width != 0 && img_holder.height != 0) {
var width = img_holder.width;
var height = img_holder.height;
GB.width = width;
GB.height = height;
setupOuterGB();
if(GB.use_fx) {
AJS.setOpacity(frame, 0);
AJS.fx.fadeIn(frame);
}
}
}
else {
GB.width = frame.offsetWidth;
GB.height = frame.offsetHeight;
setupOuterGB();
}
In think that code should be called as the "load" handler for the image. Note that your page works fine in Firefox the second time you click on any particular image.
if(GB.show_loading) {
AJS.AEV(window, 'load', function(e) {
loaded();
});
}
else {
loaded();
}
Try putting these lines on either a timeout or replace the lower loaded() with AJS.AEV(window, 'load', function(e) {loaded();});
(I couldn't add comment, nothing happens when click on 'add comment'..)
yes I know I can use other lightboxes.. but what I do need is one in which slideshow lands in photo the user CLICKED.. at work I've been using this one, flowplayer.org/tools/demos/scrollable/easing.html, but when you tell it to start at a given photo (not photo 1) it SLIDES towards it.. I need one in which it just lands on specified photo without the sliding effect -- other than that this one would be perfect
a lot of slick JS lightboxes out there have 'next' button on top of photo itself and other stuff obstructing photo a bit, I don't want that.. ) oh man, I still can't get this thing to work AT ALL in Safari, whereas examples they have online (orangoo.com/labs/GreyBox/) work fine in Safari, I don't get this.. thank you for your help (btw: I tried many diff settings for setTimeout, all the way from 1000 milliseconds to about 30,000.. either way Safari won't touch it.. :-(