text: /**
   * @license
   * Copyright 2011 Robert Konigsberg (konigsberg@google.com)
   * MIT-licensed (http://opensource.org/licenses/MIT)
   */
  
  /**
   * @fileoverview The default interaction model for Dygraphs. This is kept out
   * of dygraph.js for better navigability.
   * @author Robert Konigsberg (konigsberg@google.com)
   */
  
  /*global Dygraph:false */
  "use strict";
  
  Object.defineProperty(exports, "__esModule", {
    value: true
  });
  
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj["default"] = obj; return newObj; } }
  
  var _dygraphUtils = require('./dygraph-utils');
  
  var utils = _interopRequireWildcard(_dygraphUtils);
  
  /**
   * You can drag this many pixels past the edge of the chart and still have it
   * be considered a zoom. This makes it easier to zoom to the exact edge of the
   * chart, a fairly common operation.
   */
  var DRAG_EDGE_MARGIN = 100;
  
  /**
   * A collection of functions to facilitate build custom interaction models.
   * @class
   */
  var DygraphInteraction = {};
  
  /**
   * Checks whether the beginning & ending of an event were close enough that it
   * should be considered a click. If it should, dispatch appropriate events.
   * Returns true if the event was treated as a click.
   *
   * @param {Event} event
   * @param {Dygraph} g
   * @param {Object} context
   */
  DygraphInteraction.maybeTreatMouseOpAsClick = function (event, g, context) {
    context.dragEndX = utils.dragGetX_(event, context);
    context.dragEndY = utils.dragGetY_(event, context);
    var regionWidth = Math.abs(context.dragEndX - context.dragStartX);
    var regionHeight = Math.abs(context.dragEndY - context.dragStartY);
  
    if (regionWidth < 2 && regionHeight < 2 && g.lastx_ !== undefined && g.lastx_ != -1) {
      DygraphInteraction.treatMouseOpAsClick(g, event, context);
    }
  
    context.regionWidth = regionWidth;
    context.regionHeight = regionHeight;
  };
  
  /**
   * 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.
   */
  DygraphInteraction.startPan = function (event, g, context) {
    var i, axis;
    context.isPanning = true;
    var xRange = g.xAxisRange();
  
    if (g.getOptionForAxis("logscale", "x")) {
      context.initialLeftmostDate = utils.log10(xRange[0]);
      context.dateRange = utils.log10(xRange[1]) - utils.log10(xRange[0]);
    } else {
      context.initialLeftmostDate = xRange[0];
      context.dateRange = xRange[1] - xRange[0];
    }
    context.xUnitsPerPixel = context.dateRange / (g.plotter_.area.w - 1);
  
    if (g.getNumericOption("panEdgeFraction")) {
      var maxXPixelsToDraw = g.width_ * g.getNumericOption("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.getNumericOption("panEdgeFraction");
  
      for (i = 0; i < g.axes_.length; i++) {
        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, i);
        var boundedBottomValue = g.toDataYCoord(boundedBottomY, i);
  
        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, then we want a 2D pan.
    // We can't store data directly in g.axes_, because it does not belong to us
    // and could change out from under us during a pan (say if there's a data
    // update).
    context.is2DPan = false;
    context.axes = [];
    for (i = 0; i < g.axes_.length; i++) {
      axis = g.axes_[i];
      var axis_data = {};
      var yRange = g.yAxisRange(i);
      // TODO(konigsberg): These values should be in |context|.
      // In log scale, initialTopValue, dragValueRange and unitsPerPixel are log scale.
      var logscale = g.attributes_.getForAxis("logscale", i);
      if (logscale) {
        axis_data.initialTopValue = utils.log10(yRange[1]);
        axis_data.dragValueRange = utils.log10(yRange[1]) - utils.log10(yRange[0]);
      } else {
        axis_data.initialTopValue = yRange[1];
        axis_data.dragValueRange = yRange[1] - yRange[0];
      }
      axis_data.unitsPerPixel = axis_data.dragValueRange / (g.plotter_.area.h - 1);
      context.axes.push(axis_data);
  
      // While calculating axes, set 2dpan.
      if (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.
   */
  DygraphInteraction.movePan = function (event, g, context) {
    context.dragEndX = utils.dragGetX_(event, context);
    context.dragEndY = utils.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;
      }
    }
  
    if (g.getOptionForAxis("logscale", "x")) {
      g.dateWindow_ = [Math.pow(utils.LOG_SCALE, minDate), Math.pow(utils.LOG_SCALE, maxDate)];
    } else {
      g.dateWindow_ = [minDate, maxDate];
    }
  
    // y-axis scaling is automatic unless this is a full 2D pan.
    if (context.is2DPan) {
  
      var pixelsDragged = context.dragEndY - context.dragStartY;
  
      // Adjust each axis appropriately.
      for (var i = 0; i < g.axes_.length; i++) {
        var axis = g.axes_[i];
        var axis_data = context.axes[i];
        var unitsDragged = pixelsDragged * axis_data.unitsPerPixel;
  
        var boundedValue = context.boundedValues ? context.boundedValues[i] : null;
  
        // In log scale, maxValue and minValue are the logs of those values.
        var maxValue = axis_data.initialTopValue + unitsDragged;
        if (boundedValue) {
          maxValue = Math.min(maxValue, boundedValue[1]);
        }
        var minValue = maxValue - axis_data.dragValueRange;
        if (boundedValue) {
          if (minValue < boundedValue[0]) {
            // Adjust maxValue, and recompute minValue.
            maxValue = maxValue - (minValue - boundedValue[0]);
            minValue = maxValue - axis_data.dragValueRange;
          }
        }
        if (g.attributes_.getForAxis("logscale", i)) {
          axis.valueRange = [Math.pow(utils.LOG_SCALE, minValue), Math.pow(utils.LOG_SCALE, maxValue)];
        } else {
          axis.valueRange = [minValue, maxValue];
        }
      }
    }
  
    g.drawGraph_(false);
  };
  
  /**
   * 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.
   *
   * @param {Event} event the event object which led to the endPan 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.
   */
  DygraphInteraction.endPan = DygraphInteraction.maybeTreatMouseOpAsClick;
  
  /**
   * 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.
   *
   * @param {Event} event the event object which led to the startZoom 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.
   */
  DygraphInteraction.startZoom = function (event, g, context) {
    context.isZooming = true;
    context.zoomMoved = false;
  };
  
  /**
   * 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.
   *
   * @param {Event} event the event object which led to the moveZoom 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.
   */
  DygraphInteraction.moveZoom = function (event, g, context) {
    context.zoomMoved = true;
    context.dragEndX = utils.dragGetX_(event, context);
    context.dragEndY = utils.dragGetY_(event, context);
  
    var xDelta = Math.abs(context.dragStartX - context.dragEndX);
    var yDelta = Math.abs(context.dragStartY - context.dragEndY);
  
    // drag direction threshold for y axis is twice as large as x axis
    context.dragDirection = xDelta < yDelta / 2 ? utils.VERTICAL : utils.HORIZONTAL;
  
    g.drawZoomRect_(context.dragDirection, context.dragStartX, context.dragEndX, context.dragStartY, context.dragEndY, context.prevDragDirection, context.prevEndX, context.prevEndY);
  
    context.prevEndX = context.dragEndX;
    context.prevEndY = context.dragEndY;
    context.prevDragDirection = context.dragDirection;
  };
  
  /**
   * TODO(danvk): move this logic into dygraph.js
   * @param {Dygraph} g
   * @param {Event} event
   * @param {Object} context
   */
  DygraphInteraction.treatMouseOpAsClick = function (g, event, context) {
    var clickCallback = g.getFunctionOption('clickCallback');
    var pointClickCallback = g.getFunctionOption('pointClickCallback');
  
    var selectedPoint = null;
  
    // Find out if the click occurs on a point.
    var closestIdx = -1;
    var closestDistance = Number.MAX_VALUE;
  
    // check if the click was on a particular point.
    for (var i = 0; i < g.selPoints_.length; i++) {
      var p = g.selPoints_[i];
      var distance = Math.pow(p.canvasx - context.dragEndX, 2) + Math.pow(p.canvasy - context.dragEndY, 2);
      if (!isNaN(distance) && (closestIdx == -1 || distance < closestDistance)) {
        closestDistance = distance;
        closestIdx = i;
      }
    }
  
    // Allow any click within two pixels of the dot.
    var radius = g.getNumericOption('highlightCircleSize') + 2;
    if (closestDistance <= radius * radius) {
      selectedPoint = g.selPoints_[closestIdx];
    }
  
    if (selectedPoint) {
      var e = {
        cancelable: true,
        point: selectedPoint,
        canvasx: context.dragEndX,
        canvasy: context.dragEndY
      };
      var defaultPrevented = g.cascadeEvents_('pointClick', e);
      if (defaultPrevented) {
        // Note: this also prevents click / clickCallback from firing.
        return;
      }
      if (pointClickCallback) {
        pointClickCallback.call(g, event, selectedPoint);
      }
    }
  
    var e = {
      cancelable: true,
      xval: g.lastx_, // closest point by x value
      pts: g.selPoints_,
      canvasx: context.dragEndX,
      canvasy: context.dragEndY
    };
    if (!g.cascadeEvents_('click', e)) {
      if (clickCallback) {
        // TODO(danvk): pass along more info about the points, e.g. 'x'
        clickCallback.call(g, event, g.lastx_, g.selPoints_);
      }
    }
  };
  
  /**
   * 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.
   *
   * @param {Event} event the event object which led to the endZoom call.
   * @param {Dygraph} g The dygraph on which to end the zoom.
   * @param {Object} context The dragging context object (with
   *     dragStartX/dragStartY/etc. properties). This function modifies the
   *     context.
   */
  DygraphInteraction.endZoom = function (event, g, context) {
    g.clearZoomRect_();
    context.isZooming = false;
    DygraphInteraction.maybeTreatMouseOpAsClick(event, g, context);
  
    // The zoom rectangle is visibly clipped to the plot area, so its behavior
    // should be as well.
    // See http://code.google.com/p/dygraphs/issues/detail?id=280
    var plotArea = g.getArea();
    if (context.regionWidth >= 10 && context.dragDirection == utils.HORIZONTAL) {
      var left = Math.min(context.dragStartX, context.dragEndX),
          right = Math.max(context.dragStartX, context.dragEndX);
      left = Math.max(left, plotArea.x);
      right = Math.min(right, plotArea.x + plotArea.w);
      if (left < right) {
        g.doZoomX_(left, right);
      }
      context.cancelNextDblclick = true;
    } else if (context.regionHeight >= 10 && context.dragDirection == utils.VERTICAL) {
      var top = Math.min(context.dragStartY, context.dragEndY),
          bottom = Math.max(context.dragStartY, context.dragEndY);
      top = Math.max(top, plotArea.y);
      bottom = Math.min(bottom, plotArea.y + plotArea.h);
      if (top < bottom) {
        g.doZoomY_(top, bottom);
      }
      context.cancelNextDblclick = true;
    }
    context.dragStartX = null;
    context.dragStartY = null;
  };
  
  /**
   * @private
   */
  DygraphInteraction.startTouch = function (event, g, context) {
    event.preventDefault(); // touch browsers are all nice.
    if (event.touches.length > 1) {
      // If the user ever puts two fingers down, it's not a double tap.
      context.startTimeForDoubleTapMs = null;
    }
  
    var touches = [];
    for (var i = 0; i < event.touches.length; i++) {
      var t = event.touches[i];
      // we dispense with 'dragGetX_' because all touchBrowsers support pageX
      touches.push({
        pageX: t.pageX,
        pageY: t.pageY,
        dataX: g.toDataXCoord(t.pageX),
        dataY: g.toDataYCoord(t.pageY)
        // identifier: t.identifier
      });
    }
    context.initialTouches = touches;
  
    if (touches.length == 1) {
      // This is just a swipe.
      context.initialPinchCenter = touches[0];
      context.touchDirections = { x: true, y: true };
    } else if (touches.length >= 2) {
      // It's become a pinch!
      // In case there are 3+ touches, we ignore all but the "first" two.
  
      // only screen coordinates can be averaged (data coords could be log scale).
      context.initialPinchCenter = {
        pageX: 0.5 * (touches[0].pageX + touches[1].pageX),
        pageY: 0.5 * (touches[0].pageY + touches[1].pageY),
  
        // TODO(danvk): remove
        dataX: 0.5 * (touches[0].dataX + touches[1].dataX),
        dataY: 0.5 * (touches[0].dataY + touches[1].dataY)
      };
  
      // Make pinches in a 45-degree swath around either axis 1-dimensional zooms.
      var initialAngle = 180 / Math.PI * Math.atan2(context.initialPinchCenter.pageY - touches[0].pageY, touches[0].pageX - context.initialPinchCenter.pageX);
  
      // use symmetry to get it into the first quadrant.
      initialAngle = Math.abs(initialAngle);
      if (initialAngle > 90) initialAngle = 90 - initialAngle;
  
      context.touchDirections = {
        x: initialAngle < 90 - 45 / 2,
        y: initialAngle > 45 / 2
      };
    }
  
    // save the full x & y ranges.
    context.initialRange = {
      x: g.xAxisRange(),
      y: g.yAxisRange()
    };
  };
  
  /**
   * @private
   */
  DygraphInteraction.moveTouch = function (event, g, context) {
    // If the tap moves, then it's definitely not part of a double-tap.
    context.startTimeForDoubleTapMs = null;
  
    var i,
        touches = [];
    for (i = 0; i < event.touches.length; i++) {
      var t = event.touches[i];
      touches.push({
        pageX: t.pageX,
        pageY: t.pageY
      });
    }
    var initialTouches = context.initialTouches;
  
    var c_now;
  
    // old and new centers.
    var c_init = context.initialPinchCenter;
    if (touches.length == 1) {
      c_now = touches[0];
    } else {
      c_now = {
        pageX: 0.5 * (touches[0].pageX + touches[1].pageX),
        pageY: 0.5 * (touches[0].pageY + touches[1].pageY)
      };
    }
  
    // this is the "swipe" component
    // we toss it out for now, but could use it in the future.
    var swipe = {
      pageX: c_now.pageX - c_init.pageX,
      pageY: c_now.pageY - c_init.pageY
    };
    var dataWidth = context.initialRange.x[1] - context.initialRange.x[0];
    var dataHeight = context.initialRange.y[0] - context.initialRange.y[1];
    swipe.dataX = swipe.pageX / g.plotter_.area.w * dataWidth;
    swipe.dataY = swipe.pageY / g.plotter_.area.h * dataHeight;
    var xScale, yScale;
  
    // The residual bits are usually split into scale & rotate bits, but we split
    // them into x-scale and y-scale bits.
    if (touches.length == 1) {
      xScale = 1.0;
      yScale = 1.0;
    } else if (touches.length >= 2) {
      var initHalfWidth = initialTouches[1].pageX - c_init.pageX;
      xScale = (touches[1].pageX - c_now.pageX) / initHalfWidth;
  
      var initHalfHeight = initialTouches[1].pageY - c_init.pageY;
      yScale = (touches[1].pageY - c_now.pageY) / initHalfHeight;
    }
  
    // Clip scaling to [1/8, 8] to prevent too much blowup.
    xScale = Math.min(8, Math.max(0.125, xScale));
    yScale = Math.min(8, Math.max(0.125, yScale));
  
    var didZoom = false;
    if (context.touchDirections.x) {
      g.dateWindow_ = [c_init.dataX - swipe.dataX + (context.initialRange.x[0] - c_init.dataX) / xScale, c_init.dataX - swipe.dataX + (context.initialRange.x[1] - c_init.dataX) / xScale];
      didZoom = true;
    }
  
    if (context.touchDirections.y) {
      for (i = 0; i < 1 /*g.axes_.length*/; i++) {
        var axis = g.axes_[i];
        var logscale = g.attributes_.getForAxis("logscale", i);
        if (logscale) {
          // TODO(danvk): implement
        } else {
            axis.valueRange = [c_init.dataY - swipe.dataY + (context.initialRange.y[0] - c_init.dataY) / yScale, c_init.dataY - swipe.dataY + (context.initialRange.y[1] - c_init.dataY) / yScale];
            didZoom = true;
          }
      }
    }
  
    g.drawGraph_(false);
  
    // We only call zoomCallback on zooms, not pans, to mirror desktop behavior.
    if (didZoom && touches.length > 1 && g.getFunctionOption('zoomCallback')) {
      var viewWindow = g.xAxisRange();
      g.getFunctionOption("zoomCallback").call(g, viewWindow[0], viewWindow[1], g.yAxisRanges());
    }
  };
  
  /**
   * @private
   */
  DygraphInteraction.endTouch = function (event, g, context) {
    if (event.touches.length !== 0) {
      // this is effectively a "reset"
      DygraphInteraction.startTouch(event, g, context);
    } else if (event.changedTouches.length == 1) {
      // Could be part of a "double tap"
      // The heuristic here is that it's a double-tap if the two touchend events
      // occur within 500ms and within a 50x50 pixel box.
      var now = new Date().getTime();
      var t = event.changedTouches[0];
      if (context.startTimeForDoubleTapMs && now - context.startTimeForDoubleTapMs < 500 && context.doubleTapX && Math.abs(context.doubleTapX - t.screenX) < 50 && context.doubleTapY && Math.abs(context.doubleTapY - t.screenY) < 50) {
        g.resetZoom();
      } else {
        context.startTimeForDoubleTapMs = now;
        context.doubleTapX = t.screenX;
        context.doubleTapY = t.screenY;
      }
    }
  };
  
  // Determine the distance from x to [left, right].
  var distanceFromInterval = function distanceFromInterval(x, left, right) {
    if (x < left) {
      return left - x;
    } else if (x > right) {
      return x - right;
    } else {
      return 0;
    }
  };
  
  /**
   * Returns the number of pixels by which the event happens from the nearest
   * edge of the chart. For events in the interior of the chart, this returns zero.
   */
  var distanceFromChart = function distanceFromChart(event, g) {
    var chartPos = utils.findPos(g.canvas_);
    var box = {
      left: chartPos.x,
      right: chartPos.x + g.canvas_.offsetWidth,
      top: chartPos.y,
      bottom: chartPos.y + g.canvas_.offsetHeight
    };
  
    var pt = {
      x: utils.pageX(event),
      y: utils.pageY(event)
    };
  
    var dx = distanceFromInterval(pt.x, box.left, box.right),
        dy = distanceFromInterval(pt.y, box.top, box.bottom);
    return Math.max(dx, dy);
  };
  
  /**
   * Default interation model for dygraphs. You can refer to specific elements of
   * this when constructing your own interaction model, e.g.:
   * g.updateOptions( {
   *   interactionModel: {
   *     mousedown: DygraphInteraction.defaultInteractionModel.mousedown
   *   }
   * } );
   */
  DygraphInteraction.defaultModel = {
    // Track the beginning of drag events
    mousedown: function mousedown(event, g, context) {
      // Right-click should not initiate a zoom.
      if (event.button && event.button == 2) return;
  
      context.initializeMouseDown(event, g, context);
  
      if (event.altKey || event.shiftKey) {
        DygraphInteraction.startPan(event, g, context);
      } else {
        DygraphInteraction.startZoom(event, g, context);
      }
  
      // Note: we register mousemove/mouseup on document to allow some leeway for
      // events to move outside of the chart. Interaction model events get
      // registered on the canvas, which is too small to allow this.
      var mousemove = function mousemove(event) {
        if (context.isZooming) {
          // When the mouse moves >200px from the chart edge, cancel the zoom.
          var d = distanceFromChart(event, g);
          if (d < DRAG_EDGE_MARGIN) {
            DygraphInteraction.moveZoom(event, g, context);
          } else {
            if (context.dragEndX !== null) {
              context.dragEndX = null;
              context.dragEndY = null;
              g.clearZoomRect_();
            }
          }
        } else if (context.isPanning) {
          DygraphInteraction.movePan(event, g, context);
        }
      };
      var mouseup = function mouseup(event) {
        if (context.isZooming) {
          if (context.dragEndX !== null) {
            DygraphInteraction.endZoom(event, g, context);
          } else {
            DygraphInteraction.maybeTreatMouseOpAsClick(event, g, context);
          }
        } else if (context.isPanning) {
          DygraphInteraction.endPan(event, g, context);
        }
  
        utils.removeEvent(document, 'mousemove', mousemove);
        utils.removeEvent(document, 'mouseup', mouseup);
        context.destroy();
      };
  
      g.addAndTrackEvent(document, 'mousemove', mousemove);
      g.addAndTrackEvent(document, 'mouseup', mouseup);
    },
    willDestroyContextMyself: true,
  
    touchstart: function touchstart(event, g, context) {
      DygraphInteraction.startTouch(event, g, context);
    },
    touchmove: function touchmove(event, g, context) {
      DygraphInteraction.moveTouch(event, g, context);
    },
    touchend: function touchend(event, g, context) {
      DygraphInteraction.endTouch(event, g, context);
    },
  
    // Disable zooming out if panning.
    dblclick: function dblclick(event, g, context) {
      if (context.cancelNextDblclick) {
        context.cancelNextDblclick = false;
        return;
      }
  
      // Give plugins a chance to grab this event.
      var e = {
        canvasx: context.dragEndX,
        canvasy: context.dragEndY,
        cancelable: true
      };
      if (g.cascadeEvents_('dblclick', e)) {
        return;
      }
  
      if (event.altKey || event.shiftKey) {
        return;
      }
      g.resetZoom();
    }
  };
  
  /*
  Dygraph.DEFAULT_ATTRS.interactionModel = DygraphInteraction.defaultModel;
  
  // old ways of accessing these methods/properties
  Dygraph.defaultInteractionModel = DygraphInteraction.defaultModel;
  Dygraph.endZoom = DygraphInteraction.endZoom;
  Dygraph.moveZoom = DygraphInteraction.moveZoom;
  Dygraph.startZoom = DygraphInteraction.startZoom;
  Dygraph.endPan = DygraphInteraction.endPan;
  Dygraph.movePan = DygraphInteraction.movePan;
  Dygraph.startPan = DygraphInteraction.startPan;
  */
  
  DygraphInteraction.nonInteractiveModel_ = {
    mousedown: function mousedown(event, g, context) {
      context.initializeMouseDown(event, g, context);
    },
    mouseup: DygraphInteraction.maybeTreatMouseOpAsClick
  };
  
  // Default interaction model when using the range selector.
  DygraphInteraction.dragIsPanInteractionModel = {
    mousedown: function mousedown(event, g, context) {
      context.initializeMouseDown(event, g, context);
      DygraphInteraction.startPan(event, g, context);
    },
    mousemove: function mousemove(event, g, context) {
      if (context.isPanning) {
        DygraphInteraction.movePan(event, g, context);
      }
    },
    mouseup: function mouseup(event, g, context) {
      if (context.isPanning) {
        DygraphInteraction.endPan(event, g, context);
      }
    }
  };
  
  exports["default"] = DygraphInteraction;
  module.exports = exports["default"];