Update readme, add interaction model.
authorRobert Konigsberg <konigsberg@google.com>
Sun, 15 Jan 2012 17:05:21 +0000 (12:05 -0500)
committerRobert Konigsberg <konigsberg@google.com>
Sun, 15 Jan 2012 17:05:21 +0000 (12:05 -0500)
gallery/README
gallery/gallery.css
gallery/index.html
gallery/interaction-api.js [new file with mode: 0644]
gallery/interaction.js

index 9063e81..e00cf81 100644 (file)
@@ -21,4 +21,15 @@ Tips on adding entries to the gallery
   run: function() { function window.func() { .. }; }
 
 * You'll find it easier if you convert all the double-quotes in your HTML to
-  single quotes.
\ No newline at end of file
+  single quotes.
+
+TODOs:
+  * Remove the awful tables in interaction.html (that I wrote)
+  * Move all style to css
+  * Create links to get code
+  * Consider moving HTML to HTML files that are read via XMLHTTP
+  * Add margin-left: 30px to #workarea, and then make #workarea h2 { margin-left: -30px}
+  * Replace <input type='button'> with <button>
+  * Create a scope so we don't rely on window, something that gets
+    reset after cleanup is called.
+  * Why does the gallery scroll upon selection?
\ No newline at end of file
index 37462cf..ca05d43 100644 (file)
@@ -123,6 +123,6 @@ aside {
   padding: 2px;
 }
 
-@workarea #temperature-sf-ny #bordered {
+#workarea #temperature-sf-ny #bordered {
   border: 1px solid red;
 }
index f1bdf1e..75c0521 100644 (file)
@@ -10,6 +10,7 @@
     <script src="../dygraph-dev.js"></script>
     <script src="gallery.js"></script>
     <script src="data.js"></script>
+    <script src="interaction-api.js"></script>
     <script src='http://www.google.com/jsapi'></script> <!-- required in some cases -->
 
     <!-- gallery entries. Can these be auto-loaded? -->
@@ -27,6 +28,7 @@
     <script src="stock.js"></script>
     <script src="styled-chart-labels.js"></script>
     <script src="temperature-sf-ny.js"></script>
+    <script src="interaction.js"></script>
 
     <!-- These might not remain in the gallery -->
     <script src="dygraph-simple.js"></script>
diff --git a/gallery/interaction-api.js b/gallery/interaction-api.js
new file mode 100644 (file)
index 0000000..38a5b68
--- /dev/null
@@ -0,0 +1,211 @@
+// Code for a variety of interaction models. Used in interaction.html, but split out from
+// that file so they can be tested in isolation.
+//
+function downV3(event, g, context) {
+  context.initializeMouseDown(event, g, context);
+  if (event.altKey || event.shiftKey) {
+    Dygraph.startZoom(event, g, context);
+  } else {
+    Dygraph.startPan(event, g, context);
+  }
+}
+
+function moveV3(event, g, context) {
+  if (context.isPanning) {
+    Dygraph.movePan(event, g, context);
+  } else if (context.isZooming) {
+    Dygraph.moveZoom(event, g, context);
+  }
+}
+
+function upV3(event, g, context) {
+  if (context.isPanning) {
+    Dygraph.endPan(event, g, context);
+  } else if (context.isZooming) {
+    Dygraph.endZoom(event, g, context);
+  }
+}
+
+// Take the offset of a mouse event on the dygraph canvas and
+// convert it to a pair of percentages from the bottom left. 
+// (Not top left, bottom is where the lower value is.)
+function offsetToPercentage(g, offsetX, offsetY) {
+  // This is calculating the pixel offset of the leftmost date.
+  var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
+  var yar0 = g.yAxisRange(0);
+
+  // This is calculating the pixel of the higest value. (Top pixel)
+  var yOffset = g.toDomCoords(null, yar0[1])[1];
+
+  // x y w and h are relative to the corner of the drawing area,
+  // so that the upper corner of the drawing area is (0, 0).
+  var x = offsetX - xOffset;
+  var y = offsetY - yOffset;
+
+  // This is computing the rightmost pixel, effectively defining the
+  // width.
+  var w = g.toDomCoords(g.xAxisRange()[1], null)[0] - xOffset;
+
+  // This is computing the lowest pixel, effectively defining the height.
+  var h = g.toDomCoords(null, yar0[0])[1] - yOffset;
+
+  // Percentage from the left.
+  var xPct = w == 0 ? 0 : (x / w);
+  // Percentage from the top.
+  var yPct = h == 0 ? 0 : (y / h);
+
+  // The (1-) part below changes it from "% distance down from the top"
+  // to "% distance up from the bottom".
+  return [xPct, (1-yPct)];
+}
+
+function dblClickV3(event, g, context) {
+  // Reducing by 20% makes it 80% the original size, which means
+  // to restore to original size it must grow by 25%
+  var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
+  var xPct = percentages[0];
+  var yPct = percentages[1];
+
+  if (event.ctrlKey) {
+    zoom(g, -.25, xPct, yPct);
+  } else {
+    zoom(g, +.2, xPct, yPct);
+  }
+}
+
+var lastClickedGraph = null;
+
+function clickV3(event, g, context) {
+  lastClickedGraph = g;
+  Dygraph.cancelEvent(event);
+}
+
+function scrollV3(event, g, context) {
+  if (lastClickedGraph != g) {
+    return;
+  }
+  var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
+  // For me the normalized value shows 0.075 for one click. If I took
+  // that verbatim, it would be a 7.5%.
+  var percentage = normal / 50;
+
+  var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
+  var xPct = percentages[0];
+  var yPct = percentages[1];
+
+  zoom(g, percentage, xPct, yPct);
+  Dygraph.cancelEvent(event);
+}
+
+// Adjusts [x, y] toward each other by zoomInPercentage%
+// Split it so the left/bottom axis gets xBias/yBias of that change and
+// tight/top gets (1-xBias)/(1-yBias) of that change.
+//
+// If a bias is missing it splits it down the middle.
+function zoom(g, zoomInPercentage, xBias, yBias) {
+  xBias = xBias || 0.5;
+  yBias = yBias || 0.5;
+  function adjustAxis(axis, zoomInPercentage, bias) {
+    var delta = axis[1] - axis[0];
+    var increment = delta * zoomInPercentage;
+    var foo = [increment * bias, increment * (1-bias)];
+    return [ axis[0] + foo[0], axis[1] - foo[1] ];
+  }
+  var yAxes = g.yAxisRanges();
+  var newYAxes = [];
+  for (var i = 0; i < yAxes.length; i++) {
+    newYAxes[i] = adjustAxis(yAxes[i], zoomInPercentage, yBias);
+  }
+
+  g.updateOptions({
+    dateWindow: adjustAxis(g.xAxisRange(), zoomInPercentage, xBias),
+    valueRange: newYAxes[0]
+    });
+}
+
+var v4Active = false;
+var v4Canvas = null;
+
+function downV4(event, g, context) {
+  context.initializeMouseDown(event, g, context);
+  v4Active = true;
+  moveV4(event, g, context); // in case the mouse went down on a data point.
+}
+
+var processed = [];
+
+function moveV4(event, g, context) {
+  var RANGE = 7;
+
+  if (v4Active) {
+    var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(g.graphDiv);
+    var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(g.graphDiv);
+
+    var rows = g.numRows();
+    // Row layout:
+    // [date, [val1, stdev1], [val2, stdev2]]
+    for (var row = 0; row < rows; row++) {
+      var date = g.getValue(row, 0);
+      var x = g.toDomCoords(date, null)[0];
+      var diff = Math.abs(canvasx - x);
+      if (diff < RANGE) {
+        for (var col = 1; col < 3; col++) {
+          // TODO(konigsberg): these will throw exceptions as data is removed.
+          var vals =  g.getValue(row, col);
+          if (vals == null) { continue; }
+          var val = vals[0];
+          var y = g.toDomCoords(null, val)[1];
+          var diff2 = Math.abs(canvasy - y);
+          if (diff2 < RANGE) {
+            var found = false;
+            for (var i in processed) {
+              var stored = processed[i];
+              if(stored[0] == row && stored[1] == col) {
+                found = true;
+                break;
+              }
+            }
+            if (!found) {
+              processed.push([row, col]);
+              drawV4(x, y);
+            }
+            return;
+          }
+        }
+      }
+    }
+  }
+}
+
+function upV4(event, g, context) {
+  if (v4Active) {
+    v4Active = false;
+  }
+}
+
+function dblClickV4(event, g, context) {
+  restorePositioning(g);
+}
+
+function drawV4(x, y) {
+  var ctx = v4Canvas;
+
+  ctx.strokeStyle = "#000000";
+  ctx.fillStyle = "#FFFF00";
+  ctx.beginPath();
+  ctx.arc(x,y,5,0,Math.PI*2,true);
+  ctx.closePath();
+  ctx.stroke();
+  ctx.fill();
+}
+
+function captureCanvas(canvas, area, g) {
+  v4Canvas = canvas;
+}
+
+function restorePositioning(g) {
+  g.updateOptions({
+    dateWindow: null,
+    valueRange: null
+  });
+}
index ced5aef..7ef64b0 100644 (file)
-// Code for a variety of interaction models. Used in interaction.html, but split out from
-// that file so they can be tested in isolation.
-//
-function downV3(event, g, context) {
-  context.initializeMouseDown(event, g, context);
-  if (event.altKey || event.shiftKey) {
-    Dygraph.startZoom(event, g, context);
-  } else {
-    Dygraph.startPan(event, g, context);
-  }
-}
-
-function moveV3(event, g, context) {
-  if (context.isPanning) {
-    Dygraph.movePan(event, g, context);
-  } else if (context.isZooming) {
-    Dygraph.moveZoom(event, g, context);
-  }
-}
-
-function upV3(event, g, context) {
-  if (context.isPanning) {
-    Dygraph.endPan(event, g, context);
-  } else if (context.isZooming) {
-    Dygraph.endZoom(event, g, context);
-  }
-}
-
-// Take the offset of a mouse event on the dygraph canvas and
-// convert it to a pair of percentages from the bottom left. 
-// (Not top left, bottom is where the lower value is.)
-function offsetToPercentage(g, offsetX, offsetY) {
-  // This is calculating the pixel offset of the leftmost date.
-  var xOffset = g.toDomCoords(g.xAxisRange()[0], null)[0];
-  var yar0 = g.yAxisRange(0);
-
-  // This is calculating the pixel of the higest value. (Top pixel)
-  var yOffset = g.toDomCoords(null, yar0[1])[1];
-
-  // x y w and h are relative to the corner of the drawing area,
-  // so that the upper corner of the drawing area is (0, 0).
-  var x = offsetX - xOffset;
-  var y = offsetY - yOffset;
-
-  // This is computing the rightmost pixel, effectively defining the
-  // width.
-  var w = g.toDomCoords(g.xAxisRange()[1], null)[0] - xOffset;
-
-  // This is computing the lowest pixel, effectively defining the height.
-  var h = g.toDomCoords(null, yar0[0])[1] - yOffset;
-
-  // Percentage from the left.
-  var xPct = w == 0 ? 0 : (x / w);
-  // Percentage from the top.
-  var yPct = h == 0 ? 0 : (y / h);
-
-  // The (1-) part below changes it from "% distance down from the top"
-  // to "% distance up from the bottom".
-  return [xPct, (1-yPct)];
-}
-
-function dblClickV3(event, g, context) {
-  // Reducing by 20% makes it 80% the original size, which means
-  // to restore to original size it must grow by 25%
-  var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
-  var xPct = percentages[0];
-  var yPct = percentages[1];
-
-  if (event.ctrlKey) {
-    zoom(g, -.25, xPct, yPct);
-  } else {
-    zoom(g, +.2, xPct, yPct);
-  }
-}
-
-var lastClickedGraph = null;
-
-function clickV3(event, g, context) {
-  lastClickedGraph = g;
-  Dygraph.cancelEvent(event);
-}
-
-function scrollV3(event, g, context) {
-  if (lastClickedGraph != g) {
-    return;
-  }
-  var normal = event.detail ? event.detail * -1 : event.wheelDelta / 40;
-  // For me the normalized value shows 0.075 for one click. If I took
-  // that verbatim, it would be a 7.5%.
-  var percentage = normal / 50;
-
-  var percentages = offsetToPercentage(g, event.offsetX, event.offsetY);
-  var xPct = percentages[0];
-  var yPct = percentages[1];
-
-  zoom(g, percentage, xPct, yPct);
-  Dygraph.cancelEvent(event);
-}
-
-// Adjusts [x, y] toward each other by zoomInPercentage%
-// Split it so the left/bottom axis gets xBias/yBias of that change and
-// tight/top gets (1-xBias)/(1-yBias) of that change.
-//
-// If a bias is missing it splits it down the middle.
-function zoom(g, zoomInPercentage, xBias, yBias) {
-  xBias = xBias || 0.5;
-  yBias = yBias || 0.5;
-  function adjustAxis(axis, zoomInPercentage, bias) {
-    var delta = axis[1] - axis[0];
-    var increment = delta * zoomInPercentage;
-    var foo = [increment * bias, increment * (1-bias)];
-    return [ axis[0] + foo[0], axis[1] - foo[1] ];
-  }
-  var yAxes = g.yAxisRanges();
-  var newYAxes = [];
-  for (var i = 0; i < yAxes.length; i++) {
-    newYAxes[i] = adjustAxis(yAxes[i], zoomInPercentage, yBias);
-  }
-
-  g.updateOptions({
-    dateWindow: adjustAxis(g.xAxisRange(), zoomInPercentage, xBias),
-    valueRange: newYAxes[0]
-    });
-}
-
-var v4Active = false;
-var v4Canvas = null;
-
-function downV4(event, g, context) {
-  context.initializeMouseDown(event, g, context);
-  v4Active = true;
-  moveV4(event, g, context); // in case the mouse went down on a data point.
-}
-
-var processed = [];
-
-function moveV4(event, g, context) {
-  var RANGE = 7;
-
-  if (v4Active) {
-    var canvasx = Dygraph.pageX(event) - Dygraph.findPosX(g.graphDiv);
-    var canvasy = Dygraph.pageY(event) - Dygraph.findPosY(g.graphDiv);
-
-    var rows = g.numRows();
-    // Row layout:
-    // [date, [val1, stdev1], [val2, stdev2]]
-    for (var row = 0; row < rows; row++) {
-      var date = g.getValue(row, 0);
-      var x = g.toDomCoords(date, null)[0];
-      var diff = Math.abs(canvasx - x);
-      if (diff < RANGE) {
-        for (var col = 1; col < 3; col++) {
-          // TODO(konigsberg): these will throw exceptions as data is removed.
-          var vals =  g.getValue(row, col);
-          if (vals == null) { continue; }
-          var val = vals[0];
-          var y = g.toDomCoords(null, val)[1];
-          var diff2 = Math.abs(canvasy - y);
-          if (diff2 < RANGE) {
-            var found = false;
-            for (var i in processed) {
-              var stored = processed[i];
-              if(stored[0] == row && stored[1] == col) {
-                found = true;
-                break;
-              }
-            }
-            if (!found) {
-              processed.push([row, col]);
-              drawV4(x, y);
-            }
-            return;
-          }
-        }
+Gallery.register(
+  'interaction',
+  {
+    name: 'Custom interaction models',
+    title: 'title',
+    setup: function(parent) {
+      parent.innerHTML =
+          "<table border='1'>" +
+          "<tr><td>" +
+          "<b>Default interaction model</b>" +
+          "<div id='div_g' style='width:600px; height:300px;'></div>" +
+          "</td><td>Zoom: click-drag<br/>Pan: shift-click-drag<br/>Restore zoom level: double-click<br/>" +
+          "</td></tr>" +
+          "<tr><td>" +
+          "<b>No interaction model</b>" +
+          "<div id='div_g2' style='width:600px; height:300px;'></div>" +
+          "</td><td>Click and drag all you like, it won't do anything!" +
+          "<div id='g2_console'></div>" +
+          "</td></tr>" +
+          "<tr><td>" +
+          "<b>Custom interaction model</b>" +
+          "<button id='restore3'>Restore Position</button>" +
+          "<div id='div_g3' style='width:600px; height:300px;'></div>" +
+          "</td><td>" +
+          "Zoom in: double-click, scroll wheel<br/>" +
+          "Zoom out: ctrl-double-click, scroll wheel<br/>" +
+          "Standard Zoom: shift-click-drag" +
+          "Standard Pan: click-drag<br/>" +
+          "Restore zoom level: press button<br/>" +
+          "</td></tr>" +
+          "<tr><td>" +
+          "<b>Fun model!</b>" +
+          "<div id='div_g4' style='width:600px; height:300px;'></div>" +
+          "</td><td>" +
+          "Keep the mouse button pressed, and hover over all points" +
+          "to mark them." +
+          "</td></tr>" +
+          "</table>";
+
+    },
+    run: function() {
+      // TODO(konigsberg): Add cleanup to remove callbacks.
+      Dygraph.addEvent(document, "mousewheel", function() { lastClickedGraph = null; });
+      Dygraph.addEvent(document, "click", function() { lastClickedGraph = null; });
+      var g = new Dygraph(document.getElementById("div_g"),
+           NoisyData, { errorBars : true });
+      var s = document.getElementById("g2_console");
+      var g2 = new Dygraph(document.getElementById("div_g2"),
+           NoisyData,
+           {
+             errorBars : true,
+             interactionModel: {}
+           });
+      var g3 = new Dygraph(document.getElementById("div_g3"),
+           NoisyData, { errorBars : true, interactionModel : {
+            'mousedown' : downV3,
+            'mousemove' : moveV3,
+            'mouseup' : upV3,
+            'click' : clickV3,
+            'dblclick' : dblClickV3,
+            'mousewheel' : scrollV3
+      }});
+      document.getElementById("restore3").onclick = function() {
+        restorePositioning(g3);
       }
+      var g4 = new Dygraph(document.getElementById("div_g4"),
+           NoisyData, { errorBars : true, drawPoints : true, interactionModel : {
+            'mousedown' : downV4,
+            'mousemove' : moveV4,
+            'mouseup' : upV4,
+            'dblclick' : dblClickV4,
+           },
+           underlayCallback : captureCanvas
+      });
     }
-  }
-}
-
-function upV4(event, g, context) {
-  if (v4Active) {
-    v4Active = false;
-  }
-}
-
-function dblClickV4(event, g, context) {
-  restorePositioning(g4);
-}
-
-function drawV4(x, y) {
-  var ctx = v4Canvas;
-
-  ctx.strokeStyle = "#000000";
-  ctx.fillStyle = "#FFFF00";
-  ctx.beginPath();
-  ctx.arc(x,y,5,0,Math.PI*2,true);
-  ctx.closePath();
-  ctx.stroke();
-  ctx.fill();
-}
-
-function captureCanvas(canvas, area, g) {
-  v4Canvas = canvas;
-}
-
-function restorePositioning(g) {
-  g.updateOptions({
-    dateWindow: null,
-    valueRange: null
   });
-}