これはある程度詳細な質問です。最初に状況を説明し、次に私の実装を説明し、最後に質問をして理解を深めてください。
4 月 4 日の時点で更新が追加され、問題は 1 つの保留中の問題に絞り込まれています。最新情報については、この質問の下部を参照してください。
TLDR;
Google Maps Directions API から返された長いルートがあり、そのルートの標高チャートが必要です。残念ながら、GET 経由で要求され、URL の最大長が 2.048 文字を超えているため、機能しません。リクエストを分割しました。Promises を使用して正しい処理順序を保証します。しかし、標高データはルート全体で常に完全であるとは限らず、常に正しい順序で表示されるとは限らず、常に指定されたパスに従っているとは限らず、標高間の位置が数 km にまたがることがあります。
序章;
Google Maps DirectionsService レスポンスの標高チャートを作成しようとしていますが、ルートが長すぎるという問題に直面しています (これは、overview_path ごとの LatLng の数ではなく、距離に関連していないようです)。これは、ElevationService が 経由でリクエストGET
され、URL の最大長が 2048 文字であることが原因です。この問題はSO here にも記載されています。
実装;
overview_path
私は、DirectionsService (プロパティ) によって返されたパスをバッチに分割し、結果 ( elevations
ElevationService メソッドによって返されたgetElevationsAlongPath
)を連結するために、Google よりも賢く (実際にはそうではありませんが、少なくともそれを回避する方法を見つけようとしている) と考えました。.
- 最良の詳細レベルを取得するために、バッチごとに 512 サンプルで ElevationService をクエリします。
- また、ElevationService はサンプルをパスの長さに分散させるため、バッチごとの最大数を設定し
LatLng
、フル パスを処理するために必要なバッチの数を確認します (totalBatches = overview_path.length / maxBatchSize
)。 - 最終的にルート案内を均等に広げると、完全なルートについて同じレベルの詳細を取得しようとします (
batchSize = Math.ceil(overview_path.length / totalBatches)
)。
ElevationService は非同期的に動作しますが、最初に setTimout を使用し、現在は Promises を使用している他の SO ユーザーの助けを借りて、すべての要求が正しい順序で処理されるようにしています。
私のコード
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);
});
}
サイドノート;
サービスが持つ 8 つのウェイポイントの制限に対処するために、DirectionService のリクエストもバッチ処理していますが、8 つ以下のウェイポイントの問題にも直面しているため、これが問題ではないことを確認できます。
問題;
私が直面している問題は次のとおりです。
- 標高データは常にルートの完全なパスに従っているとは限りません。つまり、チャートの最後の標高ポイントはルートの終点から (遠く) 離れています。
- 次のタスクの実行を約束がまだ待っていないように見えるかのように、標高データがランダムな順序で表示されることがあります。
- 標高データは、特定のバッチで提供された特定
LatLng
の に常に従うとは限りません(スクリーンショットを参照)。overview_path
- 標高間距離データはたくさんあります。
LatLng
バッチごとに最大 200 秒の均等に一致するバッチ サイズの 512 サンプルを要求している間、複数の km にまたがることがあります。
Promises を使用して (および setTimtout でタイミングを合わせる前に) ElevationService をバッチ処理すると、すべての問題が解決すると考えましたが、解決した唯一の問題は、2.048 文字のリクエスト URL を超えず、上記の新しい問題に直面していることです。
助けていただければ幸いです
また、250レップを入れたいと思います。すぐにこの質問に報奨金を出しますが、現時点ではそれは不可能です。後で報奨金を追加して、記載されている問題を解決した回答に報奨金を授与できますので、お気軽に返信してください。250レップ。報奨金は、私を正しい方向に向けてくれたあなたへの感謝を示すために授与されました.
読んで返信してくれてありがとう!
4 月 4 日に更新され、保留中の問題が 1 つ残っています (現時点でわかる限り)。
ランダムな順序での標高の問題に取り組みました
ルート検索結果の動作に一貫性がないことに気付いたとき、いくつかの問題に取り組むことができました。これは明らかな理由で発生しました。非同期呼び出しがスケジュールされることが「約束」されていなかったため、順序が正しい場合もあれば、そうでない場合もありました。マーカーが正しく表示されていた (キャッシュされていた) ため、最初はこれに気づきませんでした。
上下間距離の問題に取り組みました
標高データを表示する div は幅が 300 ピクセルしかなく、多くのデータポイントが含まれていました。このように幅が狭いため、十分な数のポイントにカーソルを合わせることができず、互いに離れた位置にある標高ポイントがトリガーされました。
標高データがルートに沿って表示されない問題
どういうわけか、この問題も解決しましたが、幅が広いか、方向の順序が「有望」であるかどうかはわかりません。
保留中の問題: 標高データは必ずしも完全ではありません
唯一残っている問題は、標高データが常に完全なパスをカバーしているとは限らないことです。これは、コンソールにいくつかのメッセージを記録すると、すべての Promise-then が完了していない時点で標高グラフが描画されていることがわかるため、Promising ロジックのエラーが原因であると考えられます。 Query Limit エラーは、Google Maps API によって返されます。
Over Query Limit エラーが返されたときに同じチェーンを再起動するにはどうすればよいですか? 同じ関数を再度解決setTimeout(...)
しないようにしましたが、単に起動しましたが、Promise は再起動されたバッチを解決していないようで、クエリ制限を超えていません。現在、これは私が設定した方法です(方向と仰角の両方について):
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();
}
});
});
}