score:1

Accepted answer

It looks like speed is the total duration of the transition. You can use a variable outside the update function that gate keeps the update

let inTransition = false;

update(new Date().getFullYear(), 0);

function update(year, speed) {

    if (!inTransition) {

         inTransition = true;

         setTimeout(() => { inTransition = false; }, speed);

          var t = d3.transition().duration(speed);

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

          var result = [(year -1).toString(), (year).toString(), (year +1).toString()];

          var buttons = svg.selectAll(".button").data(result, d => d)

          buttons.exit().transition(t)
            .attr("x", d => +d > year ? 240 : -60)
            .style("opacity", 0)
            .remove()

          buttons.enter().append("rect")
            .attr("class", "button")
            .style("opacity", 0)
            .attr("width", 70)
            .attr("height", 25)
            .attr("y", 15)
            .attr("x", d => +d > year ? 240 : -60)
            .attr("value", d => d)
            .merge(buttons)
          .transition(t)
            .style("opacity", 1)
            .attr("x", (_, i) => 15 + 75 * i)
            .attr("fill", d => +d == year ? "#666" : "#ddd")

          var onclick = d3.selectAll(".button")
            .on("click", function() {
              update(+(d3.select(this).attr("value")), 750)
            })
    }
}
body {
	padding-top: 35px;
	margin: auto;
	width: 550px;
	font: 12px monospace;
}
svg {
	width: 250px;
	height: 55px;
}
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg class="buttons"></svg>

score:3

d3 has events for that. (Reference: https://github.com/d3/d3-transition/blob/master/README.md#transition_on)

You have to disable pointer events when transition on start, then enable pointer events when transition on end. (Also you can bind and unbind click event on start and on end)

Check it out:

update(new Date().getFullYear(), 0);

function update(year, speed) {

  var t = d3.transition().duration(speed);

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

  var result = [(year - 1).toString(), (year).toString(), (year + 1).toString()];

  var buttons = svg.selectAll(".button").data(result, d => d)

  buttons.exit().transition(t)
    .attr("x", d => +d > year ? 240 : -60)
    .style("opacity", 0)
    .remove()

  buttons.enter().append("rect")
    .attr("class", "button")
    .style("opacity", 0)
    .attr("width", 70)
    .attr("height", 25)
    .attr("y", 15)
    .attr("x", d => +d > year ? 240 : -60)
    .attr("value", d => d)
    .merge(buttons)
    .transition(t)
    .on("start", function() {
      document.getElementById("buttons").style.pointerEvents = "none";
    })
    .on("end", function() {
      document.getElementById("buttons").style.pointerEvents = "all";
    })
    .style("opacity", 1)
    .attr("x", (_, i) => 15 + 75 * i)
    .attr("fill", d => +d == year ? "#666" : "#ddd")

  var onclick = d3.selectAll(".button")
    .on("click", function() {
      update(+(d3.select(this).attr("value")), 750)
    })
}
body {
  padding-top: 35px;
  margin: auto;
  width: 550px;
  font: 12px monospace;
}

svg {
  width: 250px;
  height: 55px;
}
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg id="buttons" class="buttons"></svg>


Related Query