Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / HTML, JavaScript, VBScript, CSS Новый топик    Ответить
 Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Мне нужно на одной странице использовать обе карты.
По отдельности все работает, вместе не получается.
В конце страницы указываю так:
<script src="jquery.min.js"></script>
<script async src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<script async src="https://maps.googleapis.com/maps/api/js?key=...&callback=initMap"></script>
<script defer src="maps.js"></script>

В скрипте maps.js указан необходимый код, а также инициализация (в функции initMap инициализируются обе карты).
Для Яндекс-Карт используется такой код:
ymaps.ready(initMap);

Для Гугл-Карт достаточно указанного в параметрах callback=initMap.
Пробовал сделать так:
$(document).ready(function() {
	ymaps.ready(initMap);
});

Но так не работают Яндекс-Карты, на момент события ready скрипт еще не загружен.
17 янв 18, 14:54    [21114110]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Areostar
Member

Откуда:
Сообщений: 3293
<script src="jquery.min.js"></script>
<script async src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<script async src="https://maps.googleapis.com/maps/api/js?key=...&callback=initMap"></script>
<script defer src="maps.js"></script>


Неподелитесь мануалом по яндекс картам?
17 янв 18, 14:58    [21114118]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Amiri
Member

Откуда: Pakistan
Сообщений: 716
Alibek B.,

https://tech.yandex.ru/maps/jsapi/
https://developers.google.com/maps/documentation/javascript/?hl=ru
17 янв 18, 14:59    [21114123]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Amiri
Member

Откуда: Pakistan
Сообщений: 716
Alibek B.,

Для того, чтобы этого избежать.
Напишите код создания карт в одном обработчике.
17 янв 18, 15:02    [21114125]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
А когда именно это нужно делать?
Функция initMap как раз и является таким обработчиком, в котором инициализируются обе карты.
Если initMap вызывать по событию ready, то Яндекс-Карты не работают — видимо к моменту построения DOM скрипты еще не инициализированы.
А если вызывать ymaps.ready(initMap), то карты Яндекс работают, но не работают карты Google, видимо из-за асинхронной загрузки скриптов.
17 янв 18, 15:22    [21114185]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Areostar
Member

Откуда:
Сообщений: 3293
Areostar,

Спасибо за ссылки!
17 янв 18, 15:24    [21114192]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Вначале у меня был один контейнер для всех карт, в скрипте я при переключении карт его очищал и заново инициализировал. Но в таком способе оказалось несколько затруднений. Поэтому я сделал отдельные контейнеры для каждой карты и переключаю их видимость скриптом:
<div id="map-frame-google" class="hidden" style="width: 100%; height: 450px;"></div>
<div id="map-frame-yandex" class="hidden" style="width: 100%; height: 450px;"></div>

Так же я убрал асинхронную загрузку:
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://api-maps.yandex.ru/2.1/?lang=ru_RU"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=key"></script>
<script src="maps.js"></script>

Файл maps.js выглядит так (все лишнее убрал):
var maps = {google:null, yandex:null};

function initMap() {
	var $mode = <выясняется текущий режим, google или yandex>;
	$('[id|="map-frame"]').addClass('hidden');
	$('#map-frame-'+$mode).removeClass('hidden');
	switch ($mode)
	{
	case 'google':
		initMapGoogle();
		break;
	case 'yandex':
		ymaps.ready(initMapYandex);
		break;
	}
}

function initMapGoogle() {
	return; // сейчас инициализация карт Google отключена
	if (!maps.google) {
		maps.google = google.maps.Map(document.getElementById('map-frame-google'), {center: {lat:20, lng:30}, zoom: 10});
		setMapGoogle('село Кукуево');
	}
}

function initMapYandex() {
	if (!maps.yandex) {
		maps.yandex = new ymaps.Map('map-frame-yandex', {center: [20, 30], zoom: 10});
		setMapYandex('село Кукуево');
	}
}

function setMap(source) {
	var $mode = <выясняется текущий режим, google или yandex>;
	switch ($mode)
	{
	case 'google':
		setMapGoogle(source);
		break;
	case 'yandex':
		setMapYandex(source);
		break;
	}
}

function setMapGoogle(source) {
}

function setMapYandex(source) {
	maps.yandex.geoObjects.removeAll();
	maps.yandex.geoObjects.add(maps['yandex-base']);
	var multiRoute = new ymaps.multiRouter.MultiRoute({referencePoints: [source, 'Москва']}, {boundsAutoApply:true});
	maps.yandex.geoObjects.add(multiRoute);
	multiRoute.events.once('update', function () {
		var routes = multiRoute.getRoutes();
		for (var i = 0, l = routes.getLength(); i < l; i++) {
			var route = routes.get(i);
			if (!route.properties.get('blocked')) {
				multiRoute.setActiveRoute(route);
				route.balloon.open();
				break;
			}
		}
	});
}

$('#map-citylist a').on('click', function(event){
	event.preventDefault();
	setMap($(this).text());
});

$(document).ready(function() {
	initMap();
});


В таком варианты Яндекс-Карты работают нормально — успешно инициализируются и работает построение маршрута.
Но как только я убираю заглушку-return из функции initMapGoogle, как получаю ошибку jQuery.Deferred exception.

Если поменять порядок подключения скриптов (вначале maps.js, затем Карту Google) и добавить в подключаемый скрипт Гугл-Карт параметр callback=initMap, то получаю другую ошибку: Uncaught TypeError: this.setValues is not a function.

Не подскажите, как сделать правильно?
17 янв 18, 16:37    [21114403]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Amiri
Member

Откуда: Pakistan
Сообщений: 716
Alibek B.,

я думаю у вас где-то дублируются переменные типа map или иное. проблем быть не должно.
17 янв 18, 16:43    [21114421]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Да, maps используется где-то в коде гугловских карт.
Переименовал maps в maplist, также добавил new при создании карты (new google.maps.Map). И еще убрал опцию map для маркера.
Теперь ошибок в консоли нет, но на карте отсутствует изображение, есть только серый фон и логотип Google.
Из-за чего такое может быть?

В настройках ключа API я указывал адрес сайта, на котором эти карты используются.
И на всякий случай я вообще убрал эти ограничения, но не помогло.
17 янв 18, 17:07    [21114500]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Как-то себя странно Гугл-Карты ведут.
На мобильном устройстве карта рисуется, правда долго.
А десктопе вместо карты серый экран. Но как только включаю панель разработчика, на карте прорисовывается изображение. Правда позиция не такая, какую я указываю в скрипте инициализации, но недалеко от этого места.
Когда я делал встраиваемую карту, проблем не было. На JS я перешел для того, чтобы ускорить отрисовку маршрута при смене пункта отправления (при использовании встраиваемой карты iframe загружался заново), но что-то вообще не работает.
17 янв 18, 17:28    [21114573]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Amiri
Member

Откуда: Pakistan
Сообщений: 716
Alibek B.,

может кешируется криво.
17 янв 18, 17:36    [21114595]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Есть такой список:
cities = [
	{'Москва': [55.751574, 37.573856]},
	...
];

На основании этого списка добавляю на карту выпадающих список:
items = cities.map(function(item, index, list){
	key = Object.keys(item)[0];
	obj = new ymaps.control.ListBoxItem({data: {content: key, center: item[key]}});
	return obj;
});
var lst = new ymaps.control.ListBox({data:{content:'Выбрать город'}, items:items});

Но почему-то в obj оказывается скаляр (значение), а не объект.
Хотя такой код работает нормально:
items = [
	new ymaps.control.ListBoxItem({data: {content: 'Москва', center: [55.751574, 37.573856]}}),
	...
];

Как нужно правильно использовать ymaps.control.ListBoxItem ?
17 янв 18, 20:36    [21114903]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
С Яндексом разобрался.
С Гуглом частично, нужно было добавить триггер на resize (https://stackoverflow.com/questions/42222130/google-maps-shows-gray-screen-instead-of-map).
17 янв 18, 23:50    [21115137]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Триггер на resize частично помогает, но не всегда.
Карты Google глючат, если контейнер в момент инициализации еще не был виден.
При переключении карт помогает повторная инициализация с небольшой задержкой (400 мс).
Но при загрузке страницы этого недостаточно, потому что карта находится на скрываемой закладке и к моменту загрузки страницы контейнер не виден.

Подскажите, как отловить событие, когда DIV становится видимым?
Я нашел пример с IntersectionObserver, но это на многих браузерах не работает.
Нужно какое-то универсальное решение, которое будет учитывать в том числе и то, что родительский контейнер DIV с картой тоже может быть скрытым.
18 янв 18, 00:43    [21115182]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Судя по всему, определение момента видимости элемента на JS задача нетривиальная.
Универсальный способ только в периодическом опросе по таймеру.
18 янв 18, 08:40    [21115398]     Ответить | Цитировать Сообщить модератору
 Re: Как правильно подключать Яндекс-Карты и Гугл-Карты?  [new]
Alibek B.
Member

Откуда:
Сообщений: 2967
Сделал так:
var maplist = {google:null, yandex:null};
maplist.origins = [
	{'Москва': [50, 30], type: 'столица', area: 'РФ'},
	...
];

function initMap() {
	var $mode = $('#map-mode input:checked').attr('id');
	$mode = $mode.substr(9);
	maplist.mode = $mode;
	$('[id|="map-frame"]').addClass('hidden');
	$('#map-frame-'+$mode).removeClass('hidden');
	if (maplist[$mode]) maplist['refresh-'+$mode] = true;
	maplist['active-frame'] = $('#map-frame-'+maplist.mode);
	var checkRedraw = function (mode,frame) {
		if (frame.is(':visible')) {
			switch (mode)
			{
			case 'google':
				if (maplist.google) google.maps.event.trigger(maplist.google, 'resize');
				break;
			case 'yandex':
				if (maplist.yandex) maplist.yandex.redraw();
				break;
			}
		} else {
			setTimeout(checkRedraw(mode,frame), 250);
		}
	};
	if (maplist['refresh-google']) checkRedraw('google',$('#map-frame-google'));
	if (maplist['refresh-yandex']) checkRedraw('yandex',$('#map-frame-yandex'));
	switch ($mode)
	{
	case 'google':
		maplist['google-frame'] = $('#map-frame-google');
		var checkVisibility = function () {
			var state = maplist['google-frame'].is(':visible');
			if (state) {
				initMapGoogle();
			} else {
				setTimeout(checkVisibility, 250);
			}
		};
		if (!maplist.google) checkVisibility();
		break;
	case 'yandex':
		ymaps.ready(initMapYandex);
		break;
	}
}

function initMapGoogle() {
	if (maplist.google) return;
	var $center = new google.maps.LatLng(43.564393, 41.280583);
	var $options = {zoom: 10, center: $center, mapTypeId: google.maps.MapTypeId.ROADMAP};
	maplist.google = new google.maps.Map(document.getElementById('map-frame-google'), $options);
	searchMapGoogle('село Кукуево');
}

function initMapYandex() {
	if (maplist.yandex) return;
	var ctlControls = ['searchControl','geolocationControl','typeSelector','fullscreenControl','zoomControl'];
	maplist.yandex = new ymaps.Map('map-frame-yandex', {center: [43.564393, 41.280583], zoom: 10, controls: ctlControls});
	var search = maplist.yandex.controls.get('searchControl');
	search.options.set('provider', 'yandex#map');
	search.options.set('kind', 'locality');
	search.options.set('noSelect', false);
	search.options.set('noPlacemark', true);
	search.options.set('noCentering', true);
	search.options.set('placeholderContent', 'Поиск населенного пункта...');
	search.options.set('suppressYandexSearch', true);
	search.options.set('boundedBy', maplist.yandex.getBounds());
	search.events.add('resultselect', function (e) {
		var index = e.get('index');
		var result = search.getResultsArray()[index];
		search.hideResult();
		searchMapYandex(search.getRequestString(), result.geometry.getCoordinates());
	}, this);
	var lstOrigins = maplist.origins.map(function(item, index, list){
		var obj = new ymaps.control.ListBoxItem({options: {type: 'separator'}});
		if (item) {
			var key = Object.keys(item)[0];
			var obj = {content: key, center: item[key]};
			if (item.type) obj.content += ' ('+item.type+')';
			obj = new ymaps.control.ListBoxItem({data: obj, options: {selectOnClick:false}});
		}
		return obj;
	});
	var ctlOrigins = new ymaps.control.ListBox({data:{content:'Выбрать город'}, items:lstOrigins});
	ctlOrigins.events.add('click', function (e) {
		var item = e.get('target');
		if (item != ctlOrigins) {
			searchMapYandex(item.data.get('content'), item.data.get('center'));
			item.getParent().collapse();
		}
	});
	maplist.yandex.controls.add(ctlOrigins);
	searchMapYandex('село Кукуево');
}

function searchMapGoogle(origin, position) {
	var local;
	if (!position)
	{
		for (var i = 0, l = maplist.origins.length; i < l; i++) {
			var item = maplist.origins[i];
			if (!item) continue;
			var name = Object.keys(item)[0];
			if (name == origin)
			{
				position = item[name];
				local = item;
				if (!position)
				{
					if (!item.type) origin = item.type + ' ' + origin;
				}
				break;
			}
		}
	}
}

function searchMapYandex(origin, position) {
	var local;
	if (!position)
	{
		for (var i = 0, l = maplist.origins.length; i < l; i++) {
			var item = maplist.origins[i];
			if (!item) continue;
			var name = Object.keys(item)[0];
			if (name == origin)
			{
				position = item[name];
				local = item;
				if (!position)
				{
					if (!item.type) origin = item.type + ' ' + origin;
				}
				break;
			}
		}
	}
	maplist.yandex.geoObjects.removeAll();
	var multiRoute = new ymaps.multiRouter.MultiRoute({referencePoints: [(position ? position : origin), 'Москва']}, {boundsAutoApply:true});
	maplist.yandex.geoObjects.add(multiRoute);
	multiRoute.events.once('update', function () {
		var routes = multiRoute.getRoutes();
		for (var i = 0, l = routes.getLength(); i < l; i++) {
			var route = routes.get(i);
			if (!route.properties.get('blocked')) {
				multiRoute.setActiveRoute(route);
				route.balloon.open();
				break;
			}
		}
	});
}

// Карты переключаются по нажатию radio-кнопок
$('#map-mode input').on('change', function(event){
	initMap();
});

$(window).resize(function() {
	maplist['refresh-google'] = !$('#map-frame-google').is(':visible')
	maplist['refresh-yandex'] = !$('#map-frame-yandex').is(':visible')
});

$(document).ready(function() {
	initMap();
});

Насколько вижу, все работает во всех режимах (ресайз на скрытой вкладке, долгая загрузка и т.д.). К тому же загрузка скриптов теперь асинхронная.
Буду благодарен за советы по оптимизации и улучшению.
18 янв 18, 09:30    [21115534]     Ответить | Цитировать Сообщить модератору
Все форумы / HTML, JavaScript, VBScript, CSS Ответить