Функциональные географические карты с помощью SVG и jQuery. Интерактивная векторная карта России JQVMap

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

Что же, и возьмём мы 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.
Для массовых преобразований можно сочинить команду посложнее или посмотреть примеры в форумной ветке , где я эту команду и нашёл.Вместо заключенияНу вот и всё. При ближайшем рассмотрении это не так уж и сложно, а главное — всё близко и знакомо веб-разработчику. Смотрите, о чём я написал выше в виде демо-страницы , раздирайте исходный код из репозитория , если есть предложения и улучшения — высказывайте в комментариях или присылайте в репозиторий в виде пулл реквестов . Приятной вам работы с современными веб-технологиями!

Здравствуйте! Недавно на одном из сайтов мне потребовалось вставить интерактивную карту России со всеми регионами. Как оказалось подобных скриптов карт немного и большинство либо не соответствовали требованиям, либо были платными. Требования к такой карте были следующие:

  • Карта должна быть довольно хорошо прорисована (Все границы регионов должны быть похожи на реальные),
  • На карту можно добавлять объекты, которые будут появляться при наведении на соответствующий регион,
  • Карту можно было легко адаптировать по размерам и цветам под стиль сайта,
  • Подсветка регионов, в которых есть объекты другим цветом.

И вот я наткнулся на JQVMap – карты в формате SVG. Первое что мне понравилось – это хорошо прорисованная карта России. Почитав документацию, я понял, что и все мои задачи можно решить, хотя поначалу и возникли некоторые трудности.

Скачав архив, я нашел в нем пример как эту самую карту подключить на сайт. Здесь все очень просто. Подключаем скрипты и стили:


Создаем блок для будущей карты, указав размеры:

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

// Массив всех объектов
var data_obj = { "no": ["Объект 1", "Объект 2"], "kr": ["Объект 3", "Объект 4", "Объект 5"], "ir": ["Объект 6", "Объект 7", "Объект 8"] };
colorRegion = "#1076C8"; // Цвет всех регионов focusRegion = "#FF9900"; // Цвет подсветки регионов при наведении на объекты из списка selectRegion = "#0A4C82"; // Цвет изначально подсвеченных регионов
highlighted_states = {};
// Массив подсвечиваемых регионов, указанных в массиве data_obj for(iso in data_obj){ highlighted_states = selectRegion; }
$(document).ready(function() { $("#vmap").vectorMap({ map: "russia", backgroundColor: "#ffffff", borderColor: "#ffffff", borderWidth: 2, color: colorRegion, colors: highlighted_states, hoverOpacity: 0.7, enableZoom: true, showTooltip: true,
// Отображаем объекты если они есть onLabelShow: function(event, label, code){ name = ""+label.text()+"
";
if(data_obj){ list_obj = "

    "; for(ob in data_obj){ list_obj += "
  • "+data_obj+"
  • "; } list_obj += "
"; }else{ list_obj = ""; }
label.html(name + list_obj); list_obj = ""; },
// Клик по региону
onRegionClick: function(element, code, region){ alert(region+" - " +code); } }); });
// Выводим список объектов из массива $(document).ready(function() { for(region in data_obj){ for(obj in data_obj){ $(".list-object").append("
  • "+data_obj+" ("+region+")
  • ");
    } } });
    // Подсветка регионов при наведении на объекты $(function(){ $(".focus-region").mouseover(function(){ iso = $(this).prop("id"); fregion = {}; fregion = focusRegion; $("#vmap").vectorMap("set", "colors", fregion); });
    $(".focus-region").mouseout(function(){ c = $(this).attr("href"); cl = (c === "#")?colorRegion:c; iso = $(this).prop("id"); fregion = {}; fregion = cl; $("#vmap").vectorMap("set", "colors", fregion); }); });

    В самом начале идет массив data_obj со всеми имеющимися объектами в регионах в формате

    Data_obj = { "no": ["Объект 1", "Объект 2"] }

    В качестве ключа используется код региона по стандартам ISO, который представляет собой двухбуквенное значение на английском языке (В исходниках приложен файл с расшифровкой всех обозначений). А значением служит еще один массив со списком объектов в этом регионе. В коде выше у нас имеется два объекта в Новгородской области (no). Далее идут переменные, задающие цвет для наших регионов:

    colorRegion - цвет всех регионов по умолчанию
    focusRegion - цвет подсветки регионов при наведении на объекты из списка
    selectRegion - цвет изначально подсвеченных регионов
    map – название карты,
    backgroundColor – цвет фона карты,
    borderColor – цвет границ регионов,
    borderWidth – толщина границ,
    color – цвет всех регионов по умолчанию,
    colors - массив подсвечиваемых регионов с указанием цвета,
    hoverOpacity – прозрачность цвета регионов при наведении на них,
    enableZoom – включение кнопок масштабирования карты,
    showTooltip – отображение всплывающих подсказок.

    Более подробно о всех параметрах можно почитать на официальном сайте , однако я не очень понял как некоторые из них работают. Затем у нас идет onLabelShow функция обратного вызова выполняется перед отображением лейбла с названием региона. В ней мы добавляем все объекты в лейбл для отображения. Функция onRegionClick выполняется при клике на объекте. В нашем примеры мы просто выводим название и код региона с помощью alert. Также существуют функции onRegionOver - выполняется при наведении на регион и onRegionOut - выполняется при уводе курсора мыши с объекта. В принципе мои задачи на этом были решены, но я решил продолжить изучение скрипта. А что если бы мы могли вывести список регионов под картой и при наведении на соответствующий он подсвечивался. В документации описан метод для динамического обновления цветов на карте:

    JQuery("#vmap").vectorMap("set", "colors", {us: "#0000ff"});

    В нем мы задаем массивом список областей на карте и соответственно цвет. Для примера я создал список и написал небольшую функцию, которая приведена выше:

    Теперь при наведении на название у нас подсвечивается нужная область. Было бы хорошо вывести список всех объектов, и чтобы при наведении на них подсвечивалась соответствующая область. Писать все вручную неохота, тем более у нас уже есть массив, поэтому просто выведем его в цикле. Обратите внимание на атрибут href – он указывает, на какой цвет будет меняться регион при уводе мышки. Сделали мы это для того что бы регионы, в которых есть объекты, перекрашивались не на цвет по умолчанию, а на цвет изначально подсвеченных регионов (selectRegion).

    Ну вот, все оказалось не так и сложно, и возможно в каком-то из проектов может пригодиться. Дополнительные карты так же можно скачать с официального сайта.

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

    ШАГ 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 карту.

    • 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 Достаточно подробно этот процесс был освещён в хабратопике .

    Мы же будем использовать 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.
    Для массовых преобразований можно сочинить команду посложнее или посмотреть примеры в форумной ветке интерактивная карта Добавить метки
    • Сергей Савенков

      какой то “куцый” обзор… как будто спешили куда то