Skip to content

关于折线图上的原点平滑移动的实现 #91

Description

@ckinmind

参考资料

核心代码部分

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))

      }

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions