3
votes

I have a kml file that loads fine in google maps. On the same page I have a text box where the user can enter their location which will add a marker, this works as well.

Where I'm having trouble is if the user enters a location outside the bounds of the kml file, the map won't zoom to include both the kml and the new marker.

If I have preserveViewport=false, it will zoom to fit the kml. If it's true, it will zoom to fit the new marker.

$(document).ready(function () {
  var mapOptions = {
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  var ctaLayer = new google.maps.KmlLayer('KMLLOCATION', { preserveViewport: false });
  ctaLayer.setMap(map);

  var marker = new google.maps.Marker({ position: new google.maps.LatLng(LAT, LONG), map: map, title: 'You are here', clickable: false, icon: '/media/youarehere.png' });

  var bounds = new google.maps.LatLngBounds();
  var ll = new google.maps.LatLng(LAT, LONG);
  bounds.extend(ll);
  map.fitBounds(bounds);
});

EDIT

Thanks to geocodezip for pointing me in the right direction. This is my updated code that works.

$(document).ready(function () {
  var mapOptions = {
    mapTypeId: google.maps.MapTypeId.ROADMAP
  };

  var map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  var layer = new google.maps.KmlLayer('KMLLOCATION', { map: map, preserveViewport: true });

  var marker = new google.maps.Marker({ position: new google.maps.LatLng(LAT, LONG), map: map, title: 'You are here', clickable: false, icon: '/media/youarehere.png' });

  google.maps.event.addListener(layer, 'defaultviewport_changed', function() {
    var bounds = layer.getDefaultViewport();
    var ll = new google.maps.LatLng(LAT, LONG);
    bounds.extend(ll);
    map.fitBounds(bounds);
  });
});
3

3 Answers

2
votes

You need to get the bounds to the kml (getDefaultViewport() on the KmlLayer), extend that with the additional marker then call fitBounds using the "extended" bounds object (with preservViewport set to true so the map doesn't zoom to the default viewport of the KmlLayer).

2
votes

To add to this, if you include multiple kml and want to zoom all the kml, this worked for me.

var bounds = null;
google.maps.event.addListener(layer, 'defaultviewport_changed', function () {
  if (bounds == null)
      bounds = layer.getDefaultViewport();
  else
      bounds.union(layer.getDefaultViewport());

      map.fitBounds(bounds);

});
0
votes

After much trial and error here's what I came up with. You'll need to include the charts loader https://www.gstatic.com/charts/loader.js and geoxml3 https://github.com/geocodezip/geoxml3/blob/master/kmz/geoxml3.js. This map looks at a country-code sorted fusiontable with geometry representing the countries boundaries then paints the boundaries to the map and zooms in on them. If you want to add another marker to it just use bounds.extend(someLatLngClassInstanceOrLiteral)

google.charts.load('current', {
   'packages': ['table']
});
google.charts.setOnLoadCallback(zoomMap);

function zoomMap(){

    var map = new google.maps.Map(document.querySelectorAll('.single-map-selector')[0], {
        center: new google.maps.LatLng(30, 0),
        zoom: 2,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        disableDefaultUI: true,
        scrollwheel: false,
        draggable: false,
    });

    var CountriesServed = ['US', 'CA', 'AU'];

    var jointCountriesArray = CountriesServed.map(function(val, index){
        if( index < CountriesServed.length - 1 ){
            return '\'' + val + '\', ';
        }
        else{
            return '\'' + val + '\'';
        }
    });
    jointCountriesArray = jointCountriesArray.join('');

    var world_geometry = new google.maps.FusionTablesLayer({
        query: {
            select: 'geometry',
            from: '1N2LBk4JHwWpOY4d9fobIn27lfnZ5MDy-NoqqRpk',
            where: "ISO_2DIGIT IN (" + jointCountriesArray + ")",
        },
        heatmap: {
            enabled: false
        },
        suppressInfoWindows: true,
        map: map,
        options: {
            styleId: 2,
            templateId: 2
        },
    });

    var queryText = encodeURIComponent("select geometry from 1N2LBk4JHwWpOY4d9fobIn27lfnZ5MDy-NoqqRpk where 'ISO_2DIGIT' in (" + jointCountriesArray + ")");

    var query = new google.visualization.Query('http://www.google.com/fusiontables/gvizdata?tq=' + queryText);

    query.send(handleQuery);

    function handleQuery(response){
        if (!response) {
            console.log('no response');
            return;
        }
        if (response.isError()) {
            console.log('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
            return;
        } 
        FTresponse = response;

        numRows = FTresponse.getDataTable().getNumberOfRows();

        var coordinates = [];
        var bounds = new google.maps.LatLngBounds();

        for(var i = 0; i < numRows; i++) {

            var kml = FTresponse.getDataTable().getValue(i,0);

            var coordEls = geoXML3.xmlParse(kml).querySelectorAll('coordinates');
            var coordinateString = '';

            for(var j = 0; j < coordEls.length; j++){
                coordinateString += coordEls[j].innerHTML + ' ';
            }

            var unpairedCoordinates = coordinateString.split(',').map(function(val,index, arr){
                if( val == '0.0' ){
                    arr.splice(index,1);
                }
                else{
                    return val.replace('0.0 ', '');
                }
            });
            for(var k = 0; k < unpairedCoordinates.length; k++){
                if( (k == 0 || k % 2 == 0) && k < unpairedCoordinates.length - 2 ){
                    // is even or zero and we're not at the end of the array
                    // in the coordinates element the latlngs are flipped
                    bounds.extend({
                        lat : parseFloat(unpairedCoordinates[k+1]),
                        lng : parseFloat(unpairedCoordinates[k])
                    });
                }
            }

        }

        map.fitBounds(bounds, -300);
        map.setCenter(bounds.getCenter());

        //// uncomment if you want to see the rectangle of the bounds
        // var rect = new google.maps.Rectangle({
        //  strokeColor: '#FFFFFF',
        //  strokeOpacity: 0.8,
        //  strokeWeight: 2,
        //  fillColor: '#FFFFFF',
        //  fillOpacity: 0.35,
        //  map: map,
        //  bounds: bounds
        // });
    }
}