block by milroc 10606529

d3.dispatch + reusable components

Full Screen

This is a fork of Interrupting Chained Transitions. It is showing the power of d3.dispatch for building reusable components.

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

body {
  position: relative;
  width: 960px;
  height: 500px;
}

button {
  position: absolute;
  cursor: pointer;
  top: 50%;
  left: 50%;
  margin-top: -1.75em;
  margin-left: -6em;
  width: 12em;
  padding: 1em 2em;
  background: #000;
  color: #fff;
  border-radius: 8px;
  border: solid 2px #fff;
  font: 16px "Helvetica Neue", sans-serif;
}

button:focus {
  outline: none;
}

button:hover {
  text-shadow: 0 1px 0 #000;
  background: #444;
}

button:active {
  background: #222;
}

</style>
<button>Toggle The Music</button>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>



function danceBoard() {
  var width = 960,
      height = 500,
      size = 80,
      color = d3.scale.ordinal()
                        .range(["#333", "brown", "white", "green", "steelblue"]),
      dispatch = d3.dispatch("start", "stop");


  function render(selection) {
    selection.each(function(data) {
      var svg = d3.select(this).selectAll('svg')
                        .data([0]);
        svg.enter().append("svg")
                    .attr("width", width)
                    .attr("height", height)
                  .append("g")
                    .attr("transform", "translate(-40,-30)");
      svg = svg.select("g");

      var rect = svg.selectAll("rect")
          .data(data)
        .enter().append("rect")
          .attr("transform", function(d) { return "translate(" + d + ")"; })
          .attr("width", size)
          .attr("height", size)
          .style("stroke", "black")
          .style("stroke-width", "2px")
          .style("fill", "#000");

      dispatch.on("start.danceBoard", function() {
        rect.transition()
              .duration(0)
              .delay(function(d, i) { return i * 5; })
              .each(pulse);
      });

      dispatch.on("stop.danceBoard", function() {
        rect.transition()
          .duration(0)
          .delay(function(d, i) { return i * 5; })
          .style("fill", "#333");
      });

      dispatch.start();

      function pulse() {
        var rect = d3.select(this);
        (function loop() {
          rect = rect.transition()
              .duration(750)
              .style("fill", color(Math.random() * 5 | 0))
              .each("end", function() { if (this.__transition__.count < 2) loop(); });
        })();
      }

    });
  }

  // get/set these
  render.dispatch = dispatch;
  render.width = width;
  render.height = height;
  render.size = size;


  return render;
}

var dance = danceBoard();

d3.select("button")
    .on("click", function stop() {
      dance.dispatch.stop();
      d3.select(this).on("click", function() {
        dance.dispatch.start();
        d3.select(this).on("click", stop);
      });
    });

var data = d3.merge(d3.range(0, dance.width + dance.size, dance.size).map(function(x) {
  return d3.range(0, dance.height + dance.size, dance.size).map(function(y) {
    return [x, y];
  });
}));

d3.select("body").datum(data).call(dance);

</script>