Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 1019293
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 16, 20262026-05-16T10:59:22+00:00 2026-05-16T10:59:22+00:00

I need to create a custom look for the Google Maps info windows (straight-edge

  • 0

I need to create a custom look for the Google Maps info windows (straight-edge frame and transparency, etc). I understand this is only doable with an external plugin, but I am not sure which one to use.

I have tried to use extInfoWindow, but I have had problems with getting it to work properly.

I have also looked at PD Marker window (http://www.pixeldevelopment.com/pdmarker.asp), but it seems it has been a while since it has been updated (2007)

Are there any other plugins with similar functionality?

Thank you,

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-16T10:59:23+00:00Added an answer on May 16, 2026 at 10:59 am

    I had that problem myself.
    I’ve been using api v.3 and there was no really good custom infobox out there, so I made up one myself (based on a few that I’ve found).
    I hope it helps 🙂

    Here’s the plugin code:

    function InfoBox(opt_opts) {
        opt_opts = opt_opts || {};
        this.imgPath='img/infoBox/';
        google.maps.OverlayView.apply(this, arguments);
        // Standard options (in common with google.maps.InfoWindow):
        this.content_ = opt_opts.content || "";
        this.maxWidth_ = opt_opts.maxWidth || 0;
        this.pixelOffset_ = opt_opts.pixelOffset || new google.maps.Size(0, 0);
        this.position_ = opt_opts.position || new google.maps.LatLng(0, 0);
        this.zIndex_ = opt_opts.zIndex || null;
    
        // Additional options (unique to InfoBox):
        this.boxStyle_ = opt_opts || {};
        this.infoBoxClearance_ = new google.maps.Size(1, 1);
        this.isHidden_ = opt_opts.isHidden || false;
        this.pane_ = "overlayMouseTarget";
        this.enableEventPropagation_ = opt_opts.enableEventPropagation || false;
        this.div_ = null;
        this.closeListener_ = null;
        this.eventListener1_ = null;
        this.eventListener2_ = null;
        this.eventListener3_ = null;
        this.contextListener_ = null;
        this.fixedWidthSet_ = null;
    }
    
    /* InfoBox extends OverlayView in the Google Maps API v3. */
    InfoBox.prototype = new google.maps.OverlayView();
    
    // Creates the DIV representing the InfoBox. @private
    InfoBox.prototype.createInfoBoxDiv_ = function(){
        var bw, me = this;
    
        // This handler prevents an event in the InfoBox from being passed on to the map.
        var cancelHandler = function (e){ e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); };
        // This handler ignores the current event in the InfoBox and conditionally prevents the event from being passed on to the map. It is used for the contextmenu event.
        var ignoreHandler = function (e) { e.returnValue = false; if (e.preventDefault) e.preventDefault(); if (!me.enableEventPropagation_){ e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation(); } };
    
        if (!this.div_){    // first time create
            this.div_ = document.createElement("div");
            this.div_.className = 'infowindow';
            this.setBoxStyle_();
    
            // Apply required styles:
            if (this.zIndex_ !== null) this.div_.style.zIndex = this.zIndex_;
    
            this.div_.contentDiv = document.createElement('div');
            this.div_.contentDiv.className = 'infowindow-wrapper';
            this.div_.contentDiv.innerHTML = this.content_;
            this.div_.innerHTML = '<img src="'+this.imgPath+'close.png" align="right" class="infowindow-close">';
            this.div_.appendChild(this.div_.contentDiv);
    
            // Add the InfoBox DIV to the DOM
            this.getPanes()[this.pane_].appendChild(this.div_);
            this.addClickHandler_();
            if (this.div_.style.width) this.fixedWidthSet_ = true;
            else {
                if (this.maxWidth_ !== 0 && this.div_.offsetWidth > this.maxWidth_) {
                    this.div_.style.width = this.maxWidth_;
                    this.fixedWidthSet_ = true;
                } 
                else { // The following code is needed to overcome problems with MSIE
                    bw = this.getBoxWidths_();
                    this.div_.style.width = (this.div_.offsetWidth - bw.left - bw.right) + "px";
                    this.fixedWidthSet_ = false;
                }
            }
    
            //add shadow
            this.shadowContainer_ = document.createElement("div");
            this.shadowContainer_.style.position='absolute';
            this.shadowContainer_.style.display = 'block';
            this.shadowContainer_.style.zIndex='-99';
            this.getPanes()['overlayShadow'].appendChild(this.shadowContainer_);
    
            this.shadow = document.createElement('img');
            this.shadow.src = this.imgPath+'shadow.png';
            this.shadow.style.position='absolute';
            this.shadow.style.width = '100%';
            this.shadow.style.height    = '100%';
    
            this.shadowContainer_.appendChild(this.shadow);
            if (!this.enableEventPropagation_) {
                this.eventListener1_ = google.maps.event.addDomListener(this.div_.contentDiv, "mousedown", cancelHandler);
                this.eventListener2_ = google.maps.event.addDomListener(this.div_, "click", function(e){
                    e.cancelBubble = true; if (e.stopPropagation) e.stopPropagation();
                    if (GoogleMap && GoogleMap.closeEditors) GoogleMap.closeEditors(true);              
                });
                //this.eventListener3_ = google.maps.event.addDomListener(this.div_, "dblclick", cancelHandler);
                try{ this.eventListener3_ = google.maps.event.addDomListener(this.div_, "dblclick", facilityEditor);}catch(e){}
            }
            this.contextListener_ = google.maps.event.addDomListener(this.div_, "contextmenu", ignoreHandler);
    
            var contentWidth = parseInt(this.div_.style.width.slice(0,-2)), contentHeight = this.div_.offsetHeight;
            this.wrapperParts = { //create an object to reference each image
                tl:{l:-26, t:-26, w:26, h:26},
                t:{l:0, t:-26, w:contentWidth, h:26},
                tr:{l:contentWidth, t:-26, w:26, h:26},
                l:{l:-26, t:0, w:26, h:contentHeight},
                r:{l:contentWidth, t:0, w:26, h: contentHeight },
                bl:{l:-26, t:contentHeight, w:26, h:26},
                b:{l:0, t:contentHeight, w:contentWidth, h:26},
                br:{l:contentWidth, t:contentHeight, w:26, h:26},
                p:{l:contentWidth-170, t:contentHeight+18, w:92, h:77 }
            }
            for (i in this.wrapperParts){ //create the image DOM objects
                var img = document.createElement('img');
                img.src = this.imgPath + i + '.png'; //load the image from your local image directory based on the property name of the wrapperParts object
                img.style.position='absolute'; //set the appropriate positioning attributes
                img.style.top=this.wrapperParts[i].t+'px';
                img.style.left=this.wrapperParts[i].l+'px';
                img.style.width=this.wrapperParts[i].w+'px';
                img.style.height=this.wrapperParts[i].h+'px';
                this.div_.appendChild(img);
                this.wrapperParts[i].img = img;
            }
            google.maps.event.trigger(this, "domready");
        }
    
        else {
            var contentWidth = parseInt(this.div_.style.width.slice(0,-2)), contentHeight = this.div_.offsetHeight, twp=this.wrapperParts;
            twp.t.img.style.width=contentWidth+'px';
            twp.tr.img.style.left=contentWidth+'px';
            twp.l.img.style.height=contentHeight+'px';
            twp.r.img.style.left=contentWidth+'px';
            twp.r.img.style.height=contentHeight+'px';
            twp.bl.img.style.top=contentHeight+'px';
            twp.b.img.style.top=contentHeight+'px';
            twp.b.img.style.width=contentWidth+'px';
            twp.br.img.style.left=contentWidth+'px';
            twp.br.img.style.top=contentHeight+'px';
            twp.p.img.style.left=(contentWidth-170)+'px';
            twp.p.img.style.top=(contentHeight+18)+'px';
        }
    };
    
    InfoBox.prototype.addClickHandler_=function(){ 
        this.closeListener_ = google.maps.event.addDomListener(this.div_.firstChild, 'click', this.getCloseClickHandler_());
        try{ this.eventListener3_ = google.maps.event.addDomListener(this.div_, "dblclick", facilityEditor);}catch(e){}
    };
    InfoBox.prototype.getCloseClickHandler_=function () { var me = this; return function(){ me.close(); google.maps.event.trigger(me, "closeclick"); }; };
    
    //Pans the map so that the InfoBox appears entirely within the map's visible area. @private
    InfoBox.prototype.panBox_ = function (disablePan) {
      if (!disablePan) {
        var map = this.getMap();
        var bounds = map.getBounds();
        // The degrees per pixel
        var mapDiv = map.getDiv();
        var mapWidth = mapDiv.offsetWidth;
        var mapHeight = mapDiv.offsetHeight;
        var boundsSpan = bounds.toSpan();
        var longSpan = boundsSpan.lng();
        var latSpan = boundsSpan.lat();
        var degPixelX = longSpan / mapWidth;
        var degPixelY = latSpan / mapHeight;
    
        // The bounds of the map
        var mapWestLng = bounds.getSouthWest().lng();
        var mapEastLng = bounds.getNorthEast().lng();
        var mapNorthLat = bounds.getNorthEast().lat();
        var mapSouthLat = bounds.getSouthWest().lat();
    
        // The bounds of the box
        var position = this.position_;
        var iwOffsetX = this.pixelOffset_.width;
        var iwOffsetY = this.pixelOffset_.height;
        var padX = this.infoBoxClearance_.width;
        var padY = this.infoBoxClearance_.height;
    
        var iwWestLng = position.lng() + (iwOffsetX - padX - this.div_.contentDiv.offsetWidth/2 - 450) * degPixelX; // 450 - move right - from under the sidebar
        var iwEastLng = position.lng() + (iwOffsetX + padX + 220) * degPixelX;
        var iwNorthLat = position.lat() - (iwOffsetY - padY - this.div_.contentDiv.offsetHeight - 180) * degPixelY; // 180 - move down - from under the top search bar
        var iwSouthLat = position.lat() - (iwOffsetY + padY + 20) * degPixelY;
    
        // Calculate center shift
        var shiftLng = (iwWestLng < mapWestLng ? mapWestLng - iwWestLng : 0) + (iwEastLng > mapEastLng ? mapEastLng - iwEastLng : 0);
        var shiftLat = (iwNorthLat > mapNorthLat ? mapNorthLat - iwNorthLat : 0) + (iwSouthLat < mapSouthLat ? mapSouthLat - iwSouthLat : 0);
        if (!(shiftLat === 0 && shiftLng === 0)) {
          // Move the map to the new shifted center.
          var c = map.getCenter();
          map.setCenter(new google.maps.LatLng(c.lat() - shiftLat, c.lng() - shiftLng));
        }
      }
    };
    
    // Sets the style of the InfoBox. @private
     InfoBox.prototype.setBoxStyle_ = function () {
      var i;
      var boxStyle = this.boxStyle_;
      for (i in boxStyle)  if (boxStyle.hasOwnProperty(i))  this.div_.style[i] = boxStyle[i];
      // Fix up opacity style for benefit of MSIE:
      if (typeof this.div_.style.opacity !== "undefined")  this.div_.style.filter = "alpha(opacity=" + (this.div_.style.opacity * 100) + ")";
    };
    
    // Get the widths of the borders of the InfoBox. @private; @return {Object} widths object (top, bottom left, right)
    InfoBox.prototype.getBoxWidths_ = function () {
      var computedStyle;
      var bw = {top: 0, bottom: 0, left: 0, right: 0};
      var box = this.div_;
      if (document.defaultView && document.defaultView.getComputedStyle) {
        computedStyle = box.ownerDocument.defaultView.getComputedStyle(box, "");
        if (computedStyle) {
          // The computed styles are always in pixel units (good!)
          bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0;
          bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
          bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0;
          bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0;
        }
      } 
      else if (document.documentElement.currentStyle) { // MSIE
        if (box.currentStyle) {
          // The current styles may not be in pixel units, but assume they are (bad!)
          bw.top = parseInt(box.currentStyle.borderTopWidth, 10) || 0;
          bw.bottom = parseInt(box.currentStyle.borderBottomWidth, 10) || 0;
          bw.left = parseInt(box.currentStyle.borderLeftWidth, 10) || 0;
          bw.right = parseInt(box.currentStyle.borderRightWidth, 10) || 0;
        }
      }
      return bw;
    };
    
    // Invoked when <tt>close</tt> is called. Do not call it directly.
    InfoBox.prototype.onRemove = function () {
      if (this.div_) {
         this.shadowContainer_.parentNode.removeChild(this.shadowContainer_);
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
      }
    };
    
    //Draws the InfoBox based on the current map projection and zoom level.
    InfoBox.prototype.draw = function(){
        this.createInfoBoxDiv_();
        var pixPosition = this.getProjection().fromLatLngToDivPixel(this.position_);
    
        this.div_.style.left = (pixPosition.x - this.div_.offsetWidth + 180 ) + "px";
        this.div_.style.top = (pixPosition.y - this.div_.offsetHeight - 125) + "px";
    
        this.shadowContainer_.style.left = (pixPosition.x - this.div_.offsetWidth + 220 ) + 'px';
        this.shadowContainer_.style.top = (pixPosition.y - this.div_.offsetHeight - 130) + "px";
    
        this.shadowContainer_.style.height = (this.div_.offsetHeight+100 ) + 'px';
        this.shadowContainer_.style.width = (this.div_.offsetWidth+100 ) + 'px';
    
        if (this.isHidden_) this.div_.style.visibility = 'hidden';
        else this.div_.style.visibility = "visible";
    
        this.panBox_();
    };
    
    
    InfoBox.prototype.setContent = function(content){
        this.content_ = content;
        if (this.div_){// Odd code required to make things work with MSIE.
            this.div_.style.visibility='hidden'
            if (!this.fixedWidthSet_) this.div_.style.width = "";
            this.div_.contentDiv.innerHTML = content;
            // Perverse code required to make things work with MSIE. (Ensures the close box does, in fact, float to the right.)
            if (!this.fixedWidthSet_){ this.div_.style.width = this.div_.offsetWidth + "px"; this.div_.contentDiv.innerHTML = content; }
            this.addClickHandler_();
        }
        // This event is fired when the content of the InfoBox changes. @name InfoBox#content_changed; @event
        google.maps.event.trigger(this, "content_changed");
    };
    
    //Sets the geographic location of the InfoBox. @param {LatLng} latlng
    InfoBox.prototype.setPosition = function (latlng) { 
      this.position_ = latlng;
      if (this.div_) this.draw();
      //This event is fired when the position of the InfoBox changes. @name InfoBox#position_changed;  @event
      google.maps.event.trigger(this, "position_changed");
    };
    
    
    InfoBox.prototype.getContent = function () {  return this.content_; }; //Returns the content of the InfoBox. @returns {string}
    InfoBox.prototype.show = function (){ this.isHidden_ = false; this.div_.style.visibility = "visible"; }; //Shows the InfoBox.
    InfoBox.prototype.hide = function (){ this.isHidden_ = true; this.div_.style.visibility = "hidden"; }; //Hides the InfoBox.
    
    InfoBox.prototype.open = function (map, anchor) {
        if (anchor) this.position_ = anchor.getPosition();
        this.setMap(map);
    };
    
    //Removes the InfoBox from the map.
    InfoBox.prototype.close = function (){
      if (this.closeListener_) {
        google.maps.event.removeListener(this.closeListener_);
        this.closeListener_ = null;
      }
      if (this.contextListener_) {
        google.maps.event.removeListener(this.contextListener_);
        this.contextListener_ = null;
      }
    
      this.setMap(null);
    };
    

    and here’s the sample usage:

    infobox = new InfoBox({ width: "260px" }); // initialize
    infobox.setContent('Loading...');  // set content
    infobox.open(googlemap, marker);   // open on the marker
    infobox.draw(); // to redraw if infobox size changed
    infobox.close();
    

    Here’s the website, where this is used: http://goo.gl/A8g1D

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I need to create a custom, reusable view component. I've been trying to look
I need create custom dialog and put JPanel into it. Is it possible?
Need to create a custom DNS name server using C which will check against
I need to create a custom user interface using extJS/JSP which will allow me
I need to create a custom json for the jit library. Should I use
I need to create a custom component which consist of a drop down box,
I need to create a custom view, which extends RelativeLayout and simply needs to
I need to create a custom constraint annotation which can access the value of
I need to create a custom URI scheme for my project. i.e urn:myprotocol:{p1}:{p2}:{p3}:{p4} -
I need to create a custom application domain to work around a bug in

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.