如何在' mouseenter'上获取所有重叠元素?在D3?

时间:2017-05-29 00:13:58

标签: d3.js event-handling

我在D3中有一个多线图,每一行代表一个"样本"。

图表中有很大一部分是重叠的,但有些部分是分开的。我想要做的是当鼠标在线上移动时,获取该重叠部分中每个样本的ID。

目前我只能获得最顶行的ID。有没有办法将'mouseenter'事件传播到该点的所有行并获取每个事件的ID?

这是一个最小的工作示例。在线条重叠的部分中,我基本上需要[line1, line2, line3]或类似的东西。



<!DOCTYPE html>

<head>
  <script src="https://d3js.org/d3.v4.min.js"></script>
</head>

<body>
  <script>
    var myData = "x	line1	line2	line3\n\
1	63.4	62.7	72.2\n\
2	58.0	59.9	67.7\n\
3	53.3	59.1	69.4\n\
4	55.7	55.7	55.7\n\
5	58.7	58.7	58.7\n\
6	77.0	77.0	77.0\n\
7	57.9	56.7	82.3\n\
8	61.8	56.8	78.9\n\
9	69.3	56.7	68.8\n\
10	71.2	60.1	68.7\n";
    var data = d3.tsvParse(myData);

    var margin = {
      top: 20,
      right: 20,
      bottom: 40,
      left: 50
    };
    var height = 500 - margin.bottom - margin.top,
      width = 960 - margin.left - margin.right;
    var line = d3.line()
      .x(function(d) {
        return X(d.x);
      })
      .y(function(d) {
        return Y(d.y);
      });

    var X = d3.scaleLinear().range([0, width]);
    var Y = d3.scaleLinear().range([height, 0]);
    var colour = d3.scaleOrdinal(d3.schemeCategory10);

    colour.domain(d3.keys(data[0]).filter(function(key) {
      return key !== "x";
    }));

    var lines = colour.domain().map(function(name) {
      return {
        name: name,
        values: data.map(function(d) {
          return {
            x: +d.x,
            y: +d[name]
          };
        })
      };
    });

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

    X.domain(d3.extent(data, function(d) {
      return d.x;
    }));
    Y.domain([
      d3.min(lines, function(c) {
        return d3.min(c.values, function(v) {
          return v.y;
        });
      }),
      d3.max(lines, function(c) {
        return d3.max(c.values, function(v) {
          return v.y;
        });
      })
    ]);

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

    svg.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(Y));

    var gLines = svg.selectAll('.lines')
      .data(lines)
      .enter().append('g')
      .attr('class', 'lines');

    gLines.append('path')
      .attr('d', function(d) {
        return line(d.values);
      })
      .style('stroke', function(d) {
        return colour(d.name)
      })
      .style('fill', 'none')
      .on('mouseenter', function(d) {
        console.log(d.name);
      });
  </script>
</body>

</html>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:1)

您可以使用Document.elementsFromPoint()。虽然这种方法仍被认为是实验性的,但所有主流浏览器都是implemented

该方法将返回指定坐标下的所有元素,包括您感兴趣的路径的所有祖先。要获得您的路径,您必须应用额外的过滤:

d3.selectAll(document.elementsFromPoint(d3.event.x, d3.event.y)).filter("path");

因为访问DOM树的Stack Snippets以某种方式倾向于冻结浏览器,所以这里有JSFiddle证明了这一点。

如果将来修复这个缺点,这是工作演示:

    var myData = "x	line1	line2	line3\n\
1	63.4	62.7	72.2\n\
2	58.0	59.9	67.7\n\
3	53.3	59.1	69.4\n\
4	55.7	55.7	55.7\n\
5	58.7	58.7	58.7\n\
6	77.0	77.0	77.0\n\
7	57.9	56.7	82.3\n\
8	61.8	56.8	78.9\n\
9	69.3	56.7	68.8\n\
10	71.2	60.1	68.7\n";
    var data = d3.tsvParse(myData);

    var margin = {
      top: 20,
      right: 20,
      bottom: 40,
      left: 50
    };
    var height = 500 - margin.bottom - margin.top,
      width = 960 - margin.left - margin.right;
    var line = d3.line()
      .x(function(d) {
        return X(d.x);
      })
      .y(function(d) {
        return Y(d.y);
      });

    var X = d3.scaleLinear().range([0, width]);
    var Y = d3.scaleLinear().range([height, 0]);
    var colour = d3.scaleOrdinal(d3.schemeCategory10);

    colour.domain(d3.keys(data[0]).filter(function(key) {
      return key !== "x";
    }));

    var lines = colour.domain().map(function(name) {
      return {
        name: name,
        values: data.map(function(d) {
          return {
            x: +d.x,
            y: +d[name]
          };
        })
      };
    });

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

    X.domain(d3.extent(data, function(d) {
      return d.x;
    }));
    Y.domain([
      d3.min(lines, function(c) {
        return d3.min(c.values, function(v) {
          return v.y;
        });
      }),
      d3.max(lines, function(c) {
        return d3.max(c.values, function(v) {
          return v.y;
        });
      })
    ]);

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

    svg.append("g")
      .attr("class", "axis axis--y")
      .call(d3.axisLeft(Y));

    var gLines = svg.selectAll('.lines')
      .data(lines)
      .enter().append('g')
      .attr('class', 'lines');

    gLines.append('path')
      .attr('d', function(d) {
        return line(d.values);
      })
      .style('stroke', function(d) {
        return colour(d.name)
      })
      .style('fill', 'none')
      .on('mouseenter', function(d) {
        console.dir(d3.selectAll(document.elementsFromPoint(d3.event.x, d3.event.y)).filter("path"));
      });
<script src="https://d3js.org/d3.v4.min.js"></script>