这是一个相当详细的问题,让我先解释一下情况,然后介绍我的实现以及最后的问题,这样你就可以更好地理解了。
截至4月4日,更新了内容,问题已被缩小到一项未解决的问题,请查看问题底部的最新信息。
TLDR;
我从Google Maps Directions API获得了一个长路线,并希望为该路线创建一个高程图。但很遗憾,它无法正常工作,因为它是通过GET请求获取的,而URL的最大长度为2048个字符,此长度已超过。我将请求分开;使用Promises确保了正确的处理顺序;但完整路线的高程数据并不总是完整的,也不总是按正确顺序显示,也不总是沿着给定路径走,并且间隔有时跨越几公里。
简介;
尝试为Google Maps DirectionsService响应创建一个高程图,我遇到了一个太长的路线问题(这似乎与距离无关,而是与每个overview_path的LatLngs数量有关)。这是由于ElevationService是通过GET
请求的,而URL的最大长度为2048个字符引起的。这个问题在这里也有描述。
实现;
我想我比Google更聪明(其实不是,但至少试图找到一种解决方法),将DirectionsService返回的路径(overview_path
属性)分成批次并连接结果(通过ElevationService方法getElevationsAlongPath
返回的elevations
)。
- 为了获得最佳详细级别,我使用每个批次512个样本查询ElevationService;
- 由于ElevationService将样本分散在路径的长度上,因此我设置了每个批次的最大
LatLng
数量,并检查需要处理完整路径的批次数(totalBatches=overview_path.length/maxBatchSize
); - 最后,在我的Directions结果中获得均匀分布,以尝试获得完整路线的相等详细级别(
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个或更少的路标,我仍然面临同样的问题。
问题;
我正在遇到以下问题:
- 高程数据并未始终沿着路径完全显示,这意味着图表中的最后一个高程点(远离)不在路径的末端;
- 高程数据有时会按随机顺序显示,好像promise仍在等待下一个任务执行一样;
- 高程数据并未始终按照给定的批次中提供的
overview_path
中的LatLng
依次显示(请参见屏幕截图); - 相邻高程距离数据很多。有时要跨越数公里,而请求512个样本以匹配均匀的批处理大小,每个批处理最多具有200个
LatLng
。
我发现使用Promise(在setTimtout之前计时)对ElevationService进行批处理将解决我的所有问题,但我只解决了一项问题,即不超过2.048个char的请求URL,并且面临上述新问题。
非常感谢您的帮助
此外,我想提前放置250 rep。悬赏问题,但当前不可能。因此,请随意回复,因为我以后可以添加赏金并授予解决所述问题的答案。我已经授予250 rep。赏金,显示我对您指导我正确方向的赞赏。
感谢您的阅读和回复!
更新于4月4日,留下1个未解决的问题(据我目前所知)
处理高程随机排序问题
当我注意到路线结果的不一致行为时,我能够解决一些问题。这是由于异步调用未被“Promised”以安排,因此有些情况下顺序是正确的,大多数情况下则不是。一开始我没有注意到这一点,因为标记显示正确(缓存)。
解决相邻高程距离问题
显示高程数据的div宽度仅为300px,包含了许多数据点。由于这么小的宽度,我根本无法悬停在足够的点上引发距离彼此更远的高程点。
未沿路线显示高程数据的问题
不知何时何处我也解决了此问题,但我不确定较大的宽度或“Promising”方向顺序是否解决了此问题。
待处理问题:高程数据不完整
唯一剩下的问题是高程数据并不总是覆盖整个路径。我认为这是 Promising 逻辑中的错误,因为在控制台记录了一些信息后,发现高程图表在未完成所有 Promise-then 的情况下绘制,我认为这是由于 Google Maps API 返回 Over Query Limit 错误时重新触发批量调用导致的。
当出现 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();
}
});
});
}