这是一个有点细节的问题,所以让我先解释一下情况,然后是我的实现,最后是这个问题,这样你就明白了。
自 4 月 4 日起,添加了更新,并将问题缩小到一个未决问题,请参阅此问题的底部以获取最新信息。
TLDR;
我从 Google Maps Directions API 返回了一条很长的路线,并且想要该路线的高程图。太糟糕了,它不起作用,因为它是通过 GET 请求的,并且 URL 最大长度是 2.048 个字符,超出了。我拆分了请求;使用 Promises 保证正确的处理顺序;但海拔数据并不总是完整的完整路线,并不总是以正确的顺序显示,并不总是遵循给定的路径,而且海拔间的位置有时跨越几公里。
介绍;
尝试为 Google Maps DirectionsService 响应创建高程图时,我遇到了路线太长的问题(这似乎与距离无关,而不是与每个 overview_path 的 LatLng 数有关)。这是因为 ElevationService 是通过请求的,GET
并且 URL 的最大长度为 2048 个字符。这个问题也在 SO here 上进行了描述。
执行;
我想我会比谷歌更聪明(不是真的,但至少试图找到一种解决方法),将 DirectionsService(overview_path
属性)返回的路径分成批次并连接结果(elevations
由 ElevationService 方法返回getElevationsAlongPath
) .
- 为了获得最佳细节水平,我使用每批 512 个样本查询 ElevationService;
- 因为 ElevationService 将样本分布在路径的长度上,所以我设置了
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 个或更少航点的问题。
问题;
我面临的问题是:
- 高程数据并不总是遵循路线的完整路径,这意味着图表中的最后一个高程点距离路线末端(远);
- 海拔数据有时会以随机顺序显示,就好像 Promise 似乎还没有等待下一个任务执行一样;
- 海拔数据并不总是遵循给定批次
LatLng
中overview_path
提供的给定数据(见截图); - 高程距离数据很多。有时跨越多个公里,同时请求 512 个样本以获得均匀匹配的批次大小,
LatLng
每批次最多 200 秒。
我认为使用 Promises 批处理 ElevationService(以及在使用 setTimtout 计时之前)可以解决我所有的问题,但我解决的唯一问题是不超过 2.048 字符请求 URL 并面临上述新问题。
非常感谢帮助
另外我想提出250个代表。就在这个问题上的赏金,但目前这是不可能的。因此,请随时回复,因为我稍后可以添加赏金并将其奖励给解决所描述问题的答案。250 代表。赏金已被授予以感谢您为我指明正确的方向。
感谢阅读和回复!
4 月 4 日更新,留下 1 个未决问题(据我目前所知)
解决了随机顺序高程的问题
当我注意到方向结果中的不一致行为时,我已经能够解决一些问题。这是由一个明显的原因引起的:异步调用不是“承诺”安排的,所以有时顺序是正确的,大多数时候不是。起初我没有注意到这一点,因为标记显示正确(缓存)。
解决了高程距离问题
显示高程数据的 div 只有 300 像素宽,并且包含许多数据点。由于宽度如此之小,我根本无法将鼠标悬停在足够多的点上,从而导致触发彼此相距较远的高程点。
高程数据未沿路线显示的问题
不知何故,我也解决了这个问题,但我不确定更大的宽度或“有希望”的方向顺序是否解决了这个问题。
待解决的问题:高程数据并不总是完整的
唯一剩下的问题是高程数据并不总是覆盖完整路径。我相信这是因为 Promising 逻辑中的错误,因为在控制台中记录一些消息告诉我海拔图是在并非所有 Promise-then 完成的点绘制的,我认为这是由于在 Over 时重新触发批处理调用引起的Google Maps API 返回查询限制错误。
当返回 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();
}
});
});
}