Show loading status during loading of a GeoJSON using Gmaps - google-maps

How can I intercept the loading of a GeoJSON using loadGeojson function Gmaps ? I'm carrying a gejson of MultiLineString but takes a few seconds to appear on the screen and I need to add a loading for the user to wait for charging
function load(){
google.maps.event.addListener(myLayer, 'addfeature', function (e) {
map.setCenter(e.feature.getGeometry().getAt(0).getAt(0));
});
myLayer.loadGeoJson("/data/myLayer.json");
myLayer.setMap(map);
myLayer.setStyle(function(feature) {
return {
strokeColor: "#B00000",
strokeOpacity:0.8,
strokeWeight: 4
};
});
}
Ivan your answer was the solution to my problem. Thank you! But still have a doubt only works when I create a new map object:
......
var map = new google.maps.Map(document.getElementById('map'), mapOptions);
cicloviasLayer.setMap(map);
I do not want to create a new map but plot in an existing map, how do I get the loading run in this case?

If you take a look at the API reference, you'll see that loadGeoJson has a callback function as the third parameter. So you can show a spinner before the call to loadGeoJson and hide it right after the callback is invoked.

As described in this SO answer:
Use CSS to add loading giff image:
#map_canvas {background: transparent url(images/ajax-loading.gif) no-repeat center center;}
It will dissappear once map is loaded, as shown in jsfiddle.

Related

Polygon how to know if vertex moving on google map

I'm using drawing manager to draw polygon.
I want to display live moving data on polygon vertex.
I have tried used two methods below.
google.maps.event.addListener(polygon.getPath(), 'set_at', processVertex);
google.maps.event.addListener(polygon.getPath(), 'insert_at',processVertex);
But its call after vertex end moving/ drag end.
i want something while moving ...
I have this fiddle and data i'm displaying.
http://jsfiddle.net/subhashchavda/6a8db64z/65/
I want something like this
listener(polygon.getPath(), 'vertex_drag',function(){
update_data(); /* dragging/moving */
});
Is there any way /trick for listen vertex dragging ?
There is no in build function available in google map doc. so right now if want to it to workout you can use custom code like listening vertax click and drag on map.
Here is some code you can try with that.
google.maps.event.addListener(polygon, 'mousedown', function(e){
if(e.vertex){
// flag for vertax drag start
}
});
google.maps.event.addListener(map, 'mousemove', function(e){
if(e.vertex){
// flag for vertax dragging
}
});
google.maps.event.addListener(polygon, 'mouseup', function(e){
if(e.vertex){
// flag for vertax drag stop
}
});
But i'm not sure it will work with every conditions.
you need to more workout with this code.

API V3 - set the zoom -1 from the zoom required to fit the markers

I would like my map to initially zoom out -1 from zoom determined by bounds.
If I do the following, it just zooms in/out, but I want to set the zoom level "a little bigger".
map.fitBounds(bounds);
For the reasons quite well known I can't use map.setZoom afterwards.
Is there some simple way to do this?
The best thing to do is to create an event listener for the map idle event. Once fitbounds has done its thing, the idle event will be triggered.
If you need to do it every time you fit the bounds then create a custom fitbounds method
var fitBounds = function(map, bounds) {
google.maps.event.addListenerOnce(map, 'idle', function() {
this.setZoom(this.getZoom() - 1);
});
map.fitBounds(bounds);
}
Notice we use the addListenerOnce method instead of the normal addListener.
The problem with this method though is you will still see the initial bounds set for a split second before the map zooms out.
You could use an event listener on zoom_changed:
google.maps.event.addListenerOnce(map, 'zoom_changed', function() {
var zoomLevel = map.getZoom();
map.setZoom(zoomLevel-1);
});

Google Maps API v3 cannot make a marker...

I’ve just built up a customized tiles map site : http://shuttle.wanglingjie.net/memoire/memoire.html.
But I have a trouble with making a marker on it. Once I added the new marker code:
var marker = new google.maps.Marker(
{
position: new google.maps.LatLng(0, 0),
map: map
}
);
The maker doesn’t show up and the js reports an error with the following message:
Uncaught Error: Invalid value for property : [object HTMLDivElement]
Any ideas? Thank you for your attention. :)
map is null. In firebug, your site gives this error:
map is not defined
http://shuttle.wanglingjie.net/memoire/memoire.html
Line 129
Your javascript code is badly laid out, so it is hard to see what you have done wrong. I think the problem is that your window.onload function does not have a closing bracket: }.
You should lay your javascript out so that all code contained within brackets has the same amount of indent. For instance, the code you have posted should look like this:
var marker = new google.maps.Marker(
{
position: new google.maps.LatLng(0, 0),
map: map
}
);
It's also acceptable to write it like this:
var marker = new google.maps.Marker({
position: new google.maps.LatLng(0, 0),
map: map
});
This makes your code easier to read, and will help you find bugs.
If you need more help, please edit your question to include the full body of your function, correctly formatted.
From the source code given in the link I noticed that the block that creates the marker is outside the function that creates the map. That's why the marker doesn't see the variable map.

Disable drag inertia / momentum on Google Maps V3

Is there a way to disable drag inertia on Google Maps V3? Seems like it should be a MapOption, but I can't find any way to do this.
I ran into this same problem today, with some custom Div's floating above the map needing to be re-positioned on Map Movement. My repositioning worked fine as long as the user came to a complete stop after dragging before letting the mouse go (so there would be no momentum), but if one just dragged quickly and released the div's would end up a bit off.
To fix this, I hooked into the drag event and the idle event:
var map = /* All the map config */
var stickyCenter = map.getCenter();
/* ... Code ... */
google.maps.event.addListener(map, 'drag', function(){ stickyCenter = map.getCenter(); });
google.maps.event.addListener(map, 'idle', function() { map.setCenter(stickyCenter); });
What happens is that after you've dragged and the map has come to a stop (after the momentum is done) the map 'snaps' back into place.
If the snapping is too sudden, one could probably panTo or animate the movement in some way. Hope that helps, it's not perfect, but it's a way to reverse the momentum from a drag event.
Use the undocumented option disablePanMomentum e.g.:
new google.maps.Map(document.getElementById(id), {
disablePanMomentum: true,
backgroundColor: 'none',
disableDefaultUI: true,
center: {
lat: 40.674,
lng: -73.945
},
zoom: 2,
...
This cannot be done with Maps API V3 at this time. Consider filing a feature request here:
http://code.google.com/p/gmaps-api-issues/
I'm pretty sure it's possible to at least counter-act the momentum. Somebody please correct me if I'm wrong! For the sake of simplicity, for instance, let's say your map container has a width of 100vw and a height of 100vh. You simply call getCenter() in a function that is called by a mouseup event, and then use those coordinates to immediately setCenter()?
function initMap(){
...
var win = window;
google.maps.event.addDomListener(win, 'mouseup', setCoords);
function setCoords(){
var x = myMap.getCenter();
var lat = x.lat();
var lng = x.lng();
myMap.addListener('center_changed', function(lat, lng){
myMap.setCenter(new google.maps.LatLng(lat, lng));
};
};
The code above actually works, but the kicker is that it only works once until the browser becomes seemingly overloaded and produces the error Uncaught RangeError: Maximum call stack size exceeded.
Not sure what to do now.
More info about this here.
This one works just fine for me:
map.addListener("dragend", () => map.setCenter(map.getCenter()));

How to access Google Maps API v3 marker's DIV and its pixel position?

Instead of Google Maps API's default info window, I'm going to use other jQuery tooltip plugin over marker. So I need to get marker's DIV and its pixel position.
But couldn't get it because there are no id or class for certain marker. Only I can access map canvas div from marker object and undocumented pixelBounds object.
How can I access marker's DIV?
Where can I get DIV's pixel position? Can I convert lat-lng position to pixel values?
==
appended:
I also tried with below code, but it doesn't change when I scroll the map.
var marker = new google.maps.Marker({...});
google.maps.event.addListener(marker, 'click', function() {
var px = this.getMap().getProjection().fromLatLngToPoint(this.getPosition());
console.log("(" + px.x + "," + px.y + ")");
});
I don't really get why would you want to get specific div for marker? If you want to display tooltip then all you need is pixel position of markers anchor (and knowledge about size of marker and placement of anchor), not div element. You can always trigger opening and closing tooltip by hand when event occurs on google.maps side.
For getting pixel position of anchor of given marker you can use this code:
var scale = Math.pow(2, map.getZoom());
var nw = new google.maps.LatLng(
map.getBounds().getNorthEast().lat(),
map.getBounds().getSouthWest().lng()
);
var worldCoordinateNW = map.getProjection().fromLatLngToPoint(nw);
var worldCoordinate = map.getProjection().fromLatLngToPoint(marker.getPosition());
var pixelOffset = new google.maps.Point(
Math.floor((worldCoordinate.x - worldCoordinateNW.x) * scale),
Math.floor((worldCoordinate.y - worldCoordinateNW.y) * scale)
);
In pixelDistance you get offset of specific marker anchor counted from left upper corner of the map (and you can get it's position from map.getDiv() div). Why it works like this (or is there a better way?) you can read in documentation of google maps overlays.
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
var proj = overlay.getProjection();
var pos = marker.getPosition();
var p = proj.fromLatLngToContainerPixel(pos);
You can now access your pixel coordinates through p.x and p.y.
FOLLOWING ADDED POST COMMENT:
The downfall of the overlay projection is that until it your map canvas finishes loading it isn't initialized. I have the following listener that will force whatever method I need to trigger when the map does finish loading.
google.maps.event.addListener(map, 'idle', functionName());
In the mean time I use the following check to avoid any errors before it does draw.
if(overlay.getProjection()) {
// code here
}
One thing to remember when using MBO's code:
When the map tiles are repeated, map.getBounds().getSouthWest() returns "-180" independent of the map's position. A fallback I'm using in this case is calculating the pixel distance to the center instead of the upper left corner, since map.getCenter() seems to return the currently centered point in any case. E.g. (using jQuery):
// Calculate marker position in pixels form upper left corner
var pixelCoordsCenter = map.getProjection().fromLatLngToPoint(map.getCenter());
pixelOffset = new google.maps.Point(
Math.floor((pixelCoordsMarker.x - pixelCoordsCenter.x) * scale + $(container).width()/2),
Math.floor((pixelCoordsMarker.y - pixelCoordsCenter.y) * scale + $(container).height()/2)
);
anyone still looking for an answer to this, have a look here: http://code.google.com/p/google-maps-utility-library-v3/wiki/Libraries
among some other useful google maps stuff there's RichMarker which allows you to add DOM elements of your choice as draggable markers. just add class/id to handle with jQuery.
Rene's answer only gives you the "world coordinates" (that is, coords independent of zoom level and viewport). MBO's answer seems right, though, so that's the one you should accept and vote up (I can't as I just registered) as the solution might easily be overlooked otherwise.
As for an "easier" version, you can use the methods in MapCanvasProjection instead, but that means you'll have to make your own overlay. See here for an example. :P
MapCanvasProjection's fromLatLngToContainerPixel() is probably what the author's after. It will give you the pixel offset relative to the map's container. I did some experiments and found the "simplest" working solution. (I wish Google makes this feature more accessible!)
First you declare a subclass of OverlayView somewhere like so:
function CanvasProjectionOverlay() {}
CanvasProjectionOverlay.prototype = new google.maps.OverlayView();
CanvasProjectionOverlay.prototype.constructor = CanvasProjectionOverlay;
CanvasProjectionOverlay.prototype.onAdd = function(){};
CanvasProjectionOverlay.prototype.draw = function(){};
CanvasProjectionOverlay.prototype.onRemove = function(){};
Then somewhere else in your code where you instantiate the map, you also instantiate this OverlayView and set its map, like so:
var map = new google.maps.Map(document.getElementById('google-map'), mapOptions);
// Add canvas projection overlay so we can use the LatLng to pixel converter
var canvasProjectionOverlay = new CanvasProjectionOverlay();
canvasProjectionOverlay.setMap(map);
Then, whenever you need to use fromLatLngToContainerPixel, you just do this:
canvasProjectionOverlay.getProjection().fromLatLngToContainerPixel(myLatLng);
Note that because the MapCanvasProjection object will only be available once draw() is called, which is sometime before the map's idle, I suggest creating a boolean "mapInitialized" flag, set it to true on the first map idle callback. And then do what you need to do only after that.
Well, if you MUST access the DIV, here's some code. Beware that this will only work with the standard marker (20x34px), and it'll find all markers. You might want to improve this hack to suit your needs...
BEWARE! THIS IS A HACK
var a=document.getElementById('map_canvas');
var b=a.getElementsByTagName('img');
var i, j=b.length;
for (i=0; i<j; i++) {
if(b[i].src.match('marker_sprite.png')){
if(b[i].style.width=='20px' && b[i].style.height=='34px') {
c=b[i].parentElement;
console.log(c.style.top+":"+c.style.left);
// this is a marker's enclosing div
}
}
}
A working snippet jQuery style ready to copy/paste:
step 1 - initialize your map and options
<html>
<head>
<script src="get-your-jQuery" type="text/javascript"></script>
<script src="get-your-maps.API" type="text/javascript"></script>
<script type="text/javascript">
<!--
$(document).ready(function(){
var bucharest = new google.maps.LatLng(44.43552, 26.10250);
var options = {
zoom: 14,
center: bucharest,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
As you can see, lower, the variable map is not preceded by VAR, because it should be Global as we use another function to get the fromLatLngToContainerPixel. For more details check closures.
map = new google.maps.map($("#map_canvas")[0], options);
var marker = new google.maps.Marker({
position: google.maps.LatLng(44.4407,26.0864),
map: map
});
new google.maps.event.addListener(marker, 'mouseover', function(){
placeMarker( marker.getPosition(),'#tooltip');//param1: latlng, param2: container to place result
});
new google.maps.event.addListener(map, 'bounds_changed', function(){
$("#tooltip").css({display:'none'}); //this is just so you can see that all goes well ;)
});
overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map);
}); //here ends jQuery.ready
function placeMarker(location, ID){
var containerPixel = overlay.getProjection().fromLatLngToContainerPixel(location);
var divPixel = overlay.getProjection().fromLatLngToDivPixel(location);
$(ID).css({top:containerPixel.y, left:containerPixel.x, 'dislay':'block'});
}
//-->
</script>
</head>
<body>
<div id="tooltip" style="width:100px; height:100px; position:absolute; z-index:1; background:#fff">Here I am!</div>
<div id="map_canvas" style="width:300px; height:300px"></div>
</body>
</html>
I found it's easiest to assign a custom icon and use the img src attribute to get to the element. You can still use the default google maps icon, just save it locally.
$("#map img[src='my_marker.png']").getBoundingClientRect();
For many circumstances the complex math used the calculate and change the pin position in the accepted answer may be appropriate.
For my particular use I just created a transparent PNG with a canvas significantly larger than I needed for the icon. Then I just experimented moving the pin around within the transparent background and applying the new image to the map.
Here is the spec for adding the custom pin image, with examples:
https://developers.google.com/maps/documentation/javascript/examples/icon-simple
This method will definitely scale as an offset in pixels instead of an actual different long/lat even when you zoom in.
Try this way, got div by event.
marker.addListener("click", markerClicked);
function markerClicked(event) {
// here you can get the marker div by event.currentTarget
}