Openlayers 3 - WFS not updating on map pan - javascript

I was using a CQL Filter to return my points based on a certain type. I then added a BBOX to the filter to limit the results only to the current extent of the map. This was all working correctly. The only issue is if I pan the map it does not reload the WFS call. So if I zoom into a point the wfs filters correctly, if I then pan to an area where I know there is a point there will be nothing there unless I change the zoom level. This will update the WFS.
In my ServerVector loader parameter I call a function updateWFSURL(extent). I use this to build the WFS url based on the filter criteria to be passed to the CQL_FILTER. I currently have no loading strategy, I tried using createTile and bbox but neither gave me the proper result.
Here is the code I am using to add the BBOX to my CQL_FILTER. More filters are added after and this filter is appended to the WFS url.
var coord1 = ol.proj.transform([extent[0], extent[1]], 'EPSG:3857', 'EPSG:4326');
var coord2 = ol.proj.transform([extent[2], extent[3]], 'EPSG:3857', 'EPSG:4326');
var filter = "&CQL_FILTER=BBOX(GEOM, " + coord1 + ", " + coord2 + ", 'EPSG:4326')";
The workaround I found was to capture the map moveend event and call the updateWFSURL(extent) from there. This will update properly on a pan but causes the updateWFSURL to be called twice on zoom since it gets fired from the WFS loader and moveend event.
The solution I am looking for is to either have my WFS update properly on the pan or how to determine the difference between a pan/zoom so I can not call the function in moveend if it was a zoom.
Added more code below. Removed the geoserver url and layer name I am using and stripped out some of CQL Filter that was just filtering on an ID. This wfs is not updating the map on pan without my work around.
//this function gets called on page load
function loadPointAssets() {
// Source retrieving WFS data in GeoJSON format using JSONP technique
pointAssetVector = new ol.source.ServerVector({
format: new ol.format.GeoJSON(),
loader: function (extent, resolution, projection) {
//this gets called whenever the map zooms
updateWFSURL(extent);
},
projection: 'EPSG:3857'
});
//cluster markers adds the markers to the map from the pointAssetVector
clusterMarkers();
}
function updateWFSURL(extent) {
//transform the extent to coordinates can be passed in as lat/long
var coord1 = ol.proj.transform([extent[0], extent[1]], 'EPSG:3857', 'EPSG:4326');
var coord2 = ol.proj.transform([extent[2], extent[3]], 'EPSG:3857', 'EPSG:4326');
var filter = "&CQL_FILTER=BBOX(GEOM, " + coord1 + ", " + coord2 + ", 'EPSG:4326')";
$.ajax({
//create the url with the filter
url: 'http://myGeoserverURL/wfs?' +
'service=WFS&request=GetFeature&' +
'version=1.1.0&typename=LayerName&outputFormat=text/javascript&' +
'format_options=callback:loadFeatures&' +
'srsname=EPSG:4326' + filter,
dataType: 'jsonp'
});
pointAssetVector.clear(true);
}
// Executed when data is loaded by the $.ajax method.
var loadFeatures = function (response) {
//clear the features before adding them to the source again
pointAssetVector.clear();
pointAssetVector.addFeatures(pointAssetVector.readFeatures(response));
};

You cannot use CQL filter and BBOX together in the same WFS request. If you have a CQL property filter then you need to add the BBOX filter as a CQL filter.
For example, this BBOX filter:
bbox: extent.join(',') + ',EPSG:3857'
Is equivalent to this CQL filter:
cql_filter: "BBOX(geometry," + extent.join(',') + ")"

Related

How to customize HERE Maps Clusters

In my current Hybrid app I am in the process of switching from using Leaflet and its Clusterer plugin to using the HERE Maps v3 JavaScript API. The HERE Maps documentation can be rather dense at times for someone used to the clarity of Leaflet documentation. Nevertheless the process of using HERE is fairly straightforward. However, there is one Leaflet feature that I really miss:
In Leaflet when you add markers to a cluster it is possible to assign custom map pins to each marker. Further, you can quite easily customize the pin used to represent the cluster itself. In HERE the documentation indicates the following
var dataPoints = [];
//create an array for the clustered marker datapoints
dataPoints.push(new H.clustering.DataPoint(43.25539364396839, -79.07150530321474));
dataPoints.push(new H.clustering.DataPoint(43.255434408174246, -79.07175552759227));
dataPoints.push(new H.clustering.DataPoint(43.25557588373579, -79.07203209137799));
dataPoints.push(new H.clustering.DataPoint(43.25567419706804, -79.07218354297491));
//populate that array
var clusteredDataProvider = new H.clustering.Provider(dataPoints);
//create a cluster data provider and assign it the freshly created data points
var layer = new H.map.layer.ObjectLayer(clusteredDataProvider);
//create a new layer that uses this provider
map.addLayer(layer);
//inject this layer into the map
This works. However, it leaves me with three unanswered questions
How can I make the Cluster icon "explode" when tapped so the map zooms in automatically to the clustered map pins and shows each individual map pin with its assigned icon?
How do I assign individual PNG icon images to each of the "datapoints" above?
How to I customize the look and feel of the actual Cluster map pin itself?
Clusters and noise points are represented on the map with markers. Unless otherwise configured, the clustering provider uses the default bitmap markers theme with weight information to display clusters and noise points on the map. You can define your own custom theme and pass it to the provider as the theme property.
Read please this docu on https://developer.here.com/documentation/maps/3.1.22.0/dev_guide/topics/clustering.html
A custom theme is defined in an object that implements the interface H.clustering.ITheme as demonstrated by the code below.
/**
* Make clustering of markers with a custom theme
*
* Note that the maps clustering module https://js.api.here.com/v3/3.1/mapsjs-clustering.js
* must be loaded to use the Clustering
*
* #param {H.Map} map A HERE Map instance within the application
* #param {H.ui.UI} ui Default ui component
* #param {Function} getBubbleContent Function returning detailed information about photo
* #param {Object[]} data Raw data containing information about each photo
*/
function startClustering(map, ui, getBubbleContent, data) {
// First we need to create an array of DataPoint objects for the ClusterProvider
var dataPoints = data.map(function(item) {
// Note that we pass "null" as value for the "altitude"
// Last argument is a reference to the original data to associate with our DataPoint
// We will need it later on when handling events on the clusters/noise points for showing
// details of that point
return new H.clustering.DataPoint(item.latitude, item.longitude, null, item);
});
// Create a clustering provider with a custom theme
var clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
// Maximum radius of the neighborhood
eps: 64,
// minimum weight of points required to form a cluster
minWeight: 3
},
theme: CUSTOM_THEME
});
// Note that we attach the event listener to the cluster provider, and not to
// the individual markers
clusteredDataProvider.addEventListener('tap', onMarkerClick);
// Create a layer that will consume objects from our clustering provider
var layer = new H.map.layer.ObjectLayer(clusteredDataProvider);
// To make objects from clustering provider visible,
// we need to add our layer to the map
map.addLayer(layer);
}
// Custom clustering theme description object.
// Object should implement H.clustering.ITheme interface
var CUSTOM_THEME = {
getClusterPresentation: function(cluster) {
// Get random DataPoint from our cluster
var randomDataPoint = getRandomDataPoint(cluster),
// Get a reference to data object that DataPoint holds
data = randomDataPoint.getData();
// Create a marker from a random point in the cluster
var clusterMarker = new H.map.Marker(cluster.getPosition(), {
icon: new H.map.Icon(data.thumbnail, {
size: {w: 50, h: 50},
anchor: {x: 25, y: 25}
}),
// Set min/max zoom with values from the cluster,
// otherwise clusters will be shown at all zoom levels:
min: cluster.getMinZoom(),
max: cluster.getMaxZoom()
});
// Link data from the random point from the cluster to the marker,
// to make it accessible inside onMarkerClick
clusterMarker.setData(data);
return clusterMarker;
},
getNoisePresentation: function (noisePoint) {
// Get a reference to data object our noise points
var data = noisePoint.getData(),
// Create a marker for the noisePoint
noiseMarker = new H.map.Marker(noisePoint.getPosition(), {
// Use min zoom from a noise point
// to show it correctly at certain zoom levels:
min: noisePoint.getMinZoom(),
icon: new H.map.Icon(data.thumbnail, {
size: {w: 20, h: 20},
anchor: {x: 10, y: 10}
})
});
// Link a data from the point to the marker
// to make it accessible inside onMarkerClick
noiseMarker.setData(data);
return noiseMarker;
}
};
/**
* Boilerplate map initialization code starts below:
*/
// Helper function for getting a random point from a cluster object
function getRandomDataPoint(cluster) {
var dataPoints = [];
// Iterate through all points which fall into the cluster and store references to them
cluster.forEachDataPoint(dataPoints.push.bind(dataPoints));
// Randomly pick an index from [0, dataPoints.length) range
// Note how we use bitwise OR ("|") operator for that instead of Math.floor
return dataPoints[Math.random() * dataPoints.length | 0];
}
/**
* CLICK/TAP event handler for our markers. That marker can represent either a single photo or
* a cluster (group of photos)
* #param {H.mapevents.Event} e The event object
*/
function onMarkerClick(e) {
// Get position of the "clicked" marker
var position = e.target.getGeometry(),
// Get the data associated with that marker
data = e.target.getData(),
// Merge default template with the data and get HTML
bubbleContent = getBubbleContent(data),
bubble = onMarkerClick.bubble;
// For all markers create only one bubble, if not created yet
if (!bubble) {
bubble = new H.ui.InfoBubble(position, {
content: bubbleContent
});
ui.addBubble(bubble);
// Cache the bubble object
onMarkerClick.bubble = bubble;
} else {
// Reuse existing bubble object
bubble.setPosition(position);
bubble.setContent(bubbleContent);
bubble.open();
}
// Move map's center to a clicked marker
map.setCenter(position, true);
}
// Step 1: initialize communication with the platform
// In your own code, replace variable window.apikey with your own apikey
var platform = new H.service.Platform({
apikey: window.apikey
});
var defaultLayers = platform.createDefaultLayers();
// Step 2: initialize a map
var map = new H.Map(document.getElementById('map'), defaultLayers.vector.normal.map, {
center: new H.geo.Point(50.426467222414374, 6.3054632497803595),
zoom: 6,
pixelRatio: window.devicePixelRatio || 1
});
// add a resize listener to make sure that the map occupies the whole container
window.addEventListener('resize', () => map.getViewPort().resize());
// Step 3: make the map interactive
// MapEvents enables the event system
// Behavior implements default interactions for pan/zoom (also on mobile touch environments)
var behavior = new H.mapevents.Behavior(new H.mapevents.MapEvents(map));
// Step 4: create the default UI component, for displaying bubbles
var ui = H.ui.UI.createDefault(map, defaultLayers);
/**
* Merges given data with default bubble template and returns resulting HTML string
* #param {Object} data Data holding single picture information
*/
function getBubbleContent(data) {
return [
'<div class="bubble">',
'<a class="bubble-image" ',
'style="background-image: url(', data.fullurl, ')" ',
'href="', data.url, '" target="_blank">',
'</a>',
'<span>',
// Author info may be missing
data.author ? ['Photo by: ', '<a href="//commons.wikimedia.org/wiki/User:',
encodeURIComponent(data.author), '" target="_blank">',
data.author, '</a>'].join(''):'',
'<hr/>',
'<a class="bubble-footer" href="//commons.wikimedia.org/" target="_blank">',
'<img class="bubble-logo" src="data/wikimedia-logo.png" width="20" height="20" />',
'<span class="bubble-desc">',
'Photos provided by Wikimedia Commons are <br/>under the copyright of their owners.',
'</span>',
'</a>',
'</span>',
'</div>'
].join('');
}
// Step 5: request data that will be visualized on a map
startClustering(map, ui, getBubbleContent, photos);
This worked example try please on JsFiddle: https://jsfiddle.net/gh/get/jquery/2.1.0/heremaps/maps-api-for-javascript-examples/tree/master/custom-cluster-theme
The data for this example loaded from https://heremaps.github.io/maps-api-for-javascript-examples/custom-cluster-theme/data/photos.js
How the Cluster icon to "explode" when tapped you can see sources of this example https://tcs.ext.here.com/examples/v3.1/cluster_marker_spider . Note please on loaded additional js module "ClusterMarkerSpider-..."
How zoom-in to "exploded" of the clustered map pins - note please on "forEachDataPoint" (in Spider example) there are created all Markers which you can simple push to some H.map.Group and after zoom-in to this group by its bounding box.

How to set wms parameter (bbox, width, height, x, y)

I access the geoserver after creating the wms url. Then I use getFeatureInfo to get the information.
How do I set the parameters to get multiple layers info?
what is means width, height, x,y, bbox?
var bboxControl = 0.0001;
var bbox = (coordinate[0]-bboxControl) + ',' +
(coordinate[1]-bboxControl) + ',' +
(coordinate[0]+bboxControl) + ',' +
(coordinate[1]+bboxControl);
var projection = map.getView().getProjection().getCode();
const parameter = "?SERVICE=WMS
&VERSION=1.1.1
&REQUEST=GetFeatureInfo
&FORMAT=image/png
&TRANSPARENT=true"
+ "&QUERY_LAYERS=" + layers
+ "&LAYERS=" + layers
+ "&exceptions=application/vnd.ogc.se_inimage
&INFO_FORMAT=application/json
&FEATURE_COUNT=50
&X=50&Y=50"
+ "&SRS=" + projection
+ "&STYLE=&WIDTH=101&HEIGHT=101"
+ "&BBOX=" + bbox;
$(document).ready(function(){
$.ajax({
url: getFeatureInfoUrl + parameter,
dataType : 'json',
success: function(result){
success(result);
}
});
});
This works but not depending on the zoom state.
If you want more layers, somewhere in your code you have a list/array named layers. Add every layer you want into that.
For your second question check here for GeoServer requests.
But in nutshell:
BBox means the bounding box. it define the area GeoServer sends the data.
Width and height define map size returned from GeoServer.

Cesium get coordinates from Entity loaded from KML

I am trying to draw an arrowhead for each point in a kml file. For this I plan to fetch coordinates for each point by getById. So far I am getting an error:
Uncaught TypeError: Cannot read property 'position' of undefined (on line 14)
Here is my code:
var src = Cesium.KmlDataSource.load('../../My_KML/plots.kml', options);
viewer.dataSources.add(src).then(function(data) {viewer.flyTo(data);});
//-------------------********--------------**********-----------------//
var point = viewer.entities.getById('geom_20102');
var entities = viewer.entities;
var cartographicPosition = Cesium.Cartographic.fromCartesian(point.position.getValue(Cesium.JulianDate.now()));
var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);
var line1 = entities.add({
polyline : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights([longitude, latitude, 360, longitude + 1, latitude + 1, 400]),
width : 10,
followSurface : false,
material : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.BLUE)
}
});
I have specified the element with id 'geom_20102' as a linestring wrapped around by a placemark in the kml. Also I would like to know which id to specify as both placemark and linestring have an id. Or am I confusing kml id with entity id?
I am new to Cesium.Js and I followed this example partially:
Cesium Workshop
KML snippet:
<Placemark id="feat_20125">
<name>874</name>
<styleUrl>#stylesel_20102</styleUrl>
<LineString id="geom_20102">
<coordinates>104.99108,10.4118,247.3 72.991075,26.25412,247.6</coordinates>
<altitudeMode>relativeToGround</altitudeMode>
</LineString>
</Placemark>
Two things are going on here.
First, the Cesium.KmlDataSource.load() function returns a JavaScript "Promise" which represents the eventual completion (or failure) of an asynchronous operation. At the time the viewer.entities is referenced in the code, the KML file has not yet loaded so the collection in viewer.entities is empty and calling getById() on it will return undefined. You should only access the viewer.entities or data.entities after the async Promise is completed and the "then" callback is invoked. Only at that time are the entities populated.
var src = Cesium.KmlDataSource.load('../../My_KML/plots.kml', options);
viewer.dataSources.add(src).then(function(data) {
var entities = data.entities;
console.log("f=" + entities.getById('feat_20125')); // f=[object Object]
console.log("g=" + entities.getById('geom_20102')); // undefined
viewer.flyTo(data);
});
Next, notice that the 'feat_20125' returns an object but the 'geom_20102' is not found. Only the "id" on the placemarks are populated when KML is converted into Cesium entities. Ids on any other KML element are discarded.

How do I access and hide markers created by loadGeoJson()?

I am loading custom coordinates into my map application via JSON. I have been able to find out how to color code the markers based on feature properties, but one of my next steps will be to create filters to show or hide markers based on the properties.
My code starts like this:
var map;
var infowindow = new google.maps.InfoWindow();
function initialize()
{
var mapCanvas = document.getElementById('map');
var mapOptions = {
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(mapCanvas, mapOptions);
map.data.loadGeoJson('/map_json.php', null, SetBounds);
map.data.setStyle(function(feature) {
var color = 'FF0000';
var symbol = '%E2%80%A2'; // dot
// color selection code here [...]
return /** #type {google.maps.Data.StyleOptions} */ {
icon: 'http://chart.apis.google.com/chart?chst=d_map_pin_letter_withshadow&chld=' + symbol + '|' + color
};
}
I already found how I can access the imported data through a jquery autocomplete search:
$(input).autocomplete({
minLength: 0,
source: function(request, response) {
data = [];
map.data.forEach(function(feature)
{
var str = request.term.toUpperCase();
if (String(feature.getProperty('name')).toUpperCase().indexOf(str) > -1)
{
data.push({id: feature.getProperty('id'), name: feature.getProperty('name'), address: feature.getProperty('address')});
}
});
response(data);
},
select: function(event, ui)
{
map.data.forEach(function(feature)
{
if (feature.getProperty('id') == ui.item.id)
{
var content = GetContent(feature);
infowindow.setContent(content);
infowindow.setPosition(feature.getGeometry().get());
infowindow.setOptions({pixelOffset: new google.maps.Size(0, -34)});
infowindow.open(map);
// zoom in
map.setZoom(15);
map.panTo(feature.getGeometry().get());
return false;
}
});
}
})
.autocomplete().data('uiAutocomplete')._renderItem = function(ul, item)
{
return $('<li>')
.append('<a>' + item.name + ' (ID: ' + item.id + ')<br>' + item.address + '</a>')
.appendTo(ul)
};
So using this same principle to run my filters is not a problem.
The problem is that I have not found a way yet to access the visible markers based on the feature information that I have in map.data.
All the examples I found so far are based on the principle of manually adding markers and storing them in an array to access later, e.g.:
var marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: 'Hello World!'
});
But I don't have that - I load the entire set of data using getGeoJson().
How can I access the marker and manipulate it (e.g. hide it or show it) based on the information I can access using map.data.forEach()?
--- Update ---
Here are more details on the project.
The map will markers that are generated from a list of customers. The customers have different categories and properties, so a typical entry form the GeoJSON string would look like this:
{"type":"Feature","geometry":{"type":"Point","coordinates":[0,0]},"properties":{"name":"Customer 1","id":"1001","address":"1234 Test Street, Test City, TX 12345, USA","category":"vendor","active":1}}
Also on the map is a filter box with checkboxes that are checked by default. Clicking any of them will run the filtering code that should hide or remove the markers that are associated with any customers that match that filter.
So if I disable the checkbox that filters "inactive", then only customers with the property "active":1 will remain on the map. If I disable the checkbox that filters "vendors", then all customers with the category "vendor" will be hidden.
Checking the checkboxes again later will undo the hiding of these entries.
What I have found in my research is a lot of mentioning of markers, but ONLY if they are added manually - not via GeoJSON import.
I can see a few potential solutions to my problem - I could ignore the GeoJSON format and instead import the client list into jQuery manually and parse it from there into markers that then go into an array. But then why use the GeoJSON format at all?
My current solution of using map.data.setStyle() (see comment) seems to work and do the job. But I am curious if there isn't another more direct way.
I figured, the filter function would go through all data (map.data.forEach()) to locate any items that should be hidden based on the filters, and then each item would communicate to its associated marker that the marker needs to be hidden. But it is this association that I have not been able to figure out so far.
When I loop through all features (map.data.forEach()), I have access to the data I uploaded, but not to the markers that were placed as a result of the import.
My question is if there is a direct way to access the marker from the feature.
I hope this is clearer now.
--- Update ---
I created a very simple jsfiddle for it:
http://jsfiddle.net/semmelbroesel/9bv68ngp/
This is the concept I want to achieve, and it works as is. My only question is if there is another way to achieve the same results by directly accessing the placed markers instead of using setStyle() to hide/show them.
You don't need to use forEach, since setStyle does already traverse the Features.
If you declare the styling function as:
map.data.setStyle(function(feature) {
var color = 'FF0000';
var symbol = '%E2%80%A2'; // dot
return /** #type {google.maps.Data.StyleOptions} */ {
visible: feature.getProperty('active'), // this links visibility to feature property
icon: 'http://chart.apis.google.com/chart?chst=d_map_pin_letter_withshadow&chld=' + symbol + '|' + color
};
});
You don't need to call the method again, since the style gets bound to the feature property. Setting the active property to false will propagate to the marker style seamlessly.
After that, you can make your filters like (rough example)
var setFilter = function(property, value) {
map.data.forEach(function(feature) {
feature.setProperty('active', feature.getProperty(property) === value);
});
};
and calling for example setFilter('name','John');
Again, this is a rough example. I'd rather implement the filtering method on the google.maps.Data prototype, but this should point you in the right direction.

How to display markers (huge numbers) on a map which has been logically divided into segments?

What i have done so far:
i'm developing an application where i have to display more than(50K) points/Markers on the Navteq map divided into different segments.
for example: if i have 50K points i will divide all points into different segments.
if i divide 50K points into 50 segments each segment would have 1000 points (may not be 50 segments , it may depend).
right now it is working but it takes long time and hangs to render all the points on the MAP.so that i would like to perform segmentation displaying to display only few points with clustering.
so that i can get an idea of how the segment will look like.
but the problem here is i should only perform the clustering based on the segments.otherwise points from different segments willbe mixed together and displayed
as single unit and that conveys the wrong information to the user.
so here my question is: is it possible to perform the clustering based on the segment. so that only points from same segment will be clustered.
Note: if this is not possible, i would like to use Latest version of here-maps 2.5.3 (Asynchronous) may reduce some time while loading, so that i would like to use indexing functionality also while rendering the points
to improve the rendering time using nokia.maps.clustering.Index class.
i studied that indexing would reduce the time while rendering the points/markers on map. does it help in my case? could anybody please suggest how to perform indexing ?
This is the code with which i'm displaying points on map:
function displayAllLightPoints(arrLightPointCoordinats, totalLightPoints,
selectedSegmentId, totalSegmentsCount,segmentColorcode)
{
var MyTheme1 = function () {
};
segmentColorcode = segmentColorcode.substring(2,segmentColorcode.length-1);
MyTheme1.prototype.getNoisePresentation = function (dataPoint) {
var markerLightPoint = new nokia.maps.map.Marker(dataPoint, {
icon: new nokia.maps.gfx.BitmapImage("..//Images//Lightpoint//" +
segmentColorcode + ".png"),
anchor: {
x: 12,
y: 12
}
});
return markerLightPoint;
};
MyTheme1.prototype.getClusterPresentation = function (data) {
var markerLightPoint = new
nokia.maps.map.StandardMarker(data.getBounds().getCenter(), {
icon: new nokia.maps.gfx.BitmapImage("..//Images//
Segment/" + segmentColorcode + ".png", null, 66, 65),
text: data.getSize(),
zIndex: 2,
anchor: {
x: 12,
y: 12
}
});
return markerLightPoint;
};
var ClusterProvider = nokia.maps.clustering.ClusterProvider,
theme = new MyTheme1(),
clusterProvider = new ClusterProvider(map, {
eps: 0.00000000001,
minPts: 1000000,
strategy: nokia.maps.clustering.ClusterProvider.
STRATEGY_DENSITY_BASED,
theme: theme,
dataPoints: []
});
var lightpointsDataSet1 = new Array();
for (var i = 0; i < totalLightPoints; i++) {
lightpointsDataSet1[i] = { latitude: arrLightPointCoordinats[i][0],
longitude: arrLightPointCoordinats[i][1], title:
'LightPoint ' + (i + 1) };
}
clusterProvider.addAll(lightpointsDataSet1);
clusterProvider.cluster();
}
To deal with a very large (50K+) data set , I would do all the heavy number crunching server side and send over a new JSON response whenever the map is updated. Something like the HTML page described here
The key section of the code is the ZoomObserver:
var zoomObserver = function (obj, key, newValue, oldValue) {
zoom = newValue;
if (zoom < 7)
{ zoom = 7;}
if (zoom > 16)
{ zoom = 16;}
// Define the XML filename to read that contains the marker data
placeMarkersOnMaps('http://api.maps.nokia.com/downloads/java-me/cluster/'+ zoom + '.xml'
+ '?lat1=' + map.getViewBounds().topLeft.latitude
+ '&lng1='+ map.getViewBounds().topLeft.longitude
+ '&lat2='+ map.getViewBounds().bottomRight.latitude
+ '&lng2='+ map.getViewBounds().bottomRight.longitude);
};
map.addObserver("zoomLevel", zoomObserver );
Where the REST service returns a "well-known" data format which can be used to add markers and clusters to the map.
Now assuming you have two massive data sets you could make two requests to different endpoints, or somehow distinguish which cluster of data belongs to which so that you would just be returning information of the form:
{latitude':51.761,'longitude':14.33128,'value':102091},
i.e. using the DataPoint standard (which means you could use a heat map as well.
Of course, what I'm not showing here is the back-end functionality to cluster in the first place - but this leaves the client (and the API) to do what it does best displaying data, not number crunching.

Categories