Когда мне нужно создать карты, то первым делом, я обращаюсь к Google Charts или любой другой специализированной библиотеке. Но иногда мне могут понадобиться специфические особенности, которые я не могу там найти. В этом случае SVG-изображения оказываются очень ценными (полезными).
Недавно, мне нужно было проектировать страницу отчета, которая могла бы показывать карту Италии, на которой каждый регион имел бы свой цвет, в зависимости от некоторых значений выборки из базы данных. Благодаря SVG, эта задача стала очень простой.
Создаем SVG карту в Illustrator
Первым делом я нарисовал карту Италии в Adobe Illustrator:
Каждый регион рисовался как отдельный объект, который помещался на свой отдельный слой, с названием совпадающим с кодом, используемом в базе данных, чтобы определить соотносимые данные (например, «tos» для Тосканы).
Наконец, карта должна быть сохранена в формате SVG. Вам следует обратить внимание на то, чтобы установить опцию «CSS property» в графе «Элементы стиля» в Иллюстраторе, как показано ниже:
Открыв только что созданный файл, вы увидите, что он содержит набор тегов g, идентификаторы которого совпадают с названиями уровней в Illustrator.
Построение нашего HTML файла
Каждый элемент, содержащийся в тегах g имеет класс st0, так чтобы обводки и заливки CSSс войства <strong>stroke</strong> и fill:
Если вы попытаетесь изменить эти значения, карта изменится тоже:
Теперь мы можем использовать этот код, чтобы создать наш HTML файл со встроенным SVG, как показано ниже (код был сокращен для удобства):
<!doctype html> <html> <head> <meta charset="UTF-8"> <title>Map Sample</title> <style type="text/css" media="all"> .map svg { height: auto; width: 350px; } .map g { fill: #ccc; stroke: #333; stroke-width: 1; } </style> </head> <body> <div class="map"> <svg version="1.1" id="Livello_1" xmlns="//www.w3.org/2000/svg" xmlns:xlink="//www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 -21.6 761 919" style="enable-background:new 0 -21.6 761 919;" xml:space="preserve"> <g id="sar"> <polygon class="st0" points="193,463 ... "/> </g> <!-- etc ... --> </svg> </div> </body> </html>
Можно заметить, что атрибут style из тега svg был перенесен в секцию head, и все элементы g изначально залиты светло-серым цветом.
Класс st0 уже не используется (его можно удалить из вашего кода), и он был заменен селектором .map g. В любом случае, это не было обязательным действием – вы можете использовать любые CSS селекторы – на ваше усмотрение.
Вторым шагом надо привязать нашу карту к данным, получаемым из внешнего источника. В данном примере мы будет раскрашивать регионы в цвета, зависящие от населенности этих регионов.
Добавляем JSON-данные и JavaScript
Данные мы получаем в формате JSON, и вставляем их в HTML файл напрямую (в реальных условиях, мы, конечно же, будет получать данные по Ajax, или подобным способом).
Теперь наша страница будет содержать JSON внутри нашего файла с JavaScript, который будет выглядеть примерно так:
var regions=[ { "region_name": "Lombardia", "region_code": "lom", "population": 9794525 }, { "region_name": "Campania", "region_code": "cam", "population": 5769750 }, // etc ... ];
После этого мы выбираем цвет (в данном случае – #0b68aa), и принимаем его за цвет региона с самым большим населением. Остальные регионы будут раскрашены в тона основного цвета в пропорциях процента населенности (по отношению к максимальному населению).
Далее мы добавим немного JavaScript.
Первым делом надо определить регион с самым большим населением. Это можно сделать несколькими строчками кода.
Как только мы составим массив со значениями размера населения, из него можно получить максимальное значение с помощью метода Math.max:
var temp_array= regions.map( function( item ) { return item.population; }); var highest_value = Math.max.apply( Math, temp_array );
Далее можно пройтись по всем элементам regions, и применить уровень прозрачности, в зависимости от вычисленного параметра население / максимальное значение (с небольшой помощью jQuery):
$(function() { for(i=0; i < regions.length; i++) { $('#'+ regions[i].region_code).css({'fill': 'rgba(11, 104, 170,' + regions[i].population/highest_value + ')'}); } });
А вот и результат:
Добавляем интерактивности с помощью CSS и jQuery
Карту можно улучшить, добавив немного интерактивности. Нам бы хотелось показать размер населения при наведении курсора на регион.
Сначала добавим правила CSS для селектора g:hover и класса info_panel, чтобы стилизовать информационный всплывающий блок:
.map g:hover { fill: #fc0 !important; cursor: help; } .info_panel { background-color: rgba(255,255,255, .7); padding: .3em; font-size: .8em; font-family: Helvetica, Arial, sans-serif; position: absolute; } .info_panel::first-line { font-weight: bold; }
Модификатор !important в селекторе .map g:hover нужен для того, чтобы переопределить свойство fill, иначе будет использовано правило встроенного в элемент CSS.
Также нам нужно модифицировать цикл for, определенный ранее, чтобы добавить data-атрибут, в котором будет хранится значение, отображаемое при наведении:
for (i = 0; i < regions.length; i++) { $('#'+ regions[i].region_code) .css({'fill': 'rgba(11, 104, 170,' + regions[i].population/highest_value +')'}).data('region', regions[i]); }
И, наконец, разнообразим наш скрипт добавлением некоторых эффектов при наведении:
$('.map g').mouseover(function (e) { var region_data=$(this).data('region'); $('<div class="info_panel">' + region_data.region_name + '<br>' + 'Population: ' + region_data.population.toLocaleString("en-UK") + '</div>').appendTo('body'); }).mouseleave(function () { $('.info_panel').remove(); }).mousemove(function(e) { var mouseX = e.pageX, // X coordinates of mouse mouseY = e.pageY; // Y coordinates of mouse $('.info_panel').css({ top: mouseY-50, left: mouseX - ($('.info_panel').width() / 2) }); });
Как это работает:
- с помощью mouseover мы добавили элемент div, содержащий отображаемую информацию (имя региона и населенность). Div создается при каждом наведении на элемент g, и добавляется в элемент body документа;
- mouseleave удаляет этот div, когда курсор выходит за пределы региона;
- последний метод, mousemove, получает координаты мыши, и применяет их к сгенерированным div’ам.