AccessにGoogleMapsAPIを埋め込む(3)

データベースとGoogleMapsAPIの連携は、
 1.PHP(もしくは他の言語)にて接続・取得した情報を所定フォーマット(XMLもしくはJSON形式)に出力
 2.それをJavaScript(GoogleMapsAPI)で受け取り、配列に変換するなどしてマップ出力
という形がスタンダードかと思います。

今回のテストでは、JSON形式でやり取りすることにしました。

1.Accessデータベースの情報を取得しJSON出力(PHP)
 プログラムソース(getPlaceData.php)を以下に記載します。

<?php
  $DB_File = "C:\Users\ひつじかい\Documents\GoogleMapsAPI埋め込みテスト.mdb"; //Accessファイル名(フルパス)
  $Database = mb_convert_encoding($DB_File, "SJIS", "UTF-8");
  $User     = "";             //ログインユーザー名
  $Password = "";             //パスワード

  //Accessに接続
  $DSN = "Driver={Microsoft Access Driver (*.mdb)};Dbq=$Database";
  if (!$con = odbc_connect($DSN, $User, $Password)) {
     echo("err:Accessデータベースへの接続に失敗しました。\n");
     exit();
  }

  $places = array();

  //SELECT文を実行し、結果を取得
  $strSQL = "SELECT PlaceCode, PlaceName, ZIP, Address, TEL, Remarks, Lat, Lng FROM M_Place";
  $strSQL .= " WHERE IsNull(Lat) = false AND IsNull(Lng) = false";
  $strSQL .= " ORDER BY PlaceCode";
  $result = odbc_exec($con, $strSQL);

  while ($row = odbc_fetch_array($result)) {
     $place = array();
     foreach ($row as $key => $value){
        $place[$key] = mb_convert_encoding($value, "UTF-8", "SJIS");
     }
     array_push($places,$place);
  }

  //PHP5.2~
  $jsondata = json_encode($places);

  //PHP5.2未満のバージョンではJSONライブラリが標準搭載されていないため、追加で入手・設置する必要があります
  //以下はZend Framework(http://framework.zend.com/)のJSONを使用する場合のコード例
  //require_once('Zend/Json.php'); 
  //$json = new Services_JSON();
  //$jsondata = $json->encode($places);
  //$json = new Services_JSON();
  //$jsondata = $json->encode($places);

  header("Content-Type: text/javascript; charset=utf-8");
  echo $jsondata;
?>

前半のデータベース接続箇所は前回のテストとほぼ同じです。

  $strSQL .= " WHERE IsNull(Lat) = false AND IsNull(Lng) = false";

MAP出力用なので、緯度もしくは経度が入力されていないデータは除外しています(今回のテストデータには全て入力されていますが)。

  while ($row = odbc_fetch_array($result)) {
     $place = array();
     foreach ($row as $key => $value){
        $place[$key] = mb_convert_encoding($value, "UTF-8", "SJIS");
     }
     array_push($places,$place);
  }

この箇所でJSONエンコード用の連想配列を生成しています。22行目の$rowは既に連想配列になっているのですが、Accessから取得したデータは文字コードがShift_JISなので、そのままでは文字化けしてしまいます。
そこで、$rowを各要素毎にUTF-8に変換したものを新たに準備した$placeに再収納しています(23~26行目)。

そして、

  $jsondata = json_encode($places);

とJSON形式にエンコードします。
なお、PHP5.2未満のバージョンではJSONライブラリが標準搭載されていないため、追加で入手・設置する必要があります。
Zend Framework(http://framework.zend.com/)のJSON等を使用する場合は、上記コマンドとは若干異なりますのでご注意ください。

最後に

  header("Content-Type: text/javascript; charset=utf-8");
  echo $jsondata;

と出力することで、Javascript(GoogleMapsAPI)に結果を渡します。
上記のプログラム(getPlaceData.php)を単独で実行すると、以下のような出力が得られます(実際には改行されません)。

[
	{"PlaceCode":"1001","PlaceName":"\u4e2d\u592e\u56f3\u66f8\u9928","ZIP":"183-0055","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u5e9c\u4e2d\u753a2-24","TEL":"042-362-8647","Remarks":"\u30eb\u30df\u30a8\u30fc\u30eb\u5e9c\u4e2d\u5185","Lat":"35.6759578","Lng":"139.4838876"},
	{"PlaceCode":"1002","PlaceName":"\u767d\u7cf8\u53f0\u56f3\u66f8\u9928","ZIP":"183-0011","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u767d\u7cf8\u53f01-60","TEL":"042-360-3443","Remarks":"","Lat":"35.667168","Lng":"139.5061246"},
	{"PlaceCode":"1003","PlaceName":"\u897f\u5e9c\u56f3\u66f8\u9928","ZIP":"183-0031","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u897f\u5e9c\u753a1-10","TEL":"042-360-8998","Remarks":"\u897f\u5e9c\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6709476","Lng":"139.4562688"},
	{"PlaceCode":"1004","PlaceName":"\u6b66\u8535\u53f0\u56f3\u66f8\u9928","ZIP":"183-0042","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u6b66\u8535\u53f02-2","TEL":"042-576-6390","Remarks":"\u6b66\u8535\u53f0\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6886062","Lng":"139.4614882"},
	{"PlaceCode":"1005","PlaceName":"\u65b0\u753a\u56f3\u66f8\u9928","ZIP":"183-0052","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u65b0\u753a1-66","TEL":"042-360-6336","Remarks":"\u65b0\u753a\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6871558","Lng":"139.4893015"},
	{"PlaceCode":"1006","PlaceName":"\u4f4f\u5409\u56f3\u66f8\u9928","ZIP":"183-0034","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u4f4f\u5409\u753a1-61","TEL":"042-360-5775","Remarks":"\u4f4f\u5409\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6603687","Lng":"139.4602852"},
	{"PlaceCode":"1007","PlaceName":"\u662f\u653f\u56f3\u66f8\u9928","ZIP":"183-0014","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u662f\u653f2-20","TEL":"042-360-2882","Remarks":"\u662f\u653f\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6608908","Lng":"139.4953562"},
	{"PlaceCode":"1008","PlaceName":"\u7d05\u8449\u4e18\u56f3\u66f8\u9928","ZIP":"183-0004","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u7d05\u8449\u4e182-1","TEL":"042-360-7227","Remarks":"\u7d05\u8449\u4e18\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6766068","Lng":"139.5092064"},
	{"PlaceCode":"1009","PlaceName":"\u62bc\u7acb\u56f3\u66f8\u9928","ZIP":"183-0012","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u62bc\u7acb\u753a5-4","TEL":"042-483-4122","Remarks":"\u62bc\u7acb\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6537054","Lng":"139.517872"},
	{"PlaceCode":"1010","PlaceName":"\u56db\u8c37\u56f3\u66f8\u9928","ZIP":"183-0035","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u56db\u8c372-75","TEL":"042-360-3663","Remarks":"\u56db\u8c37\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6653238","Lng":"139.4456242"},
	{"PlaceCode":"1011","PlaceName":"\u7247\u753a\u56f3\u66f8\u9928","ZIP":"183-0021","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u7247\u753a2-17","TEL":"042-368-7117","Remarks":"\u7247\u753a\u6587\u5316\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6703378","Lng":"139.4693835"},
	{"PlaceCode":"1012","PlaceName":"\u5bae\u753a\u56f3\u66f8\u9928","ZIP":"183-0023","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u5bae\u753a3-1","TEL":"042-364-3613","Remarks":"","Lat":"35.6688235","Lng":"139.4786725"},
	{"PlaceCode":"1013","PlaceName":"\u751f\u6daf\u5b66\u7fd2\u30bb\u30f3\u30bf\u30fc\u56f3\u66f8\u9928","ZIP":"183-0001","Address":"\u6771\u4eac\u90fd\u5e9c\u4e2d\u5e02\u6d45\u9593\u753a1-7","TEL":"042-336-5702","Remarks":"\u751f\u6daf\u5b66\u7fd2\u30bb\u30f3\u30bf\u30fc\u5185","Lat":"35.6791431","Lng":"139.4964433"}
]

日本語テキスト箇所は「\u4e2d・・・」などとUnicodeエスケープされていますが、この形でJavascriptに引き渡してOKです。

2.JSON形式のデータをJavaScript(GoogleMapsAPI)で受け取りマップ出力
 まずはソースを記載します(mapAccessTest.html)。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta http-equiv="Content-Style-Type" content="text/css">
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">

  var initialLocation = new google.maps.LatLng(35.672154,139.480323); //府中駅
  var initialZoom = 13;                           //ズームレベル
  var markerImage_Normal = 'icon/s_green.png';    //マーカー画像(通常時:緑)
  var markerImage_Selected = 'icon/s_red.png';    //マーカー画像(選択時:赤)
  var currentMarkerNo = -1;                       //選択中のマーカーNo
  var PlaceMarker = new Array();                  //マーカー配列
  var currentInfoWindow = null;                   //情報ウィンドウ

  function initialize() {
     var myOptions = {
        zoom: initialZoom,
        center: initialLocation,
        mapTypeControl: true,
        mapTypeId: google.maps.MapTypeId.ROADMAP
     };
     map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

     PlaceMarker.length = 0;
     getPlaceData();
     //alert(PlaceMarker.length);  //マーカー数
  }

  function getPlaceData() { 
     var objJSON;
     jQuery.ajax({
        url : "getPlaceData.php",
        async : false,
        success: function(res){
           if (res.substring(0,4) == "err:"){
              alert("エラー:"+res.substring(4));
           }else{
              PlaceMarker.length = 0;
              objJSON = eval(res);
             for (var i = 0; i < objJSON.length; i++) {
                  setPlaceMarker(objJSON[i]);
              }
           }
        },
        error: function() {
           alert('データ取得に失敗しました');
        }
     });
  }

  function setPlaceMarker(myPlaceInfo) {
     var markerNo = PlaceMarker.length;
     var myPoint = new google.maps.LatLng(myPlaceInfo.Lat,myPlaceInfo.Lng);
     var myTitle;
     var image = markerImage_Normal;
     PlaceMarker[markerNo] = new google.maps.Marker({
        position: myPoint,
        map: map,
        title: myPlaceInfo.PlaceName,
        icon: image,
        draggable: false
     });
     google.maps.event.addListener(PlaceMarker[markerNo], 'click', function() {
        changeMarkerImages(markerNo);
     });
     PlaceMarker[markerNo].Info = myPlaceInfo;
     google.maps.event.addListener(PlaceMarker[markerNo], 'rightclick', function() {
        setInfoWindow(PlaceMarker[markerNo]);
     });
  }

  function changeMarkerImages(markerNo) {
     if (currentMarkerNo >= 0 && currentMarkerNo !== markerNo) {
        changeMarkerImage(currentMarkerNo,"false");
     }
     currentMarkerNo = markerNo;
     changeMarkerImage(markerNo,"true");
  }

  function changeMarkerImage(markerNo,currentFlag) {
     var dispimage;
     var myMarkerImg;
     if (markerNo >= PlaceMarker.length) {
        return false;
     }
     if (currentFlag == "true") {
        myMarkerImg = markerImage_Selected;
     } else {
        myMarkerImg = markerImage_Normal;
     }
     PlaceMarker[markerNo].setIcon(myMarkerImg);
  }

  function setInfoWindow(myMarker) {
    if (currentInfoWindow) {
       currentInfoWindow.close();
    }
    var contentString =  "<b>"+myMarker.Info["PlaceName"]+"</b><br>"
                        +myMarker.Info["ZIP"]+" "+myMarker.Info["Address"]+"<br>"
                        +"TEL:"+myMarker.Info["TEL"]+"<br>"
                        +myMarker.Info["Remarks"];
    var infoWindow = new google.maps.InfoWindow(
      { content: contentString }
    );
    infoWindow.open(map, myMarker);
    currentInfoWindow = infoWindow;
  }

</script>

</head>

<body onload="initialize()">
  <div id="map_canvas" style="width:100%; height:100%"></div>
</body>
</html>

JSON形式のデータを読み込みは関数getPlaceData(31~51行目)で行っています。
phpで出力したデータの取得には、jQueryの$.ajax関数を利用しています。
非同期通信オプションはasync=falseとして同期通信としました(デフォルトはasync=trueの非同期)。

        async : false,

今回のテストソースでは、どちらでも同じ結果が得られるのですが、参考までに以下の箇所

     //alert(PlaceMarker.length);  //マーカー数

のコメントアウトを外すとasync=false時とtrue時で結果が異なることが分かります。

JSONデータの取り扱いは以下の箇所

              objJSON = eval(res);
             for (var i = 0; i < objJSON.length; i++) {
                  setPlaceMarker(objJSON[i]);
              }

42行目のeval()関数で、オブジェクト(objJSON)に変換し、その要素数回マーカー生成関数(setPlaceMarker)を呼び出しています(43~45行目)。

setPlaceMarker関数(54~73行目)では、マーカーを配列(PlaceMarker)の形で生成させています。
単にMAP表示させるだけであれば配列にする必要はないのですが、配列に収納しておけば複数マーカーに同じ処理を実行したい場合などに利用出来ます。
今回のテストではマーカーのクリック時にアイコンの色を緑色から赤色に変更する(と同時に前回赤色だったマーカーを緑色に戻す)仕組みにしました。
また、JSONデータを正しく取得出来ているかを確認するため、

     PlaceMarker[markerNo].Info = myPlaceInfo;

と、JSONから取得したオブジェクトをPlaceMarker[].Infoに丸ごと収納しておき、右クリック時に情報ウィンドウとして表示させました(setInfoWindow)。

出力イメージは以下のようになります。
MAP出力

図書館の名称や住所等、Unicodeエスケープされていた日本語テキストもきちんと表示出来ています。

 
 
※今回テストで使用したアイコン画像(「icon」ディレクトリに収納)

通常時

s_green.png(通常時)

選択時

s_red.png(選択時)

次回は、このhtmlをAccessに埋め込みます。

コメントはまだありません。

    コメントフォーム

    post date*

     日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

      トラックバックURL: