ANTICHAT

ANTICHAT (https://forum.antichat.xyz/index.php)
-   Статьи (https://forum.antichat.xyz/forumdisplay.php?f=30)
-   -   SVG объекты + jQuery или два дня Ада (https://forum.antichat.xyz/showthread.php?t=398715)

Sum.cogitans 08.11.2013 04:39

Предисловие

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

Суть задачи

В ТЗ была описана, так называемая "Интерактивная карта", которая подразумевала навигацию по котологу неких отчетов. Предусмотрено 2 основных параметра, направление деятельности и регион. Я не буду описывать и приводить примеры, построения каталога и смежных вопросов типа: jQuery tabs, подключение iframe, css etc т.к. этой инфы у гугла с лихвой, а сконцентрируюсь только на том, что лично для меня было ново.

Подбор софта \ библиотеки

Да да да, мне пришлось рисовать эти чертовы карты в SVG и после 6 часов копирования Google maps, с неработающим cmd+tab из под X11 на OSx, я был готов убивать. Пошел я на это, лишь потому что, набор стран должен быть представлен в формате описаном ТЗ, так же на карте присутствовали нефтяные Шельфы России, искать которые в SVG исходниках - без толку. Так что, хорошая новость для вас - я затрону ключевые моменты работы с SVG редактором.

Первым делом я конечно же ломанулся в illustrator, но был крайне разачарован, тем что при экспорте вектора в SVG не отдается параметр path (набор координат и действия для jQuery), даже если мучать настройки. Не долго думая я решил, что мою проблему исправит online конвертер, но к сажалению как выяснилось, выдача path происходит в неподходящем к выбронной мною библиотеке формате. Это можно определить на глаз, по мимо разных координат, пробелы заменены тире.

В итоге пробежавшись по предоставленным программам, я остановился на Inkscape, основным фактором для меня была работа под OSx:

1. Он бесплатный

2. Доступные платформы - OSx \ Linux \ Windows

3. Весит не много, а я сидел у заказчика в офисе, где интернет не ахти

P.s. Единственный фактор, который меня выморозил - это тот факт, что на OSx он поднялся под X11, который в свою очередь имеет свой набор хоткеев, при отключении ассоциации которых, оные вообще перестают работать. За учетом того, что например в моем случае идет одновременная работа: Inkscape + Aptana Studio + Safari + Chrome, получается 3 разных набора хоткеев и самое страшное для меня - замена cmd на ctrl в X11. Это не то, что бы не удобно. Это бесит, если изолгаться в рамках правил форума.

Относительно бибилиотеки jQuery, я выбрал jqvmap:

1. Проект живой, можно качать null версию, ничьи кривые руки ее не кастумили

2. Есть большой набор уже готовых карт, мне это конечно было не к чему, но я их поковырял пока разбирался

3. Чистая, минимальный набор функционала

Ссылки:

Inkscape - SVG редактор

jqvmap - Библиотека

Создание SVG

Основные инструменты которые надо знать в Inkscape:

1. Группировка объектов - не подходит для получения корректного path, я испытал первый приступ бешенства, когда это выяснил. Для получения корректных координат надо выделить объекты которые должны быть одним целым и объединить контур (Контур > Объединить)

2. Инструмент произвольные контуры - не подходит для получения корректного path, я испытал восьмой приступ бешенства, когда это выяснил. Дело в том, что в момент заливки таких объектов уже в jqvmap, самопересечения или субконтуры образуют дырку в Вашем объекте, даже если изменить эту опцию в настройках - короче получается полная хрень. Так что полсе отрисовки нужного объекта, выберите Заливку замкнутой области. Получившийся объект и будет выдавать Вам корректный path. Так же, прийдется поиграть с настройками этого инструмента (порог \ интервалы etc), если надо получить в точности то, что вы рисовали.

3. Теперь, получаем результат наших трудов - выбираем объект > Правка > XML редактор. Откроется окно, которое будет указывать на класс выбраного нами объекта, видим атрибут d, в котором находится наш path. ГИП ГИП УРА!

Кастомим jqvmap

Дальше все предельно просто, врубаем jquery, подключаем бибилотеку jqvmap + sampledata + наши path, инициируем, ставим div в тело.

Структура файла карт (находится в каталоге maps):

PHP код:

[COLOR="#000000"][COLOR="#0000BB"]jQuery[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]fn[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]vectorMap[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'addMap'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]'[имя_карты]'[/COLOR][COLOR="#007700"],{[/COLOR][COLOR="#DD0000"]"width"[/COLOR][COLOR="#007700"]:[[/COLOR][COLOR="#0000BB"]ширина[/COLOR][COLOR="#007700"]],[/COLOR][COLOR="#DD0000"]"height"[/COLOR][COLOR="#007700"]:[[/COLOR][COLOR="#0000BB"]высота[/COLOR][COLOR="#007700"]],[/COLOR][COLOR="#DD0000"]"pathes"[/COLOR][COLOR="#007700"]:{

[/
COLOR][COLOR="#DD0000"]"[код_объекта]"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"[значение_path]"[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"[название_для_ховера]"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"kz"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Казахстан"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"tu"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Туркменистан"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"uz"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Узбекистан"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"az"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Азербайджан"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"uk"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Украина"[/COLOR][COLOR="#007700"]},

[/
COLOR][COLOR="#DD0000"]"sh"[/COLOR][COLOR="#007700"]:{[/COLOR][COLOR="#DD0000"]"path"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"m 12.958961,158.51389 c -5.1155772..."[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]"name"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]"Шельф"[/COLOR][COLOR="#007700"]}}});[/COLOR][/COLOR

Инициируем нашу прелесть:

PHP код:

[COLOR="#000000"][COLOR="#0000BB"][/COLOR][COLOR="#007700"]

[/
COLOR][COLOR="#0000BB"]jQuery[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#0000BB"]document[/COLOR][COLOR="#007700"]).[/COLOR][COLOR="#0000BB"]ready[/COLOR][COLOR="#007700"](function() {

[/
COLOR][COLOR="#0000BB"]jQuery[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'#vmap'[/COLOR][COLOR="#007700"]).[/COLOR][COLOR="#0000BB"]vectorMap[/COLOR][COLOR="#007700"]({[/COLOR][COLOR="#FF8000"]// #ID где будет инициализированы наши объекты, не забываем растянуть в CSS

[/COLOR][COLOR="#0000BB"]map[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]'my_objects'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Подключение карты (имя)

[/COLOR][COLOR="#0000BB"]backgroundColor[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]''[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Фон

[/COLOR][COLOR="#0000BB"]color[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]'#9ab8cd'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Цвет объектов

[/COLOR][COLOR="#0000BB"]hoverOpacity[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#0000BB"]0.7[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Уровень прозрачности при ховере

[/COLOR][COLOR="#0000BB"]selectedColor[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]''[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Цвет, выделенного объекта

[/COLOR][COLOR="#0000BB"]enableZoom[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#0000BB"]false[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Кнопочки + \ -

[/COLOR][COLOR="#0000BB"]showTooltip[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#0000BB"]true[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Вывод название при ховере

[/COLOR][COLOR="#0000BB"]values[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#0000BB"]sample_data[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Подключение sample_data

[/COLOR][COLOR="#0000BB"]scaleColors[/COLOR][COLOR="#007700"]: [[/COLOR][COLOR="#DD0000"]'#C8EEFF'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]'#2a82aa'[/COLOR][COLOR="#007700"]],[/COLOR][COLOR="#FF8000"]// Тут можем разнообразить цвета объектов

[/COLOR][COLOR="#0000BB"]normalizeFunction[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#DD0000"]'polynomial'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#FF8000"]// Ага, спасибо!

[/COLOR][COLOR="#007700"]}

});

});

[/
COLOR][COLOR="#0000BB"][/COLOR][/COLOR

Ссылки из объектов в jqvmap отсуствуют, добавим

PHP код:

[COLOR="#000000"][COLOR="#0000BB"]onRegionClick[/COLOR][COLOR="#007700"]: function([/COLOR][COLOR="#0000BB"]element[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]code[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#0000BB"]region[/COLOR][COLOR="#007700"])

{

switch ([/COLOR][COLOR="#0000BB"]code[/COLOR][COLOR="#007700"]) {

case[/COLOR][COLOR="#DD0000"]"ru"[/COLOR][COLOR="#007700"]:[/COLOR][COLOR="#FF8000"]// Тут добавляем код объекта из файла с path, на который будем вешать url

[/COLOR][COLOR="#0000BB"]window[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]open[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'/some_direction/page_1.php'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]'_top'[/COLOR][COLOR="#007700"]);[/COLOR][COLOR="#FF8000"]// Обратите внимание на атрибут _top, он для iframe, поясню ниже

[/COLOR][COLOR="#007700"]break;

case[/COLOR][COLOR="#DD0000"]"kz"[/COLOR][COLOR="#007700"]:

[/
COLOR][COLOR="#0000BB"]window[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]open[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'/some_direction/page_2.php'[/COLOR][COLOR="#007700"],[/COLOR][COLOR="#DD0000"]'_top'[/COLOR][COLOR="#007700"]);

break;

case[/COLOR][COLOR="#DD0000"]"tu"[/COLOR][COLOR="#007700"]:

[/
COLOR][COLOR="#0000BB"]window[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]open[/COLOR][COLOR="#007700"]([/COLOR][COLOR="#DD0000"]'/some_direction/page_3.php,'[/COLOR][COLOR="#0000BB"]_top[/COLOR][COLOR="#DD0000"]');

break;

case "uz":

window.open('
[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]some_direction[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]page_4[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]php[/COLOR][COLOR="#DD0000"]','[/COLOR][COLOR="#0000BB"]_top[/COLOR][COLOR="#DD0000"]');

break;

case "az":

window.open('
[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]some_direction[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]page_5[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]php[/COLOR][COLOR="#DD0000"]','[/COLOR][COLOR="#0000BB"]_top[/COLOR][COLOR="#DD0000"]');

break;

case "uk":

window.open('
[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]some_direction[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]page_6[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]php[/COLOR][COLOR="#DD0000"]','[/COLOR][COLOR="#0000BB"]_top[/COLOR][COLOR="#DD0000"]');

break;

case "sh":

window.open('
[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]some_direction[/COLOR][COLOR="#007700"]/[/COLOR][COLOR="#0000BB"]page_7[/COLOR][COLOR="#007700"].[/COLOR][COLOR="#0000BB"]php[/COLOR][COLOR="#DD0000"]','[/COLOR][COLOR="#0000BB"]_top[/COLOR][COLOR="#DD0000"]');

break;

}

}[/COLOR][/COLOR] 

Позиционирование карт

Если помните, в тз был еще один параметр, так называемые направление деятельности. Суть в том, что у каждого направления, есть набор своих регионов и пользователь должен иметь возможность выбрать его. Решение выбрал достаточно простое, т.к. хотелось уже завязывать с этим вопросом - делаем табы с направлениями, куда закидываем разные карты с нужным набором регионов.

Когда я все причесал, сверстал и нажал долгожданную cmd+r, что бы посмотреть результат, выяснилось что дальше первой карты ничего не работает. Первым делом я конечно же пошел менять коды регионов, чертыхаясь своей недальновидностью. Но не тут то было, все равно ничего не работало. От безысходности, перепробовав все варианты, я пошел читать всякие забугорные статьи бородатых дядек, о процессе SVG моделирования на jQuery и о чудо, я все понял.

Проблема оказалась не в "дальше первой карты", а в "дальше первой вкладки". Дело в том, что jqvmap рисовал таки свои карты, но по логике табов они были позиционированы где-то в космосе относительно окна браузера и там оставались, даже после активации таба.

В общем-то решение было очевидно, убрать карты в iframe, для чего в ссылках и добавлен атрибут _top (кто не понял, ссылка в iframe - открывается в iframe, данный атрибут повзоляет открыть ее в текущем окне). Вообще, может это решение не очень мудрое с точки зрения оптимизации (что безусловно можно решить, по желанию), но если Вам нужно подключать на страницу более одной группы объектов - такое решение будет как минимум удобней, не надо будет морочиться с разными кодами и скролить head в дальнейшем.

FIN

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

2013 (c) Sum cogitans

expert3030 16.12.2013 01:35

Неплохая статья))) У меня тоже возникли проблемы с подобной картой. Понадобилась карта областей России и стран СНГ. Так как с векторной графикой дел раньше не имел, заказал на фрилансе схематическую карту в SVG формате. Исполнитель сделал ее в Кореле. Перед началом работы я спрашивал его - будут ли проблемы при импорте в Инскейп, на что получил ответ, что проблем не будет. Но после сдачи готовой карты, проблемы все-таки возникли: в XML редакторе не отображался этот параметр "path" для нескольких объектов этой карты. Я несколько раз отправлял карту на доработку и вроде бы в конце концов исполнитель добился, чтобы параметр отображался у всех объектов. Но как оказалось, все равно проблемы остались: если я вставляю значения этого параметра из любого объекта в jqvmap, на странице не отображаются эти объекты. Но, если, я рисую в Инскейпе окружность рядом с этой картой, копирую path из окружности – вставляю в js скрипт, окружность появляется на странице. А с любым объектом из этой карты, такое не получается, объект просто не отображается на странице. Получается или проблемы при импорте или исполнитель некорректно задал какие-то параметры: заливка или слои, в общем, карта бесполезна. Ничего в голову не приходит, не могли бы вы помочь советом, в чем может быть дело? Заранее спасибо.

Sum.cogitans 02.03.2014 17:26

Извиняюсь, что отвечаю как слоупок, через 2 месяца. Но все же, может кому-то в дальнейшем поможет.

expert3030

Твоя бедя в том, что jqvmap очень придирчив к формату path, по сути, он воспринимает только один из видов. Как показал опыт, после изучения различных SVG редакторов, оные унификацией значения path не парятся.

В твоем случае, если в предоставленном тебе исходнике нет возможности "Залить замкнутую область", он для тебя действительно бесполезен, если ты конечно не хочешь обрисовывать карту второй раз в Inkscape.

P.s. Мне самому, было бы интересно глянуть формат path, который у тебя не читал jqvmap.


Время: 11:05