【发布时间】:2015-03-04 20:32:50
【问题描述】:
在 stackoverflow 的大力帮助下,我一直在编写一个小应用程序。基本前提很简单,我在整个网络上都看到过这种功能:我正在尝试将位置列表绘制到可搜索/可平移的谷歌地图上。位置存储在后端,控制器将这些位置提供给视图。涉及 AJAX 是因为我不想重新加载整个页面。以下是场景:a)用户通过邮政编码搜索位置=>地图加载新位置,搜索获取被发送到服务器并且地图加载任何标记(如果在设置的半径内有任何标记),地图设置默认缩放级别; b) 用户平移/缩放 => 地图停留在用户离开的任何地方,带有视口边界框的搜索被发送到服务器并映射结果。地图在初始加载时将默认为西雅图,它尝试的第一件事是定位用户...
使用 gmaps4ails wiki 和这个问题的答案的修改版本:Google Maps for Rails - update markers with AJAX 我已经非常接近了。它的工作原理,实际上,只是有一个障碍。这是它的样子:
sightings_controller.rb
def search
if params[:lat]
@ll = [params[:lat].to_f, params[:lng].to_f]
@sightings = Sighting.within(5, origin: @ll).order('created_at DESC')
@remap = true
elsif search_params = params[:zipcode]
geocode = Geokit::Geocoders::GoogleGeocoder.geocode(search_params)
@ll = [geocode.lat, geocode.lng]
@sightings = Sighting.within(5, origin: @ll).order('created_at DESC')
@remap = true
elsif params[:bounds]
boundarray = params[:bounds].split(',')
bounds = [[boundarray[0].to_f, boundarray[1].to_f], [boundarray[2].to_f, boundarray[3].to_f]]
@ll = [params[:center].split(',')[0].to_f, params[:center].split(',')[1].to_f]
@sightings = Sighting.in_bounds(bounds, origin: @ll).order('created_at DESC')
@remap = false
else
search_params = '98101'
geocode = Geokit::Geocoders::GoogleGeocoder.geocode(search_params)
@ll = [geocode.lat, geocode.lng]
@sightings = Sighting.within(5, origin: @ll).order('created_at DESC')
@remap = true
end
@hash = Gmaps4rails.build_markers(@sightings) do |sighting, marker|
marker.lat sighting.latitude
marker.lng sighting.longitude
marker.name sighting.title
marker.infowindow view_context.link_to("sighting", sighting)
end
respond_to do |format|
format.html
format.js
end
end
search.html.haml
= form_tag search_sightings_path, method: "get", id: "zipform", role: "form", remote: true do
= text_field_tag :zipcode, params[:zipcode], size: 5, maxlength: 5, placeholder: "zipcode", id: "zipsearch"
= button_tag "Search", name: "button"
%input{type: "button", value: "Current Location", onclick: "getUserLocation()"}
#locationData
.sightings_map_container
.sightings_map_canvas#sightings_map_canvas
#sightings_container
- content_for :javascript do
%script{src: "//maps.google.com/maps/api/js?v=3.13&sensor=false&libraries=geometry", type: "text/javascript"}
%script{src: "//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js", type: "text/javascript"}
:javascript
function getUserLocation() {
//check if the geolocation object is supported, if so get position
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setLocation);
}
else {
document.getElementById("locationData").innerHTML = "Sorry - your browser doesn't support geolocation!";
}
}
function setLocation(position) {
//build text string including co-ordinate data passed in parameter
var displayText = "Latitude: " + position.coords.latitude + ", Longitude: " + position.coords.longitude;
//display the string for demonstration
document.getElementById("locationData").innerHTML = displayText;
//submit the lat/lng coordinates of current location
$.get('/sightings/search.js',{lat: position.coords.latitude, lng: position.coords.longitude});
}
// build maps via Gmaps4rails
handler = Gmaps.build('Google');
handler.buildMap({
provider: {
},
internal: {
id: 'sightings_map_canvas'
}
},
function() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setLocation);
}
var json_array = #{raw @hash.to_json};
var latlng = #{raw @ll};
resetMarkers(handler, json_array);
resetMap(handler, latlng);
// listen for pan/zoom and submit new coordinates
(function gmaps4rails_callback() {
google.maps.event.addListener(handler.getMap(), 'idle', function() {
var bounds = handler.getMap().getBounds().toUrlValue();
var center = handler.getMap().getCenter().toUrlValue();
$.get('/sightings/search.js',{bounds: bounds, center: center, old_hash: #{raw @hash.to_json}});
})
})();
});
search.js.erb
(function() {
var json_array = <%= raw @hash.to_json %>;
if (<%= @remap %>) {
var latlng = <%= raw @ll %>;
resetMarkers(handler, json_array);
resetMap(handler, latlng);
}
else {
resetMarkers(handler, json_array);
}
})();
map.js
(function() {
function createSidebarLi(json) {
return ("<li><a>" + json.name + "</a></li>");
};
function bindLiToMarker($li, marker) {
$li.on('click', function() {
handler.getMap().setZoom(18);
marker.setMap(handler.getMap()); //because clusterer removes map property from marker
google.maps.event.trigger(marker.getServiceObject(), 'click');
})
};
function createSidebar(json_array) {
_.each(json_array, function(json) {
var $li = $( createSidebarLi(json) );
$li.appendTo('#sightings_container');
bindLiToMarker($li, json.marker);
});
};
function clearSidebar() {
$('#sightings_container').empty();
};
function clearZipcode() {
$('#zipform')[0].reset();
};
/* __markers will hold a reference to all markers currently shown
on the map, as GMaps4Rails won't do it for you.
This won't pollute the global window object because we're nested
in a "self-executed" anonymous function */
var __markers;
function resetMarkers(handler, json_array) {
handler.removeMarkers(__markers);
clearSidebar();
clearZipcode();
if (json_array.length > 0) {
__markers = handler.addMarkers(json_array);
_.each(json_array, function(json, index){
json.marker = __markers[index];
});
createSidebar(json_array);
}
};
function resetMap(handler, latlng) {
handler.bounds.extendWith(__markers);
handler.fitMapToBounds();
handler.getMap().setZoom(12);
handler.map.centerOn({
lat: latlng[0],
lng: latlng[1]
});
}
// "Publish" our method on window. You should probably have your own namespace
window.resetMarkers = resetMarkers;
window.resetMap = resetMap;
})();
这就是问题所在,这与我对 javascript(我是新手)变量如何工作的看似误解一样,与这个特定示例有关。当用户平移和缩放,但搜索结果相同时,我宁愿不调用“resetMarkers”函数,而宁愿不理会地图。地图当前将始终重置标记/侧边栏/等,这会导致屏幕上的标记有点闪烁。
我已经尝试了几个不同的版本,但都不起作用。在 map.js 中:
var __markers;
var __oldmarkers;
function resetMarkers(handler, json_array) {
if(!(_.isEqual(__oldmarkers, __markers))) {
handler.removeMarkers(__markers);
clearSidebar();
clearZipcode();
if (json_array.length > 0) {
__markers = handler.addMarkers(json_array);
_.each(json_array, function(json, index){
json.marker = __markers[index];
});
createSidebar(json_array);
}
__oldmarkers = __markers.slice(0);
}
};
由于 __markers 似乎在页面的整个生命周期中都保持其价值(我们在设置新标记之前使用它来删除旧标记),我想我可以简单地创建另一个变量来检查它。然而,即使我认为它应该是真的,它也总是假的。
我尝试的另一件事是在每个搜索请求中重新提交旧哈希作为参数,然后设置一个标志,但这似乎很复杂,字符串/哈希/数组操作变得如此混乱,我放弃了。我真的不认为这是最好的方法,但也许我应该这样做?
或者,是否有什么我完全遗漏而应该做的事情?
【问题讨论】:
标签: javascript ruby-on-rails ajax gmaps4rails