I started a simple project in javascript a few days ago and found this issue. Every time I reload my google-page i get an empty canvas. I have already tried to take out the drawImage() function out of class and it worked. But what if I need to use that function as a class method? (Also I've already tried passing the canvas as an argument of the draw method but it doesn't work)
So this is working but I don't need it
const canvas = document.getElementById('main_canvas')
const ctx = canvas.getContext('2d')
var img = new Image()
img.src = 'some source'
ctx.drawImage(img,10,10)
And this isn't working but supposed to
const canvas = document.getElementById('main_canvas')
const ctx = canvas.getContext('2d')
class Person
{
constructor(name){
this.name = name
this.img = new Image()
this.img.src = 'some source'
}
draw(){
ctx.drawImage(this.img,10,10)
}
}
var peter = new Person('Peter Griffin')
peter.draw()
The reason is simple. Your image is not loaded when you want to draw it.
You have to wait until the image is loaded before drawing it in the canvas.
const canvas = document.getElementById('main_canvas')
const ctx = canvas.getContext('2d')
class Person
{
constructor(name){
this.name = name;
this.img = new Image()
this.img.src = 'monimage.jpg'
}
on_image_loaded(f) {
this.img.onload = f;
}
draw(){
ctx.drawImage(this.img,10,10)
}
}
var peter = new Person('Peter Griffin')
peter.on_image_loaded(function() {
peter.draw();
});
Related
Earlier I used something like this (html5+javascript):
var img;
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
img = new Image();
img.onload = function() {
context.drawImage(img,0,0);
};
img.src = "maze.png";
Now I learn Haxe (platform-javascript) and can't write this code in accordance with js-libraries. I've found examples only for vector drawing.
Thanks!
It's quite possible to port that code to javascript; to find javascript classes in the Haxe API, just search them on api.haxe.org. In this case, the Image class is js.html.Image. Here is a basic example of image drawing: view example on try.haxe
var canvas = js.Browser.document.createCanvasElement();
canvas.width = 400;
canvas.height = 400;
js.Browser.document.body.appendChild(canvas);
var ctx = canvas.getContext2d();
var img = new js.html.Image();
img.onload = function() {
ctx.drawImage(img,0,0);
};
img.src = "http://dreamicus.com/data/maze/maze-02.jpg";
Alternative libraries exist that make this easier and more cross platform. You are not using the full haxe ecosystem to it's full if you are just writing code to get compiled to javascript - libraries such as kha and phaser will let you draw an image using a standard API that will let you target any platform.
You can port the exact code to Haxe:
https://try.haxe.org/#a7287
import js.Browser.*;
import js.html.*;
class Test {
static function main() {
var img;
window.onload = function() {
var canvas:CanvasElement = cast document.getElementById("myCanvas");
var context = canvas.getContext2d();
img = document.createImageElement();
img.onload = function() {
context.drawImage(img,0,0);
};
img.src = "maze.png";
}
}
}
I'm trying to add images to canvas strictly, but images are added randomly.
What's the problem?
Here is my simple code.
var canvas = new fabric.Canvas("preview");
var imgs = ['bgBottom','bgTop', 'bgLevel', 'bgCircle'];
for (var i=0; i<imgs.length;i++){
var url = imgs[i]+'.png';
fabric.Image.fromURL(url, function (oImg) {
canvas.add(oImg)
})
}
fabric.Image.fromURL loads the image in the background and runs the anonymous function you pass to it once image load is complete which adds it to the canvas. The order that the browser loads the images will vary and you can't rely on it being in a specific order.
Check out this jsfiddle that shows loading an array of images and making sure they're displayed in a set order. This works by adding the image to the canvas before it's loaded; it just doesn't render until the image is available to be displayed.
The code from the jsfiddle:
var SelfLoadingImage = fabric.util.createClass(fabric.Object, {
initialize: function(src) {
this.image = new Image();
this.image.src = src;
this.image.onload = (function() {
this.width = this.image.width;
this.height = this.image.height;
this.loaded = true;
this.setCoords();
this.fire('image:loaded');
canvas.renderAll();
}).bind(this);
},
_render: function(ctx)
{
if (this.loaded) {
ctx.drawImage(this.image, -this.width / 2, -this.height / 2);
}
}
});
var canvas = new fabric.Canvas("preview");
var imgs = [
'http://icons.iconarchive.com/icons/fasticon/ifunny/128/dog-icon.png', // dog
'http://33.media.tumblr.com/avatar_14ee6ada72a4_128.png', // cat
'http://upload.wikimedia.org/wikipedia/commons/b/bc/Nuvola_devices_mouse.png' // mouse
];
for (var i=0; i<imgs.length;i++){
var url = imgs[i];
var img = new SelfLoadingImage(url);
canvas.add(img);
}
why this doesn't work? i need a solution without appending canvas within 'Can' function.
function Can(canvasId) {
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
this.canvas.width = 200;
this.canvas.height = 200;
this.canvas.id = canvasId;
}
var canvas1 = new Can(document.getElementById('can1');
var canvas2 = new Can(document.getElementById('can2');
FIDDLE
EDIT
i need to wrap both canvases into container and apply constructor function. hope it's more clear now. thanks. FIDDLE
If I understand your question correctly, it looks like you don't even need to use createElement(), because you already have the canvas elements in your html. See if this works for you:
JSFiddle Demo
function Can(canvasId) {
this.canvas = document.getElementById(canvasId);
this.context = this.canvas.getContext('2d');
this.canvas.width = 200;
this.canvas.height = 200;
this.canvas.id = canvasId;
}
var canvas1 = new Can('can1');
var canvas2 = new Can('can2');
This just grabs the reference to the canvas element in the constructor with getElementById().
forgive me if this is ignorant, but at a glance, should 'Can' not be defined as a class?
I wrote a simple libraryless rotozoomer for html5-canvas, and I'm wondering what is the correct way to let image load to canvas before using getImageData?
var hc = document.getElementById("hiddenCanvas"); var hctx = hc.getContext("2d"); // Hidden canvas for imageload (hctx)
var imageObj = new Image(); imageObj.onload = function() { hctx.drawImage(this, 0, 0); }; imageObj.src = 'img/8.jpg';
alert("Click to start");
// This alert needs to be replaced with "hold-the-script-until-image-is-fully-loaded" or the image_data will be nothing but black.
var image_data = hctx.getImageData(0,0,1000,1000);
var rgba_byte_array = image_data.data; // image_data.data.length = 4000000
var loop = setInterval(loop,1000/30);
function loop()
{ ...
The code works with the alert, because it causes the required "break" for loading the image. I wish not to use JQuery nor Ajax.
Here I use imageObj.onload directly at drawing on canvas. Probably not the right way?
Thanks in advance for the feedback and the solution.
You should put
var image_data = hctx.getImageData(0,0,1000,1000);
var rgba_byte_array = image_data.data; // image_data.data.length = 4000000
var loop = setInterval(loop,1000/30);
inside imageObj.onload function
Hi I'm trying to learn how to use the EaselJS libraries, eventually combining with some of the EXTJS libs butt I'm having trouble putting all my code in the .Js files. My js file looks like this
var democanvas = document.createElement('canvas');
document.body.appendChild(democanvas);
democanvas.height = "400";
democanvas.width = "600";
function init() {
var canvas = document.getElementById("democanvas");
var stage = new createjs.Stage('canvas');
var im = new createjs.Bitmap("dbz.jpg");
// im.regX - im.image.width *.2;
// im.regY - im.image.height *.2;
stage.addChild(im);
stage.update();
im.addEventListener("click", function(){
var seed = new createjs.Bitmap("seed.jpg");
seed.alpha = 0.5;
seed.x = window.event.clientX;
seed.y = window.event.clientY;
stage.addChild(seed);
stage.update();
}); //end seed evenlistener */
} //end functin init()
this doesn't work, but if I comment out the whole document.createElement('canvas') section and I apply
<body onLoad="init();">
<canvas id="demoCanvas" width="1000" height="1000">
alternate content
</canvas>
to my index.html file It will start working :( I included the .js within the body tag of te index html
Edit:::::::::::::::::::::: this is my current code, still not showing anything unless I add the canvas to the html page :(
window.onload = function (){
var demoCanvas = document.createElement('canvas');
//document.body.appendChild(democanvas);
demoCanvas.height = "400";
demoCanvas.width = "600";
}
var stage;
function init() {
stage = new createjs.Stage("demoCanvas");
var text = new createjs.Text("Hello World", "bold 86px Arial", "#ff7700");
stage.addChild(text);
stage.update();
}
init();
Another thing - since you are using image paths, and not fully loaded images as Bitmaps sources, its possible the images are not ready when you update the stage. You can either put onload handlers on your image(s) to update the stage, or preload them first.
var image = new Image();
image.onload = handleLoad;
image.src = "src.jpg";
function handleLoad(event) { stage.update(); }
// You can also use the Bitmap
var bitmap = new createjs.Bitmap("src.jpg");
bitmap.image.onload = handleLoad;
You can also tick the stage to update it constantly. This is a quick way to see if thats the problem.
createjs.Ticker.addEventListener("tick", stage);
// OR
createjs.Ticker.on("tick", stage);
try the below :
document.body.onload = function(){
var democanvas = document.createElement('canvas');
document.body.appendChild(democanvas);
democanvas.height = "400";
democanvas.width = "600";
function init() {
var canvas = document.getElementById("democanvas");
var stage = new createjs.Stage('canvas');
var im = new createjs.Bitmap("dbz.jpg");
// im.regX - im.image.width *.2;
// im.regY - im.image.height *.2;
stage.addChild(im);
stage.update();
im.addEventListener("click", function(){
var seed = new createjs.Bitmap("seed.jpg");
seed.alpha = 0.5;
seed.x = window.event.clientX;
seed.y = window.event.clientY;
stage.addChild(seed);
stage.update();
}); //end seed evenlistener */
} //end functin init()
init();
}
Firstly you need to use the console of your navigator to see javascript's errors before any question.
You will see this error : Uncaught TypeError: Cannot call method 'appendChild' of null
That because you load document.body.appendChild(democanvas); before the html is load so your document.body is null.
This is the way:
function init() {
var democanvas = document.createElement('canvas');
document.body.appendChild(democanvas);
democanvas.height = "400";
democanvas.width = "600";
var canvas = document.getElementById("democanvas");
var stage = new createjs.Stage('canvas');
var im = new createjs.Bitmap("dbz.jpg");
// im.regX - im.image.width *.2;
// im.regY - im.image.height *.2;
stage.addChild(im);
stage.update();
im.addEventListener("click", function(){
var seed = new createjs.Bitmap("seed.jpg");
seed.alpha = 0.5;
seed.x = window.event.clientX;
seed.y = window.event.clientY;
stage.addChild(seed);
stage.update();
}); //end seed evenlistener */
} //end functin init()
I had the same problem and I solved it by using a preloader.
You can use the PreloadJS preloader like this:
var preloader = new createjs.LoadQueue(true);
preloader.addEventListener("complete",this.handleComplete.bind(this));
var manifest = [
{src:"./images/yourIMAGE.PNG"},
//another image
];