Пузырьковая диаграмма d3.js, события mousover и mouseout работают только в первый раз

1

Новое для d3. У меня небольшие проблемы с обработчиками событий mouseover и mouseout.

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

Любое направление на то, что я делаю неправильно, оценивается.

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

Я вставил свой код ниже.

d3.csv('../csv/homeless_population.csv')
  .row((data) => {
    return {
      State: data.State,
      PercentHomeless: Number(data.Homeless) / Number(data.Population)
    };
  })
  .get((error, data) => {

    let width = 650;
    let height = 600;

    let maxRadius = d3.max(data, (data) => { return data.PercentHomeless; })
    let minRadius = d3.min(data, (data) => { return data.PercentHomeless; })

    let svg = d3.selectAll('section')
                .append('svg')
                .attr('height', height)
                .attr('width', width)
                .append('g')
                .attr('transform', 'translate(0, 0)')

    let colors = d3.scaleOrdinal(d3.schemePaired);

    let simulation = d3.forceSimulation()
                      .force('x', d3.forceX(width/2).strength(0.5))
                      .force('y', d3.forceY(height/2).strength(0.5))
                      .force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless) + 3; }))

    let r = d3.scaleSqrt()
              .domain([minRadius, maxRadius])
              .range([15,75])


    let circles = svg.selectAll('circles')
                  .data(data)
                  .enter()
                  .append('circle')
                  .attr('stroke', 'black')
                  .attr('fill', (data) => { return colors(data.State); })
                  .attr('r', (data) => { return r(data.PercentHomeless); })
                  .on('mouseover', mouseOn)
                  .on('mouseout', mouseOff)

   function mouseOn(data) {
     circles
      .attr('opacity', 0.5)
     d3.select(this)
      .attr('r', r(data.PercentHomeless) * 1.5)
      .style('opacity', 1)

     simulation
      .force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless * 1.5) + 3; }))
   }

   function mouseOff(data) {
     d3.select(this)
      .attr('r', r(data.PercentHomeless))

     circles
      .attr('opacity', 1)

     simulation
      .force('collide', d3.forceCollide((data) => { return r(data.PercentHomeless) + 3; }))
   }

   let texts = svg.selectAll(null)
                .data(data)
                .enter()
                .append('text')
                .text((data) => { return data.State; } )
                .attr('color', 'black')
                .attr('font-size', 10)


    let ticked = () => {
      circles
        .attr('cx', (data) => { return data.x; })
        .attr('cy', (data) => { return data.y; })
      texts
        .attr('x', (data) => { return data.x; })
        .attr('y', (data) => { return data.y;  })
    };



    simulation.nodes(data)
      .on('tick', ticked)


  });
  • 0
    Я исправил проблему с непрозрачностью, изменив .attr на .style, но все еще пытался выяснить проблему forceCollide.
  • 0
    Поскольку вы уже исправили непрозрачность, я удалил ее из вашего вопроса. Что касается функции стрелки: вы видите this в обработчиках событий? Вот почему функция стрелка не будет работать здесь.
Теги:
d3.js

1 ответ

1
Лучший ответ

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

Поэтому вам нужно повторно mouseOn симуляцию в ваших mouseOn и mouseOff. Например:

simulation.alpha(0.8).restart();

Вот демонстрация с использованием упрощенного кода (поскольку у меня нет доступа к вашим данным). Наведите указатель мыши на круги:

var svg = d3.select("svg");

var colour = d3.scaleOrdinal(d3.schemeCategory10);

var data = d3.range(30).map(d => ({
  r: 6
}));

var simulation = d3.forceSimulation(data)
  .force("x", d3.forceX(150).strength(0.05))
  .force("y", d3.forceY(75).strength(0.05))
  .force("collide", d3.forceCollide(function(d) {
    return d.r + 1;
  }));

var circles = svg.selectAll(".circles")
  .data(data)
  .enter()
  .append("circle")
  .attr("r", d => d.r)
  .attr("fill", (d, i) => colour(i));

circles.on('mouseover', mouseOn)
  .on('mouseout', mouseOff)

simulation.nodes(data)
  .on("tick", d => {
    circles.attr("cx", d => d.x).attr("cy", d => d.y);
  });

function mouseOn() {
  circles.attr('opacity', 0.5)
  d3.select(this)
    .attr('r', d => d.r * 1.5);

  simulation.force("collide", d3.forceCollide(function(d) {
    return d.r * 1.5 + 1;
  }));

  simulation.alpha(0.8).restart();
}

function mouseOff() {
  d3.select(this)
    .attr('r', d => d.r);

  circles.attr('opacity', 1);

  simulation.force("collide", d3.forceCollide(function(d) {
    return d.r + 1;
  }));

  simulation.alpha(0.8).restart();


}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>

PS: Вам не нужно передавать data в функции mouseOn и mouseOff.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню