Заказная карта Карачаево-Черкессии

19.02.2015

Наша компания выполнила работы по созданию заказной карты Карачаево-Черкессии. На карте республики отображаются муниципальные районы и крупные города. С помощью JavaScript API организовано взаимодействие карты с текстовым списком районов и блоком для дополнительного контента.

Выберите регион для получения информации о нем
г. Черкесск
дополнительный блок информации о городе
г. Карачаевск
дополнительный блок информации о городе
Карачаевский район
дополнительный блок информации о регионе
Малокарачаевский район
дополнительный блок информации о регионе
Урупский район
дополнительный блок информации о регионе
Абазинский район
дополнительный блок информации о регионе
Усть-Джегутинский район
дополнительный блок информации о регионе
Зеленчукский район
дополнительный блок информации о регионе
Хабезский район
дополнительный блок информации о регионе
Прикубанский район
дополнительный блок информации о регионе
Адыге-Хабльский район
дополнительный блок информации о регионе
Ногайский район
дополнительный блок информации о регионе

Подробнее о разработке.
При создании карты Карачаево-Черкесской республики были поставлены следующие задачи:
1) Показывать отдельно города.
2) Связать список районов с картой, так чтобы взаимодействие с картой отражалось на списке и наоборот.
3) При выборе конкретного района — отображать контент для выбранного района.
4) «Связать» выделение района «Черкесск» и точки, обозначающей город Черкесск.

Итак, для решения поставленных задач был выбран продукт «многоуровневая карта» новой версии 2.3, так как он включает в себя возможность размещать точки на карте, а также выделять и выбирать несколько регионов одновременно.

Точки для городов.
Чтобы подготовить необходимые точки был использован debug-режим карты. Включается ключом debug при инициализации объекта карты:

var map = new FlaMap({debug: true, ...});

В данном режиме к курсору прикреплен блок, в котором отображаются координаты позиции на карте. Это позволяет легко определить нужное положение для точки. Остается лишь вписать их в points.js.
В итоге конфигурация точек выглядит следующим образом:

	{
		"id": "c1",
		"x": 259,
		"y": 76,
		"tx": 269,
		"radius": 5,
		"name": "г. Черкесск",
		"color": "#999",
		"color2": "#f3a72f",
		"color3": "#c48826",
		"url": "javascript:void(0)"
	},
	...

Ну и напоследок остается лишь указать имя файла с точками для нашей карты.

var map = FlaMap({pathToJson:"data/", mainPoints: "points.js", ...});

В итоге наш файл будет искать по относительному пути data/points.js
Вам следует указывать не относительные пути, а абсолютный путь к данным карты на вашем сервере.
Например: "/static/map/data/".

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

Карачаевский район
...

Что же нам нужно для связи? Указать обработчики различных событий:

Карачаевский район

Это нам позволит перенести взаимодействие с ссылками из нашего списка регионов на карту.
Добавим CSS стиль, для подсвечивания выделенной ссылки:

a:hover { color: green }

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

map.on('select', function(ev, sid, map) {
	$('#href-'+sid).addClass('selected');
});
map.on('unselect', function(ev, sid, map) {
	$('#href-'+sid).removeClass('selected');
});
map.on('mousein', function(ev, sid, map) {
	$('#href-'+sid).addClass('hovered');
});
map.on('mouseout', function(ev, sid, map) {
	$('#href-'+sid).removeClass('hovered');
});

Остается лишь определить 2 CSS класса для придания нашим ссылкам желаемого вида:

a.selected { color: red !important }
a.hovered { color: green }

Контент для выбранного региона.
Заранее заготовим нужный контент в скрытом DIV.
Для хранения контента каждого региона мы будем использовать отдельный DIV.
В итоге мы получим что-то типа:

Выберите регион для получения информации о нем
Какой-то контент 1
...

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

map.on('select', function(ev, sid, map) {
	$('#href-'+sid).addClass('selected');
	$('#left-panel').html($('#block'+sid).html());
});
map.on('unselect', function(ev, sid, map) {
	$('#href-'+sid).removeClass('selected');
	$('#left-panel').html($('#block-def').html());
});
$('#left-panel').html($('#block-def').html()); // отображать контент по-умолчанию сразу после загрузки страницы.

«Связать» выделение района «Черкесск» и точки, обозначающей город Черкесск.
Самая сложная часть. Для реализации этой задачи нам потребуется включить возможность выбирать по несколько районов и вручную контролировать какие районы будут выбраны.

var map = new FlaMap({multiSelect: true, ...});

Теперь нам надо вручную «отменять» ранее выбранные регионы при выборе региона.
Для этого модернизируем наши обработчики следующим образом:

map.on('select', function(ev, sid, map) {
	if(map.selectedStates.length > 1)
		map.unselectState(map.selectedStates[0]);
	$('#left-panel').html($('#block'+sid).html());
	$('#href-'+sid).addClass('selected');
});

Т.е. мы будем проверять сколько элементов у нас выбрано. Если больше 1 — то убираем все, до тех пор пока не останется 1 последний.
И так, подготовительная часть завершена. Начнем «связывать». Начнем со списка регионов:

г. Черкесск

Итак, по наведению курсора мыши мы будем выделять сразу оба региона и так же снимать выделение если курсор уходит со ссылки.
Осталось корректно обработать выбор региона.

Теперь доработаем обработчики на стороне карты:

map.on('mousein', function(ev, sid, map) {
	if (sid == 'st11')
		sid = 'c1';
	$('#href-'+sid).addClass('hovered');
});
map.on('mouseout', function(ev, sid, map) {
if (sid == 'st11')
		sid = 'c1';
	$('#href-'+sid).removeClass('hovered');
});

Так, если был выделен район, а не точка, то мы подменяем идентификатор области и «выделяем» нужную ссылку. С выделением при наведении курсора мыши разобрались. Осталось выбор района по клику. Для этого при выборе одного района будем автоматически выбирать второй. Так же при снятии выбора:

map.on('select', function(ev, sid, map) {
	if(map.selectedStates.length > 1)
		map.unselectState(map.selectedStates[0]);
	if (sid == 'st11') {
		map.selectState('c1');
		sid = 'c1';
	} else if (sid == 'c1')
		map.selectState('st11');
	$('#left-panel').html($('#block'+sid).html());
	$('#href-'+sid).addClass('selected');
});
map.on('unselect', function(ev, sid, map) {
	if (sid == 'st11') {
		map.unselectState('c1');
		sid = 'c1';
	} else if (sid == 'c1')
		map.unselectState('st11');
	$('#left-panel').html($('#block-def').html());
	$('#href-'+sid).removeClass('selected');
});

но данный код все еще не работает как надо.
Из-за того, что мы вызываем selectState внутри обработчика — у нас генерируется новое событие onselect и второй раз вызывается обработчик, в начале которого снимется выбор предыдущего района.
Чтобы избежать этого мы передадим параметр silent в вызовы selectState и unselectState. С этим параметром не будет генерироваться событие. В итоге весь получившийся блок JavaScript выглядит следующим образом:

var map;
$().ready(function(){
	map = new FlaMap({mapWidth: 0, pathToJSON: 'data/', mainPoints: 'points.js', multiSelect: true});
	map.draw('map');

	map.on('select', function(ev, sid, map) {
		if(map.selectedStates.length > 1)
			map.unselectState(map.selectedStates[0]);
		if (sid == 'st11') {
			map.selectState('c1', true);
			sid = 'c1';
		} else if (sid == 'c1')
			map.selectState('st11', true);
		$('#left-panel').html($('#block'+sid).html());
		$('#href-'+sid).addClass('selected');
	});
	map.on('unselect', function(ev, sid, map) {
		if (sid == 'st11') {
			map.unselectState('c1', true);
			sid = 'c1';
		} else if (sid == 'c1')
			map.unselectState('st11', true);
		$('#left-panel').html($('#block-def').html());
		$('#href-'+sid).removeClass('selected');
	});
	map.on('mousein', function(ev, sid, map) {
		if (sid == 'st11')
			sid = 'c1';
		$('#href-'+sid).addClass('hovered');
	});
	map.on('mouseout', function(ev, sid, map) {
	if (sid == 'st11')
			sid = 'c1';
		$('#href-'+sid).removeClass('hovered');
	});
	$('#left-panel').html($('#block-def').html());
});

Вот и все!