Функциональные географические карты с помощью SVG и jQuery. Руководство по созданию SVG карт на основе данных сервиса Natural Earth


Хочу иметь возможность самому рисовать через SVG на карте.

Идея такая: создаю слой по размерам на ВСЮ карту текущего масштаба и потом отрисовываю уже на этом слое, преобразовывая geo-точки в пиксельные.

Как это сделать самым простым способом? Чере IOverlay или ILayer, или может ещё что-то есть более удобное?

","contentType":"text/html"},"proposedBody":{"source":"

Хочу иметь возможность самому рисовать через SVG на карте.

Идея такая: создаю слой по размерам на ВСЮ карту текущего масштаба и потом отрисовываю уже на этом слое, преобразовывая geo-точки в пиксельные.

Как это сделать самым простым способом? Чере IOverlay или ILayer, или может ещё что-то есть более удобное?

Хочу иметь возможность самому рисовать через SVG на карте.

Идея такая: создаю слой по размерам на ВСЮ карту текущего масштаба и потом отрисовываю уже на этом слое, преобразовывая geo-точки в пиксельные.

Как это сделать самым простым способом? Чере IOverlay или ILayer, или может ещё что-то есть более удобное?

","contentType":"text/html"},"authorId":"20653410","slug":"6812","canEdit":false,"canComment":false,"isBanned":false,"canPublish":false,"viewType":"old","isDraft":false,"isOnModeration":false,"isSubscriber":false,"commentsCount":9,"modificationDate":"Thu Jan 01 1970 03:00:00 GMT+0000 (UTC)","showPreview":true,"approvedPreview":{"source":"

Хочу иметь возможность самому рисовать через SVG на карте.

Идея такая: создаю слой по размерам на ВСЮ карту текущего масштаба и потом отрисовываю уже на этом слое, преобразовывая geo-точки в пиксельные.

Как это сделать самым простым способом? Чере IOverlay или ILayer, или может ещё что-то есть более удобное?

","html":"Хочу иметь возможность самому рисовать через SVG на карте. ","contentType":"text/html"},"proposedPreview":{"source":"

Хочу иметь возможность самому рисовать через SVG на карте.

Идея такая: создаю слой по размерам на ВСЮ карту текущего масштаба и потом отрисовываю уже на этом слое, преобразовывая geo-точки в пиксельные.

Как это сделать самым простым способом? Чере IOverlay или ILayer, или может ещё что-то есть более удобное?

","html":"Хочу иметь возможность самому рисовать через SVG на карте. ","contentType":"text/html"},"titleImage":null,"tags":[{"displayName":"API 1.x","slug":"api-1-x","categoryId":"150000131","url":"/blog/mapsapi??tag=api-1-x"}],"isModerator":false,"commentsEnabled":true,"url":"/blog/mapsapi/6812","urlTemplate":"/blog/mapsapi/%slug%","fullBlogUrl":"https://yandex.ru/blog/mapsapi","addCommentUrl":"/blog/createComment/mapsapi/6812","updateCommentUrl":"/blog/updateComment/mapsapi/6812","addCommentWithCaptcha":"/blog/createWithCaptcha/mapsapi/6812","changeCaptchaUrl":"/blog/api/captcha/new","putImageUrl":"/blog/image/put","urlBlog":"/blog/mapsapi","urlEditPost":"/blog/56a9a2b3b15b79e31e0d72f2/edit","urlSlug":"/blog/post/generateSlug","urlPublishPost":"/blog/56a9a2b3b15b79e31e0d72f2/publish","urlUnpublishPost":"/blog/56a9a2b3b15b79e31e0d72f2/unpublish","urlRemovePost":"/blog/56a9a2b3b15b79e31e0d72f2/removePost","urlDraft":"/blog/mapsapi/6812/draft","urlDraftTemplate":"/blog/mapsapi/%slug%/draft","urlRemoveDraft":"/blog/56a9a2b3b15b79e31e0d72f2/removeDraft","urlTagSuggest":"/blog/api/suggest/mapsapi","urlAfterDelete":"/blog/mapsapi","isAuthor":false,"subscribeUrl":"/blog/api/subscribe/56a9a2b3b15b79e31e0d72f2","unsubscribeUrl":"/blog/api/unsubscribe/56a9a2b3b15b79e31e0d72f2","urlEditPostPage":"/blog/mapsapi/56a9a2b3b15b79e31e0d72f2/edit","urlForTranslate":"/blog/post/translate","urlRelateIssue":"/blog/post/updateIssue","urlUpdateTranslate":"/blog/post/updateTranslate","urlLoadTranslate":"/blog/post/loadTranslate","urlTranslationStatus":"/blog/mapsapi/6812/translationInfo","urlRelatedArticles":"/blog/api/relatedArticles/mapsapi/6812","author":{"id":"20653410","uid":{"value":"20653410","lite":false,"hosted":false},"aliases":{},"login":"shasoft","display_name":{"name":"shasoft","avatar":{"default":"21493/20653410-939638","empty":false}},"address":"[email protected]","defaultAvatar":"21493/20653410-939638","imageSrc":"https://avatars.mds.yandex.net/get-yapic/21493/20653410-939638/islands-middle","isYandexStaff":false},"originalModificationDate":"1970-01-01T00:00:00.000Z","socialImage":{"orig":{"fullPath":"https://avatars.mds.yandex.net/get-yablogs/47421/file_1456488726678/orig"}}}}}">

Интерактивные карты - это отличный способ предоставить географические данные пользователям вашего сайта. Одним из популярных вариантов реализации подобного являются такие сервисы, как Google Maps и Open Street Maps, которые преуспели в визуализации данных до уровня улиц. Тем не менее, для мелкомасштабных карт наиболее подходящим вариантом являются карты в формате SVG . Они легки, полностью настраиваемы и не обременены никакими ограничениями лицензирования.

Можно найти ряд SVG карт, выпущенных в рамках разрешительных лицензий в Википедии. К сожалению, того, что вы в конечном итоге найдете, может вам не хватить. Необходимая вам карта может не существовать, может быть устаревшей (например, из-за изменения границ) или может быть недостаточно хорошо отформатирована для использования на вашем сайте. Данная статья объяснит, как создавать ваши собственные SVG карты, используя данные сервиса Natural Earth и open-source инструменты. После чего вы сможете создавать SVG карты для любого региона мира, используя любую проекцию и любое разрешение. В качестве примера мы создадим SVG карту мира.

Нам будет необходимо выполнить следующее:

  • скачать географические данные с Natural Earth data;
  • просмотреть и отредактировать данные, используя QGIS;
  • конвертировать географические данные в SVG, используя Kartograph.py.
Получение географических данных

Для начала, нам необходимы географические данные о границах стран. Эти данные доступны на Natural Earth . Natural Earth создан добровольцами при поддержке Северо-Американского картографического информационного общества (NACIS, North American Cartographic Information Society). Данный сервис специализируется на мелкомасштабных картах, которые хорошо подходят для интернета. Это означает, что карты будут отлично смотреться на уровне стран и провинций, но с недостаточно большим разрешением, чтобы показать окрестности города. Natural Earth выпускает свои карты в общественное достояние.

Чтобы посмотреть все карты, доступные для скачивания, посетите страницу загрузок Natural Earth .

Многие границы в мире горячо оспариваются. Политика Natural Earth заключается в рисовании границ в зависимости от того, кто контролирует ситуацию на местах. Мы в первую очередь будем работать с мелкомасштабной политической картой, которая содержит все 247 стран мира, и из которой удалены границы, которые проходят через озера. Вы можете скачать её в zip архиве (186 Кб) .

Данные, которые вы скачали, сохранены в формате shape-файла (.shp). Shape-файл - это открытый стандарт векторного формата геопространственных данных, созданный Esri. Shape-файл сопровождается дополнительными файлами с расширениями.dbf , .prj и.shx . Вместе эти файлы содержат векторную геометрию, атрибуты (имя, id и т.д.) и геопространственные данные для каждой страны. Для простоты, когда люди ссылаются на shape-файл, они на самом деле имеют в виду эту группу файлов.

Просмотр географических данных

Чтобы увидеть данные, которые мы только что скачали, нам необходимо воспользоваться программным обеспечением GIS (геоинформационных систем). QGIS - это открытое GIS ПО, работающее под Linux, Mac OS X и Windows. Скачать ПО с QGIS . Данное руководство будет использовать QGIS 2.8.2 Wien.

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

Для начала, мы добавим наш shape-файл в наш проект как векторный слой:

  • выберите Слой (Layer) → Добавить слой (Add Layer) → Добавить векторный слой (Add Vector Layer) ;
  • выберите и откройте файл ne_110m_admin_0_countries_lakes.shp ;
  • карта должна появиться в окне (цвет может отличаться от вашего).
Векторный слой карты мира

Обратите внимание, что ne_110m_admin_0_countries_lakes.shp был добавлен в диалоговое окно Слои .

Новый слой

Слои в QGIS похожи на слои, которые вы можете обнаружить в таких графических редакторах, как Photoshop или GIMP. Вы должны выбрать слой перед тем, как сможете работать на нём. Если на протяжении данного руководства вы обнаружите, то программа работает неправильно, вы вероятно забыли выбрать текущий слой.

Также возможно скрыть слои, сняв флажок. Это позволяет добавить несколько shape-файлов в ваш проект и просматривать их по отдельности.

После добавления векторного слоя было бы неплохо сохранить вашу работу: Проекты (Project) → Сохранить (Save) .

Каждая страна содержит список атрибутов. Вы можете посмотреть эти атрибуты в таблице: Слой (Layer) → Открыть таблицу атрибутов (Open Attribute Table) .


Таблица атрибутов стран.

Данные Natural Earth содержат огромное количество информации о каждой стране. Для однозначной идентификации стран мы будем использовать двухбуквенные ISO коды , которые хранятся в переменной iso_a2 . Также мы будем использовать название стран (name), чтобы маркировать страны в нашем SVG файле. Не стесняйтесь исследовать таблицу, чтобы понять смысл данных. Закройте таблицу, когда закончите.

Редактирование географических данных

(вы можете пропустить этот раздел, если довольны данными, предоставляемыми Natural Earth по умолчанию)

Использование QGIS позволяет редактировать отдельные географические фигуры. Возможно вам не нужно перерисовывать границы, но вы можете разделить страну на части.

Каждая фигура в нашем shape-файле соответствует объекту в QGIS. Чтобы выбрать объект, выберите Вид (View) → Выделить (Select) → Выделить объект(ы) (Select Feature(s)) , а затем кликните по вашей цели. Весь объект должен стать желтым. Например, так будет выглядеть Франция, когда вы кликните по ней:


Франция выделена и подсвечена.

Обратите внимание, что Франция включает в себя и Французскую Гвиану в Южной Америке. Это потому что Французская Гвиана является заморскими департаментом и регионом Франции (Французская Гвиана в Википедии). Тем не менее, Французская Гвиана имеет свой уникальный ISO код, и для многих приложений это означает, что её необходимо отображать как отдельный самостоятельный объект.

Разделение Франции на два отдельных объекта - это простой процесс, требующий выполнения нескольких шагов:


Создание SVG файлов с Kartograph.py Изменение проекции карты

Вы можете заметить, что данная карта выглядит несколько иначе, чем карта в QGIS. Есть целый ряд различных способов спроецировать нашу трехмерную Землю на двухмерное пространство. По умолчанию Kartograph использует проекцию Робинсона , красиво выглядящую проекцию, обычно используемую для карт мира. Однако вы можете предпочесть работать с проекцией Меркатора (используется в Google Maps), которая проецирует широту и долготу в качестве прямых линий. Чтобы сделать это, добавьте объект proj после объекта layers в файл config.json:

"proj": { "id":"mercator" }

Уменьшение размера файла

Часто созданный SVG файл может быть слишком большим для практичного использования в веб-приложении. Kartograph включается в себя алгоритм упрощения Висвалингам-Уайатта , который позволяет резко уменьшить размер файла при незначительных визуальных изменениях границ стран. Наш файл уже достаточно мал (231 Кб), то мы можем упростить его еще, добавив свойство simplify в конец объекта countries:

"simplify": 1

Чем выше значение simplify , тем сильнее границы стран будут упрощены, и тем меньше будет выходной файл.

Фильтрация объектов

По умолчанию карта будет включать в себя все объекты, представленные в shape-файле. Но вы можете исключить определенные объекты из SVG файла. Например, мы можем захотеть удалить Антарктиду, так как она не имеет отношения к нашей задаче. Kartograph включает в себя инструмент фильтрации, позволяющий отсеять объекты на основе их атрибутов. Мы можем исключить Антарктиду, используя её ISO код. Чтобы сделать это, добавьте свойство filter к слою countries:

"filter": ["iso_a2", "not in", ["AQ"]],

Сохранение данных внутри SVG файла

В завершение, мы хотим, чтобы наша SVG карта включала в себя атрибуты данных с ISO кодом и названием каждой страны. Это позволит идентифицировать SVG элементы в браузере. Чтобы сделать это, добавьте свойство attributes к слою countries:

"attributes": { "id": "iso_a2", "name": "name" },

Собираем всё вместе

После внесения всех изменений config.json будет выглядеть следующим образом:

{ "layers": { "countries": { "src": "ne_110m_admin_0_countries_lakes.shp", "filter": ["iso_a2", "not in", ["AQ"]], "attributes": { "id": "iso_a2", "name": "name" }, "simplify": "1" } }, "proj": { "id": "mercator" } }

Выполните ту же команду Kartograph, что и ранее (с новым именем SVG файла):

Kartograph config.json -o world.svg

Kartograph создаст новую карту world.svg , которая меньше по размеру и выглядит немного иначе:

Если вы откроете этот файл в текстовом редакторе, то увидите, что каждый Теперь содержит идентифицирующую информацию в следующей форме:

Data-id="US" data-name="United States" id="US"

Добавление SVG карты на сайт

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

Однако встраивание карты подобным способом затрудняет возможности по изменению внешнего вида карты и приданию ей интерактивности. Простой способ обеспечить возможность применения CSS и JavaScript к карте - встроить SVG файл в HTML код. Просто откройте world.svg в текстовом редакторе, скопируйте весь элемент , и вставьте его непосредственно в код страницы.

Элемент содержит отдельный Для каждой страны. Чтобы изменить стиль карты, просто примените CSS ко всем елементам Используйте свойства fill и stroke , чтобы изменить для каждой страны цвет и границу соответственно. Например, мы можем сделать все страны светло-серыми и добавить эффект наведения:

Path {fill: lightgray; stroke: white;} path:hover {fill: gray;}

Аналогичным образом мы можем использовать JavaScript для задания обработчиков событий. Следующий код будет выводить модальное окно с названием страны при клике на неё:

//

  • Tutorial

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

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

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

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

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

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

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

Далее, в секции изображения помещаем до боли знакомое:
.area { stroke: black; stroke-width: 2px; fill: #E9FFE9; } .city { stroke: black; stroke-width: 2px; fill: red; }
Вот и обещанный мною 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" Diff .

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


Жаль. Придётся привлечь JavaScript и подогнать высоту элемента вручную.
var viewBox = svgdom.rootElement.getAttribute("viewBox").split(" "); var aspectRatio = viewBox / viewBox; svgobject.height = parseInt(svgobject.offsetWidth / aspectRatio); Diff .

Результат:

Взаимодействуем с 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"); // Находим тег с id="figure1" в SVG DOM и заливаем его красным } });
Да, jQuery работает с SVG, но только частично. Например, я заметил, что не работают функции addClass и removeClass, а так же поиск по классам (jQuery(".class")). Приходится извращаться.

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

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

Здесь мы будем при щелчке по флажку ставить или убирать класс selected у соответствующей области на карте, а так уже у самой строки. Это несложно:
$("#areas input").change(function() { var row = $(this).parent().parent(); var id = row.attr("id"); if (this.checked) { row.addClass("selected"); $("#"+id, svgdom).myAddClass("selected"); } else { row.removeClass("selected"); $("#"+id, svgdom).myRemoveClass("selected"); } });
Соответственно, нужно добавить и стилевые определения для данного класса. Предоставляю вам это сделать самостоятельно, согласно своих вкусов и предпочтений. Diff .

Интерактивность вторая: вскрываем/показываем названия на карте щелчком по чекбоксу на странице. Это взаимодействие делается ещё проще. Вставляем на страницу и немножко яваскрипта, который добавляет/удаляет всем связанным с названиями элементам на карте класс hidden {visibility: 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 = $(this).attr("id"); $("#"+id, svgdom).myAddClass("highlight"); }, function () { var id = $(this).attr("id"); $("#"+id, svgdom).myRemoveClass("highlight"); });
…так и на районы на карте:
// Подсвечиваем строку в таблице при наведении мыши на соотв. регион на карте $(svgdom.getElementsByClassName("area")).hover(function () { var id = $(this).attr("id"); $("#areas #"+id).addClass("highlight"); }, function () { var id = $(this).attr("id"); $("#areas #"+id).removeClass("highlight"); });
Для того, чтобы мы это видели, добавим соответствующие CSS-правила в страницу:
tr.highlight, tr:hover, tr:nth-child(even):hover { background: lightyellow; } …и в SVG-карту: .highlight, .area:hover { fill: lightyellow; stroke: black; }
При наведении мышкой на строку таблицы (или на район на карте) на соответствующий район на карте (на строку таблицы) вешается нужный для подсвечивания класс. Чтобы приведённый выше код работал, необходимо, чтобы у районов на карте и строк таблицы были совпадающие (или схожие) id. Diff .

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

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

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

Ну и JavaScript-код, который будет брать данные из ячеек таблицы и помещать в блоки текста:
$("input").change(function () { var descnum = $(this).parent().prevAll().length+1; $("#areas tbody tr").each(function() { var id = $(this).attr("id").substring(4); var value = $(this).children(":nth-child("+descnum+")").text(); $("#text"+id, svgdom).text(value); }); });
И по переключению радиокнопок карта будет показывать нужные цифры. Вуаля !

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

Для данного взаимодействия возьмём плагин jQuery.tooltip и привяжем его к областям на карте. Текст для подсказок будем брать, конечно же, из таблицы:
$(svgdom.getElementsByClassName("area")).tooltip({ bodyHandler: function() { var id = $(this).attr("id"); 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.
Для массовых преобразований можно сочинить команду посложнее или посмотреть примеры в Добавить метки

Когда мне нужно создать карты, то первым делом, я обращаюсь к Google Charts или любой другой специализированной библиотеке. Но иногда мне могут понадобиться специфические особенности, которые я не могу там найти. В этом случае SVG-изображения оказываются очень ценными (полезными).

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

Создаем SVG карту в Illustrator

Первым делом я нарисовал карту Италии в Adobe Illustrator:

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

Наконец, карта должна быть сохранена в формате SVG. Вам следует обратить внимание на то, чтобы установить опцию «CSS property» в графе «Элементы стиля» в Иллюстраторе, как показано ниже:

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

Построение нашего HTML файла

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

Если вы попытаетесь изменить эти значения, карта изменится тоже:

Теперь мы можем использовать этот код, чтобы создать наш HTML файл со встроенным SVG, как показано ниже (код был сокращен для удобства):

Map Sample .map svg { height: auto; width: 350px; } .map g { fill: #ccc; stroke: #333; stroke-width: 1; }

Можно заметить, что атрибут 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);

$(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"); $("" + region_data.region_name + "
" + "Population: " + region_data.population.toLocaleString("en-UK") + "").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’ам.

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

ШАГ 1. Подготовка базовой HTML разметки

Добавьте код ниже:

После того как вы добавите этот код, не пугайтесь если вы не увидели свою картинку, которую подключили. Промотайте страницу немного вниз, она будет там. Изображение, которое вы подключили съехало вниз из-за елемента svg , который был добавлен перед ней. Мы в нем прописали размеры нашей картинки и он теперь занимает такое же место как и оригинальное изображение. Примечание . В атрибуте viewBox елемента svg необходимо прописать размер вашего изображения которое вы будете делать
интерактивным.

ШАГ 2. Создание SVG елементов

Для дальнейшей работы вам необходимо установить программу позволяющую работать с svg графикой Inkscape . После установки программы смело запускайте её. Открывайте ваше изображение в этой программе во вкладке «файл» и «открыть…» . В моём случае это изображение карты мира. Затем нажимайте на кнопку в правом нижнем углу «Просмотреть и изменить XML «. У вас после нажатия на эту кнопку в правой части экрана появится соответствующий виджет.

После выделения выберите появившуюся строку выделенной вами части изображения в редакторе xml. Затем выберите поле d этого елементаи скопируйте его содержимое немного ниже.

В поле d будет довольно большой объем координат. Копируйте это все и вставляйте в вашем HTML коде в атрибут d елемента path .

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

ШАГ 3. Добавление стилей

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

Map { position: relative; text-align: center; } svg { position: absolute; top: 0; left: 0; height: 100%; width: 100%; } path { opacity: 0.4; fill: orange; cursor: pointer; transition: 0.3s; } path:hover { opacity: 0.8; transition: 0.3s; }

В зависимости от того, что вы за картинку использовали у вас будет немного разный вид изображения. Вот, например, у меня получилось так. Довольно криво я навел контуры картинки, но для меня главное было показать, что вышло в итоге) Я не делал всю карту интерактивной и более аккуратной ибо это заняло бы намного больше времени, а результат был бы один и тот же. Главное, что вы поняли как это работает и как это реализовывать.

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

Все! Теперь вы сделали свою первую интерактивную svg карту.



Есть вопросы?

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: