События

Несколько Canvas на одной странице? Легко!

2017-04-06

Как-то раз на форуме задавался любопытный вопрос об использовании нескольких Canvas на одной странице. Мне еще подумалось, а зачем вcе это нужно? Но множество прекрасно выполненных приложений, в том числе и от небезызвестной студии Animagraffs, поколебали мою уверенность. Кто не верит, приглашаю заглянуть на страницу с демонстрациями. Например, можно посмотреть 3D-инфографику МКС .

Эта интересная возможность, предлагаемая разработчиками Blend4Web, определенно заслуживает пристального изучения.

В чем соль

Если в своем скрипте вы попытаетесь выполнить инициализацию нескольких Canvas, то закономерно получите ошибку, ведь движок использует массу собственных переменных для хранения рабочего состояния. Это выглядит логично. Поэтому для таких ситуаций разработчики предлагают использовать концепцию «пространства имен».

Идея заключается в следующем... Браузер пользователя загружает, как обычно, один единственный файл движка. Однако в своих скриптах вы указываете специальные идентификаторы (имя пространства). Они позволяют движку «рассматривать» такие скрипты, как уникальные единицы, в которых результаты работы независимы друг от друга.

Немного практики

Сначала нужно подготовить место для расположения нескольких Canvas в теле HTML. Я буду исходить из стандартной заготовки, что предлагает менеджер проектов при создании нового проекта.

Задача. Нужно на странице разместить два независимых Canvas. Соответственно, в файле HTML определяем контейнеры DIV:

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

Допустим, реализация кода различных контейнеров должна храниться в отдельных файлах JavaScript. Добавляем нужные строки в HTML:

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

Также требуется определить местоположение, размеры и иные параметры в файле CSS:

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

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

А теперь самое интересное. Чтобы движок мог определить, к какому пространству имен относится код скрипта, достаточно указать идентификатор при инициализации модуля в функции b4w.require. Причем, внутренние вызовы функции require должны оставаться без указания идентификатора.

В итоге, стандартный код, сгенерированный менеджером проектов, в новых условиях будет выглядеть так:

// 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();

...и код для канвы №2:

// 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();

Взаимодействие между двумя Canvas

Рассмотрим более сложный пример, где разные Canvas могут взаимодействовать друг с другом. Попробуем запустить анимацию в Canvas №1 щелчком мыши в окне Canvas №2.

В коде Canvas №1 определяем внешнюю функцию "ext_method" для запуска анимации:

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

В коде Canvas №2 объявляем функцию анимации через require и указываем в виде параметра - идентификатор нужной канвы. Обратите внимание, что метод require в данном случае вызывается у глобального объекта b4w:

...
var m_ext_canv  = b4w.require("canvas1", "canvas1");
...
Добавляем стандартный код, обслуживающий событие "клик":
...
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();
}

Как видите, ничего сложного в работе с несколькими Canvas нет. Зато какие возможности открываются!

Исходники примера.

Комментарии
08 май. 2017 12:02
А как отключить ненужный канвас ?
b4w.require("canvas2","canvas2").init();

вот его например ? как выключить чтобы не работал ?
14 июн. 2017 11:01
Думаю, что надо написать метод, который будет останавливать рендеринг

exports.stop = function() {
    m_main.stop();
}
04 сен. 2019 15:45
Он будет останавливаться при каком условии? Если курсор уходит с канваса?
Пожалуйста, зарегистрируйтесь или войдите под своей учетной записью , чтобы оставлять сообщения.