如何使用D3.js解析Date.now()时间戳生成折线图并设置x轴分钟刻度
修复后可用的代码及说明
错误根因梳理
- 时间解析逻辑错误:你用的
d3.timeParse("%s")仅支持解析10位秒级时间戳,接口返回的timestamp是13位毫秒级时间戳,解析结果为null,传入比例尺后就会生成NaN值,导致路径报错 - 比例尺domain设置错误:x轴
scaleTime的domain需要传入Date对象,你错误调用了格式化方法timeFormat处理时间戳,生成了非法的字符串入参 - 绘图区域偏移错误:你给整个svg元素设置了向下偏移的transform,导致所有元素坐标计算错位
- 重复渲染问题:每次useEffect触发都会新增一个svg元素,没有清理旧内容
修正后的代码
useEffect(() => { const svgContainer = d3.select(d3Container.current); // 先清空旧内容,避免重复渲染 svgContainer.selectAll("*").remove(); const margin = { top: 20, right: 20, bottom: 50, left: 70 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; // 13位毫秒时间戳直接转Date对象即可,不需要用parseTime const getDate = (timestamp) => new Date(timestamp); // 设置x轴10分钟窗口:结束时间为最新数据的时间,开始时间为结束时间减10分钟 const latestTime = getDate(Math.max(...data.map(d => d.timestamp))); const tenMinutesAgo = new Date(latestTime.getTime() - 10 * 60 * 1000); // x轴比例尺domain直接传Date对象 const x = d3.scaleTime() .domain([tenMinutesAgo, latestTime]) .range([0, width]); const y = d3.scaleLinear() .domain([0, d3.max(data, (d) => d.loadAverage)]) .nice() .range([height, 0]); // 时间格式化仅用于刻度展示,不要用于比例尺计算 const timeFormat = d3.timeFormat("%M:%S"); const myLine = d3.line() .x((d) => x(getDate(d.timestamp))) .y((d) => y(d.loadAverage)); // 绘制主画布 const svg = svgContainer.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})`); // 绘制折线 svg.append("path") .datum(data) .attr("d", myLine) .attr("fill", "none") .attr("stroke", "steelblue") .attr("stroke-width", 1.5) .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round"); // 绘制x轴:强制1分钟间隔刻度 svg.append("g") .attr("transform", `translate(0, ${height})`) .call(d3.axisBottom(x) .ticks(d3.timeMinute.every(1)) .tickFormat(timeFormat) ); // 绘制y轴 svg.append("g") .call(d3.axisLeft(y)); }, [data]);
关键配置说明
- 固定10分钟窗口:通过手动计算
latestTime和tenMinutesAgo设置x轴domain即可,如果你需要窗口随时间自动滚动,可以将latestTime替换为new Date() - 1分钟刻度间隔:通过
ticks(d3.timeMinute.every(1))配置x轴,会自动按整分钟生成刻度
内容的提问来源于stack exchange,提问作者Bianca
相关产品推荐
相关产品推荐

