Синхронное добавление точек на карту

193
21 февраля 2018, 12:13

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

Не могу придумать способ для добавления точек и по координатам, если они есть, и по адресу, если координат нет. Дело в том, что функция геокодирования Яндекса работает асинхронно, поэтому на карте отображаются только те точки, которые имеют координаты.

var clients = { 
	name: ['Клиент 1', 'Клиент 2', 'Клиент 3', 'Клиент 4', 'Клиент 5', 'Клиент 6', 'Клиент 7'], 
  address: [ 
  	'Российская Федерация, Москва г, Херсонская ул, 43 дом, 7 корп', 
  	'Российская Федерация, Москва г, Лётчика Бабушкина ул, владение 1, строение 27', 
    'Российская Федерация, Москва г, Чермянский проезд, 7, 1', 
    'Российская Федерация, Москва г, Варварка ул, 6', 
    'Российская Федерация, Москва г, Скотопрогонная ул, 29', 
    'Российская Федерация, Москва г, Академика Ландау б-р, 9', 
    'Российская Федерация, Москва г, Татарская ул, 35' 
  ], 
  coordinates: [ 
  	['Нет', 'Нет'], 
  	[37.666557,55.854249], 
   	[37.632664,55.888786], 
   	[37.625729,55.751563], 
   	['Нет', 'Нет'], 
   	[37.553217,55.920381], 
   	['Нет', 'Нет'] 
  ] 
}; 
 
function init () { 
	var myMap = new ymaps.Map('map', { 
  	center: [37.626, 55.750625], 
    zoom: 7, 
    controls: [] 
   }, { 
   	buttonMaxWidth: 300 
	}); 
   
  for(var i = 0; i < clients.name.length; i++){ 
  	// если нет координат, то определяем их 
  	if(clients.coordinates[i][0] == 'Нет' && clients.coordinates[i][1] == 'Нет'){ 
    	var coord = null; 
      ymaps.geocode(clients.address[i]).then( 
				function(res){ 
        	coord = res.geoObjects.get(0).geometry.getCoordinates(); 
        }, 
        function(err){ 
        	console.log('Ошибка геокодирования'); 
        } 
      ); 
      clients.coordinates[i] = coord; 
    } 
    // добавляем точки 
    var point = new ymaps.Placemark(clients.coordinates[i], { 
			balloonContent: clients.name[i] 
		}, { 
			preset: 'islands#violetDotIcon' 
		}); 
    myMap.geoObjects.add(point); 
  } 
  myMap.setBounds(myMap.geoObjects.getBounds()); 
} 
 
ymaps.ready(init);
html, body, #map { 
  width: 100%; height: 100%; padding: 0; margin: 0; 
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<script type="text/javascript" src="https://api-maps.yandex.ru/2.1/?lang=ru_RU&coordorder=longlat"></script> 
<div id="map"></div>

Answer 1

Вам надо использовать Promise.all. Про промисы можно почитать вот тут http://learn.javascript.ru/promise

var clientsPromises = [];
for (var i = 0; i < clients.name.length; i++) {
    // Функции начнут выпоняться после завершения цикла и в этот моммент
    // будет clients.name.length. Обойти это можно или использованием ES6
    // или созданием новой функции.
    clientsPromises.push(loadClient(i));
}
// Ждем когда для всех клиентов или появятся метки или произойдет ошибка
// геокодирования.
ymaps.vow.Promise.all(clientsPromises)
    .then(function (clients) {
        myMap.setBounds(myMap.geoObjects.getBounds());
    });
function loadClient(clientIndex) {
    // Промис, который резолвится координатами клиента.
    var clientCoordinatesPromise;
    var coordinates = clients.coordinates[clientIndex];
    if (coordinates[0] == 'Нет' && coordinates[1] == 'Нет') {
        // Если координат нет, используем геокодирование.
        clientCoordinatesPromise = ymaps.geocode(clients.address[clientIndex])
            .then(function (res) { return res.geoObjects.get(0).geometry.getCoordinates(); })
            .catch(function (err) {
                console.log('Ошибка геокодирования');
                // Для этого клиента координаты определить не удалось.
                return null;
            });
    } else {
        // Для унифицикации дальнейшего кода, если координаты уже есть,
        //  создаем зарезолвившийся ими промис.
        clientCoordinatesPromise = ymaps.vow.resolve(coordinates);
    }
    // Подписываемся на получение координат и создаем метку.
    return clientCoordinatesPromise
        .then(function (coordinates) {
            if (!coordinates) {
                // Игнорируем клиентов без координат.
                return null;
            }
            var point = new ymaps.Placemark(coordinates,
                { balloonContent: clients.name[clientIndex] },
                { preset: 'islands#violetDotIcon' });
            myMap.geoObjects.add(point);
            // Можно вернуть дополнительную информацию.
            // Или вообще ничего не возвращать.
            return { point: point, additional: 42 };
        });
}

Так же советую хранить clients в виде массива с объектами, а вместо 'Нет' для обозначения отсутствия координат использовать null:

[
  { coordinates: null, name: 'Клиент 1', address: 'улица Пушкина' },
  { coordinates: [42, 42], name: 'Клиент 2', address: 'улица Ленина' },
]
READ ALSO
React.js + D3.js - Узлы перекрывают друг друга

React.js + D3.js - Узлы перекрывают друг друга

У меня есть дерево для отображения данныхЗдесь можно увидеть TREE

230
Вывод JSON в Javascript

Вывод JSON в Javascript

Подскажите, как можно передать параметр в функцию с JSON данными, после чего вывести JSON с полученным параметром?

170
Как пометить тип дочернего класса

Как пометить тип дочернего класса

Есть такой кодИ я не могу понять, как описать JSDoc'ом тип дочернего класса

177
Как изображение сделать ссылкой

Как изображение сделать ссылкой

Есть HTML документ, в нем присутствует <img src="

181