最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Google Maps API and KML File LocalHost Development Options - Stack Overflow

programmeradmin1浏览0评论

The Google Maps JavaScript version 3 API library documentation clearly explains:

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.

There are even several Stack Overflow questions about how to load local data:

  • Loading a local .kml file using google maps?
  • Google Maps kml files

Some of the answers have pointed to third party libraries which can parse KML locally without the file needing to be public:

  • geoxml3
  • GeoXML
  • EGeoXml

And while these solutions are good if you have a need to keep your data private, I simply want to make development easier. When running locally I obviously cannot parse my KML and therefore lose functionality that I am trying to test. I've posted a single generic KML file on a publicly available site, but then have to have different development code to render one thing vs. something else when running for real.

What are my options for local development to render what would be publicly available dynamically generated KML files?

The Google Maps JavaScript version 3 API library documentation clearly explains:

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.

There are even several Stack Overflow questions about how to load local data:

  • Loading a local .kml file using google maps?
  • Google Maps kml files

Some of the answers have pointed to third party libraries which can parse KML locally without the file needing to be public:

  • geoxml3
  • GeoXML
  • EGeoXml

And while these solutions are good if you have a need to keep your data private, I simply want to make development easier. When running locally I obviously cannot parse my KML and therefore lose functionality that I am trying to test. I've posted a single generic KML file on a publicly available site, but then have to have different development code to render one thing vs. something else when running for real.

What are my options for local development to render what would be publicly available dynamically generated KML files?

Share Improve this question edited May 23, 2017 at 10:29 CommunityBot 11 silver badge asked May 23, 2011 at 1:55 ahsteeleahsteele 26.5k28 gold badges138 silver badges252 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 11

It seems like you've outlined the options pretty well:

If you want to work with local data, without involving a publicly accessible webserver, you'll need to use a javascript-based approach to parse the KML and load it onto the map. While this won't perfectly replicate the Google functionality, it is likely good enough for initial development if you only care about displaying the KML features. In this case, I'd probably set up a stub class, like this:

    // I'll assume you have a global namespace called MyProject
    MyProject.LOCAL_KML = true;

    MyProject.KmlLayer = function(url) {
        // parse the KML, maybe caching an array of markers or polygons,
        // using one of the libraries you list in your question
    };

    // now stub out the methods you care about, based on
    // http://code.google.com/apis/maps/documentation/javascript/reference.html#KmlLayer
    MyProject.KmlLayer.prototype.setMap = function(map) {
        // add the markers and polygons to the map, or remove them if !map
    }
    // etc

Now either put a switch in the code, or comment/uncomment, or use a build script to switch, or whatever your current process is for switching between dev and production code:

    var kmlPath = "/my.kml";
    var kmlLayer =  MyProject.LOCAL_KML ?
        new MyProject.KmlLayer(MyProject.LOCAL_KML_HOST + kmlPath) :
        new google.maps.KmlLayer(MyProject.PRODUCTION_KML_HOST + kmlPath);
    kmlLayer.setMap(myMap);

If, on the other hand, you need all of the functionality in the Google KmlLayer, or you want to make sure things work with the production setup, or you don't want to bother stubbing out the functionality Google provides, then you'll need to upload it to a publicly available server, so that Google can do its server-side processing.

Aside from the obvious options (FTP, a command-line script to upload your new KML file, etc), most of which require you to do something manually before you load your map page, you might consider building the update into the page you're loading. Depending on the platform you're using, this might be easier to do on the back-end or the front-end; the key would be to have a script on your public server that would allow the KML to be updated:

  1. Get KML string from request.POST
  2. Validate the KML string (just so you aren't opening your server to attacks)
  3. Write to a single file, e.g. "my.kml"

Then, when you view your map page, update the remote KML based on the data from localhost. Here's a client-side version, using jQuery:

// again, you'd probably have a way to kill this block in production
if (MyProject.UPDATE_KML_FROM_LOCALHOST) {
    // get localhost KML
    $.get(MyProject.LOCAL_KML_HOST + kmlPath, function(data) {
        // now post it to the remote server
        $.post(
            MyProject.DEV_KML_HOST + '/update_kml.php', 
            { kml: data }, 
            function() {
                // after the post completes, get the KML layer from Google
                var kmlLayer new google.maps.KmlLayer(MyProject.DEV_KML_HOST + kmlPath);
                kmlLayer.setMap(myMap);
            }
        );
    })
}

Admittedly, there are a lot of round-trips here (page -> localhost, page -> remote server, Google -> remote server, Google -> page), so this is going to be slow. But it would allow you to have Google's code properly render dynamic KML data produced on localhost, without having to take a separate manual step every time you reload the page.

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}
...
发布评论

评论列表(0)

  1. 暂无评论