"use strict";

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

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

var _styled = _interopRequireDefault(require("@emotion/styled"));

var _d2 = require("d3");

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

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)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }

function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }

function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }

var Viewport =
/*#__PURE__*/
(0, _styled.default)('div', {
  target: "e1z139210"
})("position:relative;overflow:hidden;height:100%;width:100%;");
var Canvas =
/*#__PURE__*/
(0, _styled.default)('div', {
  target: "e1z139211"
})("position:absolute;width:", function (_ref) {
  var width = _ref.width;
  return width;
}, "px;height:", function (_ref2) {
  var height = _ref2.height;
  return height;
}, "px;transform-origin:top left;transform:", function (_ref3) {
  var transform = _ref3.transform;
  return "translate(".concat(transform.x, "px,").concat(transform.y, "px) scale(").concat(transform.k, ")");
}, ";");

function createZoom(t) {
  if (!t) {
    return _d2.zoomIdentity;
  }

  var _t$x = t.x,
      x = _t$x === void 0 ? 0 : _t$x,
      _t$y = t.y,
      y = _t$y === void 0 ? 0 : _t$y,
      _t$k = t.k,
      k = _t$k === void 0 ? 1 : _t$k;
  return _d2.zoomIdentity.translate(x, y).scale(k);
}

function computeFitZoom(_ref4) {
  var viewportWidth = _ref4.viewportWidth,
      viewportHeight = _ref4.viewportHeight,
      canvasHeight = _ref4.canvasHeight,
      canvasWidth = _ref4.canvasWidth,
      minZoomScale = _ref4.minZoomScale,
      maxZoomScale = _ref4.maxZoomScale,
      margin = _ref4.margin;
  var actualMargin = margin || Math.min(viewportWidth, viewportHeight) * 0.05; // 5% margin on the smallest viewport dimension

  var updatedScale = Math.max(minZoomScale, Math.min((viewportWidth - actualMargin) / canvasWidth, // The scale along the x axis
  (viewportHeight - actualMargin) / canvasHeight, // The scale along the y axis
  maxZoomScale));
  return createZoom({
    x: viewportWidth / 2 - canvasWidth * updatedScale / 2,
    y: viewportHeight / 2 - canvasHeight * updatedScale / 2,
    k: updatedScale
  });
}

var DEFAULT_PROPS = {
  minZoomScale: 0.1,
  maxZoomScale: 10,
  onZooming: function onZooming(isZooming) {},
  onZoomChange: function onZoomChange(transform) {},
  disable: false
};

var ZoomableCanvas = _react.default.memo(function (_ref5) {
  var children = _ref5.children,
      canvasHeight = _ref5.canvasHeight,
      canvasWidth = _ref5.canvasWidth,
      _ref5$minZoomScale = _ref5.minZoomScale,
      minZoomScale = _ref5$minZoomScale === void 0 ? DEFAULT_PROPS.minZoomScale : _ref5$minZoomScale,
      _ref5$maxZoomScale = _ref5.maxZoomScale,
      maxZoomScale = _ref5$maxZoomScale === void 0 ? DEFAULT_PROPS.maxZoomScale : _ref5$maxZoomScale,
      initialZoom = _ref5.initialZoom,
      _ref5$onZooming = _ref5.onZooming,
      onZooming = _ref5$onZooming === void 0 ? DEFAULT_PROPS.onZooming : _ref5$onZooming,
      _ref5$onZoomChange = _ref5.onZoomChange,
      onZoomChange = _ref5$onZoomChange === void 0 ? DEFAULT_PROPS.onZoomChange : _ref5$onZoomChange,
      _ref5$disable = _ref5.disable,
      disable = _ref5$disable === void 0 ? DEFAULT_PROPS.disable : _ref5$disable,
      otherProps = _objectWithoutProperties(_ref5, ["children", "canvasHeight", "canvasWidth", "minZoomScale", "maxZoomScale", "initialZoom", "onZooming", "onZoomChange", "disable"]);

  var viewportRef = (0, _react.useRef)();

  var _useState = (0, _react.useState)(createZoom(initialZoom)),
      _useState2 = _slicedToArray(_useState, 2),
      zoom = _useState2[0],
      setZoomState = _useState2[1]; // Create the zoom system only once.


  var zoomSystem = (0, _react.useMemo)(function () {
    return (0, _d2.zoom)().scaleExtent([minZoomScale, maxZoomScale]);
  }, [maxZoomScale, minZoomScale]); // Create the callback that can be used to properly change the zoom.

  var setZoom = (0, _react.useCallback)(function (zoom) {
    (0, _d2.select)(viewportRef.current).call(zoomSystem.transform, zoom);
  }, [viewportRef, zoomSystem]); // Fit to screen callback

  var fitToScreen = (0, _react.useCallback)(function () {
    var viewportClientRect = viewportRef.current.getBoundingClientRect();
    var fitZoom = computeFitZoom({
      viewportWidth: viewportClientRect.right - viewportClientRect.left,
      viewportHeight: viewportClientRect.bottom - viewportClientRect.top,
      canvasHeight: canvasHeight,
      canvasWidth: canvasWidth,
      minZoomScale: minZoomScale,
      maxZoomScale: maxZoomScale
    });
    setZoom(fitZoom);
  }, [canvasHeight, canvasWidth, minZoomScale, maxZoomScale, setZoom]); // Attach the zoom system

  (0, _react.useEffect)(function () {
    var viewportDomNode = viewportRef.current;

    if (disable) {
      (0, _d2.select)(viewportDomNode).on('.zoom', null);
    } else {
      (0, _d2.select)(viewportDomNode).call(zoomSystem.on('zoom', function () {
        var zoom = _d2.event.transform;
        var x = zoom.x,
            y = zoom.y,
            k = zoom.k;
        setZoomState(function (oldZoom) {
          if (x == oldZoom.x && y == oldZoom.y && k == oldZoom.k) {
            return oldZoom;
          }

          onZoomChange({
            x: x,
            y: y,
            k: k
          });
          return zoom;
        });
      }).on('start', function () {
        return onZooming(true);
      }).on('end', function () {
        return onZooming(false);
      })).on('dblclick.zoom', null);
      return function () {
        (0, _d2.select)(viewportDomNode).on('.zoom', null);
      };
    }
  }, [disable, minZoomScale, maxZoomScale, zoomSystem, onZoomChange, onZooming]);
  var initialZoomX = initialZoom && initialZoom.x;
  var initialZoomY = initialZoom && initialZoom.y;
  var initialZoomK = initialZoom && initialZoom.k;
  (0, _react.useEffect)(function () {
    if (!initialZoom) {
      fitToScreen();
    } else {
      setZoom(createZoom({
        x: initialZoomX,
        y: initialZoomY,
        k: initialZoomK
      }));
    }
  }, [fitToScreen, setZoom, initialZoomX, initialZoomY, initialZoomK]);
  return _react.default.createElement(Viewport, _extends({}, otherProps, {
    ref: viewportRef,
    onDoubleClick: disable ? null : fitToScreen
  }), _react.default.createElement(Canvas, {
    transform: zoom,
    height: canvasHeight,
    width: canvasWidth
  }, children));
});

ZoomableCanvas.displayName = 'ZoomableCanvas';
ZoomableCanvas.propTypes = {
  canvasHeight: _propTypes.default.number.isRequired,
  canvasWidth: _propTypes.default.number.isRequired,
  canvasOffset: _propTypes.default.oneOfType([_propTypes.default.oneOf([false]), _propTypes.default.shape({
    x: _propTypes.default.number,
    y: _propTypes.default.number
  })]),
  children: _propTypes.default.node.isRequired,
  disable: _propTypes.default.bool,
  minZoomScale: _propTypes.default.number,
  maxZoomScale: _propTypes.default.number,
  onZooming: _propTypes.default.func,
  initialZoom: _propTypes.default.oneOfType([_propTypes.default.oneOf([false]), _propTypes.default.shape({
    x: _propTypes.default.number,
    y: _propTypes.default.number,
    k: _propTypes.default.number
  })]),
  onZoomChange: _propTypes.default.func
};
var _default = ZoomableCanvas;
exports.default = _default;