d3 raise()无法在特定选择上使用

时间:2018-12-25 16:37:45

标签: javascript d3.js svg

我有一个用d3制成的折线图,但是由于数据的形状,线和点(我在每个特定数据点的线上方使用点的形式)通常最终位于彼此。

为解决此问题,我结束了为线条和点赋予不透明度0.4,当您将鼠标悬停在一条线上时,该特定数据行的线条和点会弹出,并将其不透明度设置为{ {1}}。

我的问题是:我正在使用1函数使它们弹出并站立在其余的线和点上,该功能仅适用于我的线选择,而不适用于我的点选择,我不知道为什么。

我的代码:

.raise()

因此,当您将鼠标悬停在一条线上时,这应该将与之相关的线条和点置于不透明// draw the data lines const lines = svg.selectAll('.line') .data(this.data) .enter() .append('path') .attr('class', 'data.line') .attr("fill", "none") .attr("stroke", d => colors(d.key)) .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 2.5) .attr('stroke-opacity', 0.4) .attr('d', d => line(d.values)) .on('mouseenter', d => { // Highlight them let myCircles = circles.selectAll('.circle'); lines.attr('stroke-opacity', b => { return b.key === d.key ? 1 : 0.4; }); myCircles.attr('fill-opacity', b => { return b[this.typeIdentifier] === d.key ? 1 : 0.4; }); // Bring them to the front myCircles = circles.selectAll('.circle') .filter(b => b[this.typeIdentifier] === d.key); const myLines = lines.filter(b => b.key === d.key); myLines.raise(); myCircles.raise(); }); // draw the circles const circles = svg.selectAll('.circle') .data(this.data) .enter() .append('g'); circles.selectAll('.circle') .data(d => d.values) .enter() .append('circle') .attr('class', 'circle') .attr('stroke', 'white') .attr('stroke-width', 1) .attr('r', 6) .attr('fill', d => colors(d[this.typeIdentifier])) .attr('fill-opacity', 0.4) .attr('cx', d => x(d[this.xAxisValue]) + x.bandwidth() / 2) .attr('cy', d => y(d[this.yAxisValue])) .on('mouseenter', (d, b, j) => { tooltip.raise(); tooltip.style("display", null); tooltip.select("#text1").text(d[this.typeIdentifier]) .attr('fill', colors(d[this.typeIdentifier])); tooltip.select('#text4').text(d[this.yAxisValue]); tooltip.select('#text5').text(d[this.xAxisValue]); const tWidth = tooltip.select('#text1').node().getComputedTextLength() > 60 ? tooltip.select('#text1').node().getComputedTextLength() + 20 : 80; tooltipRect.attr('width', tWidth); const xPosition = d3.mouse(j[b])[0]; const yPosition = d3.mouse(j[b])[1]; if (xPosition + tWidth + 35 < this.xWIDTH) { // display on the right tooltip.attr("transform", `translate(${xPosition + 15}, ${yPosition - 25})`); } else { // display on the left tooltip.attr("transform", `translate(${xPosition - tWidth - 15}, ${yPosition - 25})`); } }) .on('mouseleave', d => { tooltip.style("display", "none"); }) 的前面,但是由于某些原因,它只能在{{1} }选择,而不是1选择。选择不是空的,我一直在打印它们以进行测试。另外,我尝试使用lines方法将圆圈(带有单选和原始元素)一个接一个地移到最前面,但这种方法并没有奏效。

为什么不起作用?可能与将鼠标悬停在圆圈上的提示有关吗?我是在做错事而看不到吗?

1 个答案:

答案 0 :(得分:1)

实际上,selection.raise()在工作。这里的问题仅仅是SVG的树结构:给定线的所有圆都属于<g>元素。

如果您look at the docs,您会看到selection.raise()

  

按顺序将每个选定元素重新插入为其父级的最后一个子级。

上面的重点是我的:这里的主要工作是 parent 。因此,您想要的是将包含所选圆的<g>元素提高到其他圆的其他<g>元素上方,而不是在其<g>父级内部的圆之上。

就您而言,这就像更改...一样简单。

myCircles = circles.selectAll('.circle').filter(etc...)

...至:

myCircles = circles.filter(etc...)

现在,myCircles是带有<g>元素的选择,可以将其提高。注意filter函数:由于您没有共享数据结构,因此我不知道<g>元素(即this.data)的数据数组是否包含{ {1}}属性。相应地更改它。

这是一个演示:

每行都有一组圆圈,每个圆圈都位于其自己的key父级中。只有左侧的圆是分开的,所有其他圆是故意在另一个圆上绘制的。当您将鼠标悬停在一个圆圈上(使用左侧的圆圈)时,其<g>容器会升高,在这种情况下,使用...

<g>

...,因此所有圆圈都可见:

d3.select(this.parentNode).raise()
const svg = d3.select("svg");
const scale = d3.scaleOrdinal(d3.schemeSet1);
const lineGenerator = d3.line()
  .x(function(d) {
    return d.x
  })
  .y(function(d) {
    return d.y
  })
const data = d3.range(5).map(function(d) {
  return {
    key: d,
    values: d3.range(5).map(function(e) {
      return {
        x: 50 + 100 * e,
        y: e ? 150 : 50 + 50 * d
      }
    })
  }
});
const lines = svg.selectAll(null)
  .data(data)
  .enter()
  .append("path")
  .attr("d", function(d) {
    return lineGenerator(d.values);
  })
  .style("fill", "none")
  .style("stroke-width", "3px")
  .style("stroke", function(d) {
    return scale(d.key)
  });
const circleGroups = svg.selectAll(null)
  .data(data)
  .enter()
  .append("g");
const circles = circleGroups.selectAll(null)
  .data(function(d) {
    return d.values
  })
  .enter()
  .append("circle")
  .attr("r", 20)
  .attr("cx", function(d) {
    return d.x
  })
  .attr("cy", function(d) {
    return d.y
  })
  .style("fill", function(d) {
    return scale(d3.select(this.parentNode).datum().key)
  });
circles.on("mouseover", function(d) {
  const thisKey = d3.select(this.parentNode).datum().key;
  lines.filter(function(e) {
    return e.key === thisKey;
  }).raise();
  d3.select(this.parentNode).raise();
})