Расширение прототипов

В Paper.js все объекты основаны на прототипах JavaScript, что позволяет гибко расширять их функциональность, добавляя собственные методы и свойства. Это особенно полезно для создания повторно используемых компонентов и упрощения работы с графикой в векторной среде.

Добавление методов к существующим классам

Каждый класс Paper.js имеет свой прототип. Например, Path — это класс для создания и управления кривыми и линиями. Чтобы добавить новый метод, достаточно расширить прототип:

Path.prototype.getMidPoint = function() {
    return this.segments.length > 0
        ? this.getPointAt(this.length / 2)
        : null;
};

Метод getMidPoint теперь доступен для всех объектов Path и возвращает точку, находящуюся в середине пути.

Важно: изменения прототипа влияют на все экземпляры класса, включая уже созданные объекты.

Расширение класса Point

Класс Point представляет координаты в пространстве. Часто требуется добавлять методы для вычислений или преобразований:

Point.prototype.rotateAround = function(center, angle) {
    var vector = this.subtract(center);
    var rad = angle * (Math.PI / 180);
    var cos = Math.cos(rad);
    var sin = Math.sin(rad);
    var rotated = new Point(
        vector.x * cos - vector.y * sin,
        vector.x * sin + vector.y * cos
    );
    return center.add(rotated);
};

Метод rotateAround позволяет повернуть точку относительно заданного центра на заданный угол.

Примеры расширения Path

Для работы с графическими объектами можно создавать методы, которые упрощают сложные операции, например, изменение цвета сегментов или автоматическое создание кривых:

Path.prototype.randomizeSegmentColors = function() {
    this.segments.forEach(segment => {
        segment.strokeColor = new Color(Math.random(), Math.random(), Math.random());
    });
};

Path.prototype.smoothAllSegments = function() {
    this.smooth({ type: 'continuous' });
};

Теперь любой путь можно сразу сгладить или назначить случайные цвета сегментам через новые методы.

Создание цепочек вызовов

При расширении прототипов удобно возвращать this для поддержки цепочек вызовов:

Path.prototype.scaleAndColor = function(factor, color) {
    this.scale(factor);
    this.strokeColor = color;
    return this;
};

// Использование:
var path = new Path.Line([0,0], [100,100])
    .scaleAndColor(1.5, 'red')
    .smoothAllSegments();

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

Расширение PaperScope

Paper.js использует объект paper как глобальное пространство имён. Можно расширять и его функциональность, добавляя собственные утилиты:

paper.createRandomCircle = function(bounds) {
    var radius = Math.random() * 50 + 10;
    var point = new Point(
        Math.random() * bounds.width,
        Math.random() * bounds.height
    );
    return new Path.Circle(point, radius);
};

Теперь paper.createRandomCircle(view.bounds) создаёт случайный круг в пределах видимой области.

Практика безопасного расширения

  • Использовать уникальные имена методов, чтобы избежать конфликтов с будущими обновлениями библиотеки.
  • Проверять наличие метода перед добавлением:
if (!Path.prototype.getMidPoint) {
    Path.prototype.getMidPoint = function() { ... };
}
  • Ограничивать изменения прототипов лишь теми методами, которые будут активно использоваться во множестве объектов, чтобы не перегружать память.

Наследование и собственные классы

Paper.js поддерживает наследование через прототипы. Создание собственного класса на основе Path:

function FancyPath(segments) {
    Path.call(this, segments);
    this.strokeWidth = 2;
    this.strokeColor = 'blue';
}

FancyPath.prototype = Object.create(Path.prototype);
FancyPath.prototype.constructor = FancyPath;

FancyPath.prototype.addRandomSegment = function() {
    var last = this.lastSegment.point;
    var newPoint = last.add(new Point(Math.random()*50, Math.random()*50));
    this.add(newPoint);
};

Теперь FancyPath наследует все методы Path и обладает дополнительными функциями.

Расширение для анимаций

Методы прототипов удобно использовать для динамических эффектов:

Path.prototype.oscillate = function(amplitude, frequency) {
    var path = this;
    var initialY = path.position.y;
    view.onFr ame = function(event) {
        path.position.y = initialY + Math.sin(event.time * frequency) * amplitude;
    };
};

Любой путь можно «оживить», задав амплитуду и частоту колебаний.

Выводы по расширению прототипов

  • Позволяет создавать более читаемый и компактный код.
  • Ускоряет разработку сложных графических приложений.
  • Обеспечивает единообразие методов для всех объектов одного типа.
  • Требует осторожности при именовании и совместимости с будущими версиями библиотеки.

Расширение прототипов в Paper.js открывает возможности для построения мощных и повторно используемых инструментов визуализации, позволяя интегрировать дополнительные методы напрямую в объекты библиотеки.