Как сделать svg карту
Перейти к содержимому

Как сделать svg карту

  • автор:

Как сделать интерактивную схему на SVG + jQuery

Как сделать интерактивную схему на SVG + jQuery

Задачу можно выполнить на основе векторной графики SVG, с помощью тегов и .

Итак, имеем картинку-подложку:

Над ней нужно абсолютно разместить холст и в нем разместить элементы , каждый магазин это отдельный элемент со своими координатами.

Координаты в теге задаются точками x,y разделенные пробелами.

Атрибут data-id=»1″ потребуется для связки полигона c названием магазина.

.scheme < height: 393px; width: 738px; margin: 0 auto; position: relative; >.scheme svg < position: absolute; top: 0px; left: 0px; height: 393px; width: 738px; >.scheme polygon

В итоге получится следующее:

Как сделать кликабельную карту из файла SVG?

В настоящее время я изучаю Javascript. Я пытаюсь составить кликабельную карту Германии с данными. Такую, как эта.
Amchart предоставляет карту Германии в файле SVG. Но это не похоже на тот пример, что выше. У меня есть некоторые данные по Германии, и я хочу отобразить их в соответствии с регионами, как указано выше. Я знаю, что мне нужно загрузить jquery на html, но не знаю, как это сделать с SVG картой Германии. Свободный перевод вопроса How to make a clickable map from an SVG file? от участника @Doo Hyun Shin.

Отслеживать
Alexandr_TT
задан 27 мар 2020 в 12:07
Alexandr_TT Alexandr_TT
110k 23 23 золотых знака 114 114 серебряных знаков 377 377 бронзовых знаков
ассоциация:stackoverflow.com/q/60852724/7394871
27 мар 2020 в 12:17

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Вы можете легко изменить пример США, который вы цитировали: https://www.amcharts.com/demos/us-heat-map/ для Германии
Самое главное, ссылаться на данные Германии:

Затем измените строку определения карты на:

// Set map definition chart.geodata = window.am4geodata_germanyLow; 

И установите немецкие данные с немецкими государственными идентификаторами (ID). Вы можете изменить данные на то, что вы хотите:

polygonSeries.data = [ < id: "DE-BB", value: 4447100 >, < id: "DE-BE", value: 626932 >, . ] 

Полное демо здесь: codepen

// //console.log(window.am4core); //console.log(window.am4geodata_germanyLow); window.am4core.ready(function () < // Themes begin window.am4core.useTheme(am4themes_animated); // Themes end // Create map instance var chart = window.am4core.create("chartdiv", window.am4maps.MapChart); // Set map definition chart.geodata = window.am4geodata_germanyLow; // Set projection //chart.projection = new window.am4maps.projections.Albers(); // Create map polygon series var polygonSeries = chart.series.push(new window.am4maps.MapPolygonSeries()); //Установите min/max fill color для каждой области polygonSeries.heatRules.push(< property: "fill", target: polygonSeries.mapPolygons.template, min: chart.colors.getIndex(1).brighten(1), max: chart.colors.getIndex(1).brighten(-0.3) >); // Заставить карту загружать данные многоугольника (указать формы и имена) из GeoJSON polygonSeries.useGeodata = true; // Установите значения тепловых карт для каждого состояния polygonSeries.data = [ < id: "DE-BB", value: 4447100 >, < id: "DE-BE", value: 626932 >, < id: "DE-BW", value: 5130632 >, < id: "DE-BY", value: 2673400 >, < id: "DE-HB", value: 33871648 >, < id: "DE-HE", value: 4301261 >, < id: "DE-HH", value: 3405565 >, < id: "DE-MV", value: 783600 >, < id: "DE-NI", value: 15982378 >, < id: "DE-NW", value: 8186453 >, < id: "DE-RP", value: 1211537 >, < id: "DE-SH", value: 1293953 >, < id: "DE-SL", value: 12419293 >, < id: "DE-SN", value: 6080485 >, < id: "DE-ST", value: 2926324 >, < id: "DE-TH", value: 2688418 >]; // Установить легенду тепла let heatLegend = chart.createChild(window.am4maps.HeatLegend); heatLegend.series = polygonSeries; heatLegend.align = "right"; heatLegend.valign = "bottom"; heatLegend.width = window.am4core.percent(20); heatLegend.marginRight = window.am4core.percent(4); heatLegend.minValue = 0; heatLegend.maxValue = 40000000; // Настроить пользовательские метки легенды тепловой карты, используя диапазоны осей var minRange = heatLegend.valueAxis.axisRanges.create(); minRange.value = heatLegend.minValue; minRange.label.text = "Little"; var maxRange = heatLegend.valueAxis.axisRanges.create(); maxRange.value = heatLegend.maxValue; maxRange.label.text = "A lot!"; // Вычеркнуть внутренние метки осей значений labels heatLegend.valueAxis.renderer.labels.template.adapter.add("text", function ( labelText ) < return ""; >); // Настроить всплывающую подсказку var polygonTemplate = polygonSeries.mapPolygons.template; polygonTemplate.tooltipText = ": "; polygonTemplate.nonScalingStroke = true; polygonTemplate.strokeWidth = 0.5; // Создать состояние наведения и установить альтернативный цвет заливки var hs = polygonTemplate.states.create("hover"); hs.properties.fill = window.am4core.color("#3c5bdc"); >); // end am4core.ready()

HTML и SVG: создаём интерактивную карту

Давайте создадим интерактивную карту. Чего-нибудь. Что значит интерактивную? Ну, она должна взаимодействовать с пользователем и с данными на веб-странице, на которой она расположена. Думаю, этого достаточно, чтобы считать её интерактивной.

Что же, и возьмём мы SVG. Почему? Да потому что с ним легко работать человеку, знакомому с HTML. SVG — это векторный формат, основанный на XML. То есть у SVG-рисунка есть своя DOM, к различным элементам можно применять CSS-правила и управлять старым добрым JavaScript’ом.

Что же, начнём?

Самые нетерпеливые, могут сразу посмотреть демо, но я предлагаю читать обо всём по порядку.

Готовим карту

Для начала нам нужна суть. То бишь сама карта. В случае, если гугл не помогает, то её можно нарисовать и самому, даром что в Inkscape это сделать не трудно.

Я же, к примеру, возьму карту одной круглой страны (исходник на Wikimedia Commons)

Поскольку, по моему замыслу, у областей карты не должно быть различного окраса, то вначале я вырезаю из интересующих меня тегов стили fill и stroke, зато взамен даю этим элементам нужные мне class и id. Например, для регионов и для городов.

Далее, в секции изображения помещаем до боли знакомое:

 .area < stroke: black; stroke-width: 2px; fill: #E9FFE9; >.city 

Вот и обещанный мною CSS в действии. В принципе, этого уже достаточно. Diff.

Результат:

Вставляем SVG в HTML

Достаточно подробно этот процесс был освещён в хабратопике К вопросу о кроссбраузерном использовании SVG.

Мы же будем использовать HTML5 и воспользуемся самым простым, гуманным и стандартным способом:

Все браузеры, поддерживающие SVG, его корректно «скушают» и покажут. И даже дадут нам с ним поработать. При одном условии: если веб-сервер отдаст его с MIME-типом image/svg+xml. Другой MIME-тип может очень смутить Google Chrome (но не Оперу, которая из тега твёрдо знает, что идёт за SVG и на провокации не поддаётся).

Второй правильный метод — вставка SVG-кода прямо в HTML. Великолепно с точки зрения скриптинга, но поддержка браузерами пока похуже. Кстати, заметьте, что SVG, вставленный в «либеральный» HTML, всё-таки остаётся «суровым» XML’ем. Так что кавычки и закрывающие теги обязательны.

Подводные грабли

Но не всё так просто. Сразу можно заметить, что браузеры упорно не хотят масштабировать нашу карту, а если она не влезает, то показывают полосы прокрутки, вот так:

Чтобы заставить браузеры работать с SVG так, как мы ожидаем, следует убрать в SVG-файле из тега атрибуты width и height (или задать им значения в 100%), а вставить специально предназначенный для браузеров атрибут viewBox со значениями координат левого верхнего и правого нижнего углов изображения:

viewBox="0 0 493 416"

После этого ситуация значительно улучшается, но другую граблю нам подкладывает Google Chrome: он упорно стремится смасштабировать картинку по высоте до высоты элемента , а не увеличить высоту согласно ширине тега и пропорциям изображения, как ведут себя остальные браузеры.

Жаль. Придётся привлечь JavaScript и подогнать высоту элемента вручную.

var viewBox = svgdom.rootElement.getAttribute("viewBox").split(" "); var aspectRatio = viewBox[2] / viewBox[3]; svgobject.height = parseInt(svgobject.offsetWidth / aspectRatio);

Результат:

Взаимодействуем с SVG

Чтобы нам взаимодействовать с SVG, вписаннным прямо в HTML, ничего не нужно — он уже часть DOM веб-страницы.

Получить доступ к SVG, вставленным через чуть сложнее:

jQuery(window).load(function () < // Нам нужно дождаться, пока вся графика (и наша карта тоже) загрузится, поэтому используем window.onload, var svgobject = document.getElementById('svgmap'); // Находим тег if ('contentDocument' in svgobject) < // У нас действительно там что-то есть? var svgdom = jQuery(svgobject.contentDocument); // Получаем доступ к объектной модели SVG-файла // Теперь делаем свою работу, например: jQuery("#figure1", svgdom).attr("fill", "red"); // Находим тег с в SVG DOM и заливаем его красным >>);

Да, jQuery работает с SVG, но только частично. Например, я заметил, что не работают функции addClass и removeClass, а так же поиск по классам ( jQuery(«.class») ). Приходится извращаться.

Заметьте, что я использую событие window.onload, так как нам необходимо дождаться полной загрузки страницы, вместе со всеми связанными элементами (в числе которых и наша карта). Однако и тут Google Chrome спешит подложить нам свинью: в том случае, если скрипт с window.onload находится в html-коде до тега , то код в обработчике выполняется ДО того, как карта на самом деле загрузится. Поэтому тег необходимо разместить после нашей карты. Sad but true.

Интерактивность первая: выделяем районы на карте щелчком по чекбоксу на странице.

Для этого взаимодействия нам понадобятся чекбоксы в каждой строке таблицы с районами, а так же совпадающие или схожие id у строк таблицы и районов на карте.

Здесь мы будем при щелчке по флажку ставить или убирать класс selected у соответствующей области на карте, а так уже у самой строки. Это несложно:

$("#areas input[type=checkbox]").change(function() < var row = $(this).parent().parent(); var if (this.checked) < row.addClass("selected"); $("#"+id, svgdom).myAddClass("selected"); >else < row.removeClass("selected"); $("#"+id, svgdom).myRemoveClass("selected"); >>);

Соответственно, нужно добавить и стилевые определения для данного класса. Предоставляю вам это сделать самостоятельно, согласно своих вкусов и предпочтений. Diff.

Интерактивность вторая: вскрываем/показываем названия на карте щелчком по чекбоксу на странице.

Это взаимодействие делается ещё проще. Вставляем на страницу и немножко яваскрипта, который добавляет/удаляет всем связанным с названиями элементам на карте класс hidden :

$("#titleswitch").change(function () < var elements = $(svgdom.getElementsByClassName("areatitle")) .add($(svgdom.getElementsByClassName("citytitle"))) .add($(svgdom.getElementsByClassName("titlebox"))) .add($(svgdom.getElementsByClassName("titleline"))); if (this.checked) < elements.myAddClass("hidden"); >else < elements.myRemoveClass("hidden"); >>);

Вот так.

Интерактивность третья: подсвечиваем районы на карте при наведении на строку таблицы (и наоборот)

Для этого необходимо повешать обработчики события onhover как на таблицу:

// Подсвечиваем регион на карте при наведении мыши на соотв. строку таблицы. $("#areas tr").hover( function () < var $("#"+id, svgdom).myAddClass("highlight"); >, function () < var $("#"+id, svgdom).myRemoveClass("highlight"); >); 

…так и на районы на карте:

// Подсвечиваем строку в таблице при наведении мыши на соотв. регион на карте $(svgdom.getElementsByClassName("area")).hover( function () < var $("#areas #"+id).addClass("highlight"); >, function () < var $("#areas #"+id).removeClass("highlight"); >);

Для того, чтобы мы это видели, добавим соответствующие CSS-правила в страницу:

tr.highlight, tr:hover, tr:nth-child(even):hover

…и в SVG-карту:

.highlight, .area:hover

При наведении мышкой на строку таблицы (или на район на карте) на соответствующий район на карте (на строку таблицы) вешается нужный для подсвечивания класс. Чтобы приведённый выше код работал, необходимо, чтобы у районов на карте и строк таблицы были совпадающие (или схожие) id. Diff.

Интерактивность четвёртая: Отображаем данные со страницы на карте

Ну что же, банальное присваивание классов, наверное, уже наскучило. Пускай карта нам показывает на себе какие-нибудь данные.

Перво-наперво: данные. Добавим к нашей табличке пару столбцов, например «Люди» и «Деньги». Внимание: Данные взяты от балды и никакого отношения к реальному Аместрису не имеют. А так же радиокнопки, по которым будем переключать, какие данные показывать.

Во-вторых, нам нужно место на карте, где будут отображаться данные. Добавим на карту пять блоков (по одному на каждый регион, соотнеся их id с регионами) и соответствующие стили в :

Ну и JavaScript-код, который будет брать данные из ячеек таблицы и помещать в блоки текста:

$("input[name=tabledata]").change(function () < var descnum = $(this).parent().prevAll().length+1; $("#areas tbody tr").each(function() < var var value = $(this).children(":nth-child("+descnum+")").text(); $("#text"+id, svgdom).text(value); >); >);

И по переключению радиокнопок карта будет показывать нужные цифры. Вуаля!

Интерактивность пятая: всплывающие подсказки

Возможно, это уже и лишнее, но пусть будет. Для ровного счёта.

Для данного взаимодействия возьмём плагин jQuery.tooltip и привяжем его к областям на карте. Текст для подсказок будем брать, конечно же, из таблицы:

$(svgdom.getElementsByClassName("area")).tooltip(< bodyHandler: function() < var var area = $("#areas #"+id+" td:nth-child(2)").text(); var result = $("

").append($("").text(area)); $("#areas #"+id+" td:nth-child(2)").nextAll().each(function()< var pos = $(this).prevAll().length+1; var title = $("#areas thead th:nth-child("+pos+")").text(); var value = $(this).text(); result.append($("

").text(title + ": " + value)); >); return result; > >);

Diff.

И так далее…

Разумеется, этим возможности взаимодействия с SVG не ограничиваются. Вы можете делать всё. Перетасовывать DOM, менять страницу и SVG по AJAX-запросам и многое, многое другое. Дерзайте.

Результат

Оставшиеся подводные камни

Из известных проблем пока что можно отметить, что Google Chrome не выводит на печать SVG-картинки. Это или его баг или баг WebKit в целом.

Обратная совместимость

Почти все современные браузеры поддерживают SVG: IE 9+, Opera 8+, Firefox 3+ (в Firefox 1.5+ частичная поддержка), Chrome всех версий, Safari 3.2+ (более полный список)

Но увы и ах, светлое будущее целиком всё никак не наступит и задумываться о поддержке старых браузеров всё же приходится.

Стандартный и самый простой путь, если SVG — это просто картинка: вставляем замещающее содержимое (отрендеренную в PNG картинку и абзац текста) внутрь тега .

  Неинтерактивная карта

К сожалению, вы используете устаревшую версию браузера, который не поддерживает интерактивную карту.

Если в браузере поддержки SVG нет, будет показана PNG-картинка и текст, уведомляющий пользователей, что их браузер устарел. Никакого интерактива. Впрочем, он, может быть, не очень-то и нужен. Правда, есть один минус — как я заметил, современные браузеры упорно скачивают себе замещающую png-картинку, несмотря на то, что они её всё равно не отобразят.

Желающие могут воспользоваться детектированием поддержки SVG с помощью Modernizr и наворотить на яваскрипте что-нибудь посложнее.

В более сложных случаях вам могут помочь многочисленные решения на Flash, VML или Canvas (или на всех вместе). Список можно посмотреть здесь: HTML5 Crossbrowser Polyfills, но те решения, которые я опробовал, мне, к сожалению, не помогли. Возможно потому, что тот SVG c CSS’ом, что я набросал на коленке — оказался им не по зубам.

Конвертирование SVG в PNG

В сети есть много мест, где можно конвертнуть SVG-картинку во что-нибудь другое. Я же предложу воспользоваться командой rsvg-convert из пакета librsvg2-bin. Примерно вот так:

cat map.svg | rsvg-convert > map.png

Впрочем, она может преобразовывать и в другие форматы, а так же увеличивать/уменьшать картинку, смотрите —help.
Для массовых преобразований можно сочинить команду посложнее или посмотреть примеры в форумной ветке, где я эту команду и нашёл.

Вместо заключения

Ну вот и всё. При ближайшем рассмотрении это не так уж и сложно, а главное — всё близко и знакомо веб-разработчику. Смотрите, о чём я написал выше в виде демо-страницы, раздирайте исходный код из репозитория, если есть предложения и улучшения — высказывайте в комментариях или присылайте в репозиторий в виде пулл реквестов. Приятной вам работы с современными веб-технологиями!

  • Веб-разработка
  • JavaScript

Как сделать интерактивную SVG-диаграмму

Сейчас все активно обсуждают радости и гадости удалённой работы, и мы даже выпустили статью на эту тему. А ещё провели небольшой опрос и попросили наших пользователей рассказать, с какими трудностями они сталкиваются во время работы дома (спойлер — все ленятся). Статистику нужно как-то красиво оформить, так почему бы не сделать SVG-график? Заодно научимся чему-нибудь новому. Поехали!

Давайте немного поговорим о том, что такое SVG. Это формат векторной графики, который позволяет растягивать и сжимать изображения без потери качества, очень удобно. Такая возможность реализована за счёт крутой особенности SVG — фактически это обычный код. Каждое изображение описано опорными точками, кривыми и простыми фигурами, которые представляют из себя строки кода, их можно изменять в обычном редакторе. И, конечно, SVG-элементы можно создавать с нуля самим.

Именно этим и займёмся — создадим SVG-диаграмму и легенду к ней, а затем стилизуем всё с помощью CSS и в самом конце добавим немного JavaScript-магии. Вам понадобятся базовые знания HTML, CSS и JavaScript. Если их пока нет — самое время пройти бесплатные тренажёры, а после этого вернуться к туториалу.

Создаём диаграмму

1. Подготовка

Начнём с родительского блока. График и легенда будут лежать внутри элемента .canvas , который мы сделаем флекс-контейнером, чтобы выровнять дочерние элементы внутри него.

.canvas

2. Добавляем SVG

Есть разные методы вставки SVG-элементов, самый подходящий для наших целей — вставить код элемента непосредственно в HTML, то есть заинлайнить. Это способ позволяет изменять свойства SVG-элементов и фигур прямо из CSS. Добавим разметку диаграммы:

Мы использовали тег svg — специальный тег для создания SVG-элемента, задали элементу размеры с помощью width и height , а ещё добавили атрибут viewBox . Для чего он нужен? Вообще содержимое SVG-элемента отрисовывается на бесконечном холсте, и изменение размеров элемента не влияет на его содержимое. С помощью viewBox как раз можно задать область отрисовки, которая будет растягиваться и сжиматься в зависимости от размеров. В нашем случае первые два нуля в значении — это координаты верхнего левого угла области (начало отсчёта системы координат), а следующие два числа — ширина и высота соответственно.

Внутри SVG-элемента мы нарисовали несколько одинаковых окружностей, задав радиус и центр окружности с помощью тега circle и его атрибутов, где: r — радиус окружности, cx — координата центра окружности по горизонтальной оси, а cy — по вертикальной. По умолчанию центр окружности расположен в начале координат — левом верхнем углу, поэтому мы задаём значение 50% , чтобы окружность находилась по центру.

Количество окружностей равно количеству секций в диаграмме. У нас их будет семь.

3. Создаём секции

На прошлом шаге мы получили обычные окружности, но хотелось бы превратить их в диаграмму в виде пончика, то есть нужно как-то вырезать середину. Мы реализуем это с помощью добавления обводки окружности. Оставим только её и уберём заливку самой фигуры — fill .

.unit < fill: none; stroke-width: 10; >.unit:nth-child(1) < stroke: #86cfa3; >.unit:nth-child(2) < stroke: #a2c6e0; >.unit:nth-child(3) < stroke: #ffc7ec; >/* Далее ещё четыре секции по аналогии */ 

Свойство stroke-width задаёт толщину обводки — она у всех секций одинаковая. А цвет разный, поэтому свойство stroke , которое за него отвечает, мы прописали отдельно для каждой окружности. Кстати, мы не указываем единицы измерения у свойств обводки, потому что по умолчанию это пиксели, и нам нужны именно они.

На данном этапе каждая секция занимает всю окружность, нам нужно изменить это поведение. Для этого используем свойство stroke-dasharray . Оно предназначено для создания пунктирных обводок и в качестве значения принимает длину отрезков и пробелов между ними. В нашем случае мы используем свойство не совсем традиционным способом: отрезок будет только один — сама секция, а вся остальная окружность — это пробел.

Ещё учтём, что по умолчанию все секции будут начинаться из одной точки, а нам нужно расположить их одну за другой по кругу. Чтобы добиться нужного поведения, используем свойство stroke-dashoffset — оно позволит сдвинуть обводку на нужное нам расстояние.

.unit:nth-child(1) < stroke: #86cfa3; stroke-dasharray: 8 100; >.unit:nth-child(2) < stroke: #a2c6e0; stroke-dasharray: 11 100; stroke-dashoffset: -8; >.unit:nth-child(3) < stroke: #ffc7ec; stroke-dasharray: 11 100; stroke-dashoffset: -19; >/* Далее ещё четыре секции по аналогии */ 

Давайте подробнее остановимся на значении свойства stroke-dashoffset . У первой секции этого свойства нет, потому что её не нужно никуда сдвигать, а у остальных сдвиг равен длине всех предшествующих секций. То есть у второго элемента сдвиг равен длине первой секции, у третьего — длине первой и второй секции и так далее. Значение отрицательное, потому что сдвигаем по часовой стрелке, а по умолчанию сдвиг идёт против.

4. Немного математики

Можно пропустить, если вы не любите математику.

Возможно, вы заметили, что на втором шаге мы задали окружностям довольно странный радиус — 15.9 , и теперь пришло время рассказать, почему значение именно такое.

В графиках используются данные в процентах, то есть каждая секция диаграммы иллюстрирует какой-то процент от общего количества. В нашем случае длина секции, которая была прописана первым значением у свойства stroke-dasharray , должна отражать этот процент, то есть 100% соответствует длине всей окружности, а n% — длине секции. В таком случае, чтобы найти длину окружности, нам нужно вспомнить школьную формулу C = 2πr. Вот здесь мы схитрим и изначально договоримся, что длина окружности будет равна 100px , и тогда путём нехитрых вычислений выведем из формулы радиус, равный примерно 15.9px . Вот откуда появилось значение.

Для чего это было нужно? Допустим, нас попросили построить диаграмму по некоторым статистическим данным: 1% котов рыжие (и любят командовать), а 99% котов — других цветов. Благодаря тому, что мы приравняли длину всей окружности к 100 , длина секций будет равна проценту из статистики — 1 и 99 соответственно. Это очень удобно. Если бы мы пошли альтернативным путём и не стали отталкиваться от длины окружности, то для каждого процента приходилось бы вычислять длину секции из пропорции, и она была бы дробным числом с кучей знаков после запятой.

Здесь стоит отметить, что нам помогает провернуть этот хак атрибут viewBox , который был задан в самом начале SVG-элементу. Масштабируя область видимости, мы может управлять размером диаграммы. При этом радиус окружности изменять не будем — мы зафиксировали его значение по причинам, изложенным выше.

Вот откуда взялась длина секции в свойстве stroke-dasharray — это процент, который занимает каждая секция диаграммы согласно данным статистики.

5. Легенда

Диаграмма готова, а теперь давайте добавим к ней легенду с описанием секций. Мы не будем изобретать ничего сложного, поэтому пробежимся по основным этапам вскользь:

    Добавляем разметку легенды внутрь элемента .canvas :

.legend < max-width: 250px; margin-left: 30px; >.title < font-family: "Verdana", sans-serif; font-size: 18px; line-height: 21px; color: #591d48; >.caption-list < margin: 0; padding: 0; list-style: none; >.caption-item < position: relative; margin: 20px 0; padding-left: 30px; font-family: "Verdana", sans-serif; font-size: 16px; line-height: 18px; color: #591d48; cursor: pointer; >.caption-item:hover
.caption-item::before < content: "; position: absolute; top: 0; left: 0; width: 20px; height: 20px; border-radius: 8px; >.caption-item:nth-child(1)::before < background-color: #86cfa3; >.caption-item:nth-child(2)::before < background-color: #a2c6e0; >.caption-item:nth-child(3)::before < background-color: #ffc7ec; >/* Далее ещё четыре секции по аналогии */ 

Добавляем немного интерактивности

Всё хорошо, но не помешало бы сделать диаграмму более живой. Давайте добавим небольшую анимацию во время отрисовки и эффекты при наведении.

1. Анимация

В предыдущем туториале мы уже разбирали, как сделать простую анимацию. Если вы никогда не делали анимации на CSS, будет полезно для начала прочитать его.

Давайте добавим анимацию во время отрисовки секций диаграммы. Для этого будем постепенно изменять свойство stroke-dasharray , начиная с нуля и заканчивая теми значениями, которые мы указали ранее — для каждой секции оно своё. То есть длина секции будет постепенно возрастать от нуля до нужного значения.

Для создания анимации используем ключевое слово @keyframes , зададим название анимации и укажем состояние в начальной точке — 0% :

@keyframes render < 0% < stroke-dasharray: 0 100; >> 

Мы намеренно не указали состояние в конечной точки анимации — 100% , так как у каждой секции своя длина. В данном случае после выполнения анимации свойство stroke-dasharray примет то значение, которое мы уже прописали ранее для каждой секции. Так работает анимация — по окончании элемент возвращается в исходное состояние.

Теперь добавим к уже имеющимся свойствам элемента .unit новые — animation-name и animation-duration . Они позволят задать название и продолжительность анимации и применить её к секциям диаграммы.

.unit < /* Здесь должны быть свойства, заданные ранее */ animation-name: render; animation-duration: 1.5s; >

Всё работает — секции постепенно появляются в течение заданного времени.

2. Эффект при наведении

Добавим плавное увеличение секции при наведении на неё. Используем псевдокласс hover , чтобы увеличить толщину обводки наших окружностей-секций и добавить им полупрозрачность.

.unit:hover

Сейчас переход между состояниями происходит резко, но это поведение можно изменить с помощью плавных переходов. Укажем свойства, которые нужно изменять плавно (в нашем случае все), и длительность перехода — за это отвечают transition-property и transition-duration .

.unit < /* Здесь должны быть свойства, заданные ранее */ transition-property: all; transition-duration: 1.5s; >

Теперь переход между состояниями происходит плавно.

3. Немного JavaScript

Всё почти готово, но хочется ещё создать связь между легендой и диаграммой. В этом нам поможет JavaScript. Если вы пока с ним не знакомы, то познакомьтесь. Оно того стоит, правда.

Мы напишем небольшой скрипт, который позволит выделять нужную секцию при наведении на её название в легенде. Эффекты будем использовать точно такие же, как при наведении на саму секцию. Мы уже прописали их для .unit:hover , поэтому теперь просто продублируем для специального класса hovered , который далее будем использовать в JavaScript-коде.

.hovered

Вот шаги, которые должны быть реализованы в скрипте:

  1. Найти все названия секций в легенде.
  2. Найти все секции диаграммы.
  3. Добавить каждому названию секции отслеживание событий наведения и снятия курсора.
  4. Внутри обработчиков этих событий добавлять или удалять класс hovered у секций диаграммы в зависимости от положения курсора.
let captionsList = document.querySelectorAll('.caption-item'); let unitsList = document.querySelectorAll('.unit'); captionsList.forEach(function (item, index) < item.addEventListener('mouseover', function () < unitsList[index].classList.add('hovered'); >); item.addEventListener('mouseout', function () < unitsList[index].classList.remove('hovered'); >); >); 

Здесь мы отслеживаем движение мыши с помощью событий mouseover (курсор над элементом) и mouseout (курсор уходит с элемента). А для поиска нужной секции используем совпадение порядковых номеров названий в легенде и секций диаграммы — index названия = index секции. Нужно учесть, что их всегда должно быть равное количество.

Вот теперь диаграмма готова! Весь код, который мы написали в туториале, доступен на CodePen.

See the Pen svg pie chart by sasha_htmlacademy (@sasha-sm)on CodePen.

Полезности

  • Подборка графиков на CodePen. Всех видов и разного уровня сложности.
  • Как правильно вставлять SVG. В туториале мы инлайнили SVG, но в других ситуациях — другие способы.
  • Размеры в SVG. В этой статье можно подробнее почитать о том, как работает viewBox , но не только.
  • Движение мыши: mouseover/out. Подробнее о работе этих событий.
  • Курс «Основы SVG». Обо всём, что касается создания и оформления SVG-фигур.
  • Курс «Динамические эффекты». Здесь можно изучить плавные переходы и анимацию, которые мы только поверхностно затронули в туториале.
  • Курс «Мастер анимаций: CSS и JS-анимации». Научитесь анимировать карточки товаров, модальные окна и другие элементы сайта.

«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *