HOME
デルタラボ.
Google Maps APIでお店のランキング表示をしてみると
Google Maps APIでお店のランキング表示をしてみると(1/3)
技術情報 JavaScript Google Maps 作り方
更新日:2019/03/22
この記事は、2020年1月22日に一部内容を見直し再編集しました。
お腹がすいた。この辺でどこか評判がいいレストランはないかな?
では、Googleで検索っと!
Googleには、お店の口コミ情報が集まっていて、5段階評価の星表示もお店選びには役立ちますね。
欲を言うなら、評価順にランキング表示ができたら、サクッと評判のよいお店が探せるのに。
ということで今回は、Google Maps APIを使用して、お店のランキング表示をしてみましょう!
お店ランキング表示の流れ
お店情報探しに、Google検索ではなく、なぜGoogle Mapsを使うかというと、Google Maps APIを使った検索では「特定のポイントから半径○メートル圏内」といった検索指定ができるからです。
こうした位置情報を使った検索は、Google Mapsが得意ですね。
お店ランキング表示をするのに必要な機能は、
検索エリアの位置情報を取得
指定ポイントから半径○メートルのお店情報を取得
お店情報を評価順に並べて表示
です。
検索エリアの位置情報を取得
住所から位置情報(緯度・経度)を取得するには、Google Maps APIの『ジオコーディング』を使います。
こちらは以前にテーマとして取り上げていますので、詳しくは過去記事にて!
【おさらい!】
【住所⇔緯度・経度】位置情報の相互変換
皆さん、住所から緯度・経度、緯度・経度から住所を知りたいことってありますよね?
地図と連携したサービスを考えた時には必要になってくる技術です。
今回はGoogle Maps APIを使用して、住所変換遊びをしてみましょ!
技術情報 JavaScript Google Maps 作り方
指定ポイントから半径○メートルのお店情報を取得
お店情報を検索するのに必要なAPIは
Map JavaScript API
Places API
Geocoding API
です。
お店検索をするAPIの本体は「Places API」ですが、JavaScriptから呼び出すために「Map JavaScript API」を介すことになります。
「Geocoding API」は、住所から緯度・経度を取得するのに必要です。
Google API コンソール で、この3つを有効化しておきましょう。
では、指定のポイントから半径○メートル以内のお店情報を取得していきます!
【サンプル1】 住所(ランドマーク名)→緯度・経度→お店情報
★結果★
【サンプル1ソース】
<table>
<tr>
<td>検索場所:</td><td><input type="text" id="addressInput" value="近江町市場" style="width: 200px"></td>
</tr>
<tr>
<td>KeyWord:</td><td><input type="text" id="keywordInput" value="寿司" style="width: 200px"></td>
</tr>
<tr>
<td colspan="2" style="padding: 10px">
<input type="button" value="お店情報取得" onclick="getPlaces();">
</td>
</tr>
</table>
★結果★<br />
<div id="results" style="width: 100%; height: 200px; border: 1px dotted; padding: 10px; overflow-y: scroll; background: white;"></div>
<script src="https://maps.googleapis.com/maps/api/js?key=xxxxxxxxxx&libraries=places"></script>
<script type="text/javascript">
var placesList;
/*
お店情報取得
*/
function getPlaces(){
//結果表示クリア
document.getElementById("results").innerHTML = "";
//placesList配列を初期化
placesList = new Array();
//入力した検索場所を取得
var addressInput = document.getElementById("addressInput").value;
if (addressInput == "") {
return;
}
//検索場所の位置情報を取得
var geocoder = new google.maps.Geocoder();
geocoder.geocode(
{
address: addressInput
},
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
//取得した緯度・経度を使って周辺検索
startNearbySearch(results[0].geometry.location);
}
else {
alert(addressInput + ":位置情報が取得できませんでした。");
}
});
}
/*
位置情報を使って周辺検索
latLng : 位置座標(google.maps.LatLng)
*/
function startNearbySearch(latLng){
//読み込み中表示
document.getElementById("results").innerHTML = "Now Loading...";
//Mapインスタンス生成
var map = new google.maps.Map(
document.createElement("div")
);
//PlacesServiceインスタンス生成
var service = new google.maps.places.PlacesService(map);
//入力したKeywordを取得
var keywordInput = document.getElementById("keywordInput").value;
//周辺検索
service.nearbySearch(
{
location: latLng,
radius: 800,
type: ['restaurant'],
keyword: keywordInput,
language: 'ja'
},
displayResults
);
}
/*
周辺検索の結果表示
※nearbySearchのコールバック関数
results : 検索結果
status : 実行結果ステータス
pagination : ページネーション
*/
function displayResults(results, status, pagination) {
if(status == google.maps.places.PlacesServiceStatus.OK) {
//検索結果をplacesList配列に連結
placesList = placesList.concat(results);
//pagination.hasNextPage==trueの場合、
//続きの検索結果あり
if (pagination.hasNextPage) {
//pagination.nextPageで次の検索結果を表示する
//※連続実行すると取得に失敗するので、
//1秒くらい間隔をおく
setTimeout(pagination.nextPage(), 1000);
//pagination.hasNextPage==falseになったら
//全ての情報が取得できているので、
//結果を表示する
} else {
//placesList配列をループして、
//結果表示のHTMLタグを組み立てる
var resultHTML = "<ol>";
for (var i = 0; i < placesList.length; i++) {
place = placesList[i];
//ratingがないのものは「---」に表示変更
var rating = place.rating;
if(rating == undefined) rating = "---";
//表示内容(評価+名称)
var content = "【" + rating + "】 " + place.name;
resultHTML += "<li>";
resultHTML += content;
resultHTML += "</li>";
}
resultHTML += "</ol>";
//結果表示
document.getElementById("results").innerHTML = resultHTML;
}
} else {
//エラー表示
var results = document.getElementById("results");
if(status == google.maps.places.PlacesServiceStatus.ZERO_RESULTS) {
results.innerHTML = "検索結果が0件です。";
} else if(status == google.maps.places.PlacesServiceStatus.ERROR) {
results.innerHTML = "サーバ接続に失敗しました。";
} else if(status == google.maps.places.PlacesServiceStatus.INVALID_REQUEST) {
results.innerHTML = "リクエストが無効でした。";
} else if(status == google.maps.places.PlacesServiceStatus.OVER_QUERY_LIMIT) {
results.innerHTML = "リクエストの利用制限回数を超えました。";
} else if(status == google.maps.places.PlacesServiceStatus.REQUEST_DENIED) {
results.innerHTML = "サービスが使えない状態でした。";
} else if(status == google.maps.places.PlacesServiceStatus.UNKNOWN_ERROR) {
results.innerHTML = "原因不明のエラーが発生しました。";
}
}
}
</script>
【編集注】
Places APIの結果が英語で取得されることが多くなったため、nearbySearchにパラメータ「language:'ja'」を追加しました。
サンプル1では、金沢・近江町市場の中心地から半径800m以内のレストラン情報を、「寿司」に絞って検索してみました。
リストに表示しているのは、rating(評価)とname(名称)です。
この時点では、評価順に並んでいない ことに注目してください。
サンプル1のソースをポイント解説していきます。
[18行目]
<script src="https://maps.googleapis.com/maps/api/js?key=xxxxxxxxxx&libraries=places"></script>
「Map JavaScript API」から「Places API」を利用するために、
「libraries=places」 のパラメータが必要です。
[64〜70行目]
//Mapインスタンス生成
var map = new google.maps.Map(
document.createElement("div")
);
//PlacesServiceインスタンス生成
var service = new google.maps.places.PlacesService(map);
new google.maps.places.PlacesService で「Places API」のサービスインスタンスを生成します。引数は、new google.maps.Mapで取得したMapインスタンスです。
new google.maps.Mapの引数は、地図表示するためのコンテナとなるdivタグですが、画面に地図を表示する必要がない場合は、「document.createElement("div")」で生成したdiv要素を渡すだけで事足ります。
[75〜85行目]
//周辺検索
service.nearbySearch(
{
location: latLng,
radius: 800,
type: ['restaurant'],
keyword: keywordInput,
language: 'ja'
},
displayResults
);
指定範囲周辺の施設情報を取得するには、「Places API」の
nearbySearch を使用します。
第1引数は検索条件を、第2引数にはコールバック関数を指定します。
<検索条件>
location : 中心位置の緯度・経度(google.maps.LatLng)を指定します。指定必須です。
radius :検索範囲を半径○メートルで指定します。指定必須です。
type :施設情報の種類を指定します。
keyword :キーワードを指定して、検索結果を絞り込むことができます。
language :検索結果の言語を指定します。
typeに指定できる種類は複数あるので、目的に合わせて指定するとよいでしょう。
⇒ Place Types Places API Google Developers
[95行目]
function displayResults(results, status, pagination) {
nearbySearchのコールバック関数の引数は、
results :検索結果
status :実行結果ステータス
pagination :ページネーション
です。
resultsに、検索結果の施設情報が『連想配列』で格納されています。
<連想配列イメージ>
results[0].name = "あいうえ寿司"
results[0].rating = 3.5
:
results[1].name = "かきくけ寿司"
results[1].rating = 4.0
[97〜114行目]
if(status == google.maps.places.PlacesServiceStatus.OK) {
//検索結果をplacesList配列に連結
placesList = placesList.concat(results);
//pagination.hasNextPage==trueの場合、
//続きの検索結果あり
if (pagination.hasNextPage) {
//pagination.nextPageで次の検索結果を表示する
//※連続実行すると取得に失敗するので、
// 1秒くらい間隔をおく
setTimeout(pagination.nextPage(), 1000);
//pagination.hasNextPage==falseになったら
//全ての情報が取得できているので、
//結果を表示する
} else {
実行結果ステータスが"OK"ならば、1件以上の検索結果が取得できています。
ここで、nearbySearchの検索結果の仕様で、知っておかなければいけない重要なポイントがあります。
それは
「最大60件取得可能で、20件ずつ取得される」 ということ。
21件目以降は、コールバック関数の第3引数である
pagination (ページネーション)を使って、ページ遷移しながら取得する必要があります。
pagination.hasNextPage==true の場合、「続きの検索結果あり」と判断できます。
今取得できた検索結果をplacesList配列変数に退避しつつ、
pagination.nextPage() をコールします。
すると、コールバック関数(displayResults)が再び呼び出され、その時のresultsの内容が次の20件のものに変化しているという仕組みです。
pagination.nextPage() を実行する時は、
「連続実行すると上手く取得できない」 というハマリポイントがあるのでご注意を!
setTimeoutなどを使って、1秒くらい間隔をおいて実行すると上手くいきます。
pagination.nextPage()を繰り返し、
pagination.hasNextPage==false になったら、「全ての情報が取得できた」と判断できます。
placesList配列変数に記憶しておいた検索結果から、HTMLを組み立てて表示します。
さて、「Places API」のnearbySearchメソッドを使って、指定の場所から半径○メートル以内のお店情報を取得できました。
ランキング表示するために、次は「お店情報を評価順に並べる」必要がありますね!