拆分过大的路径时,Google Maps Elevation Service响应不准确

Ben*_*Ben 8 javascript batch-processing google-maps-api-3 map-directions google-elevation-api

这是一个有一定程度细节的问题,所以让我首先解释一下情况,然后我的实现和最后的问题让你最了解.

截至4月4日,已添加更新,问题范围缩小为一个待处理问题,请参阅此问题的底部以获取最新信息.

TLDR;

我有一条很长的路线从谷歌地图方向API返回,并希望该路线的高程图表.太糟糕了它不起作用,因为它是通过GET请求的,并且URL最大长度是超过2.048个字符.我分开了请求; 使用Promises保证正确的处理顺序; 但是,对于完整路线,Evelation数据并不总是完整的,并不总是按照正确的顺序显示,并不总是遵循给定的路径,并且有时会跨越几公里的高程间隔.

介绍;

尝试为Google Maps DirectionsService响应创建高程图我遇到了路线太长的问题(这似乎与距离无关,而不是每个overview_path的LatLng数量).这是由于通过请求ElevationService GET并且URL的最大长度为2048个字符的事实引起的.这里也描述了这个问题.

实施;

我想我会比谷歌更聪明(不是真的,但至少试图找到一种方法来解决它),分裂由为DirectionsService(返回的路径overview_path属性)为批次,连接结果(elevations通过ElevationService方法返回getElevationsAlongPath) .

  • 为了获得最佳细节,我查询ElevationService每批512个样本;
  • 并且因为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);
    });
}
Run Code Online (Sandbox Code Playgroud)

边注;

我也正在批准DirectionService的请求,以解决该服务所具有的8个航点限制,但我可以确认这不是问题,因为我也遇到了8个或更少航路点的问题.

问题;

我面临的问题是:

  • 高程数据并不总是遵循路径的完整路径,这意味着图表中的最后一个高程点(远离)路径的末端;
  • 高程数据有时会以随机顺序显示,好像似乎承诺仍未等待下一个任务执行;
  • 高程数据doensn't始终遵循给定的LatLng"从S overview_path中一个给定的批量提供(见截图);
  • 高程间距离数据很多.有时跨越多公里,同时请求512个样品,均匀匹配的批量大小,每批最多200 LatLng秒.

高程数据不遵循它被告知遵循的overview_path

我想用分批的承诺ElevationService(与setTimtout时间之前)将解决我所有的问题,但我解决了这个唯一的问题是不超过2.048焦炭请求URL和所面临的上述新问题.

非常感谢帮助

另外我想说250代表.关于这个问题的赏金,但是现在这是不可能的.所以请随时回复,因为我可以稍后添加赏金并将其奖励给解决所述问题的答案.250代表.赏金已被授予我感谢你指出我正确的方向.

感谢阅读和回复!

4月4日更新,留下1个未决问题(据我现在所知)

解决了随机顺序升高的问题

当我注意到路线结果中的不一致行为时,我已经能够解决一些问题.这是由于一个显而易见的原因造成的:异步调用没有"承诺"被安排,所以有些时候订单是正确的,大部分时间都没有.起初我没有注意到这一点,因为标记显示正确(缓存).

海拔高度距离问题被解决了

显示高程数据的div只有300px宽,包含许多数据点.通过如此小的宽度,我根本无法悬停在足够的点上,从而触发彼此远离的高程点.

高程数据未沿路线显示的问题

在某种程度上,我已经解决了这个问题,但我不确定更大的宽度或"有希望"的方向顺序是否解决了这个问题.

待定问题:高程数据并不总是完整的

唯一剩下的问题是高程数据并不总是覆盖整个路径.我相信这是因为在有前途的逻辑错误,因为在控制台登录的一些消息告诉我的高度图表在一个点上画不是所有的承诺,那么的完成,我认为这是由于当再烧制成批呼叫过引起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();
            }
        });
    });
}
Run Code Online (Sandbox Code Playgroud)

Ben*_*Ben 0

最后剩下的问题也已在这个SO问题的帮助下得到解决:How to re-run a javascript Promise when failed? 。因此,如果jfriend00回答了这个问题,我就可以将赏金奖励给他,因为这是最终帮助我摆脱困境的技巧。

为了确保函数在 status 、重试和拒绝解析,我必须将 Promise 逻辑放入函数中并调用该函数,如下所示:OKOVER_QUERY_LIMITany other status

function getRouteElevationChartDataBatchPromise(batch, batchSize) {
    return new Promise(function(resolve, reject) {
        function run(batch, batchSize) {
            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) {
                    routeElevations = routeElevations.concat(elevations);
                    resolve();
                } else if (status == google.maps.ElevationStatus.OVER_QUERY_LIMIT) {                        
                    setTimeout(function () {
                        run(batch, batchSize);
                    }, 200);
                } else {
                    reject(status);
                }
            });
        }

        run(batch, batchSize);
    });
}
Run Code Online (Sandbox Code Playgroud)