Google Maps InfoBubble pixelOffset (Moving from default position above marker)

Undefined picture Undefined · Jun 2, 2012 · Viewed 21.3k times · Source

I am trying to implement a custom infoBubble that has the box opening to the side of a marker rather than the default position of on top. This has turned out to be harder than expected.

Using the normal infoWindow you can use pixelOffset. See here for the documentation

Using infoBubble this does not seem to be the case. Is there anyway of using pixelOffset in an infoBubble, or something that will do the same thing?

I have found this very difficult to search for, as using a google search such as this returns no relevant results Google Search

Below is all my resources I have been using.

  • Example of infoBubble here.

  • My JavaScript to setup the map and infoBubble here.

And now my javascript here just in-case the jsfiddle link is broken.

<script type="text/javascript">

    $(document).ready(function () {
        init();
    });

    function init() {

        //Setup the map
        var googleMapOptions = {
            center: new google.maps.LatLng(53.5167, -1.1333),
            zoom: 13,
            mapTypeId: google.maps.MapTypeId.ROADMAP
        };

        //Start the map
        var map = new google.maps.Map(document.getElementById("map_canvas"),
        googleMapOptions);

        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(53.5267, -1.1333),
            title: "Just a test"
        });

        marker.setMap(map);

        infoBubble = new InfoBubble({
            map: map,
            content: '<div class="phoneytext">Some label</div>',
            //position: new google.maps.LatLng(-35, 151),
            shadowStyle: 1,
            padding: '10px',
            //backgroundColor: 'rgb(57,57,57)',
            borderRadius: 5,
            minWidth: 200,
            arrowSize: 10,
            borderWidth: 1,
            borderColor: '#2c2c2c',
            disableAutoPan: true,
            hideCloseButton: false,
            arrowPosition: 7,
            backgroundClassName: 'phoney',
            pixelOffset: new google.maps.Size(130, 120),
            arrowStyle: 2
        });
        infoBubble.open(map, marker);

    }
</script>

Update

To help with answering this question i have put together a test case here. The important lines are lines 38 & 39, which should specify where to position the label.

Update 2

For the bounty to be awarded i need to see an example of the infoBubble positioned away from its default position above the marker. Preferably to the right hand side of the marker.

Update 3

I have removed the testcase from update 1 because it is hosted on my old company's servers.

Answer

Anubhav Gupta picture Anubhav Gupta · Mar 19, 2013

This is my solution.

In InfoBubble library

replace

entire InfoBubble.prototype.draw method

with

/*
 * Sets InfoBubble Position
 * */
InfoBubble.prototype.setBubbleOffset = function(xOffset, yOffset) {
  this.bubbleOffsetX = parseInt(xOffset);
  this.bubbleOffsetY = parseInt(yOffset);
}


/*
 * Gets InfoBubble Position
 * */
InfoBubble.prototype.getBubbleOffset = function() {
  return {
    x: this.bubbleOffsetX || 0,
    y: this.bubbleOffsetY || 0
  }
}

/**
 * Draw the InfoBubble
 * Implementing the OverlayView interface
 */
InfoBubble.prototype.draw = function() {
  var projection = this.getProjection();

  if (!projection) {
    // The map projection is not ready yet so do nothing
    return;
  }

  var latLng = /** @type {google.maps.LatLng} */ (this.get('position'));

  if (!latLng) {
    this.close();
    return;
  }

  var tabHeight = 0;

  if (this.activeTab_) {
    tabHeight = this.activeTab_.offsetHeight;
  }

  var anchorHeight = this.getAnchorHeight_();
  var arrowSize = this.getArrowSize_();
  var arrowPosition = this.getArrowPosition_();

  arrowPosition = arrowPosition / 100;

  var pos = projection.fromLatLngToDivPixel(latLng);
  var width = this.contentContainer_.offsetWidth;
  var height = this.bubble_.offsetHeight;

  if (!width) {
    return;
  }

  // Adjust for the height of the info bubble
  var top = pos.y - (height + arrowSize) + this.getBubbleOffset().y;

  if (anchorHeight) {
    // If there is an anchor then include the height
    top -= anchorHeight;
  }

  var left = pos.x - (width * arrowPosition) + this.getBubbleOffset().x;

  this.bubble_.style['top'] = this.px(top);
  this.bubble_.style['left'] = this.px(left);

  var shadowStyle = parseInt(this.get('shadowStyle'), 10);

  switch (shadowStyle) {
    case 1:
      // Shadow is behind
      this.bubbleShadow_.style['top'] = this.px(top + tabHeight - 1);
      this.bubbleShadow_.style['left'] = this.px(left);
      this.bubbleShadow_.style['width'] = this.px(width);
      this.bubbleShadow_.style['height'] =
        this.px(this.contentContainer_.offsetHeight - arrowSize);
      break;
    case 2:
      // Shadow is below
      width = width * 0.8;
      if (anchorHeight) {
        this.bubbleShadow_.style['top'] = this.px(pos.y);
      } else {
        this.bubbleShadow_.style['top'] = this.px(pos.y + arrowSize);
      }
      this.bubbleShadow_.style['left'] = this.px(pos.x - width * arrowPosition);

      this.bubbleShadow_.style['width'] = this.px(width);
      this.bubbleShadow_.style['height'] = this.px(2);
      break;
  }
};

and then you can use this by

var infoBubble = new InfoBubble({
  map: map,
  content: "My Content",
  position: new google.maps.LatLng(1, 1),
  shadowStyle: 1,
  padding: 0,
  backgroundColor: 'transparent',
  borderRadius: 7,
  arrowSize: 10,
  borderWidth: 1,
  borderColor: '#2c2c2c',
  disableAutoPan: true,
  hideCloseButton: true,
  arrowPosition: 50,
  backgroundClassName: 'infoBubbleBackground',
  arrowStyle: 2

});

Then finally we have to use this method setBubbleOffset(x,y); to set InfoBubble position

infoBubble.setBubbleOffset(0,-32);