d3-shape icon indicating copy to clipboard operation
d3-shape copied to clipboard

add optional angle radius parameter in curbeBezier `curveStep` curves

Open njourdane opened this issue 1 year ago • 4 comments

Following #177, as suggested in https://github.com/d3/d3-shape/pull/177#issuecomment-809936541, it could be useful to have a curve similar to curveStep but with smooth angles:

image

An important note is that the curve angle should be identical whatever its length. This way we don't see curves duplication on nodes with many child of various link length:

image

~~Those curves could be named curbeBezierX and curbeBezierY as suggested in this example.~~

In fact, I think those curves could be included in curveStep, by adding an extra optional parameter allowing to define the angle radius, which is 0 by default.

This will also allow some customization. This is for instance large angle (ie curveStep(15)) and small angle (ie curveStep(5)) stepCurves, respectively:

image image

Some other visuals to get the idea:

curveStep(10)

image image

curveStepBefore(10)

image image

curveStepAfter(10)

image image

Edit: as pointed out by @Fil, the curve horizontal and vertical distance might be lower than twice the angle radius. In that case the radius remains the same, but angles stops before 90° in order to share the same tangential line. Example with several curves formed with curveStep(20), tangential line in red:

image

njourdane avatar Jul 09 '23 09:07 njourdane

Nice! Note that you need the difference in x and the difference in y to be greater than twice the radius—the spec should also describe what to do when it's smaller.

Fil avatar Jul 10 '23 05:07 Fil

Good point! I edited the issue.

njourdane avatar Jul 10 '23 08:07 njourdane

We'll need to specify all the cases :)

pseudo code:

move to x1,y1
xa = (x1+x2)/2; // x1+r if stepBefore, x2-r if stepAfter
ya = (y1+y2)/2;
sx = Math.sign(x2-x1); 
sy = Math.sign(y2-y1); 
if (|x2-x1| > 2r && |y2-y1| > 2r):
  line to xa - sx * r, y1 
  arc to xa, y1 + sy * r
  line to xa, y2 - sy * r
  arc to xa + sx * r, y2
  line to x2, y2
else if (|x2-x1| > 2r)
  … // line + bezier + line?
else if (|y2-y1| > 2r)
  … // ?? smaller r?
else
  ... // bezier ??

Fil avatar Jul 10 '23 08:07 Fil

Does that image cover all the cases?

image

njourdane avatar Jul 10 '23 09:07 njourdane