async function ChoroplethMap(
geoJSON,
{
width = 800,
height = 600,
scale = d3.scaleSequential,
interpolator = d3.interpolateBlues,
id = null,
idFeatures = null,
value = null,
projection = d3.geoEquirectangular,
stroke = "black",
strokeWidth = 0.5,
colorLegendOptions = { title: null },
fill = null,
features = geoJSON.features,
tooltip = () => "",
topoJSONObject = geoJSON.objects ? Object.keys(geoJSON.objects)[0] : null
} = {}
) {
if (geoJSON.type === "Topology") {
geoJSON = topojson.feature(geoJSON, geoJSON.objects[topoJSONObject]);
features = geoJSON.features;
}
let data = Array.isArray(geoJSON) ? geoJSON : geoJSON.features;
let f = scale(interpolator);
if (!value) {
const quantProperty = findAttribute(
Array.isArray(geoJSON) ? data[0] : data[0].properties,
{
numeric: true
}
);
if (quantProperty) {
value = (d) => d.properties[quantProperty];
colorLegendOptions.title = quantProperty;
} else {
fill = "none";
}
}
if (value) {
if (id) {
const valuesArray = data.map((d) => [id(d), +value(d)]);
f = scale(interpolator).domain(d3.extent(valuesArray.map((d) => d[1])));
let mapValues = new Map(valuesArray);
if (!idFeatures) idFeatures = id;
if (!fill) {
fill = (d) => f(mapValues.get(idFeatures(d)));
}
} else {
f = scale(interpolator).domain(d3.extent(features, value));
if (!fill && value) {
fill = (d) => f(value(d));
}
}
}
const path = d3.geoPath().projection(
projection().fitSize([width, height], {
type: "FeatureCollection",
features
})
);
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", width);
svg
.selectAll("path")
.data(features)
.join("path")
.attr("stroke", stroke)
.attr("stroke-width", strokeWidth)
.attr("fill", fill)
.attr("d", path)
.attr("tooltip", tooltip)
.call((path) => path.join("title").append("title").text(tooltip));
const zoom = d3.zoom().on("zoom", (event) => {
svg.selectAll("path").attr("transform", event.transform);
});
svg.call(zoom);
const legend = await Legend(f, colorLegendOptions);
return html`<div>
${svg.node()}
${legend}
</div>`;
}