現在、WordPressでGoogleMapを使い、地域情報サイトを作ろうとしております。
固定ペ-ジに設置したGoogleMapに、店舗情報(post)の数だけマ-カ-が表示されるようにしています。
(店舗情報には緯度経度の情報を持たせています)
このマップをGoogle MapからOpenStreetMapに書き換えたいのです。
また、その際にGoogleMapでいうところの「MarkerClusterer」のような機能があればさらに嬉しいです。
ちなみに、マップに表示されたマ-カ-をクリックすると、その店舗情報ペ-ジ(post)にジャンプするようになっていて、その店舗情報ペ-ジにも、その店舗専用のマップを表示しており、そちらもOpenStreetMapに変更したいのです。
補足の欄に現状の、固定ペ-ジでマップ表示させるためのコ-ド、店舗専用マップを表示させるためのコ-ドを貼りますので具体的なアドバイスをいただけませんでしょうか。
なにとぞよろしくお願いいたします。
そのものズバリご回答いただけた場合、設定以上のポイントをお支払いさせていただきます。
下記のコ-ドに出てくる以下のものは、カスタムフィ-ルドで設定した値が出力されます。
centerlat マップ中心点の緯度
centerlng マップ中心点の経度
zoom ズ-ムレベル
displaycategory 表示するカテゴリ-のスラッグ
lat 店舗の緯度
lon 店舗の経度
Name 店舗の業種名
固定ペ-ジのコ-ド(表示条件を入力すればその条件に合った複数の店舗がグ-グルマップ上に表示される)
<?php $place = $_POST['place']; $cc = $_POST['cc']; if ($cc) { foreach ($cc as $v) { $cc_stat[$v] = 'checked'; } } ?> <style> form label { margin-right: 2ex; } </style> <form action="" method="post"> 検索したい地域 <input type="text" name="place" value="<?php echo $place ?>"> <!-- カテゴリーの指定 --> <label><input type="checkbox" name="cc[]" value="2" <?php echo $cc_stat[2] ?>>飲食 </label> <label><input type="checkbox" name="cc[]" value="3" <?php echo $cc_stat[3] ?>>家関係 </label> <label><input type="checkbox" name="cc[]" value="4" <?php echo $cc_stat[4] ?>>ファッション関係 </label> <label><input type="checkbox" name="cc[]" value="5" <?php echo $cc_stat[5] ?>>ペット関係 </label> <br> <input type="submit" name="send" value="検索"> </form> <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <!-- <script type="text/javascript" src="https://googlemaps.github.io/js-marker-clusterer/src/markerclusterer.js"></script> --> <?php // $categories = get_post_meta( $post->ID, 'displaycategory', true); // if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <?php if ($place): $args = Array( 'post_type' => 'post', 'posts_per_page' => -1, 'meta_query' => array(array( 'key' => 'address', 'value' => $place, 'compare' => 'LIKE' )) ); // カテゴリーのどれかにチェックが入っていたら、検索条件を追加する $cc = $_POST['cc']; if (sizeof($cc) > 0) { $args['category__in'] = $cc; } $the_query = new WP_Query($args); if ($the_query->have_posts()): ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> var posts = []; <?php while ($the_query->have_posts()) : $the_query->the_post(); $googlemap = get_field('googlemap'); if (! $googlemap) { // マップ住所が登録されていないこともある continue; } $category = get_the_category(); ?> posts.push({ lat: <?php echo $googlemap['lat']; ?>, lng: <?php echo $googlemap['lng']; ?>, name: '<?php echo post_custom("Name")?>', link: '<?php the_permalink(); ?>', title: '<?php the_title(); ?>', cat_id: '<?php echo $category[0]->cat_ID; ?>' }); <?php endwhile; // End the loop. Whew. ?> // カテゴリーID とマーカー画像の対応 var icon_map = { 2: "http://maps.google.co.jp/mapfiles/ms/icons/red-dot.png", 3: "http://maps.google.co.jp/mapfiles/ms/icons/blue-dot.png", 4: "http://maps.google.co.jp/mapfiles/ms/icons/yellow-dot.png", 5: "http://maps.google.co.jp/mapfiles/ms/icons/green-dot.png", }; // 地図の中心、最北西、再南東 var sum_lat = 0, sum_lng = 0; var min_lat = 999, min_lng = 999; var max_lat = 0, max_lng = 0; for (var i = 0 ; i < posts.length ; ++i) { var lat = posts[i].lat, lng = posts[i].lng; sum_lat += lat; sum_lng += lng; min_lat = Math.min(min_lat, lat); max_lat = Math.max(max_lat, lat); min_lng = Math.min(min_lng, lng); max_lng = Math.max(max_lng, lng); } var pos_center = {lat: sum_lat / posts.length, lng: sum_lng / posts.length}; var pos_sw = new google.maps.LatLng(max_lat,min_lng); var pos_ne = new google.maps.LatLng(min_lat,max_lng); google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById('map'); var myOptions = { zoom: 11, center: new google.maps.LatLng(pos_center.lat, pos_center.lng), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); map.fitBounds(new google.maps.LatLngBounds(pos_sw, pos_ne)); // Zoom の最大値は 16 まで var zoom_listener = google.maps.event.addListener(map, "idle", function() { if (map.getZoom() > 16) { map.setZoom(16); } google.maps.event.removeListener(zoom_listener); }); var marker = []; var infowindow = []; for (var i = 0 ; i < posts.length ; ++i) { var post = posts[i]; // 緯度、経度を指定して Marker を作成 var latlng = new google.maps.LatLng(post.lat, post.lng); var m = new google.maps.Marker({ icon: icon_map[ post.cat_id ], position: latlng, map: map, title: post.title }); marker.push(m); var iw = new google.maps.InfoWindow({ content: '<div style="width : 100%;height : 36px;">' + post.name + ':' + '<a href="' + post.link + '">' + post.title + '</a></div>', size: new google.maps.Size(50, 30) }); infowindow.push(iw); var handler = (function() { var m_ = m, iw_ = iw; return function() { if (iw_.getMap() == null){ iw_.open(map, m_); } else { iw_.close(); } }; })(); google.maps.event.addListener(m, 'click', handler); } var markerCluster = new MarkerClusterer( map, marker ); }); </script> <?php else: ?> 該当する店舗はありませんでした。 <?php endif; ?> <?php else: ?> 地域を入力してください。 <?php endif; ?>
店舗情報ペ-ジ(post)に表示させている、その店舗のマップ
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script> <script type="text/javascript"> google.maps.event.addDomListener(window, 'load', function() { var mapdiv = document.getElementById( 'map' ); var myOptions = { zoom: 17, center: new google.maps.LatLng( <?php echo post_custom("lat")?>,<?php echo post_custom("lon")?> ), mapTypeId: google.maps.MapTypeId.ROADMAP, scaleControl: true }; var map = new google.maps.Map( mapdiv, myOptions ); var marker = []; var infowindow = []; marker[0] = new google.maps.Marker({icon: 'http://maps.google.co.jp/mapfiles/ms/icons/red-dot.png',position: new google.maps.LatLng(<?php echo post_custom("lat")?>,<?php echo post_custom("lon")?>), map: map, title: '<?php the_title(); ?>' }); }); </script>
グ-グルマップからオ-プンストリ-トマップに変更し、以下のことを満足したいのです。
・店舗の場所にマーカーを設置する
・マーカーをクリックすると吹き出しが表示され、もう一度クリックすると吹き出しが消える
・カテゴリーごとにマーカーの画像を変える
・検索結果の店舗が全て表示されるように表示範囲を調整する
以下のような感じで、それっぽく表示されるかなあ、と思います。
<?php $place = $_POST['place']; $cc = $_POST['cc']; if ($cc) { foreach ($cc as $v) { $cc_stat[$v] = 'checked'; } } ?> <style> form label { margin-right: 2ex; } </style> <form action="" method="post"> 検索したい地域 <input type="text" name="place" value="<?php echo $place ?>"> <!-- カテゴリーの指定 --> <label><input type="checkbox" name="cc[]" value="2" <?php echo $cc_stat[2] ?>>飲食 </label> <label><input type="checkbox" name="cc[]" value="3" <?php echo $cc_stat[3] ?>>家関係 </label> <label><input type="checkbox" name="cc[]" value="4" <?php echo $cc_stat[4] ?>>ファッション関係 </label> <label><input type="checkbox" name="cc[]" value="5" <?php echo $cc_stat[5] ?>>ペット関係 </label> <br> <input type="submit" name="send" value="検索"> </form> <!-- ★ Google Maps API → OpenLayers API --> <script type="text/javascript" src="http://www.openlayers.org/api/OpenLayers.js"></script> <!-- <script type="text/javascript" src="https://googlemaps.github.io/js-marker-clusterer/src/markerclusterer.js"></script> --> <?php // $categories = get_post_meta( $post->ID, 'displaycategory', true); // if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <?php if ($place): $args = Array( 'post_type' => 'post', 'posts_per_page' => -1, 'meta_query' => array(array( 'key' => 'address', 'value' => $place, 'compare' => 'LIKE' )) ); // カテゴリーのどれかにチェックが入っていたら、検索条件を追加する $cc = $_POST['cc']; if (sizeof($cc) > 0) { $args['category__in'] = $cc; } $the_query = new WP_Query($args); if ($the_query->have_posts()): ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> (function() { // ★ こんなので、くるんでみる var posts = []; <?php while ($the_query->have_posts()) : $the_query->the_post(); $googlemap = get_field('googlemap'); if (! $googlemap) { // マップ住所が登録されていないこともある continue; } $category = get_the_category(); ?> posts.push({ lat: <?php echo $googlemap['lat']; ?>, lng: <?php echo $googlemap['lng']; ?>, name: '<?php echo post_custom("Name")?>', link: '<?php the_permalink(); ?>', title: '<?php the_title(); ?>', cat_id: '<?php echo $category[0]->cat_ID; ?>' }); <?php endwhile; // End the loop. Whew. ?> // ★ これ以降、OpenLayers API を使うように、ばっさりと書き換え var map; var select; function display_map() { // マーカーとツールチップを、店舗情報毎に設定するための overlay var overlay = new OpenLayers.Layer.Vector('Overlay', { styleMap: new OpenLayers.StyleMap({ externalGraphic: '${marker_image}', graphicWidth: 21, graphicHeight: 25, graphicYOffset: -25, cursor: "pointer", title: '${tooltip}', }) }); var icon_map = { 2: "http://dev.openlayers.org/img/marker.png", 3: "http://dev.openlayers.org/img/marker-blue.png", 4: "http://dev.openlayers.org/img/marker-gold.png", 5: "http://dev.openlayers.org/img/marker-green.png", }; var epsg4326 = new OpenLayers.Projection("EPSG:4326"); var epsg3857 = new OpenLayers.Projection("EPSG:3857"); // マーカーの生成 var features = []; for (var i in posts) { var post = posts[i]; features.push(new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(post.lng, post.lat) .transform(epsg4326, epsg3857), { tooltip: post.title, marker_image: icon_map[ post.cat_id ], post: post, } )); } overlay.addFeatures(features); overlay.events.on({ 'featureselected': display_popup, 'featureunselected': erase_popup, }); // マップの生成 map = new OpenLayers.Map("map"); map.addLayers([new OpenLayers.Layer.OSM(), overlay]); // マーカーのクリック状態を取得するために、SelectFeature なるものを作る select = new OpenLayers.Control.SelectFeature(overlay); map.addControl(select); select.activate(); // マーカーが含まれる範囲の Bounds と、それに合わせたズーミング var bounds = new OpenLayers.Bounds(); for (var i in posts) { bounds.extend(new OpenLayers.LonLat(posts[i].lng, posts[i].lat)); } bounds.transform(epsg4326, epsg3857); map.zoomToExtent(bounds); // ズームの最大値は 16 まで if (map.getZoom() > 16) { map.zoomTo(16); } } // 吹き出しの「×」を押したときの処理 function close_popup(evt) { select.unselect(this.feature); } // マーカーをクリックしたときに吹き出しを表示する function display_popup(evt) { var feature = evt.feature; var post = feature.attributes.post; var content = '<div>' + post.name + ':' + '<a href="' + post.link + '">' + post.title + '</a></div>'; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100, 100), content, null, true, close_popup); feature.popup = popup; popup.feature = feature; map.addPopup(popup); } // 他のマーカーをクリックしたり、関係ないところをクリックしたときに、吹き出しを消す function erase_popup(evt) { var feature = evt.feature; if (feature.popup) { popup.feature = null; map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } // ページの読み込みが終わったら、地図表示の処理を行う window.addEventListener("DOMContentLoaded", display_map); })(); </script> <?php else: ?> 該当する店舗はありませんでした。 <?php endif; ?> <?php else: ?> 地域を入力してください。 <?php endif; ?> <!-- ★ スタイルの調整 --> <style> /* 地図領域と地図のサイズが合わないとき : Google Maps は API が設定する */ #map { position: relative; overflow: hidden; } /* style.css の指定が影響して、吹き出しが正しく表示されない */ #map .olPopup img { max-width: none; } </style>
修正した量は多いですが、大きく四ついじってます。
マーカーの画像は http://dev.openlayers.org/img/ のものを使ってますが、自サイトに用意した方が良いと思います。
Google Maps API を使ってたときと違うところ。
マーカーをクリックしたときの動作は変更できると思いますが、以前の質問の回答でも書いたような記憶がありますが、この辺は好みなので、こちらの動作でも良いかな、とは思います。
吹き出しの見た目は画像ファイルを使っているので、これを修正すると変更できそうな気がします。
Marker Cluster は、いくつかやり方がありそうなのですが、うーんって感じになってます。
検索結果が含まれる範囲を適切にズーミングできれば、必要ないんじゃないか、という言い訳をしてみたり :-)
気に食わないところは言ってください。
直せそうなら、直します。
以下、参考にしたページです。
以下のような感じで、それっぽく表示されるかなあ、と思います。
<?php $place = $_POST['place']; $cc = $_POST['cc']; if ($cc) { foreach ($cc as $v) { $cc_stat[$v] = 'checked'; } } ?> <style> form label { margin-right: 2ex; } </style> <form action="" method="post"> 検索したい地域 <input type="text" name="place" value="<?php echo $place ?>"> <!-- カテゴリーの指定 --> <label><input type="checkbox" name="cc[]" value="2" <?php echo $cc_stat[2] ?>>飲食 </label> <label><input type="checkbox" name="cc[]" value="3" <?php echo $cc_stat[3] ?>>家関係 </label> <label><input type="checkbox" name="cc[]" value="4" <?php echo $cc_stat[4] ?>>ファッション関係 </label> <label><input type="checkbox" name="cc[]" value="5" <?php echo $cc_stat[5] ?>>ペット関係 </label> <br> <input type="submit" name="send" value="検索"> </form> <!-- ★ Google Maps API → OpenLayers API --> <script type="text/javascript" src="http://www.openlayers.org/api/OpenLayers.js"></script> <!-- <script type="text/javascript" src="https://googlemaps.github.io/js-marker-clusterer/src/markerclusterer.js"></script> --> <?php // $categories = get_post_meta( $post->ID, 'displaycategory', true); // if ( have_posts() ) : query_posts('category_name=' . $categories . '&showposts=10000'); ?> <?php if ($place): $args = Array( 'post_type' => 'post', 'posts_per_page' => -1, 'meta_query' => array(array( 'key' => 'address', 'value' => $place, 'compare' => 'LIKE' )) ); // カテゴリーのどれかにチェックが入っていたら、検索条件を追加する $cc = $_POST['cc']; if (sizeof($cc) > 0) { $args['category__in'] = $cc; } $the_query = new WP_Query($args); if ($the_query->have_posts()): ?> <div id="map" style="width: 99%; height: 650px;"></div> <script type="text/javascript"> (function() { // ★ こんなので、くるんでみる var posts = []; <?php while ($the_query->have_posts()) : $the_query->the_post(); $googlemap = get_field('googlemap'); if (! $googlemap) { // マップ住所が登録されていないこともある continue; } $category = get_the_category(); ?> posts.push({ lat: <?php echo $googlemap['lat']; ?>, lng: <?php echo $googlemap['lng']; ?>, name: '<?php echo post_custom("Name")?>', link: '<?php the_permalink(); ?>', title: '<?php the_title(); ?>', cat_id: '<?php echo $category[0]->cat_ID; ?>' }); <?php endwhile; // End the loop. Whew. ?> // ★ これ以降、OpenLayers API を使うように、ばっさりと書き換え var map; var select; function display_map() { // マーカーとツールチップを、店舗情報毎に設定するための overlay var overlay = new OpenLayers.Layer.Vector('Overlay', { styleMap: new OpenLayers.StyleMap({ externalGraphic: '${marker_image}', graphicWidth: 21, graphicHeight: 25, graphicYOffset: -25, cursor: "pointer", title: '${tooltip}', }) }); var icon_map = { 2: "http://dev.openlayers.org/img/marker.png", 3: "http://dev.openlayers.org/img/marker-blue.png", 4: "http://dev.openlayers.org/img/marker-gold.png", 5: "http://dev.openlayers.org/img/marker-green.png", }; var epsg4326 = new OpenLayers.Projection("EPSG:4326"); var epsg3857 = new OpenLayers.Projection("EPSG:3857"); // マーカーの生成 var features = []; for (var i in posts) { var post = posts[i]; features.push(new OpenLayers.Feature.Vector( new OpenLayers.Geometry.Point(post.lng, post.lat) .transform(epsg4326, epsg3857), { tooltip: post.title, marker_image: icon_map[ post.cat_id ], post: post, } )); } overlay.addFeatures(features); overlay.events.on({ 'featureselected': display_popup, 'featureunselected': erase_popup, }); // マップの生成 map = new OpenLayers.Map("map"); map.addLayers([new OpenLayers.Layer.OSM(), overlay]); // マーカーのクリック状態を取得するために、SelectFeature なるものを作る select = new OpenLayers.Control.SelectFeature(overlay); map.addControl(select); select.activate(); // マーカーが含まれる範囲の Bounds と、それに合わせたズーミング var bounds = new OpenLayers.Bounds(); for (var i in posts) { bounds.extend(new OpenLayers.LonLat(posts[i].lng, posts[i].lat)); } bounds.transform(epsg4326, epsg3857); map.zoomToExtent(bounds); // ズームの最大値は 16 まで if (map.getZoom() > 16) { map.zoomTo(16); } } // 吹き出しの「×」を押したときの処理 function close_popup(evt) { select.unselect(this.feature); } // マーカーをクリックしたときに吹き出しを表示する function display_popup(evt) { var feature = evt.feature; var post = feature.attributes.post; var content = '<div>' + post.name + ':' + '<a href="' + post.link + '">' + post.title + '</a></div>'; popup = new OpenLayers.Popup.FramedCloud("featurePopup", feature.geometry.getBounds().getCenterLonLat(), new OpenLayers.Size(100, 100), content, null, true, close_popup); feature.popup = popup; popup.feature = feature; map.addPopup(popup); } // 他のマーカーをクリックしたり、関係ないところをクリックしたときに、吹き出しを消す function erase_popup(evt) { var feature = evt.feature; if (feature.popup) { popup.feature = null; map.removePopup(feature.popup); feature.popup.destroy(); feature.popup = null; } } // ページの読み込みが終わったら、地図表示の処理を行う window.addEventListener("DOMContentLoaded", display_map); })(); </script> <?php else: ?> 該当する店舗はありませんでした。 <?php endif; ?> <?php else: ?> 地域を入力してください。 <?php endif; ?> <!-- ★ スタイルの調整 --> <style> /* 地図領域と地図のサイズが合わないとき : Google Maps は API が設定する */ #map { position: relative; overflow: hidden; } /* style.css の指定が影響して、吹き出しが正しく表示されない */ #map .olPopup img { max-width: none; } </style>
修正した量は多いですが、大きく四ついじってます。
マーカーの画像は http://dev.openlayers.org/img/ のものを使ってますが、自サイトに用意した方が良いと思います。
Google Maps API を使ってたときと違うところ。
マーカーをクリックしたときの動作は変更できると思いますが、以前の質問の回答でも書いたような記憶がありますが、この辺は好みなので、こちらの動作でも良いかな、とは思います。
吹き出しの見た目は画像ファイルを使っているので、これを修正すると変更できそうな気がします。
Marker Cluster は、いくつかやり方がありそうなのですが、うーんって感じになってます。
検索結果が含まれる範囲を適切にズーミングできれば、必要ないんじゃないか、という言い訳をしてみたり :-)
気に食わないところは言ってください。
直せそうなら、直します。
以下、参考にしたページです。
できる/できないの条件がはっきりしているので、それほど苦労しませんでした。
こういうのも含めて、面白いなあと思います。
# マウス、久しぶりに使った :-)
そういったa-kuma3さんの開発舞台裏みたいなのも興味深いですね>マウス久しぶり
ブログにもそういった方面(使用PCだとか)の記事を期待しています :-)
できる/できないの条件がはっきりしているので、それほど苦労しませんでした。
2016/07/13 00:33:17こういうのも含めて、面白いなあと思います。
# マウス、久しぶりに使った :-)
そういったa-kuma3さんの開発舞台裏みたいなのも興味深いですね>マウス久しぶり
2016/07/13 00:49:26ブログにもそういった方面(使用PCだとか)の記事を期待しています :-)