Jakub Jakub - 7 months ago 11
Javascript Question

Assign individual infowindows to individual markers, call content from div

I'm working on a custom Google map. I have multiple markers with custom infowindows (everything working, wrapped in divs and styled). I've managed to assign links in a sidebar menu to the markers, so that an infowindow opens, when a menu item is clicked. The problem is, that it is always the same infowindow. I've probably gone through every question and answer on this subject, but I just can't get this to work...

The code for the map, markers, infowindows is:

var map;
var markers = [];
var content = [];
var map = new google.maps.LatLng(46.2171749, 7.5984075);

var MY_MAPTYPE_ID = 'custom_style';
function initialize() {

var featureOpts = [
{
"featureType": "landscape.natural.landcover",
"elementType": "geometry.fill",
"stylers": [
{ "visibility": "on" },
{ "color": "#f2f9f4" }
]
}, // and so on with the styling

var mapOptions = {
zoom: 10,
center: map,
mapTypeControl: false,
mapTypeControlOptions: {
mapTypeIds: [google.maps.MapTypeId.ROADMAP, MY_MAPTYPE_ID]
},
mapTypeId: MY_MAPTYPE_ID
};

map = new google.maps.Map(document.getElementById('map-canvas'),
mapOptions);

var styledMapOptions = {
name: 'Custom Style'
};

var customMapType = new google.maps.StyledMapType(featureOpts,styledMapOptions);

map.mapTypes.set(MY_MAPTYPE_ID, customMapType);

var locations = [
['Location 1', 46.096678, 7.2281081, 'pin.png', 1],
['Location 2', 46.0230159, 7.7428676, 'pin.png', 2],
['Location 3', 46.1125509, 7.919948, 'pin.png', 3],
];

var infobox = new InfoBox({
content: document.getElementById("infobox"),
disableAutoPan: false,
maxWidth: 800,
pixelOffset: new google.maps.Size(-400, 10),
zIndex: null,
closeBoxMargin: "12px 12px 2px 2px",
closeBoxURL: "icon-close.png",
infoBoxClearance: new google.maps.Size(0, 0),
});

var marker, i;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map,
icon: locations[i][3]
});

markers.push(marker);

google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infobox.open(map, marker);
/* infowindow.setContent(locations[i][0]); //enabling this line disables correct map panning!! */
map.panTo(marker.getPosition(0, 427));
map.panBy(0, 400);
}
})(marker, i));
}
}

function myClick(id){
google.maps.event.trigger(markers[id], 'click');
}

google.maps.event.addDomListener(window, 'load', initialize);


The content for the infowindows is in the html, like so:

<div id="Location 1">
<div id="infobox_wrapper">
<div id="infobox">
<div id="infobox_title_wrapper">
<div id="info_icon">
<img src="green_s.png"/>
</div>
<div id="info_title"><p>##</p>
</div>
<div id="info_place"><p>##</p>
</div>
</div>
<iframe width="800" height="450" src="##" frameborder="0" allowfullscreen></iframe>
<p class= "txt">##</p>
</div>
</div>
</div>


Does anyone have a solution for getting this to work? Is there any simple way of calling the infowindow content for each marker e.g. from the var locations = [] array, meaning that when a location is added, and a div or other id is specified there, the marker, along with the corresponding infowindow is placed on the map? Also, a side issue, the line infowindow.setContent(locations[i][0]); disables the correct panning of the map to the markers...
Thanks

Answer

You need to have:

  1. unique ids for any html elements
  2. content for all the different markers in the DOM
  3. you can't call .setContent on infowindow unless you have defined it (I suspect that should be infobox)
  4. you need to clone the node when it is displayed or it gets destroyed when the infobox is closed.

proof of concept fiddle

code snippet:

var map;
var markers = [];
var content = [];
var map = new google.maps.LatLng(46.2171749, 7.5984075);
var bounds = new google.maps.LatLngBounds();

function initialize() {

  var mapOptions = {
    zoom: 10,
    center: map
  };

  map = new google.maps.Map(document.getElementById('map-canvas'),
    mapOptions);

  var locations = [
    ['Location1', 46.096678, 7.2281081, 'pin.png', 1],
    ['Location2', 46.0230159, 7.7428676, 'pin.png', 2],
    ['Location3', 46.1125509, 7.919948, 'pin.png', 3],
  ];

  var infobox = new InfoBox({
    content: document.getElementById("infobox"),
    disableAutoPan: false,
    maxWidth: 800,
    pixelOffset: new google.maps.Size(-400, 10),
    zIndex: null,
    closeBoxMargin: "12px 12px 2px 2px",
    closeBoxURL: "http://www.google.com/intl/en_us/mapfiles/close.gif",
    infoBoxClearance: new google.maps.Size(0, 0),
  });

  var marker, i;
  for (i = 0; i < locations.length; i++) {
    marker = new google.maps.Marker({
      position: new google.maps.LatLng(locations[i][1], locations[i][2]),
      map: map,
      // icon: locations[i][3]
    });

    markers.push(marker);

    google.maps.event.addListener(marker, 'click', (function(marker, i) {
      return function() {
        infobox.open(map, marker);
        infobox.setContent(document.getElementById(locations[i][0]).cloneNode(true));
        map.panTo(marker.getPosition(0, 427));
        map.panBy(0, 400);
      }
    })(marker, i));
    bounds.extend(marker.getPosition());
  }
  map.fitBounds(bounds);
}

function myClick(id) {
  google.maps.event.trigger(markers[id], 'click');
}

google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
  height: 100%;
  width: 100%;
  margin: 0px;
  padding: 0px
}
.infowindow {
  border: 1px solid black;
  margin-top: 8px;
  background: white;
  padding: 5px;
}
<script src="https://maps.googleapis.com/maps/api/js"></script>
<script src="https://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox.js"></script>
<div id="map-canvas"></div>
<div id="Location1">
  <div class="infobox_wrapper">
    <div class="infowindow">
      <div class="infobox_title_wrapper">
        <div class="info_icon">
          <img src="https://www.google.com/drive/images/drive/logo-drive.png" height="20" />
        </div>
        <div class="info_title">
          <p>##</p>
        </div>
        <div class="info_place">
          <p>##</p>
        </div>
      </div>
      <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d193571.43828905202!2d-74.11808638273646!3d40.7058253631455!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x89c24fa5d33f083b%3A0xc80b8f06e177fe62!2sNew+York%2C+NY!5e0!3m2!1sen!2sus!4v1461436300347"
      width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
      <p class="txt">##</p>
    </div>
  </div>
</div>

<div id="Location2">
  <div class="infobox_wrapper">
    <div class="infowindow">
      <div class="infobox_title_wrapper">
        <div class="info_icon">
          <img src="https://www.google.com/drive/images/drive/logo-drive.png" height="20" />
        </div>
        <div class="info_title">
          <p>##</p>
        </div>
        <div class="info_place">
          <p>##</p>
        </div>
      </div>
      <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d88704.87577364442!2d7.671905434077621!3d45.990682827318246!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x478f35a2292ee5cd%3A0x400ff8840196f70!2s3920+Zermatt%2C+Switzerland!5e0!3m2!1sen!2sus!4v1461437058426"
      width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
      <p class="txt">##</p>
    </div>
  </div>
</div>

<div id="Location3">
  <div class="infobox_wrapper">
    <div class="infowindow">
      <div class="infobox_title_wrapper">
        <div class="info_icon">
          <img src="https://www.google.com/drive/images/drive/logo-drive.png" height="20" />
        </div>
        <div class="info_title">
          <p>##</p>
        </div>
        <div class="info_place">
          <p>##</p>
        </div>
      </div>
      <iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d44233.88369647231!2d7.936860760323751!3d46.13844402760392!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x478f45103f606a5d%3A0xb47592074f679662!2s3910+Saas-Grund%2C+Switzerland!5e0!3m2!1sen!2sus!4v1461437405679"
      width="600" height="450" frameborder="0" style="border:0" allowfullscreen></iframe>
      <p class="txt">##</p>
    </div>
  </div>
</div>