D3JS图表:将鼠标悬停在某些过渡元素上,而其他元素仍在过渡时,也会停止执行图表动画

时间:2018-10-21 06:18:21

标签: javascript d3.js

我一直在研究水平条形图。我将transition的{​​{1}}属性的width从0添加到所需的值,它们工作正常。然后,我添加了一些rect元素,并使用circle使其一个接一个地“出现”,将delay属性从0过渡到所需的r值,以及所有也很好。如果我没有在所有元素都完成过渡之前将鼠标悬停在任何元素上,则可视化效果将达到预期的效果。

rrect都在不同的延迟之间过渡它们的circlewidth属性,这使得其中的一些在其他属性之前显示。

问题:如果我将鼠标悬停在任何r上而其他元素尚未完成其转换,则所有这些元素都会突然停止转换其属性。因此,没有达到整个图表所需的最终状态,实际上变成了一片混乱。我不知道为什么将鼠标悬停在一个元素上会干扰其他“明显”独立元素的预期行为。

rect
function draw(){
				
  var width =  $( window ).width() ;
  var height =  document.body.clientHeight 	;

  var data = [
    {country:"Pichonita", growth: 15},
    {country:"Andromeda", growth: 12},
    {country:"India", growth: 33},
    {country:"Indonesia", growth: 22},
    {country:"Russia", growth: 6},
    {country:"Mars", growth: 41},
    {country:"Pluton", growth: 16},
    {country:"Earth", growth: 24},
    {country:"Neptune", growth: 8}
  ]; 

    //set margins
    var margin = {top:30, right:30, bottom:30, left:40};
    var width = width - margin.left - margin.right*2.5;
    var height = height - margin.top - margin.bottom;

    //set scales & ranges

    var xScale = d3.scaleLinear()
      .range([0,  width - 100])

    var yScale = d3.scaleBand()
      .range([0, height]).padding(.2)

    //draw the svg

    var svg = d3.select("body")
      .append("svg")
      .attr("width", width + margin.left + margin.right * 3)
      .attr("height",height + margin.top + margin.bottom)
      .append("g")
      .attr("transform","translate(" + margin.left*2 + "," + margin.top  + ")")

      //force data

       data.forEach(function(d){
      return d.growth = +d.growth;
       });

      //set domains

      yScale.domain(data.map(d => d.country))

      xScale.domain([0, d3.max(data, d=> d.growth)])

      //add X & Y axes and append the bars to Y axis

      var xAxis = svg.append("g")
          .attr("class",xAxis)
          .attr("transform","translate(" + 0 + "," + height + ")")
						.call(d3.axisBottom(xScale))

     var yAxis =  svg.append("g")
           .attr("class",yAxis)
           .call(d3.axisLeft(yScale))
           .selectAll("rect")
           .data(data)
           .enter()
           .append("rect")
           .attr("stroke","transparent")
           .attr("stroke-width",4)
           .on("mouseover", function(){d3.select(this).transition().duration(600).attr("stroke","#6D2077").attr("stroke-width",3).style("fill","#6D2077")
            d3.selectAll(".textCircle").transition().duration(600)
           .attr("r",yScale.bandwidth() / 1.9)
           .attr("stroke","#6D2077")
           .attr("stroke-width",1)
			    }) 
          
		  .on("mouseout", function(){d3.select(this)
      .transition()
      .duration(600)
		  .attr("stroke","transparent")
          .attr("stroke-width",0)
          .style("fill","#00338D")
					 d3.selectAll(".textCircle")
          .transition().duration(600)
					.attr("r", yScale.bandwidth() / 2)
          .attr("stroke","transparent")
				}) 
          .attr("class","bar")
          .attr("height",yScale.bandwidth())
          .attr("x",0.5)
          .attr("y",function(d){
           return  yScale(d.country)
         })
         .attr("width",0)
         .transition()
         .duration(3800)
         .delay( (d,i)=> (i+1) *200)
         .ease(d3.easeElastic)
         .attr("width", function(d){
           return xScale(d.growth)
         })
        .style("fill","#00338D")

        var newG = svg.append("g")
        
         newG.selectAll("circle")
        .data(data)
        .enter()
        .append("circle")
        .attr("class","textCircle")
        .attr("cx",d=> xScale(d.growth) )
        .attr("cy",d=> yScale(d.country) + yScale.bandwidth() / 2)
        .attr("r",0)
        .transition()
          .duration(1200)
        .delay( (d,i)=> (i+1) *450)
        .attr("r",yScale.bandwidth() / 2)
        .attr("opacity",1)
        .style("fill","#0091DA")
        .attr("stroke","transparent")
        }

  draw();

  $( window ).resize(function() {
    $("body").empty();	
    draw();
  });
html{ 
  height: 98%;
  margin: 0;
  padding: 0;
}

body{
  min-height: 98%;
  margin: 0;
  padding: 0;
}

svg{
  text-rendering: geometricPrecision;
  shape-rendering:geometricPrecision;
}

1 个答案:

答案 0 :(得分:1)

事情变得混乱,因为您添加了mouseovermouseout事件监听器,它们试图执行与正在进行的过渡事件冲突的动作。要解决此问题,请在图表栏执行初始转换之前,不要添加mouseover / mouseout侦听器。您可以使用transition.on('end', function(){...}在过渡结束时添加一个侦听器,然后在过渡完成后将鼠标事件侦听器添加到DOM元素中。

    d3.select('#whateverItIs')
    // stuff to do prior to transition
    .transition()
    // transition stuff
    .on('end', function() {
      d3.select(this)
        .on("mouseover", function() {
        // handler code here
        })
        .on("mouseout", function() {
        // handler code here
        })
    })

使用您的代码:

function draw() {

  var width = $(window).width();
  var height = document.body.clientHeight;

  var data = [{
      country: "Pichonita",
      growth: 15
    },
    {
      country: "Andromeda",
      growth: 12
    },
    {
      country: "India",
      growth: 33
    },
    {
      country: "Indonesia",
      growth: 22
    },
    {
      country: "Russia",
      growth: 6
    },
    {
      country: "Mars",
      growth: 41
    },
    {
      country: "Pluton",
      growth: 16
    },
    {
      country: "Earth",
      growth: 24
    },
    {
      country: "Neptune",
      growth: 8
    }
  ];

  //set margins
  var margin = {
    top: 30,
    right: 30,
    bottom: 30,
    left: 40
  };
  var width = width - margin.left - margin.right * 2.5;
  var height = height - margin.top - margin.bottom;

  //set scales & ranges

  var xScale = d3.scaleLinear()
    .range([0, width - 100])

  var yScale = d3.scaleBand()
    .range([0, height]).padding(.2)

  //draw the svg

  var svg = d3.select("body")
    .append("svg")
    .attr("width", width + margin.left + margin.right * 3)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left * 2 + "," + margin.top + ")")

  //force data

  data.forEach(function(d) {
    return d.growth = +d.growth;
  });

  //set domains

  yScale.domain(data.map(d => d.country))

  xScale.domain([0, d3.max(data, d => d.growth)])

  //add X & Y axes and append the bars to Y axis

  var xAxis = svg.append("g")
    .attr("class", xAxis)
    .attr("transform", "translate(" + 0 + "," + height + ")")
    .call(d3.axisBottom(xScale))

  var yAxis = svg.append("g")
    .attr("class", yAxis)
    .call(d3.axisLeft(yScale))
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("stroke", "transparent")
    .attr("stroke-width", 4)
    .attr("class", "bar")
    .attr("height", yScale.bandwidth())
    .attr("x", 0.5)
    .attr("y", function(d) {
      return yScale(d.country)
    })
    .attr("width", 0)
    .transition()
    .duration(3800)
    .delay((d, i) => (i + 1) * 200)
    .ease(d3.easeElastic)
    .attr("width", function(d) {
      return xScale(d.growth)
    })
    .style("fill", "#00338D")
    .on('end', function() {
      d3.select(this)
        .on("mouseover", function() {
          d3.select(this)
            .transition().duration(600)
            .attr("stroke", "#6D2077")
            .attr("stroke-width", 3)
            .style("fill", "#6D2077")
          d3.selectAll(".textCircle")
            .transition().duration(600)
            .attr("r", yScale.bandwidth() / 1.9)
            .attr("stroke", "#6D2077")
            .attr("stroke-width", 1)
        })
        .on("mouseout", function() {
          d3.select(this)
            .transition()
            .duration(600)
            .attr("stroke", "transparent")
            .attr("stroke-width", 0)
            .style("fill", "#00338D")
          d3.selectAll(".textCircle")
            .transition().duration(600)
            .attr("r", yScale.bandwidth() / 2)
            .attr("stroke", "transparent")
        })

    })

  var newG = svg.append("g")

  newG.selectAll("circle")
    .data(data)
    .enter()
    .append("circle")
    .attr("class", "textCircle")
    .attr("cx", d => xScale(d.growth))
    .attr("cy", d => yScale(d.country) + yScale.bandwidth() / 2)
    .attr("r", 0)
    .transition()
    .duration(1200)
    .delay((d, i) => (i + 1) * 450)
    .attr("r", yScale.bandwidth() / 2)
    .attr("opacity", 1)
    .style("fill", "#0091DA")
    .attr("stroke", "transparent")
}

draw();

$(window).resize(function() {
  $("body").empty();
  draw();
});
html{ 
  height: 98%;
  margin: 0;
  padding: 0;
}

body{
  min-height: 98%;
  margin: 0;
  padding: 0;
}

svg{
  text-rendering: geometricPrecision;
  shape-rendering:geometricPrecision;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>