Когда мне нужно создать диаграммы, я выбираю Google Charts или другую выделенную библиотеку. Иногда, однако, мне нужны некоторые специфические особенности, которые я не могу найти там. В этих случаях изображения SVG оказываются очень ценными.
Недавно мне пришлось создать страницу отчета, на которой можно было показать карту Италии, в которой каждый регион имел свой цветовой тон в соответствии с некоторыми значениями, полученными из базы данных. Благодаря SVG эта задача была очень простой.
Создание карты SVG в Illustrator
Сначала я нарисовал карту Италии с помощью Illustrator:
Каждый регион рисуется как один объект, и каждый из них имеет свой собственный уровень с именем, совпадающим с кодом, используемым в базе данных для идентификации его относительных данных (например, «tos» для Тосканы).
Наконец карта должна быть сохранена как файл SVG. Необходимо обратить внимание на то, чтобы в «Illustrator» для параметра «Свойство CSS» было установлено значение «Элементы стиля», как показано ниже:
Открыв только что созданный файл, вы увидите, что он содержит набор тегов g
, идентификаторы которых соответствуют названиям уровней Illustrator.
Создание нашего HTML-файла
Каждый элемент, содержащийся в тегах g
имеет класс st0
так что им могут быть назначены свойства CSS stroke
и 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>
Вы можете видеть, что атрибут style
внутри тега svg
был удален и заменен новым атрибутом, расположенным внутри svg
документа; все g
элементов были изначально заполнены светло-серым.
Класс st0
больше не используется (вы можете удалить его из кода SVG) и был заменен селектором .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
чтобы 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
, извлекает координаты мыши и присваивает их сгенерированнымmousemove
.
Вот окончательный результат на CodePen: