block by emeeks b2cdc14617aa91c07b25

Ch. 12, Fig. 7 - D3.js in Action

Full Screen

This is the code for Chapter 12, Figure 7 from D3.js in Action which requires a touch interface (or emulator) to see any effect. This example uses data from d3.touches() to implement rotate by calculate the initial angle of the touches and rotating the SVG g element based on the current rotation of the touches.

You can see a more advanced visual explanation of how this calculation is made in this example.

index.html

<html>
<head>
  <title>D3 in Action Chapter 12 - Example 6</title>
  <meta charset="utf-8" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
</head>
<style>
  body, html {
    width:100%;
    height:100%;
  }
  #vizcontainer {
    width:100%;
    height:100%;
  }
  svg {
    width: 100%;
    height: 100%;
  }
</style>
<body>
<div id="vizcontainer">
  <svg></svg>
</div>
</body>
  <footer>
    
<script>
    var initialD = [];
    var initialRotate;

     d3.select("svg").on("touchstart", touchBegin);
     d3.select("svg").on("touchmove", touchStatus);

     var touchColor = d3.scale.linear().domain([0, 10]).range(["pink", "darkred"])
     
     var graphicsG = d3.select("svg").append("g").attr("id", "graphics").attr("transform", "rotate(0)");
     
     graphicsG.append("rect").attr("width", 250).attr("height", 50).attr("x", 50).attr("y", 50)
     .style("fill", "red").style("stroke", "gray").style("stroke-width", "1px");

     graphicsG.append("rect").attr("width", 100).attr("height", 400).attr("x", 350).attr("cy", 400)
     .style("fill", "gray").style("stroke", "black").style("stroke-width", "1px");

      function touchBegin() {
       d3.event.preventDefault();
       d3.event.stopPropagation();
        initialRotate = d3.transform(d3.select("#graphics").attr("transform")).rotate;
       
       d = d3.touches(this);
      if (d.length == 3) {
        initialD = d;
      }

          }
     function touchStatus() {
       d3.event.preventDefault();
       d3.event.stopPropagation();
       d = d3.touches(this);
       d3.select("svg").selectAll("circle").data(d).enter().append("circle").attr("r", 75).style("fill", function(d, i) {
         return touchColor(i)
       });

       d3.select("svg").selectAll("circle").data(d).exit().remove();

       d3.select("svg").selectAll("circle").attr("cx", function(d) {
         return d[0]
       }).attr("cy", function(d) {
         return d[1]
       });

      if (d.length == 3) {
        var slope1 = (initialD[0][1] - initialD[1][1]) / (initialD[0][0] - initialD[1][0]);
        var slope2 = (d[0][1] - d[1][1]) / (d[0][0] - d[1][0]);
        
        var angle = Math.atan((slope1 - slope2)/(1 + slope1*slope2)) * 180/Math.PI;

        d3.select("#touchStatus").html("")
        d3.select("#touchStatus").append("p").html("Slope 1: " + slope1);
        d3.select("#touchStatus").append("p").html("Slope 2: " + slope2);

        d3.select("#touchStatus").append("p").html("Angle: " + angle);
        
        var newRotate = initialRotate - angle;
        
        d3.select("#graphics").attr("transform", "rotate(" +newRotate +")")

      }

     }
</script>
  </footer>

</html>