Add user location marker to existing gmap - google-maps

I am using Drupal 7 - Location, GMap module. I have a view that renders the result in a gmap. Everything works fine here and I get all the markers. Now I need a Find My location button which shows the users current location and adds a marker to the existing map.
Google Map Api V3 always works on a newly created map and I couldn't find a function which returns an existing map in the current page.
Gmap module provides a JS function - Drupal.gmap.getMap('ur-map-id') which is supposed to return a pointer to the map whose id is given. But this did not work.
Could someone please guide me as to how I should go about this? Can I get it work with Google Maps API? I need to retain the original map with all its markers.

Here's something for reference.
if (typeof(navigator.geolocation) !== 'undefined') {
var showUserOnMap = function(position) {
var map = Drupal.gmap.getMap('gmap-auto1map-gmap0');
if (typeof(map) !== 'undefined' && map !== false) {
latitude = position.coords.latitude;
longitude = position.coords.longitude;
var marker = {
latitude: latitude,
longitude: longitude,
markername: Drupal.t('You'),
opts: {
title: Drupal.t('You')
}
}
marker.opts.position = new google.maps.LatLng(latitude, longitude);
marker.opts.map = map.map;
Drupal.gmap.factory.marker(marker.opts);
}
};
// Get the current location
navigator.geolocation.getCurrentPosition(showUserOnMap);
}

I am having this issue as well, you can put this jquery code in for it to actually centre around your current location - but no marker is added. Just add it anywhere in your theme,
jQuery(document).ready(function() {
jQuery(function($) {
$.extend({
initialize: function () {
var m = Drupal.gmap.getMap('auto1map');
if (m.map && m.markersready) {
$.setCoords();
}
else {
m.bind('markersready', function(data) {
$.setCoords();
});
}
},
setCoords: function () {
navigator.geolocation.getCurrentPosition(function (position) {
var gmap = Drupal.gmap.getMap('auto1map').map;
var lat = position.coords.latitude;
var lng = position.coords.longitude;
gmap.setCenter(new google.maps.LatLng(lat, lng));
gmap.setZoom(13);
});
}
});
$.initialize();
});
});
Now you can centre your map around your location and now I need to figure out a way to place a marker down at this location.

Related

Google Maps API - Get New Center Coordinates after map is moved

I'm using the Google Maps API to display a map, but I now need to capture the centre coordinators if the user moves the map. I'm after the new lat/long of the new centre of the map after it has been moved.
Looking at the Maps Events docs I can see a few options here:
center_changed
dragend
that I could potentially move. I've tried both but can't get the syntax right and not sure how to retrieve the centre lat/long. Here's my latest attempt
google.maps.event.addListener(map, 'dragend', function() {
var latitude = event.latLng.lat();
var longitude = event.latLng.lng();
console.log("current latitude is: "+latitude);
console.log("current longitude is: "+longitude);
});
but I get an error TypeError: undefined is not an object (evaluating 'event.latLng.lat') when this runs.
Can anyone tell me what the most approrpriate event to use here and how I can get the new centre co-ordinatates when the map has changed by the user dragging it.
If you want the center values when it changes, use the 'center_changed' event:
center_changed
Arguments: None
This event is fired when the map center property changes.
google.maps.event.addListener(map, "center_changed", function() {
var center = this.getCenter();
var latitude = center.lat();
var longitude = center.lng();
console.log("current latitude is: " + latitude);
console.log("current longitude is: " + longitude);
});
proof of concept fiddle
code snippet:
function initMap() {
var myLatlng = {
lat: -25.363,
lng: 131.044
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: myLatlng
});
google.maps.event.addListener(map, "center_changed", function() {
var center = this.getCenter();
var latitude = center.lat();
var longitude = center.lng();
console.log("current latitude is: " + latitude);
console.log("current longitude is: " + longitude);
});
}
html,
body,
#map {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map"></div>
<!-- Replace the value of the key parameter with your own API key. -->
<script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap">
</script>

Place API - getting place photo as marker icon

I follow this guide
https://developers.google.com/maps/documentation/javascript/places#places_photos
to create place photo as marker icon. This is my map initialization code:
var map;
function initMap() {
// Create a map centered in Pyrmont, Sydney (Australia).
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: -6.920812, lng: 107.604116},
zoom: 13
});
var request = {
location: map.getCenter(),
radius: '5000',
type: ['shopping_mall']
};
var service = new google.maps.places.PlacesService(map);
service.textSearch(request, callback);
}
// Checks that the PlacesServiceStatus is OK, and adds a marker
// using the place ID and location from the PlacesService.
function callback(results, status) {
console.log(results);
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createPhotoMarker(place);
}
}
}
google.maps.event.addDomListener(window, 'load', initMap);
this is the createPhotoMarker function
function createPhotoMarker(place) {
var photos = place.photos;
if (!photos) {
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
title: place.name
});
return;
}
var marker = new google.maps.Marker({
map: map,
position: place.geometry.location,
title: place.name,
icon: photos[0].getUrl({'maxWidth': 35, 'maxHeight': 35})
});
}
the function will create regular marker if place photo is not available. But for the place with photo available, I get this error :
Failed to load resource: the server responded with a status of 404 () lh3.googleusercontent.com/w35-h35-p/AF1QipOIL6GVVmtqp_cw_hBEQxdILZSa8poMO0HAqFHd=k
And the map only shows regular marker.
What did I do wrong?
This is the fiddle http://jsfiddle.net/v90fmrhp/
==========Update 2017-07-07============
Thanks for the answers and fixes
It seems the issue solved. My fiddle is working now
https://issuetracker.google.com/issues/63298126
Marked as Fixed
Good news! We have fixed this issue. Thanks for your patience.
Happy Mapping!
Looks like the error you are seeing is caused by some issue on Google's side. It's affecting quite a few other users as well, have a look at their public issue tracker:
Thanks for reporting this issue. We verified it and we'll keep tracking it.
https://issuetracker.google.com/issues/63298126
UPDATE (2017-07-06):
A fix for this is going into our release process now and it should be out soon - probably Monday at the latest.
https://issuetracker.google.com/issues/63298126#comment13
Had the same issue and Sulyman suggested a workaround that is working but I don't know for how long when google fixes this.
Google Places Photos .GetUrl is adding width and height to url
Here is what we did.
if(place.photos != null){
for(var i = 0; i < place.photos.length; i++){
//Do a string replace to get the w-h-p out of there.
var str = place.photos[i].getUrl({"maxWidth": 100, "maxHeight": 100});
var res = str.replace("w100-h100-p", "p");
self.pacPhotos.push({
id : res
});
}
}else {
console.log("no photo");
}
}
I also ran into this with google places api. Everything was working fine then randomly it stopped. It seems likely that it is due to google making changes as they get ready for releasing a better maps api to support vector
#DKinnison saved me with his solution so I just wanted to post my ES6 solution for parsing a received place. I commented out the other properties I am personally not using in case you need to.
const PHOTO_WIDTH = 600;
const PHOTO_HEIGHT = 600;
export function parseGooglePlace(place) {
if (!place) {
return;
}
const {
// address_components,
formatted_address,
geometry,
// icon,
// id,
// international_phone_number,
name,
// rating,
// reviews,
// opening_hours,
photos: _photos = [],
place_id,
// reference,
types = [],
// url: mapsURL,
// utc_offset,
// vicinity,
website,
} = place;
const photos = _photos.map(p =>
p
.getUrl({ maxWidth: PHOTO_WIDTH, maxHeight: PHOTO_HEIGHT })
.replace(`w${PHOTO_WIDTH}-h${PHOTO_HEIGHT}-p`, 'p'),
);
return {
website,
name,
photos,
address: formatted_address,
placeId: place_id,
geometry,
types,
};
}

Get all markers from GeoJSon map data and store them in an array?

I was wondering if my "logic" is correct.
I am loading different datas on a map using a geojson object using addGeoJson.
With this method markers as well as polygons, are drawn automatically, which is good but how to access to them from outside the map ?
There no problems at all, I just wanted to get all markers for all my geometry type "Point" to store them in an array, in order to be able to trigger them from outside the map and launch an infowindow for exemple.
I found nothing in documentation, so I used the code below to remove the markers then create the same markers and add them to markers array.
// add GeoJson datas
map.data.addGeoJson($.parseJSON(Config.polygon));
var bounds = new google.maps.LatLngBounds(),
markers = [];
map.data.forEach(function(feature){
if(feature.getGeometry().getType() === 'Polygon'){
feature.getGeometry().forEachLatLng(function(latlng){
bounds.extend(latlng);
});
}else if(feature.getGeometry().getType() === 'Point'){
var LatLng = feature.getGeometry().get(),
id = feature.getProperty('id'),
icon = Config.templateDirectoryUri+feature.getProperty('icon'),
marker = new google.maps.Marker({
position: LatLng,
map: map,
id: id,
icon: icon,
});
markers[id] = marker;
// load infowindow
IDV.mapInfoWindowHTML(feature, map, marker);
// remove previous markers from map.data
map.data.remove(feature);
}
});
// bounds gmap window to polygons boundaries
map.fitBounds(bounds);
Afterwards no problem to trigger my markers from my ".property" class using jQuery and data attribute.
$('.property').on('click', function () {
if($(this).data('markerid') !== 0){
google.maps.event.trigger(markers[$(this).data('markerid')], 'click');
}
})
.mouseenter(function() {
if($(this).data('markerid') !== 0){
markers[$(this).data('markerid')].setAnimation(google.maps.Animation.BOUNCE);
}
})
.mouseleave(function() {
if($(this).data('markerid') !== 0){
markers[$(this).data('markerid')].setAnimation(null);
}
});
My question is simple, does someone know a more efficient way to store markers directly form map.data, instead of having to add them again (new google.maps.Marker) and delete the previous one... it works well anyway like this.
Thanks

Adding Google Maps V3 User input through a searchbox

So, I found some instructions around and a few questions that seemed to answer this question, but none really worked for me or were very incomplete. I'm seeking a way to display the traditional google maps interaction of search and a pin is displayed on the map at the location. This marker, then, should be a blank option to include the data a user wants and the location saved to my database. I tried this sample by Google Dev and it worked for a custom click on the map, but the integration with a simple auto-complete search or even the google's own autocomplete search didn't quite worked.
I was wondering if there is a plugin or a technique (or a tutorial) that would suit this case (that I previously thought would be a simple matter as it is the traditional search on google maps). Thanks!
I can show you how I did this page http://www.a-zhotels.net/register, you could easily combine all the fields into one autocomplete address field. However, this should give you an idea.
First, create a function:
function getMapByGeoLocation() {
//build the address using many fields.
var postcode = $("#HotelPostcode").val();
var address = $("#HotelAddress").val();
var town = $("#HotelTown").val();
var city = $("#HotelCity").val();
var country = $("#HotelCountryId > option:selected").text();
var fulladdress = address + ', ' + town + ', ' + postcode + ', ' + city + ', ' + country;
geocoder.geocode(
{
'address': fulladdress
},
function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].geometry.location;
console.log(location);
//map and marker should be previously created
map.setCenter(location);
map.setZoom(14);
marker.setPosition(location);
//These 2 hidden inputs will be posted to the server
$("#HotelLatitude").val(location.Ya);
$("#HotelLongitude").val(location.Za);
} else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
This function is then called when the textbox and dropdowns change:
$("#HotelTown, #HotelAddress, #HotelPostcode").change(getMapByGeoLocation);
See below the function that creates the map:
var map;
var marker;
var geocoder;
function createMap() {
if (map) { //Map already exists
return;
}
if (!$('#mapCanvas').is(':visible')) {
return;
}
var mapCanvas = $("#mapCanvas")[0];
var averageLatitude = $("#HotelLatitude").val();
var averageLongitude = $("#HotelLongitude").val();
map = new google.maps.Map(mapCanvas, {
streetViewControl: true,
zoom: 13,
scrollwheel: false,
center: new google.maps.LatLng(averageLatitude, averageLongitude)
});
geocoder = new google.maps.Geocoder();
//Associate the styled map with the MapTypeId and set it to display.
map.setMapTypeId(google.maps.MapTypeId.ROADMAP);
marker = new google.maps.Marker({
position: new google.maps.LatLng(averageLatitude, averageLongitude),
draggable: true,
map: map
});
google.maps.event.addListener(marker, "dragend", function () {
var position = marker.getPosition();
map.panTo(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
google.maps.event.addListener(map, "center_changed", function () {
var position = map.getCenter();
marker.setPosition(position);
$("#HotelLatitude").val(position.lat());
$("#HotelLongitude").val(position.lng());
});
}
createMap();
I am not sure what exactly you are looking for.
If you are looking for autocomplete field that adds a marker to the map after the user entered some string and opens an infowindow with a form on the map, is may be something like that: http://jsfiddle.net/XG9Qj/2/
It is important to notice, that this example only places a marker on the map if the user selected one of the suggestions from the autocomplete. To allow him to enter an arbitrary string you have to watch the input for RETURN and use the google maps geocoder on your own(1).
var geocoder = new google.maps.Geocoder();
geocoder.geocode(...)

Geocoding using Google Maps API v3 - Linking the original request to the response

I have a list of schools that I want to plot on a Google Map. I'm using Google's Geocoding Service to lookup the lng/lat for a given postcode, upon successfully retrieving this information I want to drop a marker, together with adding the appropriate event listener that opens an infobox when a given marker is clicked.
When I make a request to the geocoder it's in the context of a school, when I receive a callback I lose this context. You'll see from code below that I've come up with a clunky solution to this, although it fails occasionally when the geocoder results truncate the postcode.
Should I be using something like jQuery's Deferred Object to solve this issue?
var geocoder;
var map;
var infowindow
var iterator = 0;
geosearch = new Array();
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() { // delay added to prevent being throttled
addMarker();
iterator++;
}, i * 1000);
}
}
function addMarker() {
address = schools[iterator].addresses[0].address.zip;
geosearch[address] = schools[iterator]; // this is how I'm keeping track of initial request
geocoder.geocode( { 'address': address }, function(results, status) {
var school = geosearch[results[0].address_components[0].short_name]; // loading the school associated with the initial request, which only works if the postcode completely matches up - clunky!
if (status == google.maps.GeocoderStatus.OK) {
// each school has tags, I want to set a marker if certain tags exist
if ($.inArray('D', school.tags) > 0) {
var image = 'map_markers/brown_MarkerD.png';
} else if ($.inArray('C', school.tags) > 0) {
var image = 'map_markers/red_MarkerC.png';
} else if ($.inArray('B', school.tags) > 0) {
var image = 'map_markers/yellow_MarkerB.png';
} else if ($.inArray('A', school.tags) > 0) {
var image = 'map_markers/green_MarkerA.png';
} else {
var image = 'map_markers/blue_MarkerZ.png';
}
// add the marker to the map, using result
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
draggable: false,
icon: image,
shadow: 'http://www.google.com/mapfiles/arrowshadow.png',
animation: google.maps.Animation.DROP
});
// adds listening on marker so that popup box appears when clicked
google.maps.event.addListener(marker, 'click', (function(marker, school) {
return function() {
infowindow.setContent(
''+school.name+''
+'<address>'
+school.addresses[0].address.street+'<br />'
+school.addresses[0].address.city+'<br />'
+school.addresses[0].address.state+'<br />'
+school.addresses[0].address.zip+'<br />'
+school.addresses[0].address.country+'<br />'
+'</address>');
infowindow.open(map, marker);
}
})(marker, school));
} else {
console.log("* NOT found: " + status);
}
});
}
function initialise() {
geocoder = new google.maps.Geocoder();
infowindow = new google.maps.InfoWindow();
var latlng = new google.maps.LatLng(54.82659788452641,-3.417279296874991);
var mapOptions = {
zoom: 6,
center: latlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
drop(); // loops through schools to add marker
}
I would suggest geocoding the addresses offline and storing the coordinates in your database (or wherever you are storing the addresses). Then use the coordinates to display the markers.
I would also suggest reviewing this article on geocoding strategies from the documentation
To answer your question, I would suggest using javascript function closures to associate the address with the callback function.
The problem I was experiencing here was just a questions of scope, and in particular the way that I was referencing the school within the addMarker() function. Rather than referencing the school within the schools array using the global iterator variable, I instead pass in this school, this way the correct school is always referenced on the callback that is created within this scope.
var geocoder;
var map;
var infowindow
var iterator = 0;
function drop() {
for (var i = 0; i < schools.length; i++) {
setTimeout(function() {
addMarker(schools[iterator]); // pass in the school as an argument
iterator++;
$('#current_school').text(iterator); // taken this out of addMarker()
}, i * 1000);
}
}
function addMarker(school) {
geocoder.geocode( { 'address': school.addresses[0].address.zip }, function(results, status) {
... // the inners from here remain the same
});
}