Placing a MapLabel on top of a Polygon in Google Maps V3 - javascript

I'm trying to place a MapLabel on top of a Polygon in Google Maps V3. I've tried to set the MapLabel zIndex to 2 and the Polygon zIndex to 1 without any luck. Isn't this possible since the Polygon doesn't really follow zIndex?
I've created a jsFiddle for you guys to check out: http://jsfiddle.net/7wLWe/1/
Solution: In maplabel.js change:
mapPane.appendChild(canvas);
to:
floatPane.appendChild(canvas);
The reason is because floatPane is above all map layers (pane 6)
http://code.google.com/apis/maps/documentation/javascript/reference.html#OverlayView

This is probably a late find.. but hope someone would find this useful.
If you don't want to use floatPane (John's Solution) as this will be always on top of everything, and want to give a custom zIndex.. Edit the maplabel.js. Add the following line just before the end of MapLabel.prototype.onAdd = function() {
if (canvas.parentNode != null) {
canvas.parentNode.style.zIndex = style.zIndex;
}
Now you can pass zIndex while creating a maplabel:
var mapLabel = new MapLabel({
text: "abc",
position: center,
map: map,
fontSize: 8,
align: 'left',
zIndex: 15
});

If you don't want to touch maplabel.js, you can add this function to change the z-index of the parent of the labels (although if you have other canvas elements, you may need to alter the function):
//change the z-index of the canvas elements parents to move them above polygon layer
google.maps.event.addListenerOnce(map, 'idle', function(){
//var canvasElements = document.getElementsByTagName('canvas');//plain js to get the elements
var canvasElements = jQuery('canvas'); //jquery for easy cross-browser support
for(var i=0; i<canvasElements.length; i++){
canvasElements[i].parentNode.style.zIndex = 9999;
}
});

Great to see that you're using the MapLabel utility library!
As you've found out, the MapLabel sits in a different map pane. zIndex is only respected within a certain pane.

var maplabel = new MapLabel....
$(maplabel.getPanes().mapPane).css('z-index', maplabel.zIndex);
jQuery made it pretty simple for me without changing maplabel.js
I also found an alternate solution
$(maplabel.getPanes().mapPane).addClass('map-pane');
and then defining the z-index in a stylesheet

I sketched up this CodePen example utilizing the gmaps-labels class. It is based on the fiddle in the Q above and adds the ose of a LabelOverlay class. The class requires a new google.maps.LatLng, dimensions (in LatLng units) of a box centered around the label's point (If the label would overflow this box, hide it, and some CSS. Heres a code stub, check out the demo in the CodePen.
var MIN_BOX_H = 0.0346,
MIN_BOX_W = 0.121,
MAX_BOX_H = 0.001,
MAX_BOX_W = 0.03;
var overlay1 = new LabelOverlay({
ll : myLatlng,
minBoxH : MIN_BOX_H,
minBoxW : MIN_BOX_W,
maxBoxH : MAX_BOX_H,
maxBoxW : MAX_BOX_W,
...
label : "I want on top",
map : map
});

Related

Google Maps API v3, Remove Marker icon or changing to "null"?

I'm writing a Python Flask application in which I'm using Google Maps. I want to be able to add labels to a polyline that I've drawn which symbolizes a ship route.
The route is drawn using a set of coordinates and the polyline feature of the Maps API. I want to add time labels to the polyline and the easiest way seems to be to use Map Markers. However I don't want the large standard pins to show up, but would prefer a small icon/marker together with my text or even none at all. As far as I have gathered you can create "Circles" (which are modifiable) or "Markers" (which you only can change the icon of). I would prefer to go with "Circles", but those you apparently can't add text to..
How can I add text to my map and avoid the Google Maps Pins showing up?
Currently I have an list of objects that contains latitude, longitude and date + time. I'm iterating through it adding markers, but as I do I would like to keep out the marker icon or instead draw the circles if someone knows how to draw circles with added text?
for(i = 0; i < markerList.length; i++){
var position = new google.maps.LatLng(markerList[i].lat, markerList[i].lng);
var date = markerList[i].date;
var marker = new google.maps.Marker({
position: position,
label: date,
map: map,
icon: "None" //Produces error: 404 (NOT FOUND)
});
}
Being able to change the label size also is a very much appreciated function, but I have been unable to find any information about whether that is available. Being able to change the color of the text would also be nice.
As no answers have been given yet and I've sort of found a solution to my problem I guess I will share for others out there with the same problem. At least until someone comes up with a better solution:
I ended up using a predefined symbol and scaling it down to 0 in size as follows:
for(i = 0; i < markerList.length; i++){
var position = new google.maps.LatLng(markerList[i].lat, markerList[i].lng);
var date = markerList[i].date;
var marker = new google.maps.Marker({
position: position,
label: date,
map: map,
icon: {
path: google.maps.SymbolPath.CIRCLE,
scale: 0
}
});
}
Sadly I haven't found a way to mess with the label yet.
try markerWithlabel and you can change the icon of the marker whit a svg or png plus the label too
like this jsfiddel
.
#Zeliax You can add visible: false to not have marker icon show on your google map. icon prop looks for a path that you want specify for your marker to look as. It is basically a url for your display image.

How to use Leaflet to create a map out of an image

OK, I have found an example of exactly what I think I require. I cannot work out how to set it up for my image and I'm not sure if this is the best approach to achieve my goal.
Intended Result :
http://maps.mixedbredie.net/leaflet/image.html
Example Code:
var map = L.map('map', {maxZoom: 17}).setView([51.495, -0.075], 14);
/* Instead of a tile layer, use a bitmap image */
var imageUrl = 'data/TM_pano.jpg';
var imageBounds = [[51.490, -0.122], [51.510, -0.028]];
L.imageOverlay(imageUrl, imageBounds).addTo(map);
L.marker([51.495, -0.075]).addTo(map)
.bindPopup("This is Table Mountain.");
var popup = L.popup();
function onMapClick(e) {
popup
.setLatLng(e.latlng)
.setContent("You clicked the map at " + e.latlng.toString())
.openOn(map);
}
map.on('click', onMapClick);
map.setMaxBounds(imageBounds);
Questions:
1.) How to choose the longitude/latitude, image bounds?
i.e. .setView([51.495, -0.075], 14)
var imageBounds = [[51.490, -0.122], [51.510, -0.028]];
2.) Should zoom 0 show my whole image? What are reasonable limits?
3.) Can I use real coordinates with this approach? i.e. Mapping a water pipe underground but using a custom .jpg of that pipe schematic? Then I could put markers on the pipe for certain long/lats.
See http://omarriott.com/aux/leaflet-js-non-geographical-imagery/ for question 1 and 2
For the third one, you could georeference (or warp) the image, and then display it onto a map, setting the transparency for example.
The georeferencing could be done with Qgis or a tool like Mapwarper https://github.com/timwaters/mapwarper
(old question, but I think an answer could be useful)

is there a way to resize marker icons depending on zoom level in leaflet?

I'm making a project for the school and I need to resize the marker icons depending on zoom level in a leaflet map, Is there an easy way to accomplish this? Any tutorial on the web? Thanks in advance for the help!!!
In order to change the size of the markers when you zoom in/out, you'll need to handle the event.
map.on('zoomend', function() { });
The zoomend event will be called whenever the map has finished zooming in or out. See the API here.
Now, inside this function, you can call your custom code in order to change the size of the markers. For example, let's say you wanted to take a simple approach and set the size of a circle marker equal to the size of the maps zoom level. See the API for a CircleMarker here
// Create some marker that will be resized on the map zooming
var myMarker = new L.CircleMarker([10,10], { /* Options */ });
map.on('zoomend', function() {
var currentZoom = map.getZoom();
myMarker.setRadius(currentZoom);
});
Now whenever the map zooms in or out, the size of the marker will change.
I'm not sure what Stophace is referring to regarding circleMarkers not changing size, but, adding to the approved answer... if you want to resize circleMakers or change any other styling options (I find it helpful to change the weight along with radius), you can use the following approach:
map.on('zoomend', function() {
var currentZoom = map.getZoom();
var myRadius = currentZoom*(1/2); //or whatever ratio you prefer
var myWeight = currentZoom*(1/5); //or whatever ratio you prefer
layername.setStyle({radius: myRadius, weight: setWeight});
});
layername will be replaced with the name of whatever layer you have which contains circleMarkers... and of course you can change the fractions to your liking to suit your needs.
I'm guessing the OP's school project is finished, but I hope this helps others who have the same question!

Google Maps custom content boxes?

I can't seem to find andthing in the Google Maps V3 docs about creating custom content boxes for Google maps.
Below is an example of a custom content box:
http://www.apple.com/retail/alamoana/map/
My question is... how do you go about changing the default white balloon popup?
Cheers!
Look at the InfoBox toolkit in the v3 utility libraries. I'm using them on dev.mapfaire.com, if you want to take a look.
Personally, i don't use any of google's custom overlay scripts and such. I made a custom php page which hold the iframe, where I can load custom css files, and also I create custom DIVs that go over top of the map, which are then repositioned while dragging when opened.
You can use the "Drag,Dragstart,Dragend" events to help you reposition elements that you have created.
If you have custom markers set onto you page you can get their pixel position with this function:
getPosition: function (marker) {
var map = this.map /* Your map, in my case is part of my controller object linked to this.map */;
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)
);
return pixelOffset; /* Returns the top left pixel of the specified marker on the specified map */
}
And then I use a setPosition function which is used when the window is dragging, it sets your custom element's position to the marker's position.
The dragging event can be set in such manner:
google.maps.addEventListener(map,'drag',function () { setPosition(marker,element); });
The setPosition Function simply gathers the width,height of the element, and the pixel offset associated to the marker using the getPosition(marker) function:
setPosition: function (marker,element) {
var p = this.getPosition(marker),
s = {width:element.offsetWidth,height:element.offsetHeight},
markerOffset = {width:58,height:58};
element.style.left = p.x - (s.width/2) + (markerOffset.width/2) + "px"; /* We set the element's left position to the marker's position + half of our element's width + half of the marker's width's so it is centered */
element.style.top = p.y - s.height - (markerOffset.height) + 10 + "px"; /* We set the element's top position to the marker's position + our element's height + markers height so it is 10px above our marker vertically */
},
Sometimes you just have to think a bit outside the box
That example is using the second version of google maps. That features might not be available in the 3rd one.
But you can add any html code in the infowindows and personalize them. I'm not sure if you can change how they look directly, but you can definitely change how the content looks like.
Edit: I found some sample code: http://gmaps-samples-v3.googlecode.com/svn/trunk/infowindow_custom/infowindow-custom.html
Take a look at gmaps-utility-library-dev and more specific in the ExtInfoWindow utility and PopupMarker utility
As Sudhir pointed out, the Infobox Plugin is one way to do what you want. I've recently answered a similar question about using the infobox plugin for google maps api 3 and provided a complete example.

Drag (move) a polygon using Google Maps v3

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.

Categories

Resources