observablehq / plot

A concise API for exploratory data visualization implementing a layered grammar of graphics
https://observablehq.com/plot/
ISC License
4.3k stars 175 forks source link

Rounded corners on rect, but only for some corners #2054

Closed mbostock closed 2 months ago

mbostock commented 5 months ago

As originally suggested in #1201, this is a common request, and the workaround isn’t always feasible (for example with diverging bars).

image

Fil commented 5 months ago

Thinking about this has sent me into a rabbit hole. Two issues:

1) how do we name this option (maybe "high-end radius—rh"—knowing that high will be bottom for negative values, right for horizontal bars and left for horizontal-negative)? 2) instead of a svg:rect we'll now have a generic svg:path. We can do one that just implements rh (if not nullish[1]), and keep it at this.

But there might be future use cases (some we already have in mind) where the element we create is completely different: what if, for example, if we want bars that follow a radial coordinate system (#133). (Or even, marks that are rendered with the same visual logic but using canvas instead of SVG…)

So, while we can implement this with a simple test like (rh != null ? "rect" : "path") (and maybe we should, I can put up a PR for this anyway), it's also tempting to take this as an opportunity to think more globally about how we'd want to be able to pass new "visual materializers" to marks.

[1] I'd want an explicit rh: 0 to opt-in to a svg:path, in order to make it possible to transition from rh=0 to rh=5 without discontinuity.

mbostock commented 5 months ago

Hmm, one possibility is an ry2 option that rounds the corners corresponding to the y2 edge. Then you could have similar options ry1, rx1, rx2 for the other sides — but you’d have to define which side takes precedence since the sides would compete for the corners.

Another possibility is separate radii for each corner, like CSS does for border-radius (which also supports elliptical corners!).

Complicated!

Fil commented 3 months ago

I'm going to give up on that one, because a clean generalization with all the possibilities is just too much work — too many "corner" cases, for a limited usage. Instead let's create examples to show how to use a render transform?

For instance: https://observablehq.com/@observablehq/dog-eared-bars (although the implementation is not optimal since it creates rects then discards them… I find it easier that way).