|
// This is a Chiasm component that implements a bubble map. |
|
// Based on chiasm-leaflet. |
|
function BubbleMap() { |
|
|
|
// Extend chiasm-leaflet using composition (not inheritence). |
|
var my = ChiasmLeaflet(); |
|
// my.map is the Leaflet instance. |
|
|
|
// TODO move this into chiasm-component. |
|
my.addPublicProperties = function (publicProperties){ |
|
Object.keys(publicProperties).forEach(function (property){ |
|
my.addPublicProperty(property, publicProperties[property]); |
|
}); |
|
}; |
|
|
|
my.addPublicProperties({ |
|
|
|
// This is the data column that maps to bubble size. |
|
// "r" stands for radius. |
|
rColumn: Model.None, |
|
|
|
// The circle radius used if rColumn is not specified. |
|
rDefault: 3, |
|
|
|
// The range of the radius scale if rColumn is specified. |
|
rMin: 0, |
|
rMax: 10, |
|
|
|
fillColor: "black" |
|
}); |
|
|
|
var rScale = d3.scale.sqrt(); |
|
|
|
// Add a semi-transparent white layer to fade the |
|
// black & white base map to the background. |
|
var canvasTiles = L.tileLayer.canvas(); |
|
canvasTiles.drawTile = function(canvas, tilePoint, zoom) { |
|
var ctx = canvas.getContext('2d'); |
|
|
|
// TODO move opacity to config. |
|
ctx.fillStyle = "rgba(255, 255, 250, 0.85)"; |
|
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height); |
|
} |
|
canvasTiles.addTo(my.map); |
|
|
|
// Generate a function or constant for circle radius, |
|
// depending on whether or not rColumn is defined. |
|
my.when(["data", "rColumn", "rDefault", "rMin", "rMax"], |
|
function (data, rColumn, rDefault, rMin, rMax){ |
|
|
|
if(rColumn === Model.None){ |
|
my.r = function (){ return rDefault}; |
|
} else { |
|
rScale |
|
.domain([0, d3.max(data, function (d){ return d[rColumn]; })]) |
|
.range([rMin, rMax]); |
|
my.r = function (d){ return rScale(d[rColumn]); }; |
|
} |
|
}); |
|
|
|
var oldMarkers = []; |
|
my.when(["data", "r", "fillColor"], _.throttle(function (data, r, fillColor){ |
|
|
|
oldMarkers.forEach(function (marker){ |
|
my.map.removeLayer(marker); |
|
}); |
|
|
|
// TODO move these to config. |
|
var latitudeColumn = "latitude"; |
|
var longitudeColumn = "longitude"; |
|
|
|
oldMarkers = data.map(function (d){ |
|
|
|
var lat = d[latitudeColumn]; |
|
var lng = d[longitudeColumn]; |
|
var markerCenter = L.latLng(lat, lng); |
|
var circleMarker = L.circleMarker(markerCenter, { |
|
color: fillColor, |
|
weight: 1, |
|
|
|
// TODO move this to config. |
|
fillOpacity: 1, |
|
opacity: 0, |
|
weight: 0, |
|
clickable: true |
|
}); |
|
circleMarker.setRadius(r(d)); |
|
|
|
circleMarker.addTo(my.map) |
|
.bindPopup([ |
|
d.name + " - " + d.deaths + " death" + (d.deaths > 1 ? "s" : ""), |
|
d.note, |
|
"source: " + "<a href=\"" + d.source_url + "\">" + d.source_name + "</a>" |
|
].join("<br>")); |
|
|
|
//if(d.name === "Le Petit Cambodge"){ |
|
// circleMarker.openPopup(); |
|
//} |
|
|
|
return circleMarker; |
|
}); |
|
}, 100)); |
|
|
|
return my; |
|
} |