使用谷歌地图加载本地 .kml 文件?
Posted
技术标签:
【中文标题】使用谷歌地图加载本地 .kml 文件?【英文标题】:Loading a local .kml file using google maps? 【发布时间】:2011-03-31 16:43:31 【问题描述】:我创建了一个 hello world 程序来加载本地 kml 文件(借自 google 的文档):
var ctaLayer = new google.maps.KmlLayer("http://localhost:8080/kml/cta.kml");
这不起作用(什么都没有加载)。
但是,当我将该行更改为:
var ctaLayer = new google.maps.KmlLayer("http://gmaps-samples.googlecode.com/svn/trunk/ggeoxml/cta.kml");
它正确加载。两个 kml 文件是相同的。自己上菜时,我需要做什么才能加载它? (我尝试了绝对路径和相对路径,我知道我使用的路径是正确的......)
我还在我的应用服务器的配置文件中添加了正确的 mime 类型:
<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>
但它仍然无法加载。
我在 google 的 docs 中找到了这个:
Google Maps API 支持 KML 和 GeoRSS 数据格式来显示地理信息。这些数据格式使用 KmlLayer 对象显示在地图上,其构造函数采用可公开访问的 KML 或 GeoRSS 文件的 URL。
所以我想我想要做的是不可能如果不从可公开访问的 url 提供 kml...除非有人可以证明不是这样
【问题讨论】:
当您在浏览器中访问本地 KML URL 时会发生什么? 【参考方案1】:此网站display-kml.appspot.com 要求您将整个 KML 文件复制/粘贴到网站中。或者,您可以使用 Dropbox 在您的公用文件夹中托管 KML 文件。在公共 Dropbox 文件夹中,有一个右键单击上下文菜单可让您复制 URL。
更新:appspot 网站有不稳定的历史。截至 2019 年 1 月,该网站似乎正在运行。
参考:-
http://display-kml.appspot.com/
https://www.dropbox.com/
【讨论】:
该网站自 2017 年起不再可用。 我认为 Dropbox 也不再允许在这种情况下托管文件:\【参考方案2】:毫无疑问,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 标记和多边形。
<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
...
【讨论】:
【参考方案3】:很遗憾,您不能使用“localhost”。你有两个选择:
-
将 kml 放置在公开可用的域中。 (如果谷歌无法访问它,它将无法工作)
使用geoxml3,它基本上可以做谷歌所做的,但允许您自己下载和托管解析器JS文件。它将允许您加载 LOCALHOST KML 并为您解析它(可通过 JSON 访问的对象)(http://code.google.com/p/geoxml3/)。
对于那些从事国防合同和处理敏感信息的人来说,选择 #1 可能不是一个选项,因为 kml 在后台发送到 google 并呈现在地图上。
【讨论】:
如果我必须阅读 GeoJSON,是否应该公开?或者可以直接从 DB 中获取并绑定到 Map。 GeoJSON 支持缓存吗?【参考方案4】:无法访问 KML,因为它位于您的本地计算机上,而 google 无法访问它,因为它不知道如何访问 localhost:8080
【讨论】:
这是正确的,google 需要能够访问它。我们遇到了同样的问题,因为我们不希望我们的 KML 文件可供公众访问。远程API访问KML文件,所以不能是本地的,必须发布到网络上。 @KieranSenior 您可以在创建 kml 时将您的 kml 设为可私下访问。在“隐私设置”下,有两个选项可用“公开”和“未列出”。 好吧……难怪我找不到 KmlLayer 的“rawData”(相对于“url”)选项。 GeoJSON也一样吗? @gorp88 理论上您可以从文件系统加载本地 GeoJSON 文件。在相关说明中,this example 可能会有所帮助。以上是关于使用谷歌地图加载本地 .kml 文件?的主要内容,如果未能解决你的问题,请参考以下文章
google_maps_flutter 或任何其他 Flutter 地图插件是不是支持谷歌地图的 kml 文件?