Merge pull request #619 from davidmsibley/cidaUsers
authorDan Vanderkam <danvdk@gmail.com>
Wed, 23 Sep 2015 18:06:04 +0000 (14:06 -0400)
committerDan Vanderkam <danvdk@gmail.com>
Wed, 23 Sep 2015 18:06:04 +0000 (14:06 -0400)
Cida users

auto_tests/chrome.karma.conf.js
auto_tests/karma.conf.js
auto_tests/tests/synchronize.js [new file with mode: 0644]
bower.json
docs/users.html
src/extras/synchronizer.js

index 9cd6039..0caceb6 100644 (file)
@@ -8,6 +8,7 @@ module.exports = function (config) {
         files: [
             'dist/dygraph-combined-dev.js',
             'src/extras/smooth-plotter.js',
+            'src/extras/synchronizer.js',
             'auto_tests/data/*.js',
             'auto_tests/tests/*.js',
         ],
index 606c571..09d0596 100644 (file)
@@ -8,6 +8,7 @@ module.exports = function (config) {
         files: [
             'dist/dygraph-combined-dev.js',
             'src/extras/smooth-plotter.js',
+            'src/extras/synchronizer.js',
             'auto_tests/data/*.js',
             'auto_tests/tests/*.js',
         ],
diff --git a/auto_tests/tests/synchronize.js b/auto_tests/tests/synchronize.js
new file mode 100644 (file)
index 0000000..173b32f
--- /dev/null
@@ -0,0 +1,109 @@
+/**
+ * @fileoverview Tests synchronizer.
+ *
+ * @author nyx@nyx.cz (Marek Janda)
+ */
+describe("synchronize", function() {
+  var gs;
+  var originalCallbackCalled;
+  var data = "X,a,b,c\n" +
+    "10,-1,1,2\n" +
+    "11,0,3,1\n" +
+    "12,1,4,2\n" +
+    "13,0,2,3\n";
+  var h_row, h_pts;
+
+  beforeEach(function() {
+    document.body.innerHTML = "<div id='graph1'></div><div id='graph2'></div>";
+    originalCallbackCalled = false;
+    h_row = 0, h_pts = [];
+    gs = [];
+
+    var highlightCallback = function(e, x, pts, row) {
+      originalCallbackCalled = true;
+
+      h_row = row;
+      h_pts = pts;
+      assert.equal(gs[0], this);
+    };
+
+    gs.push(new Dygraph(document.getElementById("graph1"), data, {
+      width: 100,
+      height: 100,
+      visibility: [false, true, true],
+      highlightCallback: highlightCallback
+    }));
+    gs.push(new Dygraph(document.getElementById("graph2"), data, {
+      width: 100,
+      height: 100,
+      visibility: [false, true, true],
+    }));
+  });
+
+  afterEach(function() {
+
+  });
+
+  /**
+   * This tests if original highlightCallback is called when synchronizer is attached
+   */
+  it('testOriginalHighlightCallbackStillWorks', function() {
+    var sync = Dygraph.synchronize(gs);
+
+    DygraphOps.dispatchMouseMove(gs[1], 5, 5);
+    // check that chart2 doesn't trigger highlightCallback on chart1
+    assert.equal(originalCallbackCalled, false);
+
+    DygraphOps.dispatchMouseMove(gs[0], 13, 10);
+    // check that original highlightCallback was called
+    assert.equal(originalCallbackCalled, true);
+
+    sync.detach();
+  });
+
+  /**
+   * This tests if selection is propagated correctly between charts
+   */
+  it('testChartsAreSynchronized', function() {
+    DygraphOps.dispatchMouseMove(gs[0], 13, 10);
+    assert.notEqual(gs[0].getSelection(), gs[1].getSelection());
+    DygraphOps.dispatchMouseMove(gs[0], 0, 0);
+
+    var sync = Dygraph.synchronize(gs);
+
+    DygraphOps.dispatchMouseMove(gs[0], 13, 10);
+
+    //check correct row is highlighted on second chart
+    assert.equal(3, h_row);
+    //check there are only two points (because first series is hidden)
+    assert.equal(2, h_pts.length);
+    //check that selection on both charts is the same
+    assert.equal(gs[0].getSelection(), gs[1].getSelection());
+
+    sync.detach();
+  });
+
+  /**
+   * This tests if detach works
+   */
+  it('testSynchronizerDetach', function() {
+    var sync = Dygraph.synchronize(gs);
+    DygraphOps.dispatchMouseMove(gs[1], 10, 10);
+    sync.detach();
+
+    originalCallbackCalled = false;
+    DygraphOps.dispatchMouseMove(gs[1], 0, 0);
+
+    //check that chart2 doesn't have highlightCallback
+    assert.equal(originalCallbackCalled, false);
+
+    DygraphOps.dispatchMouseMove(gs[0], 13, 10);
+
+    //check that original callback was re-attached
+    assert.equal(originalCallbackCalled, true);
+
+    //check that selection isn't synchronized anymore
+    assert.equal(gs[0].getSelection(), 3);
+    assert.equal(gs[1].getSelection(), 0);
+  });
+});
index d5d5d5b..c7bffe2 100644 (file)
@@ -1,6 +1,5 @@
 {
   "name": "dygraphs",
-  "version": "v1.1.0",
   "main": "dygraph-combined.js",
   "ignore": [
     "Makefile",
index e8f7a49..0f362c5 100644 (file)
   (<a href="http://cavorite.com/labs/js/dygraphs-export/">[1]</a>, <a href="https://github.com/cavorite/dygraphs">[2]</a>).
   </span></li>
 
-  <li><a href="http://www.glerl.noaa.gov/data/now/wlevels/dbd/altSite.html">NOAA Great Lakes Water Level Dashboard</a><br/>
-  <span class="desc">The Great Lakes Water Level dashboard was designed to help users view, understand, and compare Great Lakes surface water elevation data and forecasts from a variety of different sources, and across a variety of time scales ranging from monthly average values, to annual and multi-decadal values. First developed in Adobe Flash, a HTML 5 compatible version has been in the works and a functional draft is available here.</span></li>
+  <li>
+    <a href="http://www.glerl.noaa.gov/data/dashboard/GLD_HTML5.html">NOAA Great Lakes Dashboard</a><br/>
+    <span class="desc">
+      The Great Lakes Dashboard provides user-friendly 
+      access to aggregated time series data, model output, and forecasts for 
+      multiple variables describing the Great Lakes along with background 
+      information. First developed in Adobe Flash, a HTML 5 compatible version 
+      has been in the works and a functional draft is available here.
+    </span>
+  </li>
   
   <li>
     <a href="http://howmanydiapers.com">HowManyDiapers.com</a><br />
index 16e4d96..dd4329c 100644 (file)
@@ -47,12 +47,7 @@ Dygraph.synchronize = function(/* dygraphs..., opts */) {
     range: true
   };
   var dygraphs = [];
-
-  var prevCallbacks = {
-    draw: null,
-    highlight: null,
-    unhighlight: null
-  };
+  var prevCallbacks = [];
 
   var parseOpts = function(obj) {
     if (!(obj instanceof Object)) {
@@ -100,12 +95,23 @@ Dygraph.synchronize = function(/* dygraphs..., opts */) {
     throw 'Invalid invocation of Dygraph.synchronize(). ' +
           'Need two or more dygraphs to synchronize.';
   }
-  
+
   var readycount = dygraphs.length;
   for (var i = 0; i < dygraphs.length; i++) {
     var g = dygraphs[i];
     g.ready( function() {
       if (--readycount == 0) {
+        // store original callbacks
+        var callBackTypes = ['drawCallback', 'highlightCallback', 'unhighlightCallback'];
+        for (var j = 0; j < dygraphs.length; j++) {
+          if (!prevCallbacks[j]) {
+            prevCallbacks[j] = {};
+          }
+          for (var k = callBackTypes.length - 1; k >= 0; k--) {
+            prevCallbacks[j][callBackTypes[k]] = dygraphs[j].getFunctionOption(callBackTypes[k]);
+          }
+        }
+
         // Listen for draw, highlight, unhighlight callbacks.
         if (opts.zoom) {
           attachZoomHandlers(dygraphs, opts, prevCallbacks);
@@ -117,18 +123,18 @@ Dygraph.synchronize = function(/* dygraphs..., opts */) {
       }
     });
   }
+
   return {
     detach: function() {
       for (var i = 0; i < dygraphs.length; i++) {
         var g = dygraphs[i];
         if (opts.zoom) {
-          g.updateOptions({drawCallback: prevCallbacks.draw});
+          g.updateOptions({drawCallback: prevCallbacks[i].drawCallback});
         }
         if (opts.selection) {
           g.updateOptions({
-            highlightCallback: prevCallbacks.highlight,
-            unhighlightCallback: prevCallbacks.unhighlight
+            highlightCallback: prevCallbacks[i].highlightCallback,
+            unhighlightCallback: prevCallbacks[i].unhighlightCallback
           });
         }
       }
@@ -144,10 +150,8 @@ function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
   var block = false;
   for (var i = 0; i < gs.length; i++) {
     var g = gs[i];
-    prevCallbacks.draw = g.getFunctionOption('drawCallback');
     g.updateOptions({
       drawCallback: function(me, initial) {
-        if (prevCallbacks.draw) prevCallbacks.draw(me, initial);
         if (block || initial) return;
         block = true;
         var opts = {
@@ -156,12 +160,17 @@ function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
         if (syncOpts.range) opts.valueRange = me.yAxisRange();
 
         for (var j = 0; j < gs.length; j++) {
-          if (gs[j] == me) continue;
+          if (gs[j] == me) {
+            if (prevCallbacks[j] && prevCallbacks[j].drawCallback) {
+              prevCallbacks[j].drawCallback.apply(this, arguments);
+            }
+            continue;
+          }
           gs[j].updateOptions(opts);
         }
         block = false;
       }
-    }, false /* no need to redraw */);
+    }, true /* no need to redraw */);
   }
 }
 
@@ -169,18 +178,19 @@ function attachSelectionHandlers(gs, prevCallbacks) {
   var block = false;
   for (var i = 0; i < gs.length; i++) {
     var g = gs[i];
-    prevCallbacks.highlight = g.getFunctionOption('highlightCallback');
-    prevCallbacks.unhighlight = g.getFunctionOption('unhighlightCallback');
+
     g.updateOptions({
       highlightCallback: function(event, x, points, row, seriesName) {
-        if (prevCallbacks.highlight) {
-            prevCallbacks.highlight(event, x, points, row, seriesName);
-        }
         if (block) return;
         block = true;
         var me = this;
         for (var i = 0; i < gs.length; i++) {
-          if (me == gs[i]) continue;
+          if (me == gs[i]) {
+            if (prevCallbacks[i] && prevCallbacks[i].highlightCallback) {
+              prevCallbacks[i].highlightCallback.apply(this, arguments);
+            }
+            continue;
+          }
           var idx = gs[i].getRowForX(x);
           if (idx !== null) {
             gs[i].setSelection(idx, seriesName);
@@ -189,17 +199,21 @@ function attachSelectionHandlers(gs, prevCallbacks) {
         block = false;
       },
       unhighlightCallback: function(event) {
-        if (prevCallbacks.unhighlight) prevCallbacks.unhighlight(event);
         if (block) return;
         block = true;
         var me = this;
         for (var i = 0; i < gs.length; i++) {
-          if (me == gs[i]) continue;
+          if (me == gs[i]) {
+            if (prevCallbacks[i] && prevCallbacks[i].unhighlightCallback) {
+              prevCallbacks[i].unhighlightCallback.apply(this, arguments);
+            }
+            continue;
+          }
           gs[i].clearSelection();
         }
         block = false;
       }
-    });
+    }, true /* no need to redraw */);
   }
 }