Интерактивные графические редакторы на базе Paper.js строятся вокруг
сцены (Project), слоя (Layer) и элементов
(Item). Каждое действие пользователя преобразуется в
операции над векторными объектами: создание, трансформация, удаление или
модификация.
Ключевую роль играют инструменты (Tool), которые
позволяют организовать поведение ввода:
onMouseDown — начало действияonMouseDrag — процесс измененияonMouseUp — завершениеСостояние редактора обычно хранится в виде текущего режима (например, рисование, выделение, перемещение) и набора активных объектов.
Свободное рисование (freehand) реализуется через динамическое
создание пути (Path) и добавление сегментов:
let path;
tool.onMouseD own = function(event) {
path = new Path();
path.strokeColor = 'black';
path.add(event.point);
};
tool.onMouseD rag = function(event) {
path.add(event.point);
};
tool.onMous eUp = function(event) {
path.simplify();
};
Метод simplify() уменьшает количество точек, сглаживая
линию и оптимизируя производительность.
Визуальное разнообразие достигается за счёт настройки параметров:
strokeWidth — толщинаstrokeColor — цветstrokeCap — форма концов (round,
square, butt)dashArray — пунктирПример имитации кисти:
path.strokeWidth = 10;
path.strokeCap = 'round';
path.opacity = 0.5;
Для более сложных кистей применяются группы (Group) или
клонирование объектов вдоль траектории.
Создание геометрических фигур строится на основе начальной и конечной точки:
let shape;
tool.onMouseD own = function(event) {
shape = new Path.Rectangle({
point: event.point,
size: [0, 0],
strokeColor: 'black'
});
};
tool.onMouseD rag = function(event) {
shape.remove();
shape = new Path.Rectangle({
from: event.downPoint,
to: event.point,
strokeColor: 'black'
});
};
Аналогично реализуются:
Path.Circle)Path.Ellipse)Path.Line)Для работы с объектами применяется хит-тестирование
(hitTest):
tool.onMouseD own = function(event) {
let hitResult = project.hitTest(event.point);
if (hitResult) {
selectedItem = hitResult.item;
}
};
Перемещение:
tool.onMouseD rag = function(event) {
if (selectedItem) {
selectedItem.position += event.delta;
}
};
Масштабирование и вращение реализуются через трансформации:
selectedItem.scale(1.1);
selectedItem.rotate(10);
Группировка (Group) позволяет объединять элементы:
let group = new Group([path1, path2]);
group.rotate(45);
Слои (Layer) используются для управления порядком
рендеринга:
let layer = new Layer();
layer.activate();
Ластик реализуется несколькими способами:
1. Удаление объектов:
if (hitResult) {
hitResult.item.remove();
}
2. Булевы операции:
let result = path1.subtract(eraserPath);
path1.remove();
3. Частичное редактирование сегментов:
path.segments[0].point += [10, 0];
Редактор требует системы отката:
undoStack)redoStack)Простейшая реализация:
let undoStack = [];
function saveState() {
undoStack.push(project.exportJSON());
}
function undo() {
if (undoStack.length > 0) {
let state = undoStack.pop();
project.clear();
project.importJSON(state);
}
}
Цвет задаётся через Color:
path.fillColor = 'red';
Поддерживаются:
Gradient)Пример градиента:
path.fillColor = {
gradient: {
stops: ['yellow', 'red']
},
origin: path.bounds.leftCenter,
destination: path.bounds.rightCenter
};
Paper.js поддерживает текст:
let text = new PointText({
point: [100, 100],
content: 'Hello',
fillColor: 'black',
fontSize: 20
});
Редакторы добавляют:
Редактор обычно делится на:
Состояние инструментов управляется через переменные:
let currentTool = 'brush';
И переключается:
if (currentTool === 'rectangle') {
// логика прямоугольника
}
Сохранение работы:
let json = project.exportJSON();
Загрузка:
project.importJSON(json);
Экспорт в SVG:
let svg = project.exportSVG({ asString: true });
При большом количестве объектов важно:
simplify()Пример оптимизации:
view.autoUpdate = false;
// изменения
view.update();
Функциональность легко расширяется:
Обработка клавиатуры:
tool.onKeyD own = function(event) {
if (event.key === 'z') {
undo();
}
};
Рекомендуемая структура:
Пример:
const tools = {
brush: new Tool(),
rectangle: new Tool()
};
Каждый инструмент инкапсулирует свою логику, что делает редактор масштабируемым и удобным для поддержки.
Для сложных редакторов применяются:
Это позволяет поддерживать предсказуемое поведение при большом количестве функций.
Качественный редактор требует:
Пример сетки:
let gridSize = 10;
function snap(point) {
return new Point(
Math.round(point.x / gridSize) * gridSize,
Math.round(point.y / gridSize) * gridSize
);
}
Изменение курсора повышает удобство:
canvas.style.cursor = 'crosshair';
На базе Paper.js реализуются:
Ключевая идея — управление векторной сценой через события и трансформации, где каждый элемент остаётся редактируемым объектом, а не просто пикселями.