ひつじかいさんの「ひつじかいの雑記帳」というブログを拝見し、その中に、地図の描写において色々と興味深い記事を拝読しました。これは自分でもやってみたい、そう思い、その記録を記載してみたいと思います。
Web上で操作可能な日本の白地図(都道府県別)を作る(6) ― データをGeoJSON形式にする ―
今回はMySQLのデータをGeoJSONコードに落として、DBを使わず、スタンドアロンでも使用できるようにします。なお現在、国土数値情報でもGeoJSON形式でデータが公開されているようです。
データはMultiPolygonとして、次の様式です。
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "prefcode": "1", "prefname": "北海道" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [141.883998, 45.496344], [141.878319, 45.488176], …, [141.883998, 45.496344], [141.883998, 45.496344] ] ], [ [ [141.188495,45.2545], [141.178855,45.24859], …, [141.197514,45.258546], [141.188495,45.2545] ] ], … ] } },{ "type": "Feature", "properties": { "prefcode": "2", "prefname": "青森県" }, "geometry": { "coordinates": [ … ] } } … ] }
その上で、次のプログラムを実行させました。GeoJSONファイルは生成されるのですが、白地図が表示できません。症状としては、北海道から秋田県(05)までは表示されるのですが、山形県(06)を加えると表示されなくなります。ひつじかいさんのブログにある[blankmap.zip]では正しく表示されるのに、自分の環境で生成したGeoJSONファイルでは表示されません。
<?php $errMsg; $mysqli = connectDBi($errMsg); if ($mysqli) { echo "MySQL接続OK<br>"; } else { echo "MySQL接続NG<br>" . $errMsg; exit(); } $fc = new FeatureCollection; $d2 = 0; // 配列coordinatesの第2層の要素。ポリゴンに穴がある場合は$d2>0となるが、今回扱うデータには存在しないため0で固定 // for ($PrefCode = 1; $PrefCode <= 47; $PrefCode++) { for ($PrefCode = 1; $PrefCode <= 5; $PrefCode++) { $formerPoint = null; $feature = new Feature; $strSQL = "SELECT t_JapanPrefectureBorder.*, t_Prefecture.PrefectureName"; $strSQL .= " FROM t_JapanPrefectureBorder"; $strSQL .= " INNER JOIN t_Prefecture"; $strSQL .= " ON t_JapanPrefectureBorder.PrefectureCode = t_Prefecture.PrefectureCode"; $strSQL .= " WHERE t_JapanPrefectureBorder.PrefectureCode = " . $PrefCode; $strSQL .= " ORDER BY BorderCode, PointNo DESC"; $rst = $mysqli->query($strSQL); while($col = $rst->fetch_array(MYSQLI_ASSOC)) { if (!isset($formerPoint)) { $cNo = 0; $feature->properties = new PrefInfo($col); $feature->geometry = new Geometry("MultiPolygon"); } else if ($formerPoint["BorderCode"]<>$col["BorderCode"]) { $cNo ++; } if (!isset($feature->geometry->coordinates[$cNo])) { $feature->geometry->coordinates[$cNo][$d2] = array(); } array_push($feature->geometry->coordinates[$cNo][$d2],array(floatval($col["Lng"]),floatval($col["Lat"]))); $formerPoint = $col; } $rst->close(); array_push($fc->features,$feature); } if ($mysqli) { $mysqli->close(); } $geojson = json_encode($fc); $geojson = str_replace("}},","}},\n",$geojson); echo $geojson . "<br>"; $path = "json/PrefectureBorder.json"; $fp = fopen($path,'w'); fwrite($fp, $geojson); fclose($fp); echo "終了しました。"; class FeatureCollection { public $type = "FeatureCollection"; public $features = array(); } class Feature { public $type = "Feature"; public $properties; public $geometry; } class Geometry { public $type; public $coordinates = array(); function __construct($type=""){ $this->type = $type; } } class PrefInfo { public $prefcode; public $prefname; function __construct($p){ $this->prefcode = $p["PrefectureCode"]; $this->prefname = $p["PrefectureName"]; } } //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; } }
※06の山形県を加えるとすべて表示されなくなる。
データを確認すると、”coordinates”の最初と最後のデータが一致している必要があるのですが、どうもそれが一致していないようです。そこで”coordinates”の最初と最後のデータを比較し、異なるようであれば最後のデータに最初のデータを付け加えるようプログラムを少し変更してみました。
<?php $errMsg; $mysqli = connectDBi($errMsg); if ($mysqli) { echo "MySQL接続OK<br>"; } else { echo "MySQL接続NG<br>" . $errMsg; exit(); } $fc = new FeatureCollection; $d2 = 0; // 配列coordinatesの第2層の要素。ポリゴンに穴がある場合は$d2>0となるが、今回扱うデータには存在しないため0で固定 for ($PrefCode = 1; $PrefCode <= 47; $PrefCode++) { $formerPoint = null; $feature = new Feature; $strSQL = "SELECT t_JapanPrefectureBorder.*, t_Prefecture.PrefectureName"; $strSQL .= " FROM t_JapanPrefectureBorder"; $strSQL .= " INNER JOIN t_Prefecture"; $strSQL .= " ON t_JapanPrefectureBorder.PrefectureCode = t_Prefecture.PrefectureCode"; $strSQL .= " WHERE t_JapanPrefectureBorder.PrefectureCode = " . $PrefCode; $strSQL .= " ORDER BY BorderCode, PointNo DESC"; $rst = $mysqli->query($strSQL); while ($col = $rst->fetch_array(MYSQLI_ASSOC)) { if (!isset($formerPoint)) { $cNo = 0; $feature->properties = new PrefInfo($col); $feature->geometry = new Geometry("MultiPolygon"); } else if ($formerPoint["BorderCode"] <> $col["BorderCode"]) { //! 最初と最後のデータを確認する... if ($tmp1 <> $tmp2){ array_push($feature->geometry->coordinates[$cNo][$d2], $tmp1); } $cNo++; } if (!isset($feature->geometry->coordinates[$cNo])) { $feature->geometry->coordinates[$cNo][$d2] = array(); $tmp1 = array(floatval($col["Lng"]), floatval($col["Lat"])); } $tmp2 = array(floatval($col["Lng"]), floatval($col["Lat"])); array_push($feature->geometry->coordinates[$cNo][$d2], $tmp2); $formerPoint = $col; } //! 最初と最後のデータを確認する... if ($tmp1 <> $tmp2){ array_push($feature->geometry->coordinates[$cNo][$d2], $tmp1); } $rst->close(); array_push($fc->features, $feature); } if ($mysqli) { $mysqli->close(); } $geojson = json_encode($fc); $geojson = str_replace("}},", "}},\n", $geojson); echo $geojson . "<br>"; $path = "json/PrefectureBorder.json"; $fp = fopen($path, 'w'); fwrite($fp, $geojson); fclose($fp); echo "終了しました。"; class FeatureCollection { public $type = "FeatureCollection"; public $features = array(); } class Feature { public $type = "Feature"; public $properties; public $geometry; } class Geometry { public $type; public $coordinates = array(); function __construct($type = "") { $this->type = $type; } } class PrefInfo { public $prefcode; public $prefname; function __construct($p) { $this->prefcode = $p["PrefectureCode"]; $this->prefname = $p["PrefectureName"]; } } //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; } }
これで正常に表示されるようになりました。