Хотя SVG существует уже более десяти лет, он стал популярным в последние несколько лет как способ рисования диаграмм в веб-приложениях благодаря некоторым замечательным библиотекам, которые сделали прекрасные диаграммы и рисунки легко доступными для разработчиков: в частности, D3. JS для диаграмм и Raphaël для классных рисунков и анимации SVG.
Недавно появились новые выдающиеся библиотеки; они предоставляют передовым разработчикам и дизайнерам новые подходы и удивительные новые функции:
- Snap.svg , как мы увидим, предлагает новейшие функции SVG, такие как маскирование, отсечение, шаблоны, градиенты и т. Д.
- PathsJs — это минимальная библиотека для создания графиков на основе SVG. Он предназначен для поддержки реактивного программирования путем создания SVG-путей, которые можно использовать с шаблонизаторами. Лучше всего работает с шаблонным движком на основе усов, таким как Ractive .
- Хотя он не основан на SVG, P5 заслуживает упоминания. Это попытка, и, видимо, хорошая, чтобы преодолеть традиционные проблемы, затрагивающие элемент HTML5 canvas — взаимодействие, в частности.
В оставшейся части этой статьи мы подробно рассмотрим Snap.svg, начиная с основ.
Рафаель
Если у вас не было возможности взглянуть на Рафаэля , вам, вероятно, следует. Это хороший кусок JavaScript, созданный Дмитрием Барановским как сольный проект. Хотя это началось как личный проект, результат замечательный для интерфейса (очень четкий и последовательный), производительности и внешнего вида (особенно для анимации). Библиотека больше ориентирована на рисование от руки и анимацию, чем на графики. Расширение gRaphaël позже было выпущено для решения этой проблемы, но оно не стало таким популярным и распространенным, как D3.
Несмотря на то, что Raphaël опередил другие библиотеки, со временем он начал показывать свои границы. Например, чтобы быть совместимым со старыми браузерами, Raphaël не поддерживает все эти новые классные функции SVG, которые позволили бы выделить ваши анимации.
Вот почему его автор решил начать все заново с нового проекта Snap.svg, который, конечно же, извлекает пользу из опыта, накопленного при разработке Raphaël. Snap.svg также разрывается с прошлым, позволяя вводить совершенно новый вид спецэффектов.
О, Snap!
Прежде чем углубиться в синтаксис Snap и начать с нескольких примеров, давайте быстро рассмотрим плюсы и минусы этой новой библиотеки:
Плюсы:
- Он поддерживает все интересные функции, которые мы упоминали выше.
- Snap может обернуться и оживить существующий SVG. Вы можете сгенерировать SVG с помощью таких инструментов, как Adobe Illustrator, Inkscape или Sketch, или асинхронно загружать строки SVG и запрашивать фрагменты, необходимые для превращения файла SVG в спрайт.
- Это бесплатно и с открытым исходным кодом.
Минусы:
- Это низкоуровневая библиотека, поэтому, если вам нужно визуализировать данные, к сожалению, пока нет поддержки диаграмм.
- Нет поддержки для привязки данных.
- Snap — это молодой проект, который еще не достиг полной зрелости. Это уже отлично подходит для ваших личных проектов, но вы должны взвесить этот аспект, прежде чем использовать его в комплексе.
Как мы уже упоминали, Snap использует функции, не поддерживаемые старыми браузерами. Хотя полная обновленная таблица совместимости еще не предоставлена, эта библиотека должна нормально работать, по крайней мере, со следующими версиями браузера (и новее):
- Firefox ESR 18
- IE 9.0.8
- Chrome 29
- Опера 24
Начало работы с Snap
После загрузки исходных файлов из репозитория GitHub вы можете разархивировать их и найти папку dist
, которая содержит встроенные файлы дистрибутива. Для получения подробных инструкций по созданию оснастки с помощью Grunt или для проверки последней версии, посмотрите здесь .
После того, как вы скопировали минимизированную версию файла в папку js
вашего нового проекта, просто включите скрипт в свою HTML-страницу. Предполагая, что он находится в корневом каталоге вашего проекта, вы можете просто добавить эту строку прямо перед закрывающим тегом body
страницы:
<script src="/js/snap.svg-min.js"></script>
Теперь мы готовы создать область рисования для нашей векторной графики. У нас есть два способа сделать это:
- Создайте совершенно новую поверхность для рисования, которая будет добавлена к DOM страницы (внутри
body
). - Повторно используйте существующий элемент DOM и оберните его в структуру Snap. Вы можете обернуть любой элемент, но для методов рисования вам понадобится элемент SVG.
Первый способ позволяет вам явно установить ширину и высоту поверхности при создании в коде JavaScript. Если вы хотите достичь большего уровня разделения между представлением и контентом, вы можете использовать второй способ, указав значения в правиле CSS. На высоком уровне первый метод позволяет динамически настраивать внешний вид поверхности чертежа, но если вам это не нужно, второй способ более совместим с MVC. Более того, обертывание — это то, что позволяет импортировать и изменять чертежи SVG, созданные с помощью внешних инструментов, как упоминалось в разделе введения.
Так, например, чтобы создать новую область рисования размером 800 на 600 пикселей, вам просто нужна следующая строка JavaScript:
var s = Snap(800, 600);
Если вместо этого вы хотите обернуть существующий, скажите #complexSVGfromIllustrator
:
<svg id='complexSVGfromIllustrator' version="1.1" xmlns="http://www.w3.org/2000/svg"> ... </svg>
Вы все еще можете использовать одну строку JavaScript, чтобы импортировать поверхность для рисования:
var s = Snap('#complexSVGfromIllustrator');
Примечание: для любопытного читателя: если вы осмотрите объекты Snap после создания, вы заметите, что у них есть paper
поле, свидетельствующее о наследии Рафаэля.
Формы
Как только мы создали нашу поверхность для рисования, нашу обертку Snap
, пришло время нарисовать на ней несколько фигур. Допустим, вы хотите нарисовать круг:
var paper = Snap('#complexSVGfromIllustrator'), circle = paper.circle(100, 50, 10);
Как видно из документов , первые два параметра в методе circle()
являются координатами его центра, а третий — радиусом круга. Все эти параметры являются обязательными, и непредоставление их приведет к возникновению ошибки. Метод circle()
, как и все другие методы рисования, возвращает ссылку на объект.
Вы также можете рисовать эллипсы , как показано в следующем примере кода. Вертикальные и горизонтальные радиусы необходимы на этот раз. Опять же, все параметры являются обязательными.
var ellipse = paper.ellipse(100, 50, 10, 20);
Если вы хотите нарисовать прямоугольник , используйте следующий код. Это создаст прямоугольник с его верхним левым углом в (100px, 100px), шириной 200px и высотой 200px.
var r = paper.rect(100, 100, 200, 300);
Крутая вещь в методе rect()
заключается в том, что он также принимает два необязательных параметра, которые управляют радиусом закругленных углов, независимо для вертикальной и горизонтальной осей. Эти параметры по умолчанию равны 0, когда они не переданы, но будьте осторожны, если вы передадите только один (горизонтальный радиус), второй не будет установлен в ноль, а вместо этого оба примут одно и то же значение.
var rect = paper.rect(100, 100, 200, 300, 10); //equivalent to paper.rect(100, 100, 200, 300, 10, 10);
Теперь, если вы хотите начать с нуля, вы можете создать другую поверхность для рисования или просто использовать метод paper.clear()
чтобы стереть все рисунки с paper
.
Линии и Полигоны
Чтобы покрыть более сложные рисунки, нам нужно сделать шаг назад и поговорить о рисовании линий. Как и следовало ожидать, метод принимает четыре координаты конечных точек линии, как показано ниже.
var line = paper.line(10, 100, 110, 200);
var line = paper.polyline(10, 100, 110, 200);
интереснее возможность рисовать сложные полилинии : var line = paper.polyline(10, 100, 110, 200);
в принципе эквивалентен методу line()
описанному выше, но вы, вероятно, будете удивлены его визуальным результатом. Чтобы понять почему, давайте попробуем это
var p1 = paper.polyline(10, 10, 10, 100, 210, 20, 101, 120);
paper.polyline()
и paper.polygon()
являются псевдонимами для одного и того же метода, и по умолчанию результирующий (закрытый) многоугольник рисуется с черной заливкой и без обводки. Вот почему вы не могли видеть линию, нарисованную с помощью polyline()
выше (хотя вы можете проверить, проверив страницу, что код SVG для нее действительно добавлен в ее контейнер).
Чтобы изменить это поведение, а также внешний вид других элементов, мы должны ввести атрибуты.
Атрибуты
Понятие атрибутов для элементов Snap несколько шире, чем обычно, это означает, что оно включает в себя как атрибуты HTML, так и атрибуты CSS в одном интерфейсе (в то время как в большинстве других библиотек проводится различие между .attr()
для атрибутов HTML и ‘.style () для CSS). Используя метод element.attr()
объекта-обертки Snap, вы можете установить его class
или id
, а также его цвет или ширину.
Как упоминалось выше, используя Snap, вы можете назначить CSS-свойства элементу двумя способами. Одним из них является включение этих свойств в отдельный файл CSS, а затем просто назначьте соответствующий элемент для вашего элемента:
.big-circle { stroke: red; stroke-width: 2; fill: yellow; }
circle.attr({class: 'big-circle'});
Тот же результат можно получить, назначив эти свойства с помощью JavaScript:
circle.attr({ stroke: 'red'; stroke-width: 2; fill: 'yellow'; });
Опять же, первый способ позволяет лучше разделить контент и представление, а второй — возможность динамически изменять атрибуты. Если вы думаете о смешении двух стратегий, имейте в виду, что правила, определенные в файле CSS, будут element.attr()
перед правилами, которые вы назначаете с помощью element.attr()
, несмотря на временный порядок, в котором они назначаются элементам.
Если вы не сохранили ссылку на элемент, который хотите стилизовать, не беспокойтесь, вы можете легко получить его с помощью CSS-селекторов:
circle = paper.select('circle'); //First circle in paper's DOM tree circle = paper.select('circle.big-circle'); //First circle in paper's DOM tree which has class 'big-circle' circle = paper.select('circle:nth-child(3)'); //Third circle in paper's DOM tree circle = paper.selectAll('circle.big-circle'); //All circles in paper's DOM tree with class 'big-circle'
группы
Элементы SVG могут быть сгруппированы так, чтобы общие преобразования и обработка событий можно было легко применять ко всем элементам в группе. Создать группу легко:
var group = paper.g(circle, rect); var g2 = paper.group(rect, circle, ellipse); //an alias for paper.g
Будьте осторожны: порядок или аргументы имеют значение! Во-вторых, если вы назначите элемент группе, он будет удален из любой группы, к которой он, возможно, уже принадлежит.
Элементы могут, конечно, также добавляться в существующие группы после их создания:
group.add(circle);
Картинки
Snap поддерживает вложение растровых изображений в элементы SVG, их асинхронную загрузку и отображение только после завершения загрузки.
var img = paper.image('bigImage.jpg', x, y, width, height);
Полученный объект можно рассматривать как элемент SVG. Обратите внимание: если вы используете select()
для изображений, чтобы получить их позже, созданная оболочка будет той же, что и для элементов HTML, поэтому большинство методов, доступных для элементов SVG, не будут поддерживаться.
Трансформации
Мы видели, как рисовать асимметричные многоугольники, такие как эллипсы и прямоугольники. Однако базовые методы заставляют нас рисовать эти фигуры выровненными по декартовым осям. Что если мы хотим нарисовать эллипс, оси которого повернуты на 45 ° относительно осей xy? Мы не можем указать это в методах создания, но мы можем использовать преобразования для получения того же результата.
Аналогичным образом нам может понадобиться повернуть изображение или переместить элемент (или группу) в какой-то момент после его создания. Метод transform()
позволяет нам сделать это, передав строку SVG-преобразования:
var ellipse = paper.ellipse(100, 50, 10, 20); ellipse.transform('r45');
Этот метод может принимать либо строку, либо объект в качестве входных данных. Мы также можем использовать матрицу преобразования, связанную с элементом, чтобы применить то же преобразование к другому элементу:
var e1 = paper.ellipse(100, 50, 10, 20), e2 = paper.ellipse(200, 50, 12, 24); e1.transform('r45'); e2.transform(e1.matrix);
Будьте осторожны: центр преобразования для второго элемента все равно будет тем же, который использовался для первого, поэтому конечный эффект может вас удивить.
Метод transform()
также можно использовать для извлечения объекта дескриптора преобразования для элемента, к которому он вызывается — просто вызовите его без аргументов. Этот дескриптор может использоваться для извлечения матрицы локального преобразования и матрицы разностей в случае вложенных элементов:
var g1 = paper.group(), e1 = paper.ellipse(200, 50, 12, 24); g1.add(e1); g1.transform('r30'); e1.transform('t64.6447,-56.066r45,0,0'); console.log(e1.transform());
Вывод
Эта статья представляет собой введение в основы Snap.svg. Если вы заинтересованы в просмотре самых крутых вещей, пожалуйста, следите за обновлениями, так как расширенное продолжение будет опубликовано в ближайшее время.
Если вы хотите узнать больше о визуализации данных и Snap, вот несколько полезных ресурсов: