Loading a local .kml file using google maps?
Asked Answered
F

4

58

I created a hello world program to load a local kml file (borrowed from google's docs):

var ctaLayer = new google.maps.KmlLayer("http://localhost:8080/kml/cta.kml");

This does not work (nothing gets loaded).

However, when I change that line to:

  var ctaLayer = new google.maps.KmlLayer("http://gmaps-samples.googlecode.com/svn/trunk/ggeoxml/cta.kml");

it loads properly. Both kml files are identical. What do I need to do to get it to load when serving it myself? (I tried both absolute and relative paths, and I know the paths I am using are correct...)

Also I added the correct mime type to my appserver's config file:

<mime-mapping>
    <extension>kml</extension>
<mime-type>application/vnd.google-earth.kml+xml</mime-type>
</mime-mapping>
<mime-mapping>
    <extension>kmz</extension>
    <mime-type>application/vnd.google-earth.kmz</mime-type>
</mime-mapping>

But it still doesn't load.

I found this in google's docs:

The Google Maps API supports the KML and GeoRSS data formats for displaying geographic information. These data formats are displayed on a map using a KmlLayer object, whose constructor takes the URL of a publicly accessible KML or GeoRSS file.

So I guess what I am trying to do is not possible without serving the kml from a publicly accessible url...unless someone can prove otherwise

Forsooth answered 18/8, 2010 at 17:22 Comment(1)
what happens when you visit the local KML URL in the browser?Signorelli
C
62

The KML can't be accessed since it's on your local machine and google can't access that since it doesn't know how to get to localhost:8080

Chavarria answered 18/8, 2010 at 18:35 Comment(5)
This is correct, google needs to be able to access it. We had the same problem, because we didn't want our KML files to be accessible to the public. The remote API accesses the KML file, so it can't be local, it must be published on the web.Exposure
@KieranSenior you can make your kml to be privately accessible at the time of creating kml.. Under Privacy Setting Two Options Available Public & UnListed.Uracil
well hell... no wonder I couldn't find a "rawData" (as opposed to "url") option for KmlLayer.Fossorial
Is it the same case with GeoJSON too?Anaglyph
@Anaglyph in theory you could load a local GeoJSON file from file system. on a related note, this example may help.Ovotestis
A
43

Unfortunately you cannot use "localhost". You have two choices:

  1. place the kml on a publically available domain. (if google cannot access it, it won't work)
  2. Use geoxml3 which basically does what google does but allows you to downlaod and host the parser JS file youself. It will allow you to load a LOCALHOST KML and parse it out for you (objects accessible via JSON) (http://code.google.com/p/geoxml3/).

Choice #1 might not be an option for those working on defense contracts and deal with sensitive information as the kml is sent to google in the background and rendered on the map.

Alit answered 8/10, 2010 at 13:55 Comment(1)
If I have to read GeoJSON, should it be made publicly available? Or it can be fetched directly from DB and binded to Map. Does GeoJSON suport caching?Anaglyph
K
19

This website, display-kml.appspot.com, requires that you copy/paste the entire KML file into the website. Alternatively, you can use Dropbox to host the KML file using your public folder. Within the public Dropbox folder, there is a right-click context menu that allows you to copy the URL.

Update:

The appspot website has a history of being unstable. As of January 2019, the website appears to be working.

REFERENCES:
  1. http://display-kml.appspot.com/
  2. https://www.dropbox.com/
Kaffiyeh answered 18/10, 2011 at 15:8 Comment(2)
This website is no longer usable as of 2017.Dorran
I don't think Dropbox allows file hosting in this context anymore either :\Kaffiyeh
O
2

Definitely, Google Maps KmlLayer is designed for you to send your data to them. https://developers.google.com/maps/documentation/javascript/kml

Have a look the following log.

//console
var src = 'https://developers.google.com/maps/documentation/javascript/examples/kml/westcampus.kml';

var kmlLayer = new google.maps.KmlLayer(src, {
  suppressInfoWindows: true,
  preserveViewport: false,
  map: your_gmap_object
});

Creating Marker, Polygon, they are all browser side parsing and rendering.

As you can see from next network log, KmlLayer class send source URL to Google Server to parse it and (do something in their end) and send the parsed result back to your browser to render.

//REQUEST from browser

https://maps.googleapis.com/maps/api/js/KmlOverlayService.GetOverlays?1shttps%3A%2F%2Fdevelopers.google.com%2Fmaps%2Fdocumentation%2Fjavascript%2Fexamples%2Fkml%2Fwestcampus.kml&callback=_xdc_._lidt3k&key=AIzaSyBeLTP20qMgxsQFz1mwLlzNuhrS5xD_a_U&token=103685

//RESPONSE from google server

/**/_xdc_._lidt3k && _xdc_._lidt3k( [0,"kml:cXOw0bjKUSmlnTN2l67v0Sai6WfXhSSWuyNaDD0mAzh6xfi2fYnBo78Y2Eg","|ks:;dc:tg;ts:51385071|kv:3|api:3",...
["KmlFile"],[[37.423017,-122.0927],[37.424194,-122.091498]],[["g74cf1503d602f2e5"],["g58e8cf8fd6da8d29"],["ge39d22e72437b02e"]],1,[["client","2"]],-21505,[["ks",";dc:tg;ts:51385071"],["kv","3"],["api","3"]]] )

As @capdragon mentioned above, it would be better parse KML by yourself.

UPDATE

Here is compact KML parser code. This only for google.maps Marker and Polygon.

html

<input type='file' accept=".kml,.kmz" onchange="fileChanged()">

script, I used typescript but it is pretty same with javascript

  file: any
  fileChanged(e) {
    this.file = e.target.files[0]
    this.parseDocument(this.file)
  }
  parseDocument(file) {
    let fileReader = new FileReader()
    fileReader.onload = async (e: any) => {
      let result = await this.extractGoogleCoords(e.target.result)

      //CREATE MARKER OR POLYGON WITH result here
      console.log(result)

    }
    fileReader.readAsText(file)
  }

  async extractGoogleCoords(plainText) {
    let parser = new DOMParser()
    let xmlDoc = parser.parseFromString(plainText, "text/xml")
    let googlePolygons = []
    let googleMarkers = []

    if (xmlDoc.documentElement.nodeName == "kml") {

      for (const item of xmlDoc.getElementsByTagName('Placemark') as any) {
        let placeMarkName = item.getElementsByTagName('name')[0].childNodes[0].nodeValue.trim()
        let polygons = item.getElementsByTagName('Polygon')
        let markers = item.getElementsByTagName('Point')

        /** POLYGONS PARSE **/        
        for (const polygon of polygons) {
          let coords = polygon.getElementsByTagName('coordinates')[0].childNodes[0].nodeValue.trim()
          let points = coords.split(" ")

          let googlePolygonsPaths = []
          for (const point of points) {
            let coord = point.split(",")
            googlePolygonsPaths.push({ lat: +coord[1], lng: +coord[0] })
          }
          googlePolygons.push(googlePolygonsPaths)
        }

        /** MARKER PARSE **/    
        for (const marker of markers) {
          var coords = marker.getElementsByTagName('coordinates')[0].childNodes[0].nodeValue.trim()
          let coord = coords.split(",")
          googleMarkers.push({ lat: +coord[1], lng: +coord[0] })
        }
      }
    } else {
      throw "error while parsing"
    }

    return { markers: googleMarkers, polygons: googlePolygons }

  }

output

markers: Array(3)
0: {lat: 37.42390182131783, lng: -122.0914977709329}
...

polygons: Array(1)
0: Array(88)
0: {lat: -37.79825999283025, lng: 144.9165994157198}
...
Ogden answered 7/11, 2018 at 1:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.