D3: поиск графа y-координаты с помощью мыши

Я делаю интерактивную диаграмму области, используя D3. В то время как мышь над диаграммой области, я хотел бы, чтобы точка прокатилась по верхней части диаграммы, как в следующем примере: http://hci.stanford.edu/jheer/files/zoo/ex/time/multiples.html

Как только я получу позицию мыши (используя d3.mouse), как мне перевести эти координаты в соответствующие данные? Ось X проста, используя инверсию x-scale (например, x.invert). Однако я не могу найти соответствующую координату y для моего графика. В идеале я мог бы "найти" координату x в своих данных и найти соответствующую координату y, но не знаю, как это сделать с D3. Спасибо!

Ответ 1

На самом деле относительно легко создать собственную таблицу поиска:

/* Create the lookup table */
var table = {};
data.forEach(function(d) {
    table[d.x] = d.y;
});

Это жизнеспособное решение, если у вас достаточно данных, но скорее всего вам понадобится использовать какое-то округление или интерполятор для заполнения промежуточных значений x. Например, если между вашими точками существует фиксированный интервал, вы можете использовать линейный интерполятор и выполнить следующие вычисления, чтобы получить координаты для вашего круга на mouseover:

var x = d3.mouse(this)[0];
var y;

if ( table[x] === undefined ) {
    var lower = x - (x % SPACING);
    var upper = lower + SPACING;
    var between = d3.interpolateNumber(table[lower], table[upper]);
    y = between( (x % SPACING) / SPACING );
} else {
    y = table[x];
}

Вот код в действии: http://jsfiddle.net/Wexcode/KGxHF/

Вот еще один пример того, как вы могли это сделать из Майк Босток: http://bl.ocks.org/3025699

Ответ 2

mbostock (автор D3.js) реализует это здесь

svg.append("rect")
  .attr("class", "overlay")
  .attr("width", width)
  .attr("height", height)
  .on("mouseover", function() { focus.style("display", null); })
  .on("mouseout", function() { focus.style("display", "none"); })
  .on("mousemove", mousemove);

function mousemove() {
  var x0 = x.invert(d3.mouse(this)[0]),
    i = bisectDate(data, x0, 1),
    d0 = data[i - 1],
    d1 = data[i],
    d = x0 - d0.date > d1.date - x0 ? d1 : d0;
  focus.attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")");
  focus.select("text").text(formatCurrency(d.close));
}

Ответ 3

Я использую этот код, чтобы увидеть значение X и Y каждой точки и нарисовать круг на моей кривой на событии мыши: пример jsFiddle здесь

Y_value является глобальным!

var Y_value; 

я определяю свою ось осязания

x = d3.time.scale().range([0, w]);
y = d3.scale.linear().range([h, 0]);

i определите курсор круга

var circle = svg.append("circle")
        .attr("r", 8)
        .attr("cx", 0)
        .attr("cy", 0)
        .style({fill: '#fff', 'fill-opacity': .2, stroke: '#000', "stroke-width": '1px'})
        .attr("opacity", 0);

добавить всплывающую подсказку на круге

var tooltip = circle.append("svg:title");

и у меня есть код события

mySensitiveArea.on("mousemove", function() {
    var X_pixel = d3.mouse(this)[0],
        X_date = x.invert(X_pixel);
    var Y_pixel = y(Y_value);

    var pathData = curve1.data()[0]; // recupere donnée de la courbe

    pathData.forEach(function(element, index, array) {
            if ((index+1 < array.length) && (array[index].date <= X_date) && (array[index+1].date >= X_date)) {
                if (X_date-array[index].date < array[index+1].date-X_date)  Y_value = array[index].val;
                else Y_value = array[index+1].val;
            }
        });

        circle.attr("opacity", 1)
            .attr("cx", X_px)
            .attr("cy", Math.round(y(Y_value)));

        tooltip.text("X = " + (X_date) + "\nY = " + (Y_value));
    });