A Leaflet tutorial uses the following hard-coded getColor
function to return colors.
// get color function getColor(n) { return n > 30 ? '#b10026' : n > 25 ? '#e31a1c' : n > 25 ? '#fc4e2a' : n > 20 ? '#fd8d3c' : n > 15 ? '#feb24c' : n > 10 ? '#fed976' : n > 5 ? '#ffeda0' : n > 0 ? '#ffffcc' : '#ffffff'; }
However, I wanted to use Chroma.js to generate the legend colors dynamically. So I needed a new getColor
function.
Chroma.js has a variety of methods to return colors. The one I choose was using scale and classes. These can then be sent as variables to a getColor
function to return colors to use in legend and map.
scale can be single value or an array of two colors (either as hex values or color words). In my case, the first is a light blue and the second is a darker blue. Chroma.js will then return gradients between these two colors. See colorHex variable below.
classes is an array of legend ‘breaks’ for the color gradients. For example they could be the numerical values from the Leaflet tutorial getColor
function above (eg 10, 20, 50, etc). See classBreaks variable below.
The new getColor
function is shown below:
var classBreaks = [1,50,100,250,500,1000,2000,3000,6000,9000]; var colorHex = ['#deebf7','#08306b']; function getColor(n,classBreaks,colorHex) { var mapScale = chroma.scale(colorHex).classes(classBreaks); if (n === 0) { var regionColor = '#ffffff'; } else { var regionColor = mapScale(n).hex(); } return regionColor }
This getColor
function can then be used as described in the Leaflet tutorial to set choropleth polygon fill colors. It also be used similarly to create the legend by looping through the classes to get a color for each legend entry.
However there is important consideration when creating the legend. Using scale and classes, Chroma.js only returns classes – 1 colors. For example the variable classBreaks array with 10 elements will only return 9 colors. To hack this I push a dummy element (‘999’) to the array so Chroma.js would return 10 colors and then ignore the dummy element when creating the legend.
The legend code is below includes hard-coded zero (0) value set to color white (#ffffff). Looping through the classBreaks each time using getColor
function to return legend color based on break value.
var legend = L.control({position: 'topright'}); legend.onAdd = function (map) { var div = L.DomUtil.create('div', 'legend'); div.innerHTML += '<i style="background: #ffffff;"></i>0 '; classBreaks.push(999); // add dummy class to extend to get last class color, chroma only returns class.length - 1 colors for (var i = 0; i < classBreaks.length; i++) { if (i+2 === classBreaks.length) { div.innerHTML += '<i style="background: ' + getColor(classBreaks[i], classBreaks, colorHex) + ';"></i> ' + classBreaks[i] + '+'; break } else { div.innerHTML += '<i style="background: ' + getColor(classBreaks[i], classBreaks, colorHex) + ';"></i> ' + classBreaks[i] + '–' + classBreaks[i+1] + '<br>'; } } return div; }; legend.addTo(map);
The final map legend looks like this:
Hi Curtis,
thanks for the tutorial. I tried your code on my map but get error saying “mapScale is not a function”. The error is related to the line var mapScale = chroma.scale(colorHex).classes(classBreaks);
Do you know what I can do to solve the problem? Any help will be much appreciated.
Best regards,
Tim
Hi Tim,
Check that the variables used in getColor function and mapScale variable eg “n,classBreaks,colorHex” are what is expected eg n = integer and classBreaks and colorHex are arrays.
Here is result from my page:
console.log(“n:”, n,”classBreaks:”,classBreaks,”colorHex:”, colorHex,”regionColor:”, regionColor);
n: 156 classBreaks: (10) [1, 50, 100, 250, 500, 1000, 2000, 3000, 6000, 9000] colorHex: (2) [“#deebf7”, “#08306b”] regionColor: #a9bcd4
FYI, here is the code in action on functioning web page https://sitrucp.github.io/canada_covid_health_regions/canada.js.
Curtis
Hi Curtis,
thanks for your reply. I solved the problem:
as I am an html newbie, I forgot to change the input at the “fillColor: getColor” function to the required inputs from your function.
Think before you copy code I guess…
Tim
Me again… Not all is good I guess. I can’t seem to get rid of the extra class in the upper right hand corner. Would you help me out one more time?
https://ibb.co/k3C9rNf
Thanks,
Tim
Looks like it is working fine but my code was missing a line break at the end of if then statement which should fix that!
The original post had it but seems WordPress interpreted it as an actual line break and not something I want to show as code.
Never noticed this before. Weird.
Code now updated!
classBreaks[i] + '–' + classBreaks[i+1] + '';
should be
classBreaks[i] + '–' + classBreaks[i+1] + 'put line break here';