Help me understand how google maps show images? - ajax

With firebugs net tab open i stated zooming in and out of google map and i found its making requests for the png images.
Ok with this i understood that we can request the images using the Ajax. but wait ? i always used to request html, jsox, txt and xml. Image ........ its strange for me ? Can some one please elaborate on this ?
Also i would like to know if text is downloaded we add it to some DOM element and it show up. How images retried from the ajax can be accessed ?
Any help or pointer will be great help :)

GMaps doesn't make XMLHttpRequests to get the images. They instead use a normal <img /> element that is injected via javascript.
They then use the "onload" and "onerror" events to detect if the image was loaded correctly.
They retry a download of the image if it times out. This is achieved by setting a timer and once it expires re-setting the src property of the image.
var tile = document.createElement('img');
var url = 'http://sometilehost/X.Y.Z.png';
var downloadTimeout = 10000; // Retry in 10 seconds
// Tile downloaded successfully
tile.onload = function (e) {
window.clearTimeout(tile.downloadTimer);
alert('tile downloaded');
};
// The tile couldn't be downloaded. 404, 503 ...
tile.onerror = function (e) {
window.clearTimeout(tile.downloadTimer);
alert('tile not downloaded');
};
// This will fire if the tile doesn't download in time
tile.downloadTimer = window.setTimeout(function () {
tile.src = url; // Start the download again
}, downloadTimeout);
tile.src = url;

Related

How do I make iScroll5 work when the image is generated from a DB?

I am using iScroll5 in a PhoneGap project. On the index page, user will click on a series of thumbnails generated from a database, then the image ID chosen will be written to localstorage, the page will change, the image ID will be pulled from localstorage and the image displayed.
It works fine if I reference the image directly (not from the DB) this way (as a test):
<body onload="loaded()">
<div id='wrapper'><div id='scroller'>
<ul><li><a id='output' href='index.html' onclick='returnTo()'></a></li></ul>
</div></div>
<script>
var newWP = document.createElement('img');
newWP.src = '0buggies/0118_buggies/wallpaper-18b2.jpg';
document.getElementById('output').appendChild(newWP);
</script>
</body>
I can pinch/zoom to resize the image for the screen (the main function my app requires), and scroll the image on the X and Y axis, then upon tapping the image, I will be returned to the index page. All of this works.
But if I pull the image out of a database and reference it the following way, all other aspects of the page code being the same, pinch/zoom does not work, though the picture is displayed and I can scroll on X and Y:
// ... DB code here ...
function querySuccess(tx, results) {
var path = results.rows.item.category +
"/" + results.rows.item.subcat +
"/" + results.rows.item.filename_lg;
document.getElementById("output").innerHTML = "<img src='" + path +
"'>";
}
// ... more DB code here ...
<body onload="loaded()">
<div id='wrapper'> <ul><li><a id='output' href='index.html'
onclick='returnTo()'></a></li></ul> </div>
How do I make iScroll5 work when the image is generated from a DB? I'm using the same CSS and iScroll JS on both pages. (iScroll4 has the same problem as iScroll 5 above.) I am using the SQLite DB plugin (from http://iphonedevlog.wordpress.com/2014/04/07/installing-chris-brodys-sqlite-database-with-cordova-cli-android/ which is my own site).
Try calling refresh on the scrollbar to get it to recognize the DOM change.
Best to wrap it in a 0-delay setTimeout, like so (Stolen from http://iscrolljs.com/#refresh)
:
setTimeout(function () {
myScroll.refresh();
}, 0);
If it takes time for the image to load, you'll want to wait until it's loaded entirely, unless you know the dimensions up-front.
When dealing with images loaded dynamically things get a little more complicated. The reason is that the image dimensions are known to the browser only when the image itself has been fully loaded (and not when the img tag has been added to the DOM).
Your best bet is to explicitly declare the image width/height. You'd do this like so:
function querySuccess (results) {
var path = results.rows.item.category +
"/" + results.rows.item.subcat +
"/" + results.rows.item.filename_lg;
var img = document.createElement('img');
img.width = 100;
img.height = 100;
img.src = path;
document.getElementById('output').appendChild(img);
// need to refresh iscroll in case the previous img was smaller/bigger than the new one
iScrollInstance.refresh();
}
If width/height are unknown you could save the image dimensions into the database and retrieve them together with the image path.
function querySuccess (results) {
var path = results.rows.item.category +
"/" + results.rows.item.subcat +
"/" + results.rows.item.filename_lg;
var img = document.createElement('img');
img.width = results.width;
img.height = results.height;
img.src = path;
document.getElementById('output').appendChild(img);
// need to refresh iscroll in case the previous img was smaller/bigger than the new one
iScrollInstance.refresh();
}
If you can't evaluate the image dimensions in any way then you have to wait for the image to be fully loaded and at that point you can perform an iScroll.refresh(). Something like this:
function querySuccess (results) {
var path = results.rows.item.category +
"/" + results.rows.item.subcat +
"/" + results.rows.item.filename_lg;
var img = document.createElement('img');
img.onload = function () {
setTimeout(iScrollInstance.refresh.bind(iScrollInstance), 10); // give 10ms rest
}
img.onerror = function () {
// you may want to deal with error404 or connection errors
}
img.src = path;
document.getElementById('output').appendChild(img);
}
Why is the viewport user-scalable prop different on each sample? works=no, broken=yes
Just an observation.
fwiw, here are a few things to look into:
Uncomment the deviceReady addListener, as Cordova init really depends on this.
Your loaded() method assigns myScroll a new iScroll, then explicitly calls onDeviceReady(), which then declares var myScroll; -- this seems inherently problematic - rework this.
If 1 & 2 don't help, then I suggest moving queryDB(tx); from populateDB() to successCB() and commenting out the myScroll.refresh()
And just a note, I find that logging to console is less intrusive than using alerts when trying to track down a symptom that seems to be messing with events firing, or timing concerns.

Chrome: Prevent image reload when rebuilding image elements

Using AngularJS:
I'm displaying a list of images with ng-repeat. When I reset and rebuild the model (get new data from backend), I'm displaying the same images as before.
I understand these are new elements created by ng-repeat, but the image srcs are the same. Unlike IE or firefox, Chrome tries and gets a 403 for those same images and then renders them.
That causes a flicker. On IE and Firefox the images come from cache. No hit on the server to check for image changes. No flicker.
How can I prevent that? Should the images be served with some cache header? I tried loading the images to a dataurl, but then I hit the CORS problem, and would have to proxy those images on the backend to get them.
Possibly related: Chrome sometimes reloads image after jQuery .appendTo, recieves 304
Thanks
Some fix would be related to preload the images in javascript and after that display them
function loadImages(arrayOfImgs) {
var imageNumber=0;
$(arrayOfImgs).each(function(){
(new Image()).src = this;
if(arrayOfImgs.length == imageNumber) $scope.showImages = true;
else imageNumber++;
});
}
// Usage:
loadImages([
'img1.jpg',
'img2.jpg'
]);
if you are retriving images from backend use it at success promise
i hope it helps you
Check that example retrinving images from backend:
$scope.loading = true;
getImages().then(function (response) {
var objects= response.results;
var listImages = [];
angular.forEach(objects, function (item) {
listImages.push(item.UrlImage);
});
function preload(arrayOfImages) {
var numImages = 0;
$(arrayOfImages).each(function () {
var img = (new Image());
img.src = this;
$(img).load(function () {
numImages++;
if (numImages == arrayOfImages.length){
$scope.loading = false;
}
});
});
}
preload(listImages);
});

Waiting for ajax response append and load content before firing function

Hi i got a project where i get posts from server with ajax post, them i detect images in appended posts and resize them based on their ratio using a function.
The problem is when i append new post's and try to fire the function, it detects the images as size (height and width) 0, cause the image ain`t loaded yet. I searched, but i won't found any answer, there is a way to detect if all images in ajax response (where it contains, other elements) have been loaded using .onload or another alternative?
**Update**
I figure it out:
Checking for img elements length inside ajax response:
$("#yourelement").append(html);
var $dialog = $(html);
imglength = $dialog.find("img").length;
Add a count++ on every img loaded, and check if its equal to img length:
n_images = 0;
$("#yourelement img").on('load', function(){ // check for every new image loaded in #
n_images++;
if (n_images == imglength) {
//alert(imglength); // I used to verify if it works
yourfunction(); // will fire when all new images have been appended and loaded
}
});

jQuery .load() wait till content is loaded

How to prevent jQuery $('body').load('something.php'); from changing any DOM till all the content from something.php (including images,js) is fully loaded
-Lets say some actual content is:
Hello world
And something.php content is:
image that loads for 10 seconds
20 js plugins
After firing .load() function nothing should happen, till images an js files are fully loaded, and THEN instantly change the content.
some preloader may appear, but its not subject of question.
[edit]----------------------------------------------------------------------
My solution for that was css code (css is loaded always before dom is build) that has cross-browser opacity 0.
.transparent{
-moz-opacity: 0.00;
opacity: 0.00;
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha"(Opacity=0);
filter: progid:DXImageTransform.Microsoft.Alpha(opacity=0);
filter:alpha(opacity=0);
}
And it prevent from bad flickr of content usually but not always. Now its possible to detect somehow that content is loaded by jQuery ajax and apply some show timeout and so on. But in fact question is still open.
To make now a little more simple example for that question:
How to begin changing DOM after $('body').load('something.php') with 3000ms delay after clicking the link that fire .load('something.php') function? (Browser should start downloading instantly, but DOM changing has to be initiated later)
Use .get instead and assign the contents in the success callback:
$.get('something.php', function(result) {
$('body').html(result);
});
There are some implementation details you may have to solve yourself, but here's a rough solution:
Don't use .load() directly. It can't be changed to wait for all images to load.
Use $.get() to fetch the HTML into a variable, let's call it frag.
Use $(frag).find('img').each(fn) to find all images and dump each this.src inside a preloader.
var images = [],
$frag = $(frag),
loaded = 0;
function imageLoaded()
{
++loaded;
// reference images array here to keep it alive
if (images.ready && loaded >= images.length) {
// add $frag to the DOM
$frag.appendTo('#container');
}
}
$frag.find('img').each(function() {
var i = new Image();
i.onload = i.onerror = imageLoaded;
i.src = this.src;
images[images.length] = i;
});
// signal that images contains all image objects that we wish to monitor
images.ready = true;
Demo
Once all images are loaded, append the earlier frag to the DOM using $frag.appendTo('#container').
Here is a quick proof of concept that loads relevant images before inserting an HTML fragment into the DOM: http://jsfiddle.net/B8B6u/5/
You can preload the images using the onload handler to trigger iterations:
var images = $(frag).find('img'),
loader = $('<img/>');
function iterate(i, callback) {
if (i > 0) {
i--;
loader.unbind("load");
loader.load(function() {
iterate(i, callback);
});
loader.attr('src', images[i].src);
}else{
callback();
}
}
iterate(images.length,function(){
$('#container').html(frag);
});
This should work, since each image is loaded after the previous one has finished loading.
Have you tried this?
$(function(){$('body').load('something.php')});
Edit: I just realized you are actually wanting to wait for the stuff to load before it get's placed in the body.
Here are three links to similar questions.
Preloading images with jQuery
Is it possible to preload page contents with ajax/jquery technique?
Preloading images using PHP and jQuery - Comma seperated array?
You can probably adapt those to scripts too.
This might work too.
$.ajax({
'url': 'content.php',
'dataType': 'text',
'success': function(data){
var docfrag = document.createDocumentFragment();
var tmp = document.createElement('div'), child;
//get str from data here like: str data.str
tmp.innerHTML = str;
while(child = tmp.firstChild){
docfrag.appendChild(child);
}
$('body').append(docfrag);
}
});
It's a longer way of doing what Shadow Wizard suggests, but it will probably work.
Hm. Never mind. Jack's answer looks the best. I'll wait a while and if no one likes my answer I'll delete it.
Edit: It looks like appending to documentfragments can do http requests.
Any script using createDocumentFrament may benefit from preloading.
In this question they want no http requests even though that's what createDocumentFragment is doing:
Using documentFragment to parse HTML without sending HTTP requests.
I can't be sure if this is true for all browsers or just when the console.log is run, but it could be a good option for preloading if this behavior is universal.

images not loading in websockets

I have a problem loading images
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
alert('it loaded');
bgReady = true;
};
bgImage.src = "images/background.png";
the alert does not appear when the websocket server is running.
The alert will appear if I remove the socket code and turn the server off.
I have already placed alerts throughout the code to see how far it will run without breaking.
Nothing seems to be breaking except the image does not seem to want to load.
any suggestions will be helpful.
I was accessing files from a different port so thats why they were not loading

Resources