0

I am trying to implement a pop-up context menu in GoogleMaps. The best of the Google search results I found was this 2012 StackOverflow post

Google Map V3 context menu

(of four examples given at top, two URLs no longer work - but some additional options are given in later comments)

I investigated four code options mentioned there, deciding that the Pearman code, as referenced in

http://googlemapsmania.blogspot.com/2012/04/create-google-maps-context-menu.html

would be best for my case. However, when I implemented it I discovered a problem - which I then determined also occurs in his original example

http://code.martinpearman.co.uk/googlemapsapi/contextmenu/1.0/examples/advanced_example.htm

when one knows what to look for. (This also occurs for a later fork of the original code that I found). All works as expected so long as the map is not moved, with the pop-up menu position being altered by the location of the mouse click such that the entire menu is always visible within the map area. BUT if the map is moved, then the popup can be cutoff, per the bottom left corner in the example below (in which I first moved Norwich into the corner, then right-clicked on it)

enter image description here

Looking into the code, I see it uses GoogleMaps Overlay. Reading up a bit on that, I get the impression that "something" needs to be done/updated when an overlay is moved. But I am beyond my knowledge level and ability to fully understand what I am reading, so am hoping to find some help/insight here. Hoping to figure out a general solution to also help others who implement Pearman's code.

Community
  • 1
  • 1
Jack
  • 175
  • 2
  • 11

2 Answers2

0

SOLUTION FOUND

Lots of searching and testing and false turns while working on this, but finally got a solution - of course it seems "obvious" after one finally sorts out what is going on.

Short answer: values returned by GM Overlay "fromLatLngToDivPixel" function represent the "GM DIV" and hence location on the GM map whereas "fromLatLngToContainerDiv" values represent the "map_canvas DIV" and hence the observed map boundary. So the actual placing of the menu must be based upon values returned by "fromLatLngToDivPixel" but testing its visibility within the map_canvas DIV must be based upon values from "fromLatLngToContainerDiv". Sometimes values returned by the different functions are identical but sometimes not - the former seems to occur when the map is static whereas the latter can occur when the map is moved/dragged.

Long answer:

The relevant part of the original Pearman code is, where "left" and "top" are later used in CSS styling of the menu, to set its position:

var mousePosition=this.getProjection().fromLatLngToDivPixel(this.position_);
var left=mousePosition.x;
var top=mousePosition.y;
if(mousePosition.x>mapSize.width-menuSize.width-this.pixelOffset.x){
  left=left-menuSize.width-this.pixelOffset.x;
} else {
  left+=this.pixelOffset.x;
}
if(mousePosition.y>mapSize.height-menuSize.height-this.pixelOffset.y){
  top=top-menuSize.height-this.pixelOffset.y;
} else{
 top+=this.pixelOffset.y;
}                       

I found the following helpful comments regarding "fromLatLngToContainerPixel" in How to call fromLatLngToDivPixel in Google Maps API V3? , which led me to my fix

... This works perfectly for me initially, but if I pan the map the pixel positions are not updated. ...
... using fromLatLngToContainerPixel instead of fromLatLngToDivPixel solved my issue with pixel positions not updating after panning the map. Roger Ertesvag

Looking at values returned by "fromLatLngToDivPixel", they were sometimes not valid for the map_canvas DIV containing the map (i.e. were sometime larger than the size of that DIV), whereas "fromLatLngToContainerPixel" DID produce apparently valid values. But the seemingly obvious "fix" of simply replacing "fromLatLngToDivPixel" with "fromLatLngToContainerPixel" often produced much weirdness, with the menu not appearing.

I now gather that the "mousePosition" values returned by "fromLatLngToDivPixel" are valid for the location within the "GoogleMaps DIV" (still unclear exactly what that is) but are not appropriate for the map_canvas DIV. Thus my "fix" was to use values from "fromLatLngToDivPixel" for the "base" menu location but use values from "fromLatLngToContainerPixel" to test and alter its display within the map_canvas DIV.

Specifically, instead of the original I'm now using the following code and it is working successfully.

var mousePosition=this.getProjection().fromLatLngToDivPixel(this.position_);
var left=mousePosition.x;
var top=mousePosition.y;
// my fix below, adjusting location based on nearness of map area boundary
var containerPosition=this.getProjection().fromLatLngToContainerPixel(this.position_);
if(containerPosition.x>mapSize.width-menuSize.width-this.pixelOffset.x){
  left=left-menuSize.width-this.pixelOffset.x;
} else {
  left+=this.pixelOffset.x;
}
if(containerPosition.y>mapSize.height-menuSize.height-this.pixelOffset.y){
  top=top-menuSize.height-this.pixelOffset.y;
} else {
  top+=this.pixelOffset.y;
}
Community
  • 1
  • 1
Jack
  • 175
  • 2
  • 11
0

PS: as a note to someone wanting to use the Pearman code for their context menus, I am actually using code (now altered) from a fork based upon it

https://github.com/knezmilos13/google-maps-api-contextmenu

The fork adds the ability to have global class names for the menu items, but that is not why I'm using it. For me, the original Pearman code sometimes produced a "sticky" menu, i.e. the menu remained displayed after it should be closed, especially on first usage of a menu, but that behaviour did not occur using the forked code. Don't know the reason for the difference, did not investigate further.

Jack
  • 175
  • 2
  • 11