Basically I'm rendering a map of Europe, it is taking all the countries and giving them a colour as far as I can understand from this line of code
.attr("fill", "#348C31") // Color Of Country
when I click a country I can highlight it by using the onclick attrib and the "this" statement like so d3.select(this).style("fill", '#03a5fd');
how would I be able to select multiple countries in this d3.select function to change there color? Any help would be appreciated as I'm confused as to how it can be done.
// Create an Svg variable
const svg = d3.select("svg"),
width = +svg.attr("width")
// Map and projection
const projection = d3.geoNaturalEarth1()
.scale(width / 1.9) // Lower the num closer the zoom
.translate([200, 550]) // (Horizontal, Vertical)
// Load external data from geographic api and use data to project path info from map.
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson").then(function (data) {
svg.append("g")
.selectAll("path")
.data(data.features)
.join("path")
.style("stroke", "white")// Border Lines
.attr("fill", "#348C31") // Color Of Country
.attr("d", d3.geoPath().projection(projection))
You can highlight certain countries based on data, by using a function to set the attribute/style of the element. Since there is no data in the geo-json except the name of the country, the snippet below adds an array selectableCountries that contains some countries to be highlighted. One way of doing this could be to conditionally add a class
selection.classed("selectable", d => selectableCountries.includes(d.properties.name))
Alternatively, one can filter the desired elements using the selection.filter method of d3-selection.
selection.filter(d => selectableCountries.includes(d.properties.name))
.classed("selectable", true)
That way, one can also add event listeners to a subset of the selection
selection.filter(d => selectableCountries.includes(d.properties.name))
.classed("selectable", true)
.on("click", function(event, datum) {})
The datum of the clicked element is passed as a second argument to the click event handler. In the snippet below this is used to highlight the countries with the same first character in the click event handler.
// The svg
const svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
// Map and projection
const projection = d3.geoNaturalEarth1()
.scale(width / 1.3 / Math.PI)
.translate([width / 2, height / 2]);
const geoPath = d3.geoPath().projection(projection);
// Countries that can be clicked on
const selectableCountries = ["USA", "Brazil", "India", "France", "Algeria"];
// Load external data and boot
d3.json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson")
.then(function(data) {
// Draw the map
svg.append("g")
.selectAll("path")
.data(data.features)
.join("path")
.attr("class", "country")
.attr("d", geoPath)
.filter(d => selectableCountries.includes(d.properties.name))
.classed("selectable", true)
.on("click", function(event, datum) {
d3.selectAll("path.highlighted").classed("highlighted", false);
d3.select(this).classed("highlighted", true);
const startCharacter = datum.properties.name[0];
svg.selectAll("path")
.filter(d => d.properties.name[0] === startCharacter)
.classed("highlighted", true);
});
});
.country {
fill: lightgrey;
stroke: white;
cursor: not-allowed;
}
.selectable {
fill: teal;
cursor: pointer;
}
.highlighted {
fill: dimgrey;
}
.selectable.highlighted {
fill: firebrick;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.3.0/d3.min.js"></script>
<h1 id="selected">
No country selected.
</h1>
<svg width="800" height="600"></svg>