【问题标题】:D3 Line chart doesn't return correct value on ticks mouse overD3 折线图在鼠标悬停时未返回正确的值
【发布时间】:2021-06-12 12:40:51
【问题描述】:

我有一个包含当年和比较年/上一期的折线图。我想在悬停时显示一个工具提示,因此它将显示当前年份和比较年份的当前刻度值。但是,我注意到返回的总值与 y 轴上的金额不匹配(请参见下面的屏幕截图)。

根据上图,该值应在 30M - 40M 之间,但显示为 56150248.2。

CodeSandbox

// tooltip on x axis
    d3.selectAll(".xAxis > .tick")
      .style("color", "#65757E")
      .on("mouseover", function (d) {
        console.log("data");
        const mousePosition = d3.pointer(d);
        const data = yScale.invert(mousePosition[0]);
        console.log("pos", mousePosition);
        console.log("data", data);
      })
      .on("mouseout", (d) => {
        console.log("test");
      });

【问题讨论】:

    标签: javascript d3.js tooltip data-visualization linechart


    【解决方案1】:

    会发生以下情况:

    • 您选择的鼠标悬停是d3.selectAll(".xAxis > .tick")
    • 在线:.on("mouseover", function (d) { 参数d 指的是通过的事件。我建议 称它为 event 而不是 d 否则会令人困惑
    • mousePosition 由一个具有奇怪坐标的数组初始化,即相对于选择的坐标(即刻度)

    见:d3.pointer(event[, target])

    返回一个由数字 [x, y] 组成的二元素数组,表示 指定事件相对于指定目标的坐标。 事件可以是 MouseEvent、PointerEvent、Touch 或自定义事件 持有 UIEvent 作为 event.sourceEvent。

    如果未指定目标,则默认为源事件的 currentTarget 属性(如果可用)。如果目标是 SVG 元素, 事件的坐标使用 屏幕坐标变换矩阵。如果目标是 HTML 元素,事件的坐标相对于 目标边界客户矩形的左上角。 (因此, 坐标系只能相对于客户端进行平移 坐标。另见 GeometryUtils。)否则,[event.pageX, event.pageY] 被返回。

    • const data = yScale.invert(mousePosition[0]); 使用 mousePosition[0] 指代 x 位置,您的意思可能是 mousePosition[1]

    要使用与 yscale 反转的坐标,您希望坐标相对于直接在 svg 下的平移 g。您已经选择了变量 svg 引用的那个元素。

    // tooltip on the g child of the svg
        svg  
          .style("color", "#65757E")
          .on("mouseover", function (event) {
            console.log("data");
            const mousePosition = d3.pointer(event);
            const data = yScale.invert(mousePosition[1]);
            console.log("pos", mousePosition);
            console.log("data", data);
          })
          .on("mouseout", (event) => {
            console.log("test");
          });
    

    更新 06/13/2021 基于以下 cmets: 你可能想做这样的事情(不确定我是否引用了正确的数据,但你可以从这里开始工作:

    d3.selectAll(".xAxis > .tick")  
          .style("color", "#65757E")
          .on("mousemove", function (event) {
            const mousePosition = d3.pointer(event, svg.node()); // gets [x,y]
            console.log("mouse position:", mousePosition);
            const currentDate = xScale.invert(mousePosition[0]); // converts x to date
            console.log("date at position:", currentDate);
            const bisect = d3.bisector(d => new Date(d.date)) // create a bisector
    
            const index_currentData = bisect.right(lineChartData.values[0].dataset, currentDate);     
            if (index_currentData < lineChartData.values[0].dataset.length) {
              console.log(`Current data at index[${index_currentData}]: ${lineChartData.values[0].dataset[index_currentData].value}`);
            }
    
            const index_comparisonData = bisect.right(comparisonData.values[0].dataset, currentDate);     
            if (index_comparisonData < comparisonData.values[0].dataset.length) {
              console.log(`Comparison data at index[${index_comparisonData}]: ${comparisonData.values[0].dataset[index_comparisonData].value}`);
            }
          })
    

    【讨论】:

    • 非常感谢!通过在这种情况下使用svg 可以工作,但是当我将鼠标悬停在图表中的任何位置时都会出现工具提示,但是如何使其仅在悬停在刻度上时出现?
    • 基本上我必须在那个特定的刻度上选择那个确切时间点的值,因为我有一个带有两个值的工具提示,带有一些颜色代码标签,例如当前期间的红色和比较的蓝色期间,我正在弄清楚如何通过将鼠标悬停在同一个刻度上来获取值?所以无论我的鼠标在哪里,工具提示都会为每行显示两个值。并且值是恒定的,不受鼠标y 在该刻度上的位置的影响。
    • 我已经更新了我的答案。我希望你能从这个开始工作......我不确定你为什么使用 2 个单独的 y 刻度......
    • 谢谢,非常感谢。我使用一个 yScale 作为当前周期线,使用 yScale2 比较周期,想不出更优雅的解决方案...
    • 我在想你可以对两条线使用相同的 yscale ......在我更新的答案中,数据在某一点似乎相似,可能是我不理解你拥有的数据。但我希望 d3.pointer() 和 d3.bisector() 的正确使用变得清晰
    猜你喜欢
    • 2015-02-20
    • 1970-01-01
    • 2014-07-05
    • 2015-04-22
    • 2018-01-23
    • 1970-01-01
    • 2017-01-19
    • 2016-03-14
    • 2018-10-15
    相关资源
    最近更新 更多