Hi,
I'm playing around with Here maps and was wondering if anyone has an example to generate heatmaps from a kml file.
An example on how to bypass the cross domain restrictions would also be useful.
thanks in advance.
JW
Hi,
I'm playing around with Here maps and was wondering if anyone has an example to generate heatmaps from a kml file.
An example on how to bypass the cross domain restrictions would also be useful.
thanks in advance.
JW
For a heatmap you will need to transform your data into an array of nokia.maps.heatmap.Overlay.DataPoint objects see here
The basis of the DataPoint is a coordinate of longitude/latitude which can be taken from the parsed KML resulSet as shown below. i.e. the coordinates of all objects (ie. placemarks) within all containers (ie. folders) within the root container (i.e the document)
You could also traverse the KML Document object to obtain the same data instead i.e. iterate through documents, folders and placemarks such as kml.kmlDocument.documents[0].folders[0].placemarks[0].geometry.coordinate.
Each DataPoint is added to the array and the array of DataPoints is added to the heatmapProvider.
Regarding cross domain restrictions the best option would be to investigate a server-side proxy such as this one for PHP. This means the data is effectively coming from your own domain.
The API itself can't get round cross domain scripting as this is a restriction within the browser "for your own safety". (Hint older versions of IE didn't enforce this.)
By the way the data set used is from the Playground examples: http://developer.here.net/apiexplore...arthquakes.kml
Code:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=7; IE=EmulateIE9" /> <title>KML HeatMap</title> <!-- KML support is required here. --> <script type="text/javascript" charset="UTF-8" src="http://api.maps.nokia.com/2.2.1/jsl.js?with=all"></script> </head> <style type="text/css"> html { overflow:hidden; } body { margin: 0; padding: 0; overflow: hidden; width: 100%; height: 100%; position: absolute; } #mapContainer { width: 100%; height: 90%; } </style> </head> <body> <div id="mapContainer"></div> <script type="text/javascript"> ///////////////////////////////////////////////////////////////////////////////////// // Don't forget to set your API credentials // // Replace with your appId and token which you can obtain when you // register on http://api.developer.nokia.com/ // nokia.Settings.set( "appId", "..."); nokia.Settings.set( "authenticationToken", "..."); // ///////////////////////////////////////////////////////////////////////////////////// </script> <div id="uiContainer"></div> <script> // Get the DOM node to which we will append the map var mapContainer = document.getElementById("mapContainer"); // We create a new instance of InfoBubbles bound to a variable so we can call it later on var infoBubbles = new nokia.maps.map.component.InfoBubbles(); infoBubbles.options.defaultWidth = 100; // Create a map inside the map container DOM node var map = new nokia.maps.map.Display(mapContainer, { components: [ // We add the behavior component to allow panning / zooming of the map new nokia.maps.map.component.Behavior(), infoBubbles ] }); var resultSet; var heatmapProvider = new nokia.maps.heatmap.Overlay({ // This is the greatest zoom level for which the overlay will provide tiles max: 20, // This is the overall opacity applied to this overlay opacity: 0.6, // Defines if our heatmap is value or density based type: "density", // Coarseness defines the resolution with which the heat map is created. coarseness: 20 }); var kml = new nokia.maps.kml.Manager(); // We define a callback function for parsing kml file, // and then push the parsing result to map display var onParsed = function (kmlManager) { // KML file was successfully loaded if (kmlManager.state == "finished") { // KML file was successfully parsed resultSet = new nokia.maps.kml.component.KMLResultSet(kmlManager.kmlDocument, map); console.log(resultSet); resultSet.addObserver("state", function (resultSet) { if (resultSet.state == "finished") { // Retrieve map objects container from KML resultSet var container = resultSet.container.objects.get(0); // This is DOCUMENT var data = new Array(); // This is the data for the heatmap // Iterate through the Document/ Folders and Placemarks.... for (i= 0; i < container.objects.getLength(); i++){ var folder = container.objects.get(i); for (j= 0; j < folder.objects.getLength(); j++){ var placeMark = folder.objects.get(j); for (k= 0; k < placeMark.objects.getLength();k++){ data.push(placeMark.objects.get(k).coordinate); } } } heatmapProvider.addData(data); map.overlays.add(heatmapProvider); // Add the container to the map's object collection so they will be rendered onto the map. map.objects.add(container); // Switch the viewport of the map do show all KML map objects within the container map.zoomTo(container.getBoundingBox()); } }); resultSet.create(); } }; // Add an observer to kml manager kml.addObserver("state", onParsed); // Start parsing a kml file with given url // Note: please adapt the following path to the file you want to parse. kml.parseKML("earthquakes.kml"); </script> </body> </html>
If you just want a heatmap, and your KML file contains a lot of coordinates, then time taken to create and process the KML document on the browser will be significant. It would make a lot of sense to use your proxy productively to transform the KML directly into json holding the point values in DataPoint format, which can then be entered as in the example here. Since KML is just a specific type of XML you can use an XSLT transform such as the one below to do this
This returns data like:Code:<?xml version="1.0" encoding="UTF-8" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="/"> data = [ <xsl:for-each select="kml/Document/Folder/Placemark/Point"> { <xsl:variable name="coordinates"> <xsl:value-of select="*" /> </xsl:variable> <xsl:variable name="longitude"> <xsl:value-of select="substring-before($coordinates,',')"/> </xsl:variable> <xsl:variable name="latitude"> <xsl:value-of select="substring-before(substring-after($coordinates,','),',')"/> </xsl:variable> latitude: <xsl:value-of select="$latitude" />, longitude: <xsl:value-of select="$longitude" /> } <xsl:if test="position()!=last()">,</xsl:if> </xsl:for-each> ]; </xsl:template> </xsl:stylesheet>
You could even use the loadScript function from the example helpers to make the call to your data proxy.Code:data = [ { latitude: -21.5594, longitude: -179.3685 } , { latitude: 38.8050, longitude: -122.8153 } , { latitude: 58.7561, longitude: -152.6842 } , { latitude: 19.3985, longitude: -155.2708 } ];
Code:this.loadScript = function (url, callback) { var script = document.createElement("script"), head = document.getElementsByTagName("head")[0]; script.type = "text/javascript"; if (script.readyState) { // Internet explorer script.onreadystatechange = function () { if (script.readyState == "loaded" || script.readyState == "complete") { script.onreadystatechange = null; callback(); } }; } else { // All other browsers script.onload = function () { callback(); }; } script.src = url; head.appendChild(script); };
Last edited by jasfox; 2012-12-20 at 11:24.