files: [
'dist/dygraph-combined-dev.js',
'src/extras/smooth-plotter.js',
+ 'src/extras/synchronizer.js',
'auto_tests/data/*.js',
'auto_tests/tests/*.js',
],
files: [
'dist/dygraph-combined-dev.js',
'src/extras/smooth-plotter.js',
+ 'src/extras/synchronizer.js',
'auto_tests/data/*.js',
'auto_tests/tests/*.js',
],
--- /dev/null
+/**
+ * @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);
+ });
+});
{
"name": "dygraphs",
- "version": "v1.1.0",
"main": "dygraph-combined.js",
"ignore": [
"Makefile",
(<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 />
range: true
};
var dygraphs = [];
-
- var prevCallbacks = {
- draw: null,
- highlight: null,
- unhighlight: null
- };
+ var prevCallbacks = [];
var parseOpts = function(obj) {
if (!(obj instanceof Object)) {
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);
}
});
}
-
+
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
});
}
}
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 = {
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 */);
}
}
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);
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 */);
}
}