I have ran into a very strange issue with Google Maps in Chrome 5.0.375.99:
if you dynamically create more than one Maps instance, the second and on have a strange bug where it does not display properly, is only shows in a fraction of the map space.
Some Example Pages:
one default - When you click addOne, the new object has the problem.
none default - When you click addOne the second time, the new object has the problem.
two default - Both of the initial maps display properly, but when you click addOne, the new object has the problem.
The really wierd part, is that re-sizing the window will force any improperly displaying maps to display properly to fix themselves. This leads me to believe that what is fixing it is the redraw event
Crescent Fresh is correct, in that the dimension of the div needs to be set before initialising a new map on a div.
To set the width height before creating the map div you could try the following:
return this.each(function(){
var jT = $(this),
center = new mAPI.LatLng(options.lat, options.long),
geocoder = new mAPI.Geocoder();
jT.css({
'width': hw[0],
'height': hw[1],
'margin-left': 'auto',
'margin-right': 'auto'
});
jT.data('map', new mAPI.Map(this, $.extend(options, { center: center })));
geocoder.geocode({ address: address }, function(results, status) {
if (status === mAPI.GeocoderStatus.OK && results.length) {
if (status !== mAPI.GeocoderStatus.ZERO_RESULTS) {
jT.data('map').setCenter(results[0].geometry.location);
var dump = new mAPI.Marker({
position: results[0].geometry.location,
map: jT.data('map')
});
return dump;
}
}
});
});
the above 'should' work, havent tested it tho
Related
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/
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>
I use the following block of JavaScript to try to show a WMS layer. I'm using OpenLayers 2.8.
The map's base layer (Openstreetmap) shows correctly, it zooms to the correct area, the "pyramid" layer is shown in the layer switcher, but no request to its WMS service is ever made (so the fact that the URL, styles and params are dummies shouldn't matter -- it never even attempts to get them).
OpenLayers does try to get a WMS layer once I pan or zoom far enough so that the Gulf of Guinea is in view (but all my data is in the Netherlands). This suggests a projection problem (WGS84's (0, 0) point is there), but I don't understand why OpenLayers doesn't even try to fetch a map layer elsewhere. My data is in EPSG:3857 (Web Mercator) projection.
/*global $, OpenLayers */
(function () {
"use strict";
$(function () {
$(".map").each(function () {
var div = $(this);
var data_bounds = div.attr("data-bounds");
console.log("data_bounds: " + data_bounds);
if (data_bounds !== "") {
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857"});
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
map.addLayer(
new OpenLayers.Layer.OSM(
"OpenStreetMap NL",
"http://tile.openstreetmap.nl/tiles/${z}/${x}/${y}.png",
{buffer: 0}));
map.addLayer(
new OpenLayers.Layer.WMS(
"pyramid", "http://rasterserver.local:5000/wms", {
layers: "test",
styles: "test"
}, {
singleTile: true,
isBaseLayer: false,
displayInLayerSwitcher: true,
units: 'm'
}));
map.addControl(new OpenLayers.Control.LayerSwitcher());
map.zoomToExtent(bounds);
}
});
});
})();
Edit: the 'data_bounds' console print prints (with some added formatting):
data_bounds: {
"minx": 582918.5701295201,
"miny": 6923595.841021758,
"maxx": 821926.9006116659,
"maxy": 7079960.166533174
}
It zooms to the correct region in the north of the Netherlands, so I don't think the problem is there.
Since posting, I found out that if I don't use the OSM layer, and instead use the WMS layer as baselayer, it works. So perhaps there's some incompatibility with a OSM baselayer and a WMS layer added to it? But then I don't get that it does seem to do something near WGS84 (0, 0).
I eventually managed to fix this by giving the map an explicit maxExtent:
var extent = JSON.parse(data_bounds);
var bounds = new OpenLayers.Bounds(
extent.minx, extent.miny,
extent.maxx, extent.maxy);
var map = new OpenLayers.Map(div.attr("id"), {
projection: "EPSG:3857",
maxExtent: bounds
});
Oddly enough this doesn't limit the user's ability to pan and zoom around the world, but it does make the overlay work...
Short version of my question:
How do I integrate a pair of Google Maps fusion tables (polygons and markers) with GroundOverlays from a KML file? Everything clickable.
Background:
I am working on an interactive history mapping project that uses 2 layers of fusion tables (one layer is polygons, the other is location markers).
I also want to overlay old maps via GroundOverlay -- which is not presently possible with fusion tables -- and so I have been experimenting with GroundOverlay in a KML file.
I've complicated it by adding listeners on both the pages to control click boxes.
I have two webpages:
1. the fusion tables and
2. the KML groundoverlays,
both working fine.
What I want to do is integrate them into a single page. I am not a programmer and don't understand JS well enough to make this happen.
The scripting used was all adapted from examples found online.
Here is my first working page:
http://wendysmithtoronto.com/mapping/townofyork-fusiontables2.html
You'll find a link to the second page there.
Your help would be greatly appreciated.
Thank you.
Wendy
Update:
Here's my effort to merge my two sets of data:
http://wendysmithtoronto.com/mapping/townofyork-merged.html
I tried to do this by adding bits of script from the kmlmaps page into the fusiontables page, but clearly I didn't put things in the right place. Or am missing bits of punctuation (or mixing up different types of scripting, or?)
The map appears, with the polygons and the markers both properly appearing. But now (1) the fusion table icons aren't clickable, and (2) the history maps don't appear. However, the fusion table checkboxes (in blue table) DO work.
I don't understand JS well enough to figure it out.
The two sets of controls from the two pages are both here (in the blue and grey boxes, just above the map). Each set of controls (listeners & click boxes) worked fine in its own wepage but now only the fusion tables controls work.
Eric, thanks for having a look at this! (I just now found your reply. I've been watching for a reply notification but wasn't checking the right place.)
Cheers,
Wendy
Your html file had significant errors in the javascript portions. You really should study up on same basic javascript and in particular using JS with the GMap API.
You created 2 global map objects. You did not encapsulate all your map and layer creations within you initialize function(). All map and layer creation must be done within the initialize (on body load) function. You must set globals outside your initialize function, e.g. the map, all the layers, etc. Finally you were failing to call layer.setMap(map) on 2 of your KML layers.
Despite all this I fixed your file, really just re-arranging things. This is just the section I had to fix. Moved everything into the initialize()
function showbuildings(buildingcheck) {
if (buildingcheck.checked == true)
{
campusmap.setMap(map);
} else {
campusmap.setMap(null);
}
}
function showphilpotts(philpottscheck) {
if (philpottscheck.checked == true)
{
philpotts.setMap(map);
} else {
philpotts.setMap(null);
}
}
function showbeartrail(beartrailcheck) {
if (beartrailcheck.checked == true)
{
beartrail.setMap(map);
} else {
beartrail.setMap(null);
}
}
var infoWindow = new google.maps.InfoWindow();
function openIW(FTevent) {
// infoWindow.setContent(FTevent.infoWindowHtml);
// infoWindow.setPosition(FTevent.latLng);
infoWindow.setOptions(
{
content: FTevent.infoWindowHtml,
position: FTevent.latLng,
pixelOffset: FTevent.pixelOffset
});
infoWindow.open(map);
}
// Globals
//Begin map parameters
var map;
var layer_2;
var layer_1;
var tableid_1 = 2920040; // polygons
var tableid_2 = 3189980; // houses
var zoom = 12;
var center = new google.maps.LatLng(43.652417455515476, -79.37926607055226);
var campusmap;
var philpotts;
var beartrail;
function initialize() {
map = new google.maps.Map(document.getElementById('map_canvas'), {
center: center,
zoom: zoom,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
//End map parameters
campusmap = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1851mapshoreline.kml', {preserveViewport:true, suppressInfoWindows:true});
campusmap.setMap(map);
google.maps.event.addListener(campusmap, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
philpotts = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1818maplieutphilpottsd.kml', {preserveViewport:true, suppressInfoWindows:true});
google.maps.event.addListener(philpotts, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
philpotts.setMap(map);
beartrail = new google.maps.KmlLayer('http://wendysmithtoronto.com/mapping/1842map-jamescaneb.kml', {preserveViewport:true, suppressInfoWindows:true});
google.maps.event.addListener(beartrail, 'click', function(kmlEvent) {
document.getElementById('sidebarinfo').innerHTML = kmlEvent.featureData.description;
});
beartrail.setMap(map);
layer_2 = new google.maps.FusionTablesLayer({
suppressInfoWindows:true,
query: {
select: 'Location',
from: '3189980'
},
styles: [
{where: "'style' = 14", markerOptions:{ iconName:"star"}},
{where: "'style' = 13", markerOptions:{ iconName:"wht_pushpin"}},
{where: "'style' = 11", markerOptions:{iconName:"red_blank"}}, //town houses
{where: "'style' = 12", markerOptions:{ iconName:"orange_blank"}}, //country homes
{where: "'style' = 15", markerOptions:{ iconName:"target"}},
]});
layer_1 = new google.maps.FusionTablesLayer({
suppressInfoWindows:true,
query: {
select: 'Location',
from: '2920040'
}}),
google.maps.event.addListener(layer_1, "click", openIW);
google.maps.event.addListener(layer_2, "click", openIW);
google.maps.event.addListener(map, "click", function() { infoWindow.close();});
layer_1.setMap(map);
layer_2.setMap(map);
} // end initialize
I'm working on optimizing a site for mobile. We have a Location page that includes info about a location and a map of the location via the Google Maps API. (v2 - I know it's deprecated but I haven't justified the time to upgrade, "if it ain't broke..") I want to use a single column layout with basic information followed by the map followed by more information.
Now when I use my finger to scroll down the mobile page on an iPhone, once I get to the map, the page scrolling is overridden and the map starts panning. The only way for me to scroll farther down the page is to put my finger above or below the map, assuming such space is available. If I disable map dragging, then when I start scrolling down and get to the map it doesn't pan but the page doesn't scroll either. I would like to treat the map as a static image that I can scroll past, but still allow the zoom buttons and allow the map to be redrawn with directions through a select field I have coded, so a literal static image is not a solution.
I found this post that required similar functionality, but it's using v3. I think all I need to do is "add touch events to the map container," but I'm not familiar with that part of javascript, and what I have below does not allow normal scrolling. Do I need to bite the bullet on v3, or do I have a bug on adding touch events that has a simple javascript correction to do what I want?
function initialize() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map_canvas"));
geocoder = new GClientGeocoder();
}
}
function showAddress(address, zoom) {
//clipped... this part works fine
}
//These three lines create a map that my finger pans
initialize();
showAddress("[clipped.. street, zip code]");
map.addControl(new GSmallZoomControl3D());
//This stops the map pan but still prevents normal page finger scrolling
map.disableDragging();
//If done right could this allow normal page finger scrolling??
var dragFlag = false;
map.addEventListener("touchstart", function(e){
dragFlag = true;
start = (events == "touch") ? e.touches[0].pageY : e.clientY;
},true);
map.addEventListener("touchend", function(){
dragFlag = false;
}, true);
map.addEventListener("touchmove",function(
if ( !dragFlag ) return;
end = (events == "touch") ? e.touches[0].pageY : e.clientY;
window.scrollBy( 0,( start - end ) );
}, true);
I have also tried replacing map.addEventListener with document.getElementById("map_canvas").addEventListener or document.addEventListener to no avail.
I solved it by upgrading to v3 and then detecting a basic javascript error in my use of the code from the solution linked above. The key was
start = (events == "touch") ? e.touches[0].pageY : e.clientY;
The user must have been setting the events variable somewhere outside the presented code, since it looks like the matching assignment is for touch events and the else assignment is for key events. But since I didn't have an events variable it was defaulting to the wrong assignment. I simply changed mine to start = e.touches[0].pageY (and did the same for the touchend event) and now everything works.
However, I switched back to v2 to see if it would work with that javascript error corrected, and it did not. So it looks like I did not waste any time upgrading to v3, neither in figuring out this specific solution nor in setting myself up for future compatibility.
In conclusion, if you want to embed Google Maps on a mobile page and be able to scroll past it, you need to use API v3, disable dragging, and add touch events. I made a few minor tweaks to my code as well, presented here for any who may benefit in the future:
function initialize()
{
geocoder = new google.maps.Geocoder();
var myOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
function showAddress(address, zoom)
{
if (geocoder)
{
geocoder.geocode( { 'address': address }, function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
map.setOptions( { zoom: zoom });
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
}
});
}
}
initialize();
showAddress("'.$geocode_address.'");
map.setOptions( { draggable: false });
var dragFlag = false;
var start = 0, end = 0;
function thisTouchStart(e)
{
dragFlag = true;
start = e.touches[0].pageY;
}
function thisTouchEnd()
{
dragFlag = false;
}
function thisTouchMove(e)
{
if ( !dragFlag ) return;
end = e.touches[0].pageY;
window.scrollBy( 0,( start - end ) );
}
document.getElementById("map_canvas").addEventListener("touchstart", thisTouchStart, true);
document.getElementById("map_canvas").addEventListener("touchend", thisTouchEnd, true);
document.getElementById("map_canvas").addEventListener("touchmove", thisTouchMove, true);