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
Printable View
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 [B]nokia.maps.heatmap.Overlay.DataPoint [/B] objects see [URL="http://api.maps.nokia.com/2.2.3/apireference/symbols/nokia.maps.heatmap.Overlay.DataPoint.html"]here[/URL]
The basis of the [B]DataPoint[/B] is a coordinate of longitude/latitude which can be taken from the parsed KML [B]resulSet[/B] 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 [B]documents[/B], [B]folders [/B]and [B]placemarks[/B] such as [B]kml.kmlDocument.documents[0].folders[0].placemarks[0].geometry.coordinate[/B].
Each [B]DataPoint[/B] is added to the array and the array of [B]DataPoints[/B] is added to the [B]heatmapProvider[/B].
Regarding cross domain restrictions the best option would be to investigate a server-side proxy such as [URL="http://benalman.com/projects/php-simple-proxy/"]this one for PHP[/URL]. 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". ([B]Hint[/B] older versions of IE didn't enforce this.)
By the way the data set used is from the Playground examples: [url]http://developer.here.net/apiexplorer/examples/res/kml/usgs/earthquakes.kml[/url]
[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>[/CODE]
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 [B]DataPoint [/B]format, which can then be entered as in the example [URL="http://developer.here.net/apiexplorer/examples/api-for-js/data-visualization/map-with-density-heat-map.html"]here[/URL]. Since KML is just a specific type of XML you can use an XSLT transform such as the one below to do this
[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>[/CODE]
This returns data like:
[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]
You could even use the [B]loadScript [/B]function from the example helpers to make the call to your data proxy.
[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);
};[/CODE]