Two.js — это библиотека для рисования в 2D с поддержкой Canvas, SVG и WebGL. В сочетании с современным JavaScript и подходами Composition API можно создавать динамичные, реактивные и модульные сцены с минимальным дублированием кода. Composition API обеспечивает гибкость при организации логики и позволяет разделять состояние и методы управления визуальными объектами Two.js.
Основной объект Two.js создается с помощью конструктора
Two, которому передаются параметры конфигурации сцены:
const two = new Two({
width: 800,
height: 600,
type: Two.Types.canvas
}).appendTo(document.body);
Ключевые параметры:
width и height — размеры области
рисования.type — тип рендерера (canvas,
svg, webgl).domElement (необязательный) — элемент, в который будет
встроена сцена.После создания инстанса сцена готова к добавлению объектов и анимации.
Composition API основан на ref и reactive,
что позволяет отслеживать изменения состояния и автоматически обновлять
визуальные объекты. Например:
import { ref, reactive, watch } from 'vue';
const circleProps = reactive({
x: 400,
y: 300,
radius: 50,
fill: '#FF8000'
});
const circle = two.makeCircle(circleProps.x, circleProps.y, circleProps.radius);
circle.fill = circleProps.fill;
watch(() => circleProps, (newProps) => {
circle.translation.set(newProps.x, newProps.y);
circle.radius = newProps.radius;
circle.fill = newProps.fill;
}, { deep: true });
Особенности использования:
reactive создаёт объект с реактивными свойствами.watch позволяет синхронизировать изменения состояния с
объектами Two.js.deep: true) важно для объектов с
вложенными свойствами, такими как позиции, размеры или цвета.Composition API облегчает создание модульных и повторно используемых компонентов Two.js. Пример: группа фигур, управляемых одним состоянием.
const groupState = reactive({
dx: 0,
dy: 0,
rotation: 0
});
const rect = two.makeRectangle(300, 300, 100, 50);
const ellipse = two.makeEllipse(350, 300, 50, 25);
watch(() => groupState, (state) => {
rect.translation.set(rect.translation.x + state.dx, rect.translation.y + state.dy);
ellipse.translation.set(ellipse.translation.x + state.dx, ellipse.translation.y + state.dy);
rect.rotation = state.rotation;
ellipse.rotation = state.rotation;
}, { deep: true });
Важные моменты:
reactive состояния для группы упрощает
управление всей композицией, избегая дублирования кода.Two.js поддерживает встроенный цикл рендеринга. С помощью Composition API анимацию можно сделать полностью реактивной:
import { ref } from 'vue';
const angle = ref(0);
const rotatingCircle = two.makeCircle(400, 300, 60);
rotatingCircle.fill = '#00AEEF';
two.bind('update', () => {
angle.value += 0.01;
rotatingCircle.translation.x = 400 + 100 * Math.cos(angle.value);
rotatingCircle.translation.y = 300 + 100 * Math.sin(angle.value);
});
two.play();
Принципы работы:
two.bind('update', callback) вызывается
на каждом кадре.ref и динамически менять параметры объектов.Можно вынести отдельные логические блоки в функции-композиторы. Пример: создание и управление анимируемым кругом:
function useRotatingCircle(two, options) {
const angle = ref(0);
const circle = two.makeCircle(options.x, options.y, options.radius);
circle.fill = options.fill;
two.bind('update', () => {
angle.value += options.speed;
circle.translation.x = options.x + options.radius * Math.cos(angle.value);
circle.translation.y = options.y + options.radius * Math.sin(angle.value);
});
return { circle, angle };
}
const { circle } = useRotatingCircle(two, { x: 400, y: 300, radius: 50, fill: '#FF0000', speed: 0.02 });
two.play();
Преимущества такого подхода:
Composition API позволяет не только управлять позициями, но и динамически изменять цвета, размеры и другие свойства:
const squareProps = reactive({
size: 80,
color: '#008000'
});
const square = two.makeRectangle(200, 200, squareProps.size, squareProps.size);
square.fill = squareProps.color;
watch(squareProps, (props) => {
square.width = props.size;
square.height = props.size;
square.fill = props.color;
}, { deep: true });
Особенности:
Composition API идеально подходит для интеграции Two.js с Vue 3:
onMounted, onUnmounted).import { onMounted, onUnmounted, reactive } from 'vue';
export default {
setup() {
const state = reactive({ x: 0 });
let two;
onMounted(() => {
two = new Two({ width: 500, height: 400 }).appendTo(document.body);
const circle = two.makeCircle(250, 200, 40);
circle.fill = '#0000FF';
two.bind('update', () => {
circle.translation.x = 250 + 100 * Math.sin(state.x);
state.x += 0.05;
});
two.play();
});
onUnmounted(() => {
two.clear();
});
return { state };
}
};
Ключевые моменты интеграции: