first stab at marker clusters done in web workers
xxxxxxxxxx
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=1024, user-scalable=no">
<style>
html { height: 100% }
body { height: 100%; margin: 0; padding: 0;}
#map{ height: 100% }
</style>
<link rel="stylesheet" href="https://cdn.leafletjs.com/leaflet-0.5.1/leaflet.css" />
<title>Clusters</title>
<div id="map"></div>
<script src="https://d3js.org/d3.v3.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.5.1/leaflet.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/mbostock/d3/5348d911938a0d1fdf43d7c86befbd908e431204/lib/colorbrewer/colorbrewer.js"></script>
<script src="https://cdn.jsdelivr.net/gh/caligatio/jssha/release-1.42/src/sha1.js"></script>
<script>
var m = L.map("map").setView([42.3164, -71.7],9);
//make the map
L.tileLayer("https://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg",{minZoom:4,maxZoom:12,attribution:'Map tiles by <a href="https://stamen.com">Stamen Design</a>, <a href="https://creativecommons.org/licenses/by/3.0">CC BY 3.0</a> — Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'}).addTo(m);
//add a tileset
var pts = L.layerGroup().addTo(m);
function Rtree(points,cb){
points = points || [];
var worker = new Worker('myWorker.js');
worker.onmessage=function(event){
cb(event.data);
};
worker.postMessage({action:"create",points:points});
this.add = function(pts){
worker.postMessage({action:"add",points:pts});
};
this.bbox=function(blat1,blng1,blat2,blng2){
worker.postMessage({action:"bbox",bounds:[blat1,blng1,blat2,blng2]});
};
this.cluster=function(blat1,blng1,blat2,blng2){
console.log({action:"cluster",bounds:[blat1,blng1,blat2,blng2],size:[m.getSize().y,m.getSize().x,80]});
worker.postMessage({action:"cluster",bounds:[blat1,blng1,blat2,blng2],size:[m.getSize().y,m.getSize().x,80]});
};
}
var qt, bbox;
function morePoints(lat,lng){
//compute random points
var randomLat = d3.random.normal(lat, .15),
randomLng = d3.random.normal(lng, .5);
var points = d3.range(600).map(function() { return [randomLat(), randomLng()]; });
if(!qt){//if we don't have a quad tree make one
qt = new Rtree(points,redoMap);
}else{
//else add it to the current
qt.add(points);
}
redoBox(bbox);// update the map
}
function getHash(text){
//this is very much overkill but to make sure the same random style goes in everytime
var shaObj = new jsSHA(text, "TEXT");
return parseInt(shaObj.getHash("SHA-1", "HEX").slice(0,10),16)%11;
}
function redoBox(p){
p=p||[parseFloat(m.getBounds().toBBoxString().split(",")[1]),parseFloat(m.getBounds().toBBoxString().split(",")[0]),parseFloat(m.getBounds().toBBoxString().split(",")[3]),parseFloat(m.getBounds().toBBoxString().split(",")[2])];//make sure p is defined
bbox=p;//update the bbox
qt.cluster.apply(qt,p);
}
var p;
function redoMap(event){
if(!Array.isArray(event)){
p=event;
pts.clearLayers();
event.points.forEach(function(v){//do the query
pts.addLayer(L.circleMarker(v,{stroke:false,fillOpacity:0.8,radius:6,color:colorbrewer.Spectral[11][getHash(JSON.stringify(v))],clickable:false}));//turn it into a marker wiht a popup
});
event.clusters.forEach(
function(v){//do the query
pts.addLayer(
L.polygon(v[1],{stroke:false,fillOpacity:0.8,color:colorbrewer.Spectral[11][getHash(JSON.stringify(v))]}
).bindPopup("size: "+v[0])
);//turn it into a marker wiht a popup
}
)
return;
}
pts.clearLayers();//clear the map
event.forEach(function(v){//do the query
pts.addLayer(L.circleMarker(v,{stroke:false,fillOpacity:0.8,color:colorbrewer.Spectral[11][getHash(JSON.stringify(v))],clickable:false}));//turn it into a marker wiht a popup
});
}
m.on("contextmenu moveend",function(){redoBox()});//so you can right click to add to map
var AddButton= L.Control.extend({//creating the buttons
options: {
position: 'bottomleft'
},
onAdd: function (map) {
// create the control container with a particular class name
var div = L.DomUtil.create('div','bgroup');
var addButton = L.DomUtil.create('button', 'addStuff',div);
addButton.type="button";
addButton.innerHTML="Add More Points";
L.DomEvent.addListener(addButton,"click",function(){
morePoints(map.getCenter().lat,map.getCenter().lng);//make sure it's where you currently are.
});
morePoints(map.getCenter().lat,map.getCenter().lng);
return div;
}
});
//add them to the map
m.addControl(new AddButton());
//this is the box selection thingy
var BoxSelect = L.Map.BoxZoom.extend({
_onMouseUp: function (e) {
this._pane.removeChild(this._box);
this._container.style.cursor = '';
L.DomUtil.enableTextSelection();
L.DomEvent
.off(document, 'mousemove', this._onMouseMove)
.off(document, 'mouseup', this._onMouseUp);
var map = this._map,
layerPoint = map.mouseEventToLayerPoint(e);
if (this._startLayerPoint.equals(layerPoint)) { return; }
var bounds = new L.LatLngBounds(
map.layerPointToLatLng(this._startLayerPoint),
map.layerPointToLatLng(layerPoint));
map.fire("boxselectend", {
boxSelectBounds: [bounds.getSouthWest().lat,bounds.getSouthWest().lng,bounds.getNorthEast().lat,bounds.getNorthEast().lng]
});
}
});
m.boxZoom.disable();//turn off the defult behavior
var boxSelect = new BoxSelect(m);//new box select
boxSelect.enable();//add it
m.on("boxselectend",function(e){redoBox(e.boxSelectBounds);});//put the behavior in.
</script>
Modified http://d3js.org/d3.v3.js to a secure url
Modified http://cdn.leafletjs.com/leaflet-0.5.1/leaflet.js to a secure url
Updated missing url https://raw.github.com/mbostock/d3/5348d911938a0d1fdf43d7c86befbd908e431204/lib/colorbrewer/colorbrewer.js to https://cdn.jsdelivr.net/gh/mbostock/d3/5348d911938a0d1fdf43d7c86befbd908e431204/lib/colorbrewer/colorbrewer.js
Updated missing url https://raw.github.com/Caligatio/jsSHA/release-1.42/src/sha1.js to https://cdn.jsdelivr.net/gh/caligatio/jssha/release-1.42/src/sha1.js
https://d3js.org/d3.v3.js
https://cdn.leafletjs.com/leaflet-0.5.1/leaflet.js
https://raw.github.com/mbostock/d3/5348d911938a0d1fdf43d7c86befbd908e431204/lib/colorbrewer/colorbrewer.js
https://raw.github.com/Caligatio/jsSHA/release-1.42/src/sha1.js