Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

curveStep.radius? #74

Open
mbostock opened this issue Jun 24, 2016 · 10 comments
Open

curveStep.radius? #74

mbostock opened this issue Jun 24, 2016 · 10 comments

Comments

@mbostock
Copy link
Member

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.

@lgrkvst
Copy link

lgrkvst commented Jun 25, 2016

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?

@mbostock
Copy link
Member Author

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.

@lgrkvst
Copy link

lgrkvst commented Jun 26, 2016

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.

@mbostock
Copy link
Member Author

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

@lgrkvst
Copy link

lgrkvst commented Mar 2, 2017

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;
  }

@satyamkuril143
Copy link

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.

@lgrkvst
Copy link

lgrkvst commented Mar 23, 2020

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)

@satyamkuril143
Copy link

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?

@brettsprads
Copy link

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

@anhtuanlee
Copy link

anhtuanlee commented Oct 2, 2024

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;
            default: {
                var x1, y1;
                if (this._t <= 0) {
                    this._context.arcTo(this._x, y, this._x - this._radius, y, this._radius);
                    this._context.lineTo(x, y);
                } else {
                    // Intermediate inference content between previous point and current point
                    x1 = this._x * (1 - this._t) + x * this._t;
                    y1 = this._y * (1 - this._t) + y * this._t;

                    // check angle
                    if (this._y < y - this._radius) {
                        // (Top to Bottom Arc)
                        this._context.arcTo(this._x, this._y, x, y1, this._radius);
                    } else if (this._y > y + this._radius) {
                        //  (Bottom to Top Arc)
                        this._context.arcTo(this._x, this._y, x, y1, this._radius);
                    } else if (this._x < x - this._radius) {
                        // (Left to Right Arc)
                        this._context.arcTo(this._x, this._y, x1, y, this._radius);
                    } else if (this._x > x + this._radius) {
                        //   (Right to Left Arc)
                        this._context.arcTo(this._x, this._y, x1, y, this._radius);
                    } else {
                        //  spacing lower with radiant draw line
                        this._context.lineTo(x, y);
                    }
                }
                break;
            }
        }
        this._x = x, this._y = y;
    }
};

stepRound = function (context) {
    radius = 100
    return new Step(context, 0.5, radius);
}; 


// And here i was used 

 const line = d3.line()
            .x(d => d.x)
            .y(d => d.y)
            .curve(stepRound);

I have same problem, and i was found solution in 2days. It depend of code of @lgrkvst , tks u so much.

Hope will help another go after

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

5 participants