Search code examples
javascriptgoogle-mapsoms

Get new position of map marker when using Overlapping Marker Spiderfier


I have a google map with markers that uses OverlappingMarkerSpiderfier to spread markers that overlap very closely. I have a need to retrieve the screen position of markers on mouse events (in the real version, I'm making tooltips that are much too complex to wedge into the default that google offers).

function project(latLng) {
  var TILE_SIZE = 256;
  var siny = Math.sin(latLng.lat * Math.PI / 180);

  siny = Math.min(Math.max(siny, -0.9999), 0.9999);

  return new google.maps.Point(
      TILE_SIZE * (0.5 + latLng.lng / 360),
      TILE_SIZE * (0.5 - Math.log((1 + siny) / (1 - siny)) / (4 * Math.PI)));
}

function getPixelPosition(marker, map) {
  var zoom = map.getZoom();
  var scale = 1 << zoom;
  var loc = marker.data.location;
  var worldCoordinate = project(loc);
  var pixelCoordinate = new google.maps.Point(
      Math.floor(worldCoordinate.x * scale),
      Math.floor(worldCoordinate.y * scale));

  return pixelCoordinate;
}

function getMapTopLeftPosition(map) {
  var zoom = map.getZoom();
  var scale = 1 << zoom;
  var topLeft = new google.maps.LatLng(
        map.getBounds().getNorthEast().lat(),
        map.getBounds().getSouthWest().lng());
  var projection = map.getProjection();
  var topLeftWorldCoordinate = projection.fromLatLngToPoint(topLeft);
  var topLeftPixelCoordinate = new google.maps.Point(
          topLeftWorldCoordinate.x * scale,
          topLeftWorldCoordinate.y * scale);

  return topLeftPixelCoordinate;
}

function getMarkerRelativePosition(marker, map) {
  const screenPosition = getPixelPosition(marker, map);

  const topLeftMapPosition = getMapTopLeftPosition(map);

  const markerHeight = 60;
  const markerWidth = 48;
  return {
    x: screenPosition.x - topLeftMapPosition.x - (markerWidth / 2),
    y: screenPosition.y - topLeftMapPosition.y - markerHeight,
  };
}

function showInfo(position, text) {
  // triggered on marker mouseover
  const mapContainer = document.getElementById('map-container');
  const infoDiv = document.createElement('div');
  infoDiv.innerHTML = text;
  infoDiv.setAttribute('id', 'info')
  infoDiv.style.left = position.x + 'px';
  infoDiv.style.top = position.y + 'px';
  mapContainer.appendChild(infoDiv);
}

function hideInfo() {
  // triggered on marker mouseout
  const info = document.getElementById('info')
  info.remove();
}

This works as I want for markers that haven't been spread out from a cluster by OMS. However, when I click a cluster of markers to spread them, the code above still returns the marker's original position. See the working example here: https://jsfiddle.net/ebbishop/s2mzgp0b/

I suspect there is a way to get the marker's new position using the oms library, but I haven't been able to find it in the docs.

How can I retrieve the marker's new position or the change in x & y coordinates?


Solution

  • The problem was the function getPixelPosition. We can easily change this line

    var loc = marker.data.location, which used a custom, static data attribute set for other purposes, and replace it with

    var loc = { lat: marker.getPosition().lat(), lng: marker.getPosition().lng() }, which gets the current position of the marker.

    All oms does, after a heap of calculations, is update the position of the google maps marker using gmaps' own setPosition method, so this works just fine.

    Updated, working example