In the example below, new data is loaded every time the user zooms in on the graph. This provides an overall view of the entire possible data set via the range selector below the graph, but allows interactive drill down in to more detailed views of the data without having to load the entire data set at the start. For very large data sets, loading all the data from the start is not practical.
The shaded areas above and below the solid line indicate min/max values whenever the data is being down-sampled, and in this case, the solid line indicates the average value. As the user zooms in, eventually there are no min/max indicators because the raw data values are being displayed.
On page load, two data requests are sent to the server. One for the "range" data, and one for the "detail" data. When zooming, a new request is made for more detailed data according to the new zoom extents (or "dateWindow" in Dygraphs terminology.)
When the new detail data set is received, the code in GraphDataProvider.js splices it with the previously loaded range data set to generate a single new "spliced data set". This spliced data set is what is given to Dygraphs for drawing.
This allows Dygraphs to draw and support the range selector control, but also draw the more detailed data in the zoom window currently being viewed. The non-zoomed, more down-sampled, data can be seen while dragging the range selector because the code does not initiate a new detail data load until mouse-up.
The key to this approach is in understanding the different ways the zoom window (dateWindow) can be changed in Dygraphs and the different results from each interaction. Interactions causing dateWindow to be changed include:
To handle these interactions, the code installs a mouse-down and subsequent mouse-up listener on the range selector. (It also installs corresponding touch event listeners so this works on tablets.) When a mouse down occurs on the range selector, the code tracks it and ignores all subsequent zoomCallbacks. This handles (A). We initiate the data load on mouse-up. This handles (A) and (B). If there was no mouse-down on the range selector and we get a zoomCallback, then we assume (C), and so initiate an immediate data load. Handling (D) requires hooking in to the drawCallback and is not shown in this example.
That's basically it. The code, and comments in the code, shows the details.
I used jQuery because it simplifies the code and, honestly, I've probably started forgetting how to work with DOM events correctly without it. I also used two other third party libraries that are not required, but made this example a little better. Both can be easily removed.
Credit also to KCF Technologies for giving me permission to publish code showing the basic technique above. I flushed out the technique while doing work for them on their next generation Smart Diagnostics product, which uses a much more complicated variant of the example graph above.