I'm currently working on my first real outing using Javascript to build an interactive map of our customer data .
So Far I've got the basics working but the performance starts to drop when I start going above around 500 poi's with markers or 10,000 with circle markers.... if anyone could offer some advise on how to optimize what I've already got or maybe am i best to move to a proper DB like mongo for the json data or do the work server side with Node Js maybe?
Any advice would be much appreciated :)
var apiKey = 'BC9A493B41014CAABB98F0471D759707',
styleID = '108219';
// styleID = '997';
// var map = L.map('map').setView([54.550, -4.433], 7);
var southWest = new L.LatLng(61.029031, 4.746094),
northEast = new L.LatLng(48.786962 ,-13.183594),
bounds = new L.LatLngBounds(southWest, northEast);
var mapcenter = new L.LatLng(53.457393,-2.900391);
var map = new L.Map('map',
{
center: mapcenter,
zoom: 7,
// maxBounds: bounds,
zoomControl: false
});
var cloudmadeUrl = generateTileURL(apiKey, styleID),
attribution = 'Map data © OpenStreetMap contributors.',
tileLayer = new L.TileLayer(
cloudmadeUrl,
{
maxZoom: 18,
attribution: attribution,
});
tileLayer.addTo(map);
var zoomControl = new L.Control.Zoom({ position: 'topleft'} );
zoomControl.addTo(map);
var scaleControl = new L.Control.Scale({ position: 'bottomleft' });
scaleControl.addTo(map);
geojsonLayer = L.geoJson(geojson, {
pointToLayer: function(feature, latlng) {
return new L.CircleMarker(latlng, {fillColor: feature.properties.MarkerColour, fillOpacity: 0.5, stroke: false, radius: 6});
// return new L.Marker(latlng, {icon: L.AwesomeMarkers.icon({icon: feature.properties.MarkerIcon, color: feature.properties.MarkerColour, iconColor: 'white'}) });
},
onEachFeature: function (feature, layer) {
layer.bindPopup( '<strong><b>Customer Data</b></strong><br />' + '<b>Result : </b>' + feature.properties.Result + '<br />' + '<b>Postcode : </b>' + feature.properties.Postcode + '<br />' );
}
});
console.log('starting: ' + window.performance.now());
map.addLayer(geojsonLayer);
console.log('ending: ' + window.performance.now());
function generateTileURL(apiKey, styleID) {
return 'http://{s}.tile.cloudmade/' + apiKey + '/' + styleID + '/256/{z}/{x}/{y}.png';
}
and some sample data :
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.213467,
51.494815
]
},
"properties": {
"DateTime": "1372719435.39",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "W14 8UD"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.389445,
51.512121
]
},
"properties": {
"DateTime": "1372719402.083",
"Result": "Refer for National Serviceability",
"MarkerIcon": "minus-sign",
"MarkerColour": "red",
"Postcode": "UB1 1NJ",
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.411291,
51.508012
]
},
"properties": {
"DateTime": "1372719375.725",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "UB3 3JJ"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-2.11054,
53.500752
]
},
"properties": {
"DateTime": "1372719299.088",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "OL7 9LR",
}
}
I'm currently working on my first real outing using Javascript to build an interactive map of our customer data .
So Far I've got the basics working but the performance starts to drop when I start going above around 500 poi's with markers or 10,000 with circle markers.... if anyone could offer some advise on how to optimize what I've already got or maybe am i best to move to a proper DB like mongo for the json data or do the work server side with Node Js maybe?
Any advice would be much appreciated :)
var apiKey = 'BC9A493B41014CAABB98F0471D759707',
styleID = '108219';
// styleID = '997';
// var map = L.map('map').setView([54.550, -4.433], 7);
var southWest = new L.LatLng(61.029031, 4.746094),
northEast = new L.LatLng(48.786962 ,-13.183594),
bounds = new L.LatLngBounds(southWest, northEast);
var mapcenter = new L.LatLng(53.457393,-2.900391);
var map = new L.Map('map',
{
center: mapcenter,
zoom: 7,
// maxBounds: bounds,
zoomControl: false
});
var cloudmadeUrl = generateTileURL(apiKey, styleID),
attribution = 'Map data © OpenStreetMap contributors.',
tileLayer = new L.TileLayer(
cloudmadeUrl,
{
maxZoom: 18,
attribution: attribution,
});
tileLayer.addTo(map);
var zoomControl = new L.Control.Zoom({ position: 'topleft'} );
zoomControl.addTo(map);
var scaleControl = new L.Control.Scale({ position: 'bottomleft' });
scaleControl.addTo(map);
geojsonLayer = L.geoJson(geojson, {
pointToLayer: function(feature, latlng) {
return new L.CircleMarker(latlng, {fillColor: feature.properties.MarkerColour, fillOpacity: 0.5, stroke: false, radius: 6});
// return new L.Marker(latlng, {icon: L.AwesomeMarkers.icon({icon: feature.properties.MarkerIcon, color: feature.properties.MarkerColour, iconColor: 'white'}) });
},
onEachFeature: function (feature, layer) {
layer.bindPopup( '<strong><b>Customer Data</b></strong><br />' + '<b>Result : </b>' + feature.properties.Result + '<br />' + '<b>Postcode : </b>' + feature.properties.Postcode + '<br />' );
}
});
console.log('starting: ' + window.performance.now());
map.addLayer(geojsonLayer);
console.log('ending: ' + window.performance.now());
function generateTileURL(apiKey, styleID) {
return 'http://{s}.tile.cloudmade./' + apiKey + '/' + styleID + '/256/{z}/{x}/{y}.png';
}
and some sample data :
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.213467,
51.494815
]
},
"properties": {
"DateTime": "1372719435.39",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "W14 8UD"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.389445,
51.512121
]
},
"properties": {
"DateTime": "1372719402.083",
"Result": "Refer for National Serviceability",
"MarkerIcon": "minus-sign",
"MarkerColour": "red",
"Postcode": "UB1 1NJ",
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-0.411291,
51.508012
]
},
"properties": {
"DateTime": "1372719375.725",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "UB3 3JJ"
}
},
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-2.11054,
53.500752
]
},
"properties": {
"DateTime": "1372719299.088",
"Result": "Cable Serviceable",
"MarkerIcon": "ok-sign",
"MarkerColour": "green",
"Postcode": "OL7 9LR",
}
}
Share
Improve this question
edited Sep 29, 2013 at 11:26
Bernie
5,0555 gold badges43 silver badges73 bronze badges
asked Sep 29, 2013 at 11:15
GuitaraholicGuitaraholic
611 silver badge2 bronze badges
2
- Your bottleneck is not the database to show that data. Is it a real szenario to show 500pois in one view or 10,000 circle markers. Or does your question mean the search in database inside a defined bound containing 10000 circle markers? – Bernie Commented Sep 29, 2013 at 11:27
- The current demo versions are dealing in low values of around 500 - 2500... the final version will need to be capable of showing 10,000+ and more data points at a time... I believe the issue with this is due to it doing the rendering on the browser side in real time? Just wondering if there is a different way I could be tackling the scaling issue really – Guitaraholic Commented Sep 29, 2013 at 11:36
1 Answer
Reset to default 7There are a couple of Leaflet plugins that help deal with rendering large amounts of points in the client's browser.
The simplest way is to use a plugin that clusters the markers such as Marker Clusterer. Clusterer helps the rendering on the client side greatly as it means the client puter doesn't have to draw 10,000 points, it just draws 10-40.
You could also do a Heatmap - there are two plugins for that, both based on HTML5 Canvas:
- HeatCanvas
- Heatmap.js