Skip to content

Managing Canvas resources

Igor Zinken edited this page Dec 29, 2023 · 2 revisions

Resource management

Each Canvas instance will manage its own resources, which is another word for image assets. E.g. the image content that each Sprite will render. Each image asset will be registered under its own unique identifier known as a resourceId (string). You can reuse the same resourceId across several Sprites. The rule is basically : each unique image should have a unique id, regardless of how many consumers it has.

Within zCanvas all image assets are cached as ImageBitmap instances for performance optimization. Luckily, you don't need to specify your images as ImageBitmaps, but can instead provide any of the following formats:

Supported image formats

Images can be provided through JavaScript as one of the following (defined in the ImageSource type) :

  • File reference
  • Blob (binary data)
  • HTMLImageElement
  • HTMLCanvasElement
  • ImageBitmap
  • ImageData
  • String URL (to remote file* or Blob URL)
  • String base64 encoded image data

...where each of these represents a format supported by modern browsers (JPG, GIF, PNG, WebP should be just fine).

*files served on a different domain need appropriate CORS cross origin headers.

Resource management flow

Ideally you start registering your resources after constructing your Canvas. Though referencing not-yet-registered resources in your Sprites will not throw Errors (as the Sprites will render nothing until the resource is available), it is recommended to make this part of the start up phase of your application, as the process is async and you want to handle load failures.

Let's say that your application renders a logo and a sprite sheet, you would start out like so :

const canvas = new Canvas();

try {
    const [ logo, spritesheet ] = await Promise.all([
        canvas.loadResource( "logoId", document.getElementById( "logo" ), // loading from HTMLImageElement in document
        canvas.loadResource( "spritesheetId", "./path/to/spritesheet.png" ) // loading from path
    ]);
} catch ( e: Error ) {
    // handle error like a responsible person (maybe connection loss?)
}

After which logo and spritesheet represent Size objects specifying the dimensions of the loaded assets. You can now create Sprites referencing these resources like so:

const logoSprite = new Sprite({ resourceId: "logoId", width: logo.width, height: logo.height }); // renders logo

// note that for a sprite sheet we use a smaller size, namely the size of each frame within the image

const character1 = new Sprite({ resourceId: "spritesheetId", width: TILE_WIDTH, height: TILE_HEIGHT });
const character2 = new Sprite({ resourceId: "spritesheetId", width: TILE_WIDTH, height: TILE_HEIGHT });

// add Sprites to Canvas so we can start rendering
canvas.addChild( logoSprite );
canvas.addChild( character1 );
canvas.addChild( character2 );

after which you should see the Sprites being rendered on screen.

Disposal of resources

When you're ready with your zCanvas shenanigans, calling Canvas.dispose() will automatically free up memory allocated to the image assets. If however you want to do this at runtime (maybe you are making a big game where between levels you use different assets), you can do :

canvas.disposeResource( "spritesheetId" );

...if you want to keep the logo asset registered, but remove the spritesheet. Note that all still existing Sprites that reference the disposed asset (by its resourceId) will now no longer render visual content. So be sure that your asset is no longer in use.

Note you can change resources for existing Sprites using the setResource() method.