サンプル・プログラムの実行例
サンプル・プログラムのダウンロード
searchCafe.html | サンプル・プログラム本体。 |
pahooGeoCode.js | 住所・緯度・経度に関わるクラス pahooGeoCode。 |
サンプル・プログラムの流れ
続いて、3つのボタン押下によって、各々 exec, map, clear のアクションを発生する。
execは、「JavaScriptでWebAPIを利用して住所から緯度・経度を求める」と同じで、キーワードから緯度・経度を求める。
mapは、今回のメインプログラムで、詳細は後述する。
clearは、初期化してからmapと同じ処理を行う。
解説:クラスファイル
クラスファイル "pahooGeoCode.js" の配置、各種WebAPI用のアプリケーションIDの設定方法については、「準備、クラスについて」を参照してほしい。
解説:Googleマップ描画
280: /**
281: * Googleマップを描く
282: * @param String id マップID
283: * @param Float latitude 中心座標:緯度(世界測地系)
284: * @param Float longitude 中心座標:経度(世界測地系)
285: * @param String type マップタイプ:HYBRID/ROADMAP/SATELLITE/TERRAIN
286: * @param Integer zoom 拡大率
287: * @param String call イベント発生時にコールする関数(省略可)
288: * @param Array items[] 地点情報(省略可能)
289: * 'title' タイトル
290: * 'description' 情報ウィンドウに表示する内容
291: * 'latitude' 緯度
292: * 'longitude' 経度
293: * 'icon' アイコンURL
294: * @return String Googleマップのコード
295: */
296: drawGMap(id, latitude, longitude, type, zoom, items=null) {
297: var map = new google.maps.Map(document.getElementById(id), {
298: center: new google.maps.LatLng(parseFloat(latitude), parseFloat(longitude)),
299: zoom: parseInt(zoom),
300: mapTypeId: type,
301: mapTypeControl: true,
302: scaleControl: true
303: });
304: map.addListener('dragend', getPointData);
305: map.addListener('zoom_changed', getPointData);
306: map.addListener('maptypeid_changed', getPointData);
307:
308: //イベント発生時の地図情報を取得・格納
309: function getPointData() {
310: var point = map.getCenter();
311: //経度
312: if (document.getElementById('longitude') != null) {
313: document.getElementById('longitude').value = point.lng();
314: }
315: //緯度
316: if (document.getElementById('latitude') != null) {
317: document.getElementById('latitude').value = point.lat();
318: }
319: //ズーム
320: if (document.getElementById('zoom') != null) {
321: document.getElementById('zoom').value = map.getZoom();
322: }
323: //地図タイプ
324: if (document.getElementById('type') != null) {
325: var type_g = map.getMapTypeId();
326: const types = {'roadmap':'地図', 'satellite':'航空写真', 'hybrid':'ハイブリッド', 'terrain':'地形図'};
327: for (var key in types) {
328: if (key == type_g) {
329: document.getElementById('type').value = key;
330: break;
331: }
332: }
333: }
334: }
335:
336: if (items != null) {
337: var n = items.length;
338: items.forEach(function(item, i) {
339: if (i <= 26) { //'Z'を超えたらスキップ
340: //マーカー
341: var mark = String.fromCodePoint('A'.charCodeAt(0) + i);
342: var icon_url = (typeof(item.icon) == 'undefined') ? 'https://www.google.com/mapfiles/marker' + mark + '.png' : item.icon;
343: var marker = new google.maps.Marker({
344: position: new google.maps.LatLng(item.latitude, item.longitude),
345: icon: icon_url,
346: map: map,
347: title: item.title,
348: zIndex: 100
349: });
350: var infowindow = new google.maps.InfoWindow({
351: content: item.description,
352: maxWidth: 200
353: });
354: google.maps.event.addListener(marker, 'click', function() {
355: infowindow.open(map, marker);
356: });
357: }
358: });
359: }
360: }
PHPプログラムではマーカーを静的に発生させていたが、JavaScript版ではメソッドの後半で、引数 items にforEachループをかけ、動的にマーカーを発生させている。forループを使って実装すると、new でマーカー・オブジェクトを追加生成する処理がうまくいかないので、あえてforEachループを使っている。
「ぐるなびWebサービス:レストラン検索API」による店舗探索
URL |
---|
https://api.gnavi.co.jp/RestSearchAPI/v3/ |
フィールド名 | 要否 | 内 容 |
---|---|---|
keyid | 必須 | ぐるなびより提供されたアクセスキー |
input_coordinates_mode | 任意 | 入力パラメータに含まれる緯度/経度の測地系を指定 1:日本測地系 2:世界測地系(デフォルト) |
latitude | 任意 | 検索地点の緯度(小数表記) |
longitude | 任意 | 検索地点の経度(小数表記) |
coordinates_mode | 任意 | レスポンスに含まれる緯度/経度の測地系を指定 1:日本測地系 2:世界測地系(デフォルト) |
range | 任意 | 緯度/経度からの検索範囲(半径) 1:300m、2:500m(デフォルト)、3:1000m、4:2000m、5:3000m |
freeword | 任意 | 検索ワードをUTF-8でURLエンコードすること「,」区切りで複数ワードが検索可能(10個まで) |
フィールド名 | 内 容 | |
---|---|---|
@attributes | api_version | APIのバージョン |
total_hit_count | 該当件数 | |
hit_per_page | 表示件数 | |
page_offset | 表示ページ | |
total_hit_count | 表示ページ | |
rest[] | id | 店舗ID |
update_date | 情報更新日時 | |
name | 店舗名 | |
name_kana | 店舗名称(カタカナ) | |
latitude | 緯度(小数表記) | |
longitude | 経度(小数表記) | |
category | フリーワードカテゴリー | |
url | PCサイトURL | |
url_mobile | 携帯サイトURL | |
address | 住所 | |
tel | 電話番号 | |
opentime | 営業時間 | |
holiday | 休業日 |
アプリIDの入手
31: //ぐるなびWebサービス アクセスキー:http://api.gnavi.co.jp/api/ で発行
32: GNAVI_ACCESSKEY = '*************************************';
サンプル・プログラムをダウンロードしたら、定数 GNAVI_ACCESSKEY に自分のアクセスキーを記述する。
解説:ぐるなびWebサービス
179: /**
180: * ぐるなびWebサービスのURLを取得する
181: * @param Float latitude 緯度(世界測地系)
182: * @param Float longitude 経度(世界測地系)
183: * @param Float distance 範囲(メートル)
184: * @param String freeword フリーワード検索(カンマ区切り)
185: * @return String URL 電源情報APIのURL
186: */
187: function getURL_RestSearchAPI(latitude, longitude, distance, freeword) {
188: var range_tbl = [0, 300, 500, 1000, 2000, 3000];
189:
190: var keyid = GNAVI_ACCESSKEY;
191: range = range_tbl.length;
192: for (var key = 1; key < range; key++) {
193: if (distance <= range_tbl[key]) {
194: range = key;
195: break;
196: }
197: }
198: freeword = encodeURI(freeword);
199:
200: url = 'https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid=' + keyid + '&input_coordinates_mode=2&coordinates_mode=2&latitude=' + latitude + '&longitude=' + longitude + '&range=' + range + '&freeword=' + freeword;
201: return url;
202: }
203:
204: /**
205: * レストラン検索APIを利用して指定座標の近くにある喫茶店を検索
206: * @param Array items[] 情報を格納する配列
207: * @param Object pp{error:エラーフラグ,errmsg:エラーメッセージ,
208: * hits:ヒット件数,webapi:WebAPIのURL}
209: * @return なし
210: */
211: function searchCafe(items, pp) {
212: var latitude = parseFloat($('#latitude').val());
213: var longitude = parseFloat($('#longitude').val());
214: var distance = parseInt($('#distance').val());
215: items = [];
216: var url = getURL_RestSearchAPI(latitude, longitude, distance, '喫茶店');
217: var n = 0;
218:
219: //API呼び出し
220: var req = new XMLHttpRequest();
221: req.onreadystatechange = function() {
222: searchCafe_callback(req, items, pp);
223: };
224: req.onreadystatechange = function() {
225: if (req.readyState == 4) {
226: if (req.status == 200) {
227: searchCafe_callback(req.responseText, items, pp);
228: pp.error = false;
229: pp.errmsg = '';
230: } else {
231: searchCafe_callback(req.responseText, items, pp);
232: }
233: }
234: };
235: try {
236: req.open('GET', url, true);
237: req.send(null);
238: } catch(e) {
239: pp.error = true;
240: pp.errmsg = 'エラー:レストラン検索APIが呼び出せない.';
241: pp.hits = 0;
242: searchCafe_callback(null, items, pp);
243: }
244: }
245:
246: /**
247: * レストラン検索APIのコールバック関数
248: * @param String results APIのリターン値
249: * @param Array items[] 情報を格納する配列
250: * @param Object pp{error:エラーフラグ,errmsg:エラーメッセージ,
251: * hits:ヒット件数,webapi:WebAPIのURL}
252: * @return なし
253: */
254: function searchCafe_callback(results, items, pp) {
255: if (results != null) {
256: var json = JSON.parse(results);
257: var n = 1;
258: //情報取得
259: if (json.total_hit_count > 0) {
260: json.rest.forEach(function(val) {
261: var obj = new Object();
262: obj.id = String.fromCodePoint('A'.charCodeAt(0) + n - 1);
263: obj.title = val.name;
264: obj.url = val.url;
265: obj.category = val.category;
266: obj.phone = val.tel;
267: obj.opentime = val.opentime.replace(/\n/ui, '<br />');
268: obj.holiday = val.holiday.replace(/\n/ui, '<br />');
269: obj.address = val.address.replace(/\n/ui, '<br />');
270: obj.address = obj.address.replace(/〒[0-9\-]+ /ui, '');
271: obj.latitude = parseFloat(val.latitude);
272: obj.longitude = parseFloat(val.longitude);
273: obj.description = `
274: <a href="${obj.url}" target="_blank">${obj.title}</a><br />電話:${obj.phone}<br />住所:${obj.address}<br />営業時間:${obj.opentime}<br />定休日:${obj.holiday}
275: `;
276: items.push(obj);
277: n++;
278: });
279: pp.error = false;
280: pp.errmsg = '';
281: pp.hits = n;
282:
283: //エラー
284: } else if (typeof json.error != 'undefined') {
285: pp.error = true;
286: pp.errmsg = 'エラー:' + json.error[0].message;
287: pp.hits = 0;
288: }
289: }
290: //Googleマップ描画
291: var zoom = distance2zoom($('#distance').val());
292: PGC.drawGMap(GMAPID, $('#latitude').val(), $('#longitude').val(), $('#type').val(), zoom, items);
293:
294: //一覧表作成
295: $('#results').html(makeTable(items));
296:
297: //エラーメッセージ
298: $('#errmsg').html(PGC.pp.errmsg);
299: }
300:
301: /**
302: * レストラン検索APIを利用して指定座標の近くにある喫茶店を検索し
303: * Googleマップにマッピングし、一覧表を表示する
「JavaScriptでWebAPIを利用して住所から緯度・経度を求める」と同様、非同期処理になるため、APIから戻ってくるJSONの処理はコールバック関数 searchCafe_callback で行う。
関数 searchCafe_callback では、WebAPIの応答を JSON.parse を使って解釈し、オブジェクト配列 items に格納してゆく。
Googleマップに描画する際に必要になるので、要素 description には、店舗名、電話番号、住所、営業時間、定休日とリンク先URLをハイパーリンクする。
最後に、Googleマップへの描画、一覧表の作成、エラーメッセージの表示を行い、コールバックを完了する。
参考サイト
- ぐるなびWebサービス:レストラン検索API
- PHPで「ぐるなび」を使って喫茶店を探す:ぱふぅ家のホームページ
- JavaScriptでWebAPIを利用して住所から緯度・経度を求める:ぱふぅ家のホームページ
そこで今回は、「PHPで『ぐるなび』を使って喫茶店を探す」で紹介したPHPサーバサイド・プラグラムを、JavaScriptを使ってクライアント・サイドに移植してみる。PHP環境が無くてもブラウザさえあれば、Googleマップ上で喫茶店を検索できるようになる。