Why is a delay needed when drawing a image into a canvas? - javascript

Here is the code:
var spriteFolder = "../../assets/Painter/sprites/";
var sprites = {};
sprites.background = new Image();
sprites.background.src = spriteFolder + "spr_background.jpg";
sprites.cannon_barrel = new Image();
sprites.cannon_barrel.src = spriteFolder + "spr_cannon_barrel.png";
sprites.cannon_red = new Image();
sprites.cannon_red.src = spriteFolder + "spr_cannon_red.png";
sprites.cannon_green = new Image();
sprites.cannon_green.src = spriteFolder + "spr_cannon_green.png";
sprites.cannon_blue = new Image();
sprites.cannon_blue.src = spriteFolder + "spr_cannon_blue.png";
var Canvas2D = {
canvas: undefined,
canvasContext: undefined
};
Canvas2D.initialize = function(canvasName) {
Canvas2D.canvas = document.getElementById(canvasName);
Canvas2D.canvasContext = Canvas2D.canvas.getContext("2d");
};
Canvas2D.clear = function() {
Canvas2D.canvas.clearRect(0, 0, Canvas2D.canvas.width, Canvas2D.canvas.height);
};
Canvas2D.drawImage = function(sprite, position, rotation, origin) {
Canvas2D.canvasContext.save();
Canvas2D.canvasContext.translate(position.x, position.y);
Canvas2D.canvasContext.rotate(rotation);
Canvas2D.canvasContext.drawImage(sprite,
0, 0, sprite.width, sprite.height,
-origin.x, -origin.y, sprite.width, sprite.height
);
Canvas2D.canvasContext.restore();
};
function init() {
Canvas2D.initialize("myCanvas");
setTimeout(function() {
Canvas2D.canvasContext.drawImage(sprites.background, 0, 0);
}, 1000);
}
document.addEventListener("DOMContentLoaded", init);
If I don't use setTimeout, then the image is not drawn. Why?

Because your images were not yet loaded.
Thanks to your 1sec timeout they have enough time to load.
Have a look at this example from MDN https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images
You need to use similar approach - see img.onload()
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
var img = new Image();
img.onload = function(){
ctx.drawImage(img,0,0);
ctx.beginPath();
ctx.moveTo(30,96);
ctx.lineTo(70,66);
ctx.lineTo(103,76);
ctx.lineTo(170,15);
ctx.stroke();
};
img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png';
}

Related

html5 Canvas drawimage background + 9 images

I have a little problem, sometimes work or not work drawimage, i tried to begin with draw background and if drawed then next draw 9 images(sometimes images is this same or not same).
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
$('button').on('click',function(){
var img = new Image();
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
var img4 = new Image();
var img5 = new Image();
var img6 = new Image();
var img7 = new Image();
var img8 = new Image();
var img9 = new Image();
img.src = $(location).attr('href')+'/img/frames/'+$('#frames option:selected').val();
img1.src = $(location).attr('href')+'/img/mercmain/'+$('#merc1 option:selected').val();
img2.src = $(location).attr('href')+'/img/mercmain/'+$('#merc2 option:selected').val();
img3.src = $(location).attr('href')+'/img/mercmain/'+$('#merc3 option:selected').val();
img4.src = $(location).attr('href')+'/img/mercmain/'+$('#merc4 option:selected').val();
img5.src = $(location).attr('href')+'/img/mercmain/'+$('#merc5 option:selected').val();
img6.src = $(location).attr('href')+'/img/mercmain/'+$('#merc6 option:selected').val();
img7.src = $(location).attr('href')+'/img/mercmain/'+$('#merc7 option:selected').val();
img8.src = $(location).attr('href')+'/img/mercmain/'+$('#merc8 option:selected').val();
img9.src = $(location).attr('href')+'/img/mercmain/'+$('#merc9 option:selected').val();
img.onload = function(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(img, 0, 0,307,382);
img1.onload = function(){
ctx.drawImage(img1,$xyframe[0][0],$xyframe[0][1],$xyframe[0][2],$xyframe[0][3]);
};
img2.onload = function(){
ctx.drawImage(img2,$xyframe[1][0],$xyframe[1][1],$xyframe[1][2],$xyframe[1][3]);
};
img3.onload = function(){
ctx.drawImage(img3,$xyframe[2][0],$xyframe[2][1],$xyframe[2][2],$xyframe[2][3]);
};
img4.onload = function(){
ctx.drawImage(img4,$xyframe[3][0],$xyframe[3][1],$xyframe[3][2],$xyframe[3][3]);
};
img5.onload = function(){
ctx.drawImage(img5,$xyframe[4][0],$xyframe[4][1],$xyframe[4][2],$xyframe[4][3]);
};
img6.onload = function(){
ctx.drawImage(img6,$xyframe[5][0],$xyframe[5][1],$xyframe[5][2],$xyframe[5][3]);
};
img7.onload = function(){
ctx.drawImage(img7,$xyframe[6][0],$xyframe[6][1],$xyframe[6][2],$xyframe[6][3]);
};
img8.onload = function(){
ctx.drawImage(img8,$xyframe[7][0],$xyframe[7][1],$xyframe[7][2],$xyframe[7][3]);
};
img9.onload = function(){
ctx.drawImage(img9,$xyframe[8][0],$xyframe[8][1],$xyframe[8][2],$xyframe[8][3]);
};
};
});
and link to test script https://tajkjs-olszam.c9users.io/genform/
and if i remove from img1-9.onload, leave ctx.drawimage(img1-9) and make settimeout from 3 to 5 sec then it's ok but i want without settimeout.
setTimeout(function(){
//img.onload = function(){
ctx.drawImage(img, 0, 0,307,382);
// };
ctx.drawImage(img1,$xyframe[0][0],$xyframe[0][1],$xyframe[0][2],$xyframe[0][3]);
ctx.drawImage(img2,$xyframe[1][0],$xyframe[1][1],$xyframe[1][2],$xyframe[1][3]);
ctx.drawImage(img3,$xyframe[2][0],$xyframe[2][1],$xyframe[2][2],$xyframe[2][3]);
ctx.drawImage(img4,$xyframe[3][0],$xyframe[3][1],$xyframe[3][2],$xyframe[3][3]);
ctx.drawImage(img5,$xyframe[4][0],$xyframe[4][1],$xyframe[4][2],$xyframe[4][3]);
ctx.drawImage(img6,$xyframe[5][0],$xyframe[5][1],$xyframe[5][2],$xyframe[5][3]);
ctx.drawImage(img7,$xyframe[6][0],$xyframe[6][1],$xyframe[6][2],$xyframe[6][3]);
ctx.drawImage(img8,$xyframe[7][0],$xyframe[7][1],$xyframe[7][2],$xyframe[7][3]);
ctx.drawImage(img9,$xyframe[8][0],$xyframe[8][1],$xyframe[8][2],$xyframe[8][3]);
},100);
this code is work but unfortunately I have use settimeout
Try not to draw on each image load. Use counter for loaded images and run draw function on last load. Also Pablo said right thing - set onload listener before set source. This code should run inside your click listener function
var img;
var counter = 0;
var imagesLength = 9;
var images = [];
var backgroundImage = new Image();
var imgFolder = location.href+'/img/mercmain/';
function drawImages(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(backgroundImage, 0, 0,307,382); //draw background
for ( var i=0; i<imagesLength ; i++ ){ //draw images
ctx.drawImage(images[i],$xyframe[i][0],$xyframe[i][1],$xyframe[i][2],$xyframe[i][3]);
}
}
function onLoad(){
counter++;
if( counter === imagesLength + 1 ){ // +1 - we must count also background image
drawImages(); // draw all the images at once
}
}
for ( var i=0; i<imagesLength ; i++ ){
img = new Image();
images.push( img ); // push in array before src,
// onload should not fire while image is not in array
img.onload = onLoad; // set onload before src,
// image should not load before onload listener is set
img.src = imgFolder + $('#merc'+ (i+1) +' option:selected').val();
}
// do not forget to set the same for background image
backgroundImage.onload = onLoad;
backgroundImage.src = location.href + '/img/frames/' + $('#frames option:selected').val();
You have a race condition: You are loading all the images at the same time, but if the background image is not the first one to be loaded, you are adding the onload listeners AFTER the images have been loaded, so the event has already happened and the drawing logic is never executed.
Solution? the imgN.onload=function() {...} assignments should be outside the img.onload function:
$('button').on('click',function(){
var img = new Image();
var imgArr=[];
for (var i=0;i<9;i++) {
imgArr[i]=new Image();
}
img.src = $(location).attr('href')+'/img/frames/'+$('#frames option:selected').val();
for (var i=0;i<9;i++) {
imgArr[i].src=$(location).attr('href')+'/img/mercmain/'+$('#merc'+i+' option:selected').val();
}
img.onload = function(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(img, 0, 0,307,382);
}
//Here, instead in the previous function
for (var i=0;i<9;i++) {
imgArr[i].onload = function(){
ctx.drawImage(img1,$xyframe[i][0],$xyframe[i][1],$xyframe[i][2],$xyframe[i][3]);
};
}
});

Canvas - drawImage() after clearRect()

I have a problem. I am creating simple game in Canvas using JavaScript. Image doesn't display after call clearRect(), does anyone know, how to solve it?
var left1 = 0;
var context1 = document.getElementById('canvas1').getContext('2d');
render1();
function render1() {
var image = new Image();
image.onload = function () {
context1.drawImage(image, left1, 0, 200, 200);
};
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
left1++;
requestAnimationFrame(render1);
}
var left2 = 0;
var context2 = document.getElementById('canvas2').getContext('2d');
render2();
function render2() {
context2.clearRect(0, 0, 500, 250);
var image = new Image();
image.onload = function () {
context2.drawImage(image, left2, 0, 200, 200);
};
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
left2++;
requestAnimationFrame(render2);
}
canvas {
display: block;
}
It works, but old images are not deleted:
<canvas id="canvas1" height="250" width="500"></canvas>
It doesn't work, because of clearRect():
<canvas id="canvas2" height="250" width="500"></canvas>
if you try to animate your image , its not necessary to make two canvas instead use a timer , i hope this will help
`
var left1 = 0;
var context1 = document.getElementById('canvas1').getContext('2d');
var canvas1 = document.getElementById('canvas1');
window.onload = init;
function init() {
setInterval(drawc, 1000 / 60);
};
function drawc() {
if (left1 > canvas1.width) {
left1 = 0;
}
render1();
}
function render1() {
with(context1) {
clearRect(0, 0, canvas1.width, canvas1.height);
var image = new Image();
image.src = 'http://www.pngall.com/wp-content/uploads/2016/06/Earth-Free-Download-PNG.png';
beginPath();
drawImage(image, left1, 0, 200, 200);
closePath();
fill();
left1++;
// requestAnimationFrame(render1);
}
};

Missing image when saving image from canvas

I use this code to save images in Javascript :
function saveImage() {
var canvas = document.getElementById('myPicture');
var ctx = canvas.getContext('2d');
var img = new Image();
ctx.rect(0, 0, 460, 600);
ctx.fillStyle = 'white';
img = new Image();
img.crossOrigin = 'anonymous';
img.src = "http://localhost/upload/abc.jpg";
ctx.drawImage(img,0,0,_item.width(),_item.height());
return canvas.toDataURL("image/jpeg");
}
When i click button save image:
$("#save").on('click', function () {
var rawImageData = saveImage();
$(this).attr('download', 'your_pic_name.jpeg').attr('href', rawImageData);
});
However the result I get is white image.
And I click on the save button again (ie 2 times) then is now right result. how do I can just click one time only?
Thank you.
It is because the first time you click, anchor doesn't have image data url... You may set the url and forget about the click event.
//$("#save").on('click', function () {
var rawImageData = saveImage();
$(this).attr('download', 'your_pic_name.jpeg')
.attr('href', rawImageData);
//});
OR
$("#save").on('click', function () {
var rawImageData = saveImage();
/*$(this).attr('download', 'your_pic_name.jpeg')
.attr('href', rawImageData);*/
window.location=rawImageData;
});
OR alternatively, you need this file to use following code
var canvas = document.getElementById('myPicture');
function saveImage() {
var ctx = canvas.getContext('2d');
var img = new Image();
ctx.rect(0, 0, 460, 600);
ctx.fillStyle = 'white';
img = new Image();
img.crossOrigin = 'anonymous';
img.src = "http://localhost/upload/abc.jpg";
// ctx.fill...
return canvas.toDataURL("image/jpeg");
}
$("#save").on('click', function () {
var rawImageData = saveImage();
var png= Canvas2Image.saveAsPNG(canvas , true);
});
PS: I don't see where you feel canvas with the image...int the saveImage function

draw array of images to the canvas

I am trying to draw an array of images to the canvas element, my data:image is returning an empty image.
var imgArray = ['images/image1.png','images/image2.png'];
for(i = 0; i < 2; i++){
var canvas = document.getElementById('textCanvas');
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};
}
img = canvas.toDataURL("image/png");
You never set the images' source:
var imageObj = new Image();
imageObj.src = imgArray[i]; // << addeed
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};

fill image with other image javascript/html5

I need help with the following resource http://www.filmfans.cz/test/index2.html
I don't know how to change the colours of the pinquen after the click on the sample.
I would like to do something similar as in the following link http://www.pixelbox.sk/fileadmin/Flash/cosmo_2.swf
Here is my code
$(window).load(function(){
var width = $(window).width();
var height = $(window).height();
var c = document.getElementById("a");
var ctx = c.getContext("2d");
var can2 = document.createElement('canvas');
document.body.appendChild(can2)
can2.width = c.width;
can2.height= c.height;
var ctx2 = can2.getContext("2d");
var test= new Image();
test.src = "tux.png";
test.onload = function() {
ctx2.drawImage(test, 0, 0);
}
var img = new Image();
img.src = "2.png";
img.onload = function(){
ctx2.globalCompositeOperation = "source-in";
var pattern = ctx2.createPattern(img, "repeat");
ctx2.fillStyle=pattern;
ctx2.fillRect(0,0,300,300);
}
});
$(document).ready(function () {
$('.klik').click(function() {
var adresa = $(this).children('img').attr('src');
var canvas = document.getElementById("a");
canvas.width = canvas.width;//blanks the canvas
var c = canvas.getContext("2d");
var img = new Image();
img.src = adresa;
img.onload = function(){
var pattern = c.createPattern(img, "repeat");
//c.globalCompositeOperation = "source-in";
c.fillStyle=pattern;
c.fillRect(0,0,300,300);
}
// c.drawImage(img, 0, 0);
//}
//return false;
});
});
</code>
</pre>
Problem solved !
Using a second, temporary canvas with source-in is the right idea:
ctx2.drawImage(test, 0, 0);
ctx2.globalCompositeOperation = 'source-in';
var ptrn = ctx2.createPattern(pattern,'repeat');
ctx2.fillStyle = ptrn;
ctx2.fillRect(0,0,300,300);
ctx.drawImage(can2,0,0)
live example:
http://jsfiddle.net/UcGrC/

Categories