В этом руководстве используется d3.js версии 4.6.0 и он основан на диаграмме рассеяния, для которой я сделал учебник ранее. Вы можете увидеть точечную диаграмму с эффектами наведения в моем проекте визуализации данных или проверить это на гифке ниже.

Эффекты наведения - куда они деваются?

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

var path = svg.selectAll("dot")
     .data(data)
     .enter().append("circle")
     .attr("r", 5)
     .attr("cx", function (d) {
           return x(d.date);
     })
     .attr("cy", function (d) {
          return y(d.wage);
     })
     .attr("stroke", "#32CD32")
     .attr("stroke-width", 1.5)
     .attr("fill", "#FFFFFF");

Добавление эффектов

Чтобы добавить эффекты наведения, нам нужно использовать метод .on с mouseover и mouseout. Я хотел, чтобы мои точки данных становились больше, когда пользователь наводит на них курсор. Для этого я использую .attr, чтобы изменить радиус точек. .duration позволяет мне контролировать скорость увеличения точки данных на mouseover и уменьшения до исходного размера на mouseout.

.on('mouseover', function (d, i) {
     d3.select(this).transition()
          .duration('100')
          .attr("r", 7);
})
.on('mouseout', function (d, i) {
     d3.select(this).transition()
          .duration('200')
          .attr("r", 5);
});

Теперь наш график выглядит так:

Отображение значения при наведении

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

var div = d3.select("body").append("div")
     .attr("class", "tooltip")
     .style("opacity", 0);

Говоря о CSS, это тот CSS, который я использую для его стилизации:

div.tooltip {
     position: absolute;
     text-align: center;
     padding: .2rem;
     background: #313639;
     color: #f9f9f9;
     border: 0px;
     border-radius: 8px;
     pointer-events: none;
     font-size: .7rem;
}

Теперь нам нужно заставить наш div появляться и исчезать при наведении курсора. Мы сделаем это в разделах mouseover и mouseout, которые мы написали ранее:

.on('mouseover', function (d, i) {
     d3.select(this).transition()
          .duration('100')
          .attr("r", 7);
     //Makes div appear
     div.transition()
          .duration(100)
          .style("opacity", 1);
})
.on('mouseout', function (d, i) {
     d3.select(this).transition()
          .duration('200')
          .attr("r", 5);
     //makes div disappear
     div.transition()
          .duration('200')
          .style("opacity", 0);
});

Здорово! У нас есть стилизованный div, который появляется при наведении курсора и исчезает при наведении курсора. Теперь все, что нам нужно сделать, это вставить значение точки данных и поместить его рядом с мышью. Это произойдет в функции mouseover.

Чтобы вставить значение, мы просто введем наши данные в div.html(). Для места размещения мы будем использовать d3.event.pageX и d3.event.pageY. Обязательно установите значения +/- на числа, которые имеют смысл для вашего графика.

div.html(d.wage)
          .style("left", (d3.event.pageX + 10) + "px")
          .style("top", (d3.event.pageY - 15) + "px");

Поскольку мои данные - валюта, у меня есть дополнительное форматирование. Сначала я добавляю знак доллара в начало, а затем использую d3.format() для форматирования чисел до двух десятичных знаков.

div.html("$" + d3.format(".2f")(d.wage))
          .style("left", (d3.event.pageX + 10) + "px")
          .style("top", (d3.event.pageY - 15) + "px");

Готовые div и path javascript выглядят так:

var div = d3.select("body").append("div")
     .attr("class", "tooltip")
     .style("opacity", 0);
var path = svg.selectAll("dot")
     .data(data)
     .enter().append("circle")
     .attr("r", 5)
     .attr("cx", function (d) {
           return x(d.date);
     })
     .attr("cy", function (d) {
          return y(d.wage);
     })
     .attr("stroke", "#32CD32")
     .attr("stroke-width", 1.5)
     .attr("fill", "#FFFFFF");
     .on('mouseover', function (d, i) {
          d3.select(this).transition()
                .duration('100')
                .attr("r", 7);
          div.transition()
               .duration(100)
               .style("opacity", 1);
          div.html("$" + d3.format(".2f")(d.wage))
               .style("left", (d3.event.pageX + 10) + "px")
               .style("top", (d3.event.pageY - 15) + "px");
     })
     .on('mouseout', function (d, i) {
          d3.select(this).transition()
               .duration('200')
               .attr("r", 5);
          div.transition()
               .duration('200')
               .style("opacity", 0);
     });

Ты сделал это!

Вы построили диаграмму рассеяния, добавили эффекты и показываете значения при наведении курсора. Удивительный!

Если у вас возникли проблемы, посмотрите полный код на github. Сделайте этот график адаптивным с помощью другого моего урока.