This question already has an answer here:
CanvasContext2D drawImage() issue [onload and CORS]
(1 answer)
Closed 3 years ago.
I want just to draw an image on canva using drawImage() method .But it happen sometime that the image is not drawn . even when I use the onload event it still fail to display the image.
Before I ask my question I want just to precise that the image is drawn somtimes and not drawn sometime .So what is the reason of the this problem and how can I tackle or fix it .
let imagez = new Image();
imagez.src="photo/run.png";
context.drawImage(imagez,10,10,50,60); // it does not draw the image always. why?
I expect the image to be drawn whenever I refresh the page
That most likely happens because the drawImage() method is called before the actual image is completely loaded.
Wait for it to finish loading before you call drawImage().
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = 400;
canvas.height = 300;
var context = canvas.getContext("2d");
let imagez = new Image();
imagez.onload = function() {
context.drawImage(imagez, 10, 10, 50, 60);
}
imagez.src = "https://picsum.photos/400/300";
For this you have to wait for the image(s) to load into memory before they are available to draw to the canvas.
A simple loadIMAGE() function to achieve this might look something like this...
function loadIMAGE(path, x, y, w, h) {
var img = new Image();
img.addEventListener("load", function(e) {
// 'this' === the image Object
context.drawImage(this, x, y, w, h);
}, !1);
img.src = path;
}
// USAGE
loadIMAGE("photo/run.png", 10, 10, 50, 60);
It is important that the event-Handling function is defined before the src value is assigned.
Hope that helped :)
You are attempting to draw the image without knowing if it was successfully loaded...
Here is a working sample, using the onload event
const canvas = document.getElementById("gameArea");
context = canvas.getContext("2d");
let imagez = new Image();
imagez.onload = function () {
context.drawImage(imagez, 10, 10, 50, 60);
}
imagez.src = "https://upload.wikimedia.org/wikipedia/commons/e/e2/3D_Gyroscope.png";
<canvas id=gameArea></canvas>
Related
I'm using OpenLayers to draw a map, and I'd like to fill the polygon that describes a country with a photo from that country. I know I can pass a CanvasPattern to ol.style.Fill's color, but I don't know to generate an image.
Here's my code, and a JSfiddle with a full example: http://jsfiddle.net/07366L44/5/
function getPhoto() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
return context.createPattern(photo, 'repeat');
}
I think it's because the photo is loaded async. Other examples create the pattern in the photo.onload method but I don't know how to return that.
Optimally I'd like to return a canvas which I can animate or update later with other photos, but I'll settle for just a single static image per country!
You'll have to set your style's fill color in the image's onload handler.
/**
* #param {ol.style.Style} style Style to set the pattern on.
*/
function setPattern(style) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.onload = function() {
canvas.width = photo.width;
canvas.height = photo.height;
var pattern = context.createPattern(photo, 'repeat');
style.getFill().setColor(pattern);
}
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
}
Note that the fill's color needs to be set before the style function is called, so you cannot call the setPattern function in the style function. It's better to create the style before loading the layer.
Is there any point in pre-rendering images on canvas?
An example,
var img; // Img object
var pre = document.createElement("canvas");
pre.width = img.width;
pre.height = img.height;
var precon = pre.getContext("2d");
precon.drawImage(img, 0, 0);
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
for(var i =0; i < 10000; ++i) {
ctx.drawImage(pre, Math.random() * canvas.width, Math.random() * canvas.height);
}
I don't see the point as you are still calling context.drawImage no matter what you do, unless the canvas api is faster drawing an image from a canvas object rather than image object?
Firstly, I must say that your example is not suitable to highlight the need and benefits of canvas pre-rendering.
I'll give you a better example were you need to draw multiple times something that requires heavy computation on a canvas.
Let's say you have this draw function :
function complexDraw(ctx){
ctx.drawImage(img, width, height);
// heavy computation goes here
// some transforms maybe
ctx.ctx.setTransform(-1, 0, 0, 1, 200, 200);
ctx.fillStyle = "rgba(100, 100, 255, 0.5)";
ctx.fillRect(50, 50, 100, 100);
//maybe draw another img/video/canvas
ctx.drawImage(anotherImg, width, height);
// ...
}
function draw(){
complexDraw(ctx);
}
Now let's say you want to show the current time on the canvas too. That means that we're going to add this at the bottom of our draw function :
function drawTime(ctx){
ctx.fillText(new Date().getTime(), 10, 50);
}
And now our draw function looks like this :
function draw(){
complexDraw(ctx);
drawTime(ctx);
}
Since you want to always show the current time, you need to call the draw function every second :
setInterval(draw, 1000);
This actually means that every second you are doing some heavy computation just to update a silly little text.
If only there could be a way to split the draw function and compute only the things that need computing (the ones that change)... but there is: say hello to canvas pre-rendering!
The key idea is to draw the part that doesn't change (and doesn't need to be re-computed) on a separate canvas - let's call it cacheCanvas - and just copy it's content on our app's canvas whenever we want to redraw stuff :
// suppose we have a `clone` function
var cacheCanvas = clone(canvas),
cacheCtx = cacheCanvas.getContext('2d');
// let's draw our complex stuff on the cacheCanvas
complexDraw(cacheCtx);
// modify our main `draw` function to copy the result of the `complexDraw`
// function, not to call it
function draw(){
ctx.drawImage(cacheCanvas, width, height);
drawTime();
}
And now we're basically redrawing the whole canvas each second, but we're not re-computing all the heavy work in complexDraw.
I just want to note that most of the canvas based games can't run at 60fps (redraw 60 times per second) without doing some performance boost with pre rendering or another technique called canvas layering (which is also worth looking into).
I would like to use the drawImage() function to load an image in a Javascript animation, but the image does not load with my current code. I think I need to specifically ask for the image to be loaded at some point, but I'm not sure when or how. The idea is to make a cloud that goes across the canvas. Thank you for your help.
function draw(x,y){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
x += 2;
if(x>1000){
x=0;
}
var cloud = new image();
cloud.src='small_cloud.png';
ctx.drawImage(cloud,x,0);
var loopTimer = setTimeout('draw('+x+','+y+')',20);
}
Try new Image()rather than new image()
Also move
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
to outside the draw()function, as you only want to set these things up once. Delay this setting up until the browser has had time to parse the document, for example using
window.onload = function(){ ... };
(Though in reality you'd have to make sure not to overwrite any existing window.onload listeners by using proper even handler registration.) Also delay the first invocation to draw()until the image has loaded, for example like so:
cloud.onload = function(){
draw(cloud, 0, 0);
}
I'd also change
var loopTimer = setTimeout('draw('+x+','+y+')',20);
to
setTimeout(function(){ draw(x, y); }, 20);
since you seem not to be using the loopTimer variable, and since passing setTimeout an anonymous function rather than a string is considered better practice.
Finally, it would look like this:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
cloud.onload = function(){
draw(ctx, cloud, 0, 0);
};
};
function draw(ctx, cloud, x,y){
x += 2;
if(x>1000){
x=0;
}
ctx.drawImage(cloud,x,0);
setTimeout(function(){ draw(ctx, cloud, x, y); }, 20);
}
Note that, since ctx is no longer defined inside the draw() function, as it is local to the anonymous window.onload function, you also has to pass ctx to the draw() function.
I'm writing a simple 2D side scroller game using JavaScript + Canvas. I am trying to do this while learning OO JavaScript. I'm encountering an issue where my image will not draw to the canvas, despite being loaded correctly. Here's the code:
//===================================
// class - Canvas
//===================================
var classCanvas = function(id){
canvas = document.getElementById(id);
context = canvas.getContext("2d");
}
//===================================
// abstract class - Image Drawer
//===================================
var classImageDrawer = function(that){
this.draw = function(){
context.drawImage(that.img,
that.spriteCoordsX,
that.spriteCoordsY,
that.width,
that.height,
that.posX,
that.posY,
that.width,
that.height);
}
}
//===================================
// class - Level
//===================================
var classLevel = function(name, src){
this.name = name;
this.img = new Image();
this.img.src = src;
this.img.onload = function(){ };
this.spriteCoordsX = 0;
this.spriteCoordsY = 0;
this.posY = 0;
this.posX = 0;
this.height = 400;
this.width = 600;
this.drawer = new classImageDrawer(this);
}
//==================================
// Begin
//==================================
var game = new classCanvas("playground");
game.LevelOne = new classLevel("LevelOne", "images/foreground-land.png");
game.LevelOne.drawer.draw();
I have checked the code, and I know the image is getting loaded correctly. No errors occur during runtime, the image "foreground-land.png" simply DOESN'T show up on the canvas!
Your image may be loading fine, but as far as I can tell your call to game.LevelOne.drawer.draw() has no guarantee that foreground-land.png has loaded at that point (remember, images are loaded asynchronously without blocking the execution of other code).
Your onload function for the image object in your classLevel class is empty and anonymous. Nothing happens when the image is finished loading. I'm not sure how you want to structure your code given everything else you have going on, but you should only allow the call to game.LevelOne.drawer.draw() to succeed if the resources it depends upon have been fully loaded. The best way to do this would be to hook into the onload callback for all resources you require for that object (in this case, it's just the one image).
Loading images is an async operation, you are (basically) ignoring the loading process, and acting as though it is sync operations.
One thing you could look at is using a 3rd parameter as a callback ("LevelOne", "images/foreground-land.png", function() { this.drawer.draw() }) and doing that as the onload
I have a javascript function like this:
function drawImage(canvas, image_source, dx, dy) {
image = new Image();
image.src = image_source;
image.onload = function() {
c=canvas.getContext("2d");
c.drawImage(image,dx,dy,100,100);
}
}
When I call this function twice in a row, eg:
drawImage(canvas, "foo.jpg", 0, 0);
drawImage(canvas, "bar.jpg", 0 ,100);
bar gets painted twice, once at 0, and once at 100
If I switch the order so that foo is called last, foo gets painted twice.
I've tried to use an array for the images as in "c.drawImage(images[loaded++], dx, dy, 100, 100" and the two images paint separately, but their orders are random.
Is there any way to use a function like this to paint images on a canvas?
Try changing:
image = new Image();
to:
var image = new Image();
Currently you're setting "image" in the global scope, then potentially rewriting its onload handler before the load (which doesn't happen synchronously) has happened.