Организация кода проектов

Two.js — это мощная библиотека для создания 2D-графики в браузере на JavaScript. При работе с ней структурирование проекта и грамотная организация кода имеют критическое значение, особенно для крупных анимационных или интерактивных приложений.


Структура проекта

Правильная структура помогает отделять логику, визуальные элементы и вспомогательные функции:

/project-root
│
├─ /src
│   ├─ index.js          // точка входа
│   ├─ /scenes           // сцены и их логика
│   ├─ /objects          // графические объекты и их классы
│   ├─ /utils            // вспомогательные функции
│   └─ /styles           // CSS или другие стили
│
├─ /assets
│   ├─ images
│   └─ fonts
│
├─ index.html
└─ package.json
  • /src/index.js — инициализация экземпляра Two.js, подключение сцен и объектов.
  • /src/scenes — содержит отдельные модули для каждой анимации или интерактивного состояния.
  • /src/objects — классы для повторно используемых объектов, например, персонажей, фигур или сложных графических паттернов.
  • /src/utils — функции для математических вычислений, генерации случайных чисел, работы с цветами и событиями.

Такой подход повышает читаемость и облегчает поддержку кода, особенно когда проект растет.


Инициализация Two.js и базовая сцена

Создание экземпляра Two.js начинается с указания контейнера и размеров канваса:

import Two from 'two.js';

const elem = document.getElementById('draw-area');
const two = new Two({
  width: 800,
  height: 600,
  type: Two.Types.svg // Можно выбрать 'webgl', 'canvas' или 'svg'
}).appendTo(elem);

Ключевые моменты:

  • type определяет рендерер, что влияет на производительность и возможности.
  • Размеры канваса задаются через width и height, но их можно динамически обновлять для адаптивного дизайна.

После инициализации Two.js создается основная сцена, в которой будут размещаться объекты:

const circle = two.makeCircle(400, 300, 50);
circle.fill = '#FF8000';
circle.stroke = 'orangered';
circle.linewidth = 5;

two.update();

Модульность объектов

Каждый графический объект лучше инкапсулировать в отдельный класс:

export class MovingCircle {
  constructor(two, x, y, radius, color) {
    this.circle = two.makeCircle(x, y, radius);
    this.circle.fill = color;
    this.speed = Math.random() * 2 + 1;
  }

  upd ate() {
    this.circle.translation.x += this.speed;
    if (this.circle.translation.x > 800) {
      this.circle.translation.x = 0;
    }
  }
}
  • update() отвечает за анимацию, что отделяет визуальные изменения от логики приложения.
  • Такой подход позволяет создавать массив объектов и анимировать их централизованно.

Организация анимации

Two.js предоставляет метод bind для связывания обновлений сцены с циклом анимации:

two.bind('update', function(frameCount) {
  circles.forEach(circle => circle.update());
}).play();
  • frameCount используется для синхронизации анимации и расчета сложных движений.
  • Все объекты, нуждающиеся в обновлении, помещаются в массив и обрабатываются централизованно.

Работа со слоями и группами

Two.js поддерживает группировку объектов для удобного управления:

const group = two.makeGroup();
group.add(circle1, circle2);

group.translation.se t(100, 50); // Перемещение всей группы
  • Группы позволяют перемещать, масштабировать и вращать набор объектов одновременно.
  • Для крупных проектов рекомендуется создавать отдельные группы для логически связанных элементов интерфейса и анимации.

Вспомогательные функции и утилиты

Все математические и вспомогательные функции стоит хранить в отдельном модуле:

export function randomColor() {
  const r = Math.floor(Math.random() * 256);
  const g = Math.floor(Math.random() * 256);
  const b = Math.floor(Math.random() * 256);
  return `rgb(${r},${g},${b})`;
}
  • Использование utils облегчает тестирование и переиспользование кода.
  • Централизация вспомогательных функций снижает дублирование и повышает читаемость проекта.

Поддержка масштабируемости

Для больших проектов важно:

  1. Разделять логику сцен, объектов и утилит.
  2. Использовать ES6-модули и импорт/экспорт вместо глобальных переменных.
  3. Применять классы и композицию для сложных объектов.
  4. Использовать массивы и группы для централизованного управления анимацией.
  5. Разделять CSS и визуальные настройки от логики движения и событий.

Такой подход позволяет расширять проект, добавлять новые сцены, эффекты и объекты без нарушения существующего кода.


Асинхронная загрузка ресурсов

Для проектов с изображениями или шрифтами важно использовать асинхронную загрузку:

function loadImage(src) {
  return new Promise((resolve) => {
    const img = new Image();
    img.onl oad = () => resolve(img);
    img.src = src;
  });
}

async function init() {
  const image = await loadImage('assets/images/sprite.png');
  const texture = two.makeSprite(image, 400, 300);
}
  • Асинхронная загрузка предотвращает блокировку интерфейса.
  • Позволяет управлять ресурсами и инициализировать сцену только после полной загрузки.

Обработка событий

Two.js интегрируется с DOM-событиями для интерактивности:

two.renderer.domElement.addEventListener('click', (e) => {
  const circle = two.makeCircle(e.offsetX, e.offsetY, 30);
  circle.fill = randomColor();
});
  • Использование событий напрямую с рендерером обеспечивает точное позиционирование объектов.
  • Можно создавать универсальные обработчики для кликов, движения мыши или касаний.

Эта структура организации кода обеспечивает чистую архитектуру проектов на Two.js, повышает повторное использование компонентов и упрощает поддержку крупных интерактивных приложений.