Google Maps JS API - getBounds() not always defined - javascript

I am using the Google Maps Javascript API to render a map and display a set of location markers on it. To reduce the amount of data being returned through the AJAX request that gets the locations I am sending the coordinates of the bounding box in the request to return only the visible locations.
I currently have code along the lines of:
google.maps.event.addListener(Map.map, "bounds_changed", function() {
Map.bounds.north = Map.map.getBounds().getNorthEast().lat();
Map.bounds.east = Map.map.getBounds().getNorthEast().lng();
Map.bounds.south = Map.map.getBounds().getSouthWest().lat();
Map.bounds.west = Map.map.getBounds().getSouthWest().lng();
});
Which as I understand how getBounds works should update Map.bounds (which is being sent to the server to retrieve the data) when the map is moved. However I cannot get it to set Map.bounds when the map is created, so the initial request for locations fails. If i call Map.map.getBounds outside of google.maps.event.addListener I get an error that getBounds is undefined. How can I set the bounds once the map has loaded, before the user interacts with it?
(I also tried "idle" in addition to "bounds_changed" with the same results)

The Google Maps Javascript API is event based. If you call getBounds on the map before the first bounds_changed event fires, it won't work. Any time after it is set for the first time will work.
Example:
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: 42,
lng: -72
},
zoom: 8
});
}
google.maps.event.addDomListener(window, 'load', initMap);
html,
body,
#map {
height: 100%;
width: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<input type="button" value="get bounds" onclick="document.getElementById('bounds').innerHTML = map.getBounds().toUrlValue(6);" />
<div id="bounds"></div>
<div id="map"></div>

Related

Replace long/lat on Google maps via AJAX

I have this map script from Google Maps implemented on my site. What I'd like to do is I'd like to replace the latitude and longitude numbers (lat & lng) with numbers I've fetched from an API via AJAX.
The variables containing the longitude numbers and latitude numbers are returned like: data.mondayLat & data.mondayLong via the successfunction of AJAX. I've tried just replacing the default map setting 00.0000000 with data.mondayLat, but that isn't working. How do I make those variables continuously replace the default numbers in the map function, and make the map update each time I fetch data via AJAX?
<script>
function initMap() {
/* The following variable data I want to replace with the AJAX responde numbers */
var myLatLng = {lat: 00.0000000, lng: 00.0000000};
var map = new google.maps.Map(document.getElementById('googleMap'), {
zoom: 13,
center: myLatLng
});
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Today we are here'
});
}
google.maps.event.addDomListener(window, 'load', initMap);
</script>
<div id="googleMap" style="width:500px;height:380px;float:lefT;margin-left:20px;border:3px solid;"></div>
Your AJAX request is asynchronous. Call the initMap routine in the AJAX success function once you have the results (data.mondayLat and data.mondayLong exist).

Google Maps API v3.22 reverting to old controls

Google yesterday released v3.22 of their maps api which moves a bunch of the standard controls.
According to the Google Blog at http://googlegeodevelopers.blogspot.co.uk/2015/09/new-controls-style-for-google-maps.html#gpluscomments you can temporarily revert to the old controls, but I can;t get this to work at all.
The blog post says to simply add google.maps.controlsStyle = 'azteca' before you initialize the map, but I'm still getting the old controls displayed and they clash with some of my custom controls.
I've tried adding the line right at the start of my initialize() routine (which sets up all of the map options and creates the map object; and also right before the map = new google.maps.Map() statement.
Has anyone got any pointers as to what I'm doing wrong?
They have a typo in the post (and in the documentation)
Issue in the issue tracker
google.maps.controlsStyle = 'azteca';
should be:
google.maps.controlStyle = 'azteca';
code snippet:
var map;
function initMap() {
google.maps.controlStyle = 'azteca'
map = new google.maps.Map(document.getElementById('map'), {
center: {
lat: -34.397,
lng: 150.644
},
zoom: 8
});
}
google.maps.event.addDomListener(window, 'load', initMap);
html,
body,
#map {
height: 100%;
width: 100%;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<div id="map"></div>
try this:
google.maps.controlStyle = 'azteca';

Directions map not centering/zooming properly

UPDATE: I have a static solution working right now, but I'd still like to see if it can be improved upon. All of the code is the same aside from the on click event for switching views.
$(document).on('click', '.mobile-toggle a', function (e) {
e.preventDefault();
if (!$(this).hasClass("active")) {
var target = $(this).attr("data-target");
$("#results > div, .mobile-toggle a").removeClass("active");
$(this).addClass("active");
$("#" + target).addClass("active");
}
var center = dmap.getCenter();
google.maps.event.trigger(dmap, 'resize');
dmap.setCenter(center);
dmap.setZoom(12);
});
This gets the map centered properly, which is good. The zoom is also fine, but it doesn't always fit the route. Sometimes the route is too big to fit, and other times the map should probably be zoomed in a little bit more. Is there any way to determine the zoom value that should be used based on the route? I'm fairly certain this is generally supposed to happen on its own, but that doesn't seem to be the case this time around.
Original post below.
I've read a bunch of questions/answers about this, but none of the provided answers seem to do what I'm looking for. I'll try to explain this the best I can.
I'm currently writing a store locator. On desktop, everything looks fine. Mobile is where I run into difficulty because of some changing views (showing/hiding divs). From what I've read, it looks like a lot of people run into a problem where the map is created in a hidden div and then it's displayed incorrectly (e.g. the map only occupies the top left area of the container) when the div is shown.
The layout of the store locator is as follows - after you search for a location, you see a list view of all the results. When you click the 'map view' tab up top, you see a Google maps view with all of the nearby stores on it. This works fine. If you select a store and click 'get directions' from the list view, you see a list view of the directions to get to that store. Likewise, if you select a store and click 'get directions' while in map view, you see a map of the directions. That works fine in both scenarios.
The issue is when I am in a list view, click to get directions, and then switch over from the list view of directions to the map view. The map gets drawn with the correct route and it fills the div just like it should - however, the route is in the top left of the map, and the map itself is zoomed way out. For example, if the route is in the Philadelphia area, the map is so zoomed out that its center is generally around Bermuda. And it's roughly the same spot in Bermuda every time.
Here's the relevant code for the button press between list and map views.
$(document).on('click', '.mobile-toggle a', function (e) {
e.preventDefault();
if (!(this).hasClass("active")) {
var target = $(this).attr("data-target");
$("#results > div, .mobile-toggle a").removeClass("active");
$(this).addClass("active");
$("#" + target).addClass("active");
}
google.maps.event.trigger(dmap, 'resize');
}
dmap is a global variable containing the directions map, and the map itself has these two listeners assigned to it when it is created.
google.maps.event.addListener(dmap, 'idle', function () {
google.maps.event.trigger(dmap, 'resize');
dmapCenter = dmap.getCenter();
});
google.maps.event.addDomListener(window, 'resize', function () {
dmap.setCenter(dmapCenter);
});
This redraws the map and makes sure the center stays the same while the window is resized, but the map itself still isn't focused on the route from location A to location B. I feel like the solution can't be too far from what I've already tried (based on what I've read), but I can't seem to get this working.
Sorry about the wall of text. If there's any other code you think would help potentially answer the question, please let me know. Thanks!
EDIT: As requested, here's the full code that draws the map.
function calcRoute(start, dest) {
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
var mapOptions = {
zoom: 12,
center: new google.maps.LatLng(lat, lng)
};
var map = new google.maps.Map(document.getElementById('directions-map'), mapOptions);
directionsDisplay.setMap(map);
directionsDisplay.setPanel(document.getElementById('directions'));
var request = {
origin: start,
destination: dest,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
dmap = map;
dmapCenter = map.getCenter();
google.maps.event.addListener(map, 'idle', function () {
google.maps.event.trigger(map, 'resize');
dmapCenter = map.getCenter();
});
google.maps.event.addDomListener(window, 'resize', function () {
map.setCenter(dmapCenter);
});
}
lat and lng are global variables with the latitude and longitude of the search location.
The workflow you are using (IMHO) seems a little odd to me (IMHO), mainly of your choice to initialize a map instance every time you calculate the directions.
I don't know how much this will help since I haven't been able to test it on a mobile device, but below is code to make a google map, render directions between two points, and maintain the map center after the map is resized (test resize by running snippet in full page than resizing the browser window).
var DMAP,
DMAP_RENDERER,
DIRECTIONS_SERVICE;
/*
Run only once when your page loads to ready global components
for any future direction calls.
*/
function initializeDirectionsFeature(){
//set up directions map
var dmapOptions = {
zoom: 4,
center: new google.maps.LatLng(38.8282, -98.5795) //USA center
};
DMAP = new google.maps.Map( $("#map").get(0), dmapOptions);
//set up renderer for directions map
var rendererOptions = {
map: DMAP,
panel: $("#directions").get(0)
};
DMAP_RENDERER = new google.maps.DirectionsRenderer(rendererOptions);
//Initialize the directions service
DIRECTIONS_SERVICE = new google.maps.DirectionsService();
//Trigger map redraw when dom element is resized
google.maps.event.addDomListener(window, 'resize', function () {
google.maps.event.trigger(DMAP, 'resize');
});
//Preserve map perspective when after resize
google.maps.event.addListener(DMAP, 'resize', function () {
var center = DMAP.getCenter();
google.maps.event.addListenerOnce(DMAP, 'center_changed', function () {
DMAP.setCenter( center );
});
});
}
/*
Gets and renders the directions between params.
Params 'from' and 'to' can be either LatLng or
a String that will be geocoded. Param 'renderer'
is the `google.maps.DirectionsRenderer` to use.
*/
function calcDirections(from, to, renderer){
var request = {
origin: from,
destination: to,
travelMode: google.maps.TravelMode.DRIVING
};
DIRECTIONS_SERVICE.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
renderer.setDirections(response);
}
});
}
//for Snippet, actuall run google maps initialize function
initializeDirectionsFeature();
//For Snippet example
$("#query").submit(function(e){
e.preventDefault();
calcDirections(e.target.from.value, e.target.to.value, DMAP_RENDERER)
});
/* just for Snippet, gmap element just needs a height */
html, body {
position: relative;
width: 98%;
height: 98%;
min-height: 500px;
}
#map, #directions {
width: 100%;
height: 40%;
}
.inline-block {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js">
</script>
<form id="query">
<div class="inline-block">
<label for="from">From:</label>
<input id="from" name="from" value="New York, NY"/>
</div>
<div class="inline-block">
<label for="to">To:</label>
<input id="to" name="to" value="Philadelphia, PA"/>
</div>
<button type="submit">Go</button>
</form>
<div id="map"></div>
<div id="directions">Directions:</div>

Google Maps Failing to render

Note: I thought it would be better to make a new question on this.
So I recently asked a question about why Google maps is not rendering properly. Now the answer would seem straight forward and simple, accept my code looks like this:
var map;
function initialize() {
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
google.maps.event.trigger(map, "resize");
}
google.maps.event.addDomListener(window, 'load', initialize);
The issue is the map is still broken:
This map is stored in a <div id="Map"></div> which has a height of 350. This Div that holds the map is part of Jquery-UI Tabs, so it also has jquery skinning attached to it which may affect things like size and so on.
With that said the map should just work.
If I open the console and throw in: google.maps.event.trigger(map, "resize"); the maps then works as expected.
I also had a Google Map (v3) embedded within a jQuery UI Tabs, and had to work around the issue with this fix:
var initialized = false;
$('.tabs').find('.ui-tabs-nav li').each(function() {
if($(this).find('a').text() === 'Location') {
if($(this).hasClass('ui-state-active')) {
initialize();
initialized = true;
} else {
$(this).click(function() {
if(!initialized) {
initialize();
initialized = true;
}
});
}
}
});
Note that initialize() should run your starting map code. There are lots of ways to slice-and-dice the initialization, but the point is that we don't do it until the tab we're looking for ("Location", in this case) is active.

Retrieve position of a google maps v3 marker to Qt in a desktop app with QtWebKit

I'm building a Qt app with Python where you can point and click at a (google) map and get the coordinates of the location. The map is shown through a QWebView loading a simple HTML page and the user can create markers by clicking. Screenshot of the widget after clicking on the map.
However, I'm having trouble to retrieve the just-clicked location coordinates back to Qt (so that I can use them as variables -- and, for example, show them in the QLineEdits on the topleft corner above, as current location of the marker).
This is the relevant part of the HTML file:
<script type="text/javascript">
var map;
function initialize() {
var local = new google.maps.LatLng(-23.4,-40.3);
var myOptions = {
zoom: 5,
center: local,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'rightclick', function(event) {
placeMarker(event.latLng);
});
}
function placeMarker(location) {
var clickedLocation = new google.maps.LatLng(location);
var marker = new google.maps.Marker({
position: location,
map: map
});
map.setCenter(location);
}
function dummyTxt() {
return 'This works.';
}
</script>
I've been trying with evaluateJavaScript, but was not able to retrieve the coordinates. I tried to created a function to access the position with marker.getPosition(), but with no luck. The dummy below works though..
newplace = QWebView.page().mainFrame().evaluateJavaScript(QString('dummyTxt()'))
>>> print newplace.toString()
This works.
Any suggestions on how to get the coordinates back to Qt?
Edit:
Here is the code that worked for me:
def update_geo(self):
# Capture coordinates of the last marker on the map.
mark = self.map.page().mainFrame().evaluateJavaScript('document.getElementById("markerlocation").value').toString()
# Convert string to list of floats, stripping parentheses.
marker = str(mark).strip('()').split(', ')
decimals = [float(c) for c in marker]
Full source in https://github.com/nelas/veliger/blob/master/veliger.py#L2374
I found a work around to make it work but I'm not pretty sure that it will be the right approach. Anyway, this is what I did:
Create a hidden input in the body section of your html document to save the position data of the marker:
<body>
(...)
<input id="locationData" type="hidden">
(...)
</body>
In the javascript code, save the position of the marker in the hidden input every time it's created:
function placeMarker(location) {
(...)
document.getElementById("locationData").value = marker.position;
(...)
}
In your Qt code, read the value of the hidden input with the instruction:
webView->page()->mainFrame()->findFirstElement("#locationData").evaluateJavaScript("this.value").toString();
I hope it helps!
Source: http://opendocs.net/qt/4.6/webkit-formextractor.html

Categories

Resources