在 d3 堆积面积图中鼠标悬停时显示“矩形”内的工具提示值

Show the tooltip value inside the "rect" on mouseover in d3 stacked area chart

本文关键字:矩形 工具提示 显示 d3 面积图 悬停 鼠标      更新时间:2023-09-26

<!DOCTYPE html>
<html>
<head>
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
  <style>
    body {
      font: 10px sans-serif;
    }
    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    .x.axis path {
      display: none;
    }
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 1.5px;
    }
  </style>
</head>
<body>
  <script>
    var myData = "date	New York	San Francisco	Austin'n'
20111001	63.4	62.7	72.2'n'
20111002	58.0	59.9	67.7'n'
20111003	53.3	59.1	69.4'n'
20111004	55.7	58.8	68.0'n'
20111005	64.2	58.7	72.4'n'
20111006	58.8	57.0	77.0'n'
20111007	57.9	56.7	82.3'n'
20111008	61.8	56.8	78.9'n'
20111009	69.3	56.7	68.8'n'
20111010	71.2	60.1	68.7'n'
20111011	68.7	61.1	70.3'n'
20111012	61.8	61.5	75.3'n'
20111013	63.0	64.3	76.6'n'
20111014	66.9	67.1	66.6'n'
20111015	61.7	64.6	68.0'n'
20111016	61.8	61.6	70.6'n'
20111017	62.8	61.1	71.1'n'
20111018	60.8	59.2	70.0'n'
20111019	62.1	58.9	61.6'n'
20111020	65.1	57.2	57.4'n'
20111021	55.6	56.4	64.3'n'
20111022	54.4	60.7	72.4'n";
    var margin = {
        top: 20,
        right: 80,
        bottom: 30,
        left: 50
      },
      width = 500 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
    var parseDate = d3.time.format("%Y%m%d").parse;
    var x = d3.time.scale()
      .range([0, width]);
    var y = d3.scale.linear()
      .range([height, 0]);
    var color = d3.scale.category20();
    var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom");
    var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left");
    var line = d3.svg.line()
      .interpolate("basis")
      .x(function(d) {
        return x(d.date);
      })
      .y(function(d) {
        return y(d.temperature);
      });
    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
    var data = d3.tsv.parse(myData);
    color.domain(d3.keys(data[0]).filter(function(key) {
      return key !== "date";
    }));
    data.forEach(function(d) {
      d.date = parseDate(d.date);
    });
    var cities = color.domain().map(function(name) {
      return {
        name: name,
        values: data.map(function(d) {
          return {
            date: d.date,
            temperature: +d[name]
          };
        })
      };
    });
    x.domain(d3.extent(data, function(d) {
      return d.date;
    }));
    y.domain([
      d3.min(cities, function(c) {
        return d3.min(c.values, function(v) {
          return v.temperature;
        });
      }),
      d3.max(cities, function(c) {
        return d3.max(c.values, function(v) {
          return v.temperature;
        });
      })
    ]);
    var legend = svg.selectAll('g')
      .data(cities)
      .enter()
      .append('g')
      .attr('class', 'legend');
    legend.append('rect')
      .attr('x', width - 20)
      .attr('y', function(d, i) {
        return i * 20;
      })
      .attr('width', 10)
      .attr('height', 10)
      .style('fill', function(d) {
        return color(d.name);
      });
    legend.append('text')
      .attr('x', width - 8)
      .attr('y', function(d, i) {
        return (i * 20) + 9;
      })
      .text(function(d) {
        return d.name;
      });
    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);
    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis)
      .append("text")
      .attr("transform", "rotate(-90)")
      .attr("y", 6)
      .attr("dy", ".71em")
      .style("text-anchor", "end")
      .text("Temperature (ºF)");
    var city = svg.selectAll(".city")
      .data(cities)
      .enter().append("g")
      .attr("class", "city");
    city.append("path")
      .attr("class", "line")
      .attr("d", function(d) {
        return line(d.values);
      })
      .style("stroke", function(d) {
        return color(d.name);
      });
    city.append("text")
      .datum(function(d) {
        return {
          name: d.name,
          value: d.values[d.values.length - 1]
        };
      })
      .attr("transform", function(d) {
        return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")";
      })
      .attr("x", 3)
      .attr("dy", ".35em")
      .text(function(d) {
        return d.name;
      });
    var mouseG = svg.append("g")
      .attr("class", "mouse-over-effects");
    mouseG.append("path") // this is the black vertical line to follow mouse
      .attr("class", "mouse-line")
      .style("stroke", "black")
      .style("stroke-width", "1px")
      .style("opacity", "0");
    var lines = document.getElementsByClassName('line');
    var mousePerLine = mouseG.selectAll('.mouse-per-line')
      .data(cities)
      .enter()
      .append("g")
      .attr("class", "mouse-per-line");
     // mousePerLine.append("circle")
     //   .attr("r", 7)
     //   .style("stroke", function(d) {
     //     return color(d.name);
     //   })
     //   .style("fill", "none")
     //   .style("stroke-width", "1px")
     //   .style("opacity", "0");
    mousePerLine.append("rect")
      .attr("width", 50)
      .attr("height", 50)
      .style("stroke", function(d) {
        return color(d.name);
      })
      .style("fill", function(d) {
        return color(d.name);
      })
      .style("stroke-width", "1px")
      .style("opacity", "0");
    mousePerLine.append("text")
      .attr("transform", "translate(10,3)");
    mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas
      .attr('width', width) // can't catch mouse events on a g element
      .attr('height', height)
      .attr('fill', 'none')
      .attr('pointer-events', 'all')
      .on('mouseout', function() { // on mouse out hide line, circles and text
        d3.select(".mouse-line")
          .style("opacity", "0");
        // d3.selectAll(".mouse-per-line circle")
        //   .style("opacity", "0");
        d3.selectAll(".mouse-per-line rect")
          .style("opacity", "0");
        d3.selectAll(".mouse-per-line text")
          .style("opacity", "0");
      })
      .on('mouseover', function() { // on mouse in show line, circles and text
        d3.select(".mouse-line")
          .style("opacity", "1");
        // d3.selectAll(".mouse-per-line circle")
        //   .style("opacity", "1");
        d3.selectAll(".mouse-per-line rect")
          .style("opacity", "1");
        d3.selectAll(".mouse-per-line text")
          .style("opacity", "1");
      })
      .on('mousemove', function() { // mouse moving over canvas
        var mouse = d3.mouse(this);
        d3.select(".mouse-line")
          .attr("d", function() {
            var d = "M" + mouse[0] + "," + height;
            d += " " + mouse[0] + "," + 0;
            return d;
          });
        d3.selectAll(".mouse-per-line")
          .attr("transform", function(d, i) {
            console.log(width / mouse[0])
            var xDate = x.invert(mouse[0]),
              bisect = d3.bisector(function(d) {
                return d.date;
              }).right;
            idx = bisect(d.values, xDate);
            var beginning = 0,
              end = lines[i].getTotalLength(),
              target = null;
            while (true) {
              target = Math.floor((beginning + end) / 2);
              pos = lines[i].getPointAtLength(target);
              if ((target === end || target === beginning) && pos.x !== mouse[0]) {
                break;
              }
              if (pos.x > mouse[0]) end = target;
              else if (pos.x < mouse[0]) beginning = target;
              else break; //position found
            }
            d3.select(this).select('text')
              .text(y.invert(pos.y).toFixed(2));
            return "translate(" + mouse[0] + "," + pos.y + ")";
          });
      });
  </script>
</body>
</html>

您好,我正在尝试使用 D3 绘制堆积面积图。到目前为止,我能够成功绘制图表,并且在将鼠标悬停在图表上时,图表会显示一个矩形和矩形上方的相应数据值。但是我想在鼠标悬停时在矩形内而不是矩形外显示数据值。我在这方面做错了什么。请帮助我。我被困住了。提前感谢您的任何帮助。

您可以通过翻译来定位文本:

因此,您可以更改:

mousePerLine.append("text")
      .attr("transform", "translate(10,3)");

对此:

mousePerLine.append("text")
      .attr("transform", "translate(10,13)");//this will move 10 points down

工作代码在这里