ぐるなびマッシュアップ例

ぐるなびAPIを利用して,地図サービス上で任意の地点をクリックすると,その周囲にある飲食店データをマーカで表示させるサービスを以下に示します.

地図上で任意の地点がクリックされたら,その周囲のデータを表示する


以下は,HTMLファイルのコードです.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="./css/main_mashup.css" />
	
	<script src="http://maps.google.com/maps?file=api&v=2&key=(キーを入力)"
        type="text/javascript" charset="utf-8"></script>
	
	<script type="text/javascript" src="gnavi_mashup.js" charset="utf-8"></script>
	
	<title>Google Maps Event Test Page</title>
</head>
<body>
<br>
<h1>Google Maps Gnavi Mashup Test</h1><br>
<br>
<div id="info"></div>
<div id="mymap" style="width: 900px; height: 750px"></div>
	
</body>
</html>



ウェブサイトはこちら


以下は,JavaScriptのコードです.早稲田界隈の位置情報に設定されています. 保存するファイル名は,上のHTMLコードに設定されているファイル名と一致させます(このサンプルではgnavi_mashup.js). かなり長いため,実際に実行してみる場合はサンプルファイルからコードをコピーして利用することをお勧めします.

var map;
var RANGE = 3;
var MAXHIT = 30;
var ZOOM_SIZE = 16;
var POPDIV_ID = "_shopphoto";


window.onload = function() {
    load();
    setEvent();
}

// Googleマップ初期化
function load() {
    if (GBrowserIsCompatible()) {
        map = new GMap2(document.getElementById("mymap"));
        map.setCenter(new GLatLng(35.71042, 139.710045), 17);
        map.addControl(new GScaleControl());
        map.addControl(new GLargeMapControl());
        map.addControl(new GOverviewMapControl(new GSize(128,128)));
	var screenXY = new GScreenPoint(1, 1, "fraction", "fraction");
    var overlayXY = new GScreenPoint(1, 1, "fraction", "fraction");
    var size = new GScreenSize(155, 20);
	var soverlay = new GScreenOverlay
	("http://apicache.gnavi.co.jp/image/rest/b/api_155_20.gif", screenXY, overlayXY, size);
	map.addOverlay(soverlay);
    }
}


// マーカ作成
function createGMarker(title, html, lat, lng) {
    var infoObj = new Object();
    infoObj.title = title;
    var gpObj = new GLatLng(lat, lng);
    var marker = new GMarker(gpObj, infoObj);
    map.addOverlay(marker);
    GEvent.addListener(marker, "click", function() {
        marker.openInfoWindowHtml(html);
    });
}

// イベントハンドラ設定
function setEvent() {
    GEvent.addListener(map, "click", function(lay, point) {
        if (lay == null) {
            map.clearOverlays();
            _d("info", "*** 検索中 ***");
            var lat = Math.round(chgWgs2TkyLat(point.y, point.x)*100000)/100000;
            var lng = Math.round(chgWgs2TkyLng(point.y, point.x)*100000)/100000;
            var gurunaviUrl = getGurunaviUrl(lat, lng);
            xml2Json(gurunaviUrl,"callBackX2J");
        }
    });
}

// 地図上へのマーカ配置
function setMarkers(res) {
    if (! res.total_hit_count) {
        _d("info", "該当情報が登録されていません.エラー番号:" + res.error.code);
    }
    else {
        _d("info", "検索ヒット数 " + res.total_hit_count + " 件");
        if(res.total_hit_count == 1) {
            shopName = res.rest.name;
            objShop = res.rest;
            createMarker(objShop,shopName);
        }
        else {
            for (shopName in res.rest) {
                objShop = eval("res[\"rest\"][\"" + shopName + "\"]");
                createMarker(objShop,shopName);
            }
        }
    }
}

//地図上に1つのマーカを設置
function createMarker(objShop, shopName) {
    shopName = shopName.replace(/<[ \t]*[Bb][Rr][ \t]*>/, "・");
    var tTitle = createShopTitle(objShop, shopName);
    var tHtml = createShopInfoHtml(objShop, shopName);
    createGMarker(tTitle, tHtml, objShop.latitude, objShop.longitude);
}

//マーカのチップヘルプ
function createShopTitle(objShop, shopName) {
    var sTitle = shopName +
        "(" + errChk(objShop.code.category_name_l.content) +
        ":" + errChk(objShop.code.category_name_s.content) +
        "/" + errChk(objShop.budget) + "円)";
    return sTitle;
}

//情報ウィンドウ内に表示するHTMLコード作成
function createShopInfoHtml(objShop, shopName) {
    var sBody = "<table width=\"480\">" +
        "<tr><th colspan=\"2\">" + shopName + "</th></tr>" +
        "<tr><td>■種別</td><td>" +
        errChk(objShop.code.category_name_l.content) +
        " / " +
        errChk(objShop.code.category_name_s.content) +
        "</td></tr>" +
        "<tr><td>■営業</td><td>" + 
        errChk(objShop.opentime) + " / " +
        errChk(objShop.holiday) + "</td></tr>" +
        "<tr><td>■予算</td><td>" +
        errChk(objShop.budget) + "円</td></tr>" +
        "<tr><td><nobr>■アクセス</nobr></td><td>" +
        errChk(objShop.access.line) + " " +
        errChk(objShop.access.station) + "<br /> ( " +
        errChk(objShop.access.station_exit) + " から " +
        errChk(objShop.access.walk) + "分 ) " +
        "</td></tr>";
        "<tr><td>■住所</td><td>" +
        errChk(objShop.address) + "</td></tr>" +
        "<tr><td>■電話</td><td>" + errChk(objShop.tel) + "</td></tr>";

    if (varChk(objShop.url, "string")) {
        sBody += "<tr><td>■HP</td>" +
            "<td><a href=\"" + objShop.url + "\" target=\"blank\">" +
            objShop.url + "</td></tr>";
    }

    sBody += "<tr><td colspan=\"2\">" + errChk(objShop.pr.pr_long);

    sBody += "</table>";
    return sBody;
}

// 店舗データの特定項目が未定義or空欄だった場合の判定
function errChk(tgd) {
    return varChk(tgd,"string") ? tgd : "---";
}


//ぐるナビデータアクセスURL作成
function getGurunaviUrl(lat, lng) {
    var gurunaviApi = "http://api.gnavi.co.jp/ver1/RestSearchAPI/";
    var gurunaviKey = "(ぐるなびのキーを入力)";
    var queri = gurunaviApi + "?keyid=" + gurunaviKey +
        "&coordinates_mode=2" +
        "&latitude=" + lat +
        "&longitude=" + lng +
        "&range=" + RANGE +
        "&hit_per_page=" + MAXHIT;
    return queri;
}

//APIアクセス中継(XML形式のデータをJSON形式に変換)
function xml2Json(url,callback) {
    var proxyUrl = "http://app.drk7.jp/xml2json/";
    var callUrl = proxyUrl + "var=" + callback + "&url=" + encodeURIComponent(url);
    var script = document.createElement('script');
    script.charset = 'UTF-8';
    script.src = callUrl;
    document.body.appendChild(script);
}

//JSONPコールバック関数

//コールバックオブジェクトを用意して,
var callBackX2J = {}

//そのオブジェクト内のonloadというメソッドに取得したデータを戻す
//メソッド内では受け取ったデータをマップに反映するためのsetMarkersを呼び出す
callBackX2J.onload = function(res) {
    setMarkers(res);
}

//-------------------------------------------------------------------
// 測地系変換(定番)

function chgTky2WgsLng(lat, lng) {
    return (lng - lat * 0.000046038 - lng * 0.000083043 + 0.010040);
}

function chgTky2WgsLat(lat, lng) {
    return (lat - lat * 0.00010695 + lng * 0.000017464 + 0.0046017);
}

function chgWgs2TkyLng(lat, lng) {
    return (lng + lat * 0.000046047 + lng * 0.000083049 - 0.010041);
}

function chgWgs2TkyLat(lat, lng) {
    return (lat + lat * 0.00010696 - lng * 0.000017467 - 0.0046020);
}

//-------------------------------------------------------------------

// htmlコード挿入
function _d(id, htmlTxt) {
    document.getElementById(id).innerHTML = htmlTxt;
}

// divブロック挿入
function createDiv(id,left,top) {
    var outDiv;
    outDiv =document.createElement('div');
    outDiv.id = id;
    document.body.appendChild(outDiv);

    var tgdStyle = document.getElementById(id).style;
    tgdStyle.position = "absolute";
    tgdStyle.left = left + "px";
    tgdStyle.top = top + "px";
    tgdStyle.background = "white";
}


function varChk(tgd,type) {
    return typeof(tgd) == type ? true : false;
}


ウェブサイトはこちら

測地系変換については,以下が参考になります.

測地系

Google Mapでは緯度・経度を世界測地系(WGS 84測地系)で扱っていますが,ぐるなびへのリクエストは日本測地系で受け入れる仕様となっています.従って,測地系変換のための関数を使って調整を行います.更に,Math.round関数で,緯度経度の値を小数点以下6桁までで四捨五入しています(小数点以下が長いとエラーになります).


以下は,cssのコードです.保存する場所に注意してください.HTMLファイルの中の記述と対応付けます.

body {
    font-size: 9pt;
    color: #808080;
}

div#info {
    width: 565px;
    height: 24px;
    background-color: white;
    color: black;
    margin: 4px 0px;
    padding-top: 4px;
    font-size: 13pt;
    text-align: left;
}

div#mymap {
    width: 720px;
    height: 512px;
}

td {
    font-size: 9pt;
    vertical-align: top;
    border-bottom: solid #c0c0c0 2px;
    padding: 4px 0px;
    color: #404040;
}

th {
    font-size: 12pt;
}

span {
    border-bottom: solid red 1px;
    cursor: pointer;
}

div#photocnt {
    padding: 8px;
    border: solid black 1px;
    font-size: 9pt;
    color: #808080;
}



ウェブサイトはこちら


完成版ウェブサイトはこちら

演習課題