Как правильно добавить и использовать D3 Events? - PullRequest
32 голосов
/ 27 марта 2012

У меня проблемы с пониманием использования событий D3 и функций отправки. У меня есть пример графика, над которым я работал: " Вертикальные гистограммы с легендами ."

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

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

Ответы [ 2 ]

60 голосов
/ 27 марта 2012

Этот вопрос похож на тот, который вы опубликовали в группе Google d3-js. Не дублируя то, что я там написал, я повторю, что вы, вероятно, не хотите d3.dispatch; это предназначено для пользовательских абстракций событий (таких как кисти и поведение). Будет проще использовать нативные события.

Если вы хотите, чтобы ваша легенда изменила цвет соответствующей полосы при наведении мыши, разбейте проблему на шаги:

  1. Обнаружение наведения мыши на легенду.
  2. Выберите соответствующий бар.
  3. Изменить цвет заливки бара.

Сначала используйте selection.on , чтобы прослушивать события «наведения мыши» на элементах легенды. Ваша функция слушателя будет вызвана, когда мышь наведет курсор на элемент легенды, и будет вызвана с двумя аргументами: данные (d) и индекс (i). Вы можете использовать эту информацию для выбора соответствующей панели с помощью d3.select . Наконец, используйте selection.style , чтобы изменить стиль «заливки» новым цветом.

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

function mouseover(d, i) {
  d3.select(rect[0][i]).style("fill", "red");
}

Если вы не хотите полагаться на индекс, другой вариант состоит в том, чтобы сканировать совпадающую полосу на основе идентичных данных. Используется selection.filter :

function mouseover(d, i) {
  rect.filter(function(p) { return d === p; }).style("fill", "red");
}

Еще один вариант - присвоить каждому прямоугольнику уникальный идентификатор, а затем выбрать по идентификатору. Например, при инициализации вы можете сказать:

rect.attr("id", function(d, i) { return "rect-" + i; });

Затем вы можете выбрать прямоугольник по идентификатору при наведении мыши:

function mouseover(d, i) {
  d3.select("#rect-" + i).style("fill", "red");
}

Приведенный выше пример является надуманным, поскольку я использовал индекс для генерации атрибута id (в этом случае проще и быстрее использовать первый метод выбора по индексу). Более реалистичным примером будет, если ваши данные имеют свойство name; затем вы можете использовать d.name для генерации атрибута id, а также выбрать по id. Вы также можете выбрать другие атрибуты или класс, если вы не хотите генерировать уникальный идентификатор.

6 голосов
/ 21 января 2013

Отличный ответ Майка.

Я использовал его для выбора ячейки в сетке, которую я рисовал:

.on('click', (d, i) ->
      console.log("X:" + d.x, "Y:" + d.y) #displays the cell x y location
      d3.select(this).style("fill", "red");

Так что, когда я вводил данные в Iдобавил прослушиватель событий и используя d3.select (this).

См. код в контексте ниже:

 vis.selectAll("rect")
    .data(singleArray)
    .enter().append("svg:rect")
    .attr("stroke", "none")
    .attr("fill", (d) -> 
      if d.lifeForm
        return "green" 
      else
        return "white")
    .attr("x", (d) -> xs(d.x))
    .attr("y", (d) -> ys(d.y))
    .attr("width", cellWidth)
    .attr("height", cellHeight)
    .on('click', (d, i) ->
      console.log("X:" + d.x, "Y:" + d.y)
      d3.select(this).style("fill", "red");
      return
    ) 
...