Динамические Гео карты с SVG и JQuery

Динамические Гео карты с SVG и JQuery

1645

Многофункциональные географические карты с помощью SVG и jQuery
0

 

Когда мне необходимо создать карты, то первым делом, я обращаюсь к 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="http://www.w3.org/2000/svg" xmlns:xlink="http://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>

123456789101112131415161718192021222324252627282930

<!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=»http://www.w3.org/2000/svg» xmlns:xlink=»http://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, который будет выглядеть примерно так:

JavaScript


var regions=[
{
"region_name": "Lombardia",
"region_code": "lom",
"population": 9794525
},
{
"region_name": "Campania",
"region_code": "cam",
"population": 5769750
},

// etc ...

];

123456789101112131415

var regions=[    {        «region_name»: «Lombardia»,        «region_code»: «lom»,        «population»: 9794525    },    {        «region_name»: «Campania»,        «region_code»: «cam»,        «population»: 5769750    },     // etc … ];

Опосля этого мы выбираем цвет (в данном случае – #0b68aa), и принимаем его за цвет региона с самым огромным населением. Остальные регионы будут раскрашены в тона основного цвета в пропорциях процента населенности (по отношению к наибольшему населению).

Далее мы добавим немного JavaScript.

Первым делом нужно определить регион с самым большим населением. Это можно сделать несколькими строками кода.

Как только мы составим массив со значениями размера населения, из него можно получить наибольшее значение с помощью метода
Math.max
:

JavaScript


var temp_array= regions.map( function( item ) {
return item.population;
});

var highest_value = Math.max.apply( Math, temp_array );

12345

var temp_array= regions.map( function( item ) {    return item.population;}); var highest_value = Math.max.apply( Math, temp_array );

Дальше можно пройтись по всем элементам
regions
, и применить уровень прозрачности, в зависимости от вычисленного параметра население / наибольшее значение (с небольшой помощью jQuery):

JavaScript


$(function() {
for(i=0; i < regions.length; i++) {
$('#'+ regions[i].region_code).css({'fill': 'rgba(11, 104, 170,'
+ regions[i].population/highest_value
+ ')'});
}
});

1234567

$(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
, чтоб стилизовать информационный всплывающий блок:

JavaScript


.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;
}

12345678910111213141516

.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-атрибут, в котором будет хранится значение, отображаемое при наведении:

JavaScript


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]);
}

123456

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]);}

И, в конце концов, разнообразим наш скрипт добавлением некоторых эффектов при наведении:

JavaScript


$('.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)
});
});

12345678910111213141516171819

$(‘.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’ам.
  • Финишный результат с сайта CodePen
  • See the Pen Dynamic Geo Map with SVG and jQuery by SitePoint (@SitePoint) on CodePen.

Перевод статьи

www.webdesignmagazine.ru