"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

var _typeof = require("@babel/runtime/helpers/typeof");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.gridDraggable = exports.deltaFn = void 0;

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));

var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));

var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));

var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));

var _react = _interopRequireDefault(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _types = require("./types");

var _draggable = require("./draggable");

var _debug = _interopRequireDefault(require("debug"));

var utils = _interopRequireWildcard(require("./utils"));

var _isFunction = _interopRequireDefault(require("lodash/isFunction"));

var _invariant = _interopRequireDefault(require("invariant"));

var _d3Selection = require("d3-selection");

var _excluded = ["disabled"];

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }

function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }

var log = (0, _debug["default"])('pie-lib:plot:grid-draggable');

var deltaFn = function deltaFn(scale, snap, val) {
  return function (delta) {
    var normalized = delta + scale(0);
    var inverted = scale.invert(normalized);
    var fixDecimalsArithmetic = snap(val + inverted).toFixed(4) * 1000 / 1000;
    return fixDecimalsArithmetic;
  };
};
/**
 * Creates a Component that is draggable, within a bounded grid.
 * @param {*} opts
 */


exports.deltaFn = deltaFn;

var gridDraggable = function gridDraggable(opts) {
  return function (Comp) {
    var _class;

    (0, _invariant["default"])(!!opts && (0, _isFunction["default"])(opts.fromDelta) && (0, _isFunction["default"])(opts.bounds) && (0, _isFunction["default"])(opts.anchorPoint), 'You must supply an object with: { anchorPoint: Function, fromDelta: Function, bounds: Function }');
    return _class = /*#__PURE__*/function (_React$Component) {
      (0, _inherits2["default"])(GridDraggable, _React$Component);

      var _super = _createSuper(GridDraggable);

      function GridDraggable() {
        var _this;

        (0, _classCallCheck2["default"])(this, GridDraggable);

        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
          args[_key] = arguments[_key];
        }

        _this = _super.call.apply(_super, [this].concat(args));
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "grid", function () {
          var graphProps = _this.props.graphProps;
          var scale = graphProps.scale,
              domain = graphProps.domain,
              range = graphProps.range;
          return {
            x: scale.x(domain.step) - scale.x(0),
            y: scale.y(range.step) - scale.y(0)
          };
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onStart", function (e) {
          var onDragStart = _this.props.onDragStart;

          if (document.activeElement) {
            document.activeElement.blur();
          }

          _this.setState({
            startX: e.clientX,
            startY: e.clientY
          });

          if (onDragStart) {
            onDragStart();
          }
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "position", function () {
          var _opts$anchorPoint = opts.anchorPoint(_this.props),
              x = _opts$anchorPoint.x,
              y = _opts$anchorPoint.y;

          var graphProps = _this.props.graphProps;
          var scale = graphProps.scale,
              snap = graphProps.snap;
          return {
            anchorPoint: {
              x: x,
              y: y
            },
            x: deltaFn(scale.x, snap.x, x),
            y: deltaFn(scale.y, snap.y, y)
          };
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "tiny", function (key, event) {
          var K = key.toUpperCase();
          var end = event["client".concat(K)];

          var start = _this.state["start".concat(K)];

          var delta = Math.abs(end - start);
          var out = delta < Math.abs(_this.grid()[key]) / 10;
          log('[tiny] key: ', key, 'delta: ', delta, 'out: ', out);
          return out;
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getScaledBounds", function () {
          var bounds = opts.bounds(_this.props, _this.props.graphProps);
          log('bounds: ', bounds);

          var grid = _this.grid();

          var scaled = {
            left: bounds.left / grid.interval * grid.x,
            right: bounds.right / grid.interval * grid.x,
            top: bounds.top / grid.interval * grid.y,
            bottom: bounds.bottom / grid.interval * grid.y
          };
          log('[getScaledBounds]: ', scaled);
          return scaled;
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getClientPoint", function (node, event) {
          if (!node || !event) {
            return null;
          }

          var svg = node.ownerSVGElement || node;

          if (svg && svg.createSVGPoint) {
            var point = svg.createSVGPoint(); // Check if it's a touch event and use the first touch point

            if (event.touches && event.touches.length > 0) {
              var touch = event.touches[0];
              point.x = touch.clientX;
              point.y = touch.clientY;
            } else {
              // Fall back to mouse event properties
              point.x = event.clientX;
              point.y = event.clientY;
            }

            if (node.getScreenCTM) {
              point = point.matrixTransform(node.getScreenCTM().inverse());
              return [point.x, point.y];
            } else {
              return null;
            }
          }

          var rect = node.getBoundingClientRect();

          if (rect) {
            return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
          } else {
            return null;
          }
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "skipDragOutsideOfBounds", function (dd, e, graphProps) {
          // Ignore drag movement outside of the domain and range.
          var rootNode = graphProps.getRootNode();

          var clientPoint = _this.getClientPoint(rootNode, e);

          if (clientPoint === null) {
            return true; // Indicate that the drag is outside of bounds
          }

          var _clientPoint = (0, _slicedToArray2["default"])(clientPoint, 2),
              rawX = _clientPoint[0],
              rawY = _clientPoint[1];

          var scale = graphProps.scale,
              domain = graphProps.domain,
              range = graphProps.range;
          var x = scale.x.invert(rawX);
          var y = scale.y.invert(rawY);
          var xOutside = dd.deltaX > 0 && x < domain.min || dd.deltaX < 0 && x > domain.max;
          var yOutside = dd.deltaY > 0 && y > range.max || dd.deltaY < 0 && y < range.min;
          return xOutside || yOutside;
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onDrag", function (e, dd) {
          var _this$props = _this.props,
              onDrag = _this$props.onDrag,
              graphProps = _this$props.graphProps;

          if (!onDrag) {
            return;
          }

          var bounds = _this.getScaledBounds();

          if (dd.deltaX < 0 && dd.deltaX < bounds.left) {
            return;
          }

          if (dd.deltaX > 0 && dd.deltaX > bounds.right) {
            return;
          }

          if (dd.deltaY < 0 && dd.deltaY < bounds.top) {
            return;
          }

          if (dd.deltaY > 0 && dd.deltaY > bounds.bottom) {
            return;
          }

          if (_this.skipDragOutsideOfBounds(dd, e, graphProps)) {
            return;
          }

          var dragArg = _this.applyDelta({
            x: dd.deltaX,
            y: dd.deltaY
          });

          if (dragArg !== undefined || dragArg !== null) {
            onDrag(dragArg);
          }
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "getDelta", function (point) {
          var pos = _this.position();

          var p = {
            x: pos.x(point.x),
            y: pos.y(point.y)
          };
          return utils.getDelta(pos.anchorPoint, p);
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "applyDelta", function (point) {
          var delta = _this.getDelta(point);

          log('[applyDelta] delta:', delta);
          return opts.fromDelta(_this.props, delta);
        });
        (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onStop", function (e, dd) {
          log('[onStop] dd:', dd);
          var _this$props2 = _this.props,
              onDragStop = _this$props2.onDragStop,
              onClick = _this$props2.onClick;

          if (onDragStop) {
            onDragStop();
          }

          log('[onStop] lastX/Y: ', dd.lastX, dd.lastY);

          var isClick = _this.tiny('x', e) && _this.tiny('y', e);

          if (isClick) {
            if (onClick) {
              log('call onClick');

              _this.setState({
                startX: null
              });

              var graphProps = _this.props.graphProps;
              var scale = graphProps.scale,
                  snap = graphProps.snap;

              var _clientPoint2 = (0, _d3Selection.clientPoint)(e.target, e),
                  _clientPoint3 = (0, _slicedToArray2["default"])(_clientPoint2, 2),
                  rawX = _clientPoint3[0],
                  rawY = _clientPoint3[1];

              var x = scale.x.invert(rawX);
              var y = scale.y.invert(rawY);
              x = snap.x(x);
              y = snap.y(y);
              onClick({
                x: x,
                y: y
              });
              return false;
            }
          }

          _this.setState({
            startX: null,
            startY: null
          }); // return false to prevent state updates in the underlying draggable - a move will have triggered an update already.


          return false;
        });
        return _this;
      }

      (0, _createClass2["default"])(GridDraggable, [{
        key: "render",
        value: function render() {
          var _this$props3 = this.props,
              disabled = _this$props3.disabled,
              rest = (0, _objectWithoutProperties2["default"])(_this$props3, _excluded);
          var grid = this.grid(); // prevent the text select icon from rendering.

          var onMouseDown = function onMouseDown(e) {
            return e.nativeEvent.preventDefault();
          };
          /**
           * TODO: This shouldnt be necessary, we should be able to use the r-d classnames.
           * But they aren't being unset. If we continue with this lib, we'll have to fix this.
           */


          var isDragging = this.state ? !!this.state.startX : false;
          return /*#__PURE__*/_react["default"].createElement(_draggable.DraggableCore, {
            disabled: disabled,
            onMouseDown: onMouseDown,
            onStart: this.onStart,
            onDrag: this.onDrag,
            onStop: this.onStop,
            axis: opts.axis || 'both',
            grid: [grid.x, grid.y]
          }, /*#__PURE__*/_react["default"].createElement(Comp, (0, _extends2["default"])({}, rest, {
            disabled: disabled,
            isDragging: isDragging
          })));
        }
      }]);
      return GridDraggable;
    }(_react["default"].Component), (0, _defineProperty2["default"])(_class, "propTypes", {
      disabled: _propTypes["default"].bool,
      onDragStart: _propTypes["default"].func,
      onDrag: _propTypes["default"].func,
      onDragStop: _propTypes["default"].func,
      onClick: _propTypes["default"].func,
      onMove: _propTypes["default"].func,
      graphProps: _types.GraphPropsType.isRequired
    }), _class;
  };
};

exports.gridDraggable = gridDraggable;
//# sourceMappingURL=grid-draggable.js.map