0

I am trying to draw a kitten in an HTML5 canvas through a class constructor using TypeScript but I am confused on how to achieve the task. I have commented the code to show what I have attempted to do based on the behavior that I expected vs what actually works. Thank you very much for your timer and advice.

module Game {

    export class Test {

        width: number;
        height: number;

        cellWidth: number;
        cellHeight: number;

        canvas: HTMLCanvasElement;
        context: CanvasRenderingContext2D;

        constructor() {

            this.width = 28;
            this.height = 31;

            this.cellWidth = 20;
            this.cellHeight = 20;

            this.canvas = <HTMLCanvasElement> document.getElementById("game_canvas");
            this.context = this.canvas.getContext("2d");
            this.canvas.width = this.width * this.cellWidth;
            this.canvas.height = this.height * this.cellHeight;

            this.context.fillStyle = "blue";
            this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);

            let kitten = new Image();
            kitten.src = 'img/kitten.png';

            // When trying to draw a kitten in the canvas,
            // this will work:

            kitten.onload = () => {
                this.context.drawImage(kitten, 0, 0);
            };

            // but this work won't:
            //this.context.drawImage(kitten, 0, 0);

            /*
            I was assuming that by accessing the this.context property
            I would have direct access to the canvas and I will be able to use
            drawImage to draw the kitten on it; however, that approach
            produces no kitten in the canvas.
            Only by using the .onload method it works.
            I am using the () => notation so that the this inside the block
            is referring to the class.
            I have seen many JavasScript files in which images are simple drawn
            through:
            context.drawImage(image, 0, 0);
            They are not embedded in .onload
            I have tried to Google information but I cannot pinpoint what is
            happening.
             */
        }
    }
}
5
  • 1
    quite simply because you are declaring a new Image() and setting the src, your drawImage call will no doubt be in advance of the src being loaded... if you were to use a previously loaded image (e.g. from the DOM) then the creation of a new image and load would not be required Commented May 30, 2016 at 19:59
  • @AMacdonald Thank you a lot for your explanation! I understand better now. Should I then load the images outside of this class - for example in another class? When I tried using a method for the class to load the image prior to using this.context.drawImage(), it did not work. I am trying to adhere to an OOP design :) I have to draw four kittens in the canvas. I am thinking it is better to load and store them in an array, but not sure where to create that array. Thank you for any further insight :) Commented May 30, 2016 at 20:32
  • setting the src triggers the load - doing it in another class still subjects you to the wait time for load and you cannot be sure - I would say using onload is bulletproof and essential if you are the loader of the images you are using - the only alternative methods are when the images are already loaded into the DOM, you may find the canvas examples you have seen are designed to be initiated onload of the images concerned Commented May 30, 2016 at 20:53
  • @AMacdonald Thanks. I would like to mark your response as the answer but I cannot do it through the comments Commented May 31, 2016 at 17:01
  • Thanks I'll create an answer you can accept. Commented May 31, 2016 at 17:09

2 Answers 2

1

As per my comments here is my answer: quite simply because you are declaring a new Image() and setting the src, your drawImage call will no doubt be in advance of the src being loaded... if you were to use a previously loaded image (e.g. from the DOM) then the creation of a new image and load would not be required

setting the src triggers the load - doing it in another class still subjects you to the wait time for load and you cannot be sure - I would say using onload is bulletproof and essential if you are the loader of the images you are using - the only alternative methods are when the images are already loaded into the DOM (or preloaded elsewhere), you may find the canvas examples you have seen are designed to be initiated onload of the images concerned

Sign up to request clarification or add additional context in comments.

Comments

1

From your code:

        let kitten = new Image();
        kitten.src = 'img/kitten.png';

        // When trying to draw a kitten in the canvas,
        // this will work:

        kitten.onload = () => {
            this.context.drawImage(kitten, 0, 0);
        };

        // but this work won't:
        //this.context.drawImage(kitten, 0, 0);

Using onload is the defacto way you get an image that you can draw on a canvas. A microoptimization would be to keep a dictionary of loaded images so you get to reuse them if drawing multiple kittens.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.