TypeError:无法读取未定义的属性“ year”

时间:2019-05-08 20:36:20

标签: javascript datetime d3.js

我正在尝试创建具有鼠标悬停功能的交互式折线图。当您将鼠标悬停在该行上时,可以看到该特定点的GDP值和年份。但是由于某种原因,我收到以下错误,但是我不确定为什么会发生这种情况,因为我正在将正确的格式数据集传递给该函数。

Uncaught TypeError: Cannot read property 'year' of undefined

我的代码如下:

HTML

<!DOCTYPE html>
<htmL>
  <meta charset="utf-8">
  <head>
    <style>
      .line-chart2{
        margin-top:200px;
        margin-left:100px;
        border:1px solid lightgray;
      }
      circle {
        fill: steelblue;
      }
      body { 
        font: 12px Arial;}
      path { 
        stroke: steelblue;
        stroke-width: 2;
        fill: none;
      }
      .axis path,
      .axis line {
        fill: none;
        stroke: grey;
        stroke-width: 1;
        shape-rendering: crispEdges;
      }

      div.tooltip { 
          position: absolute;           
          text-align: center;           
          width: 80px;                  
          height: 64px;                 
          padding: 2px;             
          font: 14px sans-serif;
          color: black;     
          background: lightsteelblue;   
          border: 0px;      
          border-radius: 8px;           
          pointer-events: none;         
      }
      .overlay {
          fill: none;
          pointer-events: all;
        }
      .focus circle {
        fill: #F1F3F3;
        stroke: #6F257F;
        stroke-width: 5px;
      }
      .hover-line {
        stroke: #6F257F;
        stroke-width: 2px;
        stroke-dasharray: 3,3;
      }

  </style>

  </head>
  <body>
      <svg class='line-chart2'></svg>
      <script src="https://d3js.org/d3.v4.min.js"></script> 
      <script src="math.js" type="text/javascript"></script>
      <script src="./regression.js"></script>
  </body>
</htmL>

JavaScript

var gdp=[ 387.65,   410.32,  415.73,  452.69,  462.14,
  478.96,  508.06,  599.59,  699.68,  808.90,
  920.31, 1201.11, 1186.95, 1323.94, 1656.61,
 1823.04, 1827.63, 1856.72, 2039.12,  2102.39,
 2274.22, 2600.81]; //y or GDP of India
var years=['1996','1997','1998','1999','2000','2001','2002','2003','2004','2005','2006','2007','2008','2009','2010','2011','2012','2013','2014','2015','2016','2017'];

var data_gdp=[]
  for(i=0;i<forexp.length;i++){
    data_gdp.push({year:years[i],value:gdp[i]})
    }

function drawChart_gdp(data,class_name) {
  var svgWidth = 1200, svgHeight = 400;
  var margin = { top: 60, right: 60, bottom: 60, left: 60 };
  var width = svgWidth - margin.left - margin.right;
  var height = svgHeight - margin.top - margin.bottom;
  var svg = d3.select(class_name)
    .attr("width", svgWidth)
    .attr("height", svgHeight);
  var bisectDate= d3.bisector(function(d) { return d.year; }).left;
  var g = svg.append("g")
    .attr("transform", 
       "translate(" + margin.left + "," + margin.top + ")"
    );
  var x = d3.scaleTime().range([0,width]);
  var y = d3.scaleLinear().rangeRound([height, 0]);

  var line = d3.line()
   .x(function(d) { return x(new Date(parseInt(d.year),0))})
   .y(function(d) { return y(d.value)})
   x.domain(d3.extent(data, function (d) { return new Date(parseInt(d.year),0); }));
   y.domain(d3.extent(data, function(d) { return d.value }));

   g.append("g")
   .attr("transform", "translate(0," + height + ")")
   .call(d3.axisBottom(x))
   .append("text")
    .attr("fill", "#000")
    .text("Year")
    .attr("dy", "1.90em")
    .attr("y", 5)
    .attr("x",500)
    .attr("font-size", "20px")
    .select(".domain")
    .remove();

   g.append("g")
   .call(d3.axisLeft(y))
   .append("text")
   .attr("fill", "#000")
   .attr("transform", "rotate(-90)")
   .attr("y", -80)
   .attr("x",-55)
   .attr("dy", "1.90em")
   .attr("text-anchor", "center")
   .attr("font-size", "20px")
   .text("GDP ($)")

  g.append("path")
   .datum(data)
   .attr("fill", "none")
   .attr("stroke", "steelblue")
   .attr("stroke-linejoin", "round")
   .attr("stroke-linecap", "round")
   .attr("stroke-width", 1.5)
   .attr("d", line);

   var focus = g.append("g")
   .attr("class", "focus")
   .style("display", "none");

  focus.append("line")
    .attr("class", "x-hover-line hover-line")
    .attr("y1", 0)
    .attr("y2", height);

  focus.append("line")
    .attr("class", "y-hover-line hover-line")
    .attr("x1", width)
    .attr("x2", width);

  focus.append("circle")
    .attr("r", 7.5);

  focus.append("text")
    .attr("x", 15)
    .attr("dy", ".31em");

  svg.append("rect")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .attr("class", "overlay")
    .attr("width", width)
    .attr("height", height)
    .on("mouseover", function() { focus.style("display", null); })
    .on("mouseout", function() { focus.style("display", "none"); })
    .on("mousemove",  function() { //problem in this function
      var x0 = x.invert(d3.mouse(this)[0]),
          i = bisectDate(data, x0, 1),
          d0 = data[i - 1],
          d1 = data[i],
          d = x0 - d0.year > d1.year - x0 ? d1 : d0;
      focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
      focus.select("text").text(function() { return d.value; });
      focus.select(".x-hover-line").attr("y2", height - y(d.value));
      focus.select(".y-hover-line").attr("x2", width + width);
     });

  }
drawChart_gdp(data_gdp,'.line-chart2');

1 个答案:

答案 0 :(得分:1)

由于x是时间标度,因此返回的值...

var x0 = x.invert(d3.mouse(this)[0])

...是日期对象,如下所示:

Fri Nov 29 1996 19:56:00

但是,在您的数据中,您有字符串

[{year: "1996", value: 387.65}, {year: "1997", value: 410.32} etc...];

解决方案非常简单,只需格式化日期即可:

var x0 = d3.timeFormat("%Y")(x.invert(d3.mouse(this)[0]))

这是您所做的更改的代码:

var gdp = [387.65, 410.32, 415.73, 452.69, 462.14,
  478.96, 508.06, 599.59, 699.68, 808.90,
  920.31, 1201.11, 1186.95, 1323.94, 1656.61,
  1823.04, 1827.63, 1856.72, 2039.12, 2102.39,
  2274.22, 2600.81
]; //y or GDP of India
var years = ['1996', '1997', '1998', '1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015', '2016', '2017'];

var data_gdp = []
for (i = 0; i < years.length; i++) {
  data_gdp.push({
    year: years[i],
    value: gdp[i]
  })
}

function drawChart_gdp(data, class_name) {
  var svgWidth = 1200,
    svgHeight = 400;
  var margin = {
    top: 60,
    right: 60,
    bottom: 60,
    left: 60
  };
  var width = svgWidth - margin.left - margin.right;
  var height = svgHeight - margin.top - margin.bottom;
  var svg = d3.select(class_name)
    .attr("width", svgWidth)
    .attr("height", svgHeight);
  var bisectDate = d3.bisector(function(d) {
    return d.year;
  }).left;
  var g = svg.append("g")
    .attr("transform",
      "translate(" + margin.left + "," + margin.top + ")"
    );
  var x = d3.scaleTime().range([0, width]);
  var y = d3.scaleLinear().rangeRound([height, 0]);

  var line = d3.line()
    .x(function(d) {
      return x(new Date(parseInt(d.year), 0))
    })
    .y(function(d) {
      return y(d.value)
    })
  x.domain(d3.extent(data, function(d) {
    return new Date(parseInt(d.year), 0);
  }));
  y.domain(d3.extent(data, function(d) {
    return d.value
  }));

  g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x))
    .append("text")
    .attr("fill", "#000")
    .text("Year")
    .attr("dy", "1.90em")
    .attr("y", 5)
    .attr("x", 500)
    .attr("font-size", "20px")
    .select(".domain")
    .remove();

  g.append("g")
    .call(d3.axisLeft(y))
    .append("text")
    .attr("fill", "#000")
    .attr("transform", "rotate(-90)")
    .attr("y", -80)
    .attr("x", -55)
    .attr("dy", "1.90em")
    .attr("text-anchor", "center")
    .attr("font-size", "20px")
    .text("GDP ($)")

  g.append("path")
    .datum(data)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-linejoin", "round")
    .attr("stroke-linecap", "round")
    .attr("stroke-width", 1.5)
    .attr("d", line);

  var focus = g.append("g")
    .attr("class", "focus")
    .style("display", "none");

  focus.append("line")
    .attr("class", "x-hover-line hover-line")
    .attr("y1", 0)
    .attr("y2", height);

  focus.append("line")
    .attr("class", "y-hover-line hover-line")
    .attr("x1", width)
    .attr("x2", width);

  focus.append("circle")
    .attr("r", 7.5);

  focus.append("text")
    .attr("x", 15)
    .attr("dy", ".31em");

  svg.append("rect")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
    .attr("class", "overlay")
    .attr("width", width)
    .attr("height", height)
    .on("mouseover", function() {
      focus.style("display", null);
    })
    .on("mouseout", function() {
      focus.style("display", "none");
    })
    .on("mousemove", function() { //problem in this function
      var x0 = d3.timeFormat("%Y")(x.invert(d3.mouse(this)[0])),
        i = bisectDate(data, x0, 1);
      d0 = data[i - 1],
        d1 = data[i],
        d = x0 - d0.year > d1.year - x0 ? d1 : d0;
      focus.attr("transform", "translate(" + x(d.year) + "," + y(d.value) + ")");
      focus.select("text").text(function() {
        return d.value;
      });
      focus.select(".x-hover-line").attr("y2", height - y(d.value));
      focus.select(".y-hover-line").attr("x2", width + width);
    });

}
drawChart_gdp(data_gdp, '.line-chart2');
<head>
  <style>
    circle {
      fill: steelblue;
    }
    
    body {
      font: 12px Arial;
    }
    
    path {
      stroke: steelblue;
      stroke-width: 2;
      fill: none;
    }
    
    .axis path,
    .axis line {
      fill: none;
      stroke: grey;
      stroke-width: 1;
      shape-rendering: crispEdges;
    }
    
    div.tooltip {
      position: absolute;
      text-align: center;
      width: 80px;
      height: 64px;
      padding: 2px;
      font: 14px sans-serif;
      color: black;
      background: lightsteelblue;
      border: 0px;
      border-radius: 8px;
      pointer-events: none;
    }
    
    .overlay {
      fill: none;
      pointer-events: all;
    }
    
    .focus circle {
      fill: #F1F3F3;
      stroke: #6F257F;
      stroke-width: 5px;
    }
    
    .hover-line {
      stroke: #6F257F;
      stroke-width: 2px;
      stroke-dasharray: 3, 3;
    }
  </style>

</head>

<body>
  <svg class='line-chart2'></svg>
  <script src="https://d3js.org/d3.v4.min.js"></script>
</body>