The 2015 kickoff thread has made it pretty clear that KML support is a #1 priority for many of you. I imagine it’s become an even higher priority with the deprecation of the Google Earth API. The good news is it’s a high priority for us as well.
The Cesium team has been working on KML since André Nunes got the ball rolling during Google Summer of Code in June of 2013. A large part of our KML efforts since then had more to do with adding core Cesium features needed to support such a large and diverse specification rather than dealing with the intricacies of the spec itself.
Thankfully, our work will soon start to pay off, as “Phase 1” of our KML support will be released with Cesium 1.7 on March 2nd . I say “Phase 1” because this is just the beginning. I’ve personally been disappointed with every web-mapping application that claims to support KML. Every one I have tried barely scratches the surface of its capabilities, I know the Cesium community can do better and our goal is to be fully compatibility with Google Earth. This includes the official OGC specification as well as support for Google’s own gx extension namespace, not to mention the implementation quirks in Google Earth itself. Since that is obviously a lot of work, we decided it would be better to release features as they are ready (with phase 1 being the core architecture we need going forward).
I know there have been many people building (or trying to build) the Cesium kml branch in the hopes of playing with it before the release. Because of such high demand, I decided to start making beta releases available so it’s easier to get started. You can grab the first one from Google Drive: Cesium-kml-2015-01-08.zip.
Even better, if you want to start playing with KML right now, you can drag and drop your KMZ or KML files to this beta version of Cesium Viewer that I’ve hosted on GitHub (or append the “?source=” parameter to load a url). This version will be updated on a regular basis and it’s configured to proxy everything for maximum compatibility (more on that later).
Loading KML programmatically is just as easy as loading CZML or GeoJSON. I also added a SandCastle example.
viewer.dataSources.add(Cesium.KmlDataSource.fromUrl(‘path/to/kmlOrkmz’));
What (mostly) works
- Both KML and KMZ formats are supported.
- All geometry types except for models.
- Time dynamic geometry and intervals.
- Ground Overlays
- Local, remote, and shared styles (not all style options are supported)
- Basic balloon support (via InfoBox).
- Rudimentary “one and done” NetworkLink support. (No refreshes, no view parameters, etc…)
What doesn’t work
- Vector data does not currently conform to terrain and altitude mode is ignored.
- The visibility tag is ignored, everything is loaded as if were visible.
- Other than the exception noted above, Network Links are unsupported.
- Screen Overlays
- Photo Overlays
- Super Overlays
- Hover styles
- drawOrder
- Tours and related functionality
- Your favorite KML feature that I’ve probably forgot to mention, sorry!
Since KML is a large specification, we would love to hear what parts of it are most important to you in order to help shape the roadmap. We’re also looking for some kickass offline free-to-distribute KML examples that we can include for our Sandcastle demo. If you would like to contribute one, or know of one that could do the job, let us know. (Maybe we can even make a little contest out of it and send out some free t-shirts).
I’ll also reply to this post whenever there are new builds to play with or other significant updates to KML support (even after phase 1). For example, just yesterday I added the rudimentary NetworkLink support as well as polygons with holes. If you don’t subscribe to forum updates, feel free to follow me on Twitter (@matt_amato); I’ll post updates on there as well.
Now about that proxy.
If you are familiar with Cross-Origin Resource Sharing (CORS) and the problems it presents, you can skip to the last paragraph. For everyone else, it’s really important to understand the role it plays in whether a particular KML file will work in Cesium or not; so keep reading!
KML is not very web friendly. It allows for local file system references (which can’t be generally supported by web apps). It includes Collada files which allow for all kinds of stuff that aren’t supported on the web (which is why glTF now exists). Descriptions can have embedded HTML which has to be sanitized to avoid security issues, the list goes on and on. Many of these issues we can work around one way or another, but the worst problem is likely not going away anytime soon.
Many existing KML files make use of NetworkLinks or linked image URLs that reference data on external servers. For example, take the National Weather Services KML generator. In theory, it should be easy to load the URL (which returns a KMZ) into Cesium.
viewer.dataSources.add(Cesium.KmlDataSource.fromUrl(‘http://radar.weather.gov/ridge/warningzipmaker.php’));
Unfortunately if you run this code and you’ll get something similar to this error in the console:
XMLHttpRequest cannot load http://radar.weather.gov/ridge/warningzipmaker.php. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080’ is therefore not allowed access.
For those of you not familiar with ‘Access-Control-Allow-Origin’, it’s a header that allows JavaScript to retrieve files from domains other than the one hosting the site. I won’t go into details, but this roadblock exists to prevent certain types of security attacks. Google Earth doesn’t have this problem because it’s a desktop application and not running in a browser sandbox. If the external server enabled CORS, it would have loaded fine (and securely). Unfortunately most servers never enable this functionality
Now you may think to yourself, that’s okay, I’ll just download the file to my own server or computer and use it from there. Unfortunately, you’ll get the same error as above. Why? It’s because like many KML files, it’s just a stub that include a NetworkLink that points back to (you guessed it) http://radar.weather.gov, which we’ve already learned does not enable CORS.
The only real solution is to use a proxy. What is a proxy? In this use case it’s a simple web-service that runs on your own server that downloads the file for you and passes it through to the app. This works around the CORS issue because the web-service is not running in the local browser sandbox. Cesium ships with a proxy as part of the development server. It’s easy to use and the below will work great in the beta.
var proxy = new Cesium.DefaultProxy(’/proxy/’);
viewer.dataSources.add(Cesium.KmlDataSource.fromUrl(‘http://radar.weather.gov/ridge/warningzipmaker.php’, proxy));
Of course the problem is that if you’re trying to write a general KML viewer, you have no way to tell what servers support CORS and which don’t, which means you have to proxy everything (which can be a load-time performance bottleneck and a strain on the server). What’s worse is that if you’re app is on the internet, you really don’t want to run an open proxy for another set of security reasons that I won’t go into. That being said, the simplistic Cesium Viewer app that I linked to at the beginning of this post does use http://www.corsproxy.com. Here’s how I set it up in Cesium so that I could host my demo on GitHub pages.
var proxy = {
getURL : function(url) {
var tmp = new Cesium.Uri(url));
url = 'http://www.corsproxy.com/' + tmp.authority + tmp.path;
if(tmp.query){
url += '?' + tmp.query;
}
return url;
}
};
var viewer = new Cesium.Viewer(‘cesiumContainer’);
viewer.dataSources.add(Cesium.KmlDataSource.fromUrl(‘http://radar.weather.gov/ridge/warningzipmaker.php’, proxy));
Keep in mind that by using a third-party proxy, we are sending all KML server requests through the proxy first which means it can see/manipulate the results on the way to the client. This is obviously a security issue for production applications but is not a problem for the demo. You’ll want to use your own proxy and whitelist for any production Cesium application that needs to load KML files you don’t manage yourself.
Of course the good news is that if all of the KML files and related images/NetworkLinks are on your own servers, there is no reason to use a proxy and everything will work great (as long as you enable CORS).
This email was long overdue and turned out a lot longer than I expected; but hopefully it gets everyone interested in KML on the same page and provides insight into our 2015 plans. I plan on making this the “official” KML thread until we release and I’ll probably turn this post into a full featured blog post at that time. For now, test it out and let us know what you think.
Thanks,
Matt