【问题标题】:Alternating axis line colors in D3D3中的交替轴线颜色
【发布时间】:2018-07-11 04:34:22
【问题描述】:

我正在使用 D3 (v4) 并尝试在每个刻度之间创建一个带有交替颜色条的 X 轴。这就是我想要模仿的:

目前,我有一个 X 轴,按我想要的方式每小时都有刻度。

const hoursBarAxis = axisBottom(this.xScale)
  .ticks(timeHour, 1)
  .tickSize(5)
  .tickPadding(36)
  .tickFormat('');

this.graph.append('g')
      .attr('transform', 'translate(' + this.xOffset + ',' + height + ')')
      .call(hoursBarAxis);

看起来像这样:

第一次尝试: 做了类似这个例子的事情:https://codepen.io/idan/pen/xejuD

我在每个刻度线后插入一个矩形,基本上在每个刻度线之间绘制一个矩形(下面的紫色和灰色交替)。这让我非常接近我想要的结果,但我的困境随后变成了处理轴的开始和结束(第一个刻度之前的部分和最后一个刻度之后的矩形太长的事实)。

其他尝试: 我尝试了许多其他方法来一次添加一条轴,并尝试了各种 CSS hacks 在刻度后附加项目,但它们都没有工作或正确解决我的问题。

所以我的问题是......有没有更简单的方法来解决我没有看到的这个问题?专注于改变滴答声似乎是错误的想法,因为这并不能处理第一个滴答声之前的初始片段。

提前致谢!

【问题讨论】:

    标签: javascript d3.js svg


    【解决方案1】:

    首先,我们很想使用一个简单的解决方案,它依赖于轴生成器为每个刻度创建一个这样的结构(不要介意值,只是结构):

    <g class="tick" opacity="1" transform="translate(66.5,0)">
        <line stroke="#000" y2="6">
        </line><text fill="#000" y="9" dy="0.71em">10</text>
    </g>
    

    所以,我们可以使用&lt;lines&gt;getBoundingClientRect() 来附加我们的矩形。为此,我们将在轴组中使用each()

    第一步如果检查tick是否有下一个tick,因为在最后一个tick之后不会有矩形:

    if (this.nextSibling) {
    

    然后,我们使用这个数学来附加矩形:

    d3.select(this).append("rect")
        .attr("width", this.nextSibling.firstChild.getBoundingClientRect().x -
            this.firstChild.getBoundingClientRect().x)
        .attr("height", 6)
        .style("fill", i % 2 ? "green" : "red");
    

    在此示例中,我使用刻度的索引来绘制“绿色”或“红色”矩形。注意:那个幻数6 只是 D3 中刻度的默认高度。相应地改变它。

    这里是演示:

    var svg = d3.select("svg");
    var scale = d3.scaleLinear()
      .domain([0, 100])
      .range([20, 480]);
    var axis = d3.axisBottom(scale);
    var gX = svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0,50)")
      .call(axis);
    gX.selectAll(".tick").each(function(d, i) {
      if (this.nextSibling) {
        d3.select(this).append("rect")
          .attr("width", this.nextSibling.firstChild.getBoundingClientRect().x - this.firstChild.getBoundingClientRect().x)
          .attr("height", 6)
          .style("fill", i % 2 ? "green" : "red");
      }
    });
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg width="500" height="100"></svg>

    但是,在您的情况下,这是行不通的。为什么?

    根据您的图像,您的问题是第一个和最后一个滴答声。这是解释:那些不是蜱虫。这些“线”属于在轴中创建水平线的路径。

    如果我们稍微改变一下域,我们可以清楚地看到这一点,看看:

    var svg = d3.select("svg");
    var scale = d3.scaleLinear()
      .domain([5, 105])
      .range([20, 480]);
    var axis = d3.axisBottom(scale);
    var gX = svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0,50)")
      .call(axis);
    gX.selectAll(".tick").each(function(d, i) {
      if (this.nextSibling) {
        d3.select(this).append("rect")
          .attr("width", this.nextSibling.firstChild.getBoundingClientRect().x - this.firstChild.getBoundingClientRect().x)
          .attr("height", 6)
          .style("fill", i % 2 ? "green" : "red");
      }
    });
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg width="500" height="100"></svg>

    那么,如何处理呢?

    解决方案:将那些“假”刻度转换为“真实”厚度。这可以使用tickValues

    .tickValues(scale.ticks().concat(scale.domain()));
    

    作为一个额外的复杂功能,我们必须在此之后对刻度进行排序:

    gX.selectAll(".tick").sort(function(a, b) {
      return d3.ascending(a, b);
    });
    

    这里是演示:

    var svg = d3.select("svg");
    var scale = d3.scaleLinear()
      .domain([5, 105])
      .range([20, 480]);
    var axis = d3.axisBottom(scale)
      .tickValues(scale.ticks().concat(scale.domain()))
      .tickFormat(function(d,i,n){
        return i === n.length - 1 || i === n.length - 2 ? null : d; 
      });
    var gX = svg.append("g")
      .attr("class", "axis")
      .attr("transform", "translate(0,50)")
      .call(axis);
    gX.selectAll(".tick").sort(function(a, b) {
      return d3.ascending(a, b);
    });
    gX.selectAll(".tick").each(function(d, i) {
      if (this.nextSibling) {
        d3.select(this).append("rect")
          .attr("width", this.nextSibling.firstChild.getBoundingClientRect().x - this.firstChild.getBoundingClientRect().x)
          .attr("height", 6)
          .style("fill", i % 2 ? "green" : "red");
      }
    });
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <svg width="500" height="100"></svg>

    【讨论】:

    • 这是为我做的,谢谢!我确实必须做一个小改动,因为我的是 UTC(时间)刻度,我需要每小时打勾。所以如果有人感兴趣:.tickValues(this.xScale.ticks(timeHour, 1).concat(this.xScale.domain()))
    猜你喜欢
    • 1970-01-01
    • 2017-07-23
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 2010-09-20
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多