Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple images not load on canvas

I have created Circle using arc like following way.

var startAngle = 0;
var arc = Math.PI / 6;
var ctx;

var leftValue=275;
var topValue=300;	
	   
var wheelImg = ["http://i.stack.imgur.com/wwXlF.png","http://i.stack.imgur.com/wwXlF.png","cat.png","cock.png",
				"croco.png","dog.png","eagle.png","elephant.png","lion.png",
				"monkey.png","rabbit.png","sheep.png"];

function drawWheelImg()
{
	var canvas = document.getElementById("canvas");
  	if(canvas.getContext)
	{
		var outsideRadius = 260;
		var textRadius = 217;
		var insideRadius = 202;

		ctx = canvas.getContext("2d");	

		for(var i = 0; i < 12; i++)
		{
			var angle = startAngle + i * arc;

			ctx.beginPath();
			ctx.arc(leftValue, topValue, outsideRadius, angle, angle + arc, false);
			ctx.arc(leftValue, topValue, insideRadius, angle + arc, angle, true);
			ctx.fill();
			ctx.closePath();
			ctx.beginPath();
			ctx.arc(leftValue, topValue, outsideRadius, angle, angle + arc, false);
			ctx.shadowBlur=3;
			ctx.shadowColor="#A47C15";
			ctx.stroke();
			ctx.closePath();
			
			ctx.save();
			ctx.translate(leftValue + Math.cos(angle + arc / 2) * textRadius,
						topValue + Math.sin(angle + arc / 2) * textRadius);
			ctx.rotate(angle + arc / 2 + Math.PI / 2);
			var img = new Image();
			
			img.src = wheelImg[i];
			ctx.drawImage(img,-44, -25,50,40);
			ctx.restore();
		}
  	}
}	



function spin()
{
	drawWheelImg();
}

drawWheelImg();
<button class="btnSpin" onclick="spin();">Spin</button>

<canvas id="canvas" width="550" height="580"></canvas>

Problem is that it will not load when first page load. But when i click on spin button it will load all images.

Don't know what is the issue. Any help is greatly appreciated.

Note: Here in the question same issue is solve by img.onload function but that for only single image. If there is number of multiple images in array then it's not working.

like image 962
ketan Avatar asked Oct 31 '22 12:10

ketan


1 Answers

You want to preload the images.

To do this you can start the loading at the bottom of the page just before the closing </dody> tag.

<script>
    // an array of image URLs
    var imageNames = ["image1.png", "image2.jpg", ...moreImageNames];
    // an array of images 
    var images = [];
    // for each image name create the image and put it into the images array
    imageNames.forEach(function(name){
        image = new Image();   // create image
        image.src = name;      // set the src
        images.push(image);    // push it onto the image array
    });
</script>         

In the code that uses the images you just need to check if they have loaded yet. To do this just check the image complete attribute.

// draw the first image in the array
if(images[0].complete){  // has it loaded
    ctx.drawImage(images[0],0,0);  // yes so draw it
}

Note that complete does not mean loaded. If you proved a bad URL or there is another error the complete flag will still be true. Complete means the browser has finished dealing with the image. You will have to add an onload event if there is a chance that images may fail.

Handling Errors

If you are unsure that an image will not load you will have to devise a strategy to deal with the missing content. You will need to answer questions like, Can my app function without the image? Are there alternative sources to get the image from? Is there a way to determine how often this is likely to happen? How do I stop this from happening?

On the simplest level you can flag an image as loaded by adding your own semaphore to the image object during the onload event

    // an array of image URLs
    var imageNames = ["image1.png", "image2.jpg", ...moreImageNames];
    // an array of images 
    var images = [];
    // function to flag image as loaded
    function loaded(){
        this.loaded = true;
    }
    // for each image name create the image and put it into the images array
    imageNames.forEach(function(name){
        image = new Image();   // create image
        image.src = name;      // set the src
        image.onload = loaded; // add the image on load event
        images.push(image);    // push it onto the image array
    });

Then in code you will check for the loaded semaphore before using the image.

// draw the first image in the array
if(images[0].loaded){  // has it loaded
    ctx.drawImage(images[0],0,0);  // yes so draw it
}

Critical content

If you have images that are required for you app to function then you should redirect to an error page if there is a problem loading the image. You may have several servers so you can also try the different sources before giving up.

If you need to stop the app or try an alternative URL you will have to intercept the onerror image event.

To simplify your use of the images (100% sure the images are loaded when that app runs) you should start the parts that use the images only when all the images are loaded. One way to do this is to count all the images that are being loaded, and count down as the images load. When the counter reaches zero you know all the images have loaded and you can then call you app.

The following will load images, if they fail it will try another server (source) until there are no more options at which point you should redirect to the appropriate error page to inform the client that a monkey has put a spanner in the works. It counts the loading images and when all the images have loaded then it will start the app running, sure in the knowledge that all the image content is safe to use.

    // Server list in order of preferance
    var servers = ["https://fakesiteABC.com/", "http://boogusplace.com/", "http://foobarpoo.com.au/"];

    // an array of image URLs
    var imageNames = ["image1.png", "image2.jpg", ...moreImageNames];
    // an array of images 
    var images = [];
    // loading count tracks the number of images that are being loaded
    var loadingImageCount = 0;
    // function to track loaded images
    function loaded(){
        loadingImageCount -= 1;
        if(loadingImageCount === 0){
              // call your application start all images have loaded
              appStart();
        }
    }
    // function to deal with error
    function loadError(){  // the keyword "this" references the image that generated the event.
        if(this.retry === undefined){  // is this the first error
            this.retry = 1;   // point to the second server
        }else{
            this.retry += 1;  // on each error keep trying servers (locations)
        }
        // are the any other sources to try?
        if(this.retry >= servers.length){  // no 11
            // redirect to error page.
            return;
        }
        // try a new server by setting the source and stripping the 
        // last server name from the previous src URL
        this.src = servers[this.retry] + this.src.replace( servers[ this.retry - 1],"");
        // now wait for load or error
    }


    // for each image name create the image and put it into the images array
    imageNames.forEach(function(name){
        image = new Image();   // create image
        image.src = servers[0] + name;      // set the src from the first server
        image.onload = loaded; // add the image on load event
        image.onerror = loadError; // add the image error handler
        images.push(image);    // push it onto the image array
        loadingImageCount += 1; // count the images being loaded.
    });

There are many other strategies for dealing with missing content. This just shows some of the mechanism used and does not define a perfect solution (there is none)

like image 56
Blindman67 Avatar answered Nov 12 '22 18:11

Blindman67