Pull to refresh

Панорамы на Яндекс.Картах с помощью KRPano

Reading time 3 min
Views 12K
Поставлена задача: придумать интеграцию Яндекс.Карт и популярного просмотрщика панорам KRPano. Первым делом, разумеется, лезем в API и… получаем тонну ответов, что средствами Я.Карт панорамы сделать нельзя.
Не беда, т.к. панорамы использоваться будут самодельные, но основная вещь, которую нужно сделать — это т.н. радар, который будет указывать куда в данный момент смотрит панорама.

Радар с панорам Я.Карт

Итак, имеется некий тур KRPano, каждая панорама которого должна быть отображена на карте какой-нибудь стандартной иконкой. При клике должна загрузиться определенная панорама, а так же смениться иконка на изображение радара (с корректным поворотом на карте). При просмотре панорамы радар так же должен крутиться вокруг своей оси по мере смены угла обзора.

Для начала, во время срабатывания события onxmlcomplete, сделаем вызов некой JS-функции, например, loaded, которая будет принимать в себя ID загруженной панорамы:
<pano name="solar_tower_1"
	  xmlurl="%SWFPATH%/scenes/solar_tower_1/scene.xml"
	  pageurl="/solar_tower_1/"
	  pagetitle="Солнечная башня #1"
	  onxmlcomplete="trace(Солнечная башня #1 loaded); js(loaded(0))"
/>

Что будет делать эта функция? Ничего сложного — лишь перестроит точки (Placemark) на карте и запустит функцию проверки угла обзора панорамы (с интервалом в 100 мс, например):
function loaded(id)
{
	activeId = id; // сохраняем ID загруженной панорамы, пригодится позднее
	addPmark(id);
}

function addPmark(id)
{
	clearTimeout(degreeInterval); // Сбрасываем обновление угла на время перестройки точек

	resetAll(); // Приводим все точки к стандартным иконкам

	if (typeof inactiveMarks[id] != 'undefined')
		map.geoObjects.remove(inactiveMarks[id]); // Удаляем точку активного hotspot'а

	map.geoObjects.remove(pMark); // Удаляем точку предыдущего активного hotspot'а
	// Далее всё просто - создаем новую точку и добавляем её на карту
	pMark = new ymaps.Placemark(pmarks[id].coords, {
		iconContent: '<img src="map/icon_large.png" id="pMarkIcon">',
	}, {
		iconImageHref: 'map/pixel.png',
		iconImageSize: [93, 93],
		iconImageOffset: [-54, -35]
	});
	map.geoObjects.add(pMark);

	degreeInterval = setInterval(updateDegree, 100); // Вновь запускаем обновление угла
}

function resetAll()
{
	var size = pmarks.length;

	for (var i = 0; i < size; ++i)
	{
		if (typeof inactiveMarks[i] != 'undefined')
			map.geoObjects.remove(inactiveMarks[i]);
		inactiveMarks[i] = new ymaps.Placemark(pmarks[i].coords, {
			iconContent: '<img src="map/binocular.png" style=" background:url(\'map/blue-bg.png\');">'
		}, {
			iconImageHref: 'map/placemark-bg-blue.png',
			iconImageSize: [44, 55],
			iconImageOffset: [-17, -37],
			panoPath: pmarks[i].xml // Записываем адрес к текущей панораме
		});
		if (typeof pmarks[i] != 'undefined')
		{
			inactiveMarks[i].events.add('click', function(p) {
				// По щелчку на точку произойдет переключение к текущей панораме
				kr.call('loadpano(' + p.originalEvent.target.options.get('panoPath') + ')');
			});
		}
		map.geoObjects.add(inactiveMarks[i]);
	}
}

Что мы сделали: панорама загрузилась, выстроили точки сначала по умолчанию, затем активной сменили иконку, сохранили её ID и раз в 100 мс выполняем проверку на изменение угла обзора.

Самое интересное — поворот радара. Происходит это следующим образом:
function updateDegree()
{
	var hlookat = kr.get('view.hlookat');
	// check offset
	offset = pmarks[activeId].offset; // Может быть такое, что угол панорамы по умолчанию является совсем не подходящим и приходится использовать оффсеты
	hlookat -= offset;
	// Крутить иконку будем с помощью rotate в градусах
	$('#pMarkIcon').css({
		'-moz-transform': 'rotate(' + hlookat + 'deg)',
		'-webkit-transform': 'rotate(' + hlookat + 'deg)',
		'-o-transform': 'rotate(' + hlookat + 'deg)',
		'-ms-transform': 'rotate(' + hlookat + 'deg)'
	});
}

Точки в данном примере хранятся в простом массиве с координатами, оффсетом в градусах и путями к сценам:
var pmarks = [
	{coords: [107.60835728615834, 51.80498497161981],  offset: 29.612430,  iconContent: '1', xml: '%SWFPATH%/scenes/solar_tower_1/scene.xml'},
	{coords: [107.60834053847577, 51.80625216324661],  offset: 52.541204,  iconContent: '2', xml: '%SWFPATH%/scenes/solar_tower_2/scene.xml'},
	{coords: [107.60839418265618, 51.807256449274895], offset: 58.053150,  iconContent: '3', xml: '%SWFPATH%/scenes/solar_tower_3/scene.xml'},
	{coords: [107.60832980963896, 51.807974732832555], offset: -59.017464, iconContent: '4', xml: '%SWFPATH%/scenes/solar_tower_4/scene.xml'},
	{coords: [107.60930374795694, 51.808262554869444], offset: 52.025996,  iconContent: '5', xml: '%SWFPATH%/scenes/russian_dramatic_theater_1/scene.xml'}
];

Код полностью.

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

Панорама 1:




Панорама 2:


Tags:
Hubs:
+14
Comments 4
Comments Comments 4

Articles