Sending information through a for loop - javascript

At the moment I'm making another html5/javascript ad. This one uses multiple data from cookies. In order to render everything properly I have made a for-loop that gets the information and then sends it to another function afterwards.
My problem is that it loads too quick the first time so it skips the images. Each time I have to refresh the ad before it shows properly. All the onload functions I have used failed so far (sending the wrong data, nothing at all or only 1 piece of it).
Here is the relevant part of the project:
for (var i=0; i < 3; i++){
pT.push("pT"+[i]);
pM.push("pM"+[i]);
ctx.push("ctxP"+[i]);
cvs.push("cvsP"+[i]);
cvs[i] = document.getElementById('canvas'+[i]);
ctx[i] = cvs[i].getContext('2d');
pT[i] = new Image();
pT[i].onload = function(){
console.log("pT: "+ this.height);
}
pT[i].src = data.products[i].imageUrl;
pM[i] = new Image();
pM[i].onload = function(){
console.log("pM: "+ this.height);
}
pM[i].src = data.products[i].imageUrl;
testing(pT[i], pM[i]);
}
function testing(pThumb, pMain){
console.log(pThumb.height);
}
What I want is a method so all the information gets send when everything is done loading.

pT[i].onload = function() {
alert("Image is Loaded, do you thing on the image here");
}
otherFunction(pT,pM);
function otherFunction(pT,pM) {
console.log(pT,pM);
}
pT[i] = new Image();
pT[i].onload = function(){
pM[i] = new Image();
pM[i].onload = function(){
console.log("pM: "+ this.height);
testing(pT[i], pM[i]);
}
}
pT[i].src = data.products[i].imageUrl;
pM[i].src = data.products[i].imageUrl; // this is very ugly but you'll be sure to call your function when both image are ready. Since i'm not the best with Canvas, I will accept any edit for a better code.

Related

Can anyone tell me how to trigger a function when the mouse is pressed and continues untill it is released in p5.js

I was trying to add an image using p5 and ml5 In my website where user can train there own image and get the predicted output over webcam I tried implementing it by using
var addImage;
var mobilenet;
mobilenet = ml5.featureExtractor('MobileNet', modelReady);
classifier = mobilenet.classification(video,videoReady);
addImage = createButton('Insert');
addImage.mousePressed(function (){
classifier.addImage('Insert');
});
but for every image, I need to press the mouse button to insert I just want to make it something like this
**On mousePress()
function to add multiple image;
On mouseRelease()
stop;**
From this reference, this should work;
var addImage;
var mobilenet;
var drawImageInterval = null;
mobilenet = ml5.featureExtractor('MobileNet', modelReady);
classifier = mobilenet.classification(video,videoReady);
addImage = createButton('Insert');
addImage.mousePressed(function (){
if(mouseIsPressed && !drawImageInterval){
drawImageInterval = setInterval(function(){
classifier.addImage('Insert');
}, 1000);
} else {
clearInterval(drawImageInterval);
drawImageInterval = null;
}
});

Image duplication after multiple file input

Have this issue here: I want to upload several images at once and show them directly afterwards in the browser. Everything is fine. However, doing this on mobile, sometimes I don't get all the images, but duplicates of another one from the file array. I have a suspicion, that this has to do with hardware limitations, since on PC everything works fine, but not on mobile.
Here is the fiddle. You can check it via mobile to see if duplicates appear.
So in result I get this on mobile. It wasn't two images in the selection, only one:
Here I have the Javascript snippet. Is there any room for improvement? Espacially onload processes are really confusing me from time to time. Is there any chance to write it better?
Javascript:
jQuery('.upload-mobile').change(function(){
jQuery('body').toggleClass( "loading" );
var imagecounter = jQuery(this)[0].files.length;
var loadcounter = 0;
for(var i = 0; i<imagecounter;i++){
for(var p = 1;p<=12;p++){
if(jQuery('#preview'+p).length<=0){
jQuery('.image-collection').prepend(jQuery('<div></div>',{id:'preview'+p,css:{'display':'inline-block'}}));
break;
};
}
var file = this.files[i];
var reader = new FileReader();
reader.onload = function(e){
for(var w = 1;w<=12;w++){
if(jQuery('#preview'+w).children().length>0) {
}
else{
var img = document.createElement("img");
img.src = e.target.result;
img.id = 'img'+w;
img.className += " img-responsive";
img.className += " border-blue";
img.className += " image-small";
img.className += " image-cover";
img.style.display='none';
document.getElementById("preview"+w).appendChild(img);
break;
}
}
loadcounter++;
if(loadcounter==imagecounter){
var count = jQuery('.image-collection').children().length;
jQuery('.image-small').delay('1500').fadeIn('3000', function(){
jQuery('#image-counter').text(count+'/12');
jQuery('body').removeClass( "loading" );
if( jQuery('#image-counter').text()=='12/12'){
jQuery('#upload-photos').fadeOut('200', function(){
jQuery('#three-cube-compact').fadeIn('200');
})
}
});
}
};
var image = reader.readAsDataURL(file);
}
});
EDIT:
I tried to use the forEach function. I didn't use the for each loops earlier, so I can not say much about the difference between foreach and for. I can't say if it works better or not, but I have seen less duplicates (maybe I didn't check to often to asume good functionality of it). It almost works, but maybe there is another way to make it work flawlessly?
Javascript:
jQuery('.upload-mobile').change(function(){
jQuery('body').toggleClass( "loading" );
var imagecounter = jQuery(this)[0].files.length;
var loadcounter = 0;
Array.from(this.files).forEach(function (image, index){
for(var p = 1;p<=12;p++){
if(jQuery('#preview'+p).length<=0){
jQuery('.image-collection').prepend(jQuery('<div></div>',{id:'preview'+p,css:{'display':'inline-block'}}));
break;
};
};
var reader = new FileReader();
reader.onload = function(e){
for(var w = 1;w<=12;w++){
if(jQuery('#preview'+w).children().length>0) {
}
else{
var img = document.createElement("img");
img.src = e.target.result;
img.id = 'img'+w;
img.className += " img-responsive";
img.className += " border-blue";
img.className += " image-small";
img.className += " image-cover";
img.style.display='none';
document.getElementById("preview"+w).appendChild(img);
break;
}
}
loadcounter++;
if(loadcounter==imagecounter){
var count = jQuery('.image-collection').children().length;
jQuery('.image-small').delay('1500').fadeIn('3000', function(){
jQuery('#image-counter').text(count+'/12');
jQuery('body').removeClass( "loading" );
if( jQuery('#image-counter').text()=='12/12'){
jQuery('#upload-photos').fadeOut('200', function(){
jQuery('#three-cube-compact').fadeIn('200');
})
}
});
}
};
var pic = reader.readAsDataURL(image);
});
});
EDIT2:
The fiddle was updated
EDIT3:
Added an image of the mobile screen. I also figured out it might has something to do with the file explorer on the mobile device. When I select using the first file explorer, I don't get the duplication bug:
However, by clicking on Browse ("Durchsuchen" on the image), I get to another file explorer. And using that one creates this "duplication bug":
Is there maybe a way to solve this or maybe to disable the Browse button?

Loading an image but onload/onerror not working as expected

I have a div
<div id='cards'>
Which I want to fill with images based on some logic. But only when images are first loaded into memory. Otherwise, through onerror I wanna fill in some text..
function pasteCard(card, to){
if (typeof(card) == 'string')
card = [card];
var image = [];
for (var i = 0; i < card.length; i++) {
image[i] = new Image();
image[i].src = '/sprites/open/' + card[i] + '.png';
image[i].onload = function() {
pasteImage(to, image[i]);
}
image[i].onerror = function() {
pasteText(to, card[i]);
}
// alert(card[i]) #1
}
function pasteImage(to, image) {
to.append(image);
}
function pasteText(to, text) {
// alert(card[i]) #2
to.append(text);
}
}
pasteCard(['ABC123', 'DEF456', 'GHI789'], $('#cards'));
But this isn't working.
Problem/weirdness: If only #2 alert is active it returns nothing. But strangely if #1 alert is also active it does kinda work... (but still doesn't load my images, and mostly fails too when other code is involved)
Question: Why is it not working without #1 alert (at least in that jsfiddle)
suggestions?: what should I do?
Onload and onerror events are fired (executed) outside the scope of your function so your variables will be undefined. In the event method you have access to this which is the image object. You can set a data attribute to each image and access that in your error event.
Here is an example:
http://jsfiddle.net/7CfEu/4/
The callbacks are not in the same scope as your image array is - therefor you need to declare a variable then will "connect the scopes" and use it inside the callbacks
also the i variable probably changes until the callback is fired - so by using it inside the callback you will get undefined behavior
for (var i = 0; i < card.length; i++) {
var current_card = card[i];
var current_image = new Image();
current_image.onload = function() {
pasteImage(to, current_image);
}
current_image.onerror = function() {
pasteText(to, current_card);
}
current_image.src = '/sprites/open/' + current_card + '.png';
image[i] = current_image;
}
Fiddle: http://jsfiddle.net/7CfEu/6/
(Also - closing the div tag is never a bad idea)
Just in case anyone ends up here for same reason I did.
Was going crazy because onload and onerror were not firing in the page I was building. Tried copy pasting
var myimage = new Image();
myimage.onload = function() { alert("Success"); };
myimage.onerror = function() { alert("Fail"); };
myimage.src = "mog.gif" //Doesn't exist.
Which was working within codepen and random otherwise blank pages.
Turns out the problem I was having was that I was doing AJAX requests earlier in the page. This involved authorization which in turn involved a call to
setRequestHeader();
This was resulting in a net::ERR_FILE_NOT_FOUND error instead of the expected GET mog.gif 404 (Not Found)
This seemed to prevent proper triggering of events.
Revert with
xhr.setRequestHeader("Authorization", "");

Can I "pre-load" an image with JS to be used as a CSS background-image?

Can images be preemptively loaded into the page with javascript so that they can be used at any time as a CSS background image without any request/upload delay?
If so, how?
You don't even need to use JS for this (with the downside of delaying the page load event). Include something like this:
<img src="/path/to/image.jpg.png.gif.bmp" style="display: none" />
This will trigger a request for the image, and add it to the local cache. When you set the CSS background-image property, the image will already be in the local cache, eliminating the delay of another request.
Alternatively, you can accomplish the same thing without delaying the page load by creating the images in JavaScript (this solution allows for multiple images):
function preload(list, callback, imageCallback) {
var at, len;
at = len = list.length;
for (var i = 0; i < len; i++ ) {
var img = new Image();
img.onload = function() {
if( imageCallback ) {
imageCallback.call(this, this, len-at, len);
}
if( !--at ) {
callback(list);
}
};
img.src = list[i];
list[i] = img;
}
}
You'd call this with:
var list = preload(["1.png","2.png","3.png" ... ], function complete(list) {
console.log('images all loaded!');
}, function loaded(image, index, listCount) {
console.log('image ' + index + ' of + 'listCount + 'is loaded');
});
(Thanks to #rlemon for the preload code)
I don't think that using an hidden img tag is the correct way, i'd rather use an "new Img(url)" and attaching to it an onload event where you can set the image as background-image to the element you want.
img = new Image();
img.onload = function(){
// set background-image
};
img.src = image_url;
be sure to put img.src after attaching onload, or you risk that the image is loaded before the event is attached.
Maybe a more complete base to build on:
function preload(list, callback, imageCallback, errorCallback) {
if (typeof(list) === "undefined"
|| list.length === 0) {
return;
}
var len = list.length;
var timers = {};
var checkLen0 = function() {
if (len === 0) {
if (typeof(callback) === "function") {
callback();
}
delete(timers)
}
}
var onload = function() {
clearTimeout(timers[img]);
if (typeof(imageCallback) === "function") {
imageCallback.call(img);
}
len--;
checkLen0();
}
var onerror = function() {
clearTimeout(timers[img]);
if (typeof(errorCallback) === "function") {
errorCallback.call(img);
}
len--;
checkLen0();
}
for (var i = 0; i < list.length; i++ ) {
var img = new Image();
img.onload = onload;
timers[img] = window.setTimeout(5000, onerror);
img.src = list[i];
}
}
While SomeKittens answer is valid, it'll delay the page load as commented by Jimmy. If you are using jquery, I'd go with something like this instead to keep your style, structure and logic separated:
<style>
.preload-img { display: none; }
</style>
...
<div class = "preload-img">/path/to/image.jpg.png.gif.bmp</div>
...
<script>
$(document).ready(function(){
$(".preload-img").each(function(){
preloadImage = new Image();
preloadImage.src = $(this).html();
});
});
</script>
Of course, from there on you can optimize/change it. The advantadge of this is that you can create the <div> dynamically with PHP and you can have all your javascript cached properly as a separated file.
There is an excellent framework for this job called Emerge.js
http://ilyabirman.net/projects/emerge/
Quote from project page:
Emerge.js is a framework for coordinated page loading. Normally, when a complex web page is loading, images appear in random order, causing unpleasant flashing. To replace it with nice and coordinated animations, programming is required. Emerge.js simplifies the task by removing the need to write any Javascript code. The framework uses a declarative approach, where you specify a desired behavior for each element and do not think about the implementation. Emerge.js uses jQuery.
Just as a caveat to SomeKittens' answer above, a particularly large background image should probably be added as a hidden background / via JavaScript after page load, as content images delay the firing of window.onload and may therefore create the perception of a slow loading page.
Given that it sounds like you're using dynamic content anyway, this may be an acceptable solution. It also allows you to do preloading programmatically as required, which may be better for maintenance.

On Click preload images using javascript

Directly calling preload function works without any issues. But when preload() is called onClick,even after loading of images ,not ending its processing and that can be viewed as "loading..." in a browser
function preload(images) {
if (document.images) {
var i = 0;
var imageArray = new Array();
imageArray = images.split(',');
var imageObj = new Image();
for(i=0; i<=imageArray.length-1; i++) {
document.write('<img src="' + imageArray[i] + '" width="335px" height="180px" alt="[Alternative text]" />');
imageObj.src=imageArray[i];
}
}
}
Gallery
You can't call document.write after the page is loaded. If you want to add something to the page, you must call DOM manipulation functions like document.createElement (see example).
But what you do in your function doesn't look like preloading but rather like direct insertion of images in the page.
If you want to preload images, that is to ask the browser to cache them so that they are instantly available later, then you'd better use XmlHttpRequest instead of creating Image elements. Issuing XmlHttpRequest requests doesn't make the browser display a hourglass and the user doesn't feel like something is happening.
I made a small "library" last week-end just for this : easily preload resources.
var preload = (function(){
var queue = [], nbActives = 0;
function bip(){
if (queue.length==0 || nbActives>=4) return;
nbActives++;
var req = new XMLHttpRequest(), task=queue.shift();
req.open("GET", task.src, true);
req.onload = function () {
nbActives--;
bip();
if (task.callback) task.callback(task.src);
};
req.send();
}
return function(src, priority, callback) {
queue[priority?'unshift':'push']({src:src, callback:callback});
bip();
}
})();
Usage :
preload('path/to/file.png'); // preload the file
preload('path/to/file.png', true); // preload the file with high priority
preload('path/to/file.png', false, callback); // preload the file and be notified when it's finished
Github repository : https://github.com/Canop/preload

Categories

Resources