插值后访问d3.line的y值 [英] Access y value of a d3.line after interpolation

查看:36
本文介绍了插值后访问d3.line的y值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 curveMonotoneX 插值绘制一条简单的线:

I am drawing a simple line using the curveMonotoneX interpolation :

  const line = d3
    .line()
    .x((_, i) => xScale(i))
    .y(d => yScale(d))
    .curve(d3.curveMonotoneX);

除此之外,我想在有实际数据的线上添加点.由于进行了插值,我绘制的点并不完全在直线上,所以我切换到 d3.curveLinear ,而我的问题就消失了.

Besides that, I wanted to add points on the line where there is actual data. Because of the interpolation, the points I drawn were not exactly on the line so I switched to d3.curveLinear and my issues were gone.

但是,我想知道是否有一种现成的方法可以使用 x 值访问行的 y 值?

However, I was wondering is there a ready-to-use method to access the y value of a line using the x value ?

这样,无论插值方法如何,都可以在直线上绘制点.

This way, one could draw the points on the line regardless of the interpolation method.

推荐答案

下面是一个简单的示例,其中包装了代码

Here's a quick example, wrapping the code here into a reusable function. It places a bunch of points on a fitted curve.

<!DOCTYPE html>
<meta charset="utf-8">

<style type="text/css">
  .line {
    fill: none;
    stroke: orange;
    stroke-width: 2;
  }
  
  .overlay {
    fill: none;
    pointer-events: all;
  }
  
  .dot {
    fill: steelblue;
    stroke: #fff;
  }
  
</style>


<body>

<!-- Load in the d3 library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
  var margin = {
      top: 50,
      right: 50,
      bottom: 50,
      left: 50
    },
    width = window.innerWidth - margin.left - margin.right,
    height = window.innerHeight - margin.top - margin.bottom;

  var xScale = d3.scaleLinear()
    .domain([0, 9])
    .range([0, width]);

  var yScale = d3.scaleLinear()
    .domain([0, 10])
    .range([height, 0]);


  var line = d3.line()
    .x(function(d, i) {
      return xScale(i);
    })
    .y(function(d) {
      return yScale(d);
    })
    .curve(d3.curveBasis);

  var dataset = d3.range(10).map(function(d) {
    return d3.randomUniform(1)() * 10;
  })

  var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale));

  svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));
    
  var path = svg.append("path")
    .datum(dataset)
    .attr("class", "line")
    .attr("d", line);
    
  svg.selectAll(".dot")
    .data(d3.range(0, 9.5, 0.5))
    .enter()
    .append("circle")
    .attr("cx", (d) => xScale(d))
    .attr("cy", (d) => yValueForX(d))
    .attr("r", 5)
    .attr("class", "dot")
    
  function yValueForX(xCor){
    var x = xScale(xCor),
        pathEl = path.node(),
        pathLength = pathEl.getTotalLength(); 
        
    var beginning = x, end = pathLength, target;
    while (true) {
      target = Math.floor((beginning + end) / 2);
      pos = pathEl.getPointAtLength(target);
      if ((target === end || target === beginning) && pos.x !== x) {
          break;
      }
      if (pos.x > x)      end = target;
      else if (pos.x < x) beginning = target;
      else                break; //position found
    }
    
    return pos.y;
  }
    
    
</script>

</body>

这篇关于插值后访问d3.line的y值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆