Google Maps randomly crashed when enable browser's location tracking, why? - google-maps

You can go to the live website to see how the problem occurred.
Steps to see the error are following
Go to the live website.
Enable you browser's location tracking.
Click one the the place name, it will open a new tab. It will display Google Map and center the map at the location that you clicked based on URL parameter.
The problem is sometimes it's not working randomly, it's showing plain grey background instead of showing the map.
If you try to refresh or click the place name again. The map might working.
But if you suddenly zoom out, it will crashed. You need to click the marker or dragging the map around, then you can zoom out with no problem.
All these problems are not occurred when you turn off the browser's location tracking.
Try it.
PS. Don't worry about 2 or 3 last digits of parameter. it has nothing
to do with this problem, I have tested it several times). The console log is not throw any errors also.
This is my code that involved when browser's location tracking is enabled. My full code is on JSFiddle.
function initialize() {
var myOptions = { zoom: 12, mapTypeId: google.maps.MapTypeId.ROADMAP };
map = new google.maps.Map(document.getElementById("map"), myOptions);
var infoWindow2 = new google.maps.InfoWindow({ content: '<div style="overflow:hidden;" id="currentInfoWindow"><p>You are here !!!</p></div>' });
// Try W3C Geolocation (Preferred)
if(navigator.geolocation) { // BEGIN IF USER ENABLE
browserSupportFlag = true;
navigator.geolocation.getCurrentPosition(function(position) { //getCurrentPosition
querystring = window.location.search.substr(1);
console.log(querystring);
element = querystring.split(",");
if (querystring) {
clickedLocation = new google.maps.LatLng(element[0],element[1]);
map.setCenter(clickedLocation);
map.setZoom(18);
} else {
initialLocation = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
}
//Set map center to be the user's location
map.setCenter(initialLocation);
//Place the marker of current position
var markerCurrent = new google.maps.Marker({
position: initialLocation,
map: map,
title:"You are here !!!",
icon : 'assets/frontend/images/yourmarker.png'
});
// Attaching a click event to the current marker
google.maps.event.addListener(markerCurrent, "click", function(e) {
infoWindow.close();
this.getMap().setCenter(this.getPosition());
map.setZoom(12);
infoWindow2.open(map, markerCurrent);
});
// IF NOT SUPPORT OR ENABLE >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
} // End getCurrentPosition
, function() { handleNoGeolocation(browserSupportFlag); });
} // END IF Browser doesn't support Geolocation
else {
//Other code here.
}

Currently you will never run into this branch:
else {
initialLocation = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
}
because there is always a QUERY_STRING.
Because of that initialLocation is not set, but you use it as argument for setCenter() .
changing this line:
clickedLocation = new google.maps.LatLng(element[0],element[1]);
into
initialLocation = new google.maps.LatLng(element[0],element[1]);
...should fix it.

Related

Overlapping Marker Spiderfier Marker Icon When There are Multiple Markers at Same Location

Google Maps doesn't provide a way to break apart multiple markers that are at the same location. This can occur with a people or businesses at a multiple residency location such as an apartment building or professional services building. Depending at zoom level it can also occur at shopping malls, etc.
The way around that is to "spiderfy" them: when clicking on the first it breaks them out with a line to the location. This is done in Google Earth and George MacKerron wrote a package to do that for Google Maps. (https://github.com/jawj/OverlappingMarkerSpiderfier)
It can be integrated with markerclusterer, although it doesn't support marker clusterer's batch creation of markers.
My issue is that the application I'm working on wants to have specific icons for different types of activities. Spiderfier puts one of the markers on top. A person looking at the map has no way of knowing that there can be 10 or more other markers underneath the top marker.
Ideally, there would be a way to put a top marker that displays when there are multiple markers similar to the different icon in markercluster. It isn't a direct 1-to-1 since spiderfier also works when they are close but not exactly at the same location (default is 20 pixels) and markercluster has no provision for accessing multiple markers at the exact same location.
The ideal behavior would be have a special icon for spiders that broke into the spiderfied individual icons when clicked. Similar to markerclusterer, but without the zoom change and handling the same location. The special icon ideally would indicate how many other markers are at the spot, again like markerclusterer. The special icon could be hidden or become part of the spiderfied group.
Without some accommodation users would have no way of knowing multiple activities are at the location. They may even assume that the activity they want is not at that location because another activities marker is shown.
This is a plunker that has the problem: http://plnkr.co/edit/vimZNq?p=info
var markers = [];
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < 100; ++i) {
var latLng = new google.maps.LatLng(Math.floor(Math.random() * 10) / 10 + 39,
Math.floor(Math.random() * 10) / 10 - 100);
var marker = new google.maps.Marker({
position: latLng,
title: "marker " + i + " pos: " + latLng,
maxZoom: 8,
map: map
});
marker.desc = marker.getTitle();
bounds.extend(latLng);
markers.push(marker);
oms.addMarker(marker);
}
map.fitBounds(bounds);
var markerCluster = new MarkerClusterer(map, markers);
Thanks for your help,
David
Here's how I got it to work. Where map is a Gmap instance and oms is an Overlapping Marker Spiderfier instance. We're also using Marker Clusterer on the initial zoom which buys us a break.
map.addListener('zoom_changed', function() {
map.addListenerOnce('idle', function() {
// change spiderable markers to plus sign markers
// we are lucky here in that initial map is completely clustered
// for there is no init listener in oms :(
// so we swap on the first zoom/idle
// and subsequently any other zoom/idle
var spidered = oms.markersNearAnyOtherMarker();
for (var i = 0; i < spidered.length; i ++) {
// this was set when we created the markers
url = spidered[i].icon.url;
// code to manipulate your spidered icon url
};
});
});
oms.addListener('unspiderfy', function(markers) {
var spidered = markers;
for (var i = 0; i < spidered.length; i ++) {
url = spidered[i].icon.url;
// change it back
};
});
oms.addListener('click', function(marker) {
// put the clicked-on marker on top
// when oms un-spiders
marker.zIndex=999;
// set infowindow, panning etc.
});
I managed to match the following Versions:
MarkerClusterer 2.0.13
OverlappingMarkerSpiderfier 3.27
On every creation of a new Marker, i store the initialIconUrl in the Marker Object
var marker = new google.maps.Marker({
position: //some position
});
marker.setIcon(iconUrl);
marker.initialIconUrl = iconUrl;
When declaring the OverlappingMarkerSpiderfier, set the nearbyDistance to 0.001 (or some other very small value).
this.oms = new OverlappingMarkerSpiderfier(this.map, {
markersWontMove: true,
markersWontHide: true,
nearbyDistance: 0.001 //This will only spiderfy the Markers if they have the exact same position
});
Then, we need a listener on the maps 'idle' Event, to format the Markers manually.
I needed this because my SPIDERFIABLE Marker wouldn't show correctly on the first step, when transferring from the Clustered Marker to the seperate Markers.
var me = this;
google.maps.event.addListener(this.map, 'idle', function () {
me.oms.formatMarkers();
});
Listen to the oms 'format' Event and set the iconURL for Markers that are SPIDERFIABLE.
If the Marker is not spiderfiable, reset the Icon to the initial Url.
var spiderfiableIconUrl = //Whatever you need
this.oms.addListener('format', function (marker, status) {
var iconURL = status == OverlappingMarkerSpiderfier.markerStatus.SPIDERFIABLE
? spiderfiableIconUrl :
marker.initialIconUrl;
marker.setIcon(iconURL);
});
Hope this helps.
Some methods seems to be interesting like markersNearAnyOtherMarker but I cannot get it work.
An interesting way could be to use spiderfy and unspiderfy events and change marker when it's fired
overlappingMarkers = new OverlappingMarkerSpiderfier(map, overlapOptions);
overlappingMarkers.addListener('spiderfy', function (markers) {
markers.forEach(function (marker) {
marker.setLabel('*');
marker.setIcon(myNormalIcon);
})
})
overlappingMarkers.addListener('unspiderfy', function (markers) {
markers.forEach(function (marker) {
marker.setLabel(''+markers.length);
marker.setIcon(myOverlapIcon);
})
})
Unfortunatly, the unspiderfy event isn't fired until we open then close the overlap marker. If I find a conclusion to this solution I will update this post.

Meteor: modals and google maps

I am displaying a google map in a modal and I see lots of people have had this issue and there seems to be a fix but so far nothing I've tried has worked.
Basically I am loading googles places search in Template.map.rendered - it seems like something is happening with the DIVs because when I resize the window it re-renders and displays properly.
Now, I have tried all kinds of tricks (hiding / showing various DIVs), calling google.maps.event.trigger(map, "resize"); etc.
The map template is being loaded into another template that is a form (with other fields etc).
If someone could point me in a fruitful direction that would be awesome - seems like it should be a simple fix but I'm stumped.
Thanks!
You're in luck, we just solved our issue regarding this. Assuming the template map is called within a modal:
Template.map.rendered = function() {
Tracker.autorun(function() {
Session.set('map_available', true);
var center = {
latitude: -1.8445
longitude: 52.9445
}; // end var center
var zoomLevel = 15;
if(Session.equals('map_available', true)) {
GoogleMaps.init({'sensor': true, 'key' : 'OPTIONAL_KEY' },
function() {
var mapOptions = {
zoom: zoomLevel,
minZoom: 15,
maxZoom: 20,
mapTypeId: google.maps.MapTypeId.ROADMAP,
navigationControlOptions: {
style: google.maps.NavigationControlStyle.SMALL
};
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setCenter(new google.maps.LatLng( center.latitude, center.longitude ));
} // end closure param 2 of GoogleMaps init
}); // end GoogleMaps.init
} // end Session.equals 'map_available'
} //end Tracker.autorun
} // end Template.map.rendered
Template.map.destroyed = function() {
Session.set('map_available', false);
}
So the strategy here is to monitor dependency tracking independently and make sure it gets re-added after any DOM reactions. Bonus feature here is that if you include var center modification inside Tracker.autorun (e.g. var center = navigator.location) you will have a map that changes center when you move around (lat, long has changed).
Also, we used the extension mrt:googlemaps for the GoogleMaps integration. Seems to be the best one to use.
Had the same problem that stumped me for an hour. My easy fix was to wrap it in a window onload. Try it, you might like it :-)
Template.mapsAutoComplete.rendered = function() {
window.onload = function () {
var map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);
...
};
};

need to add multiple markers using custom google map api

i was checking out the google map api to integrate in my website.
made this page with what ever i could understand so far.
everything is working fine but there is just one thing, that i want three markers on the same map.
when i am adding more than one markers then the map stops working.
test link : http://goo.gl/X9q92s
you will have a better understanding if u see my link.
this is the code that i got from google map api.
and i edited it to get grey scale map with my desired marker box.
i just want to add two more....
Please help.
<script>
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var mapOptions = {
zoom: 4,
center: myLatlng
}
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title: 'Hello World!'
});
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
You should place your "new marker" code into its own function, like so:
function LoadMarkers(name, lat, lng) {
var MarkerLatLng = new google.maps.LatLng(lat, lng);
var MarkerOption = { map: map, position: MarkerLatLng, title: name};
var Marker = new google.maps.Marker(MarkerOption);
}
Putting this into its own function allows you to "refresh" the markers with ease, by simply invoking the function with a timer or some other event. A program I'm working on refreshes the map every few seconds, as my data source is constantly changing with new/removed/updated records that should be reflected immediately on the map. I think this is a great way to do this.
Then, in your program, you can create a loop that shoots the information for each marker in by invoking the LoadMarkers function. I've recently fallen in love with SqlDataReader.
Your loop would iterate through a SqlDataReader and each record read will invoke the script like so:
InvokeScript("LoadMarkers", New Object() {name, lat, lng})
This is a great moment to also add an InfoWindow for each marker.
var infowindow = new google.maps.InfoWindow(
{
content: "Content here"
});
As well as a click listener for the InfoWindows. ;)
google.maps.event.addListener(Marker, 'click', function () {
typeof infoWindowsOpenCurrently !== 'undefined' && infoWindowsOpenCurrently.close(); //If there is an InfoWindow currently open, close it
infowindow.open(map, Marker); //Open a new one for the selected marker
infoWindowsOpenCurrently = infowindow; //Set the new info window to the temporary variable
});
Some might not like this method of using a loop. I like it because I can "personalize" each marker for each record, while personalizing each of their InfoWindows too. In my code above, assume that "name" is a unique ID that lets you specify a specific marker for later use, such as identifying which marker was clicked and which InfoWindow is currently open.

Google map in a tab created with angularjs is not centered

I have the following problem:
I'm working in an aplication to book hotels that has tabs ("Hotel Details", "Map", "Reviews") in the overview page. the tabs are created with angularjs.
also, in the page I have the hotel address that is a link to the "Map" tab.
When I click on the "Map" tab, the google map is rendering ok. But, when I click on the hotel address, the "Map" tab opens but the map is not centered. If I refresh the page, it appears centered.
this is the code that process the map:
$scope.loadMap = function (targetID){
var latitude = $scope.latitude;
var longitude = $scope.longitude;
if(latitude && longitude && document.getElementById(targetID) != null ){
var center = new google.maps.LatLng(latitude, longitude);
var map_options = {
zoom: 13,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(targetID), map_options);
// configure marker
var marker_options = {
map: map,
position: center,
title: $scope.hotelName
};
// create marker
var marker = new google.maps.Marker(marker_options);
var infoWindow = new google.maps.InfoWindow();
window.setTimeout(function(){
google.maps.event.trigger(map, 'resize');
},2000);
}
}
Can you help me, please?
I've had this very problem when I was creating maps using Leaflet.js. I was trying to initialize the map inside of my angular service and it was loading very strangely. It appears you are trying to do the same thing, but you're doing it inside of your controller, rather than a service, but the effect is the same thing.
The problem is timing. Your controller is run before the DOM finishes loading and before angular has a chance to scan through the DOM to build out your Map page partial. Because of that, the page is only partially loaded when you call $scope.loadMap, which loads the google map, as you would expect. The problem is that once Angular finishes scanning the DOM partial, it modifies the DOM and then loads it into the view. When this happens, the google map has already been initialized to its default size based on the previous state of the DOM, and doesn't resize properly when angular is finished with the DOM.
Ok, that was a long explanation, but here's how you fix it:
You should do all of your map initialization inside of a directive's linking function. You could create a directive called something like app.directive('hotelMap'), which would initialize your map using the $scope.latitude and $scope.longitude variables from your controller.
link: function(scope, elem, attrs){
var center = new google.maps.LatLng(scope.latitude, scope.longitude);
var map_options = {
zoom: 13,
center: center,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// create map
var map = new google.maps.Map(document.getElementById(targetID), map_options);
// configure marker
var marker_options = {
map: map,
position: center,
title: $scope.hotelName
};
// create marker
var marker = new google.maps.Marker(marker_options);
var infoWindow = new google.maps.InfoWindow();
}
And then in your map partial, you would have an element that looks something like <div hotel-map></div>. This fixes your problem, because your map will never be initialized until Angular has finished scanning/modifying the DOM and has finished rendering your partial. That way, the map's containing element will be at its final size/position and the map will be loaded into the element's center properly. Give it a try and let me know if that works.

Mini Map in InfowWindow for direction route

I am working in Google Map v3(actually migrating V2 to V3), and trying to customize the Infowindow of the Direction Service.
I am able to display the Direction using Origin, Destination and waypoints.
My Map displayed the route correctly with Marker (green marker with A, B, C... text).
By default, On click of teh marker infowindow will display address of that marker.
I want to customize it, so that on click of marker it should disply mini map of that location in Infowindow with more zoom.
I am able to do some progress, but the problem here is,
- Marker is changed to red pointing marker instead of Green marker (with A, B, C...text)
- whichever the marker I click, infowindow will open on the last marker
- Once marker is clicked it will display minimap, but on close and again click of that marker it will display address (default behaviour)
- my code is actually overwriting the green marker with red pointed marker
Can soboby help me how to fix all these issue
Below is my code:
function CreateDirection (arrWaypoints) {
if (!this.directions) {
this.directions = new google.maps.DirectionsService();
var origin = arrWaypoints[0];
var destination = arrWaypoints[arrWaypoints.length - 1];
var tripWaypoints = [];
for (var i = 1; i < arrWaypoints.length - 1; i++) {
tripWaypoints.push({
location: new google.maps.LatLng(arrWaypoints[i].hb, arrWaypoints[i].ib),
stopover: true
});
}
var myMap = MyMap.getMap();
var steps = [];
this.directions.route({
origin: origin,
destination: destination,
waypoints: tripWaypoints,
travelMode: google.maps.DirectionsTravelMode.DRIVING,
unitSystem: google.maps.DirectionsUnitSystem.METRIC
}, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay = new google.maps.DirectionsRenderer();
// directionDiv div element in my page
directionsDisplay.setPanel(document.getElementById("directionDiv"));
directionsDisplay.setMap(myMap);
directionsDisplay.setDirections(result);
}
});
}
}
function CreateMiniMapInfoWindow (wayPointsArray) {
for (var i = 0; i < wayPointsArray.length; i++) {
var myMap = MyMap.getMap();
var marker = new google.maps.Marker({
position: wayPointsArray[i],
map: myMap
});
google.maps.event.addListener(marker, 'click', function() {
var myOptionsMini = {
zoom: 14,
center: wayPointsArray[i],
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var infowindow = new google.maps.InfoWindow();
var minimap = new google.maps.Map(document.getElementById ("minimap"), myOptionsMini);
document.getElementById("minimap").style.display = 'block';
minimap.setCenter(marker.getPosition());
var minimapDiv = document.getElementById("minimap");
infowindow.setContent(minimapDiv);
infowindow.open(myMap, marker);
});
}
}
I need the solution for:
- How to get customized infowindow (with minimap) for all the markers
- How to put the green markers with text A, B, C...
Attached image is what I am getting from the above code
I hope my question is clear.
Please let me know if anyone have any inputs.
Thanks,
Sharath
Pass the following object as argument to the DirectionsRenderer:
{markerOptions:{clickable:false,zIndex:1000}}
It will have 2 effects:
the custom markers will be placed behind the A,B,C-markers created by the DirectionsRenderer(currently they are still present, but behind your custom markers)
the markers created by the DirectionsRenderer are not clickable, the underlying custom markers are able to receive the click.
another option(I would prefer it): set the suppressMarkers-option of the DirectionsRenderer to true and use the A,B,C-markers for your custom markers(e.g. https://maps.gstatic.com/mapfiles/markers2/marker_greenA.png , https://maps.gstatic.com/mapfiles/markers2/marker_greenB.png )
Related to the infoWindow: all you need is 1 infoWindow with 1 map for all markers. Observe the click-event of the markers and when it occurs open the infoWindow and center the map inside the infowindow at the markers position(may be retrieved inside the click-callback via this.getPosition())
Note: instead of using your predefined waypoints you better parse the route returned by the directionsService to place the custom markers at the exact positions(these may differ from your predefined waypoints)