Мотивация
С университетских времён меня увлекали различные математические визуализации. В то время это выглядело ужасно сложным, не возникало и мысли попробовать сделать что-то самостоятельно. Заметно позже, увлёкшись программированием, натолкнулся на замечательный канал The Coding Train. Лектором канала является Дэниел Шиффман, ведущий увлекательные лекции, посвященные самым различным темам на JavaScript, в том числе и серию испытаний, на которых в режиме реального времени лектор реализовывал идеи, предложенные подписчиками.
Повторяя за лектором, испытание за испытанием, я научился многому. В основном Дэниел на своём канале использует библиотеку p5js. Данная библиотека сама по себе является отличным инструментом для новичков, позволяющей творить в максимально минимальные сроки. Со временем, набравшись опыта и имея стремление пытаться сделать что-то самостоятельно и с желанием понять принцицы работы, решил отойти от использования данной библиотеки. В этом было достаточно много плюсов; например, я изучил Canvas API
, и перестал тащить за собой кучу неиспользуемого кода из библиотеки (а сам по себе p5js не маленький - почти целый мегабайт в сжатом виде).
Перестав использовать библиотеку, я потерял доступ к некоторым важным сущностям. Одной из них является P5.Vector
, представляющей собой вектор в евклидовом пространстве, реализацию которой представляет p5js “из коробки”. Множество визуализаций используют вектора, что делает код простым и читабельным.
Именно для этих целей и была написана библиотека vector. Изучив имеющиеся альтернативы и собрав всё лучшее воедино, теперь я имею под рукой удобный и многофункциональный инструмент для собственных нужд.
Функционал
vector
представляет собой библиотеку для работы с векторами, написанную на TypeScript.
Попробовать библиотеку в деле можно с помощью npm:
npm i @ericrovell/vector
Далее, необходимо импортировать функцию vector
и можно начинать работу:
import { vector } from "@ericrovell/vector";
const v1 = vector(1, 2, 3);
console.log(vector.toString()); // "(1, 2, 3)"
Ввод
Одним из преимуществ библиотеки является гибкость пользовательского ввода.
Конструктор vector
позволяет использовать декартову систему координат тройкой аргументов, объектом или массивом. Помимо декартовой системы координат конструктор поддерживает полярную и цилиндрическую системы координат. Необходимые типы уже включены в пакет:
import type { Cartesian, Polar, Cylindrical } from "@ericrovell/vector";
// Cartesian
vector(1, 2, 3);
vector([ 1, 2, 3]);
vector({ x: 1, y: 2, z: 3} as Cartesian);
// Polar
vector({
phi: Math.PI,
theta: Math.PI / 2,
magnitude: 5
} as Polar);
// Cylindrical
vector({
phi: Math.PI,
p: 5,
z: 8
} as Cylindrical);
Методы
Все методы, принимающие вектор как аргумент, обладают той же гибкостью и принимают вышеперечисленные типы данных на ввод. Конечно же, можно использовать и другие экземпляры vector
:
import { vector } from "@ericrovell/vector";
const v1 = vector(1, 2, 3);
const v2 = vector({ x: -1, y: -2, z: -3 });
console.log(
v1.add({ x: -1, y: -2, z: -3 }).toString()
); // -> "(0, 0, 0)"
console.log(
v1.add(v2).toString()
); // -> "(0, 0, 0)"
Иммутабельность
Библиотека предоставляет возможность работать в функциональном, иммутабельном стиле. Тем не менее, у большей части методов существует и мутабельный “метод-близнец”. В библиотеке используется соглашение, что мутабельные методы используют постфикс self: .add()
и .addSelf()
.
Что я узнал нового
В процессе работы над библиотекой я узнал множество мелких, тем не менее важных деталей, необходимых для публикации качественного npm пакета.
В процессе работы над библиотекой узнал и применил на практике некоторые символы, с помощью которых можно добавить функционала экземплярам класса. Например, с помощью Symbol.iterator
экземляр vector
можно использовать в for ... of
циклах, а используя Symbol.toPrimitive
можно добавить возможность приведения типов. По сути, небольшие мелочи, без которых вполне можно обойтись, однако делающие библиотеку чуть практичнее.
Помимо вышеперечисленного, удалось освежить знания линейной алгебры.