フォトログで表示しているGoogleマップでは、表示している写真の撮影場所だけを表示して、他の写真のマーカーは載せてプロットしていませんでした。
これは、撮影場所が近いとマーカーが重なりゴチャゴチャになってしまうのがイヤだったからなのですが、先日コミュニティコムの @khoshino さんに、近い場所に複数のマーカーがある場合、まとめて表示してくれる MarkerClusterer の存在を教えていただいたので、早速導入してみることにしました。
まずは、get_postsを使って、緯度経度入力のある投稿を全件取得。
$photos = get_posts( 'posts_per_page=-1&meta_key=lat,lng' );
これを foreach でループさせて、複数のマーカーをプロットすると、当然ながら画像のように重なって表示されてしまいます。
マーカーがダブって見にくいし、なにより後ろに重なってしまっているマーカーをクリックしにくいですよね。
MarkerClustererの導入
ライブラリファイルの取得
まずは、MarkerClustererのリポジトリから、ライブラリのjsファイルをダウンロードして、テーマのディレクトリに保存しておきます。私の場合は、通常のテンプレートと区分けしたかったので、jsディレクトリを作り、その中に置くことにしました。
2つあるファイルの内、markerclusterer.js は、コメント付きで読みやすくなっているので、ソースを解析などを行う場合に使えます。一方、markerclusterer_compiled.js は、圧縮処理がなされていて、ファイルサイズも markerclusterer.js の1/4に収まっているので、実際に利用するのは、是非こちらにしましょう。
MarkerClustererライブラリの読み込み
次にhead要素内でライブラリを読み込むように、functions.php にwp_head へのフックを追加します。
最初のscript は Googleマップ の 後のscript が MarkerClusterer のものです。(特に順番が決まっているわけではありません。)
function print_google_map_script() { ?> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript" src="<?php echo get_stylesheet_directory_uri(); ?>/js/markerclusterer_compiled.js"></script> <?php } add_action( 'wp_head', 'print_google_map_script' );
MarkerClustererの実行
クラスタリングを行うためには、下記のコードで MarkerClusterer のインスタンスを生成させるだけですが、必須となる引数を2つ指定し、クラスタリングの範囲などを変更できるオプションの引数が1つ指定できます。
var markerCluster = new MarkerClusterer( map, marker, options );
- map
- google.maps.Map オブジェクトのインスタンス
- marker
- 表示するマーカーの配列
- options
- 表示オプションのオブジェクト 例){gridSize: 50, maxZoom: 15} クラスタリングする範囲:50、クラスタリングする最大倍率:15
この指定が上手く言っていれば、
この通り、範囲内にあるマーカーがまとめられて、マーカー数が表示表示されるようになります。
この場合は、2個だけなので、前後での変化が分かりにくいですが、同一地域でのマーカー数が10個くらいになると、かなりすっきりした表示に見えることと思います。
クラスタリングされたマーカーをクリックすると、該当地域がズームされて、分割された元々のマーカーで表示されるようになるので、使い勝手も上々です。
最後に、フォトログテーマに仕込んだコードを掲載しておきますので、よかったら参考にしてみてください。
<?php if ( $latlng = get_post_meta( $post->ID, 'lat,lng', true ) ) : $photos = get_posts( 'posts_per_page=-1&meta_key=lat,lng' );?> <div id="map" style="margin-left: 5px; width: <?php echo (int)$content_width; ?>px; height: <?php echo ceil( (int)$content_width * 2 / 3 ); ?>px;"> </div> <script type="text/javascript"> google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById( 'map' ); var myOptions = { zoom: 11, center: new google.maps.LatLng( <?php echo esc_html( $latlng ); ?> ), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); var marker = []; var infowindow = []; <?php $cnt = 0; foreach ( $photos as $photo ) : $latlng = get_post_meta( $photo->ID, 'lat,lng', true ); ?> marker[<?php echo $cnt; ?>] = new google.maps.Marker({ icon: 'http://maps.google.co.jp/mapfiles/ms/icons/<?php echo $post->ID == $photo->ID ? 'red' : blue; ?>-pushpin.png', position: new google.maps.LatLng( <?php echo esc_html( $latlng ); ?> ), map: map, title: '<?php echo apply_filters( 'the_title', $photo->post_title ); ?>' }); infowindow[<?php echo $cnt; ?>] = new google.maps.InfoWindow({ content: '<a href="<?php echo get_permalink( $photo->ID ); ?>"><?php echo apply_filters( 'the_title', $photo->post_title ); ?></a>', size: new google.maps.Size( 50, 30 ) }); google.maps.event.addListener( marker[<?php echo $cnt; ?>], 'click', function() { infowindow[<?php echo $cnt; ?>].open( map, marker[<?php echo $cnt; ?>] ); }); <?php $cnt++; endforeach; ?> var markerCluster = new MarkerClusterer( map, marker ); }); </script> <?php endif; ?>