Transition duration does not work on page refresh

Viewed 322

I am having a slight problem with my d3 transitions.

After a page refresh, the transition occurs instantaneously. I want the first transition after the page refresh to take 1 second like the others.

JSFiddle

Here's a snippet

const name_ = d3.select('#name_container');

const M = name_
.append('text')
    .attr('y', 50)
    .attr('x', 50)
    .attr('font-size', '2em')
    .text('M')
    .attr('fill', 'blue')
    .style('pointer-events', 'none');

const M_backboard = name_
.append('rect')
    .attr('x', 50)
    .attr('y', 50)
    .attr('width', 50)
    .attr('height', 50)
    .on('mouseover', function() {
        M.transition().duration(1000)
            .attr('opacity', 0);
    })
    .on('mouseout', function() {
        M.transition().duration(1000)
            .attr('opacity', 1);
    });
<!DOCTYPE html>

<html>
    <head>
        <link rel="shortcut icon" href="#">
        <script src="https://d3js.org/d3.v6.js"></script>
    </head>
    <body>
        <svg id=name_container></svg>    
        <script src=index.js></script>
    </body>
</html>

3 Answers

Your problem is that the opacity on the problem element is not initially set when the page loads so there's nothing to transition from to the to. If you set the opacity to 1 by default, you will get the expected results.

EDIT Link to a forked fiddle. Is this what you're going for?

The default value for an SVG element's opacity is 1. That said, you don't need to previously set the opacity, provided you use selection.style() instead of selection.attr().

Here is a simple demo. style will return 1 for the opacity, even if you never set it (internally, it uses getComputedStyle), while attr returns null:

const c = d3.select("circle");
console.log(c.style("opacity"));
console.log(window.getComputedStyle(c.node()).opacity)
console.log(c.attr("opacity"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg>
  <circle r="50"></circle>
</svg>

All that being said, just use style:

const name_ = d3.select('#name_container');

const M = name_
.append('text')
    .attr('y', 50)
    .attr('x', 50)
    .attr('font-size', '2em')
    .text('M')
    .attr('fill', 'blue')
    .style('pointer-events', 'none');

const M_backboard = name_
.append('rect')
    .attr('x', 50)
    .attr('y', 50)
    .attr('width', 50)
    .attr('height', 50)
    .on('mouseover', function() {
        M.transition().duration(1000)
            .style('opacity', 0);
    })
    .on('mouseout', function() {
        M.transition().duration(1000)
            .style('opacity', 1);
    });
<!DOCTYPE html>

<html>
    <head>
        <link rel="shortcut icon" href="#">
        <script src="https://d3js.org/d3.v6.js"></script>
    </head>
    <body>
        <svg id=name_container></svg>    
        <script src=index.js></script>
    </body>
</html>

Why not use CSS?

ele {
  transition: 0.1s linear;
}
ele:hover {
  //...
}
Related