使用d3.js定位x轴和y轴

3
我现有的方法可以工作,但我想知道是否有更好的方法。
我将这个页面作为我的工作示例。源代码在这里,这个问题具体涉及绘制带正负值的x轴和y轴。
我有一个drawAxes方法,看起来像这样:
  drawAxes(data) {
    const xAxis = d3.svg.axis()
            .scale(this.xScale);

    const yAxis = d3.svg.axis()
            .orient('left')
            .scale(this.yScale);

    const dimensions = this.getDimensions();

    this.xScale.domain(d3.extent(data, (d) => d.x));

    const minY = d3.min(data, (d) => d.y);
    const maxY = d3.max(data, (d) => d.y);

    const nonNegativeXAxis = minY >= 0 && maxY >= 0;
    const positiveAndNegativeXAxis = minY < 0 && maxY > 0;

    let yScaleDomain, xAxisPosition;

    if(nonNegativeXAxis) {
      yScaleDomain = [0, d3.max(data, (d) => d.y)];
    }  else {
      yScaleDomain = d3.extent(data, (d) => d.y);
    }

    this.yScale.domain(yScaleDomain);

    const findZeroTick = (data) => {
      return data === 0;
    };

    this.svg.append('g')
      .attr('class', 'axis y-axis')
      .style('visibility', 'hidden')
      .call(yAxis);

    if(nonNegativeXAxis) {
      yScaleDomain = [0, d3.max(data, (d) => d.y)];
      xAxisPosition = dimensions.height;
    } else if(positiveAndNegativeXAxis) {
      xAxisPosition = this.svg.selectAll(".tick").filter(findZeroTick).map((tick) => {
        return d3.transform(d3.select(tick[0]).attr('transform')).translate[1];
      });
    } else {
      yScaleDomain = d3.extent(data, (d) => d.y);
      xAxisPosition = 0;
    }

    this.svg.append('g')
      .attr('class', 'axis x-axis')
      .attr('transform', `translate(0, ${xAxisPosition})`)
      .call(xAxis);

    d3.select('.y-axis').remove();

    const minX = d3.min(data, (d) => d.x);
    const maxX = d3.max(data, (d) => d.y);

    const positiveXOnly = minX > 0 && maxX > 0;
    const negativeXOnly = minX < 0 && maxX < 0;

    let yAxisPosition;

    if(positiveXOnly) {
      yAxisPosition = 0;
    } else if(negativeXOnly) {
      yAxisPosition = dimensions.width;
    } else {
      yAxisPosition = this.svg.selectAll(".x-axis .tick").filter(findZeroTick).map((tick) => {
        return d3.transform(d3.select(tick[0]).attr('transform')).translate[0];
      });
    }

    this.svg.append('g')
      .attr('class', 'axis y-axis')
      .attr('transform', `translate(${yAxisPosition}, 0)`)
      .call(yAxis);
  }

在进行y轴和x轴相反方向的0位置定位时,我遇到了很大的困难。
我的做法是首先绘制y轴,但将其隐藏起来:
this.svg.append('g')
  .attr('class', 'axis y-axis')
  .style('visibility', 'hidden')
  .call(yAxis);

我随后通过选择所有的刻度并找到0刻度的y坐标来确定y轴上的位置,我使用这个值来定位x轴:

const findZeroTick = (data) => {
  return data === 0;
};

xAxisPosition = this.svg.selectAll(".tick").filter(findZeroTick).map((tick) => {
  return d3.transform(d3.select(tick[0]).attr('transform')).translate[1];
});

this.svg.append('g')
  .attr('class', 'axis x-axis')
  .attr('transform', `translate(0, ${xAxisPosition})`)
  .call(xAxis);

要定位y轴,我首先移除y轴,然后通过选择x轴上的所有刻度线进行类似的计算,然后再添加y轴,并使用检索到的值来定位y轴。
d3.select('.y-axis').remove();

yAxisPosition = this.svg.selectAll(".x-axis .tick").filter(findZeroTick).map((tick) => {
  return d3.transform(d3.select(tick[0]).attr('transform')).translate[0];
});

this.svg.append('g')
  .attr('class', 'axis y-axis')
  .attr('transform', `translate(${yAxisPosition}, 0)`)
  .call(yAxis);

有没有更有效的方法来实现相同的结果或者说,我能否在不删除和重新添加轴的情况下移动它?


顺便提一下,如果您将一个小于等于0的数字设置为右侧x范围元素,则您的图表是错误的。 - Hubert Grzeskowiak
1个回答

0

一旦您的线性比例尺具有域和范围,您就可以使用它来获取任何域值的像素值。例如,要获取点(0,0)的像素,您将询问xScale(0)yScale(0)

如果这些值超出了定义的范围(即:SVG画布的像素尺寸),则您知道Y轴应该在最左侧或最右侧(最小或最大范围加上边距)。


是的,但问题在于要确定轴上的零点在哪里。 - dagda1
你能详细说明一下吗? - Hubert Grzeskowiak
根据用户在http://www.d3geometry.com/functions?uid=333333页面上的输入,原点可能位于许多不同的位置。它并不总是在最左边或最右边。对于y轴的顶部或底部,它可以在任何中间位置。 - dagda1
xScale(0)和yScale(0)不会返回正确的值。 - dagda1
xScale和yScale是D3用于绘制所有几何图形的工具。如果您告诉它在(0, 0)处绘制一个点,那么它实际上会调用比例函数来确定像素位置。 - Hubert Grzeskowiak
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接