Let's say I've got a full-screen google map, with a div which is on the left (but isn't, strictly speaking, an overlay or UI element of the map) and absolutely positioned.
Now let's say I have a bounding box (as in: [ [lat, lng], [lat, lng] ]which I want to have the map fit. What if I want it to take into consideration that div. I have the absolute position and the size of it in pixels. Is there something I can specify on the map to say "This area is off bounds, don't let the bounding box clash with it"?
Are you trying to place a bounding box around the map or are you trying to ensure that all markers are displayed within the map?
The api allows you to set up a bounding area so that when the map loads all points are visible within the map. The map will zoom or scale accordingly.
to setup bounds within your function add the following
(function(){
..existing code
var bounds = new google.maps.LatLngBounds();
var infowindow;
//Here I have an event listener that I have setup for the clicking of the markers
(function (i, marker) {
google.maps.event.addListener(marker, 'click', function () {
if (!infowindow) {
infowindow = new google.maps.InfoWindow();
}
infowindow.setContent('Location: ' + i);
infowindow.open(map, marker);
});
})(i, marker);
bounds.extend(places[i]);
}
map.fitBounds(bounds)
})();
There are a few things happening here. Map is the name of my DIV layer the anonymous function would just be used to wrap everything. The reason I added the click event code was to also show how I can get the map to auto position whenever I click on a marker to view the info window (using the bounds.extend(places[i]). Places is the array of coordinates that I have collected. I didn't add all the code such as for the marker generation but I would normally place this block of code following that. The bounds function as part of the api forces the map to auto position and zoom according to where the markers are located on the page. This ensures that when the map is rendered all markers are visible to the user.
Not sure if this is what you wanted but if you can clarify I may be able to elaborate more.
Best of luck
Related
I'm not using the Markers in Google Maps because I wish to render custom text and images on my marker, so what I did is a custom marker using Overlays.
The Overlay position is not exactly like the marker so I played a bit with it and now it is rendering exactly like a marker.
The problem now is the infowindow because it doesn't open on top of the overlay but exactly on the position of the overlay, I wish it to be on top of it, around 32px less on the top position.
Looking at the documentation it looks like the infowindow position is related to the object and on the LatLng, so how can I move it?
Here is the code I'm using:
var marker;
marker = new CustomMarker(markerPosition, map, {}); // custom marker is a class I wrote to prototype the overlay.
google.maps.event.addListener(marker, 'click', function() {
myInfowindow.open(map, marker);
});
Quite simple but unfortunately the infowindow is over the marker and not on top of it like if I use a marker.
Set the pixelOffset of the InfoWindow appropriately:
From the documentation on InfoWindows
pixelOffset | Type:Size | The offset, in pixels, of the tip of the info window from the point on the map at whose geographical coordinates the info window is anchored. If an InfoWindow is opened with an anchor, the pixelOffset will be calculated from the anchor's anchorPoint property.
I have many markers.
On the left I have list of marker-abstractions of actual markers on the google map.
I decided to use polylines
var flightPlanCoordinates = [
new google.maps.LatLng(near_cursor_lat, near_cursor_lon),
new google.maps.LatLng(marker_lat, marker_lon)
];
var flightPath = new google.maps.Polyline({
path: flightPlanCoordinates,
strokeColor: "#FF0000",
strokeOpacity: 1.0,
strokeWeight: 2
});
flightPath.setMap(map);
the idea is that user points his mouse on the marker-abstraction box on the left, and then he shown the line which goes from marker-abstraction to actual marker on the map. I already have everything except of the STARTING POINT(red dots on the image)
How do I find starting lat/long which is located next to the mouse pointer, when the mouse is pointed at the box on the left
Some details:
When the mouse is pointed to the box that sais PERSON1, I want the coordinates of the first red dot. When the mouse is pointed to the box that sais PERSON2, I want the coordinates of the second red dot. And so on. There is a trick part- left boxes are located outside the google maps div; in addition, if there are many boxes with PERSONS, the left div will allow to scroll those persons up and down, so the vertical correlation between the persons box, and the red dot is dynamic.
In theory, I think, I need an event that is triggered when I point to one of the boxes. When even is fired, I need to measure the vertical distance in pixels from the top to the mouse pointer. Then, when I have the vertical distance, I need to perform some action that would measure same vertical distance on the google map, and would get me that point on the map in lat/lon coordinates.
This should be the answer to your question :
You should be using markers to represent (persons) and then add a listener onMouseOver like in the below post :
var overlay = new google.maps.OverlayView();
overlay.draw = function() {};
overlay.setMap(map); // 'map' is new google.maps.Map(...)
Use overlay in the listener to get the projection and the pixel coordinates:
google.maps.event.addListener(marker, 'mouseover', function() {
var projection = overlay.getProjection();
var pixel = projection.fromLatLngToContainerPixel(marker.getPosition());
// use pixel.x, pixel.y ... (after some rounding)
});
copied from :
Get Position of Mouse Cursor on Mouseover of Google Maps V3 API Marker
#MehdiKaramosly answer is pretty spot on.
Only slightly furthering the above, to get what would be the lat lng of an element that is not part of the visible map (if the map was visible there) you can pass the events page X/Y to the line:
projection.fromLatLngToContainerPixel(marker.getPosition());
like so:
var pixelLatLng = overlay.getProjection().fromContainerPixelToLatLng(new google.maps.Point(e.pageX,e.pageY));
I have put a very basic example at: http://tinkerbin.com/p30yEXqH
If you click anywhere outside of the map (which equates to the same as clicking on a div that overlays it), you will see in the console log that the lat/lng for wherever you have clicked (even though it is not in the visible map space), is logged.
Cheers,
C.
Update with Working Example of this code
Second Update with JsFiddle Example of both ways click and open map window or mouseover map to highlight listing
As i understand the problem you are having is as following:
Persons are listed in the div separate from map
Persons have latitude and longitude associated to them on the map
Map displays location of person with markers on it using lat long (might be stored in db or something)
You want it so people can highlight a person on map as well as list with mouse over.
If you have lat/long available on map or from list you need to relate them together.
Solution is something like this but there are many ways to achieve this mapping
In your div where person is listed. Insert a data-mapid attribute to each person element when a person hovers over it you highlight it and get the data-mapid from there.
On your map when you render a marker you can additionally pass a parameter data-mapid or something else with same value and have a highlight function on map as well.
`jQuery("#gmap3ul li[data-gb='plist']").each(function(){
elemtopush = {
lat:jQuery(this).attr("data-lat"),
lng:jQuery(this).attr("data-long"),
data:{
"ht":jQuery(this).html(),
"id":jQuery(this).attr("data-mapid")
}
};
ulmarkerspgb.push(elemtopush);
});`
In above code i have html to show on map as well as id as data-mapid now this mapid can be person1 person2 and so on so you can relate back to div with lists. i am using ul and li to list them in the div.
On mouse over your markers events you can do something like this
mouseover: function(marker, event, data)
{
clearalllist();
var listelement = jQuery("td[data-mapid='"+data.id+"']");
jQuery(listelement).attr('style','background-color:#ccc');
var map = jQuery(this).gmap3('get'),
infowindow = jQuery(this).gmap3({action:'get', name:'infowindow'});
if (infowindow){
infowindow.open(map, marker);
infowindow.setContent(data.ht);
google.maps.event.addListener(infowindow, 'closeclick', function(event) {
jQuery(listelement).attr('style','');
});
google.maps.event.addListener(infowindow, 'close', function(event) {
jQuery(listelement).attr('style','');
});
} else {
jQuery(this).gmap3({action:'addinfowindow', anchor:marker, options:{content: data.ht}});
infowindow = jQuery(this).gmap3({action:'get', name:'infowindow'});
google.maps.event.addListener(infowindow, 'closeclick', function(event) {
jQuery(listelement).attr('style','');
});
google.maps.event.addListener(infowindow, 'close', function(event) {
jQuery(listelement).attr('style','');
});
}
}
There is a lot of redundant code i have copied pasted from 3 locations so you might just be able to get what you want out of it.
This can make both map linked to list and list linked to map. See my second update on top or click this JSFiddle example. When you click on list on top it opens the map window and when you mouse over the map icons it highlights the listing.
This also populates the map via list rather than hard coding lat longs in js.
I have a Google V3 map which uses steetView and some map markers.
The little yellow streetView pegman sits on the map on top of the markers.
Is there a way to change the z-indexes so that my markers will be above the pegman
(so that they can be easlly clicked on without having to zoom in)?
In case anything is not clear, here is a fiddle....
http://jsfiddle.net/spiderplant0/BRkCA/
After a bit of experimenting I came up with this...
$("#map_canvas img[src*=cb_scout]").parent("div").css({'zIndex': -200});
$($("#map_canvas img[src*=cb_scout]")[1]).parent("div").parent("div").css({'zIndex': -200});
This forces the pegman to sit beneath the markers but now the pegman is no longer dragable and each time the map is moved etc, the pegman jumps above the markers again.
To keep the pegman under your markers you can watch for the pov_changed event and reset the z-index after a short delay
$google.maps.event.addListener(panorama, 'pov_changed', function() {
var func=function(){
$("#map_canvas img[src*=cb_scout]").parent("div").css({'zIndex': -200});
}
setTimeout(func,1000);
}
});
You will also need to change the depth of the pegman after the maps moves, which can be accomplished with the following snippet
google.maps.event.addListener(map, 'idle', function() {
google.maps.event.trigger(panorama, 'pov_changed');
})
If you want to be able to drag the pegman, you must first place it above the markers by having a toggle button swap the pegman's depth and add an exception to the pov_changed event handler preventing the pagman from dropping depths when the toggle button is active.
Okay, this may be a bit hacky... (and I hope I understood what you were doing)
1) Disable street view control
2) Make another control with a lower zIndex than the marker you have.
3) Update street view control with the position of the fake street view marker.
http://jsfiddle.net/z7Lp8/
You can set the zIndex of the marker above google.maps.Marker.MAX_ZINDEX in order for the pegman to remain under the marker. MAX_ZINDEX is the maximum default z-index that the API will assign to a marker. Marker z-indexes only work when optimizations are turned off on all markers on the map.
Forked fiddle from question to illustrate: http://jsfiddle.net/brendaz/t4v8nhoq/
var marker1 = new google.maps.Marker({
position: new google.maps.LatLng(54.975, -2.020),
map: map,
zIndex: google.maps.Marker.MAX_ZINDEX + 1,
optimized: false
});
The Google Maps API for a Polygon does not offer a drag method.
What would be an efficient way of implementing such a feature (i.e., sufficiently optimised so that it would not kill a four year old laptop)?
Thank you!
I found the Google Maps V2 Polygon Implementation to be very limiting for the needs I have had and solved it by creating a custom overlay. My group is currently stuck on IE6 so I have yet to migrate over to Google Maps V3 - but taking a quick look at the API shows that you could probably do a similar thing that I did in V2 with V3.
Essentially the idea is:
Create a Custom Overlay
Populate it with your own SVG/VML Polygons and attach a drag event to this custom polygon object
Custom Overlays:
Here is some information to get you started on making your own custom overlay:
http://code.google.com/apis/maps/documentation/javascript/overlays.html#CustomOverlays
Creating your own "Dragable" Polygon Object:
Once you get that down you'll want to add your own polygons to the custom overlay instead of using GPolygons. I went through the painful process of learning SVG/VML and writing a library to bridge SVG/VML together - you could do that, but I would recommend starting by trying to use another library such as Raphaël.
http://raphaeljs.com/
Using Raphaël will save you a whole lot of time trying to figure out how to get cross-browser Vector Graphic (Polygon) functionality - and best of all it supports drag events already, here is an example from their library:
http://raphaeljs.com/graffle.html
Once you have a custom overlay and you are able to throw some Raphaël objects onto it the last step is to translate the coordinates you want from a Lat/Lng value to a Pixel value. This is available in the MapCanvasProjection of V3:
http://code.google.com/apis/maps/documentation/javascript/reference.html#MapCanvasProjection
You can use fromLatLngToDivPixel to figure out what the actual pixel values are for the points on your Raphael polygon, draw it, then add it to the overlay with a drag event.
Since version 3.11 (dated Jan 22, 2013) it's possible to just set the draggable property onto the google.maps.Polygon instance; see this example.
If you want to programmatically move a polygon, you'll need a custom Google Maps Extension which I wrote, as the API does not provide such a method.
Here's how I do it. Find the approximate center of the polygon, and add a marker, then add a drag listener to the marker. On lat/lng change, subtract the difference from the original marker lat/lng, subtract the difference to each of the paths, then, set the original position to the new position. Make sure that in your javascript api call that you have library=geometry,drawing
google.maps.event.addListener(draw, 'overlaycomplete', function(shape) {
// POLYGON
if (shape.type == 'polygon') {
var bounds = new google.maps.LatLngBounds(); var i;
var path = shape.overlay.getPath();
for (i = 0; i < path.length; i++) { bounds.extend(path.getAt(i)); }
shape.latLng = bounds.getCenter();
marker = getMarker(map,shape);
shape.overlay.marker = marker;
markers.push(marker);
}
google.maps.event.addListener(marker, 'drag', function(event) {
shape.overlay.move(event.latLng, shape, path);
});
google.maps.event.addListener(shape.overlay, 'rightclick', function() {
this.setMap(null);
this.marker.setMap(null);
draw.setDrawingMode('polygon');
});
});
}
google.maps.Polygon.prototype.move = function(latLng, shape, p) {
var lat = latLng.lat();
var lng = latLng.lng();
latDiff = shape.latLng.lat()-lat;
lngDiff = shape.latLng.lng()-lng;
for (i = 0; i < p.length; i++) {
pLat = p.getAt(i).lat();
pLng = p.getAt(i).lng();
p.setAt(i,new google.maps.LatLng(pLat-latDiff,pLng-lngDiff));
}
shape.latLng = latLng;
}
function getMarker(map,shape){
var infowindow = new google.maps.InfoWindow();
if(shape.type=='polygon'){ latLng = shape.latLng; }
marker = new google.maps.Marker({
position: latLng,
map:map,
draggable:true,
clickable: true,
animation: google.maps.Animation.DROP
});
shape.overlay.marker = marker;
shape.overlay.bindTo('center',marker,'position');
google.maps.event.addListener(marker, 'click', (function(marker) {
return function() {
infowindow.setContent('polygon');
infowindow.open(map, marker);
toggleBounce(marker);
}
})(marker));
google.maps.event.addListener(infowindow,'closeclick', (function(marker) {
return function() {
marker.setAnimation(null);
}
})(marker));
return marker;
}
If you have any questions, feel free to contact me.
You could have markers for each point on the polygon, these markers could have drag and at the end of each drag, the polygon could be redrawn.
You could also have a marker in the center of the polygon representing the polygon as a whole, when you move that marker, every marker could be moved by the same amount to maintain the shape.
Okay - so after seeing the website you are trying to implement I started to feel like Raphael may not be necessary because it is a pretty heavy JS Library - and if you are only trying to draw a rectangle polygon I thought, why not just do it with a single lightweight DIV instead?
However I think the Raphael solution would still hold water for many other cases - so I think I'll just post another possible answer.
Here is a working example I threw together:
http://www.johnmick.net/drag-div-v3/
Feel free to take a look at the source:
http://www.johnmick.net/drag-div-v3/js/main.js
Essentially we do the following
Create the Custom Overlay
Create the draggable div polygon and, using jQuery UI, make it draggable
Tie an event that listens to when the dragging has stopped that updates the LatLng position of the rectangle
Add the object to the Custom Overlay
Implement the draw function to redraw the rectangle during zooms and pans
Currently I am only storing one LatLng value for the Rectangle (being the top left corner) - you could easily extend this example to store all 4 points of the rectangle and have the shape dynamically resize itself on zooms. You may want to do that, otherwise as users zoom out they will get a climate report for a larger and larger area.
I have a webpage that finds a store by postcode or name.
I have just released an update to it so that contact details display in an info window coming from the marker. Due to the small size of the info window, after centering to the marker, the map pans down until it can fit the marker and info window in leaving the marker near the bottom.
Wondering if there is an easy way to set this offset immediately so that the marker appears at the bottom of the map window and it doesn't have to pan?
Thanks.
You could center the map appropriately before you add the marker:
var someZoom = 13;
var center = new GLatLng(37.4419, -122.1419);
map.setCenter(center, someZoom);
The zoom is optional too. You can just leave the zoom on whatever it is:
map.setCenter(center);
If you would like to center on a particular pixel, instead of a lat/lng, then you can use this function to convert:
fromContainerPixelToLatLng(pixel:GPoint)
I feel like you should spend half an hour and review the docs: http://code.google.com/apis/maps/documentation/reference.html. I read the documentation extensively while working on my website: www.trailbehind.com
Perhaps the auto-panning is caused by an internal addoverlay event handler. Have you tried handling the addoverlay event and returning false from it?
GEvent.addListener(map, "addoverlay", function() {
return false;
});
where 'map' is the name of your GMap2 object.