- // Draw zoom rectangles when the mouse is down and the user moves around
- Dygraph.addEvent(this.mouseEventElement_, 'mousemove', function(event) {
- if (isZooming) {
- dragEndX = getX(event);
- dragEndY = getY(event);
-
- var xDelta = Math.abs(dragStartX - dragEndX);
- var yDelta = Math.abs(dragStartY - dragEndY);
-
- // drag direction threshold for y axis is twice as large as x axis
- dragDirection = (xDelta < yDelta / 2) ? Dygraph.VERTICAL : Dygraph.HORIZONTAL;
-
- self.drawZoomRect_(dragDirection, dragStartX, dragEndX, dragStartY, dragEndY,
- prevDragDirection, prevEndX, prevEndY);
-
- prevEndX = dragEndX;
- prevEndY = dragEndY;
- prevDragDirection = dragDirection;
- } else if (isPanning) {
- dragEndX = getX(event);
- dragEndY = getY(event);
-
- // Want to have it so that:
- // 1. draggingDate appears at dragEndX, draggingValue appears at dragEndY.
- // 2. daterange = (dateWindow_[1] - dateWindow_[0]) is unaltered.
- // 3. draggingValue appears at dragEndY.
- // 4. valueRange is unaltered.
-
- var minDate = draggingDate - (dragEndX / self.width_) * dateRange;
- var maxDate = minDate + dateRange;
- self.dateWindow_ = [minDate, maxDate];
-
-
- // MERGE
-=======
- // y-axis scaling is automatic unless a valueRange is defined or
- // if the user zooms in on the y-axis. If neither is true, valueWindow_
- // will be null.
- if (self.valueWindow_) {
- var maxValue = draggingValue + (dragEndY / self.height_) * valueRange;
- var minValue = maxValue - valueRange;
- self.valueWindow_ = [ minValue, maxValue ];
+/**
+ * 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.
+ *
+ * @param { Event } event the event object which led to the startPan call.
+ * @param { Dygraph} g The dygraph on which to act.
+ * @param { Object} context The dragging context object (with
+ * dragStartX/dragStartY/etc. properties). This function modifies the context.
+ */
+Dygraph.Interaction.startPan = function(event, g, context) {
+ context.isPanning = true;
+ var xRange = g.xAxisRange();
+ context.dateRange = xRange[1] - xRange[0];
+ context.initialLeftmostDate = xRange[0];
+ context.xUnitsPerPixel = context.dateRange / (g.plotter_.area.w - 1);
+
+ if (g.attr_("panEdgeFraction")) {
+ var maxXPixelsToDraw = g.width_ * g.attr_("panEdgeFraction");
+ var xExtremes = g.xAxisExtremes(); // I REALLY WANT TO CALL THIS xTremes!
+
+ var boundedLeftX = g.toDomXCoord(xExtremes[0]) - maxXPixelsToDraw;
+ var boundedRightX = g.toDomXCoord(xExtremes[1]) + maxXPixelsToDraw;
+
+ var boundedLeftDate = g.toDataXCoord(boundedLeftX);
+ var boundedRightDate = g.toDataXCoord(boundedRightX);
+ context.boundedDates = [boundedLeftDate, boundedRightDate];
+
+ var boundedValues = [];
+ var maxYPixelsToDraw = g.height_ * g.attr_("panEdgeFraction");
+
+ for (var i = 0; i < g.axes_.length; i++) {
+ var axis = g.axes_[i];
+ var yExtremes = axis.extremeRange;
+
+ var boundedTopY = g.toDomYCoord(yExtremes[0], i) + maxYPixelsToDraw;
+ var boundedBottomY = g.toDomYCoord(yExtremes[1], i) - maxYPixelsToDraw;
+
+ var boundedTopValue = g.toDataYCoord(boundedTopY);
+ var boundedBottomValue = g.toDataYCoord(boundedBottomY);
+
+ boundedValues[i] = [boundedTopValue, boundedBottomValue];
+ }
+ context.boundedValues = boundedValues;
+ }
+
+ // Record the range of each y-axis at the start of the drag.
+ // If any axis has a valueRange or valueWindow, then we want a 2D pan.
+ context.is2DPan = false;
+ for (var i = 0; i < g.axes_.length; i++) {
+ var axis = g.axes_[i];
+ var yRange = g.yAxisRange(i);
+ // TODO(konigsberg): These values should be in |context|.
+ // In log scale, initialTopValue, dragValueRange and unitsPerPixel are log scale.
+ if (axis.logscale) {
+ axis.initialTopValue = Dygraph.log10(yRange[1]);
+ axis.dragValueRange = Dygraph.log10(yRange[1]) - Dygraph.log10(yRange[0]);
+ } else {
+ axis.initialTopValue = yRange[1];
+ axis.dragValueRange = yRange[1] - yRange[0];
+ }
+ axis.unitsPerPixel = axis.dragValueRange / (g.plotter_.area.h - 1);
+
+ // While calculating axes, set 2dpan.
+ if (axis.valueWindow || axis.valueRange) context.is2DPan = true;
+ }
+};
+
+/**
+ * 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.
+ *
+ * @param { Event } event the event object which led to the movePan call.
+ * @param { Dygraph} g The dygraph on which to act.
+ * @param { Object} context The dragging context object (with
+ * dragStartX/dragStartY/etc. properties). This function modifies the context.
+ */
+Dygraph.Interaction.movePan = function(event, g, context) {
+ context.dragEndX = g.dragGetX_(event, context);
+ context.dragEndY = g.dragGetY_(event, context);
+
+ var minDate = context.initialLeftmostDate -
+ (context.dragEndX - context.dragStartX) * context.xUnitsPerPixel;
+ if (context.boundedDates) {
+ minDate = Math.max(minDate, context.boundedDates[0]);
+ }
+ var maxDate = minDate + context.dateRange;
+ if (context.boundedDates) {
+ if (maxDate > context.boundedDates[1]) {
+ // Adjust minDate, and recompute maxDate.
+ minDate = minDate - (maxDate - context.boundedDates[1]);
+ maxDate = minDate + context.dateRange;
+ }
+ }
+
+ g.dateWindow_ = [minDate, maxDate];
+
+ // y-axis scaling is automatic unless this is a full 2D pan.
+ if (context.is2DPan) {
+ // Adjust each axis appropriately.
+ for (var i = 0; i < g.axes_.length; i++) {
+ var axis = g.axes_[i];
+
+ var pixelsDragged = context.dragEndY - context.dragStartY;
+ var unitsDragged = pixelsDragged * axis.unitsPerPixel;
+
+ var boundedValue = context.boundedValues ? context.boundedValues[i] : null;
+
+ // In log scale, maxValue and minValue are the logs of those values.
+ var maxValue = axis.initialTopValue + unitsDragged;
+ if (boundedValue) {
+ maxValue = Math.min(maxValue, boundedValue[1]);
+ }
+ var minValue = maxValue - axis.dragValueRange;
+ if (boundedValue) {
+ if (minValue < boundedValue[0]) {
+ // Adjust maxValue, and recompute minValue.
+ maxValue = maxValue - (minValue - boundedValue[0]);
+ minValue = maxValue - axis.dragValueRange;
+ }