用D3+Next.js从MongoDB取数绘折线图遇NaN错误
D3.js折线图报错:
<path> attribute d: Expected number, "MNaN,450LNaN,0" 你遇到的错误是因为D3生成路径时拿到了NaN值,结合你的代码和排查信息,核心问题大概率出在日期格式不兼容上,而非avgPace的读取方式。
问题根源
d3.scaleTime()要求输入的是标准的Date对象,但如果你的原始data中date字段是字符串(比如"2024-05-01")或者其他非Date类型,x比例尺无法将其映射为有效数值,导致x(d.date)返回NaN,最终路径生成失败。
另外你的代码中还有一处冗余逻辑:创建line时先设置了.y(d => y(d.avgPace)),但在生成路径时又重新覆盖了y轴映射,虽然这不会直接导致错误,但可以简化。
修复步骤
转换日期为Date对象
在处理chartData时,将字符串日期转为Date实例:const chartData = data.map(item => ({ date: new Date(item.date), // 关键转换 avgPace: item.avgPace, }))验证比例尺有效性
可以在代码中添加日志,确认x轴的domain是否为有效日期范围:console.log('X轴定义域:', x.domain()) // 应该输出两个Date对象 console.log('Y轴定义域:', y.domain()) // 应该输出avgPace的最小/最大值简化line生成逻辑(可选)
既然在路径生成时会动态设置y轴映射,初始line可以只保留x轴配置:const line = d3.line() .x(d => x(d.date)) // 去掉多余的.y配置
修复后的完整代码示例
const RunGraph = ({ data }) => { const svgRef = useRef() useEffect(() => { // 关键:将日期转为Date对象 const chartData = data.map(item => ({ date: new Date(item.date), avgPace: item.avgPace, })) const margin = { top: 20, right: 20, bottom: 30, left: 50 } const width = 960 - margin.left - margin.right const height = 500 - margin.top - margin.bottom const svg = d3.select(svgRef.current) // 清空旧内容(防止多次渲染叠加) svg.selectAll('*').remove() const x = d3.scaleTime() .range([0, width]) .domain(d3.extent(chartData, d => d.date)) .nice() const y = d3.scaleLinear() .range([height, 0]) .nice() const values = Object.keys(chartData[0]).filter(key => key !== "date"); y.domain([ d3.min(chartData, d => d3.min(values, value => d[value])), d3.max(chartData, d => d3.max(values, value => d[value])) ]) // 简化line配置 const line = d3.line() .x(d => x(d.date)) const paths = values?.map(value => { return { value: value, path: svg .append('path') .datum(chartData) .attr('fill', 'none') .attr('stroke', 'steelBlue') .attr('stroke-width', 1.5) .attr('d', line.y(d => y(d[value]))) } }) svg .append('g') .attr('transform', `translate(${margin.left}, ${height + margin.top})`) // 修正偏移,包含margin .call(d3.axisBottom(x)) svg.append('g') .attr('transform', `translate(${margin.left}, ${margin.top})`) // 修正偏移 .call(d3.axisLeft(y)) }, [data]) return ( <svg ref={svgRef} width={960} height={500}> </svg> ) } export default RunGraph
额外补充:修复了svg的宽高设置和坐标轴的偏移计算,避免图表被margin截断。
内容的提问来源于stack exchange,提问作者Lofton Gentry
相关产品推荐
相关产品推荐

