I'm trying to create a scroll-based animation functionality similar to this project.
https://codepen.io/j-v-w/pen/ZEbGzyv
But the thing is, when I define and execute this snippet inside useEffect, this will cause the images to flick, meaning they are not preloaded
const preloadImages = () => {
for (let i = 1; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(i);
}
};
preloadImages();
But if I add console.log(img), it will load images and work fine.
const preloadImages = () => {
for (let i = 1; i < frameCount; i++) {
const img = new Image();
img.src = currentFrame(I);
console.log(img)
}
};
preloadImages();
Is there any way to load the images without logging it?
this is my whole code for refrenece
https://replit.com/#farhadham/GiantTepidGraduate#src/App.jsx
Related
I have the following code where I am loading only one image. But I want to load multiple images from e folder and then to fade them in and out. But what I am interesting in, is how can I load all images from a folder without to repeat the code, as src="frames/frame_1" src="frames/frame_2" i want something soft as src="frames/frame_" + i + ".jpg" where i is the number of the frame
this is how I load only one image now
var img = new Image();
var div = document.getElementById('foo');
img.onload = function() {
div.appendChild(img);
};
img.src = 'frames/frame_1.jpg';
It's relatively simple. You basically put the code you already had in a loop:
var img, i,
imageCount = 5,
div = document.getElementById('foo');
for(i = 0; i < imageCount; i++){
img = new Image();
img.onload = function() {
div.appendChild(img);
};
img.src = 'frames/frame_' + i + '.jpg';
}
You can use a loop for :
var img,
div = document.getElementById('foo');
for (var i = 0, nbImg = 5; i < nbImg; i++) {
img = new Image();
img.onload = function() {
div.appendChild(img);
};
img.src = 'frames/frame_'+i+'.jpg';
}
I'm trying to preload a set of images and draw first one from the list on to multiple canvases using canvas constructor.
It seems I can't even start loading images using prototype function. Console log says this.setImages is not a function. I'm just starting with js therefore it might be a very simple mistake.
I left some comments in the code i hope it will make it a bit clear.
There're other ways to achieve what I'm asking but in my case i have to use constructor function.
var sources = [
'http://i.telegraph.co.uk/multimedia/archive/02830/cat_2830677b.jpg',
'http://r.ddmcdn.com/w_622/u_0/gif/05-kitten-cuteness-1.jpg',
'http://simplycatbreeds.org/images/Kitten.jpg'];
var images = [];
var canvas1 = new canvas('canvas1');
var canvas2 = new canvas('canvas2');
// load images using callback function
setImages(sources, function(images){
window.alert("Done loading... Start!");
this.draw();
});
// canvases constructor
function canvas(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.canvas.style.width = '100%';
this.canvas.style.height = '100%';
this.canvasId = canvasId;
this.setImages();
};
// preloading images
canvas.prototype.setImages = function(sources, callback){
var cnt = 0;
function imagesLoaded(){
cnt++;
if (cnt >= sources.length){
// passing the objet containing images to load as parameteres
callback(images);
}
}
for (var i=0; i<sources.length; i++) {
images[i] = new Image();
images[i].src = sources[i];
images[i].onload = function(){
imagesLoaded();
}
}
};
canvas.prototype.draw = function() {
// some code to manipulate image to be added here...
this.context.drawImage(images[1], 0, 0);
};
here is FIDDLE example
There are some things I have fixed.
First, I have moved the code that creates the two objects to the end of the JS. The reason is that the prototype functions must be loaded before you try to access them. I recommend using a event listener such as window.onload to prevent the code from starting before everything is loaded.
Second, I changed the setImage so it is called on the canvas objects.
var sources = [...];
var images = [];
// load images using callback function
// canvases constructor
function canvas(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.canvas.style.width = '100%';
this.canvas.style.height = '100%';
this.canvasId = canvasId;
//I removed this since it does not have the right params
//this.setImages();
};
// preloading images
canvas.prototype.setImages = function(sources, callback){
var cnt = 0;
var obj = this;
function imagesLoaded(){
cnt++;
if (cnt >= sources.length){
// passing the objet containing images to load as parameteres
callback(images, obj);
}
}
for (var i=0; i<sources.length; i++) {
images[i] = new Image();
images[i].src = sources[i];
images[i].onload = function(){
imagesLoaded();
}
}
};
canvas.prototype.draw = function() {
// some code to manipulate image to be added here...
this.context.drawImage(images[1], 0, 0);
};
var canvas1 = new canvas('canvas1');
canvas1.setImages(sources, function(images){
window.alert("Done loading... Start!");
this.draw();
});
var canvas2 = new canvas('canvas2');
canvas2.setImages(sources, function(images, obj){
window.alert("Done loading... Start!");
obj.draw();
});
Demo
Try moving setImages function inside canvas function like this:
function canvas(canvasId)
{
this.setImages = function(...){ };
...
this.setImages();
}
In line 13 you should call setImages on a canvas object: canvas1.setImages();
I had problem with event listener and image loader in my code. When i try to load and check status of loaded image based on event listener some of images skipped. I think browser can handle only one event and when active one isn't stopped next can work and skip its work. So few of images return wront status and can be used. Just give me some advices about this. Here is my code:
//Image loader
var urlList = [
'images/ground_02.png', // 0 - FG
'images/ground_layer0.png', // 1 - CITY
...
];
var urlListLength = urlList.length; //length of URL-array
var iCount = new Number(0); // Create zero-counter
var images = new Array(); // All images array. Each elem stores one image
var imageInfo = function(imageName, imageCount, imageWidth, imageHeight) { // Constructor for image data container
this.imageName = imageName; // Url of image
this.imageCount = imageCount; // Frames
this.imageWidth = imageWidth; // Width of images
this.imageHeight = imageHeight; // Height of images
};
var imageData = new Array(); // Images data array
for (var i=0; i!=urlListLength; ++i) { // Loop for each image load
images[i] = new Image(); // Image array.
images[i].addEventListener('load', function(i) {
imageData.push(new imageInfo(images[iCount], images[iCount].width/images[iCount].height, images[iCount].width, images[iCount].height));
iCount++;
if (iCount == urlListLength) {
var loaded = true;
loop();
};
}, false);
images[i].src = urlList[i];
images[i].onerror=function() {
alert("FAIL "+this.src);
};
};
You have a problem at least here:
imageData.push(new imageInfo(images[iCount], images[iCount].width/images[iCount].height, images[iCount].width, images[iCount].height));
load event is fired once image is loaded by browser. But it is not necessary that it will be fired in the same order as load is started. Basically, images[2] could be loaded before images[0] and images[1] and in that case iCount won't work.
You can use this instead of images[iCount] as in this case this will point to exact that image which has fired load event.
imageData.push(new imageInfo(this, this.width/this.height, this.width, this.height));
I think browser can handle only one event and when active one isn't
stopped next can work and skip its work.
Nope. That is wrong. Regularly all events will be fired. But JS is single threaded, so it will simply put an event into a queue and will run next event after previous is done. It will not skip any event.
This should work for all browsers, including IE6.
var list = [
'images/ground_02.png',
'images/ground_layer0.png'
],
images = {};
function loadImage() {
images[this.src] = {
loaded: (this.width > 0 ? true : false),
src: this.src,
width: this.width,
height: this.height
};
if (list.length < 1) return;
var url = list.pop(),
img = new Image();
img.onload = loadImage;
img.onerror = loadImage;
img.src = url;
}
loadImage(); // Initialize loading
And if you need to check if an image has been loaded:
function isImageLoaded(src) {
return (images[src] && images[src].loaded);
}
if (isImageLoaded('images/ground_02.png')) alert('Yes!');
I am playing with the canvas, and it seems to be working great in FF6, but in Chrome 13, the sprite that I am drawing does not appear reliably. I have done some research and found that the problem stems from the function firing before the asset has loaded completely.
Fiddle here:
http://jsfiddle.net/LqHY9/
Relevant Javascript:
function sprite(ipath, sh, sw, ih, iw){
/* BASIC INFO FOR SPRITE */
this.frameWidth = sw;
this.frameHeight= sh;
frame_rows = ih/sh;
frame_columns = iw/sw;
num_frames = frame_columns*frame_rows ;
this.frame = new Array();
frameNumber = 0;
for(row = 0; row<frame_rows; row++){
for(i=0;i<frame_columns;i++){
this.frame[frameNumber] = {};
this.frame[frameNumber].offsetX = this.frameWidth*i;
this.frame[frameNumber].offsetY = this.frameHeight*row;
frameNumber++
}
}
this.sheight = sh;
this.swidth = sw;
this.raw = new Image();
this.raw.src = ipath;
}
animation=new sprite("http://www.melonjs.org/tutorial/tutorial_final/data/sprite/gripe_run_right.png",64,64,64,512);
context.drawImage(animation.raw, animation.frame[0].offsetX, animation.frame[0].offsetY, animation.frameWidth, animation.frameHeight, 0, 0, animation.frameWidth,animation.frameHeight)
(Don't worry, my context variable is defined, I just cut that bit out, you can see the whole thing in the JSFiddle.)
The Image object has an onload event which you should hook into.
Assuming you have more than one image, you could implement a sort of a "loader". This would basically just take an array of image URLs, load each of them, and listen to their onload events. Once each image has loaded, it would in turn call some other function, which would signal that every resource has finished loading.
the Image() object has an onload(and onerror) event. If you need to execute something after it loads you can attach a function.
e.g.
var img = new Image();
img.onload = function() {
//do something
};
Just make sure you attach the onload before setting the src.
You need to use the onload handler for the image. You must set the handler before you set the .src for the object because in some browsers, the load event may fire immediately upon setting .src if the image is in the browser cache. Here's a piece of pseudo code:
var img = new Image();
img.onload = function () {
// image is now loaded and ready for handling
// you can safely start your sprite animation
}
img.src = "xxx";
You can see related sample code from another answer I wrote here: jQuery: How to check when all images in an array are loaded?.
function Sprite(urls, speed, box)
{
var that = this, running = false, interval = 0, loaded = false;
that.urls = urls;
that.speed = speed;
that.images = new Array();
that.box = box || { x: 0.0, y: 0.0, w: 64, h: 64 };
for(var i = 0; i < that.urls.length; ++i)
{
that.images[i] = new Image();
that.images[i].src = that.urls[i];
that.images[i].id = i;
var len = that.urls.length;
that.images[i].onload = function(){ if(parseInt(this.id) === len) { loaded = true; } };
}
that.current = 0;
var Draw = function(ctx)
{
if(loaded)
{
var curr = that.images[that.current];
ctx.drawImage(curr, 0.0, 0.0, curr.width, curr.height, that.box.x, that.box.y, that.box.w, that.box.h);
}
};
that.Run = function(ctx)
{
if(!running)
{
running = true;
interval = setInterval(function(){
Draw(ctx);
if(that.current < that.urls.length)
{
that.current++;
}
else
{
that.current = 0;
}
}, that.speed);
}
};
that.Clear = function()
{
if(running)
{
running = false;
clearInterval(interval);
}
};
}
// Exemple
var test = new Sprite(["image1.png", "image2.png", "image3.png"], 250);
test.Run(myContext);
I have an automatic slideshow on the main page of some site. Images are rotating every 10 seconds, but when they appear for the first time they aren't already loadead (I guess), so a blank is show.
I think that preloading these images they will show fine, but I don't know how to preload them. I use the following code to preload all the images of the page, but it doesn't seems to work:
function preloadAllImages() {
for (i = 0; i < document.images; i++) {
var img = new Image();
img.src = document.images[i];
}
}
So, how can I make this work?
Try
function preloadAllImages() {
for ( var i = 0; i < document.images.length; i++) {
var img = new Image();
img.src = document.images[i];
}
}
I believe you are missing the length attribute.