Используйте transition (). On ("end") в d3 v5 с несколькими типами объектов. - PullRequest
1 голос
/ 06 апреля 2020

Моя цель состоит в том, чтобы анимация появлялась после анимации некоторых дуг на графике ar c. Сначала я размещаю узлы, затем щелкаю пользователя, выделяю щелкающий (исходный) узел и анимирую дуги. Что я не могу сделать, так это анимацию целевых узлов после того, как дуги закончили анимацию. Я думаю, что происходит то, что узлы получают новые цвета, но затем перезаписываются, потому что on ("end") выполняется для всех узлов и всех дуг. Я не знаю, как заставить его работать только для целей выбранного исходного узла. Вот мой код.

// adapted from https://www.d3-graph-gallery.com/graph/arc_highlight.html
// and https://www.d3-graph-gallery.com/arc

animateArcsFromNodesForEach = {
  const radius = 8;

  const container = d3.select(DOM.svg(width+margin.left+margin.right, 
                                      height+margin.top+margin.bottom))
  const arcGroup = container
       .append("g")
         .attr("transform", "translate(" + margin.left + "," + margin.top + ")")

  // create the nodes
  const nodes = arcGroup.selectAll("nodes")
    .data(graphData.nodes)
    .enter().append("circle")
      .attr("cx", d => xScale(d.name))
      .attr("cy", height-50)
      .attr("r", radius)
      .attr("fill", "steelblue")

  // create the node labels
  arcGroup.selectAll("nodeLabels")
    .data(graphData.nodes)
    .enter().append("text")
      .attr("x", d => xScale(d.name))
      .attr("y", height-20)
      .attr("fill", "darkgrey")
      .style("text-anchor", "middle")
      .text(d => d.name)

   // This code builds up the SVG path element; see nodesAndArcs for details
   function buildArc(d) {
      let start = xScale(idToNode[d.source].name);
      let end = xScale(idToNode[d.target].name);
      const arcPath = ['M', start, height-50, 'A', (start - end)/2, ',', (start-end)/2, 0,0,",",
                  start < end ? 1: 0, end, height-50].join(' ');
      return arcPath;   
  }

  // create the arcs
  let arcs = arcGroup.selectAll("arcs")
    .data(graphData.links)
    .enter().append("path")
     .style("fill", "none")
     .attr("stroke", "none")
     .attr("d", d => buildArc(d));

  // When the user mouses over a node,
  // add interactive highlighting to see connections between nodes  
   nodes.on('mouseover', function(d) {

      //  highlight only the selected node
     d3.select(this).style("fill", "firebrick");

     // next, style the arcs      
     arcs
       // the arc color and thickness stays as the default unless connected to the selected node d
       // notice how embedding the reference to arcs within nodes.on() allows the code to connect d to arcd
       // this code iterates through all the arcs so we can compare each to the selected node d
       .style('stroke', function (arcd) { 
          return  arcd.source === d.id  ? 'firebrick' : 'none';})
       .style('stroke-width', function (arcd) {
          return arcd.source === d.id ? 4 : 1;})      
       .attr("stroke-dasharray", function(arcd) {
            return  arcd.source === d.id  ? this.getTotalLength() : 0;})
       .attr("stroke-dashoffset", function(arcd) 
             { return  arcd.source === d.id  ? this.getTotalLength() : 0;})
          // reveal the arcs  
      .transition()
      .duration(3000)
      .attr("stroke-dashoffset", 0)

 // this is the part that isn't working
      .on("end", function(arcd) {
          nodes
          .transition().style("fill", function(nd) {
            return ((d.id === arcd.source) && (nd.id === arcd.target)) ? 'firebrick' : 'steelblue';
          })
     })
    });



   // remove highlighting when user mouse moves out of node by restoring default colors and thickness
   nodes.on('mouseout', function () {   
     nodes.style("fill", "steelblue");
     arcs.style('stroke', 'none');
     arcs.style('stroke-width', 1);

   });


   return container.node();
 }
...