Комбинирование с нативным Canvas API

Two.js поддерживает несколько рендереров, включая WebGL, SVG и Canvas. Для работы с нативным Canvas API необходимо указать Canvas Renderer при создании экземпляра Two.

const elem = document.getElementById('draw-area');
const params = {
  type: Two.Types.canvas,
  width: 800,
  height: 600
};
const two = new Two(params).appendTo(elem);

После этого two.renderer.ctx предоставляет доступ к контексту Canvas, через который можно напрямую использовать все стандартные методы рисования, такие как fillRect, arc, stroke, lineTo и др.

Смешивание объектов Two.js и Canvas

Two.js управляет своими объектами в отдельном слое, но при использовании Canvas Renderer можно добавлять собственные элементы, вызывая методы контекста перед или после two.update().

// Рисуем фигуру Two.js
const circle = two.makeCircle(200, 200, 50);
circle.fill = '#3498db';
circle.stroke = '#2980b9';
circle.linewidth = 5;

// Рисуем нативный Canvas элемент
two.bind('upd ate', function() {
  const ctx = two.renderer.ctx;
  ctx.save();
  ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
  ctx.fillRect(150, 150, 100, 100);
  ctx.restore();
});

two.play();

Принципиальные моменты:

  • ctx.save() и ctx.restore() обязательны для сохранения состояния Canvas после изменений, сделанных вручную.
  • Все нативные вызовы Canvas следует размещать внутри события update, чтобы изменения отображались каждый кадр.

Управление слоями и порядок отрисовки

Two.js отрисовывает свои объекты последовательно в том порядке, в котором они добавлены в сцену. Для правильного сочетания с Canvas API важно учитывать, когда вызывается нативное рисование.

  • До two.update() – нативные элементы окажутся позади объектов Two.js.
  • После two.update() – нативные элементы будут поверх объектов Two.js.
two.bind('update', function() {
  // элементы поверх Two.js объектов
  const ctx = two.renderer.ctx;
  ctx.beginPath();
  ctx.arc(400, 300, 40, 0, Math.PI * 2);
  ctx.fillStyle = 'green';
  ctx.fill();
});

Использование трансформаций Canvas с объектами Two.js

Можно комбинировать трансформации контекста Canvas с объектами Two.js, но нужно помнить о локальном состоянии контекста:

two.bind('update', function() {
  const ctx = two.renderer.ctx;
  ctx.save();
  ctx.translate(300, 300);
  ctx.rotate(Math.PI / 4);
  ctx.fillStyle = 'orange';
  ctx.fillRect(-50, -50, 100, 100);
  ctx.restore();
});

Трансформации, примененные через Canvas, не изменяют объекты Two.js. Для синхронизации позиций или вращений можно использовать свойства объектов Two.js, например translation, rotation или scale.

Анимация и синхронизация с Two.js

Two.js позволяет привязывать анимации через метод bind('update', callback). При комбинировании с Canvas API можно анимировать нативные элементы параллельно:

let angle = 0;

two.bind('update', function(frameCount) {
  const ctx = two.renderer.ctx;
  ctx.save();
  ctx.clearRect(0, 0, two.width, two.height);

  ctx.translate(400, 300);
  ctx.rotate(angle);
  ctx.fillStyle = 'purple';
  ctx.fillRect(-50, -50, 100, 100);
  ctx.restore();

  angle += 0.01; // обновление угла каждый кадр
});

Важно: при использовании clearRect необходимо учитывать, что Two.js также рисует свои объекты. В большинстве случаев достаточно не очищать Canvas вручную, если нативные элементы рисуются поверх, либо управлять их отдельным offscreen-слоем.

Интеграция событий Canvas с Two.js

Контекст Canvas поддерживает стандартные события мыши и сенсора, однако объекты Two.js не используют их напрямую. Для интеграции:

  1. Отслеживать координаты мыши на элементе <canvas>.
  2. Преобразовывать координаты в систему Two.js.
  3. Манипулировать объектами Two.js через их свойства.
elem.addEventListener('mousemove', (e) => {
  const rect = elem.getBoundingClientRect();
  const x = e.clientX - rect.left;
  const y = e.clientY - rect.top;

  circle.translation.se t(x, y); // перемещаем Two.js объект по мыши
});

Использование Text и Path с Canvas API

Two.js поддерживает объекты Two.Text и Two.Path, но иногда удобнее рендерить сложный текст или кривые напрямую через Canvas:

two.bind('update', function() {
  const ctx = two.renderer.ctx;
  ctx.save();
  ctx.font = '48px sans-serif';
  ctx.fillStyle = 'darkred';
  ctx.fillText('Canvas + Two.js', 250, 100);
  ctx.restore();
});

Этот подход позволяет комбинировать гибкость нативного Canvas с объектной моделью Two.js, создавая интерактивные сцены с высокой производительностью.

Практические рекомендации

  • Использовать ctx.save()/ctx.restore() при каждой операции, чтобы избежать глобального изменения состояния Canvas.
  • Помещать нативное рисование внутрь update, чтобы оно синхронизировалось с анимацией Two.js.
  • Контролировать порядок отрисовки через позицию вызова нативного кода относительно two.update().
  • Для сложных сцен, где смешиваются тысячи объектов Two.js и Canvas API, рассмотреть использование offscreen canvas для нативных элементов.

Комбинирование Two.js и нативного Canvas позволяет сохранять объектную структуру сцены, используя мощные возможности низкоуровневого Canvas API для кастомного рендеринга, трансформаций, анимаций и сложных графических эффектов.