我试图在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
答案 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; });