Для интеграции Two.js в Vue компонент необходимо подключить библиотеку через npm:
npm install two.js
Импорт в компоненте осуществляется стандартно:
import Two from 'two.js';
Создание экземпляра Two выполняется в хуке
mounted, чтобы гарантировать наличие DOM-элемента:
export default {
name: 'TwoComponent',
mounted() {
const elem = this.$refs.canvasContainer;
this.two = new Two({
width: 800,
height: 600,
type: Two.Types.svg // или canvas, webgl
}).appendTo(elem);
},
beforeUnmount() {
this.two.clear();
this.two = null;
},
data() {
return {
two: null
};
}
}
Ключевой момент: appendTo должен
ссылаться на реально существующий DOM-элемент, поэтому использование
$refs в mounted критично.
Two.js поддерживает примитивы: Rectangle,
Circle, Ellipse, Polygon,
Line, Path, Text. Создание
происходит через методы экземпляра Two:
const circle = this.two.makeCircle(400, 300, 50);
circle.fill = '#FF8000';
circle.stroke = '#000000';
circle.linewidth = 2;
const rect = this.two.makeRectangle(200, 150, 100, 50);
rect.fill = 'blue';
rect.opacity = 0.7;
this.two.update();
Важно: свойства fill,
stroke, linewidth, opacity можно
динамически изменять в реактивном стиле, если хранить ссылки на фигуры в
data или refs.
Two.js предоставляет встроенный механизм анимации через
bind и play. В Vue рекомендуется использовать
реактивные данные для управления анимацией:
mounted() {
const circle = this.two.makeCircle(100, 300, 40);
circle.fill = 'red';
this.two.bind('upd ate', (frameCount) => {
circle.translation.x = 100 + 200 * Math.sin(frameCount * 0.05);
});
this.two.play();
}
Особенности:
bind('update', callback) вызывается каждый кадр.frameCount для расчета периодических
движений.two.clear()), иначе будут утечки памяти.Two.js не предоставляет собственные события мыши и клика, поэтому обработка выполняется через DOM:
mounted() {
const circle = this.two.makeCircle(150, 150, 50);
circle.fill = 'green';
this.$refs.canvasContainer.addEventListener('click', (e) => {
const rect = this.$refs.canvasContainer.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
if (Math.hypot(circle.translation.x - x, circle.translation.y - y) < circle.radius) {
circle.fill = 'yellow';
this.two.update();
}
});
}
Совет: для сложных сцен рекомендуется использовать
отдельные слои <canvas> и хранить ссылки на все
интерактивные объекты в массиве для проверки пересечений.
Two.js может быть полностью интегрирован с реактивной системой Vue. Например:
data() {
return {
circleX: 100,
circleColor: 'red'
};
},
mounted() {
const circle = this.two.makeCircle(this.circleX, 200, 50);
circle.fill = this.circleColor;
this.$watch('circleX', (newVal) => {
circle.translation.x = newVal;
this.two.update();
});
this.$watch('circleColor', (newVal) => {
circle.fill = newVal;
this.two.update();
});
this.two.play();
}
Ключевой момент: watch позволяет
связать любые изменения реактивных данных с визуальными обновлениями в
Two.js.
Two.js поддерживает группы объектов через Two.Group. Это
позволяет одновременно управлять несколькими фигурами:
const group = this.two.makeGroup();
const circle1 = this.two.makeCircle(50, 50, 20);
const circle2 = this.two.makeCircle(150, 50, 20);
group.add(circle1, circle2);
group.translation.se t(100, 100);
this.two.update();
Группы можно анимировать как единое целое, менять прозрачность или поворот:
group.rotation = Math.PI / 4;
group.opacity = 0.5;
this.two.update();
Two.js поддерживает рендеринг через WebGL для сложных эффектов:
this.two = new Two({
width: 800,
height: 600,
type: Two.Types.webgl
}).appendTo(this.$refs.canvasContainer);
const rect = this.two.makeRectangle(400, 300, 200, 100);
rect.fill = '#3498db';
rect.stroke = '#2c3e50';
this.two.update();
WebGL режим позволяет использовать Two.Textured объекты
и настраивать эффекты прозрачности и смешивания.
Two.js предоставляет Path для сложных фигур с кривыми
Безье:
const path = this.two.makePath(100, 100, 150, 50, 200, 150, true);
path.fill = 'none';
path.stroke = '#e74c3c';
path.linewidth = 3;
this.two.update();
Для кривых можно задавать управление через массивы точек и динамически изменять их координаты в анимации:
this.two.bind('update', () => {
path.vertices[1].x = 150 + 50 * Math.sin(Date.now() * 0.005);
this.two.update();
});
requestAnimationFrame через
two.bind('update', ...) вместо setInterval.Two.Group для массовых
трансформаций.beforeUnmount:beforeUnmount() {
this.two.pause();
this.two.clear();
this.two = null;
}
Vue-компонент может содержать несколько сцен одновременно:
mounted() {
this.two1 = new Two({ width: 400, height: 300 }).appendTo(this.$refs.scene1);
this.two2 = new Two({ width: 400, height: 300 }).appendTo(this.$refs.scene2);
this.two1.makeCircle(100, 100, 50);
this.two2.makeRectangle(200, 150, 100, 50);
this.two1.play();
this.two2.play();
}
Важно: каждый экземпляр Two.js независим, поэтому их анимации и группы объектов не пересекаются.