Google 带有 MarkerClusterer 的地图商店定位器库
Google Maps Store Locator Library with MarkerClusterer
我在旁边使用 Google Maps Store Locator library, but I want to be able to implement MarkerClusterer。但是,我一直无法弄清楚如何让它们协同工作。
代码:
(function($, window, document){
var map = null,
cluster = null;
function storeSource() {
$.extend(this, new storeLocator.StaticDataFeed);
var that = this;
$.getJSON('linktoAJAXThatReturnsJSON', function(data) {
that.setStores(that.parse_(data));
map.fitBounds(centerMap(data));
});
}
storeSource.prototype.parse_ = function(data) {
var stores = [];
data.forEach(function(row){
var
position = new google.maps.LatLng(row.lat, row.long),
locality = row.postcode + ', ' + row.city,
store = new storeLocator.Store(row.id, position, null, {
title : row.name,
address : [row.address, locality, row.country].join('<br>'),
phone : row.phone
});
stores.push(store);
});
return stores;
};
// Clusters Markers together
function makeCluster(data) {
var markers = [];
data.forEach(function(row){
markers.push(row.getMarker());
});
cluster = new MarkerClusterer(map, markers, {});
}
// Finds viewpoint that accomodates all locations
function centerMap(data) {
var bounds = new google.maps.LatLngBounds();
data.forEach(function(row){
bounds.extend(new google.maps.LatLng(row.lat, row.long));
});
return bounds;
}
google.maps.event.addDomListener(window, 'load', function() {
map = new google.maps.Map(document.getElementById('mappanel'), {
mapTypeId : google.maps.MapTypeId.ROADMAP
});
var data = new storeSource();
var view = new storeLocator.View(map, data, {
geolocation: false
});
new storeLocator.Panel(document.getElementById('searchpanel'), {
view: view
});
// I think this is the place to try and add the Markers
// from storeSource. However, debugging shows Markers haven't
// been created yet. This leads me to believe that it's done
// internally in the storeLocator library. Not sure what to do
makeCluster(view.data_.stores_);
});
$(document).on('click', '.action', function(e){
e.preventDefault();
});
})(window.jQuery, window, document);
不幸的是,我没有现场版。
如代码中所述,MarkerClusterer 需要类型为 google.maps.Marker 的对象数组。
我的计划是重用 storeLocator.Store 对象并从中检索标记。我尝试检索它们,但调试显示它们未定义。
不确定如何让这 2 个库一起工作而不必破解其中任何一个。
编辑::取得了一些进展
我能够通过覆盖 storeLocator.View.createMarker 函数将 StoreLocator 使用的标记存储到 MarkerClusterer 中。然而,这会导致另一个问题:标记的可见性由 2 个不同的库控制:MarkerClusterer 想要在缩小时隐藏标记,但 storeLocator 始终显示所有标记。
有没有办法让标记遵循 MarkerClusterer 的默认行为?
我也有一个JFiddle.
编辑#2::解决方案
非常感谢 P1s4 的解决方案!这是修改后的 JFiddle.
我用 opacity 0 和 zindex 10000 解决了 storelocator 标记和 opacity 1 zindex 999 集群标记问题。
view.createMarker = function(store) {
var SHADOW = new google.maps.MarkerImage('wp-content/plugins/p1s4-storelocator/img/marker-shadow.png', null, null,new google.maps.Point(14, 13));
var markerOptions = {
position: store.getLocation(),
icon: store.getDetails().icon,
Opacity:0,
zIndex:10000,
title: store.getDetails().title
},
marker = new google.maps.Marker(markerOptions);
markercluster = new google.maps.Marker(markerOptions);
markercluster.setOpacity(1);
markercluster.setZIndex(999);
clusters.addMarker(markercluster);
return marker;
}
clusters = new MarkerClusterer(map, []);
我还有一个问题。我想使用 Feauture 过滤器。但是我无法隐藏群集上的标记...
我正在研究 ClusterMarker + Storelocator。
这是我的panel.js。
现在一切正常:clustermarkers、infowindows、在面板中单击时缩放、使用 cluster 和面板中的功能进行过滤。
希望这有用。
google.maps.event.addDomListener(window, 'load', function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center : new google.maps.LatLng(43.779982, 11.242564),
zoom : 4,
mapTypeId : google.maps.MapTypeId.ROADMAP
});
var panelDiv = document.getElementById('panel');
var data = new DataSource;
var view = new storeLocator.View(map, data, {
geolocation : true,
features : data.getFeatures()
});
// create the markers for storelocator and cluster at same time
// opacity of storelocator marker 0 and cluster 1. This way you see only
// the markers of cluster. setClickable false on marker of cluster
// and you click markers of storelocator. This way you use your panel click
// and storelocator inwfowindow.
var clusterMarkers = [];
view.createMarker = function (store) {
var markerOptions = {
position : store.getLocation(),
icon : store.getDetails().icon,
Opacity : 0,
title : store.getDetails().title,
Filter : store.getDetails().filter
}
marker = new google.maps.Marker(markerOptions);
markercluster = new google.maps.Marker(markerOptions);
markercluster.setOpacity(1);
markercluster.setClickable(false);
clusters.addMarker(markercluster);
clusterMarkers.push(markercluster);
return marker;
}
//I set maxzoom at 17 and when i open infowindow at 18. This way i have
//infowindow on the marker and not inside cluster
clusters = new MarkerClusterer(map, [], {
maxZoom : 17
});
// modded infowindow for storelocator
var infowindow = new google.maps.InfoWindow;
view.getInfoWindow = function (store) {
if (!store) {
return infowindow;
}
var details = store.getDetails();
var html = ['<div class="store"><div class="title">', details.title, '</div><div class="address">', details.address, '</div>', '<div class="hours misc">', details.phone, '</div></div>'].join('');
infowindow.setContent($(html)[0]);
if (map.getZoom() < "18") map.setZoom(18);
map.panTo(store.getLocation());
return infowindow;
};
// i close infowindow on zoom out.
google.maps.event.addListener(map, 'zoom_changed', function() {
infowindow.close();
});
new storeLocator.Panel(panelDiv, {
view : view,
featureFilter : true
});
// i use features modded with radio button on storelocator. I have a filter based on number (1,2,3,4) and i added features "all" (0) to all stores.
var features = view.getFeatures().asList();
$('<div id="filter-radio" />').appendTo('.storelocator-filter');
$.each(features, function (i, o) {
list = $('<input type="radio" class="filter" name="filter" value="' + i + '" id="filter' + (o.getDisplayName()) + '"/><label for="filter' + (o.getDisplayName()) + '">' + (o.getDisplayName()) + '</label>').appendTo('#filter-radio').change(function () {
view.set('featureFilter', new storeLocator.FeatureSet(features[this.value]));
view.refreshView();
// call toggle to change the markers on the cluster too
toggle(this.value);
});
});
//in mobile view i prefer use a select for features filter
var features_mobile = view.getFeatures().asList();
$('<div id="filter-select" />').prependTo('#panel');
list = $('<select class="filter-select"/>')
.appendTo('#filter-select').
change(function () {
view.set('featureFilter',
new storeLocator.FeatureSet(features[this.selectedIndex]));
view.refreshView();
toggle(this.selectedIndex);
});
$.each(features, function (i, o) {
list.append(new Option(o.getDisplayName()));
});
// toggle function for markercluster. I filter markers inside the
// cluster array with the same value as storelocator
function toggle(filterc) {
var markers = [];
for (var i = 0; i < clusterMarkers.length; i++) {
if (filterc == '0') {
markers.push(clusterMarkers[i]);
clusterMarkers[i].setVisible(true);
}
else if (clusterMarkers[i].Filter == filterc) {
markers.push(clusterMarkers[i]);
clusterMarkers[i].setVisible(true);
}
}
if (markers.length) {
clusters.removeMarkers(clusterMarkers);
clusters.addMarkers(markers);
}
};
});
我在旁边使用 Google Maps Store Locator library, but I want to be able to implement MarkerClusterer。但是,我一直无法弄清楚如何让它们协同工作。
代码:
(function($, window, document){
var map = null,
cluster = null;
function storeSource() {
$.extend(this, new storeLocator.StaticDataFeed);
var that = this;
$.getJSON('linktoAJAXThatReturnsJSON', function(data) {
that.setStores(that.parse_(data));
map.fitBounds(centerMap(data));
});
}
storeSource.prototype.parse_ = function(data) {
var stores = [];
data.forEach(function(row){
var
position = new google.maps.LatLng(row.lat, row.long),
locality = row.postcode + ', ' + row.city,
store = new storeLocator.Store(row.id, position, null, {
title : row.name,
address : [row.address, locality, row.country].join('<br>'),
phone : row.phone
});
stores.push(store);
});
return stores;
};
// Clusters Markers together
function makeCluster(data) {
var markers = [];
data.forEach(function(row){
markers.push(row.getMarker());
});
cluster = new MarkerClusterer(map, markers, {});
}
// Finds viewpoint that accomodates all locations
function centerMap(data) {
var bounds = new google.maps.LatLngBounds();
data.forEach(function(row){
bounds.extend(new google.maps.LatLng(row.lat, row.long));
});
return bounds;
}
google.maps.event.addDomListener(window, 'load', function() {
map = new google.maps.Map(document.getElementById('mappanel'), {
mapTypeId : google.maps.MapTypeId.ROADMAP
});
var data = new storeSource();
var view = new storeLocator.View(map, data, {
geolocation: false
});
new storeLocator.Panel(document.getElementById('searchpanel'), {
view: view
});
// I think this is the place to try and add the Markers
// from storeSource. However, debugging shows Markers haven't
// been created yet. This leads me to believe that it's done
// internally in the storeLocator library. Not sure what to do
makeCluster(view.data_.stores_);
});
$(document).on('click', '.action', function(e){
e.preventDefault();
});
})(window.jQuery, window, document);
不幸的是,我没有现场版。
如代码中所述,MarkerClusterer 需要类型为 google.maps.Marker 的对象数组。
我的计划是重用 storeLocator.Store 对象并从中检索标记。我尝试检索它们,但调试显示它们未定义。
不确定如何让这 2 个库一起工作而不必破解其中任何一个。
编辑::取得了一些进展
我能够通过覆盖 storeLocator.View.createMarker 函数将 StoreLocator 使用的标记存储到 MarkerClusterer 中。然而,这会导致另一个问题:标记的可见性由 2 个不同的库控制:MarkerClusterer 想要在缩小时隐藏标记,但 storeLocator 始终显示所有标记。
有没有办法让标记遵循 MarkerClusterer 的默认行为?
我也有一个JFiddle.
编辑#2::解决方案
非常感谢 P1s4 的解决方案!这是修改后的 JFiddle.
我用 opacity 0 和 zindex 10000 解决了 storelocator 标记和 opacity 1 zindex 999 集群标记问题。
view.createMarker = function(store) {
var SHADOW = new google.maps.MarkerImage('wp-content/plugins/p1s4-storelocator/img/marker-shadow.png', null, null,new google.maps.Point(14, 13));
var markerOptions = {
position: store.getLocation(),
icon: store.getDetails().icon,
Opacity:0,
zIndex:10000,
title: store.getDetails().title
},
marker = new google.maps.Marker(markerOptions);
markercluster = new google.maps.Marker(markerOptions);
markercluster.setOpacity(1);
markercluster.setZIndex(999);
clusters.addMarker(markercluster);
return marker;
}
clusters = new MarkerClusterer(map, []);
我还有一个问题。我想使用 Feauture 过滤器。但是我无法隐藏群集上的标记...
我正在研究 ClusterMarker + Storelocator。
这是我的panel.js。
现在一切正常:clustermarkers、infowindows、在面板中单击时缩放、使用 cluster 和面板中的功能进行过滤。 希望这有用。
google.maps.event.addDomListener(window, 'load', function () {
var map = new google.maps.Map(document.getElementById('map-canvas'), {
center : new google.maps.LatLng(43.779982, 11.242564),
zoom : 4,
mapTypeId : google.maps.MapTypeId.ROADMAP
});
var panelDiv = document.getElementById('panel');
var data = new DataSource;
var view = new storeLocator.View(map, data, {
geolocation : true,
features : data.getFeatures()
});
// create the markers for storelocator and cluster at same time
// opacity of storelocator marker 0 and cluster 1. This way you see only
// the markers of cluster. setClickable false on marker of cluster
// and you click markers of storelocator. This way you use your panel click
// and storelocator inwfowindow.
var clusterMarkers = [];
view.createMarker = function (store) {
var markerOptions = {
position : store.getLocation(),
icon : store.getDetails().icon,
Opacity : 0,
title : store.getDetails().title,
Filter : store.getDetails().filter
}
marker = new google.maps.Marker(markerOptions);
markercluster = new google.maps.Marker(markerOptions);
markercluster.setOpacity(1);
markercluster.setClickable(false);
clusters.addMarker(markercluster);
clusterMarkers.push(markercluster);
return marker;
}
//I set maxzoom at 17 and when i open infowindow at 18. This way i have
//infowindow on the marker and not inside cluster
clusters = new MarkerClusterer(map, [], {
maxZoom : 17
});
// modded infowindow for storelocator
var infowindow = new google.maps.InfoWindow;
view.getInfoWindow = function (store) {
if (!store) {
return infowindow;
}
var details = store.getDetails();
var html = ['<div class="store"><div class="title">', details.title, '</div><div class="address">', details.address, '</div>', '<div class="hours misc">', details.phone, '</div></div>'].join('');
infowindow.setContent($(html)[0]);
if (map.getZoom() < "18") map.setZoom(18);
map.panTo(store.getLocation());
return infowindow;
};
// i close infowindow on zoom out.
google.maps.event.addListener(map, 'zoom_changed', function() {
infowindow.close();
});
new storeLocator.Panel(panelDiv, {
view : view,
featureFilter : true
});
// i use features modded with radio button on storelocator. I have a filter based on number (1,2,3,4) and i added features "all" (0) to all stores.
var features = view.getFeatures().asList();
$('<div id="filter-radio" />').appendTo('.storelocator-filter');
$.each(features, function (i, o) {
list = $('<input type="radio" class="filter" name="filter" value="' + i + '" id="filter' + (o.getDisplayName()) + '"/><label for="filter' + (o.getDisplayName()) + '">' + (o.getDisplayName()) + '</label>').appendTo('#filter-radio').change(function () {
view.set('featureFilter', new storeLocator.FeatureSet(features[this.value]));
view.refreshView();
// call toggle to change the markers on the cluster too
toggle(this.value);
});
});
//in mobile view i prefer use a select for features filter
var features_mobile = view.getFeatures().asList();
$('<div id="filter-select" />').prependTo('#panel');
list = $('<select class="filter-select"/>')
.appendTo('#filter-select').
change(function () {
view.set('featureFilter',
new storeLocator.FeatureSet(features[this.selectedIndex]));
view.refreshView();
toggle(this.selectedIndex);
});
$.each(features, function (i, o) {
list.append(new Option(o.getDisplayName()));
});
// toggle function for markercluster. I filter markers inside the
// cluster array with the same value as storelocator
function toggle(filterc) {
var markers = [];
for (var i = 0; i < clusterMarkers.length; i++) {
if (filterc == '0') {
markers.push(clusterMarkers[i]);
clusterMarkers[i].setVisible(true);
}
else if (clusterMarkers[i].Filter == filterc) {
markers.push(clusterMarkers[i]);
clusterMarkers[i].setVisible(true);
}
}
if (markers.length) {
clusters.removeMarkers(clusterMarkers);
clusters.addMarkers(markers);
}
};
});