Currently, I have been designing a horizontal bar chart and experimenting with transitions on various elements like rect
and circle
. The transitions are applied to attributes like width
and r
to achieve the desired effect. Everything seems to be working fine until I encounter an issue when hovering over one of the elements before all transitions have completed.
Each element, including rect
and circle
, undergoes its transition with different delays, causing some to become visible before others. However, the main problem arises when hovering over any rect
while other elements are still transitioning. It causes all transitions to halt, resulting in a messy final state for the chart.
The root cause: I am puzzled as to why hovering over a seemingly independent element can disrupt the expected behavior of other elements. This interference prevents the chart from reaching its intended final state.
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;
}
<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>