サンプル・プログラムの実行例
サンプル・プログラムのダウンロード
searchCafe.html | サンプル・プログラム本体。 |
pahooGeoCode.js | 住所・緯度・経度に関わるクラス pahooGeoCode。 |
サンプル・プログラムの流れ
続いて、3つのボタン押下によって、各々 exec, map, clear のアクションを発生する。
execは、「JavaScriptでWebAPIを利用して住所から緯度・経度を求める」と同じで、キーワードから緯度・経度を求める。
mapは、今回のメインプログラムで、詳細は後述する。
clearは、初期化してからmapと同じ処理を行う。
解説:クラスファイル
クラスファイル "pahooGeoCode.js" の配置、各種WebAPI用のアプリケーションIDの設定方法については、「準備、クラスについて」を参照してほしい。
解説:Googleマップ描画
0280: /**
0281: * Googleマップを描く
0282: * @param String id マップID
0283: * @param Float latitude 中心座標:緯度(世界測地系)
0284: * @param Float longitude中心座標:経度(世界測地系)
0285: * @param String type マップタイプ:HYBRID/ROADMAP/SATELLITE/TERRAIN
0286: * @param Integer zoom 拡大率
0287: * @param String call イベント発生時にコールする関数(省略可)
0288: * @param Array items[] 地点情報(省略可能)
0289: * 'title' タイトル
0290: * 'description' 情報ウィンドウに表示する内容
0291: * 'latitude' 緯度
0292: * 'longitude' 経度
0293: * 'icon' アイコンURL
0294: * @return String Googleマップのコード
0295: */
0296: drawGMap(id, latitude, longitude, type, zoom, items=null) {
0297: var map = new google.maps.Map(document.getElementById(id), {
0298: center: new google.maps.LatLng(parseFloat(latitude), parseFloat(longitude)),
0299: zoom: parseInt(zoom),
0300: mapTypeId: type,
0301: mapTypeControl: true,
0302: scaleControl: true
0303: });
0304: map.addListener('dragend', getPointData);
0305: map.addListener('zoom_changed', getPointData);
0306: map.addListener('maptypeid_changed', getPointData);
0307:
0308: //イベント発生時の地図情報を取得・格納
0309: function getPointData() {
0310: var point = map.getCenter();
0311: //経度
0312: if (document.getElementById('longitude') != null) {
0313: document.getElementById('longitude').value = point.lng();
0314: }
0315: //緯度
0316: if (document.getElementById('latitude') != null) {
0317: document.getElementById('latitude').value = point.lat();
0318: }
0319: //ズーム
0320: if (document.getElementById('zoom') != null) {
0321: document.getElementById('zoom').value = map.getZoom();
0322: }
0323: //地図タイプ
0324: if (document.getElementById('type') != null) {
0325: var type_g = map.getMapTypeId();
0326: const types = {'roadmap':'地図', 'satellite':'航空写真', 'hybrid':'ハイブリッド', 'terrain':'地形図'};
0327: for (var key in types) {
0328: if (key == type_g) {
0329: document.getElementById('type').value = key;
0330: break;
0331: }
0332: }
0333: }
0334: }
0335:
0336: if (items != null) {
0337: var n = items.length;
0338: items.forEach(function(item, i) {
0339: if (i <= 26) { //'Z'を超えたらスキップ
0340: //マーカー
0341: var mark = String.fromCodePoint('A'.charCodeAt(0) + i);
0342: var icon_url = (typeof(item.icon) == 'undefined') ? 'https://www.google.com/mapfiles/marker' + mark + '.png' : item.icon;
0343: var marker = new google.maps.Marker({
0344: position: new google.maps.LatLng(item.latitude, item.longitude),
0345: icon: icon_url,
0346: map: map,
0347: title: item.title,
0348: zIndex: 100
0349: });
0350: var infowindow = new google.maps.InfoWindow({
0351: content: item.description,
0352: maxWidth: 200
0353: });
0354: google.maps.event.addListener(marker, 'click', function() {
0355: infowindow.open(map, marker);
0356: });
0357: }
0358: });
0359: }
0360: }
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の入手
0031: //ぐるなびWebサービス アクセスキー:https://api.gnavi.co.jp/api/ で発行
0032: GNAVI_ACCESSKEY = '*************************************';
サンプル・プログラムをダウンロードしたら、定数 GNAVI_ACCESSKEY に自分のアクセスキーを記述する。
解説:ぐるなびWebサービス
0179: /**
0180: * ぐるなびWebサービスのURLを取得する
0181: * @param Float latitude 緯度(世界測地系)
0182: * @param Float longitude 経度(世界測地系)
0183: * @param Float distance 範囲(メートル)
0184: * @param String freeword フリーワード検索(カンマ区切り)
0185: * @return String URL 電源情報APIのURL
0186: */
0187: function getURL_RestSearchAPI(latitude, longitude, distance, freeword) {
0188: var range_tbl = [0, 300, 500, 1000, 2000, 3000];
0189:
0190: var keyid = GNAVI_ACCESSKEY;
0191: range = range_tbl.length;
0192: for (var key = 1; key < range; key++) {
0193: if (distance <= range_tbl[key]) {
0194: range = key;
0195: break;
0196: }
0197: }
0198: freeword = encodeURI(freeword);
0199:
0200: 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;
0201: return url;
0202: }
0203:
0204: /**
0205: * レストラン検索APIを利用して指定座標の近くにある喫茶店を検索
0206: * @param Array items[] 情報を格納する配列
0207: * @param Object pp{error:エラーフラグ,errmsg:エラーメッセージ,
0208: * hits:ヒット件数,webapi:WebAPIのURL}
0209: * @returnなし
0210: */
0211: function searchCafe(items, pp) {
0212: var latitude = parseFloat($('#latitude').val());
0213: var longitude = parseFloat($('#longitude').val());
0214: var distance = parseInt($('#distance').val());
0215: items = [];
0216: var url = getURL_RestSearchAPI(latitude, longitude, distance, '喫茶店');
0217: var n = 0;
0218:
0219: //API呼び出し
0220: var req = new XMLHttpRequest();
0221: req.onreadystatechange = function() {
0222: searchCafe_callback(req, items, pp);
0223: };
0224: req.onreadystatechange = function() {
0225: if (req.readyState == 4) {
0226: if (req.status == 200) {
0227: searchCafe_callback(req.responseText, items, pp);
0228: pp.error = false;
0229: pp.errmsg = '';
0230: } else {
0231: searchCafe_callback(req.responseText, items, pp);
0232: }
0233: }
0234: };
0235: try {
0236: req.open('GET', url, true);
0237: req.send(null);
0238: } catch(e) {
0239: pp.error = true;
0240: pp.errmsg = 'エラー:レストラン検索APIが呼び出せない.';
0241: pp.hits = 0;
0242: searchCafe_callback(null, items, pp);
0243: }
0244: }
0245:
0246: /**
0247: * レストラン検索APIのコールバック関数
0248: * @param String results APIのリターン値
0249: * @param Array items[] 情報を格納する配列
0250: * @param Object pp{error:エラーフラグ,errmsg:エラーメッセージ,
0251: * hits:ヒット件数,webapi:WebAPIのURL}
0252: * @returnなし
0253: */
0254: function searchCafe_callback(results, items, pp) {
0255: if (results != null) {
0256: var json = JSON.parse(results);
0257: var n = 1;
0258: //情報取得
0259: if (json.total_hit_count > 0) {
0260: json.rest.forEach(function(val) {
0261: var obj = new Object();
0262: obj.id = String.fromCodePoint('A'.charCodeAt(0) + n - 1);
0263: obj.title = val.name;
0264: obj.url = val.url;
0265: obj.category = val.category;
0266: obj.phone = val.tel;
0267: obj.opentime = val.opentime.replace(/\n/ui, '<br />');
0268: obj.holiday = val.holiday.replace(/\n/ui, '<br />');
0269: obj.address = val.address.replace(/\n/ui, '<br />');
0270: obj.address = obj.address.replace(/〒[0-9\-]+ /ui, '');
0271: obj.latitude = parseFloat(val.latitude);
0272: obj.longitude = parseFloat(val.longitude);
0273: obj.description = `
0274: <a href="${obj.url}" target="_blank">${obj.title}</a><br />電話:${obj.phone}<br />住所:${obj.address}<br />営業時間:${obj.opentime}<br />定休日:${obj.holiday}
0275: `;
0276: items.push(obj);
0277: n++;
0278: });
0279: pp.error = false;
0280: pp.errmsg = '';
0281: pp.hits = n;
0282:
0283: //エラー
0284: } else if (typeof json.error != 'undefined') {
0285: pp.error = true;
0286: pp.errmsg = 'エラー:' + json.error[0].message;
0287: pp.hits = 0;
0288: }
0289: }
0290: //Googleマップ描画
0291: var zoom = distance2zoom($('#distance').val());
0292: PGC.drawGMap(GMAPID, $('#latitude').val(), $('#longitude').val(), $('#type').val(), zoom, items);
0293:
0294: //一覧表作成
0295: $('#results').html(makeTable(items));
0296:
0297: //エラーメッセージ
0298: $('#errmsg').html(PGC.pp.errmsg);
0299: }
0300:
0301: /**
0302: * レストラン検索APIを利用して指定座標の近くにある喫茶店を検索し
0303: * 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マップ上で喫茶店を検索できるようになる。