Динамическая геокарта с SVG и JQuery

Когда мне нужно создавать диаграммы, моим первым выбором является — диаграммы Google или другая специализированная библиотека. Но иногда мне нужно некоторые особенности или специальные возможности, которые я не могу найти в таких библиотеках. В этих случаях, SVG изображения становятся очень полезными.

В этой статье мы создадим динамическую геокарту Италии используя SVG изображение.

Создание SVG карты в Illustrator

Во-первых, нарисуем карту Италии с Illustrator:

Создание SVG карты в Illustrator
image-103

Каждый регион это единый объект, и каждый из них имеет свое имя совпадающим с кодом используемый в базе данных, чтобы определить свои данные (например: «tos» для Тоскане).

Карта должна сохранена в виде файла SVG. При сохранении вы должны установить опцию «CSS Properties» — «Style Elements» , как показано ниже:

сохранение файла SVG
image-104

При открытии файла который вы только что создали, вы увидите, что он содержит набор g тегов, идентификаторы совпадающие с именами слоев в Illustrator.

Создание HTML-файла

Каждый элемент g тега имеет polygon с классом st0 и через CSS свойства stroke и fill можно изменять их вид:

polygon с координатами
image-105

Если вы измените эти значения, карта будет сразу меняться:

заливка и обводка карты
image-106

Теперь мы можем использовать этот код, чтобы создать наш 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>

Здесь атрибут 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), и мы назначить его в регион с наибольшим населением. Другие регионы будут окрашены с этим же цветом но с тоном в соответствии с их населением в отношении от максимального значения.

Прежде всего, мы должны определить регион с максимальным значением населения. Это может быть сделано с помощью нескольких строк кода.

После того, как временный массив, содержащий значения населения построен, мы можем использовать метод 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
     + ')'});
    }
});

Получим следующий результат:

140687857705_browser
image-107

Добавление интерактивности с помощью 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, в противном случае значение не изменится.

Затем мы должны изменить наш предыдущий цикл 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)
    });
});
    Как это работает:

  • Во-первых, с наведении курсора мыши, мы создаем div, содержащий информацию для отображения (регион и население). Он строится каждый раз при наведении курсора мыши на g элемент и добавляется к нашей странице;
  • mouseleave удаляет это div, когда курсор выходит из предел своего региона;
  • Последний метод, mousemove, извлекает координаты мыши и назначает их генерируемому div.

Вот конечный результат на CodePen:


See the Pen sKagI by roma (@romasport) on CodePen.7661