d3.js折线图工具提示内容未显示

时间:2019-09-01 15:17:38

标签: javascript variables d3.js

我试图在d3.js线图线条工具提示上显示csv文件的温度和时间戳列下的数据。我希望相应的日期和温度显示在工具提示上

这是我从控制台收到的错误 “未捕获的TypeError:无法读取未定义的属性'timestamp'     在SVGPathElement上。 (index.js:70)     在SVGPathElement上。 (d3.v5.js:2)”

div.html(formatTime((d.timestamp))+“
” +(+ d.temperature))

我希望日期和温度显示在工具提示上

let svg = d3.select('svg'),
  height = +svg.attr('height'),
  width = +svg.attr('width');
  let formatTime = d3.timeFormat("%m/%d/%Y");

const render = data => {
  const title = 'Engagements Over-Time(Total: 946K)';
  const xValue = d => d.timestamp;

  const yValue = d => d.temperature;

  const margin = {top: 60, right: 60, bottom: 88, left: 105};
  const innerwidth = width - margin.left - margin.right;
  const innerheight = height - margin.top - margin.bottom;
  
  const xScale = d3.scaleTime()
  	.domain(d3.extent(data, xValue))
    .range([0, innerwidth - 150])
  	.nice();
  
	const yScale = d3.scaleLinear()
  	.domain([0, d3.max(data, d => d.temperature)])
  	.range([innerheight, 0])
  	.nice();
    
  const g = svg.append('g')
  	.attr('transform', `translate(${margin.left}, ${margin.top+30})`);
    
    let parseDate = d3.timeFormat("%m/%d/%Y");
    const xAxis = d3.axisBottom(xScale)
                .tickFormat(parseDate)
                .tickPadding(5)

                
    // Define the div for the tooltip
  let div = d3.select("body").append("div")	
      .attr("class", "tooltip")				
      .style("opacity", 0)
      .style("display", "null");;

  let yAxisTicFormat = number => d3.format('.1s')(number)
  const yAxis = d3.axisLeft(yScale)
              .tickPadding(35)
              .tickFormat(yAxisTicFormat)
  ;

  const yAxisG = g.append('g').call(yAxis);
  yAxisG.selectAll('.domain').remove();
  
  const xAxisG = g.append('g').call(xAxis)
  	.attr('transform', `translate(0, ${innerheight})`);

  xAxisG.select('.domain').remove();
  
  const lineGenerator = d3.line()
  	.x(d => xScale(xValue(d)))
  	.y(d => yScale(yValue(d)))
  	.curve(d3.curveBasis);
 	 
  g.append('path')
  	.attr('class', 'line-path')
    .attr('d', lineGenerator(data))
    .on("mouseover", function(d) {
       div.transition() 
       .duration(500) 
       .style("opacity", 1)
       .style("display", "block");
       console.log(xValue);

       div.html(formatTime((d.timestamp)) + "<br/>" + (+d.temperature)) 
       .style("left", (d3.event.pageX-1) + "px") 
       .style("top", (d3.event.pageY - 28) + "px"); 
      }) 
      
       .on("mouseout", function(d) {
        div.transition() 
        .duration(500) 
        .style("opacity", 0); });;
  
  g.append('text')
  	.attr('class', 'title')
    .attr('y', -40)
    .text(title);

};

d3.csv('temperature-in-san-francisco.csv').then(data =>{
  //console.log(data)
    data.forEach(d => {
        d.timestamp =new Date (d.timestamp);
        d.temperature = +d.temperature*1000;
     
    });


    render(data);
    //console.log(data)
        
})

我的数据

时间戳,温度

2007-04-23,93.24

2007-04-24,95.35

2007-04-25,98.84

2007-04-26,99.92

1 个答案:

答案 0 :(得分:0)

您似乎认为在mouseover事件上将返回不同的数据点,具体取决于光标触摸该行的位置,但是要注意,该行只是由路径定义字符串定义的单个svg元素

您的数据数组传递到行生成器,该生成器返回定义该行的字符串,该字符串被设置为路径的d(对于 definition 而不是data(可能))属性。已经创建了一个svg path元素,但尚未绑定任何数据。

所以那个原因

div.html(formatTime((d.timestamp))

抛出参考错误是没有数据绑定到path元素,因此回调的第一个参数(d)返回undefined

如果希望用户能够触摸线的不同位置并查看数据,则可以使用与线定义相同的比例在该线上创建点(圆)。各个circle元素 将具有绑定到它们的数据。

有多种方法可以在鼠标悬停在圆圈on this SO post上时显示工具提示。最简单的方法似乎是Lars Kotthoff建议的方法,它不需要鼠标悬停侦听器,而是使用浏览器的内置功能在其中显示悬停元素的标题(这来自Lar的示例):< / p>

d3.selectAll("circle")
.data(data)
.enter()
  .append("svg:circle")
  .attr('cx', d => xScale(d.timestamp))
  .attr('cy', d => yScale(d.temperature))
  .attr('r', 3)
  .attr('fill', 'steelblue')
  .append("svg:title")
  .text(function(d) { return d.x; });