Неточный ответ Google Maps Elevation Service при разбиении слишком большого пути
Это небольшой вопрос с некоторым уровнем детализации, поэтому позвольте мне сначала объяснить ситуацию, затем мою реализацию и, наконец, вопрос, чтобы вы лучше поняли.
По состоянию на 4 апреля добавлено обновление, и проблемы сужены до одной нерешенной проблемы, см. Нижнюю часть этого вопроса для получения актуальной информации.
TLDR;
Я получил длинный маршрут, возвращенный из API Google Maps Directions, и хочу получить карту высот для этого маршрута. Жаль, что он не работает, потому что он запрашивается через GET, а максимальная длина URL составляет 2,048 символов, которые превышаются. Я разделил запросы; гарантирует правильную обработку заказа с помощью Promises; но данные Evelation не всегда полны для полного маршрута, не всегда отображаются в правильном порядке, не всегда следуют заданному пути, а расположение мест возвышения иногда превышает несколько километров.
Вступление;
Пытаясь создать диаграмму высот для ответа Google Maps DirectionsService, я столкнулся с проблемой слишком длинных маршрутов (кажется, что это не связано с расстоянием, а не с количеством LatLngs на Overview_path). Это вызвано тем, что ElevationService запрашивается черезGET
и максимальная длина URL составляет 2048 символов. Эта проблемаописано на SO здесь, а также.
Реализация;
Я подумал, что буду умнее, чем Google (не совсем, но, по крайней мере, пытаюсь найти способ обойти это), чтобы разделить путь, возвращаемый DirectionsService (overview_path
собственности) на партии и объединить результаты (elevations
возвращается методом ElevationServicegetElevationsAlongPath
).
LatLng
и проверьте, сколько пакетов требуется для обработки полного пути (totalBatches = overview_path.length / maxBatchSize
);и, наконец, получить равномерный разброс по моим маршрутам, в результате я получаю одинаковый уровень детализации для всего маршрута (batchSize = Math.ceil(overview_path.length / totalBatches)
).Хотя ElevationService работает асинхронно, я проверяю, что все запросы обрабатываются в правильном порядке с помощью других пользователей SO, которые сначала использовали setTimout, а теперь работают с Promises.
Мой код
var maxBatchSize = 200;
var currentBatch = 0;
var promise = Promise.resolve();
var totalElevationBatches = Math.ceil(directions.routes[0].overview_path.length / maxBatchSize);
var batchSize = Math.ceil(directions.routes[0].overview_path.length / totalElevationBatches);
while(currentBatch < totalElevationBatches) {
promise = addToChain(promise, currentBatch, batchSize);
currentBatch++;
}
promise.then(function() {
drawRouteElevationChart(); // this uses the routeElevations to draw an AreaChart
});
function getRouteElevationChartDataBatchPromise(batch, batchSize) {
return new Promise(function(resolve, reject) {
var elevator = new google.maps.ElevationService();
var thisBatchPath = [];
for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
if (j < directions.routes[0].overview_path.length) {
thisBatchPath.push(directions.routes[0].overview_path[j]);
} else {
break;
}
}
elevator.getElevationAlongPath({
path: thisBatchPath,
samples: 512
}, function (elevations, status) {
if (status != google.maps.ElevationStatus.OK) {
if(status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {
console.log('Over query limit, retrying in 250ms');
resolve(setTimeout(function() {
getRouteElevationChartDataBatchPromise(batch, batchSize);
}, 250));
} else {
reject(status);
}
} else {
routeElevations = routeElevations.concat(elevations);
resolve();
}
});
});
}
function addToChain(chain, batch, batchSize){
return chain.then(function(){
console.log('Promise add to chain for batch: ' + batch);
return getRouteElevationChartDataBatchPromise(batch, batchSize);
});
}
Примечание;
Я также пакетирую запрос DirectionService для устранения ограничения 8 путевых точек, которое имеет служба, но я могу подтвердить, что это не проблема, так как я также сталкиваюсь с проблемой с 8 или меньшим количеством путевых точек.
Проблема;
Проблемы, с которыми я сталкиваюсь:
Данные высотных отметок не всегда соответствуют полному пути маршрута, а это означает, что последняя точка высот на карте (далеко) от конца маршрута;Данные о высоте иногда отображаются в случайном порядке, как будто кажется, что обещания все еще не ожидали выполнения следующей задачи;Данные о высотах не всегда соответствуют заданнымLatLng
изoverview_path
предоставляется в данной партии (см. скриншот);Данные о расстоянии между отметками очень много. Иногда охватывает несколько километров при запросе 512 образцов для равномерно подобранного размера партии с максимальным количеством 200LatLng
с за партию.Я полагал, что пакетирование ElevationService с помощью Promises (и до синхронизации с setTimtout) решит все мои проблемы, но единственная проблема, которую я решил, - не превышать URL-адрес запроса 2.048 и сталкиваться с вышеописанными новыми проблемами.
Помощь очень ценится
Также я хотел бы поставить 250 респ. щедрость на этот вопрос прямо сейчас, но это невозможно в данный момент. Поэтому, пожалуйста, не стесняйтесь отвечать, так как позже я смогу добавить награду и наградить ее ответом, который решает описанные проблемы. 250 респ. Награда была вручена, чтобы показать мою признательность за то, что вы указали мне правильное направление.
Спасибо за чтение и ответ!
Обновлено 4 апреля, оставив 1 незавершенный вопрос (насколько я могу судить на данный момент)Проблема с возвышениями в случайном порядке решена
Мне удалось решить некоторые проблемы, когда я заметил непоследовательное поведение в результатах. Это было вызвано очевидной причиной: асинхронные вызовы не были «обещаны», чтобы быть запланированными, поэтому в некоторых случаях порядок был правильным, в большинстве случаев это было не так. Сначала я этого не заметил, потому что маркеры отображались правильно (кэшировались).
Проблема с расстоянием между высотами решена
Div, отображающий данные высот, имел ширину всего 300 пикселей и содержал много точек данных. Из-за такой малой ширины я просто не мог парить над достаточным количеством точек, что приводило к появлению точек возвышения, которые находятся дальше друг от друга.
Проблема с данными о высоте, не отображаемыми по маршруту
Каким-то образом где-то внизу я также решил эту проблему, но я не уверен, что большая ширина или «многообещающий» порядок направлений решил эту проблему.
Нерешенная проблема: данные высот не всегда полны
Единственная оставшаяся проблема заключается в том, что данные высот не всегда охватывают полный путь. Я полагаю, что это связано с ошибкой в логике Promising, поскольку регистрация некоторых сообщений в консоли говорит мне, что диаграмма высот рисуется в точке, где не все Promise-then завершены, и я думаю, что это вызвано повторным вызовом пакетного вызова, когда Over Ошибка лимита запросов возвращается API Карт Google.
Как я могу перефразировать ту же цепочку, когда возвращается ошибка Over Query Limit? Я пытался не разрешать ту же функцию снова, а просто запуститьsetTimeout(...)
, но в этом случае Promise, похоже, не разрешает обновленный пакет в тот момент, когда он больше не получает лимит Over Query Limit. В настоящее время вот как я настроил это (для обоих направлений и высоты):
function getRouteElevationChartDataBatchPromise(batch, batchSize) {
return new Promise(function(resolve, reject) {
var elevator = new google.maps.ElevationService();
var thisBatchPath = [];
for (var j = batch * batchSize; j < batch * batchSize + batchSize; j++) {
if (j < directions.routes[0].overview_path.length) {
thisBatchPath.push(directions.routes[0].overview_path[j]);
} else {
break;
}
}
elevator.getElevationAlongPath({
path: thisBatchPath,
samples: 512
}, function (elevations, status) {
if (status != google.maps.ElevationStatus.OK) {
if(status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {
console.log('ElevationService: Over Query Limit, retrying in 200ms');
resolve(setTimeout(function() {
getRouteElevationChartDataBatchPromise(batch, batchSize);
}, 200));
} else {
reject(status);
}
} else {
console.log('Elevations Count: ' + elevations.length);
routeElevations = routeElevations.concat(elevations);
resolve();
}
});
});
}