无法在单个工具提示中显示堆积面积图的工具提示值

时间:2016-07-14 05:23:40

标签: javascript d3.js stacked-area-chart

<!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("rect")
      .attr("width", width / 2)
      .attr("height", 30)
      .style("padding", "5px")
      .style("stroke", function(d) {
        return color(d.name);
      })
      .style("fill", function(d) {
        return color(d.name);
      })
      .style("stroke-width", "1px")
      .style("opacity", "0")
      .attr('x', 10);


    mousePerLine.append("circle")
      .attr("r", 5)
      .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(15,13)");

    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 rect")
          .style("opacity", "0");
        d3.selectAll(".mouse-per-line circle")
          .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 rect")
          .style("opacity", "0.5");
        d3.selectAll(".mouse-per-line circle")
          .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的新手。我正在尝试使用D3制作堆积区域图表并在鼠标悬停时我想在每个区域图表的单个矩形内显​​示所有多个数据值。到目前为止,我已经实现了在鼠标悬停时显示每个数据值的单独矩形的数据值。请帮助我提供一些有关如何实现这一目标的建议/提示。我真的陷入困境和挣扎。感谢您提前提供任何帮助。

2 个答案:

答案 0 :(得分:2)

好的,这很丑陋。我有些人设法解决了这个问题(我也是d3的新手)。

我将解释我是如何解决的。应该并且将会有更好的方法来实现你的目标。

  1. 首先我添加了一个组而不是三个组
  2. 接下来为每个svg元素分别添加数据,即rect,text和circle。
  3. 鼠标悬停时,我选择了每行鼠标类元素,然后我逐个转换了每个svg元素。
  4. 为了追加矩形,我将高度存储在一个数组中,取平均值来设置矩形的位置。同样,对文本进行了相同的转换。
  5. 再次,我的只是一个工作模式,将会/应该有更优雅的方式来实现同样的目标。

    如果有人可以修改或建议编辑,那将会有所帮助。 希望这可以帮助。

    &#13;
    &#13;
        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.selectAll('.mouse-per-line')
          .data([cities])
          .enter().append("rect")
          .attr("width", width / 2)
          .attr("height", 90)
          .style("padding", "5px")
          .style("stroke", function(d) {
            return color(d.name);
          })
          .style("fill", function(d) {
            return color(d.name);
          })
          .style("stroke-width", "1px")
          .style("opacity", "0")
          .attr('x', 10)
    	  .attr('y',-45);
    
    
        mousePerLine.selectAll('.mouse-per-line')
          .data(cities)
          .enter().append("circle")
          .attr("r", 5)
          .style("stroke", function(d) {
            return color(d.name);
          })
          .style("fill", function(d) {
            return color(d.name);
          })
          .style("stroke-width", "1px")
          .style("opacity", "0");
    
        mousePerLine.selectAll('.text')
          .data(cities)
          .enter().append("text")
          .attr("transform", "translate(15,13)");
    
        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 rect")
              .style("opacity", "0");
            d3.selectAll(".mouse-per-line circle")
              .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 rect")
              .style("opacity", "0.5");
            d3.selectAll(".mouse-per-line circle")
              .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("foo", function(d, i) {
                var xDate = x.invert(mouse[0]);
                var  bisect;
    			var  heights = [];
    			
    			d3.selectAll('circle')
    				.attr("transform", function(d,j) {
    					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[j].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
                }
    				heights[j] = pos.y;
    				return "translate(" + mouse[0] + "," + pos.y + ")";
    				});
    			var avgheight = 0;	
    			for(var z = 0; z < heights.length ; z++){
    				avgheight = avgheight + heights[z];
    			}	
    			avgheight = avgheight/d.length;
    						d3.select(this).selectAll('rect')
    				.attr("transform", function(d,i) {
    					return "translate(" + mouse[0] + "," + avgheight + ")";
    				});
    			var rectangleText = "";
    			for(var t = 1; t < heights.length ; t++) {
    				rectangleText = rectangleText + "<br/>" + y.invert(heights[t]).toFixed(2);
    			}	
                d3.select(this).selectAll('text').text(function(d,i) { return y.invert(heights[i]).toFixed(2)}).attr("transform", function(d,i) {
    					return "translate(" + mouse[0] + "," + (avgheight  + 30 - (i*25)) + ")";
    				}).attr("dx", '20px');			
                return "translate(" + mouse[0] + "," + pos.y + ")";
              });
          });
    &#13;
    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;
        }
    &#13;
    <!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>
    </head>
    
    <body>
      
    </body>
    
    </html>
    &#13;
    &#13;
    &#13;

答案 1 :(得分:0)

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-type" content="text/html; charset=utf-8">
  <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.selectAll('.mouse-per-line') // Rectangle
      .data([cities])
      .enter()
      .append("rect")
      .attr("width", width)
      .attr("height", 110)
      .style("padding", "5px")
      .style("stroke", "#272525")
      .style("fill", "#272525")
      .style("stroke-width", "1px")
      .style("opacity", "0")
      .attr('x', 10)
      .attr('y', -45);

    mousePerLine.selectAll('.mouse-per-line') // Circle
      .data(cities)
      .enter()
      .append("circle")
      .attr("r", 5)
      .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("class", "DateText");
    mousePerLine.selectAll('.mouse-per-line') // Text
      .data(cities)
      .enter()
      .append("text")
      .attr("class", "ValueText")
      .attr("transform", "translate(15,13)")
      .style("fill", function(d) {
        return color(d.name);
      })
      .style("font-weight", "bold")
      .style("font-size", "10pt");

    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 rect")
          .style("opacity", "0");
        d3.selectAll(".mouse-per-line circle")
          .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 rect")
          .style("opacity", "1");
        d3.selectAll(".mouse-per-line circle")
          .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("foo", function(d, i) {
          var xDate = x.invert(mouse[0]);
          var bisect;
          var heights = [];

          var xDateValue = /\w*.\s.\d.\d*.\d*.:\d*.:\d*/.exec(xDate);
          // console.log(xDateValue);

          d3.selectAll('circle')
            .attr("transform", function(d, j) {
              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[j].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
              }
              heights[j] = pos.y;
              return "translate(" + mouse[0] + "," + pos.y + ")";
            });
          var avgheight = 0;
          for (var z = 0; z < heights.length; z++) {
            avgheight = avgheight + heights[z];
          }
          avgheight = avgheight / d.length;

          d3.select(this).selectAll('rect')
            .attr("transform", function(d, i) {
              return "translate(" + mouse[0] + "," + avgheight + ")";
            });
          var rectangleText = "";
          for (var t = 1; t < heights.length; t++) {
            rectangleText = rectangleText + "<br/>" + y.invert(heights[t]).toFixed(2);
          }

          d3.select(this)
            .select(".DateText")
            .text(xDateValue)
            .attr("transform", function(d, i) {
              return "translate(" + mouse[0] + "," + (avgheight - 25) + ")";
            })
            .attr("dx", '20px')
            .style("fill", "white")
            .style("font-weight", "bold")
            .style("font-size", "10pt");;

          d3.select(this)
            .selectAll('.ValueText')
            .text(function(d, i) {
              return d.name + "  " + y.invert(heights[i]).toFixed(2)
            })
            .attr("transform", function(d, i) {
              return "translate(" + mouse[0] + "," + (avgheight + 50 - (i * 25)) + ")";
            })
            .attr("dx", '20px');

          return "translate(" + mouse[0] + "," + pos.y + ")";
        });
    });
  </script>
</body>

</html>

经过这么多障碍后,我找到了一些解决方案,使用D3库在多线图中显示X轴和Y轴的数据。我希望它可以帮助任何尝试相同的人。