Directions map not centering/zooming properly - javascript

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>

Related

FullscreenControl and Maintaining Map Center

Currently, it appears that if I have say a modestly sized Google Maps display port (300px by 300px) with FullscreenControl enabled, and I center that small map view over a specific area, like... France, for instance... And then I hit the full screen button to expand the display to the edges of my screen (1920px by 1080px), France gets tucked wayyyyy up in the top-left corner of my screen.
Basically, the top-left of the original 300px x 300px display moves to the top-left of my screen, and rest of the world map extends from that corner at the original zoom level.
Is there any way to basically just set it up so that the full screen display opens up having the same center point as the original display, and vice versa when the full screen mode gets closed?
Does toggling the full screen button trigger an event or anything that I can hook a setCenter to?
I compose a code a bit strange but it works perfectly:
<script>
var map;
var center = -1;
var isFullScreen = false;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 8,
center: { lat: -34.397, lng: 150.644 }
});
center = { lat: map.getCenter().lat(), lng: map.getCenter().lng() };
google.maps.event.addDomListener(map, 'bounds_changed', onBoundsChanged);
}
function onBoundsChanged() {
var isFullHeight = $(map.getDiv()).children().eq(0).height() == window.innerHeight;
var isFullWidth = $(map.getDiv()).children().eq(0).width() == window.innerWidth;
if (isFullHeight && isFullWidth && !isFullScreen) {
isFullScreen = true;
map.setCenter(center);
console.log('FULL');
} else if (!isFullWidth||!isFullHeight){
if (isFullScreen) {
map.setCenter(center);
}
isFullScreen = false;
console.log('NOT-FULL');
}
center = { lat: map.getCenter().lat(), lng: map.getCenter().lng() };
}
</script>
I use the bounds_changed event.
If I detect that the map is in full screen I set the map in the center that I note in the precedent event and I set a boolean to true. If the map is not in full screen, I check if the boolean is true, it mean that in the precedent event the map was in full screen, so I recenter the map and next I check if the boolean is false. At the end of the event, I keep the center in a variable fro the next event.
All this are not very clear...
You may consult this post in Stack Overflow.
Notice: This code does not work if you display a single map in all the page of your web app. I do not find a way to remove this bug. Your suggestions are very appreciated, thanks.
Also notice: My code is inspired of the precedent answer. However you can find the same code here. Please notice that it is not a duplicate answer. I add my own part of code in it.
Tell me if you have some questions or comments.
Try this
/** To detect Map Full Screen event */
google.maps.event.addListener( map, 'bounds_changed', onBoundsChanged ); //Event listener map bound change.
var isMapFullScreen = false;
var defaultLocation = {
lat: 27.94,
lng: -82.45
};
function onBoundsChanged() {
if(!isMapFullScreen){
var isFullHeight = $(map.getDiv()).children().eq(0).height() == window.innerHeight;
var isFullWidth= $(map.getDiv()).children().eq(0).width() == window.innerWidth;
if (isFullHeight && isFullWidth) {
isMapFullScreen = true;
myMarker.setPosition(defaultLocation);
map.setCenter(defaultLocation);
console.log('FULL');
} else {
isMapFullScreen = false;
console.log('NOT-FULL');
}
}
}

Hide markers from google maps when click an external link and only show its corresponding marker

How do i change my center for google maps with a link and remove other markers? i have this code
https://jsfiddle.net/m9ugbc7h/
So, i need to create a link for example
Ventura
In this case the function must change google maps center to focus the "ventura" marker and hide the other markes and when the user clicks on
Dolphinaris
the zoom will change and will hide every other marker and show only the ones of Dolphinaris
Thanks in advance
Make map visible outside of jQuery(document).ready.
Create var markers = []; array.
When crating markers, add custom property name to it, and push marker into markers array:
var marker = new google.maps.Marker({
position: new google.maps.LatLng(21.0241839, -86.8148164),
map: map,
visible: true,
icon: ventura,
name: 'ventura',
});
markers.push(marker);
On click, invoke resetMap() function:
Ventura
Inside resetMap function, set center and zoom to map, iterate markers, matching them by custom property name - matched one set visible, others set to invisible.
function resetMap(lat, lon, zoom, name) {
var newPos = new google.maps.LatLng(lat, lon);
map.setCenter(newPos);
map.setZoom(zoom);
markers.forEach(function(marker) {
if(marker.get('name') == name)
{
console.log('match');
marker.setVisible(true);
}
else
{
marker.setVisible(false);
}
});
Working fiddle: https://jsfiddle.net/m9ugbc7h/1/
EDIT:
Question: "is there any way to change smoothly the zoom and coordinates?"
Yes, use method:
panTo(latLng:LatLng|LatLngLiteral)
Changes the center of the map to the given LatLng. If the change is
less than both the width and height of the map, the transition will be
smoothly animated.
https://developers.google.com/maps/documentation/javascript/reference?csw=1
EDIT 2:
Implementing panTo is easy:
map.panTo(newPos);
instead of:
map.centerTo(newPos);
but as I have faced a bit 'flickering' effect due to hide/show markers that are close on the map, I have added some delay in functions invocation + markers show/hide:
function resetMap(lat, lon, zoom, name) {
var newPos = new google.maps.LatLng(lat, lon);
$.when( map.setZoom(zoom) ).done(function(){
$.when( map.panTo(newPos)).done(function(){
setMarkerVisibility(name);
});
});
}
And showing matched marker is now executed with 300 ms delay:
function setMarkerVisibility(name){
markers.forEach(function(marker) {
console.log(marker.get('name'));
if(marker.get('name') == name)
{
setTimeout(function(){ marker.setVisible(true); }, 300);
}
else
{
marker.setVisible(false);
}
});
}
It looks a bit smoother like this.
Working fiddle: https://jsfiddle.net/m9ugbc7h/3/

Google Map images are really tiny inside infowindow

I've got a script working to add markers to a map with an infowindow. The problem is that the images are tiny, yet when you inspect and hover over the img entity the size is correct, and the blue box that shows where the canvas sits in the main window is correctly proportioned, it's just the actual image takes up a fraction of the canvas.
I've no idea on what is causing this. Using the Developer Tools I've removed all CSS that appears to be affecting it and nothing changes, except if I remove the 100% width, then the canvas goes full size, but the image is still only a fraction of the canvas.
This is the Javascript
var startLat = 20;
var startLng = 0;
var startZoom = 2;
var isAddress = false;
var distributors = [{"logo":"http:\/\/www.elecro.demomycms.co.uk\/eshop\/files\/images\/distributor-logos\/5.jpg","name":"AG Budget Swimming Pool & Spas","contactNumber":"020 89416618","address":"Unit 10 Wilden Industrial Estate\nWilden Lane\nStourport on Severn\nWorcestershire","postcode":"DY13 9JY","latitude":"52.3504","longitude":"-2.26002"}];
var map;
var geocoder;
$(function () {
var mapOptions = {
zoom: startZoom,
center: new google.maps.LatLng(startLat, startLng)
}
var marker, i;
$('#map-canvas').height($('#map-canvas').width() / 2);
var mapOptions = {
zoom: startZoom,
center: new google.maps.LatLng(startLat, startLng)
}
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
if ( ! isAddress && $('#country').val() > 0) {
GeocodeCountry();
}
for (i = 0; i < distributors.length; i++) {
var $distributor = distributors[i];
var marker = new google.maps.Marker({
position: new google.maps.LatLng($distributor.latitude, $distributor.longitude),
map: map
});
var infowindow = new google.maps.InfoWindow();
marker.html = '<div class="container-fluid" style="width: 300px">\
<h1 class="row-fluid">\
'+($distributor.logo ? '<div class="span3"><img src="'+$distributor.logo+'" style="width: 100%"></div>' : '')+'\
<span class="span9">'+$distributor.name+'</span>\
</h1>\
<div class="row-fluid">\
<div class="span6">'+$distributor.address+'<br>'+$distributor.postcode+'</div>\
<div class="span6">'+($distributor.url ? ''+$distributor.url+'' : '')+'<br>'+$distributor.contactNumber+'</div>\
</div>\
</div>';
google.maps.event.addListener(marker, 'click', (function() {
return function() {
infowindow.setContent(this.html);
infowindow.open(map, this);
}
})(marker, i));
}
});
function GeocodeCountry() {
geocoder = new google.maps.Geocoder();
geocoder.geocode({'address': $('#country').find('option:selected').text()}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
map.fitBounds(results[0].geometry.viewport);
}
});
}
You have probably noticed the Bootstrap 2 code in the HTML, we're using Bootstrap 2 on the site, but I've not included any of the CSS / JS files in the fiddle below and it is still doing the same thing, so it's not Bootstrap affecting it.
You can see a JS fiddle of this here: http://jsfiddle.net/styphon/raLcmbvc/
I've only included one example marker in the JS Fiddle, but on the site there are over 200 and it does the same with all of them. This is the site if you want to see: http://elecro.demomycms.co.uk/distributors.php
Your testing image is huge, and also contains a lot of whitespace on right and bottom: http://www.elecro.demomycms.co.uk/eshop/files/images/distributor-logos/5.jpg
Then you also apply width:100% CSS to your image, so it will be resized to fit the window.
Depending on what you want to achieve, you could either:
User a better image without whitespace
Remove the width:100%
The problem here is that the image which your displaying is itself having large portion of itself as white!
See the link: http://www.elecro.demomycms.co.uk/eshop/files/images/distributor-logos/5.jpg and try saving the image and looking its dimensions. Its a huge 1433x755 size image of which almost 90% area is white background. So remove the extra white background by cropping the image and you be should be good to go. Rest everything seems fine. You can adjust image size in your code line <div class="container-fluid" style="width: 300px"> by giving appropriate width but first change the image.

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