bounds google maps - google-maps-api-3

My Google maps API map zooms put to show all the markers added after a google places search. On a mobile map this can take a bit to load and as this app for cyclists I prefer to only show the results within the viewport. Most research I read indicates it is not possible to only return results within the view port. Is it possible for me to just keep the map bounds from changing after the markers are added? It would be great if it would just show me the markers added to the current bounds unless there is only one marker returned, then it should zoom to that marker. So searching for something general like pizza will show many pizza places in the current viewport without panning or zooming. Searching for a specific address will zoom to that marker even if it is outside the viewport.
var input = document.getElementById('target');
var searchBox = new google.maps.places.SearchBox(input);
var bounds = map.getBounds();
searchBox.setBounds(bounds);
var markers = [];
service = new google.maps.places.PlacesService(map);
google.maps.event.addListener(searchBox, 'places_changed', function() {
var places = searchBox.getPlaces();
// alert("getPlaces returns "+places.length+" places");
for (var i = 0; i < gmarkers.length; i++) {
gmarkers[i].setMap(null);
}
gmarkers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0, place; place = places[i]; i++) {
var place = places[i];
createMarker(place);
bounds.extend(place.geometry.location);
}
map.fitBounds(bounds);
// if (markers.length == 1) map.setZoom(17);
});
google.maps.event.addListener(map, 'bounds_changed', function() {
var bounds = map.getBounds();
searchBox.setBounds(bounds);
});
ib = new InfoBox({});

The answer to your question:
it possible for me to just keep the map bounds from changing after the markers are added?
is yes. And as you say, involves removing the map.fitBounds.
To get the map to center and zoom on a single address, either use the geocoder for that (implement it separately) or check the number of results, if it is one, center the map on the result and if there is a suggested viewport in the result, use that to center and zoom the map [with map.fitBounds(place.geometry.viewport) I think].

Related

Google maps performance with 2000 markers

I have am displaying 2000 markers on google maps. I notice the performance is a little slow. What I am not sure about... is it it slow because if the number of markers added to the map or visibility? How do I improve the performance? Can I just add them to the map and "hide" markers outside of bounds? Would that help or would it not because even though its not visible, its added to the map? The data to show the markers is in an list called var datapoints = [...].
My code to add markers is like this:
for (i = 0; i < markers.length; i++) {
var data = markers[i]
var myLatlng = new google.maps.LatLng(data.lat, data.lng);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: data.title
});
(function (marker, data) {
google.maps.event.addListener(marker, "click", function (e) {
infoWindow.setContent(data.description);
infoWindow.open(map, marker);
});
})(marker, data);
}
Any optimization recommendations appreciated!
You have a few options here. Google's docs suggest either limiting visible markers to the current viewport, clustering (distance or grid based), or fusion tables. I've implemented google maps with a customization of the MarkerClusterer module that works quite well for large amounts of markers on one map. Best of luck!

MarkerclustererPlus - returning array of markers to a cluster info window

I am using Markerclustererplus with Google Maps API v3 to ease the display of markers on the screen.
The problem is that I will have several markers in the exact same place (and it should be that way) and I would like to, when clicking on a cluster, to display an info window containing all the markers that were clustered.
I've tried several code and similar questions here in StackOverflow, unfortunately I do not master JS and couldn't solve this.
Markers are pushed into an array with some data:
var marker = new google.maps.Marker({
position : latlng,
map : map,
icon : marker_image
});
map.markers.push(marker);
When I click an isolated marker, the info window appears ok with a title and an image of that marker:
var infowindow = new google.maps.InfoWindow({
content : $marker.attr('data-title') + '<img width="50" src="' + $marker.attr('data-image') + '">'
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open( map, marker );
});
What I would like to happen, is that when clicker a cluster, an info window would open with all of the markers it contains displayed with their corresponding title and image (like, reversing the clustering operation).
Thank you for the help.
Managed to solve this, thanks to the example provided in here.
If anyone is interested, here is how I've done:
First, I've added the markers to the map getting data attributes coming from several custom fields from Wordpress custom posts:
function add_marker( $marker, map ) {
var latlng = new google.maps.LatLng( $marker.attr('data-lat'), $marker.attr('data-lng') );
var marker_image = $marker.attr('data-marker');
var marker_name = $marker.attr('data-title');
var marker_userpicture = $marker.attr('data-image');
var marker = new google.maps.Marker({
position : latlng,
map : map,
icon : marker_image,
name : marker_name,
userpicture : marker_userpicture
});
map.markers.push(marker);
Created the MarkerCluster:
var markerCluster = new MarkerClusterer(map, map.markers, mcOptions);
Added a click event listener that got the markers from the cluster, their data, created the info window content from that data and finally opened the info window:
google.maps.event.addListener(markerCluster, 'click', function(cluster){
var content ='';
var clickedMarkers = cluster.getMarkers();
for (var i = 0; i < clickedMarkers.length; i++) {
if(i==0) {
var var_pos = clickedMarkers[i];
}
var clickedMarkersNames = clickedMarkers[i].name;
var clickedMarkersPicture = clickedMarkers[i].userpicture;
content +=clickedMarkersNames;
content +=clickedMarkersPicture;
}
var infowindow = new google.maps.InfoWindow();
infowindow.setContent(content);
infowindow.open(map,var_pos);
});

Google maps api v3 remove markers when dragstart

I have the following function. geolocationService.getNearbyPeoples() is a service that
fetch data from db.
function nearbyPeoples(meLat, meLng, map){
geolocationService.getNearbyPeoples(meLat, meLng).then(function(response){
for (var i = 0; i < response.data.length; i++) {
var nearbyLatLng = new google.maps.LatLng(response.data[i].lat, response.data[i].lng);
var nearbyMarkers = new google.maps.Marker({
position: nearbyLatLng,
title: response.data[i].first_name
}).setMap(map);
};
});
}
then when dragend a center marker (meMarker) will call the function above to show nearby markers
google.maps.event.addListener(meMarker, 'dragend', function() {
nearbyPeoples(meMarker.position.lat(), meMarker.position.lng(), map);
});
then I want to remove the previous markers in dragstart. The reason is to prevent duplicated
markers if meMarker is dragend same location.
google.maps.event.addListener(meMarker, 'dragstart', function() {
});
But I have no idea how to remove or any better suggestions?
Instead of removing markers, why not keep a list (object) of markers as they are added and use it to avoid duplicating a marker? And/or use it to remove markers outside the bounds of the map view, if you must remove markers.

fire click event on individual marker while using leaflet markercluster plugin

My site consists of a Leaflet map with the leaflet.markerclusters plugin. I am also using Flowplayer to play a video that opens in a JQuery Tools overlay using the selector id "#video1".
Currently, when I click on any marker on the map it fires my test video in an overlay. My goal is to create a click event unique to each individual marker in the cluster. Eventually, I would like every marker to have a click event that fires a video unique to that marker.
I am a beginner, and have been doing okay using these well documented libraries up until now. However, I don't have the skills to bridge this current gap. Would someone please give me a push in the right direction? Below is a link to my JS Fiddle. My issue begins on JavaScript line 2098.
var markers = new L.MarkerClusterGroup();
var addressPoints = [
[40.634902, -73.965054, "Video1"],
[40.660897, -73.961082, "Video2"],
[40.693353, -73.970413, "Video3"],
[40.693289, -73.966289, "Video4"],
[40.68973, -73.971007, "Video5"],
[40.718423, -73.957428, "Video6"],
[40.71817, -73.956918, "Video7"],
[40.681427, -73.993959, "Video8"]
];
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = new L.Marker(new L.LatLng(a[0], a[1]), {
title: title
});
marker.bindPopup(title);
markers.addLayer(marker);
}
map.addLayer(markers);
//assign video div ID to overlay
$('#video1').overlay({
load: false,
top: "center",
left: "center"
});
//bind marker click event to overylay
markers.on('click', function () {
$("#video1").data("overlay").load();
});
Thank you,
Joey
http://jsfiddle.net/Joey84/nM458/26/
You are headed in the right direction with the markers.on("click"... function. You just need to make a few edits. Just as you added the event listener to the entire "markers" layer, you can add it to individual markers in your for loop.
...
for (var i = 0; i < addressPoints.length; i++) {
var a = addressPoints[i];
var title = a[2];
var marker = new L.Marker(new L.LatLng(a[0], a[1]), {
title: title
});
if (title=="Video1") {
marker.on('click', function () {
$("#video1").data("overlay").load();
});
}
marker.bindPopup(title);
markers.addLayer(marker);
}
...
Likewise - and probably the better solution - you can access details about the marker you clicked in the on("click"... you are currently using by passing a variable to the function. This would be useful if you have multiple videos and don't want to check with an if statement when creating markers.
markers.on('click', function (d) {
// Grab marker title and make it look like an ID
var marker_title = "#" + d.layer.options.title.toLowerCase();
// Make sure the jQuery object exists
if ( $(marker_title) ){
// Call up the video.
$(marker_title).data("overlay").load();
}
});
Note that I used toLowerCase() because your data has the title capitalized and the video id is all lowercase.
Here it is in action:
http://jsfiddle.net/nM458/44/

Draggable Marker to Update Lat and Long Fields

I wonder whether someone may be able to help me please.
I've put some coding together (please see below) whereby a user goes onto a HTML form, they type in an address and click a 'Search' button. Upon doing this, the location is plotted on the Google map and the Lat and Long co-oridnates are automatically entered into the associated text boxes on my form.
What I would like to do, if at all possible, is for the marker to be draggable so the user can fine tune the location, and as they drag the marker, I'd like for the Lat and Long fields to change their
associated co-ordinates.
In addition, I'd also like, if at all possible, to have a field on the form called 'NearestAddress' to show the nearest address to where the marker has been dragged to.
I've managed to make the markers draggable but they don't update the Latitude and Longitude text boxes. I'm also unsure how to add the functionality to show the updated address to where the marker has been dragged to.
(function() {
// Defining some global variables
var map, geocoder, myMarker, infowindow;
window.onload = function() {
// Creating a new map
var options = {
zoom: 3,
center: new google.maps.LatLng(55.378051,-3.435973),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map'), options);
// Getting a reference to the HTML form
var form = document.getElementById('LocationSearchForm');
// Catching the forms submit event
form.onsubmit = function() {
// Getting the address from the text input
var address = document.getElementById('Address').value;
// Making the Geocoder call
getCoordinates(address);
// Preventing the form from doing a page submit
return false;
}
}
// Create a function the will return the coordinates for the address
function getCoordinates(address) {
// Check to see if we already have a geocoded object. If not we create one
if(!geocoder) {
geocoder = new google.maps.Geocoder();
}
// Creating a GeocoderRequest object
var geocoderRequest = {
address: address
}
// Making the Geocode request
geocoder.geocode(geocoderRequest, function(results, status) {
// Check if status is OK before proceeding
if (status == google.maps.GeocoderStatus.OK) {
// Center the map on the returned location
map.setCenter(results[0].geometry.location);
// Creating a new marker and adding it to the map
var myMarker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
draggable:true
});
document.getElementById('Latitude').value= results[0].geometry.location.lat();
document.getElementById('Longitude').value= results[0].geometry.location.lng();
google.maps.event.addListener(myMarker, 'dragend', function(evt){
document.getElementById('current').innerHTML = '<p>Marker dropped: Current Lat: ' + evt.latLng.lat().toFixed(3) + ' Current Lng: ' + evt.latLng.lng().toFixed(3) + '</p>';
});
google.maps.event.addListener(myMarker, 'dragstart', function(evt){
document.getElementById('current').innerHTML = '<p>Currently dragging marker...</p>';
});
map.setCenter(myMarker.position);
myMarker.setMap(map);
}
});
}
})();
I am new to Google maps development and I'm not even sure whether it's possible to achieve what I want. I've been working on this now for a few weeks and it's driving me a little crazy, so if someone could perhaps point me in the right direction it would gratefully be received.
Many thanks and kind regards
Chris
Instead of evt.latLng.lat().toFixed(3) you should just use the myMarker object and grab it's position.
Getting the nearest address is not that easy, but requires reverse geocoding, and to be honest I don't see the point in doing it. You would have to make special cases for the occurences where there couldn't be found a closest address and stuff like that.
If you really want to do it though there is a webservice you can call to do it.

Resources