为折线图创建 D3 工具提示的问题

Issues creating a D3 tooltip for line graph

我正在尝试从该站点 (http://www.d3noob.org/2014/07/my-favourite-tooltip-method-for-line.html) 为我的双轴线​​图重新创建工具提示。但是,我将 运行 保留为一个错误,圆圈仅出现在图表的右上角,我得到错误

类型错误:第 137 行未定义 d1

我一直在寻找解决方案,但还没有找到任何帮助。

代码如下:

 <!DOCTYPE html>
 <html>
 <head>
 <script type="text/javascript" src="d3/d3.min.js"></script>
 </head>
 <body>
 <script type="text/javascript">

 // http://www.baseball-reference.com/teams/PIT/attend.shtml

 /* want interactive line chart showing two lines, total attendance and      attendance per game
    cicles at vaious points that show information on hover about why attendance may be drastically different
    ie opening of pnc park or world series team */

// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 50, bottom: 30, left: 150},
    width = 1000 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// Method used for finding year corresponding with mouse location   
var bisectYear = d3.bisector(function(d) { return d.Year; }).left;

// Set the ranges
var x = d3.time.scale().range([0, width]);
var y0 = d3.scale.linear().range([height, 0]);
var y1 = d3.scale.linear().range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
    .tickFormat(d3.format(".0f"))
    .orient("bottom");

var yAxisLeft = d3.svg.axis().scale(y0)
    .orient("left")
    .ticks(5);

var yAxisRight = d3.svg.axis().scale(y1)
    .orient("right").ticks(5)

// Define the first line
var valueline = d3.svg.line()
    .x(function(d) { return x(d.Year); })
    .y(function(d) { return y0(d.AttendancePerG); });

// Define the second line
var valueline2 = d3.svg.line()
    .x(function(d) { return x(d.Year); })
    .y(function(d) { return y1(d.Wins); });

// Adds the svg canvas
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 lineSvg = svg.append("g");                             // **********

var focus = svg.append("g")                                // **********
    .style("display", "none");                             // **********
///////////////////

// Get the data
d3.csv("piratesAttendance.csv", function(error, data) {
    data.forEach(function(d) {
        d.Year = +d.Year;
        d.AttendancePerG = +d.AttendancePerG
        d.Wins = +d.Wins;
    });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.Year; }));
    y0.domain([0, d3.max(data, function(d) { return d.AttendancePerG; })]);
    y1.domain([0, d3.max(data, function(d) { return d.Wins; })]);

    // Add the valueline path.
    svg.append("path")
        .attr("class", "line")
        .attr("d", valueline(data))
        .attr("stroke", "gray")
        .attr("stroke-width",2)
        .attr("fill","none");

    // Add the second valueline path.
    svg.append("path")
        .attr("class", "line")
        .attr("d", valueline2(data))
        .attr("stroke", "gold")
        .attr("stroke-width",2)
        .attr("fill","none");

    // Add the X Axis
    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    // Add the Left Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .style("fill","gray")
        .call(yAxisLeft);

    // Add the Right Y Axis
    svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + width + ",0)")
        .style("fill","gold")
        .call(yAxisRight);

    /////////////
    // append the circle at the intersection               // **********
    focus.append("circle")                                 // **********
        .attr("class", "y")                                // **********
        .style("fill", "none")                             // **********
        .style("stroke", "blue")                           // **********
        .attr("r", 4);                                     // **********

    // append the rectangle to capture mouse               // **********
    svg.append("rect")                                     // **********
        .attr("width", width)                              // **********
        .attr("height", height)                            // **********
        .style("fill", "none")                             // **********
        .style("pointer-events", "all")                    // **********
        .on("mouseover", function() { focus.style("display", null); })
        .on("mouseout", function() { focus.style("display", "none"); })
        .on("mousemove", mousemove);                       // **********

    function mousemove() {                                 // **********
        var x0 = x.invert(d3.mouse(this)[0]),              // **********
            i = bisectYear(data, x0, 1),                   // **********
            d0 = data[i - 1],                              // **********
            d1 = data[i],                                  // **********
            d = x0 - d0.date > d1.date - x0 ? d1 : d0;     // **********

    focus.select("circle.y")                           // **********
        .attr("transform",                             // **********
              "translate(" + x(d.Year) + "," +         // **********
                             y0(d.AttendancePerG) + ")");        // **********
}                                                      // **********
});

 </script>
 </body>
 </html>

这里有一个带有固定代码的插件:http://plnkr.co/edit/Xj2ZyxqrY2PJVV0FML26

这里有几个问题。

首先,您的数据未按日期排序(从早到晚),这导致 bisectYear 函数无法正常工作(它始终返回 1)。通过添加修复:

data.sort(function(a, b) { return a.Year - b.Year; });

其次,您的日期(年份)值未被解析为 Date 对象,这导致了一系列问题。本质上,您的时间尺度是 运行 从 1891 毫秒到 2014 毫秒,而不是 1891 年到 2014 年!我在您在 CSV 中阅读的地方添加了这个:

data.forEach(function(d) {
    d.Year =  parseDate(d.Year)
    ...

使用新函数解析为 Date 仅基于全年:

var parseDate = d3.time.format("%Y").parse;