简体   繁体   English

d3 + vx反应曲线在每个数据点处平坦

[英]d3 + vx react chart curve flat at each data point

I am trying to build something along the lines of https://dribbble.com/shots/2673159-Funnel-UI-concept/attachments/538068 我正在尝试按照https://dribbble.com/shots/2673159-Funnel-UI-concept/attachments/538068的方式构建一些东西

I've looked through all the curves provided by d3/vx and none of them seem to have the curve happen between each distinct step with the line flat at the data point. 我查看了d3 / vx提供的所有曲线,但似乎没有一个曲线出现在每个不同的步骤之间,并且数据点处的线平坦。 Is there a curve type i'm missing that would look similar to the above? 我是否缺少类似上面的曲线类型? If not and it needs a custom curve, is there somewhere with a more in-depth description of how to implement custom curves than the d3 docs? 如果不是,并且需要自定义曲线,那么在某处是否比d3文档更深入地描述了如何实现自定义曲线?

There is no standard curve that does this; 没有标准曲线可以做到这一点。 however, it may be possible if duplicating adding additional points to coerce a standard d3 curve to be flat where needed. 但是,如果有需要,可以重复添加其他点以强制将标准d3曲线平坦化。 For example, adding points before and after the stage change with the same y value. 例如,在阶段之前和之后添加的点将更改为具有相同的y值。

However, a custom curve could work and avoid the need for data manipulation. 但是,自定义曲线可能会起作用,并且无需进行数据处理。 A bezier curve should do the trick. 贝塞尔曲线应该可以解决问题。 With origin, destination, and control points something like: 具有起点,终点和控制点,例如:

在此处输入图片说明

Image from this codepen 来自此Codepen的图片

To implement this idea we can replace the point function in a standard curve, such as d3.curveLinear with one that draws a bezier curve. 为了实现这一想法,我们可以用绘制贝塞尔曲线的标准曲线替换标准曲线(例如d3.curveLinear)中的点函数。

The point function of d3.curveLinear for comparison: d3.curveLinear的点函数用于比较:

  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: this._context.lineTo(x, y); break;
    }

And the new point function: 和新的点功能:

  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);
        this.x0 = x; this.y0 = y;        
        break;
      case 1: this._point = 2;
      default:  
        var x1 = this.x0 * 0.5 + x * 0.5;
        this._context.bezierCurveTo(x1,this.y0,x1,y,x,y); // bezierCurveTo(controlPoint1X,controlPoint1Y,controlPoint2X,controlPoint2Y,endPointX,endPointY)
        this.x0 = x; this.y0 = y;        
        break;
    }
  }
  return custom;
}

I'm using the same x value for each control point, this might not be ideal as they may not be flat enough at the ends, but it is easily changed 我对每个控制点使用相同的x值,这可能并不理想,因为它们的末端可能不够平坦,但是很容易更改

We can create a custom curve by using d3.curveLinear and substituting in this new point function: 我们可以通过使用d3.curveLinear并替换此新的点函数来创建自定义曲线:

var curve = function(context) {
  var custom = d3.curveLinear(context);
  custom._context = context;
  custom.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);
        this.x0 = x; this.y0 = y;        
        break;
      case 1: this._point = 2;
      default: 
        var x1 = this.x0 * 0.5 + x * 0.5;
        this._context.bezierCurveTo(x1,this.y0,x1,y,x,y); 
        this.x0 = x; this.y0 = y;        
        break;
    }
  }
  return custom;
}

This works easily enough: 这很容易工作:

 var curve = function(context) { var custom = d3.curveLinear(context); custom._context = context; custom.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); this.x0 = x; this.y0 = y; break; case 1: this._point = 2; default: var x1 = this.x0 * 0.5 + x * 0.5; this._context.bezierCurveTo(x1,this.y0,x1,y,x,y); this.x0 = x; this.y0 = y; break; } } return custom; } var data = [ [10,10], [160,50], [310,100] ]; var line = d3.line() .curve(curve); d3.select("svg") .append("path") .attr("d",line(data)); d3.select("svg") .selectAll("circle") .data(data) .enter() .append("circle") .attr("transform", function(d) { return "translate("+d+")"; }) .attr("r",3) 
 path { fill: none; stroke: black; stroke-width:1px; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <svg width="500" height="500"></svg> 

And here's an areal demonstration that draws a funnel for each stage. 这是一个区域演示,它为每个阶段绘制一个漏斗。 Depending on your data this may or may not be preferable. 根据您的数据,这可能会或可能不会是首选。 My fake data is structured by stage, so it is easiest to draw each stage individually. 我的假数据是按阶段构造的,因此最容易分别绘制每个阶段。 Unifying all the stages into one path/area may be a bit more difficult. 将所有阶段统一到一个路径/区域可能要困难一些。

 var curve = function(context) { var custom = d3.curveLinear(context); custom._context = context; custom.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); this.x0 = x; this.y0 = y; break; case 1: this._point = 2; default: var x1 = this.x0 * 0.5 + x * 0.5; this._context.bezierCurveTo(x1,this.y0,x1,y,x,y); this.x0 = x; this.y0 = y; break; } } return custom; } var data = [ {stage:1, start:1,end:0.5}, {stage:2, start:0.5,end:0.2}, {stage:3, start:0.2,end:0.1}, {stage:4, start:0.1,end:0.005} ] var yRangeMax = 100; var y = d3.scaleLinear() .range([yRangeMax,0]); var x = d3.scaleBand() .range([50,400]) .domain(data.map(function(d) { return d.stage; })) var svg = d3.select("svg"); var area = d3.area() .curve(curve) .y1(function(d) { return yRangeMax*2-d[1]; }) .y0(function(d) { return d[1]; }) svg.selectAll(null) .data(data) .enter() .append("path") .attr("d", function(d) { var p1 = [x(d.stage),y(d.start)] var p2 = [x(d.stage)+x.step(),y(d.end)] return area([p1,p2]) }) 
 path{ stroke: #bbb; stroke-width: 1px; fill:#ccc; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script> <svg width="600" height="400"></svg> 

As for guidance on custom curves, there are not a lot of resources that I've seen. 至于自定义曲线的指导,我没有看到很多资源。 However, these answers ( a , b ) might be of some assistance. 但是,这些答案( ab )可能会有帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM