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

Куда должен идти код при наведении указателя мыши?

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

var path = svg.selectAll('path')
     .data(pie(totals))
     .enter()
     .append('path')
     .attr('d', arc)
     .attr('fill', function (d, i) {
          return color(d.data.title);
     })
     .attr('transform', 'translate(0, 0)')

Этот код создает различные сегменты нашей кольцевой диаграммы. Если мы хотим, чтобы что-то происходило, когда пользователь наводит курсор на них, это должно происходить здесь.

Добавление простого эффекта наведения

Для начала давайте добавим эффект, изменяющий непрозрачность сегмента при наведении курсора. Мы собираемся использовать метод .on, чтобы добавить эффекты mouseover и mouseout к path. mouseover изменяет непрозрачность на 0,85, а mouseout снова меняет ее на 1.

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

var path = svg.selectAll('path')
     .data(pie(totals))
     .enter()
     .append('path')
     .attr('d', arc)
     .attr('fill', function (d, i) {
          return color(d.data.title);
     })
     .attr('transform', 'translate(0, 0)')
     //Our new hover effects
     .on('mouseover', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '.85');
     .on('mouseout', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '1');

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

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

Чтобы отображать ценность каждого сегмента при наведении курсора, нам нужно добавить на несколько частей больше, чем в прошлый раз. Начнем с div, в который будет помещено значение.

Нам нужно добавить div, который добавляется к телу, но не отображается. Я добавил это прямо перед path:

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

Нам нужно сделать этот div видимым, когда пользователь наводит курсор на каждый сегмент, и заставить его снова исчезать, когда пользователь уходит. Мы сделаем это в path:

var path = svg.selectAll('path')
     .data(pie(totals))
     .enter()
     .append('path')
     .attr('d', arc)
     .attr('fill', function (d, i) {
          return color(d.data.title);
     })
     .attr('transform', 'translate(0, 0)')
     .on('mouseover', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '.85');
          //Makes the new div appear on hover:
          div.transition()
               .duration(50)
               .style("opacity", 1);
     })
     .on('mouseout', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '1');
          //Makes the new div disappear:
          div.transition()
               .duration('50')
               .style("opacity", 0);
     });

Теперь нам нужно поместить значение в div и поместить его рядом с мышью пользователя. Если вы просто хотите показать значение, html(d.value) - это все, что вам нужно для этого. Мы будем использовать d3.event.pageX и d3.event.pageY, чтобы разместить div рядом с указателем мыши. Не стесняйтесь настраивать значения +/-, чтобы правильно разместить на вашем графике.

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

Для моей кольцевой диаграммы я хотел показать процент, а не значение. В моем наборе данных используется d.data.all для итоговых значений каждого набора данных. Я добавил переменную с именем num для вычисления процента, а затем использовал тот же код, что и выше.

let num = (Math.round((d.value / d.data.all) * 100)).toString() + '%';
div.html(num)
     .style("left", (d3.event.pageX + 10) + "px")
     .style("top", (d3.event.pageY - 15) + "px");

Примечание. Использование Math.round() при вычислении процентов гарантирует получение точных целых чисел.

Если вы используете только один набор данных или все ваши наборы данных имеют одинаковую сумму, вы можете использовать d.value и жестко запрограммировать итоговую сумму следующим образом:

let num = (Math.round((d.value / 1038) * 100)).toString() + '%';

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

var div = d3.select("body").append("div")
     .attr("class", "tooltip-donut")
     .style("opacity", 0);
var path = svg.selectAll('path')
     .data(pie(totals))
     .enter()
     .append('path')
     .attr('d', arc)
     .attr('fill', function (d, i) {
          return color(d.data.title);
     })
     .attr('transform', 'translate(0, 0)')
     .on('mouseover', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '.85');
          div.transition()
               .duration(50)
               .style("opacity", 1);
          let num = (Math.round((d.value / d.data.all) * 100)).toString() + '%';
          div.html(num)
               .style("left", (d3.event.pageX + 10) + "px")
               .style("top", (d3.event.pageY - 15) + "px");
     })
     .on('mouseout', function (d, i) {
          d3.select(this).transition()
               .duration('50')
               .attr('opacity', '1');
          div.transition()
               .duration('50')
               .style("opacity", 0);
     });

Стилизация div

Стиль, который я использовал, довольно минимален. Убедитесь, что вы использовали класс .tooltip-donut в созданном вами div, чтобы CSS работал (или измените оба на все, что захотите, просто убедитесь, что они совпадают).

div.tooltip-donut {
     position: absolute;
     text-align: center;
     padding: .5rem;
     background: #FFFFFF;
     color: #313639;
     border: 1px solid #313639;
     border-radius: 8px;
     pointer-events: none;
     font-size: 1.3rem;
}

Теперь у вашей диаграммы есть эффекты наведения! Отличная работа!

Если у вас возникли проблемы и вы хотите увидеть мой полный код, зацените его на github.

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