D3单折线图mousemove事件失效 悬浮圆点固定在折线末端不跟随鼠标
问题原因
你的问题出在二分查找的逻辑存在两处不匹配:
- 类型不匹配:
x.invert()返回的是Date对象,但bisector访问器返回的是原始字符串格式的日期,二者比较不会按时间逻辑计算,导致bisect结果固定 - 数组顺序不匹配:你的原始数据是按日期倒序排列的,而d3.bisector默认针对升序数组做二分查找,顺序错误也会导致查找失效
修复方案
你可以按照以下步骤修改代码:
- 提前处理数据,将日期转为Date对象并按升序排序,替换lineChart函数内的原始data使用逻辑:
function lineChart({data}){ const priceMargin = {top: 10, right: 30, bottom: 30, left: 60}; const priceWidth = 1000 - priceMargin.left - priceMargin.right; const priceHeight = 400 - priceMargin.top - priceMargin.bottom; const svg = d3.select(this) .append('svg') .attr("width", priceWidth + priceMargin.left + priceMargin.right) .attr("height", priceHeight + priceMargin.top + priceMargin.bottom) .append("g") .attr("transform", `translate(${priceMargin.left},${priceMargin.top})`); const parseDate = d3.timeParse('%Y-%m-%dT%H:%M:%S%Z') // 新增:预处理数据 转日期+升序排序 const processedData = data.map(item => ({ ...item, date: parseDate(item.date) })).sort((a, b) => a.date - b.date) const x = d3.scaleTime() .domain(d3.extent(processedData, d => d.date)) .range([0, priceWidth]); const y = d3.scaleLinear() .domain(d3.extent(processedData, d => d.close)) .range([priceHeight, 0]); const line = d3.line() .x(d => x(d.date)) .y(d => y(d.close)) svg.append("path") .attr("fill", "none") .attr("stroke", "rgba(255, 31, 31)") .attr('d', line(processedData)) .style("stroke-width", "2px") // 后续其他用到data的地方都替换为processedData
- 修改mousemove事件内的bisect查找和比较逻辑:
function mousemove() { const x0 = x.invert(d3.mouse(this)[0]), i = bisectDate(processedData, x0, 1), d0 = processedData[i - 1], d1 = processedData[i], // 转时间戳比较时间差 d = x0.getTime() - d0.date.getTime() > d1.date.getTime() - x0.getTime() ? d1 : d0; focus.attr("transform", `translate(${x(d.date)},${y(d.close)})`); focus.select("text").text(formatCurrency(d.close)); }
修改完成后悬浮点就会跟随鼠标位置匹配对应的折线上的点了。
内容的提问来源于stack exchange,提问作者Taihuynh812
相关产品推荐
相关产品推荐

