1

I've got a choropleth map working with D3 on Observable. When the user mouses over a country, the border (path) is redrawn in red. I'd like to make this border extend on the interior of the path.

Here is the page: https://observablehq.com/d/33b758c361e919e8

This question is similar to Simple way to use existing object as a clipping path? with the difference that the clipping path needs to be set for each country individually. I'm just not sure how to handle that.

In an ideal world I would use the SVG Strokes extension to simply draw the stroke on the inside of the path, as discussed here: Can you control how an SVG's stroke-width is drawn?

Theo H
  • 131
  • 10
  • Do you need one `` for every country -- or could you just create one for the whole svg, that gets set on hover before you call `d3.select(this).attr("stroke", "red").raise();`? – anbnyc Feb 22 '21 at 22:07
  • I think it makes sense to create all the clip paths using D3 at the same time as the country paths are created. There must be an easy way to do this. That is the point at which the data of country outlines is imported, anyway. Then it is just a question of referring to those clip paths, which presumably will have unique ids. – Theo H Feb 23 '21 at 21:27
  • So in that case you could just create one `clipPath` per country inside your `svg` by binding them to your data, the same way you create your `path`s. – anbnyc Feb 24 '21 at 01:33
  • That's exactly what I don't know how to do. – Theo H Feb 25 '21 at 17:51

1 Answers1

0

I think I've essentially solved this problem by adding clipPath elements which refer to the previous paths (with the "use" tag).

   svg
    .append("g")
    .attr("id", "map")
    .selectAll("path")
    .data(topojson.feature(world, world.objects.countries).features)
    .join("path")
    .attr("class", "country")
    .attr("fill", d => color(value.get(d.properties.name)))
    .attr("id", d => `${d.id}`)
    .attr("d", path);
  
  svg
    .append("g")
    .selectAll("clipPath")
    .data(topojson.feature(world, world.objects.countries).features)
    .join("clipPath")
    .attr("id", d => `${d.id}_clip`)
    .append("use")
    .attr("xlink:href", d => new URL(`#${d.id}`, location))
Theo H
  • 131
  • 10