JS: Determinining image dimensions only partially successful - javascript

I'm creating a small webapplication with JS/HTML/CSS where the user has a dropdown menu to choose from 13 different images. Option 1 is default, and when the user chooses a different option the application is refreshed and the dimensions of other objects in the application adjust to the dimensions of the new image.
In order to access the image dimensions (height and width) of the 13 different images an JS loop starts and stores the dimensions in two arrays.
var height_array = []
var width_array = []
for (i = 1; i <= 13;i = i + 1) {
var img = new Image();
if (i <= 9){
img.src = "img/rehe/RE0"+i+"/001.png";
}
else{
img.src = "img/rehe/RE"+i+"/001.png";
}
height_array.push(img.height);
width_array.push(img.width);
}
What I dont understand, is that the loop is sucessfull only part time, at times the arrays are empty or only partially populated. Naturally, the application is then built up all wrong.. A refresh helps in this case, but it is still anoying.
I have a preversion of this very simple application here: http://wieselundco.ch/plenum2/index.html Thanks in advance!

The image has to load before you can get the dimensions
var height_array = []
var width_array = []
for (i = 1; i <= 13;i = i + 1) {
(function(j) {
var img = new Image();
img.onload = function() {
height_array[j] = img.height;
width_array[j] = img.width;
}
if (img.complete) img.onload();
if (j <= 9){
img.src = "img/rehe/RE0"+j+"/001.png";
} else {
img.src = "img/rehe/RE"+j+"/001.png";
}
})(i);
}

Related

How to retain order of array using each and image.onload

I'm trying to use image.onload function but async issue is occuring. I'm passing the data through array but it is not executing according to array order in the image.onload function. How can I fix this issue?
Object.entries(data).forEach(element => {
const brushtype = element[0]['brush']
const img = new Image();
img.onload = () => {
brushctx.drawImage(img, 0, 0);
}
img.src = brushtype;
}
The problem is the way you're requesting those images.
By doing
Object.entries(data).forEach(element => {
}
it's happening at the same time virtually. Whatever image finished loading will be drawn right-after.
If you want your images to be drawn in a specific order - e.g. the order it's listed in the array - you need to request a new one after the previous finished loading.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let myImages = ['https://picsum.photos/id/1/50/50', 'https://picsum.photos/id/22/50/50', 'https://picsum.photos/id/83/50/50', 'https://picsum.photos/id/64/50/50'];
function loadImages(index) {
let image = new Image();
image.onload = function(e) {
context.drawImage(e.target, index % 2 * 50, parseInt(index / 2) * 50);
if (index + 1 < myImages.length) {
loadImages(index + 1);
}
}
image.src = myImages[index];
}
loadImages(0);
<canvas id='canvas' width='200' height='200'></canvas>
To draw images in order of request you either need to wait until all images have loaded and then draw them only when the earlier image have been draw. This answer gives an example of both approaches.
Note That if there are any load errors none of the images may be drawn. In the second method an error will mean none to all but one are drawn.
Load first then draw
The snippet bellow loads first then draws. It stores the images in an array images and keeps a count of images loading. Counting up for each new image, and when an image load it counts down.
When the counter is zero when know all images have loaded and can then draw them all
var imgCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
img.src = element[0]['brush'];
images.push(img);
imgCount ++;
img.onload = () => {
imgCount --;
if (!imgCount) {
for(const img of images) { brushctx.drawImage(img, 0, 0) }
}
}
}
Draw only when first or previous loaded.
The alternative is to again create an array to hold all the images. But this time we track what has been drawn. Each time an image is loaded, we check if any of the images in the array before it have loaded, then we draw all images until we find a empty image slot.
var drawnCount = 0;
const images = [];
Object.entries(data).forEach(element => {
const img = new Image;
const imgIdx = images.length;
img.src = element[0]['brush'];
img.onload = () => {
images[imgIdx] = img;
while (images[drawnCount]) { brushctx.drawImage(images[drawnCount++], 0, 0) }
}
images.push(null);
}

Preloader with JavaScript

I have faced such a problem. I need to make a preloader with a percentage for a page but I don't know how. Actually, I don't need animation or simple preloader. What do I can and what do I have?
window.onload = function() {
var images = document.images,
imagesTotalCount = images.length,
imagesLoadedCount = 0,
preloader = document.getElementById('js_preloader'),
percDisplay = document.getElementById('js_preload__percentage');
for(var i = 0; i < imagesTotalCount; i++) {
image_clone = new Image();
image_clone.onload = image_loaded;
image_clone.onerror = image_loaded;
image_clone.src = images[i].src;
}
function image_loaded() {
imagesTotalCount++;
percDisplay.innerHTML = (((100 / imagesTotalCount) * imagesLoadedCount) << 0) + '%';
if(imagesLoadedCount >= imagesTotalCount) {
setTimeout(function() {
if(!preloader.classList.contains('done')) {
preloader.classList.add('done');
}
}, 1500);
}
}
};
This aproach allows to see all images to be downloaded and and calculate percentage. But how do I can also take in count the download of css and js files?
You could use the same approach, but with document.scripts and document.styleSheets collections.

How to add a 16x16 grid of pseudo-random tiles as a background in canvas (or other web language)

I have recently been working on a web based project using canvas on HTML5. The program consists of a 16x16 grid of tiles that have been pseudo-randomly generated. I am relatively new to canvas, but have built this program in several other environments, none of which however compile successfully to a web based language. this is the main code section that is giving me bother:
var A = 8765432352450986;
var B = 8765432352450986;
var M = 2576436549074795;
var X = 1;
var rx = 0;
var ry = 0;
this.image = new Image();
var i = 0;
var ii = 0;
while(i < 16)
{
while(ii < 16)
{
this.image = new Image();
this.image.src = "textures/grass.png";
x = (((A*X)+B)%M)%M;
if((x/2)%1 == 0)
{
this.image.src = "textures/grass.png";
}
if((x/8)%1 == 0)
{
this.image.src = "textures/hill.png";
}
if((x/21)%1 == 0)
{
this.image.src = "textures/trees.png";
}
if((x/24)%1 == 0)
{
this.image.src = "textures/sea.png";
}
if((x/55)%1 == 0)
{
this.image.src = "textures/mountain.png";
}
if((x/78)%1 == 0)
{
this.image.src = "textures/lake.png";
}
if((x/521)%1 == 0)
{
this.image.src = "textures/volcano.png";
}
if((x/1700)%1 == 0)
{
this.image.src = "textures/shrine.png";
}
if((x/1890)%1 == 0)
{
this.image.src = "textures/outpost.png";
}
if((x/1999)%1 == 0)
{
this.image.src = "textures/civ.png";
}
ctx = myGameArea.context;
ctx.drawImage(this.image,rx, ry, 20, 20);
ii ++;
rx += 20;
}
i ++;
rx = 0;
ry += 16;
}
I would like canvas to draw along the lines of this code above, effectively generating a grid like this
pre generated grid image
(please try and ignore the obvious bad tile drawings, I planned on either finding an artist or trying slightly harder on them when I get the game fully working.)
The black square is a separate movable object. I haven't got as far as implementing it in this version, but if you have any suggestions for it please tell me
in the full html file I have now, the canvas renders but none of the background (using the w3schools tutorials, I can make objects render however)
In short: how do I render a background consisting of a 16x16 grid of pseudo-random tiles on an event triggered or on page loaded, using canvas or if that does not work another web based technology
Thank you for your time.
A few problems but the main one is that you need to give an image some time to load before you can draw it to the canvas.
var image = new Image();
image.src = "image.png";
// at this line the image may or may not have loaded.
// If not loaded you can not draw it
To ensure an image has loaded you can add a onload event handler to the image
var image = new Image();
image.src = "image.png";
image.onload = function(){ ctx.drawImage(image,0,0); }
The onload function will be called after all the current code has run.
To load many images you want to know when all have loaded. One way to do this is to count the number of images you are loading, and then use the onload to count the number of images that have loaded. When the loaded count is the same as the loading count you know all have loaded and can then call a function to draw what you want with the images.
// Array of image names
const imageNames = "grass,hill,trees,sea,mountain,lake,volcano,shrine,outpost,civ".split(",");
const images = []; // array of images
const namedImages = {}; // object with named images
// counts of loaded and waiting toload images
var loadedCount = 0;
var imageCount = 0;
// tile sizes
const tileWidth = 20;
const tileHeight = 20;
// NOT SURE WHERE YOU GOT THIS FROM so have left it as you had in your code
// Would normally be from a canvas element via canvasElement.getContext("2d")
var ctx = myGameArea.context;
// seeded random function encapsulated in a singleton
// You can set the seed by passing it as an argument rand(seed) or
// just get the next random by not passing the argument. rand()
const rand = (function(){
const A = 8765432352450986;
const B = 8765432352450986; // This value should not be the same as A?? left as is so you get the same values
const M = 2576436549074795;
var seed = 1;
return (x = seed) => seed = ((A * x) + B) % M;
}());
// function loads an image with name
function addImage(name){
const image = new Image;
image.src = "textures/" + name + ".png";
image.onload = () => {
loadedCount += 1;
if(loadedCount === imageCount){
if(typeof allImagesLoaded === "function"){
allImagesLoaded();
}
}
}
imageCount += 1;
images.push(image);
namedImages[name] = image;
}
imageNames.forEach(addImage); // start loading all the images
// This function draws the tiles
function allImagesLoaded(){ /// function that is called when all the images have been loaded
var i, x, y, image;
for(i = 0; i < 256; i += 1){ // loop 16 by 16 times
ctx.drawImage(
images[Math.floor(rand()) % images.length]; //random function does not guarantee an integer so must floor
(i % 16) * tileWidth, // x position
Math.floor(i / 16) * tileHeight, // y position
tileWidth, tileHeight // width and height
);
}
}

dynamic image variable with onclick event

I have several canvases. I also have several picture URLs. I want to draw all pictures on the canvas. There is a problem in the drawing function. Drawing the image only works when the image loads completely, but I have to draw the image as it loads. I wrote following code:
for (var i = 2; i < length; i++) {
canvid[i] = "canv" + i;
img[i] = new Image();
img[i].src = "..\\images\\UploadImage\\"+ name + i + ".jpg";
img[i].onload = function () {
var c = document.getElementById(canvId[i]);
var cDraw = c.getContext("2d");
cDraw.drawImage(img[i], 0, 0);
};
I know this code has error, it's kind of pseudo code to show what I want.
Put your logic in
$(documet).ready(function(){
//logic
});
the answer is in following link
stack overflow link
when you want to call on click event on image variable you have to wait for it
so you couldn't use loop you have to put next call on previous image on load event .
var loadImages = function (imageURLarray) {
if (!(startPage < pages))
return;
canvid = "canv" + i;
img.src = imageURLarray[startPage];
// your top code
img.onload = function (e) {
// code, run after image load
var c = document.getElementById(canvid);
var cDraw = c.getContext("2d");
cDraw.drawImage(img, 0, 0);
startPage++;
loadImages(imageURLarray);
}
}
loadImages(imageURLarray);

Random image appear when website is loaded

I have 2 pictures for my website, and i want it to load one of them whem the website loads.
I have tried using some javascript. But i am quite new to all this.
This is how i am think i want to make it.
<div class="image">
Show one of 2 images here.
</div>
<script>
var r = Math.floor(Math.random() * 100) + 1;
if(r < 51) {
SHOW IMAGE 1
}
else {
SHOWIMAGE 2
}
</sccript>
So i was hoping someone could teach me how to actually turn this into functional code.
Thanks.
You can set the src attribute of an image directly using javascript, then use Math.random like you expected to pick between different image urls.
With an image tag with id 'random_image':
// images from wikipedia featured images/articles 2015-03-03
var img = document.getElementById('random_image');
if (Math.random() > .5) {
img.src = 'http://upload.wikimedia.org/wikipedia/en/thumb/4/45/Bradford1911.jpg/266px-Bradford1911.jpg';
} else {
img.src = 'http://upload.wikimedia.org/wikipedia/commons/thumb/a/ae/Pitta_sordida_-_Sri_Phang_Nga.jpg/720px-Pitta_sordida_-_Sri_Phang_Nga.jpg';
}
Here is a jsfiddle example: http://jsfiddle.net/8zd5509u/
1.way:
var _img = document.getElementById('id1');
var newImg = new Image;
newImg.onload = function() {
_img.src = this.src;
}
newImg.src = 'http://www.something.blabla.....';
another:
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] + '" />');// Write to page (uncomment to check images)
imageObj.src=imageArray[i];
}
}
}
Then in the of each web page, add the following code after you've called the main JavaScript file:
<script type="text/javascript">
preload('image1.jpg,image2.jpg,image3.jpg');
</script>

Categories

Resources