From 885c13e45bc329818d56d375b8cac6a5a40d7c5a Mon Sep 17 00:00:00 2001 From: Robert Konigsberg Date: Wed, 15 Dec 2010 14:24:40 -0500 Subject: [PATCH] Response to code review comments, added missing interaction.html. --- dygraph.js | 157 ++++++++++++++++++++++------------- tests/interaction.html | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/zoom.html | 11 +-- 3 files changed, 322 insertions(+), 62 deletions(-) create mode 100644 tests/interaction.html diff --git a/dygraph.js b/dygraph.js index df42c06..a16d2a0 100644 --- a/dygraph.js +++ b/dygraph.js @@ -79,6 +79,53 @@ Dygraph.DEFAULT_WIDTH = 480; Dygraph.DEFAULT_HEIGHT = 320; Dygraph.AXIS_LINE_WIDTH = 0.3; + +Dygraph.DEFAULT_INTERACTION_MODEL = { + // Track the beginning of drag events + 'mousedown' : function(event, g, context) { + context.initializeMouseDown(event, g, context); + + if (event.altKey || event.shiftKey) { + Dygraph.startPan(event, g, context); + } else { + Dygraph.startZoom(event, g, context); + } + }, + + // Draw zoom rectangles when the mouse is down and the user moves around + 'mousemove' : function(event, g, context) { + if (context.isZooming) { + Dygraph.moveZoom(event, g, context); + } else if (context.isPanning) { + Dygraph.movePan(event, g, context); + } + }, + + 'mouseup' : function(event, g, context) { + if (context.isZooming) { + Dygraph.endZoom(event, g, context); + } else if (context.isPanning) { + Dygraph.endPan(event, g, context); + } + }, + + // Temporarily cancel the dragging event when the mouse leaves the graph + 'mouseout' : function(event, g, context) { + if (context.isZooming) { + context.dragEndX = null; + context.dragEndY = null; + } + }, + + // Disable zooming out if panning. + 'dblclick' : function(event, g, context) { + if (event.altKey || event.shiftKey) { + return; + } + g.doUnzoom_(); + } +}; + // Default attribute values. Dygraph.DEFAULT_ATTRS = { highlightCircleSize: 3, @@ -128,6 +175,8 @@ Dygraph.DEFAULT_ATTRS = { stepPlot: false, avoidMinZero: false, + + interactionModel: Dygraph.DEFAULT_INTERACTION_MODEL }; // Various logging levels. @@ -158,7 +207,7 @@ Dygraph.prototype.__old_init__ = function(div, file, labels, attrs) { /** * Initializes the Dygraph. This creates a new DIV and constructs the PlotKit - * and context <canvas> inside of it. See the constructor for details + * and context <canvas> inside of it. See the constructor for details. * on the parameters. * @param {Element} div the Element to render the graph into. * @param {String | Function} file Source data @@ -431,12 +480,8 @@ Dygraph.addEvent = function(el, evt, fn) { }; -// -// An attempt at scroll wheel management. -// // Based on the article at // http://www.switchonthecode.com/tutorials/javascript-tutorial-the-scroll-wheel - Dygraph.cancelEvent = function(e) { e = e ? e : window.event; if (e.stopPropagation) { @@ -451,7 +496,6 @@ Dygraph.cancelEvent = function(e) { return false; } - /** * Generates interface elements for the Dygraph: a containing div, a div to * display the current point, and a textbox to adjust the rolling average @@ -792,6 +836,13 @@ Dygraph.prototype.dragGetY_ = function(e, context) { return Dygraph.pageY(e) - context.py }; +// Called in response to an interaction model operation that +// should start the default panning behavior. +// +// It's used in the default callback for "mousedown" operations. +// Custom interaction model builders can use it to provide the default +// panning behavior. +// Dygraph.startPan = function(event, g, context) { // have to be zoomed in to pan. var zoomedY = false; @@ -824,6 +875,13 @@ Dygraph.startPan = function(event, g, context) { context.draggingDate = (context.dragStartX / g.width_) * context.dateRange + xRange[0]; }; +// Called in response to an interaction model operation that +// responds to an event that pans the view. +// +// It's used in the default callback for "mousemove" operations. +// Custom interaction model builders can use it to provide the default +// panning behavior. +// Dygraph.movePan = function(event, g, context) { context.dragEndX = g.dragGetX_(event, context); context.dragEndY = g.dragGetY_(event, context); @@ -854,6 +912,13 @@ Dygraph.movePan = function(event, g, context) { g.drawGraph_(); } +// Called in response to an interaction model operation that +// responds to an event that ends panning. +// +// It's used in the default callback for "mouseup" operations. +// Custom interaction model builders can use it to provide the default +// panning behavior. +// Dygraph.endPan = function(event, g, context) { context.isPanning = false; context.is2DPan = false; @@ -862,10 +927,24 @@ Dygraph.endPan = function(event, g, context) { context.valueRange = null; } +// Called in response to an interaction model operation that +// responds to an event that starts zooming. +// +// It's used in the default callback for "mousedown" operations. +// Custom interaction model builders can use it to provide the default +// zooming behavior. +// Dygraph.startZoom = function(event, g, context) { context.isZooming = true; } +// Called in response to an interaction model operation that +// responds to an event that defines zoom boundaries. +// +// It's used in the default callback for "mousemove" operations. +// Custom interaction model builders can use it to provide the default +// zooming behavior. +// Dygraph.moveZoom = function(event, g, context) { context.dragEndX = g.dragGetX_(event, context); context.dragEndY = g.dragGetY_(event, context); @@ -891,6 +970,14 @@ Dygraph.moveZoom = function(event, g, context) { context.prevDragDirection = context.dragDirection; } +// Called in response to an interaction model operation that +// responds to an event that performs a zoom based on previously defined +// bounds.. +// +// It's used in the default callback for "mouseup" operations. +// Custom interaction model builders can use it to provide the default +// zooming behavior. +// Dygraph.endZoom = function(event, g, context) { context.isZooming = false; context.dragEndX = g.dragGetX_(event, context); @@ -941,51 +1028,6 @@ Dygraph.endZoom = function(event, g, context) { context.dragStartY = null; } -Dygraph.prototype.defaultInteractionModel = { - // Track the beginning of drag events - 'mousedown' : function(event, g, context) { - context.initializeMouseDown(event, g, context); - - if (event.altKey || event.shiftKey) { - Dygraph.startPan(event, g, context); - } else { - Dygraph.startZoom(event, g, context); - } - }, - - // Draw zoom rectangles when the mouse is down and the user moves around - 'mousemove' : function(event, g, context) { - if (context.isZooming) { - Dygraph.moveZoom(event, g, context); - } else if (context.isPanning) { - Dygraph.movePan(event, g, context); - } - }, - - 'mouseup' : function(event, g, context) { - if (context.isZooming) { - Dygraph.endZoom(event, g, context); - } else if (context.isPanning) { - Dygraph.endPan(event, g, context); - } - }, - - // Temporarily cancel the dragging event when the mouse leaves the graph - 'mouseout' : function(event, g, context) { - if (context.isZooming) { - context.dragEndX = null; - context.dragEndY = null; - } - }, - - // Disable zooming out if panning. - 'dblclick' : function(event, g, context) { - if (event.altKey || event.shiftKey) { - return; - } - g.doUnzoom_(); - } -}; /** * Set up all the mouse handlers needed to capture dragging behavior for zoom @@ -1024,7 +1066,7 @@ Dygraph.prototype.createDragInterface_ = function() { py : 0, initializeMouseDown : function(event, g, context) { - // prevents mouse drags from selecting page text. + // prevents mouse drags from selecting page text. if (event.preventDefault) { event.preventDefault(); // Firefox, Chrome, etc. } else { @@ -1039,8 +1081,8 @@ Dygraph.prototype.createDragInterface_ = function() { } }; - // Defines default behavior if there are no event handlers. - var handlers = this.user_attrs_.interactionModel || this.defaultInteractionModel; + var interactionModel = this.attr_("interactionModel"); + // Function that binds g and context to the handler. var bindHandler = function(handler, g) { @@ -1049,9 +1091,10 @@ Dygraph.prototype.createDragInterface_ = function() { }; }; - for (var eventName in handlers) { + for (var eventName in interactionModel) { + if (!interactionModel.hasOwnProperty(eventName)) continue; Dygraph.addEvent(this.mouseEventElement_, eventName, - bindHandler(handlers[eventName], this)); + bindHandler(interactionModel[eventName], this)); } // Self is the graph. @@ -1081,7 +1124,7 @@ Dygraph.prototype.createDragInterface_ = function() { /** * Draw a gray zoom rectangle over the desired area of the canvas. Also clears * up any previous zoom rectangles that were drawn. This could be optimized to - * avoid extra redrawing, but it's tricky to avoid contexts with the status + * avoid extra redrawing, but it's tricky to avoid interactions with the status * dots. * * @param {Number} direction the direction of the zoom rectangle. Acceptable diff --git a/tests/interaction.html b/tests/interaction.html new file mode 100644 index 0000000..082a54e --- /dev/null +++ b/tests/interaction.html @@ -0,0 +1,216 @@ + + + + interaction model + + + + + + + + + + + + + + +
+ Default interaction model +
+
Zoom: click-drag
Pan: shift-click-drag
Restore zoom level: double-click
+
+ No interaction model +
+
Click and drag all you like, it won't do anything!
+ Custom interaction model + + +
+
+ Zoom in: double-click, scroll wheel
+ Zoom out: ctrl-double-click, scroll wheel
+ Pan: click-drag
+ Restore zoom level: press button
+
+ Fun model! +
+
+ Keep the mouse button pressed, and hover over all points + to mark them. +
+ + + + + diff --git a/tests/zoom.html b/tests/zoom.html index 91cee43..2f0cf98 100644 --- a/tests/zoom.html +++ b/tests/zoom.html @@ -40,9 +40,10 @@ document.getElementById("div_g"), NoisyData, { errorBars: true, - zoomCallback : function(minDate, maxDate, yRanges) { - showDimensions(minDate, maxDate, yRanges); } - } + zoomCallback : function(minDate, maxDate, yRanges) { + showDimensions(minDate, maxDate, yRanges); + } + } ); // TODO(konigsberg): Implement a visualization that verifies that initial @@ -56,8 +57,8 @@ showDimensions(minDate, maxDate, [minValue, maxValue]); function showDimensions(minDate, maxDate, yRanges) { - showXDimensions(minDate, maxDate); - showYDimensions(yRanges); + showXDimensions(minDate, maxDate); + showYDimensions(yRanges); } function showXDimensions(first, second) { -- 2.7.4