CSS Google Maps Custom InfoWindow - PullRequest
       1

CSS Google Maps Custom InfoWindow

6 голосов
/ 05 мая 2011

Я использую код из http://gmaps -samples-v3.googlecode.com / svn / trunk / infowindow_custom / infowindow-custom.html , который в настоящее время является лучшим примером Google для созданияпользовательские InfoWindow в Maps API v3.Я работал над этим, и до сих пор он близок к работе, за исключением одной вещи: контейнер div, в котором текстовое содержимое не будет расширяться, чтобы соответствовать содержимому, поэтому он просто падает вместо расширения пузыря.если я назначу контейнеру контента фиксированную ширину в пикселях, он будет работать нормально, но я не смогу расширить его в зависимости от объема текста в нем.

Я застрял на нем некоторое время.Любая помощь будет принята с благодарностью!

Вот HTML-страница

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title>Gayborhood Map Test</title>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
  html { height: 100% }
  body { height: 100%; margin: 0px; padding: 0px }
  #map_canvas { width: 900px;
    height: 400px;
    margin: 200px auto 0 auto; }
</style>
<link rel="stylesheet" type="text/css" href="map.css" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script>
<script type="text/javascript" src="InfoBox.js"></script>
<script type="text/javascript">
  function initialize() {
    var latlng = new google.maps.LatLng(39.947137,-75.161824);
    var myOptions = {
      zoom: 16,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.HYBRID
    };

    var gayborhood;

    var map = new google.maps.Map(document.getElementById("map_canvas"),
        myOptions);

    var gayborhoodcoords = [
       new google.maps.LatLng(39.9492017, -75.1631272),
       new google.maps.LatLng(39.945423, -75.1639561),
       new google.maps.LatLng(39.9450064, -75.160579),
       new google.maps.LatLng(39.9487765, -75.1597468),
       new google.maps.LatLng(39.9492017, -75.1631272)
    ];

    gayborhood = new google.maps.Polygon({
       paths: gayborhoodcoords,
       strokeColor: "#00ff00",
       strokeOpacity: 0.8,
       strokeWeight: 2,
       fillColor: "#00ff00",
       fillOpacity: 0.35
    });

    gayborhood.setMap(map);

    var image = 'red_icon.png';
    var myLatLng = new google.maps.LatLng(39.948883,-75.162246);
    var redMarker = new google.maps.Marker({
      position: myLatLng,
      map: map,
      icon: image
    });

   var contentString = '<h4>Woody\'s Bar</h4>';

   /*var infowindow = new google.maps.InfoWindow({
    content: contentString,
    disableAutoPan: true
   });*/

   google.maps.event.addListener(redMarker, 'mouseover', function() {
      var infoBox = new InfoBox({marker: redMarker, map: map});
   });
   /*google.maps.event.addListener(redMarker, 'mouseout', function() {
      infowindow.close();
   });*/
  }

</script>
</head>
<body onload="initialize()">
  <div id="map_canvas"></div>
</body>
</html>

Вот InfoBox.js:

    /* An InfoBox is like an info window, but it displays
 * under the marker, opens quicker, and has flexible styling.
 * @param {GLatLng} latlng Point to place bar at
 * @param {Map} map The map on which to display this InfoBox.
 * @param {Object} opts Passes configuration options - content,
 *   offsetVertical, offsetHorizontal, className, height, width
 */
function InfoBox(opts) {
  google.maps.OverlayView.call(this);
  this.marker_ = opts.marker
  this.latlng_ = opts.marker.getPosition();
  this.map_ = opts.map;
  this.offsetVertical_ = -65;
  this.offsetHorizontal_ = -20;
  this.height_ = 50;
  //this.width_ = 159;

  var me = this;
  this.boundsChangedListener_ =
    google.maps.event.addListener(this.map_, "bounds_changed", function() {
      return me.panMap.apply(me);
    });

  // Once the properties of this OverlayView are initialized, set its map so
  // that we can display it.  This will trigger calls to panes_changed and
  // draw.
  this.setMap(this.map_);
}

/* InfoBox extends GOverlay class from the Google Maps API
 */
InfoBox.prototype = new google.maps.OverlayView();

/* Creates the DIV representing this InfoBox
 */
InfoBox.prototype.remove = function() {
  if (this.div_) {
    this.div_.parentNode.removeChild(this.div_);
    this.div_ = null;
  }
};

/* Redraw the Bar based on the current projection and zoom level
 */
InfoBox.prototype.draw = function() {
  // Creates the element if it doesn't exist already.
  this.createElement();
  if (!this.div_) return;

  // Calculate the DIV coordinates of two opposite corners of our bounds to
  // get the size and position of our Bar
  var pixPosition = this.getProjection().fromLatLngToDivPixel(this.latlng_);
  if (!pixPosition) return;

  // Now position our DIV based on the DIV coordinates of our bounds
  //this.div_.style.width = this.width_ + "px";
  this.div_.style.left = (pixPosition.x + this.offsetHorizontal_) + "px";
  this.div_.style.height = this.height_ + "px";
  this.div_.style.top = (pixPosition.y + this.offsetVertical_) + "px";
  this.div_.style.display = 'block';
};

/* Creates the DIV representing this InfoBox in the floatPane.  If the panes
 * object, retrieved by calling getPanes, is null, remove the element from the
 * DOM.  If the div exists, but its parent is not the floatPane, move the div
 * to the new pane.
 * Called from within draw.  Alternatively, this can be called specifically on
 * a panes_changed event.
 */
InfoBox.prototype.createElement = function() {
  var panes = this.getPanes();
  var div = this.div_;
  if (!div) {
    // This does not handle changing panes.  You can set the map to be null and
    // then reset the map to move the div.
    div = this.div_ = document.createElement("div");
    div.className = "infobox";
    //div.style.width = this.width_ + "px";
    //div.style.height = this.height_ + "px";
    var leftDiv = document.createElement("div");
    leftDiv.className = "bubbleLeftDiv";
    var containerDiv = document.createElement("div");
    containerDiv.className = "infoboxContainer";
    var contentDiv = document.createElement("div");
    contentDiv.className = "infoboxContent";

    var title = "Much longer title than woody's"

    //var infoboxWidth = ( title.length*10 - (title.length) - 40) + "px"
    //containerDiv.style.width = infoboxWidth;
    //this.width_ = infoboxWidth + 47;
    contentDiv.innerHTML = "<h3>" + title + "</h3>";
    var rightDiv = document.createElement("div");
    rightDiv.className = "bubbleRightDiv";

    function removeInfoBox(ib) {
      return function() {
        ib.setMap(null);
      };
    }

    google.maps.event.addListener(this.marker_, 'mouseout', removeInfoBox(this));

    div.appendChild(leftDiv)
    div.appendChild(containerDiv);
    containerDiv.appendChild(contentDiv);
    div.appendChild(rightDiv);
    div.style.display = 'none';
    panes.floatPane.appendChild(div);
    this.panMap();
  } else if (div.parentNode != panes.floatPane) {
    // The panes have changed.  Move the div.
    div.parentNode.removeChild(div);
    panes.floatPane.appendChild(div);
  } else {
    // The panes have not changed, so no need to create or move the div.
  }
}

/* Pan the map to fit the InfoBox.
 */
InfoBox.prototype.panMap = function() {
  // if we go beyond map, pan map
  var map = this.map_;
  var bounds = map.getBounds();
  if (!bounds) return;

  // The position of the infowindow
  var position = this.latlng_;

  // The dimension of the infowindow
  var iwWidth = this.width_;
  var iwHeight = this.height_;

  // The offset position of the infowindow
  var iwOffsetX = this.offsetHorizontal_;
  var iwOffsetY = this.offsetVertical_;

  // Padding on the infowindow
  var padX = 40;
  var padY = 40;

  // 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 infowindow
  var iwWestLng = position.lng() + (iwOffsetX - padX) * degPixelX;
  var iwEastLng = position.lng() + (iwOffsetX + iwWidth + padX) * degPixelX;
  var iwNorthLat = position.lat() - (iwOffsetY - padY) * degPixelY;
  var iwSouthLat = position.lat() - (iwOffsetY + iwHeight + padY) * 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);

  // The center of the map
  var center = map.getCenter();

  // The new map center
  var centerX = center.lng() - shiftLng;
  var centerY = center.lat() - shiftLat;

  // center the map to the new shifted center
  map.setCenter(new google.maps.LatLng(centerY, centerX));

  // Remove the listener after panning is complete.
  google.maps.event.removeListener(this.boundsChangedListener_);
  this.boundsChangedListener_ = null;
};

А вот CSS:

    .infobox {
    border: 0px none;
    position: absolute;
    width: auto;
    height: auto;
}

.infoboxContent {
    font-family: arial, helvetica, sans-serif;
    font-size: 15px;
    padding: 0px;
    margin: 9px 0px 0px -24px;
    position: absolute;
    z-index: 105;
}

.infoboxContainer {
    background: url('infowindow_bg.png') repeat-x;
    height: 50px;
    margin-left: 47px;
}

.bubbleLeftDiv {
    width: 47px;
    height: 50px;
    background: url('infowindow_left.png') no-repeat;
    position: absolute;
    z-index: 102;
}

.bubbleRightDiv {
    width: 26px;
    height: 50px;
    background: url('infowindow_right.png') no-repeat;
    position: absolute;
    right: -26px;
    top: 0px;
}

.clear { clear: both; }

Спасибо !!

Ответы [ 2 ]

3 голосов
/ 05 июня 2011

Я столкнулся с той же проблемой.Подход, который работал для меня, состоял в том, чтобы динамически определять размеры содержимого и правильно устанавливать высоту и ширину InfoBox.Проблема, с которой я столкнулся, заключалась в том, что перед вставкой содержимого в DOM оно не имеет (правильных) значений измерений.В результате мой подход был следующим:

  1. Создайте элемент содержимого DOM, который нужно вставить
  2. Вставьте его в временный контейнер
  3. Получите измерения температурыcontainer
  4. Удалить временный контейнер
  5. Вставить содержимое в InfoBox и установить его высоту и ширину на основе размеров временного контейнера

Вот пример, сделанный с помощью инфраструктуры jQuery:

    var temp = $("<div class='temp'></div>").html(content).hide().appendTo("body");
    var dimentions = {
        width : temp.outerWidth(true),
        height : temp.outerHeight(true)
    };
    temp.remove();

    var overlayProjection = this.getProjection();
    var top_left = overlayProjection.fromLatLngToDivPixel(this.point_);        

    var dimensions= $.extend({}, dimensions, {
        y : top_left.y - dimensions.height,
        x : top_left.x - dimensions.width/2
    });

    var div = this.div_;
    $(div).css({
        "top": dimensions.y + 'px',
        "left" : dimensions.x + 'px',
        "width" : dimensions.width + 'px',
        "height" : dimensions.height + 'px'
    }).html(content);

Надеюсь, это поможет!

0 голосов
/ 05 июня 2013

Вы можете переопределить метод рисования инфобокса и переместить инфобокс после его рендеринга:

var infobox = new InfoBox(myOptions);
infobox.initReady = false;
var oldDraw = infobox.draw;
infobox.draw = function() {
  oldDraw.apply(this);
  if( ! infobox.initReady) {

    // Calculate the required offset
    var offsetY = -($(infobox.div_).outerHeight());
    var offsetX = -110;
    infobox.initReady = true;

    // Set the new pixelOffset
    infobox.setOptions({
        pixelOffset: new google.maps.Size(offsetX, offsetY)
   });
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...