Replace tile picures in Google maps API getTile override - javascript

I'm doing an application, where you can click on a google maps tile, and replace it with another picture.
The current solution is that I added an overlay map, and overrode the getTile(), to create a custom div with an ID, and a click event listener, where I can select it with ID selector, and work with it.
The current solution is (summed up):
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
var div = ownerDocument.createElement('div');
div.id = 'block_' + coord.x + '_' + coord.y;
return div;
};
google.maps.event.addListener(map, 'click', function(event) {
var coord = ... the current tile coordinate
var block_to_select = $('#block_' + coord.x + '_' + coord.y);
do_magic(block_to_select);
}
It would be better to add the click event listener in the gettile() so I could get rid of the IDs, and a lot of computing code.
I tried:
CoordMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
var div = ownerDocument.createElement('div');
div.dataset.x = coord.x;
div.addEventListener('click',function(){
alert(1);
});
return div;
}
But it the onclick function won't run.
Is there any more efficient way to replace tile pictures?
Returning a jquery $("") also throws error in getTile().

The tiles will be rendered in the overlayLayer-mapPane .
According to the documentation this mapPane may not receive DOM-events, so I'm afraid there is no better way than detecting a particular tile via a calculation.

Related

Best way to make marker resizable in leaflet

I am trying to resize my markers every time the map is zoomed in or out.
Currently I am using this approach:
Iterate all markers in zoomend method.
get current icon size
Perform some calculation to get the new marker size according the zoom size.
set the new dimension to the icon object.
map.on('zoomend', function() {
zoomEndLevel = map.getZoom();
var difference = zoomEndLevel - zoomStartLevel;
console.log("difference in zoom " + difference);
markerArray.forEach(function(marker) {
var icon = marker.options.icon;
var oldX = icon.options.iconSize[0];
var oldY = icon.options.iconSize[1];
var newX = getNewIconAxis(oldX, difference);
var newY = getNewIconAxis(oldY, difference);
console.log(newX + " " + newY);
icon.options.iconSize = [ newX, newY ];
marker.setIcon(icon);
});
});
map.on('zoomstart', function() {
zoomStartLevel = map.getZoom();
});
function getNewIconAxis(value, zoomChange) {
if (zoomChange > 0) {
for (var i = zoomChange; i > 0; i--) {
value = value * 2;
}
} else {
for (var i = zoomChange; i < 0; i++) {
value = value / 2;
}
}
return value;
}
Problem :
This code works fine if I zoom in and out 1 level at once. If I scroll in and out my mouse too frequently then this code given strange outputs. Sometimes the marker size becomes too large or too small.
Question :
1) Is this the only way to make the markers resizable on different zoom levels?
2) If yes then what am I missing here or what changes should be made to make it work perfectly.?
Note : Tagging google maps also because it's more of a logical issue with map (either google or leaflet or mapbox) rather than api specific issue.
Looks like there are several previous posts that you guide you:
Mapbox,leaflet: Increase marker size on Zoom
is there a way to resize marker icons depending on zoom level in leaflet?
https://gis.stackexchange.com/questions/171609/resize-divicons-svgs-at-zoom-levels-leaflet
As for your bug, instead of reading the current icon size value at "zoomstart" event, you might better remember the previous zoom value and read it only at "zoomend" event. I am not sure the "zoomstart" event is fired only once when you scroll (to zoom in/out) successively, while the "zoomend" event may be fired only at the very end.

After dragging I get incorrect coordinates of all the elements but the first

There are some div elements on my page. A user can drag any of them many times. After every dragging, I need to get new coordinates of the div that was dragged.
My code works good with div[0]: I actually get new coordinates after every new dragging.
The problem is with all the other divs, like div[1], div[2], div[10]... Script gets coordinates after the first dragging, but all the next times coordinates are still the same. They don't change.
I tried to clear variables, but that didn't help.
What could be this problem caused by? What should I check to find the solution?
I use jQuery and jQuery UI. Code:
$(document).ready(function(){
$(".rD").draggable({
stop: function(event, ui) {
// get the index of the dragged element
id = $(this).index();
// get coordinates of the dragged element
rect = document.getElementsByTagName("div")[id].getBoundingClientRect();
alert("top:" + rect.top + ", left: " + rect.left);
// clearing variables didn't help to solve the problem
delete rect;
delete id;
}
});
Try to:
alert(ui.position.top, ui.position.left)
Documentation
Whole code:
$(document).ready(function(){
$(".rD").draggable({
stop: function(event, ui) {
// Use var keyword for your local variables
// var rect = ui.helper[0].getBoundingClientRect();
alert("top:" + ui.position.top + ", left: " + ui.position.left);
}
});
});

Getting the eventargs of registered events

I'm new to maps and OpenLayers, but I'm investigating Openlayers because I'll need map functionality in my next project. The map is a WMS image of a medieval town, but without any geo-referencing information.
I found how to register events, but the problem is that the "eventargs" is not working as in the examples I found. In one of the examples they are getting the x and y values after the users panned like this:
map.events.register('moveend', map, function (e)
{
alert(e.xy);
});
If I try this in Visual Studio, e doesn't have an xy property. What am I missing? This is the code I have right now:
<script type="text/javascript">
var map, layer;
function init() {
var windowHeight = $(window).height();
var windowWidth = $(window).width();
var mapdiv = $('#map');
mapdiv.css({width: windowWidth + 'px', height: windowHeight + 'px'});
map = new OpenLayers.Map('map', { maxResolution: 1000 });
layer = new OpenLayers.Layer.Image(
'Globe ESA',
'[url]',
new OpenLayers.Bounds(-180.0, -12333.5, 21755.5, 90.0),
new OpenLayers.Size(windowWidth, windowHeight),
{numZoomLevels: 100}
);
map.addLayer(layer);
nav = new OpenLayers.Control.Navigation();
map.addControl(nav);
//events test
map.events.register('moveend', map, function (e)
{
alert(e.xy);
});
map.zoomToMaxExtent();
}
</script>
In the OpenLayers examples they don't use the eventargs, but I assume that there must be a way to get the zoomlevel, or the x and y after panning?
Thank you!
There is no explicit xy sent to the moveend event as a parameter to the listener. So, while you can write,
map.events.register('moveend', map, function(xy){
xy won't contain any useful information.
However, you can get information from the OpenLayers.Map itself, such as maxExtent and zoom, which you are passing in as the object to the moveend event.
map.events.register('moveend', map, function(){
console.log(map.maxExtent + " " + map.getZoom());
});
There are many other properties associated with the map, which you can see if you set a breakpoint inside the moveend callback. If you haven't looked at the source for map, it is well worth it to understand what is going on. OpenLayers.Map.js
You will see that the moveend event is triggered either without any parameters or with one, a boolean, zoomChanged.

Attaching to jQuery UI Tooltip to openstreetmap marker

I am trying to put a jQuery UI Marker but it's not showing up. To test I have added a title attribute to the H1 above my map and it is working fine.
I have tried a number of things like setting the marker's title using .attr() but this seems the most logical:
ic = "img/" + place.type + '/' + place.status + ".png";
marker = new OpenLayers.Icon(ic, size, 0);
placeMarker = new OpenLayers.Marker(new OpenLayers.LonLat(place.longitude,
place.latitude).transform(gg,sm), marker);
$(placeMarker).tooltip({ content: place.name });
placeLayer.addMarker(placeMarker);
As I said, the H1 tooltip works (and displays over the map so it isn't a z-index problem) but nothing shows up for marker.
To work around this I have created my own tooltip div that is moved around when the cursor moves. Then, when the cursor is above content that I want to tooltip, the div is shown and hidden:
$(document).mousemove(function(e){
curX = e.pageX + 10;
curY = e.pageY;
tooltip = $("#tooltip");
tooltip.css("left", curX);
tooltip.css("top", curY);
});

z-Index overlay in google maps version 3

I'm trying to get an overlay in google maps api v3 to appear above all markers. But it seems that the google api always put my overlay with lowest z-index priority. Only solution i've found is to iterate up through the DOM tree and manually set z-index to a higher value. Poor solution.
I'm adding my a new div to my overlay with:
onclick : function (e) {
var index = $(e.target).index(),
lngLatXYposition = $.view.overlay.getProjection().fromLatLngToDivPixel(this.getPosition());
icon = this.getIcon(),
x = lngLatXYposition.x - icon.anchor.x,
y = lngLatXYposition.y - icon.anchor.y
$('<div>test</div>').css({ left: x, position: 'absolute', top: y + 'px', zIndex: 1000 }).appendTo('.overlay');
}
I've tried every property I could think of while creating my overlay. zIndex, zPriority etc.
I'm adding my overlay with:
$.view.overlay = new GmapOverlay( { map: view.map.gmap });
And GmapOverlay inherits from new google.maps.OverlayView.
Any ideas?
..fredrik
If anyone was having the same problem as I was, here is my problem and solution:
I needed an OverlayView which would add tooltips to markers, but my popup overlay kept showing behind the markers.
I implemented a subclass of the OverlayView as per the Google documentation:
https://developers.google.com/maps/documentation/javascript/customoverlays
When you write your custom OverlayView.prototype.onAdd function, you need to specify to which Pane to attach your overlay. I just copied the code without actually reading the surrounding explanation.
In their code, they attach the overlay to the overlayLayer pane:
var panes = this.getPanes();
panes.overlayLayer.appendChild(div);
But there are many different MapPanes you can use:
"The set of panes, of type MapPanes, specify the stacking order for different layers on
the map. The following panes are possible, and enumerated in the order in which they are stacked from bottom to top:"
MapPanes.mapPane (Level 0)
MapPanes.overlayLayer (Level 1)
MapPanes.markerLayer (Level 2)
MapPanes.overlayMouseTarget (Level 3)
MapPanes.floatPane (Level 4)
I wanted the overlay to hover over all other info on the map, so I used the floatPane pane and problem solved.
So, instead of :
this.getPanes().overlayLayer.appendChild(div)
you use this :
this.getPanes().floatPane.appendChild(div);
You can't change the zIndex of an OverlayView (it has no such property), but it holds panes that contains DOM nodes. That's where you can use the z-index property;
...
lngLatXYposition = $.view.overlay.getPanes().overlayLayer.style['zIndex'] = 1001;
...
In order to be able to play around with the paneType of the mapLabel class, I added a paneType property to the MapLabel class from google utility library (https://code.google.com/p/google-maps-utility-library-v3/source/browse/trunk/maplabel/src/maplabel.js?r=303).
This is usefull to make the label not to be hidden by a polyline.
Please find the code additions to the mapLabel.js file.
MapLabel.prototype.onAdd = function() {
var canvas = this.canvas_ = document.createElement('canvas');
var style = canvas.style;
style.position = 'absolute';
var ctx = canvas.getContext('2d');
ctx.lineJoin = 'round';
ctx.textBaseline = 'top';
this.drawCanvas_();
var panes = this.getPanes();
if (panes) {
// OLD: panes.mapPane.appendChild(canvas)
var paneType = this.get('paneType');
panes[paneType].appendChild(canvas);
}
};
MapLabel = function (opt_options) {
this.set('fontFamily', 'sans-serif');
this.set('fontSize', 12);
this.set('fontColor', '#000000');
this.set('strokeWeight', 4);
this.set('strokeColor', '#ffffff');
this.set('align', 'center');
this.set('zIndex', 1e3);
this.set('paneType', 'floatPane');
this.setValues(opt_options);
}
Sample code using the paneType:
var mapLabel = new MapLabel({
text: segDoc.curr_value.toFixed(0),
position: new google.maps.LatLng(lblLat, lblLng),
map: map.instance,
fontSize: 12,
align: 'center',
zIndex: 10000,
paneType: 'floatPane',
});
Thanks!
Setting z-index to 104 for the overLay layer seems to be the "magic" number" if you care about interacting with the markers (i.e. dragging markers). Any higher than 104 and you can not interact with the markers. Wondering if there is a less brittle solution...
Use panes.overlayMouseTarget.appendChild
If you want to allow your layer to be targetable through mouse clicks (and use events such as "click" or CSS pseudo ::hover) then you should add your overlay to the map using overlayMouseTarget
var panes = this.getPanes();
panes.overlayMouseTarget.appendChild(this.div_);
Also see:
https://developers.google.com/maps/documentation/javascript/reference?csw=1#MapPanes
Disclaimer: this is a dodgy solution that may stop working at any time and you definitely shouldn't use this in production.
For those looking for a quick and dirty solution, this CSS worked for me:
.gm-style > div:first-child > div:first-child > div:nth-child(4) {
z-index: 99 !important;
}
Use at your own risk!

Categories