Blog

Multiple WebGL Canvases On a Single Page

2017-04-06

One time, somebody on the forum asked an interesting question about using several Canvas elements on a single page. Back then, I thought “Why would anybody need this?”. But after seeing many well-crafted applications, including ones from the well-known Animagraffs studio, I’m not so sure anymore. If you have doubts, then look into the demo page, for example, at the ISS 3D information graphics.

This intriguing feature provided to us by the Blend4Web developers deserves a close examination.

What’s the Point

If you try to initialize several Canvas elements in your script, you will naturally get an error, as the engine uses lots of its own variables to store operation conditions. This is understandable. So, in such cases, the developers recommend using the “namespace” concept.

Here is the idea of it: user’s web browser, as usual, loads one and only one engine file. However, you also set specific identifiers (namespaces) in your scripts, and these identifiers allow the engine to process your scripts as if they were separate units that work independently from each other.

A Bit of Practice

First, we will have to prepare a place for several Canvases in the HTML body. I will use a standard template that Project Manager generates when we create a new project.

So, here is the task: we need to place two independent Canvas elements on the page. Accordingly, let’s define DIV containers in the HTML file:

<body>
    <div id="canvas_container1"></div>
    <div id="canvas_container2"></div>
</body>

Let’s say that implemented code for different containers should be stored in different JavaScript files. Add the lines we need to the HTML:

<script type="text/javascript" src="canvas1.js"></script>
<script type="text/javascript" src="canvas2.js"></script>	

We also need to define location, size and other parameters in the CSS file:

#canvas_container1 {
  position: absolute;
  left: 0px;
  top: 0px;
  width: 640px;
  height: 480px;
}

#canvas_container2 {
  position: absolute;
  left: 0px;
  top: 500px;
  width: 640px;
  height: 480px;
}

And now comes the most interesting part. We only have to set the identifier while initializing the module in the b4w.require function so the engine would know to which namespace the script belongs. However, internal require function calls should not use any identifiers.

In the end, standard code generated by the Project Manager should look like this:

// register the application module
b4w.register("canvas1", function(exports, require) {

// import modules used by the app
var m_app       = require("app");
var m_cfg       = require("config");
...
b4w.require("canvas1","canvas1").init();

And the code for the second canvas should look like:

// register the application module
b4w.register("canvas2", function(exports, require) {

// import modules used by the app
var m_app       = require("app");
var m_cfg       = require("config");
...
b4w.require("canvas2","canvas2").init();

Interaction Between Two Canvases

Let’s take a look at a more complex example, where codes for different Canvas elements can interact with each other. Let’s try to start an animation on the first Canvas with a mouse click in the second Canvas window.

Define the external function “ext_method” for starting animation in the first Canvas code:

...
exports.ext_method = function() {
    var o = m_scs.get_object_by_name("cube");
    m_anim.apply_def(o);
    m_anim.play(o);
}
...

In the second Canvas code, define the animation function using require and set the identifier of the Canvas you need as a parameter. Note that in this case the require method is called from the global object b4w:

...
var m_ext_canv  = b4w.require("canvas1", "canvas1");
...
Add the standard code for processing “click” event:
...
function init_cb(canvas_elem, success) {

    if (!success) {
        console.log("b4w init failure");
        return;
    }
...
    canvas_elem.addEventListener("mousedown", main_canvas_click, false);
    canvas_elem.addEventListener("touchstart", main_canvas_click, false);
}

...
function main_canvas_click() {
    m_ext_canv.ext_method();
}

As you can see, there is nothing difficult in working with multiple Canvases, and still it opens the door to amazing opportunities!

Example source files.

Comments
23 apr. 2025 12:02
Developer Anna has hinted at exciting updates, including potential multiplayer functionality, Crazy Cattle 3D though the complex physics system poses challenges.
05 may. 2025 11:19
Interesting discussion about multiple Canvas elements! Reminds me of complex strategy games. Managing multiple elements efficiently is key, just like mastering Pokerogue and understanding the Pokerogue Dex to build the perfect team. Blend4Web's solution using namespaces seems like a clever way to avoid conflicts, allowing for richer and more dynamic web applications. It's like creating multiple powerful combos in your favorite game!
Please register or log in to leave a reply.