地図について#5

ひつじかいさんの「ひつじかいの雑記帳」というブログを拝見し、その中に、地図の描写において色々と興味深い記事を拝読しました。これは自分でもやってみたい、そう思い、その記録を記載してみたいと思います。

Web上で操作可能な日本の白地図(都道府県別)を作る(5) ― クリックした都道府県をペイント ―

前回までの情報をもとに、GoogleMap上に日本の白地図を描いていきます。

まずMapOptionsオブジェクトの.stylesプロパティを記載通りに設定してみます。

これは問題なく上手く行くのですが、Optionの[backgroundColor]設定ではほんの一瞬、白くなるのですが、その後に背景が表示されていまうようです(このキャプチャを撮るのに苦労しました…)。

ひつじかいさんの内容に従い、大きい白い土台を記載し、その上に日本地図を記載していきます。またクリック時に、その対象都道府県を塗りつぶしていきます。

色の指定は、[Spectrum]を用いています。サンプルを拝見しますと、これは簡単そうです。としてHTMLとしては次の通りです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
    <title>都道府県の輪郭表示 ~Web上で操作可能な日本の白地図(都道府県別)を作る~</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
    <meta http-equiv="Content-Style-Type" content="text/css">
    <!-- Google map-->
    <script
        src="http://maps.google.com/maps/api/js?key=[your_key]&language=ja&libraries=geometry"></script>
    <script type="text/javascript" src="http://code.google.com/apis/gears/gears_init.js"></script>
    <script type="text/javascript" src="js/jquery.js"></script>
    <script type="text/javascript" src="js/spectrum.js"></script>
    <link rel='stylesheet' href='css/spectrum.css'>
    <script type="text/javascript" src="js/blankmap.js"></script>

</head>

<body style="margin:0px;" onload="initialize()">
    <div id="top_bar" style="background-color:#333399;padding:5px;">
        <table>
            <tr>
                <th class="map_title" id="map_title" name="map_title" style="font-size: 16px;color: #FFFFFF;">
                    都道府県の輪郭を指定した色でペイント ~Web上で操作可能な日本の白地図(都道府県別)を作る~</td>
            </tr>
        </table>
        <form id="f_paintmenu" name="f_paintmenu">
            <table>
                <tr>
                    <td style="font-size:12px;color:#FFFFFF;padding-left:10px;">都道府県:
                        <select id="f_pref" name="f_pref" style="width:100px;font-size:12px;">
                        </select>
                    </td>
                    <td style="font-size:12px;color:#FFFFFF;padding-left:10px;">色の指定:
                        <input type='text' id="f_colorpicker" value="#FF0000">
                    </td>
                    <td style="padding-left:10px;">
                        <input type="button" style="width:80px;font-size:14px;" id="btnPaintPref" name="btnPaintPref"
                            onclick="paintPref(document.getElementById('f_pref').value,document.getElementById('f_colorpicker').value)"
                            value="ペイント">
                    </td>
                </tr>
            </table>
        </form>
    </div>
    <div id="map_canvas" style="margin:5px;"></div>
</body>

</html>

JavaScriptであるblankmap.jsは次の通り。

// *************************************************************** 
//  ~Web上で操作可能な日本の白地図(都道府県別)を作る~ 
//
//  テスト:都道府県ポリゴンを指定した色でペイント
//
// *************************************************************** 

var map;
var myPolyPref = new Array();
var OkinawaLine;

function initialize() {

   setDivSize();
   getPrefList();
   setColorPicker();

   var iniCenter = new google.maps.LatLng(37,138);
   var iniZoom = 6;

   var styleAllOFF = [
      {
         featureType: 'all',
         stylers: [
            {visibility: 'off'},
         ],
      }
   ];

   var myOptions = {
      zoom: iniZoom,
      center: iniCenter,
      backgroundColor: '#ffffff',
      styles: styleAllOFF
   };
   map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

   drawRectangle();
   getPrefBorder();

}

//ウィンドウサイズに合わせて地図サイズを調整
function setDivSize() {

   var w = 1024; //デフォルト値
   var h = 768;  //デフォルト値
   if (window.innerWidth) {
      w = window.innerWidth;
      h = window.innerHeight;
   } else if (document.all) {
      if (document.documentElement.clientWidth) {
         w = document.documentElement.clientWidth;
         h = document.documentElement.clientHeight;
      } else if (document.body.clientWidth) {
         w = document.body.clientWidth;
         h = document.body.clientHeight;
      }
   } else {
      return false;
   }

   var divTop = document.getElementById("top_bar").style;
   var divMain = document.getElementById("map_canvas").style;
   var divHeightTop = 60;

   divTop.height = divHeightTop + "px";
   divMain.width = (w - 20) + "px";
   divMain.height = (h - divHeightTop - 20) + "px";

}

//都道府県リストの取得
function getPrefList() { 

   var fldPref = document.getElementById("f_pref");
   var txtOption = "<option value='0' SELECTED >--------</option>";

   var json;
   jQuery.ajax({
      url : "getdatajson.php?",
      type : "get",
      async : false,
      data: "mode=preflist",
      success: function(request){
              var res = request;
              if (res.substring(0,4) == "err:"){
                 alert("エラー:"+res.substring(4));
              }else{
                 json = JSON.parse(res);
                 for (var i = 0; i < json.length; i++) {
                    txtOption += "<option value='"+json[i].PrefectureCode+"'"
                    if (fldPref.value == json[i].PrefectureCode) {
                       txtOption += " SELECTED";
                    }
                    txtOption += " >"+json[i].PrefectureName+"</option>"
                 }
              }
      },
      error: function() {
              alert('都道府県リストの取得に失敗しました');
      }
   });
   fldPref.innerHTML = txtOption;
} 

//都道府県輪郭データの取得
function getPrefBorder() { 

   var json;
   jQuery.ajax({
      url : "getdatajson.php?",
      type : "get",
      async : false,
      data: "mode=border",
      success: function(request){
              var res = request;
              if (res.substring(0,4) == "err:"){
                 alert("エラー:"+res.substring(4));
              }else{
                 json = JSON.parse(res);
                 setPolygon(json); 
              }
      },
      error: function() {
              alert('都道府県輪郭データの取得に失敗しました');
      }
   });
} 

//ポリゴン描画
function setPolygon(myBorderPoints) {

   var polyCoordsArray = new google.maps.MVCArray();

   myPolyPref.length = 0;
   var polyCoordsPref = new Array();

   for (var i = 1; i <= 47; i++) {
      polyCoordsPref[i] = new google.maps.MVCArray();
   }

   for (var p = 0; p < myBorderPoints.length; p++) {
      var prefCode = parseInt(myBorderPoints[p][0].PrefectureCode);
      var polyCoords = new google.maps.MVCArray();
      
      if (prefCode == 47) {
         moveLocation(myBorderPoints[p],5,15); 
      }
      for (var i = 0; i < myBorderPoints[p].length; i++) {
         polyCoords.push( new google.maps.LatLng(myBorderPoints[p][i].Lat, myBorderPoints[p][i].Lng));
      }
      polyCoordsArray.push(polyCoords);
      polyCoordsPref[prefCode].push(polyCoords);
   }

   for (var i = 1; i <= 47; i++) {
      myPolyPref[i] = new google.maps.Polygon({
         paths: polyCoordsPref[i],
         strokeColor: "#666666",
         strokeOpacity: 1.0,
         strokeWeight: 1,
         fillColor: "#FFFFFF",
         zIndex: 1,
         fillOpacity: 1.0
      });
      myPolyPref[i].setMap(map);
      myPolyPref[i].set("PrefectureCode", i);

      google.maps.event.addListener(myPolyPref[i], "click", function(event) {
         var prefFld = document.getElementById("f_pref");
         for(var j = 0; j < prefFld.length; j++) {
            if (parseInt(prefFld.options[j].value) == this.PrefectureCode) {
               prefFld.options[j].selected = true;
            } else {
               prefFld.options[j].selected = false;
            }
         }
         var fColor = document.getElementById("f_colorpicker").value;
         paintPref(this.PrefectureCode,fColor);
      });

      google.maps.event.addListener(myPolyPref[i], "rightclick", function(event) {
         var fColor = "#ffffff";
         paintPref(this.PrefectureCode,fColor);
      });

      google.maps.event.addListener(myPolyPref[i], "mouseover", function(event) {
         this.setOptions({strokeWeight: 2.0});
      });

      google.maps.event.addListener(myPolyPref[i], "mouseout", function(event) {
         this.setOptions({strokeWeight: 1.0});
      });
   }
}

//沖縄県の場所を移動(スペースの都合。白地図によくあるケース)
function moveLocation(myPoints,my,mx) {

   for (var i = 0; i < myPoints.length; i++) {
       myPoints[i].Lat = parseFloat(myPoints[i].Lat) + my;
       myPoints[i].Lng = parseFloat(myPoints[i].Lng) + mx;
   }

   //実際の位置から移動していることを示すライン
   if (!OkinawaLine && parseInt(myPoints[0].PrefectureCode)==47) {
      var OkinawaLineCoords = [
         new google.maps.LatLng(25.7+my, 126.3+mx),
         new google.maps.LatLng(26.7+my, 126.3+mx),
         new google.maps.LatLng(27.7+my, 127.8+mx),
         new google.maps.LatLng(27.7+my, 129.3+mx)
      ];
      OkinawaLine = new google.maps.Polyline({
         path: OkinawaLineCoords,
         strokeColor: "#808080",
         strokeOpacity: 1.0,
         strokeWeight: 1.5,
         zIndex: 1
      });
      OkinawaLine.setMap(map);
   }
}

//都道府県の領域(ポリゴン)を指定した色でペイント
function paintPref(prefcode,fcolor) {
   if (parseInt(prefcode) > 0) {
      myPolyPref[parseInt(prefcode)].setOptions({fillColor: fcolor});
   }
}

//巨大な矩形で地図全体を覆う(背景の設定)
function drawRectangle() {

   var rectangle = new google.maps.Rectangle();
   var rectBounds = new google.maps.LatLngBounds(
            new google.maps.LatLng(-90.0, -180),
            new google.maps.LatLng(90.0, 180));
   var rectOptions = {
      strokeColor: "#FFFFFF",
      strokeOpacity: 1.0,
      strokeWeight: 0.0,
      fillColor: "#FFFFFF",
      fillOpacity: 1.0,
      zIndex: 0,
      map: map,
      bounds: rectBounds
   };
   rectangle.setOptions(rectOptions);

}

//カラーピッカー(Spectrum)の設定
function setColorPicker() {

   var fld = document.getElementById("f_colorpicker");

   $(function(){
      $("#f_colorpicker").spectrum({
        color: fld.value,
        showInput: true,
        showInitial: true,
        showPalette: true,
        showSelectionPalette: true,
        preferredFormat: "hex",
        chooseText: "OK",
        cancelText: "Cancel",
        palette: [
           ["#000000", "#434343", "#666666", "#999999", "#b7b7b7", "#cccccc", "#d9d9d9", "#efefef", "#f3f3f3", "#ffffff"],
           ["#980000", "#ff0000", "#ff9900", "#ffff00", "#00ff00", "#00ffff", "#4a86e8", "#0000ff", "#9900ff", "#ff00ff"],
           ["#e6b8af", "#f4cccc", "#fce5cd", "#fff2cc", "#d9ead3", "#d9ead3", "#c9daf8", "#cfe2f3", "#d9d2e9", "#ead1dc"],
           ["#dd7e6b", "#ea9999", "#f9cb9c", "#ffe599", "#b6d7a8", "#a2c4c9", "#a4c2f4", "#9fc5e8", "#b4a7d6", "#d5a6bd"],
           ["#cc4125", "#e06666", "#f6b26b", "#ffd966", "#93c47d", "#76a5af", "#6d9eeb", "#6fa8dc", "#8e7cc3", "#c27ba0"],
           ["#a61c00", "#cc0000", "#e69138", "#f1c232", "#6aa84f", "#45818e", "#3c78d8", "#3d85c6", "#674ea7", "#a64d79"],
           ["#85200c", "#990000", "#b45f06", "#bf9000", "#38761d", "#134f5c", "#1155cc", "#0b5394", "#351c75", "#741b47"],
           ["#5b0f00", "#660000", "#783f04", "#7f6000", "#274e13", "#0c343d", "#1c4587", "#073763", "#20124d", "#4c1130"]
        ]

      });
   })
}

そしてJavaScriptからaJaxで呼び出されているPHPスクリプトである[getdatajson.php]は次の通り。

<?php

ini_set('memory_limit', '1024M');

$msg = "";
$jsondata = "";
$mysqli = connectDBi($msg);

if ($mysqli) {
    if (isset($_REQUEST["mode"])) {
        if ($_REQUEST["mode"] == "border") {
            if (getPrefBorderJSON($mysqli, $jsondata)) {
                header("Content-Type: text/javascript; charset=utf-8");
                print $jsondata;
            } else {
                print "err:都道府県輪郭線データの取得に失敗しました。";
            }
        } else if ($_REQUEST["mode"] == "preflist") {
            if (getPrefListJSON($mysqli, $jsondata)) {
                header("Content-Type: text/javascript; charset=utf-8");
                print $jsondata;
            } else {
                print "err:都道府県リストの取得に失敗しました。";
            }
        } else {
            print "err:モード設定エラー";
        }
    } else {
        print "err:モードが設定されていません";
    }
    $mysqli->close();
} else {
    print $msg;
}
ini_restore('memory_limit');

exit();

function getPrefBorderJSON($mysqli, &$jsondata)
{

    $p = array();
    $strSQL = "SELECT *";
    $strSQL .= " FROM t_JapanPrefectureBorder";
    $strSQL .= " ORDER BY PrefectureCode, BorderCode, PointNo";
    $former = array();

    $rst = $mysqli->query($strSQL);
    $rcount = $rst->num_rows;
    if ($rcount > 0) {
        while ($col = $rst->fetch_array(MYSQLI_ASSOC)) {
            if (
                !isset($former["PrefectureCode"]) || $col["PrefectureCode"] <> $former["PrefectureCode"]
                || $col["BorderCode"] <> $former["BorderCode"]
            ) {
                if (!isset($cNo)) {
                    $cNo = 0;
                } else {
                    $cNo++;
                }
                $p[$cNo] = array();
            }
            array_push($p[$cNo], $col);
            $former = $col;
        }
    }
    is_null($rst) or $rst->free();

    $jsondata = json_encode($p);

    return true;
}

function getPrefListJSON($mysqli, &$jsondata)
{

    $strSQL = "SELECT PrefectureCode, PrefectureName FROM t_Prefecture";
    $strSQL .= " ORDER BY PrefectureCode";

    $rst = $mysqli->query($strSQL);
    $rcount = $rst->num_rows;
    $pref = array();
    if ($rcount > 0) {
        while ($col = $rst->fetch_array(MYSQLI_ASSOC)) {
            array_push($pref, $col);
        }
    }
    $jsondata = json_encode($pref);

    is_null($rst) or $rst->free();

    return true;
}

//MySQLへ接続
function connectDBi(&$err)
{
    //MySQL 接続情報
    $MySQL_SERVER = "localhost";
    $MySQL_USER = "[user_name]";
    $MySQL_PASSWORD = "[password]";
    $MySQL_DBNAME = "map";
    $err = "";
    $mysqli = new mysqli($MySQL_SERVER, $MySQL_USER, $MySQL_PASSWORD, $MySQL_DBNAME);
    if ($mysqli->connect_errno) {
        $err = "データベース接続に失敗しました。";
    }
    if (strlen($err) > 0) {
        return false;
    } else {
        return $mysqli;
    }
}

これを実行させると次の通りです。ひつじかいさんの内容通り、沖縄県の位置が配慮され、クリックすると指定した色で塗りつぶせます。

ひつじかいさんの内容におけるコピペでそのまま動きます。またプログラムの解説も、ひつじかいさんのブログに詳しく記載されています。参考になります。