参考资料
核心代码部分
function mousemove() {
const x0 = x.invert(d3.mouse(this)[0]) // x轴坐标, 时间值
const i = bisectDate(data, x0, 1) // 使用访问器和比较器二分查找, 判断当前的落点距离那个实际值更加接近,并且有限选择左边的值
const d0 = data[i - 1] // 测试发现i从1开始(上面第三个参数是0是1都一样), bisectDate方法的第三个参数可以指定开始index
const d1 = data[i] // d0 d1是要插入的前后数据
// 根据鼠标位置控制tooltip显示在左边还是右边
if (d3.mouse(this)[0] < (width / 2)) {
svgTooltips
.transition()
.duration(150)
.ease(d3.easeLinear)
.style('left', 'auto')
.style('right', '0')
} else {
svgTooltips.transition()
.duration(150)
.ease(d3.easeLinear)
.style('left', '0')
.style('right', 'auto')
}
// 到最右边之后d1会是undefined
if (d1) {
const d = x0 - d0.date > d1.date - x0 ? d1 : d0
const formatDate = d3.timeFormat("%d %b %Y")
svgTooltips.select("text.tiptxt1").text(formatDate(d.date))
svgTooltips.select("text.tiptxt2").text(`${Math.round(d.value / 10)}%`)
// 这里这个path就是上面不知道干嘛用隐藏起来的path
const pathEl = path.node()
// console.log(pathEl)
const pathLength = pathEl.getTotalLength() // 这个是用来获取路径长度的,只适用于path,在path动画里用过这个
const BBox = pathEl.getBBox() // 返回给定元素的边界框描述,这里是返回path元素的水平距离
const scale = pathLength / BBox.width
const offsetLeft = document.getElementById("cc").offsetLeft // 获取相对于父对象的左边距,这里基本是指导页面左边距了,因为父对象是body
console.log('-----pathLength', pathLength)
console.log('-----BBox', BBox)
// console.log('-----scale', scale)
console.log('-----offsetLeft', offsetLeft)
console.log('-----d3.event.pageX', d3.event.pageX)
// pageX距离页面左边的距离,所以这里的xc应该是鼠标位置距离图左边的距离
const xc = d3.event.pageX - (offsetLeft)
let beginning = xc
let end = pathLength
let target
console.log('--------xc', xc)
// 没看懂这的平滑移动的算法
while (true) {
target = Math.floor((beginning + end) / 2)
pos = pathEl.getPointAtLength(target) // 获取给定长度length在path的坐标 (x, y)
// 如果target是末端/开始或者鼠标位置则break, why
if ((target === end || target === beginning) && pos.x !== xc) {
break
}
if (pos.x > xc) {
end = target
} else if (pos.x < xc) {
beginning = target
} else {
break
} //position found
}
// 选中移动的circe改变其位置
focus.select("circle.y").attr("transform", `translate(${pos.x},${pos.y})`)
// 改变移动circle下面线的位置
focus.select(".x")
.attr("transform", `translate(${pos.x},${pos.y})`)
.attr("y2", height - y(d.value))
}
参考资料
核心代码部分