D3 показать подсказку при наведении мыши на тайм-аут

Я хочу добавить всплывающие подсказки к элементам рта каждый раз, когда мышь входит в прямоугольник, а мышь находится над прямоугольником через несколько миллисекунд. Я также хочу удалить их, когда мышь покидает любой прямоугольник.

Я попытался связать его с событиями d3 и использовать setTimeout / clearTimeout.

Кажется, что это работает, за исключением случаев, когда вы быстро перемещаете мышь по различным полосам, когда линия подсказки перемещается,

Проблема в этом случае заключается в том, что всплывающая подсказка перемещается от бара к бару, в который мышь входит / выходит с игнорированием тайм-аута. Текст подсказки, кажется, делает некоторые странные вещи.

Позвольте мне показать вам, как всплывающая подсказка появляется до истечения времени ожидания:

GIF показывая проблему

ДЕМО и ПОЛНЫЙ КОД на CODEPEN

Код для привязки функций, которые рисует подсказки:

... 
var bar = svg.select(".bars")
            .selectAll(".barchart-group")
            .data(data);
... 
var come = bar.enter()
            .append("rect")
            .style("stroke", undefined)
            .style("fill", "hsla(34, 82%, 48%, 0.79)");
... 
        //bind events to new bars
        come.on("mouseover", delayTooltip)
            .on("mouseout", removeBarTooltip);
... 

Код функции, связанной с tootlip:

function delayTooltip(d, i) {
  // this here is every rect of the bar chart
    this.hoverTimeout = window.setTimeout(addBarTooltip.bind(this), 1000, d, i);
}

function addBarTooltip(d, i) {
  // **** PROBLEM **** 
  // this executes whithout waiting the set timeout
    var firstAnims = 500;
    var thisbar = d3.select(this);
    var tooltip = d3.select(this.parentNode);
    var gRoot = d3.select(this.parentNode.parentNode);
    //Lets define some points of interest
    var p0 = [+thisbar.attr("x") + (barWidth - 1) / 2, +thisbar.attr("y")];
    var p1 = [p0[0], +p0[1] - 9];
    var p2 = [p0[0], +p0[1] - 13];
    //relevant points to draw tooltips
    var line = gRoot.select(".linePointers");
    var text = gRoot.select(".textHelpers");
    line.append("polyline")
        .style("stroke-dasharray", "2,1")
        .style("stroke", "black")
        .attr("points", [p0, p0])
        .transition("line-Y-axis")
        .duration(firstAnims)
        .attrTween("points", function(d, i, a) {
            return d3.interpolate([p0, p0], [p0, p1]);
        });

    text.append("text")
        .attr("dy", ".2em")
        .attr("text-anchor", "middle")
        .attr("x", p2[0])
        .attr("y", p1[1])
        .text(d.value)
        .style("font-size", ".85em")
        .style("opacity", 0)
        .transition("text-Y-axis")
        .delay(firstAnims)
        .duration(300)
        .style("opacity", 1)
        .attr("y", p2[1]);

}

function removeBarTooltip() {
    window.clearTimeout(this.hoverTimeout);
    var firstAnims = 200;
    var thisbar = d3.select(this);
    var tooltip = d3.select(this.parentNode);
    var gRoot = d3.select(this.parentNode.parentNode);
    //relevant points to draw tooltips
    var p0 = [+thisbar.attr("x") + (barWidth - 1) / 2, +thisbar.attr("y")];
    var p1 = [p0[0], +p0[1] - 9];
    var p2 = [p0[0], +p0[1] - 13];
    //Lets make a group for each part of our tooltip
    var line = gRoot.select(".linePointers")
        .selectAll("polyline");
    var text = gRoot.select(".textHelpers")
        .selectAll("text");

    line.transition("line-Y-axis")
        .duration(firstAnims)
        .attrTween("points", function(d, i, a) {
            return d3.interpolate([p0, p1], [p0, p0]);
        })
        .remove();

    text.style("opacity", 0.7)
        .transition("text-Y-axis")
        .delay(firstAnims)
        .duration(300)
        .style("opacity", 0)
        .attr("dy", p0[1] - p2[1])
        .remove();
}

Я предпочитаю избегать добавления любых других библиотек, если это возможно.

2 ответа

Решение

Проблема была в removeBarTooltip(), Давайте сначала посмотрим на эти две строки, где я определил точки для линии tootlip:

var p0 = [+thisbar.attr("x") + (barWidth - 1) / 2, +thisbar.attr("y")];
var p1 = [p0[0], +p0[1] - 9];

позже в этой функции я делал:

[...]
line.transition("line-Y-axis")
    .duration(firstAnims)
    .attrTween("points", function(d, i, a) {
        return d3.interpolate([p0, p1], [p0, p0]);
    })
    .remove();

Так что происходило то, что линия Tootlip перемещалась от бара к бару из-за var p0 значение в зависимости от полосы мыши над.

Чтобы решить эту проблему, я изменил переход строки с помощью attrTween на:

line.transition("line-Y-axis")
    .duration(firstAnims)
    .attrTween("points", function(d, i, a) {
        var p0current = a.split(",");
        var p1current = p0current.splice(2);
        return d3.interpolate([p0current, p1current], [p0current, p0current]);
    })
    .remove();

Где он принимает фактическое значение свойства points с аргументом a и интерполирует фактическое событие перемещения, основываясь только на нем.

ДЕМО и ПОЛНЫЙ код на CODEPEN.

Попробуйте foxToolTip.js

Имеет параметры задержки и длительности перехода как при наведении, так и при наведении мыши

https://github.com/MichaelRFox/foxToolTip.js

Проверьте мой bl.ock по адресу: http://bl.ocks.org/MichaelRFox/59cdc1c3478fb0362448cf87fdab30d0

Использует задержку 0,5 секунды для отображения всплывающей подсказки при наведении на текстовые элементы

Другие вопросы по тегам