block by curran f5789e8c8269e7ae9c26

Reactive Mixins

Full Screen

This example shows one way to encapsulate the D3 Margin Convention using Model.js.

Check out the resize behavior in full screen mode.

More generally, this example is an experiment in how to generalize self-contained pieces of dynamic graphical behavior. Note that the following three pieces of this visualization are each implemented in separate functions:

Draws from:

forked from curran‘s block: Margin Convention with Model.js

index.html

<!DOCTYPE html>
  <head>
    <meta charset="utf-8">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
    <script src="//curran.github.io/model/cdn/model-v0.2.4.js"></script>
    <style>
      body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
      #visualization-container { width: 100%; height: 100%; }
    </style>
  </head>

  <body>
    <div id="visualization-container"></div>
    <script>
      
      function marginConvention(my, svg, g){
        my.when("box", function (box){
          svg.attr("width", box.width)
             .attr("height", box.height);
        });
        my.when(["box", "margin"], function (box, margin){
          my.width = box.width - margin.left - margin.right;
          my.height = box.height - margin.top - margin.bottom;
          g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
        });
      }
      
      function backgroundRect(my, g){
        var rect = g.append("rect")
          .style("fill", "#aaaaaa")
          .style("stroke", "#4c4c4c");
        my.when(["width", "height"], function (width, height) {
          rect.attr("width", width).attr("height", height);
        });
      }
      
      function backgroundX(my, g){
        my.when(["width", "height"], function (width, height){
          var lines = g.selectAll("line").data([
            {x1: 0, y1: 0,      x2: width, y2: height},
            {x1: 0, y1: height, x2: width, y2: 0}
          ]);
          lines.enter().append("line");
          lines
            .attr("x1", function (d) { return d.x1; })
            .attr("y1", function (d) { return d.y1; })
            .attr("x2", function (d) { return d.x2; })
            .attr("y2", function (d) { return d.y2; })
            .style("stroke-width", 280)
            .style("stroke-opacity", 0.256)
            .style("stroke", "black");
        });
      }
      
      function clipRect(my, svg, g){
        var clipRect = svg.append("clipPath").attr("id", "clip").append("rect");
        g.style("clip-path", "url(#clip)");
        my.when(["width", "height"], function (width, height){  
          clipRect.attr("width", width).attr("height", height);
        });
      }
      
      function centerCircle(my, g){
        var circle = g.append("circle")
          .style("fill", "#000000")
          .style("stroke-width", 83)
          .style("stroke", "#7f7f7f")
          .attr("r", 85);
        my.when(["width", "height"], function (width, height) {
          circle.attr("cx", width / 2).attr("cy", height / 2);
        });
      }
      
      function Visualization(){
        
        var my = new Model({
          margin: {top: 20, right: 10, bottom: 20, left: 10}
        });
        
        my.el = document.createElementNS("//www.w3.org/2000/svg", "svg");
        var svg = d3.select(my.el)
          .style("background-color", "lightgray");
        var g = svg.append("g")
          .style("background-color", "gray");
        
        marginConvention(my, svg, g);
        backgroundRect(my, g);
        backgroundX(my, g);
        clipRect(my, svg, g);
        centerCircle(my, g);
        
        return my;
      }
      
      var visualization = new Visualization();
      var container = document.getElementById("visualization-container");
      container.appendChild(visualization.el);
      
      // This is what it would look like to hard-code the size.
      //visualization.box = {
      //  width: 960,
      //  height: 500
      //};
      
      // This pattern with Model.js provides a way to respond to resize.
      // This function extracts the dimensions of the visualization container
      // and passes them into the visualization via the "box" property.
      // This size is computed originally by CSS via ".visualization-container".
      function setBox(){
        visualization.box = {
          width: container.clientWidth,
          height: container.clientHeight,
        };
      }
      setBox();
      window.addEventListener("resize", setBox);

      console.log("you are now rocking with d3 and model.js", d3, visualization);
    </script>
  </body>