Использование TypeScript при работе с библиотекой Paper.js позволяет получить строгую типизацию, улучшенную читаемость кода и более безопасную разработку графических приложений. Paper.js изначально ориентирован на JavaScript, однако благодаря наличию деклараций типов (type definitions) он хорошо интегрируется с TypeScript-проектами.
Для начала необходимо установить саму библиотеку и типы:
npm install paper
npm install --save-dev @types/paper
Типы могут быть встроены в пакет (в зависимости от версии), но в
большинстве случаев используется отдельный пакет
@types/paper.
В tsconfig.json важно учитывать следующие параметры:
{
"compilerOptions": {
"target": "ES6",
"module": "ESNext",
"strict": true,
"esModuleInterop": true,
"types": ["paper"]
}
}
Существует два основных способа подключения:
import paper from 'paper';
paper.setup(document.getElementById('canvas') as HTMLCanvasElement);
Paper.js использует концепцию PaperScope —
изолированного контекста, содержащего все объекты библиотеки.
import { PaperScope } from 'paper';
const scope = new PaperScope();
scope.setup(document.getElementById('canvas') as HTMLCanvasElement);
const circle = new scope.Path.Circle({
center: [100, 100],
radius: 50,
fillColor: 'blue'
});
Типизация позволяет точно определить, какие методы и свойства доступны в каждом объекте.
Paper.js предоставляет множество классов, которые в TypeScript представлены как типы:
PathPointSizeRectangleColorProjectLayerconst point: paper.Point = new paper.Point(50, 50);
const size: paper.Size = new paper.Size(100, 100);
const rect: paper.Rectangle = new paper.Rectangle(point, size);
const path: paper.Path = new paper.Path();
path.strokeColor = new paper.Color('black');
path.add(new paper.Point(0, 0));
path.add(new paper.Point(100, 100));
TypeScript обеспечивает проверку типов при добавлении сегментов и свойств.
Иногда требуется добавить собственные свойства к объектам Paper.js. Для этого используется расширение интерфейсов.
declare module 'paper' {
interface Path {
customId?: string;
}
}
Теперь можно безопасно использовать:
const path = new paper.Path();
path.customId = 'line-1';
Paper.js активно использует событийную модель.
const tool = new paper.Tool();
tool.onMouseD own = (event: paper.ToolEvent) => {
console.log(event.point);
};
Тип ToolEvent включает:
pointeventmodifiersTypeScript гарантирует корректный доступ к этим свойствам.
Paper.js поддерживает анимацию через onFrame:
paper.view.onFr ame = (event: paper.IViewOnFrameEvent) => {
console.log(event.delta);
};
Тип IViewOnFrameEvent содержит:
delta — время между кадрамиtime — общее времяcount — номер кадраМногие методы возвращают массивы или коллекции объектов:
const paths: paper.PathItem[] = paper.project.activeLayer.children as paper.PathItem[];
При строгой типизации может потребоваться явное приведение типов.
TypeScript позволяет создавать обобщённые функции для работы с объектами Paper.js:
function cloneItem<T extends paper.Item>(item: T): T {
return item.clone() as T;
}
Некоторые методы могут возвращать null:
const hitResult = paper.project.hitTest(new paper.Point(50, 50));
if (hitResult) {
console.log(hitResult.item);
}
Строгий режим TypeScript (strictNullChecks) требует
обязательной проверки.
Paper.js использует строковые значения для некоторых свойств:
type BlendMode =
| 'normal'
| 'multiply'
| 'screen';
const path = new paper.Path.Circle({
center: [50, 50],
radius: 20,
blendMode: 'multiply' as BlendMode
});
TypeScript помогает избежать ошибок при работе с координатами:
function movePoint(point: paper.Point, dx: number, dy: number): paper.Point {
return point.add(new paper.Point(dx, dy));
}
Рекомендуется разделять код:
/src
/graphics
shapes.ts
animation.ts
/utils
math.ts
main.ts
Canvas элемент должен быть явно типизирован:
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
paper.setup(canvas);
const layer: paper.Layer = new paper.Layer();
layer.activate();
const path = new paper.Path.Circle({
center: [100, 100],
radius: 30,
fillColor: 'red'
});
class CustomTool {
tool: paper.Tool;
constructor() {
this.tool = new paper.Tool();
this.tool.onMouseM ove = this.onMouseMove.bind(this);
}
onMouseMove(event: paper.ToolEvent): void {
console.log(event.point);
}
}
Включение strict режима выявляет:
TypeScript не влияет напрямую на производительность, но позволяет:
При интеграции с другими библиотеками (например, React):
import { useEffect, useRef } from 'react';
import paper from 'paper';
function Canvas() {
const canvasRef = useRef<HTMLCanvasElement>(null);
useEffect(() => {
if (!canvasRef.current) return;
paper.setup(canvasRef.current);
new paper.Path.Circle({
center: [50, 50],
radius: 25,
fillColor: 'green'
});
}, []);
return <canvas ref={canvasRef} />;
}
1. Потеря контекста this
tool.onMouseD own = function(event) {
// this может быть не тем, что ожидается
};
Решение — использовать стрелочные функции:
tool.onMouseD own = (event) => {};
2. Неявные типы
const point = [10, 20]; // ошибка
Правильно:
const point: paper.Point = new paper.Point(10, 20);
3. Приведение типов
const item = paper.project.activeLayer.children[0] as paper.Path;
Можно описывать собственные структуры:
interface Drawable {
draw(): void;
}
И комбинировать с Paper.js:
class CircleShape implements Drawable {
private path: paper.Path.Circle;
constructor(center: paper.Point, radius: number) {
this.path = new paper.Path.Circle(center, radius);
}
draw(): void {
this.path.fillColor = new paper.Color('blue');
}
}
При использовании TypeScript удобно применять:
TypeScript облегчает отладку:
Используются инструменты:
tscwebpackviteПример команды:
tsc --watch
Основные иерархии:
Item
├── Path
├── Shape
├── Group
└── Raster
Каждый из этих типов имеет собственные свойства и методы, которые строго контролируются TypeScript.
import paper from 'paper';
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
paper.setup(canvas);
const center = new paper.Point(200, 200);
const circle = new paper.Path.Circle({
center,
radius: 80,
strokeColor: new paper.Color('black')
});
paper.view.onFr ame = (event) => {
circle.rotate(1);
};
Типизация гарантирует: