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

curveStep.radius?

Open mbostock opened this issue 9 years ago • 10 comments

From d3/d3#2864 by @lgrkvst, it might be nice to support a radius for rounded corners on d3.curveStep and related curves. Example:

image

The radius would probably need to be constant for the whole curve, although it’s interesting to speculate whether it could also be defined per-point.

mbostock avatar Jun 24 '16 20:06 mbostock

On a side note, I noticed interpolate("step") does listen to tension, with the effect of steps aligning perfectly half-way between points – no doubt a(n undocumented) feature.

A constant radius would most likely dominate use-cases, however how should the function handle radii that exceed the shortest vector component between two points?

lgrkvst avatar Jun 25 '16 18:06 lgrkvst

If the desired radius is too big to fit, reduce it to fit; arcs use a similar strategy with arc.cornerRadius as shown in the arc corners animation.

mbostock avatar Jun 25 '16 20:06 mbostock

Wow, mesmerizing example...

On another side note, I'm using arc.cornerRadius in my rest-loaded sunburst menu. d3-sunburst-menu

I've noticed the arc.cornerRadius implementation tends to flicker when used on sunbursts with exactly two partitions. Cosmetics, so I haven't gotten around to exploring the bug further.

lgrkvst avatar Jun 26 '16 11:06 lgrkvst

You’re still using D3 3.x; the flickering has been fixed in 4.0.

mbostock avatar Jun 26 '16 15:06 mbostock

I've made an attempt at an implementation. ~~My question is whether the parameter really should be .tension. That term is better aligned with the cardinal implementation, however .radius is more straight-forward in describing what to actually pass in the function call (at least in my implementation below).~~ EDIT: realised Mike's six months ahead of me as usual – the tension discussion was closed in June last year.

Thoughts?

lineEnd: function() {
    if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
    if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
    if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
  },
  point: function(x, y) {
    x = +x, y = +y;
    switch (this._point) {
      case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
      case 1: this._point = 2; // proceed
      default: {
        if (this._t <= 0) {
          this._context.arcTo(this._x, y, this._x-this._tension, y, this._tension);
          this._context.lineTo(x, y);
        } else {
          var x1 = this._x * (1 - this._t) + x * this._t;
          if (this._y < y-this._tension) {
            this._context.arcTo(x1, this._y, x1, this._y+this._tension, this._tension);
            if (0 < this._t && this._t < 1) this._context.arcTo(x1, y, x1-this._tension, y, this._tension);
            else this._context.lineTo(x, y);
          } else if (this._y > y+this._tension) {
            this._context.arcTo(x1, this._y, x1, this._y-this._tension, this._tension);
            if (0 < this._t && this._t < 1) this._context.arcTo(x1, y, x1-this._tension, y, this._tension);
            else this._context.lineTo(x, y);
          } else {
            this._context.lineTo(x, y);
          }
        }
        break;
      }
    }
    this._x = x, this._y = y;
  }

lgrkvst avatar Mar 02 '17 17:03 lgrkvst

I am using step graph and wants to change corner radius like above design, I applied this above given code in step.js but not getting expected result. So how can I get this can I get this rounded corner radius in my step graph.

satyamkuril143 avatar Mar 22 '20 21:03 satyamkuril143

The following step function works for d3-shape 1.0.4. It needs some attention to play with the current version (1.3.7).

export function Step(context, t, radius) {
  this._context = context;
  this._t = t;
  this._radius = radius;
}

Step.prototype = {
  areaStart: function() {
    this._line = 0;
  },
  areaEnd: function() {
    this._line = NaN;
  },
  lineStart: function() {
    this._x = this._y = NaN;
    this._point = 0;
  },
  lineEnd: function() {
    if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
    if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
    if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
  },
  point: function(x, y) {
    x = +x, y = +y;
    switch (this._point) {
      case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
      case 1: this._point = 2; // proceed
      default: {
        if (this._t <= 0) {
          this._context.arcTo(this._x, y, this._x-this._radius, y, this._radius);
          this._context.lineTo(x, y);
        } else {
          var x1 = this._x * (1 - this._t) + x * this._t;
          if (this._y < y-this._radius) {
            this._context.arcTo(x1, this._y, x1, this._y+this._radius, this._radius);
            if (0 < this._t && this._t < 1) this._context.arcTo(x1, y, x1-this._radius, y, this._radius);
            else this._context.lineTo(x, y);
          } else if (this._y > y+this._radius) {
            this._context.arcTo(x1, this._y, x1, this._y-this._radius, this._radius);
            if (0 < this._t && this._t < 1) this._context.arcTo(x1, y, x1-this._radius, y, this._radius);
            else this._context.lineTo(x, y);
          } else { // ∆y < radius
              this._context.lineTo(x, y);
          }
        }
        break;
      }
    }
    this._x = x, this._y = y;
  }
};

export default (function custom(radius) {

  function step(context) {
    return radius ? new Step(context, 0.5, radius) : new Step(context, 0.5, 0);
  }

  step.radius = function(radius) {
    return custom(+radius);
  };

  return step;
})(0);

This is how I invoke it: d3.curveStepBefore.radius(10)

lgrkvst avatar Mar 23 '20 11:03 lgrkvst

Thank's for help, I applied this code and it is working fine, I need one more help, actually the curve is appearing on right side of step, can we make it to appear both the side's?

satyamkuril143 avatar Mar 25 '20 06:03 satyamkuril143

Thanks for this @lgrkvst

So your example here is really close to what I'm after, but I see that the lines are oriented left of the nodes instead of right. Do you have any ideas of how I can solve this please?

Many thanks!

image

brettsprads avatar Jun 30 '24 15:06 brettsprads