将SVG线路放在前面

时间:2017-12-12 16:12:20

标签: javascript d3.js

我想在圆圈上方添加一些圆圈和红线到我的SVG。 然而,无论它们附加在哪个顺序:我总是在后面有这条线。

如何将它带到前面? 我试图使用moveToFront和z轴属性,但我无法解决它。

我的暂定:

d3.select("svg")
  .append("g")
  .attr("id", "chart")
  .attr("width", width)
  .attr("height", height)

filename = "assets/sources/datafile.csv"
d3.csv(filename, d => dataViz(d));

function dataViz(input_data) {
  d3.select("svg")
    .selectAll("circle")
    .data(input_data)
    .enter()
    .append("circle")
}
d3.select("#chart")
  .append('line')
  .attr("id", "avg_line")
  .attr("x1", xScale(0))
  .attr("y1", yScale(3.75))
  .attr("x2", xScale(upper_limit))
  .attr("y2", yScale(3.75))
  .attr("stroke-width", 5)
  .attr("stroke", "red")

1 个答案:

答案 0 :(得分:3)

这是d3.json上众所周知的主题的有趣变体!由于d3.json 异步,因此在加载完成之前不会调用回调。虽然在附加圈子之后附加似乎的调用似乎,但它实际上会立即执行,即在追加圈子之前从而在任何情况下将线定位在圆圈下方。解决方法是在附加圆圈后将回调附加到回调中。

function dataViz(input_data) {
  d3.select("svg")
    .selectAll("circle")
    .data(input_data)
    .enter()
    .append("circle")

  d3.select("#chart")   // <-- This should be inside the callback.
    .append('line')
      .attr("id","avg_line")
      .attr("x1", xScale(0))
      .attr("y1", yScale(3.75))
      .attr("x2", xScale(upper_limit))
      .attr("y2", yScale(3.75))
      .attr("stroke-width",5)
      .attr("stroke","red");
}

另一个错误在于您选择要追加的元素的方式。上面更正的代码将生成以下结构:

<svg>
  <g id="chart" width="" height="">
    <line id="avg_line" x1="" y1="" x2="" y2="" stroke-width="5" stroke="red"></line>
  </g>
  <circle></circle>
</svg>

这是因为您首先将<g id="chart">附加到仅附加了该行的<svg>。另一方面,圆圈会附加到<svg>本身。看看这个结构很明显,为什么线仍然位于圆圈后面。

鉴于您没有提供完整的代码,我无法确定最佳解决方案是什么。但是,由于<g>只是一个容器元素,它没有widthheight属性,因此第一个语句应该放弃.append("g")。另一方面,因为svg是你想要追加的元素,所以最好保留对它的引用,这也可以让你不必反复重新选择相同的元素:

var svg = d3.select("svg")   // Keep the reference to the <svg> for later use.
    .attr("id", "chart")
    .attr("width",width)
    .attr("height",height);

在您的回调中,您可以使用此引用以所需顺序附加元素。把所有这些放在一起你得到的结果如下:

var svg = d3.select("svg")
    .attr("id", "chart")
    .attr("width",width)
    .attr("height",height);

filename="assets/sources/datafile.csv"

d3.csv(filename, dataViz);

function dataViz(input_data) {
  svg.selectAll("circle")
    .data(input_data)
    .enter()
    .append("circle")

  svg.append('line')
      .attr("id","avg_line")
      .attr("x1", xScale(0))
      .attr("y1", yScale(3.75))
      .attr("x2", xScale(upper_limit))
      .attr("y2", yScale(3.75))
      .attr("stroke-width",5)
      .attr("stroke","red");
}

生成的SVG结构如下所示,将线条呈现在任何圆圈上方:

<svg id="chart" width="" height="">
  <circle></circle>
  <line id="avg_line" x1="" y1="" x2="" y2="" stroke-width="5" stroke="red"></line>
</svg>

Protip 与您的问题无关:

请注意,我如何简化您对d3.csv()的通话。以下两个语句基本上是等价的(好吧,在我得到chastized之前,这不是完全是真的,但是在一阶近似中它们是):

d3.csv(filename, d => dataViz(d));
d3.csv(filename, dataViz);

无需将函数dataViz()包装在另一个匿名箭头函数中;只要传递对它的引用,D3就会负责调用它。