javascriptgoogle-mapsgoogle-maps-api-3geoxml3

Google Maps API & geoxml 3 - Zoom to placemark on click/Center placemark on map


UPDATED SCRIPT - with click and zoom/center

Still not quite right, first click shows infoWindow put does not zoom/center

// When the window has finished loading create our google map below
    google.maps.event.addDomListener(window, 'load', initialize);

var geoXml = null;
var geoXmlDoc = null;
var map = null;
var myLatLng = null;
var myGeoXml3Zoom = false;
var sidebarHtml = "";
var infowindow = null;
var kmlLayer = null;
var filename = "test.kml.xml";

    function initialize() {
      myLatLng = new google.maps.LatLng(52.60426, 1.72764);
      // these set the initial center and zoom for the map
      // if it is not specified in the query string
      var lat = 52.60426;
      var lng = 1.72764;
      var zoom = 16;

      if (!isNaN(lat) && !isNaN(lng)) {
        myLatLng = new google.maps.LatLng(lat, lng);
      }
                var myOptions = {
                    zoom: zoom,
                    center: myLatLng,
                    streetViewControl: false,
                    mapTypeControl: false,
                    zoomControl: true,
                    // How you would like to style the map.
                    // This is where you would paste any style found on Snazzy Maps.
                    styles: [{"featureType":"all","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.country","elementType":"labels.text","stylers":[{"visibility":"off"}]},{"featureType":"administrative.province","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.locality","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.neighborhood","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.land_parcel","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"landscape.man_made","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"landscape.natural","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"labels","stylers":[{"visibility":"on"}]},{"featureType":"road.arterial","elementType":"labels.text","stylers":[{"visibility":"on"}]},{"featureType":"transit","elementType":"labels","stylers":[{"visibility":"off"}]}]
                    // zoom: 16,
                    // center: myLatlng,
                };
                map = new google.maps.Map(document.getElementById("map"),
                      myOptions);
                infowindow = new google.maps.InfoWindow({});

   geoXml = new geoXML3.parser({
                    map: map,
                    infoWindow: infowindow,
                    singleInfoWindow: true,
                    zoom: myGeoXml3Zoom,
                    afterParse: useTheData
                });
                geoXml.parse(filename);
        };

function kmlClick(pm) {
       if (geoXml.docs[0].placemarks[pm].marker.getMap()) {
          google.maps.event.trigger(geoXml.docs[0].placemarks[pm].marker,"click");
       } else {
          geoXmlDoc.placemarks[pm].marker.setMap(map);
          google.maps.event.trigger(geoXmlDoc.placemarks[pm].marker,"click");
       }

    google.maps.event.addListener(geoXml.docs[0].placemarks[pm].marker, "click", function (e) {
        map.setZoom(19);
        //infoWindow.open(map, marker);

        map.panTo(geoXml.docs[0].placemarks[pm].marker.getPosition());
    });
}

function showAll() {
        map.setZoom(16);
        map.panTo(myLatLng);
}

// == builds the sidebar ==

function makeSidebarEntry(i) {
  var name = geoXmlDoc.placemarks[i].name;
   if (!name  || (name.length == 0)) name = "marker #"+i;
   // alert(name);
   sidebarHtml += '<tr id="row'+i+'"><td><img src='+geoXmlDoc.placemarks[i].style.href+' height="20" alt="icon" /></td><td><a href="javascript:kmlClick('+i+');">'+name+'</a></td></tr>';
}

function makeSidebar() {
  sidebarHtml = '<table><tr></tr>';
  var currentBounds = map.getBounds();
// if bounds not yet available, just use the empty bounds object;
if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
if (geoXmlDoc) {
  for (var i=0; i<geoXmlDoc.placemarks.length; i++) {
    if (geoXmlDoc.placemarks[i].marker) {
      if (currentBounds.contains(geoXmlDoc.placemarks[i].marker.getPosition())) {
         makeSidebarEntry(i);
      }
    }
  }
}
  sidebarHtml += "</table>";
  document.getElementById("sidebar").innerHTML = sidebarHtml;
}

function useTheData(doc){
  var currentBounds = map.getBounds();
  if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
  // Geodata handling goes here, using JSON properties of the doc object
  sidebarHtml = '<table><tr></tr>';
//  var sidebarHtml = '<table>';
  geoXmlDoc = doc[0];
  for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
    // console.log(doc[0].markers[i].title);
    var placemark = geoXmlDoc.placemarks[i];
    if (placemark.marker) {
      if (currentBounds.contains(placemark.marker.getPosition())) {
         makeSidebarEntry(i);
      }
    }

/*    doc[0].markers[i].setVisible(false); */
  }
  sidebarHtml += "</table>";
  document.getElementById("sidebar").innerHTML = sidebarHtml;
};

XML:

<?xml version='1.0' encoding='UTF-8'?>
<kml xmlns='http://www.opengis.net/kml/2.2'>
    <Document>
        <name>Map</name>
        <description></description>
        <Folder>
            <name>Points</name>
            <Placemark>
                <name>Placemark 1</name>
                <description>Description</description>
                <styleUrl>#icon-1239</styleUrl>
                <Point>
                    <coordinates>1.7275818,52.6043317,0.0</coordinates>
                </Point>
            </Placemark>
            <Placemark>
                <name>Placemark 2</name>
                <description>Description</description>
                <styleUrl>#icon-1279</styleUrl>
                <Point>
                    <coordinates>1.73041,52.60436,0.0</coordinates>
                </Point>
            </Placemark>
        </Folder>
        <Style id='icon-1239'>
            <IconStyle>
                <scale>1.1</scale>
                <Icon>
                    <href>http://www.gstatic.com/mapspro/images/stock/1239-poi-civic.png</href>
                </Icon>
            </IconStyle>
        </Style>
        <Style id='icon-1279'>
            <IconStyle>
                <scale>1.1</scale>
                <Icon>
                    <href>http://www.gstatic.com/mapspro/images/stock/1279-poi-library.png</href>
                </Icon>
            </IconStyle>
        </Style>
    </Document>
</kml>

Hi i'm trying to create a custom map using Google Maps API and geoxml3. I have managed to set up the map and add a custom sidebar with a list of placemarks which are loaded from an external KML.xml file.

I want to have it so when you click a placemark from the sidebar, or on the map itself, the map will auto center on the placemark and also zoom in.

Heres the HTML and Script I have so far,

HTML:

<head>
    <title>Test Map</title>
    <link rel="stylesheet" href="css/style.css" type="text/css">
</head>

<body>

    <div class="map">
        <div id="map"></div>
        <div id="side_bar">
            <h3>Locations</h3>
            <div id="sidebar"></div>
            <p>*Click to show location on map</p>
        </div>
    </div>

    <!-- Scripts -->
    <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAWj4S3HGnCZ2ZzlRg4bfb4Z7HcpJ82tl8&"></script>
    <script src="js/map.js"></script>
    <script src="js/geoxml3.js"></script>
    <!-- jQuery -->
    <script src="js/jquery.js"></script>

</body>

Script:

// When the window has finished loading create our google map below
    google.maps.event.addDomListener(window, 'load', initialize);

var geoXml = null;
var geoXmlDoc = null;
var map = null;
var myLatLng = null;
var myGeoXml3Zoom = false;
var sidebarHtml = "";
var infowindow = null;
var kmlLayer = null;
var filename = "test.kml.xml";

    function initialize() {
      myLatLng = new google.maps.LatLng(52.60426, 1.72764);
      // these set the initial center and zoom for the map
      // if it is not specified in the query string
      var lat = 52.60426;
      var lng = 1.72764;
      var zoom = 16;

      if (!isNaN(lat) && !isNaN(lng)) {
        myLatLng = new google.maps.LatLng(lat, lng);
      }
                var myOptions = {
                    zoom: zoom,
                    center: myLatLng,
                    streetViewControl: false,
                    mapTypeControl: false,
                    zoomControl: true,
                    // How you would like to style the map.
                    // This is where you would paste any style found on Snazzy Maps.
                    styles: [{"featureType":"all","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.country","elementType":"labels.text","stylers":[{"visibility":"off"}]},{"featureType":"administrative.province","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.locality","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.neighborhood","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"administrative.land_parcel","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"landscape.man_made","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"landscape.natural","elementType":"labels","stylers":[{"visibility":"off"}]},{"featureType":"road","elementType":"labels","stylers":[{"visibility":"on"}]},{"featureType":"road.arterial","elementType":"labels.text","stylers":[{"visibility":"on"}]},{"featureType":"transit","elementType":"labels","stylers":[{"visibility":"off"}]}]
                    // zoom: 16,
                    // center: myLatlng,
                };
                map = new google.maps.Map(document.getElementById("map"),
                      myOptions);
                infowindow = new google.maps.InfoWindow({});

   geoXml = new geoXML3.parser({
                    map: map,
                    infoWindow: infowindow,
                    singleInfoWindow: true,
                    zoom: myGeoXml3Zoom,
                    afterParse: useTheData
                });
                geoXml.parse(filename);
        };

function kmlClick(pm) {
   if (geoXml.docs[0].placemarks[pm].marker.getMap()) {
      google.maps.event.trigger(geoXml.docs[0].placemarks[pm].marker,"click");
   } else {
      geoXmlDoc.placemarks[pm].marker.setMap(map);
      google.maps.event.trigger(geoXmlDoc.placemarks[pm].marker,"click");
   }
}

// == builds the sidebar ==

function makeSidebarEntry(i) {
  var name = geoXmlDoc.placemarks[i].name;
   if (!name  || (name.length == 0)) name = "marker #"+i;
   // alert(name);
   sidebarHtml += '<tr id="row'+i+'"><td><img src='+geoXmlDoc.placemarks[i].style.href+' height="20" alt="icon" /></td><td><a href="javascript:kmlClick('+i+');">'+name+'</a></td></tr>';
}

function makeSidebar() {
  sidebarHtml = '<table><tr></tr>';
  var currentBounds = map.getBounds();
// if bounds not yet available, just use the empty bounds object;
if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
if (geoXmlDoc) {
  for (var i=0; i<geoXmlDoc.placemarks.length; i++) {
    if (geoXmlDoc.placemarks[i].marker) {
      if (currentBounds.contains(geoXmlDoc.placemarks[i].marker.getPosition())) {
         makeSidebarEntry(i);
      }
    }
  }
}
  sidebarHtml += "</table>";
  document.getElementById("sidebar").innerHTML = sidebarHtml;
}

function useTheData(doc){
  var currentBounds = map.getBounds();
  if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
  // Geodata handling goes here, using JSON properties of the doc object
  sidebarHtml = '<table><tr></tr>';
//  var sidebarHtml = '<table>';
  geoXmlDoc = doc[0];
  for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
    // console.log(doc[0].markers[i].title);
    var placemark = geoXmlDoc.placemarks[i];
    if (placemark.marker) {
      if (currentBounds.contains(placemark.marker.getPosition())) {
         makeSidebarEntry(i);
      }
    }

/*    doc[0].markers[i].setVisible(false); */
  }
  sidebarHtml += "</table>";
  document.getElementById("sidebar").innerHTML = sidebarHtml;
};

Any help would be greatly appreciated.


Solution

  • To center the map on a marker clicked on the sidebar, add code to do that to the function that is called (kmlClick):

    function kmlClick(pm) {
      // center the map on the marker and change the zoom to 18
      if (geoXml.docs[0].placemarks[pm].marker.getPosition){
         map.setCenter(geoXml.docs[0].placemarks[pm].marker.getPosition());
         map.setZoom(19);
      }
         
      if (geoXml.docs[0].placemarks[pm].marker.getMap()) {
        // if map is not null (marker is on the map), trigger a click on it
         google.maps.event.trigger(geoXml.docs[0].placemarks[pm].marker,"click");
      } else {
        // if map is null (marker is not on the map), add it to the map,
        // then trigger a click on it
        geoXmlDoc.placemarks[pm].marker.setMap(map);
        google.maps.event.trigger(geoXmlDoc.placemarks[pm].marker,"click");
      }
    }
    

    If you want it to center and zoom when the marker is clicked or the click is triggered from the sidebar, put that functionality in the marker click listener. One way to do that would be to add a marker click listener to the markers in useTheData:

    function useTheData(doc){
      var currentBounds = map.getBounds();
      if (!currentBounds) currentBounds=new google.maps.LatLngBounds();
      sidebarHtml = '<table><tr></tr>';
      geoXmlDoc = doc[0];
      for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
        var placemark = geoXmlDoc.placemarks[i];
        if (placemark.marker) {
          google.maps.event.addListener(placemark.marker,'click',function(evt) {
            this.getMap().setCenter(this.getPosition());
            this.getMap().setZoom(19);
          });
          if (currentBounds.contains(placemark.marker.getPosition())) {
             makeSidebarEntry(i);
          }
        }
      }
      sidebarHtml += "</table>";
      document.getElementById("sidebar").innerHTML = sidebarHtml;
    };
    

    proof of concept

    code snippet:

    google.maps.event.addDomListener(window, 'load', initialize);
    
    var geoXml = null;
    var geoXmlDoc = null;
    var map = null;
    var myLatLng = null;
    var myGeoXml3Zoom = false;
    var sidebarHtml = "";
    var infowindow = null;
    var kmlLayer = null;
    var filename = "kml/SO_20160415_placemarks.kml";
    
    function initialize() {
      myLatLng = new google.maps.LatLng(52.60426, 1.72764);
      var lat = 52.60426;
      var lng = 1.72764;
      var zoom = 16;
    
      if (!isNaN(lat) && !isNaN(lng)) {
        myLatLng = new google.maps.LatLng(lat, lng);
      }
      var myOptions = {
        zoom: zoom,
        center: myLatLng,
        streetViewControl: false,
        mapTypeControl: false,
        zoomControl: true
      };
      map = new google.maps.Map(document.getElementById("map"),
        myOptions);
      infowindow = new google.maps.InfoWindow({});
    
      geoXml = new geoXML3.parser({
        map: map,
        infoWindow: infowindow,
        singleInfoWindow: true,
        zoom: myGeoXml3Zoom,
        afterParse: useTheData
      });
      geoXml.parseKmlString(kmlStr);
      google.maps.event.addListener(map, "bounds_changed", makeSidebar);
      google.maps.event.addListener(map, "center_changed", makeSidebar);
      google.maps.event.addListener(map, "zoom_changed", makeSidebar);
      google.maps.event.addListenerOnce(map, "idle", makeSidebar);
    };
    
    function kmlClick(pm) {
      if (geoXml.docs[0].placemarks[pm].marker.getMap()) {
        google.maps.event.trigger(geoXml.docs[0].placemarks[pm].marker, "click");
      } else {
        geoXmlDoc.placemarks[pm].marker.setMap(map);
        google.maps.event.trigger(geoXmlDoc.placemarks[pm].marker, "click");
      }
    }
    
    function showAll() {
      map.setZoom(16);
      map.panTo(myLatLng);
    }
    
    // == builds the sidebar ==
    function makeSidebarEntry(i) {
      var name = geoXmlDoc.placemarks[i].name;
      if (!name || (name.length == 0)) name = "marker #" + i;
      sidebarHtml += '<tr id="row' + i + '"><td><img src=' + geoXmlDoc.placemarks[i].style.href + ' height="20" alt="icon" /></td><td><a href="javascript:kmlClick(' + i + ');">' + name + '</a></td></tr>';
    }
    
    function makeSidebar() {
      sidebarHtml = '<table><tr></tr>';
      var currentBounds = map.getBounds();
      // if bounds not yet available, just use the empty bounds object;
      if (!currentBounds) currentBounds = new google.maps.LatLngBounds();
      if (geoXmlDoc) {
        for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
          if (geoXmlDoc.placemarks[i].marker) {
            if (currentBounds.contains(geoXmlDoc.placemarks[i].marker.getPosition())) {
              makeSidebarEntry(i);
            }
          }
        }
      }
      sidebarHtml += "</table>";
      document.getElementById("sidebar").innerHTML = sidebarHtml;
    }
    
    function useTheData(doc) {
      var currentBounds = map.getBounds();
      if (!currentBounds) currentBounds = new google.maps.LatLngBounds();
      sidebarHtml = '<table><tr></tr>';
      geoXmlDoc = doc[0];
      for (var i = 0; i < geoXmlDoc.placemarks.length; i++) {
        var placemark = geoXmlDoc.placemarks[i];
        if (placemark.marker) {
          google.maps.event.addListener(placemark.marker, 'click', function(evt) {
            this.getMap().setCenter(this.getPosition());
            this.getMap().setZoom(19);
          });
    
          if (currentBounds.contains(placemark.marker.getPosition())) {
            makeSidebarEntry(i);
          }
        }
      }
      sidebarHtml += "</table>";
      document.getElementById("sidebar").innerHTML = sidebarHtml;
    };
    
    var kmlStr = "<?xml version='1.0' encoding='UTF-8'?><kml xmlns='http://www.opengis.net/kml/2.2'><Document><name>Map</name><description></description><Folder><name>Points</name><Placemark><name>Placemark 1</name><description>Description</description><styleUrl>#icon-1239</styleUrl><Point><coordinates>1.7275818,52.6043317,0.0</coordinates></Point></Placemark><Placemark><name>Placemark 2</name><description>Description</description><styleUrl>#icon-1279</styleUrl><Point><coordinates>1.73041,52.60436,0.0</coordinates></Point></Placemark></Folder><Style id='icon-1239'><IconStyle><scale>1.1</scale><Icon><href>http://www.gstatic.com/mapspro/images/stock/1239-poi-civic.png</href></Icon></IconStyle></Style><Style id='icon-1279'><IconStyle><scale>1.1</scale><Icon><href>http://www.gstatic.com/mapspro/images/stock/1279-poi-library.png</href></Icon></IconStyle></Style></Document></kml>";
    html,
    body,
    #map,
    .map {
      width: 100%;
      height: 100%;
      margin: 0;
      padding: 0;
    }
    <script src="https://rawgit.com/geocodezip/geoxml3/master/polys/geoxml3.js"></script>
    <script src="https://maps.google.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
    <div class="map">
      <div id="side_bar">
        <h3>Locations</h3>
        <div id="sidebar"></div>
        <p>*Click to show location on map</p>
      </div>
      <div id="map"></div>
    </div>