PHPで地図上に円や矩形を描く

(1/1)
ジャスコ釧路店 直進110km」というツイートにインスパイアされ、北海道と他府県の巨艦の違いを地図上に描いてみようと思い立った。

Google マップYahoo!JAPAN マップは、WebAPI 機能として円や矩形を描く機能を備えている。また、地理院地図、オープンストリートマップについては、「PHP で住所・ランドマークから最寄り駅を求める」で紹介した JavaScript ライブラリ Leaflet を使うことで同様の処理が可能となる。
そこで、PHP で中心点と対角点または距離を指定し、中心点と対角点は住所などでの検索を可能とし、地図上に円や矩形を描くプログラムを作っていくことにする。

サンプル・プログラム:実行例

PHPで地図上に円や矩形を描く
Google マップ表示

目次

サンプル・プログラム

圧縮ファイルの内容
drawArea.phpサンプル・プログラム本体
pahooGeoCode.php住所・緯度・経度に関わるクラス pahooGeoCode。
使い方は「PHPで住所・ランドマークから最寄り駅を求める」「PHPで住所・ランドマークから緯度・経度を求める」などを参照。include_path が通ったディレクトリに配置すること。

サンプル・プログラムの流れ

PHPで地図上に円や矩形を描く
  1. 中心点($center)または対角点($diagonal)が指定されていれば、pahooGeoCode::searchPoint3 メソッドを呼び出し、緯度・経度を求める。
  2. 対角点はないが距離($distance)があれば、pahooGeoCode::getPointDistance メソッドを呼び出し、中心から北西へ指定距離だけ離れた地点の緯度・経度を求め、これを対角点とする。
  3. 対角点があるか、または距離がなければ、pahooGeoCode::rhumbLine メソッドを呼び出し、中心と対角点の間の距離(等角航路距離)を計算する。
  4. 以上の計算が終わったら、中心点の存在する象限に応じて矩形の南西端と北東端を計算する。
  5. 地図描画のために必要な変数を代入し、定数 MAPSERVICE の値に応じ、Google マップ、Yahoo!JAPAN マップ、Leaflet の描画スクリプトを生成する。マップごとに、さらに円描画か矩形描画かを場合分けしている。
  6. 生成したスクリプトを pahooGeoCode::drawJSMap メソッドに渡し、画面上に地図と図形を表示する。

準備:pahooGeoCode クラス

0035: class pahooGeoCode {
0036:     var $items;      //検索結果格納用
0037:     var $error;      //エラーフラグ
0038:     var $hits;       //検索ヒット件数
0039:     var $webapi; //直前に呼び出したWebAPI URL
0040: 
0041:     //Google Cloud Platform APIキー
0042:     //https://cloud.google.com/maps-platform/
0043:     //※Google Maps APIを利用しないのなら登録不要
0044:     var $GOOGLE_API_KEY_1 = '**************************';   //HTTPリファラ用
0045:     var $GOOGLE_API_KEY_2 = '**************************';   //IP制限用
0046: 
0047:     //Yahoo! JAPAN Webサービス アプリケーションID
0048:     //https://e.developer.yahoo.co.jp/register
0049:     //※Yahoo! JAPAN Webサービスを利用しないのなら登録不要
0050:     var $YAHOO_APPLICATION_ID = '*****************************';

地図サービスを利用するために、クラスファイル "pahooGeoCode.php" を使用する。組み込み関数  require_once  を使って読めるディレクトリに配置する。ディレクトリは、設定ファイル php.ini に記述されているオプション設定 include_path に設定しておく。
クラスについては「PHP でクラスを使ってテキストの読みやすさを調べる」を参照されたい。

地図として Google マップを利用するのであれば、Google Cloud Platform API キー が必要で、その入手方法は「Google Cloud Platform - WebAPI の登録方法」を、YOLP マップを利用するのであれば、Yahoo! JAPAN Web サービス アプリケーション IDが必要で、その入手方法は「Google Cloud Platform - WebAPI の登録方法」を、それぞれ参照されたい。

準備:地図サービス(WebAPI)の選択

0031: //地図描画サービスの選択
0032: //    0:Google
0033: //    1:Yahoo!JAPAN
0034: //    2:地理院地図・OSM
0035: define('MAPSERVICE', 0);
0036: 
0037: //住所検索サービスの選択
0038: //    0:Google
0039: //    1:Yahoo!JAPAN
0040: //   11:HeartRails Geo API
0041: define('GEOSERVICE', 0);
0042: 
0043: //逆ジオコーディングサービスの選択
0044: //    0:Google
0045: //    1:Yahoo!JAPAN
0046: //   11:HeartRails Geo API
0047: //   21:簡易ジオコーディングサービス
0048: define('REVGEOSERVICE', 21);

表示する地図は、Google マップ、[Yahoo!マップ]blue]、地理院地図・オープンストリートマップ(OSM)から選べる。あらかじめ、定数 MAPSERVIC に値を設定すること。
住所検索サービスは、GoogleYahoo!JAPANHeartRails Geo APIから選べる。あらかじめ、定数 GEOSERVICE に値を設定すること。
逆ジオコーディングサービスは、GoogleYahoo!JAPANHeartRails Geo API簡易ジオコーディングサービスから選べる。あらかじめ、定数 REVGEOSERVICE に値を設定すること。
PHPで地図上に円や矩形を描く
Yahoo!マップ表示
PHPで地図上に円や矩形を描く
地理院地図表示

準備:カラーピッカー Spectrum

0080: //jQueryのフルパス
0081: define('JQUERY', 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js');
0082: 
0083: //カラーピッカー Spectrum のパス
0084: define('SPECTRUM', 'https://www.pahoo.org/common/js/spectrum/');

図形の境界線および塗りつぶしカラーを選択するために、JavaScript ライブラリ Spectrum を利用する。公式サイトからダウンロードしたら、その場所を定数 SPECTRUM に代入しておくこと。
また、jQuery も利用するので、その場所を定数 JQUERY に代入しておくこと。

0107: <script src="{$jquery}"></script>
0108: <script src="{$spectrum}spectrum.js"></script>
0109: <script>
0110: $(function() {
0111:     $("#border_color").spectrum({
0112:         showAlpha: false,
0113:         showPalette: true,
0114:         palette: [
0115:             ["#0000FF", "#FF0000", "#FF00FF"],
0116:             ["#00FF00", "#00FFFF", "#FFFF00"]
0117:         ],
0118:         maxSelectionSize: 4,
0119:         preferredFormat: "hex",
0120:         showInput: true
0121:     });
0122:     $("#fill_color").spectrum({
0123:         showAlpha: true,
0124:         showPalette: true,
0125:         palette: [
0126:             ["rgba(0, 0, 255, 0.3)", "rgba(255, 0, 0, 0.3)", "rgba(255, 0, 255, 0.3)"],
0127:             ["rgba(0, 255, 0, 0.3)", "rgba(0, 255, 255, 0.3)", "rgba(255, 255, 0, 0.3)"],
0128:         ],
0129:         maxSelectionSize: 4,
0130:         preferredFormat: "rgb",
0131:         showInput: true
0132:     });
0133: });

Spectrum の表示は、この部分で設定している。境界色パレットには 8色カラーを、領域色パレットには 8色カラー(透明度 0.3)と透明度スライドバーを用意した。自由に変更可能である。

準備:初期値

0050: //マップの表示サイズ(単位:ピクセル)
0051: define('MAP_WIDTH',  600);
0052: define('MAP_HEIGHT', 600);
0053: //マップID
0054: define('MAPID', 'map_id');
0055: //アイコン(中心)
0056: define('ICON_CENTER', 'http://maps.google.co.jp/mapfiles/ms/icons/red-dot.png');
0057: //アイコン(対角)
0058: define('ICON_DIAGONAL', 'http://labs.google.com/ridefinder/images/mm_20_red.png');
0059: //初期値
0060: define('DEF_LONGITUDE0', 139.766667);      //地図中心(経度)
0061: define('DEF_LATITUDE0',     35.681111);           //    (緯度)
0062: define('DEF_CENTER',     '');                //検索クエリ(center
0063: define('DEF_DIAGONAL',     '');                //     (diagonal
0064: define('DEF_CAT_CENTER', 'address');            //領域中心(カテゴリ)
0065: define('DEF_CAT_DIAGONAL', 'address');            //領域対角(カテゴリ)
0066: define('DEF_LONGITUDE1', 139.766667);      //領域中心(経度)
0067: define('DEF_LATITUDE1',     35.681111);           //    (緯度)
0068: define('DEF_LONGITUDE2', 139.700278);      //領域対角(経度)
0069: define('DEF_LATITUDE2',     35.690833);           //      (緯度)
0070: define('DEF_TYPE',         'roadmap');            //マップタイプ
0071: define('DEF_ZOOM',         12);             //ズーム
0072: define('DEF_FIGURE',     'circle');            //図形タイプ
0073: define('DEF_BORDER_COLOR', '#FF0000');           //境界色
0074: define('DEF_FILL_COLOR', '#FF0000');           //領域色
0075: define('DEF_OPACITY',     0.3);             //透明度

これらの初期値は、プログラム初回起動時、またはリセット・ボタン押下時に採用される値である。自由に変更できる。

Googleマップでの図形描画

0315: /**
0316:  * マーカー設定、フィット機能スクリプト:Googleマップ用
0317:  * @param float $latitude, $longitude 経路の中央点座標(緯度・経度)
0318:  * @param bool  $drag TRUE:ドラッグで再描画する/FALSE:しない(デフォルト)
0319:  * @return string JavaScript
0320: */
0321: function jsDragMarker_Gmap($latitude$longitude$drag=FALSE) {
0322:     $submit = $drag ? 'document.myform.submit();' : '';
0323: 
0324: $js =<<< EOT
0325:     //イベント設定
0326:     document.getElementById('fit').addEventListener('click', fitting, false);
0327: 
0328:     //マーカー設定
0329:     marker_A.setDraggable(true);
0330:     marker_A.addListener('dragend', function() {
0331:         marker_A.setIcon(icon_A);
0332:         marker_A.setDraggable(true);
0333:         latlng = marker_A.getPosition();
0334:         document.getElementById('longitude1').value = latlng.lng();
0335:         document.getElementById('latitude1').value  = latlng.lat();
0336:         document.getElementById('center').value = '';
0337:         document.getElementById('distance').value = '';
0338:         {$submit}
0339:     });
0340: 
0341:     marker_B.setDraggable(true);
0342:     marker_B.addListener('dragend', function() {
0343:         marker_B.setIcon(icon_B);
0344:         marker_B.setDraggable(true);
0345:         latlng = marker_B.getPosition();
0346:         document.getElementById('longitude2').value = latlng.lng();
0347:         document.getElementById('latitude2').value  = latlng.lat();
0348:         document.getElementById('diagonal').value = '';
0349:         document.getElementById('distance').value = '';
0350:         {$submit}
0351:     });
0352: 
0353:     /**
0354:      * 地図を最適サイズにフィットする
0355:      * @param なし
0356:      * @return なし
0357:     */
0358:     function fitting() {
0359:         var lat0, lng0, lat1, lng1;
0360:         var lat = Array();
0361:         var lng = Array();
0362:         lat[0] = document.getElementById('latitude1').value;
0363:         lng[0] = document.getElementById('longitude1').value;
0364:         lat[1] = document.getElementById('latitude2').value;
0365:         lng[1] = document.getElementById('longitude2').value;
0366:         lat[2] = {$latitude};
0367:         lng[2] = {$longitude};
0368: 
0369:         //南西端(lat0, lng0), 北東端(lat1, lng1)を求める
0370:         if (lat[0] <= lat[1]) {
0371:             lat0 = lat[0];
0372:             lat1 = lat[1];
0373:         } else {
0374:             lat0 = lat[1];
0375:             lat1 = lat[0];
0376:         }
0377:         if (lat[2] >= 0) {
0378:             if (lat[0] <= lat[2]) {
0379:                 lng0 = lng[0];
0380:                 lng1 = lng[1];
0381:             } else {
0382:                 lng0 = lng[1];
0383:                 lng1 = lng[0];
0384:             }
0385:         } else {
0386:             if (lat[0] <= lat[2]) {
0387:                 lng0 = lng[1];
0388:                 lng1 = lng[0];
0389:             } else {
0390:                 lng0 = lng[0];
0391:                 lng1 = lng[1];
0392:             }
0393:         }
0394: 
0395:         var bounds = new google.maps.LatLngBounds(new google.maps.LatLng(lat0, lng0), new google.maps.LatLng(lat1, lng1));
0396:         map.fitBounds(bounds);                      //地図表示の最適化
0397:     }
0398: 
0399: EOT;
0400:     return $js;
0401: }

ユーザー関数 jsDragMarker_Gmap は、Google マップにマーカーを設定し、フィット機能を実装するための JavaScript を生成する。

中心点と対角点を示すマーカーはドラッグ可能とし、ドラッグ・イベントをフックし、緯度・経度を form オブジェクトに代入するようにする。

フィット機能は、図形の南西端と北東端を求め、Google マップ API のメソッド fitBounds を呼び出すことで実現している。

0403: /**
0404:  * 円描画スクリプト:Googleマップ用
0405:  * @param int    $id          識別ID
0406:  * @param float  $lat, $lng   中心座標(緯度,経度)
0407:  * @param float  $radius      半径(キロメートル)
0408:  * @param string $color       描画色(RGB)
0409:  * @param string $fillcolor   塗りつぶし色(RGB)
0410:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0411:  * @param int    $weight      線の太さ(省略時=1)
0412:  * @return string JavaScript
0413: */
0414: function jsDrawCircle_Gmap($id$lat$lng$radius$color$fillcolor$opacity=1.0, $weight=1) {
0415:     $radius *= 1000;
0416: $js =<<< EOT
0417: var pcircle{$id} = new google.maps.Circle({
0418:     map: map,
0419:     center: new google.maps.LatLng({$lat}, {$lng}),
0420:     radius: {$radius},
0421:     strokeColor: "#{$color}",
0422:     strokeOpacity: 1.0,
0423:     fillColor: "#{$fillcolor}",
0424:     fillOpacity: {$opacity},
0425:     strokeWeight: {$weight},
0426:     zIndex: 1
0427: });
0428: 
0429: EOT;
0430:     return $js;
0431: }

0433: /**
0434:  * 矩形描画スクリプト:Googleマップ用
0435:  * @param int    $id          識別ID
0436:  * @param float  $lat1, $lng1 北東端の緯度・経度
0437:  * @param float  $lat2, $lng2 南西端の緯度・経度
0438:  * @param string $color       描画色(RGB)
0439:  * @param string $fillcolor   塗りつぶし色(RGB)
0440:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0441:  * @param int    $weight      線の太さ(省略時=1)
0442:  * @return string JavaScript
0443: */
0444: function jsDrawRectangle_Gmap($id$lat1$lng1$lat2$lng2$color$fillcolor$opacity=1.0, $weight=1) {
0445: $js =<<< EOT
0446: var prect{$id} = new google.maps.Rectangle({
0447:     map: map,
0448:     bounds: {
0449:         north: {$lat1},
0450:         south: {$lat2},
0451:         east:  {$lng1},
0452:         west:  {$lng2}
0453:     },
0454:     strokeColor: "#{$color}",
0455:     strokeOpacity: 1.0,
0456:     fillColor: "#{$fillcolor}",
0457:     fillOpacity: {$opacity},
0458:     strokeWeight: {$weight},
0459:     zIndex: 1
0460: });
0461: 
0462: EOT;
0463:     return $js;
0464: }

円や矩形を描画するユーザー関数は、Google マップ API の機能をそのまま呼び出すものである。

Yahoo! JavaScriptマップでの図形描画

0467: /**
0468:  * マーカー設定、フィット機能スクリプト:Yahoo! JavaScriptマップ用
0469:  * @param float $latitude, $longitude 経路の中央点座標(緯度・経度)
0470:  * @param bool $drag TRUE:ドラッグで再描画する/FALSE:しない(デフォルト)
0471:  * @return string JavaScript
0472: */
0473: function jsDragMarker_YOLPmap($latitude$longitude$drag=FALSE) {
0474:     $submit = $drag ? 'document.myform.submit();' : '';
0475: 
0476: $js =<<< EOT
0477:     //イベント設定
0478:     document.getElementById('fit').addEventListener('click', fitting, false);
0479: 
0480:     //マーカー設定
0481:     marker_A.setDraggable(true);
0482:     marker_A.bind('dragend', function() {
0483:         marker_A.setIcon(icon_A);
0484:         marker_A.setDraggable(true);
0485:         latlng = marker_A.getLatLng();
0486:         document.getElementById('longitude1').value = latlng.lng();
0487:         document.getElementById('latitude1').value  = latlng.lat();
0488:         document.getElementById('center').value = '';
0489:         document.getElementById('distance').value = '';
0490:         {$submit}
0491:     });
0492: 
0493:     marker_B.setDraggable(true);
0494:     marker_B.bind('dragend', function() {
0495:         marker_B.setIcon(icon_B);
0496:         marker_B.setDraggable(true);
0497:         latlng = marker_B.getLatLng();
0498:         document.getElementById('longitude2').value = latlng.lng();
0499:         document.getElementById('latitude2').value  = latlng.lat();
0500:         document.getElementById('diagonal').value = '';
0501:         document.getElementById('distance').value = '';
0502:         {$submit}
0503:     });
0504: 
0505:     /**
0506:      * 地図を最適サイズにフィットする
0507:      * @param なし
0508:      * @return なし
0509:     */
0510:     function fitting() {
0511:         var lat0, lng0, lat1, lng1;
0512:         var lat = Array();
0513:         var lng = Array();
0514:         lat[0] = document.getElementById('latitude1').value;
0515:         lng[0] = document.getElementById('longitude1').value;
0516:         lat[1] = document.getElementById('latitude2').value;
0517:         lng[1] = document.getElementById('longitude2').value;
0518:         lat[2] = {$latitude};
0519:         lng[2] = {$longitude};
0520: 
0521:         //南西端(lat0, lng0), 北東端(lat1, lng1)を求める
0522:         if (lat[0] <= lat[1]) {
0523:             lat0 = lat[0];
0524:             lat1 = lat[1];
0525:         } else {
0526:             lat0 = lat[1];
0527:             lat1 = lat[0];
0528:         }
0529:         if (lat[2] >= 0) {
0530:             if (lat[0] <= lat[2]) {
0531:                 lng0 = lng[0];
0532:                 lng1 = lng[1];
0533:             } else {
0534:                 lng0 = lng[1];
0535:                 lng1 = lng[0];
0536:             }
0537:         } else {
0538:             if (lat[0] <= lat[2]) {
0539:                 lng0 = lng[1];
0540:                 lng1 = lng[0];
0541:             } else {
0542:                 lng0 = lng[0];
0543:                 lng1 = lng[1];
0544:             }
0545:         }
0546: 
0547:         var bounds = new Y.LatLngBounds(new Y.LatLng(lat0, lng0), new Y.LatLng(lat1, lng1));
0548:         ymap.drawBounds(bounds);  //地図表示の最適化
0549:     }
0550: 
0551: EOT;
0552:     return $js;
0553: }

ユーザー関数 jsDragMarker_YOLPmap は、Yahoo! JavaScript マップにマーカーを設定し、フィット機能を実装するための JavaScript を生成する。

中心点と対角点を示すマーカーはドラッグ可能とし、ドラッグ・イベントをフックし、緯度・経度を form オブジェクトに代入するようにする。

フィット機能は、図形の南西端と北東端を求め、Yahoo! JavaScript マップのメソッド drawBounds を呼び出すことで実現している。

0555: /**
0556:  * 円描画スクリプト:Yahoo! JavaScriptマップ
0557:  * @param int    $id          識別ID
0558:  * @param float  $lat, $lng   中心座標(緯度,経度)
0559:  * @param float  $radius      半径(キロメートル)
0560:  * @param string $color       描画色(RGB)
0561:  * @param string $fillcolor   塗りつぶし色(RGB)
0562:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0563:  * @param int    $weight      線の太さ(省略時=1)
0564:  * @return string JavaScript
0565: */
0566: function jsDrawCircle_YOLPmap($id$lat$lng$radius$color$fillcolor$opacity=1.0, $weight=1) {
0567: $js =<<< EOT
0568: var pcircle{$id} = new Y.Circle(
0569:     new Y.LatLng({$lat}, {$lng}),
0570:     new Y.Size({$radius}, {$radius}),
0571:     {
0572:         unit: "km",
0573:         strokeStyle: new Y.Style("{$color}", {$weight}, 1.0),
0574:         fillStyle: new Y.Style("{$fillcolor}", null, {$opacity})
0575:     }
0576: );
0577: ymap.addFeature(pcircle{$id});
0578: 
0579: EOT;
0580:     return $js;
0581: }

0583: /**
0584:  * 矩形描画スクリプト:Yahoo! JavaScriptマップ
0585:  * @param int    $id          識別ID
0586:  * @param float  $lat1, $lng1 北東端の緯度・経度
0587:  * @param float  $lat2, $lng2 南西端の緯度・経度
0588:  * @param string $color       描画色(RGB)
0589:  * @param string $fillcolor   塗りつぶし色(RGB)
0590:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0591:  * @param int    $weight      線の太さ(省略時=1)
0592:  * @return string JavaScript
0593: */
0594: function jsDrawRectangle_YOLPmap($id$lat1$lng1$lat2$lng2$color$fillcolor$opacity=1.0, $weight=1) {
0595: $js =<<< EOT
0596: var prect{$id} = new Y.Polygon(
0597:     [
0598:         new Y.LatLng({$lat1}, {$lng1}),
0599:         new Y.LatLng({$lat1}, {$lng2}),
0600:         new Y.LatLng({$lat2}, {$lng2}),
0601:         new Y.LatLng({$lat2}, {$lng1})
0602:     ], {
0603:         strokeStyle: new Y.Style("{$color}", {$weight}, 1.0),
0604:         fillStyle: new Y.Style("{$fillcolor}", null, {$opacity})
0605:     }
0606: );
0607: ymap.addFeature(prect{$id});
0608: 
0609: EOT;
0610:     return $js;
0611: }

円や矩形を描画するユーザー関数は、Yahoo! JavaScript マップの機能をそのまま呼び出すものである。

Leaflet での図形描画

0614: /**
0615:  * マーカー設定、フィット機能スクリプト:Leafletマップ用
0616:  * @param float $latitude, $longitude 経路の中央点座標(緯度・経度)
0617:  * @param bool  $drag TRUE:ドラッグで再描画する/FALSE:しない(デフォルト)
0618:  * @return string JavaScript
0619: */
0620: function jsDragMarker_Leaflet($latitude$longitude$drag=FALSE) {
0621:     $submit = $drag ? 'document.myform.submit();' : '';
0622: 
0623: $js =<<< EOT
0624:     //イベント設定
0625:     document.getElementById('fit').addEventListener('click', fitting, false);
0626: 
0627:     //マーカー設定
0628:     marker_A.dragging.enable();
0629:     marker_A.on('dragend', function(event) {
0630:         var marker = event.target;
0631:         var position = marker.getLatLng();
0632:         marker.setLatLng(new L.LatLng(position.lat, position.lng),{draggable:'true'});
0633:         map.panTo(new L.LatLng(position.lat, position.lng))
0634:         document.getElementById('longitude1').value = position.lng;
0635:         document.getElementById('latitude1').value  = position.lat;
0636:         document.getElementById('center').value = '';
0637:         document.getElementById('distance').value = '';
0638:         {$submit}
0639:     });
0640: 
0641:     marker_B.dragging.enable();
0642:     marker_B.on('dragend', function(event) {
0643:         var marker = event.target;
0644:         var position = marker.getLatLng();
0645:         marker.setLatLng(new L.LatLng(position.lat, position.lng),{draggable:'true'});
0646:         map.panTo(new L.LatLng(position.lat, position.lng))
0647:         document.getElementById('longitude2').value = position.lng;
0648:         document.getElementById('latitude2').value  = position.lat;
0649:         document.getElementById('diagonal').value = '';
0650:         document.getElementById('distance').value = '';
0651:         {$submit}
0652:     });
0653: 
0654:     /**
0655:      * 地図を最適サイズにフィットする
0656:      * @param なし
0657:      * @return なし
0658:     */
0659:     function fitting() {
0660:         var lat0, lng0, lat1, lng1;
0661:         var lat = Array();
0662:         var lng = Array();
0663:         lat[0] = document.getElementById('latitude1').value;
0664:         lng[0] = document.getElementById('longitude1').value;
0665:         lat[1] = document.getElementById('latitude2').value;
0666:         lng[1] = document.getElementById('longitude2').value;
0667:         lat[2] = {$latitude};
0668:         lng[2] = {$longitude};
0669: 
0670:         //南西端(lat0, lng0), 北東端(lat1, lng1)を求める
0671:         if (lat[0] <= lat[1]) {
0672:             lat0 = lat[0];
0673:             lat1 = lat[1];
0674:         } else {
0675:             lat0 = lat[1];
0676:             lat1 = lat[0];
0677:         }
0678:         if (lat[2] >= 0) {
0679:             if (lat[0] <= lat[2]) {
0680:                 lng0 = lng[0];
0681:                 lng1 = lng[1];
0682:             } else {
0683:                 lng0 = lng[1];
0684:                 lng1 = lng[0];
0685:             }
0686:         } else {
0687:             if (lat[0] <= lat[2]) {
0688:                 lng0 = lng[1];
0689:                 lng1 = lng[0];
0690:             } else {
0691:                 lng0 = lng[0];
0692:                 lng1 = lng[1];
0693:             }
0694:         }
0695: 
0696:         var bounds = L.latLngBounds([lat0, lng0], [lat1, lng1])
0697:         map.fitBounds(bounds);      //地図表示の最適化
0698:     }
0699: EOT;
0700:     return $js;
0701: }

ユーザー関数 jsDragMarker_Leaflet は、Leaflet にマーカーを設定し、フィット機能を実装するための JavaScript を生成する。

中心点と対角点を示すマーカーはドラッグ可能とし、ドラッグ・イベントをフックし、緯度・経度を form オブジェクトに代入するようにする。

フィット機能は、図形の南西端と北東端を求め、Leaflet のメソッド fitBounds を呼び出すことで実現している。

0703: /**
0704:  * 円描画スクリプト:Leafletマップ用
0705:  * @param int    $id          識別ID
0706:  * @param float  $lat, $lng   中心座標(緯度,経度)
0707:  * @param float  $radius      半径(キロメートル)
0708:  * @param string $color       描画色(RGB)
0709:  * @param string $fillcolor   塗りつぶし色(RGB)
0710:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0711:  * @param int    $weight      線の太さ(省略時=1)
0712:  * @return string JavaScript
0713: */
0714: function jsDrawCircle_Leaflet($id$lat$lng$radius$color$fillcolor$opacity=1.0, $weight=1) {
0715:     $radius *= 1000;
0716: $js =<<< EOT
0717: var pcircle{$id} = new L.Circle(
0718:     [{$lat}, {$lng}],
0719:     {
0720:         radius: {$radius},
0721:         color: "#{$color}",
0722:         weight: {$weight},
0723:         fillColor: "#{$fillcolor}",
0724:         fillOpacity: "{$opacity}"
0725:     }
0726: ).addTo(map);
0727: 
0728: EOT;
0729:     return $js;
0730: }

0732: /**
0733:  * 矩形描画スクリプト:Leafletマップ用
0734:  * @param int    $id          識別ID
0735:  * @param float  $lat1, $lng1 北東端の緯度・経度
0736:  * @param float  $lat2, $lng2 南西端の緯度・経度
0737:  * @param string $color       描画色(RGB)
0738:  * @param string $fillcolor   塗りつぶし色(RGB)
0739:  * @param float  $opacity     塗りつぶしの不透明度(0.0~1.0;省略時=1.0)
0740:  * @param int    $weight      線の太さ(省略時=1)
0741:  * @return string JavaScript
0742: */
0743: function jsDrawRectangle_Leaflet($id$lat1$lng1$lat2$lng2$color$fillcolor$opacity=1.0, $weight=1) {
0744: $js =<<< EOT
0745: var prect{$id} = new L.Polygon(
0746:     [
0747:         [{$lat1}, {$lng1}],
0748:         [{$lat1}, {$lng2}],
0749:         [{$lat2}, {$lng2}],
0750:         [{$lat2}, {$lng1}]
0751:     ], {
0752:         color: "#{$color}",
0753:         weight: {$weight},
0754:         fillColor: "#{$fillcolor}",
0755:         fillOpacity: "{$opacity}"
0756:     }
0757: ).addTo(map);
0758: 
0759: EOT;
0760:     return $js;
0761: }

円や矩形を描画するユーザー関数は、Leaflet の機能をそのまま呼び出すものである。

解説:カラーコード、透明度

0262: /**
0263:  * カラーコード、透明度を取得する
0264:  * @param string $key     パラメータ名(省略不可)
0265:  * @param string $color   16進カラーコードの初期値(省略時:#FFFFFF)
0266:  * @param float  $opacity 透明度の初期値(省略時:1.0)
0267:  * @return bool array(#を除く16進カラーコード,透明度0.0~1.0)/FALSE=入力値が不正
0268: */
0269: function getColor($key$color='#FFFFFF', $opacity=1.0) {
0270:     $pat = array(
0271:         0 => '/\#([0-9a-f]+)/i',
0272:         1 => '/rgb\(\s*([0-9]+)\s*\,\s*([0-9]+)\s*\,\s*([0-9]+)\)/i',
0273:         2 => '/rgba\(\s*([0-9]+)\s*\,\s*([0-9]+)\s*\,\s*([0-9]+)\s*\,\s*([0-9\.]+)\)/i'
0274:     );
0275:     $str = getParam($keyFALSE$color);
0276:     if (preg_match($pat[0]$str$arr) > 0) {
0277:         $color = $arr[1];
0278:         $res = array($color$opacity);
0279:     } else if (preg_match($pat[1]$str$arr) > 0) {
0280:         $color = sprintf('%02X%02X%02X', $arr[1]$arr[2]$arr[3]);
0281:         $res = array($color$opacity);
0282:     } else if (preg_match($pat[2]$str$arr) > 0) {
0283:         $color = sprintf('%02X%02X%02X', $arr[1]$arr[2]$arr[3]);
0284:         $opacity = (double)$arr[4];
0285:         $res = array($color$opacity);
0286:     } else {
0287:         $res = FALSE;
0288:     }
0289: 
0290:     return $res;
0291: }

ユーザー関数 getColor は、冒頭で紹介したカラーピッカー Spectrum によって得られたカラーコードや透明度を取得する。
カラーコードは rgb で始まる 3 つの 16進数なので、関数  preg_match  を使って分解、取得する。透明度(アルファチャネル)がある場合は rgba で始まる 3 つの 16進数と、最後に透明度を示す 10進小数があるので、同様に取得する。

0293: /**
0294:  * カラーコード、透明度をrgb文字列に変換
0295:  * @param string $color   16進カラーコードの初期値
0296:  * @param float  $opacity 透明度の初期値(省略可能)
0297:  * @return string rgb文字列($opacity省略時はrgb、それ以外はrgba)
0298: */
0299: function color2rgb($color$opacity='') {
0300:     $pat = '/([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})/i';
0301:     if (preg_match($pat$color$arr) > 0) {
0302:         $res = sprintf('%d, %d, %d', hexdec($arr[1]), hexdec($arr[2]), hexdec($arr[3]));
0303:         if ($opacity == '') {
0304:             $res = sprintf('rgb(%s)', $res);
0305:         } else {
0306:             $res = sprintf('rgba(%s, %f)', $res$opacity);
0307:         }
0308:     } else {
0309:         $res = FALSE;
0310:     }
0311:     return $res;
0312: }

getColor とは逆に、URL パラメータから得られたカラーコードや透明度をカラーピッカー Spectrum に代入する必要があるので、逆関数 color2rgb を用意した。

参考サイト

(この項おわり)
header