Google Maps API 和 KML 文件 LocalHost 开发选项

Posted

技术标签:

【中文标题】Google Maps API 和 KML 文件 LocalHost 开发选项【英文标题】:Google Maps API and KML File LocalHost Development Options 【发布时间】:2011-08-30 19:56:09 【问题描述】:

Google 地图 javascript 版本 3 API library documentation clearly explains:

Google Maps API 支持 KML 和用于显示的 GeoRSS 数据格式 地理信息。这些数据 格式显示在地图上使用 KmlLayer 对象,其构造函数 采用可公开访问的网址 KML 或 GeoRSS 文件。

甚至还有几个关于如何加载本地数据的 Stack Overflow 问题:

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

一些答案​​指向了可以在本地解析 KML 而无需公开文件的第三方库:

geoxml3 GeoXML EGeoXml

如果您需要保护数据的私密性,这些解决方案是不错的选择,但我只是想让开发变得更容易。在本地运行时,我显然无法解析我的 KML,因此失去了我正在尝试测试的功能。我在一个公开的网站上发布了一个通用的 KML 文件,但是在实际运行时必须有不同的开发代码来渲染一个东西和另一个东西。

我有哪些本地开发选项来呈现公开可用的动态生成的 KML 文件?

【问题讨论】:

【参考方案1】:

毫无疑问,Google Maps KmlLayer 专为您将数据发送给他们而设计。 https://developers.google.com/maps/documentation/javascript/kml

看看下面的日志。

//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
);

创建Marker、Polygon,都是浏览器端解析和渲染

从下一个网络日志中可以看到,KmlLayer 类将源 URL 发送到 Google Server 以对其进行解析并(在其末尾执行某些操作)并将解析结果发送回您的浏览器进行渲染。

//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"]]] )

正如上面提到的@capdragon,最好自己解析KML

更新

这是紧凑的 KML 解析器代码。 这仅适用于 google.maps 标记和多边形。

html

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

脚本,我用的是打字稿,但和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 

  

输出

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

polygons: Array(1)
0: Array(88)
0: lat: -37.79825999283025, lng: 144.9165994157198
...

【讨论】:

【参考方案2】:

您似乎已经很好地概述了这些选项:

如果您想使用本地数据,而不涉及可公开访问的网络服务器,您需要使用基于 javascript 的方法来解析 KML 并将其加载到地图上。虽然这不会完美地复制 Google 功能,但如果您只关心显示 KML 功能,它对于初始开发来说可能已经足够了。在这种情况下,我可能会设置一个存根类,如下所示:

    // 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

现在要么在代码中添加一个开关,要么注释/取消注释,或者使用构建脚本来切换,或者你当前的流程是在开发代码和生产代码之间切换:

    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);

另一方面,如果您需要 Google KmlLayer 中的所有功能,或者您想确保生产设置能够正常工作,或者您不想麻烦把谷歌提供的功能存根,然后你需要将它上传到一个公开可用的服务器,以便谷歌可以进行服务器端处理。

除了显而易见的选项(FTP、用于上传新 KML 文件的命令行脚本等)之外,其中大部分需要您在加载地图页面之前手动执行某些操作,您可以考虑将更新构建到您正在加载的页面。根据您使用的平台,这可能在后端或前端更容易完成;关键是在您的公共服务器上有一个允许更新 KML 的脚本:

    从 request.POST 中获取 KML 字符串 验证 KML 字符串(以免您的服务器受到攻击) 写入单个文件,例如“我的.kml”

然后,当您查看地图页面时,根据来自localhost 的数据更新远程 KML。这是一个使用 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);
            
        );
    )

诚然,这里有很多往返(页面 -> 本地主机,页面 -> 远程服务器,Google -> 远程服务器,Google -> 页面),所以这将是慢时间>。但它可以让您让 Google 的代码正确呈现在 localhost 上生成的动态 KML 数据,而无需在每次重新加载页面时都采取单独的手动步骤。

【讨论】:

以上是关于Google Maps API 和 KML 文件 LocalHost 开发选项的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 使用“我的地图”中的.kml文件的Google Maps API

如何设置通过google maps api kmllayer调用的kml文件的infowindow的宽度?

用于驾车和步行路线的 Google Maps HTTP API

使用 Google Maps API V3,确定标记是不是在 KML 图层边界内

google_maps_flutter 或任何其他 Flutter 地图插件是不是支持谷歌地图的 kml 文件?

如何使用Google API,以便将先前创建的KML文件发送到“我的Google地图”,然后获取返回的URL以显示在网页中