function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }

function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }

function _getPrototypeOf(o) { _getPrototypeOf = Object.getPrototypeOf || function _getPrototypeOf(o) { return o.__proto__; }; return _getPrototypeOf(o); }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } _setPrototypeOf(subClass.prototype, superClass && superClass.prototype); if (superClass) _setPrototypeOf(subClass, superClass); }

function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }

// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import { CompositeLayer, log, experimental } from '@deck.gl/core';
import HexagonCellLayer from '../hexagon-cell-layer/hexagon-cell-layer';
var BinSorter = experimental.BinSorter,
    getQuantizeScale = experimental.getQuantizeScale,
    getLinearScale = experimental.getLinearScale,
    defaultColorRange = experimental.defaultColorRange;
import { pointToHexbin } from './hexagon-aggregator';

function nop() {}

var defaultProps = {
  // color
  colorDomain: null,
  colorRange: defaultColorRange,
  getColorValue: function getColorValue(points) {
    return points.length;
  },
  lowerPercentile: 0,
  upperPercentile: 100,
  onSetColorDomain: nop,
  // elevation
  elevationDomain: null,
  elevationRange: [0, 1000],
  getElevationValue: function getElevationValue(points) {
    return points.length;
  },
  elevationLowerPercentile: 0,
  elevationUpperPercentile: 100,
  elevationScale: {
    type: 'number',
    min: 0,
    value: 1
  },
  onSetElevationDomain: nop,
  radius: 1000,
  coverage: {
    type: 'number',
    min: 0,
    max: 1,
    value: 1
  },
  extruded: false,
  hexagonAggregator: pointToHexbin,
  getPosition: function getPosition(x) {
    return x.position;
  },
  fp64: false,
  // Optional settings for 'lighting' shader module
  lightSettings: {}
};

var HexagonLayer =
/*#__PURE__*/
function (_CompositeLayer) {
  _inherits(HexagonLayer, _CompositeLayer);

  function HexagonLayer(props) {
    _classCallCheck(this, HexagonLayer);

    if (!props.hexagonAggregator && !props.radius) {
      log.once(0, 'HexagonLayer: Default hexagonAggregator requires radius prop to be set, ' + 'Now using 1000 meter as default')();
      props.radius = defaultProps.radius;
    }

    if (Number.isFinite(props.upperPercentile) && (props.upperPercentile > 100 || props.upperPercentile < 0)) {
      log.once(0, 'HexagonLayer: upperPercentile should be between 0 and 100. ' + 'Assign to 100 by default')();
      props.upperPercentile = defaultProps.upperPercentile;
    }

    if (Number.isFinite(props.lowerPercentile) && (props.lowerPercentile > 100 || props.lowerPercentile < 0)) {
      log.once(0, 'HexagonLayer: lowerPercentile should be between 0 and 100. ' + 'Assign to 0 by default')();
      props.lowerPercentile = defaultProps.upperPercentile;
    }

    if (props.lowerPercentile >= props.upperPercentile) {
      log.once(0, 'HexagonLayer: lowerPercentile should not be bigger than ' + 'upperPercentile. Assign to 0 by default')();
      props.lowerPercentile = defaultProps.lowerPercentile;
    }

    return _possibleConstructorReturn(this, (HexagonLayer.__proto__ || Object.getPrototypeOf(HexagonLayer)).call(this, props));
  }

  _createClass(HexagonLayer, [{
    key: "initializeState",
    value: function initializeState() {
      this.state = {
        hexagons: [],
        hexagonVertices: null,
        sortedColorBins: null,
        sortedElevationBins: null,
        colorValueDomain: null,
        elevationValueDomain: null,
        colorScaleFunc: nop,
        elevationScaleFunc: nop,
        dimensionUpdaters: this.getDimensionUpdaters()
      };
    }
  }, {
    key: "updateState",
    value: function updateState(_ref) {
      var _this = this;

      var oldProps = _ref.oldProps,
          props = _ref.props,
          changeFlags = _ref.changeFlags;
      var dimensionChanges = this.getDimensionChanges(oldProps, props);

      if (changeFlags.dataChanged || this.needsReProjectPoints(oldProps, props)) {
        // project data into hexagons, and get sortedColorBins
        this.getHexagons();
      } else if (dimensionChanges) {
        dimensionChanges.forEach(function (f) {
          return typeof f === 'function' && f.apply(_this);
        });
      }
    }
  }, {
    key: "needsReProjectPoints",
    value: function needsReProjectPoints(oldProps, props) {
      return oldProps.radius !== props.radius || oldProps.hexagonAggregator !== props.hexagonAggregator;
    }
  }, {
    key: "getDimensionUpdaters",
    value: function getDimensionUpdaters() {
      // dimension updaters are sequential,
      // if the first one needs to be called, the 2nd and 3rd one will automatically
      // be called. e.g. if ColorValue needs to be updated, getColorValueDomain and getColorScale
      // will automatically be called
      return {
        getColor: [{
          id: 'value',
          triggers: ['getColorValue'],
          updater: this.getSortedColorBins
        }, {
          id: 'domain',
          triggers: ['lowerPercentile', 'upperPercentile'],
          updater: this.getColorValueDomain
        }, {
          id: 'scaleFunc',
          triggers: ['colorDomain', 'colorRange'],
          updater: this.getColorScale
        }],
        getElevation: [{
          id: 'value',
          triggers: ['getElevationValue'],
          updater: this.getSortedElevationBins
        }, {
          id: 'domain',
          triggers: ['elevationLowerPercentile', 'elevationUpperPercentile'],
          updater: this.getElevationValueDomain
        }, {
          id: 'scaleFunc',
          triggers: ['elevationDomain', 'elevationRange'],
          updater: this.getElevationScale
        }]
      };
    }
  }, {
    key: "getDimensionChanges",
    value: function getDimensionChanges(oldProps, props) {
      var dimensionUpdaters = this.state.dimensionUpdaters;
      var updaters = []; // get dimension to be updated

      for (var dimensionKey in dimensionUpdaters) {
        // return the first triggered updater for each dimension
        var needUpdate = dimensionUpdaters[dimensionKey].find(function (item) {
          return item.triggers.some(function (t) {
            return oldProps[t] !== props[t];
          });
        });

        if (needUpdate) {
          updaters.push(needUpdate.updater);
        }
      }

      return updaters.length ? updaters : null;
    }
  }, {
    key: "getHexagons",
    value: function getHexagons() {
      var hexagonAggregator = this.props.hexagonAggregator;
      var viewport = this.context.viewport;

      var _hexagonAggregator = hexagonAggregator(this.props, viewport),
          hexagons = _hexagonAggregator.hexagons,
          hexagonVertices = _hexagonAggregator.hexagonVertices;

      this.setState({
        hexagons: hexagons,
        hexagonVertices: hexagonVertices
      });
      this.getSortedBins();
    }
  }, {
    key: "getPickingInfo",
    value: function getPickingInfo(_ref2) {
      var info = _ref2.info;
      var _this$state = this.state,
          sortedColorBins = _this$state.sortedColorBins,
          sortedElevationBins = _this$state.sortedElevationBins;
      var isPicked = info.picked && info.index > -1;
      var object = null;

      if (isPicked) {
        var cell = this.state.hexagons[info.index];
        var colorValue = sortedColorBins.binMap[cell.index] && sortedColorBins.binMap[cell.index].value;
        var elevationValue = sortedElevationBins.binMap[cell.index] && sortedElevationBins.binMap[cell.index].value;
        object = Object.assign({
          colorValue: colorValue,
          elevationValue: elevationValue
        }, cell);
      } // add bin colorValue and elevationValue to info


      return Object.assign(info, {
        picked: Boolean(object),
        // override object with picked cell
        object: object
      });
    }
  }, {
    key: "getUpdateTriggers",
    value: function getUpdateTriggers() {
      var _this2 = this;

      var dimensionUpdaters = this.state.dimensionUpdaters; // merge all dimension triggers

      var updateTriggers = {};

      var _loop = function _loop(dimensionKey) {
        updateTriggers[dimensionKey] = {};
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
          for (var _iterator = dimensionUpdaters[dimensionKey][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
            var step = _step.value;
            step.triggers.forEach(function (prop) {
              updateTriggers[dimensionKey][prop] = _this2.props[prop];
            });
          }
        } catch (err) {
          _didIteratorError = true;
          _iteratorError = err;
        } finally {
          try {
            if (!_iteratorNormalCompletion && _iterator.return != null) {
              _iterator.return();
            }
          } finally {
            if (_didIteratorError) {
              throw _iteratorError;
            }
          }
        }
      };

      for (var dimensionKey in dimensionUpdaters) {
        _loop(dimensionKey);
      }

      return updateTriggers;
    }
  }, {
    key: "getValueDomain",
    value: function getValueDomain() {
      this.getColorValueDomain();
      this.getElevationValueDomain();
    }
  }, {
    key: "getSortedBins",
    value: function getSortedBins() {
      this.getSortedColorBins();
      this.getSortedElevationBins();
    }
  }, {
    key: "getSortedColorBins",
    value: function getSortedColorBins() {
      var getColorValue = this.props.getColorValue;
      var sortedColorBins = new BinSorter(this.state.hexagons || [], getColorValue);
      this.setState({
        sortedColorBins: sortedColorBins
      });
      this.getColorValueDomain();
    }
  }, {
    key: "getSortedElevationBins",
    value: function getSortedElevationBins() {
      var getElevationValue = this.props.getElevationValue;
      var sortedElevationBins = new BinSorter(this.state.hexagons || [], getElevationValue);
      this.setState({
        sortedElevationBins: sortedElevationBins
      });
      this.getElevationValueDomain();
    }
  }, {
    key: "getColorValueDomain",
    value: function getColorValueDomain() {
      var _this$props = this.props,
          lowerPercentile = _this$props.lowerPercentile,
          upperPercentile = _this$props.upperPercentile,
          onSetColorDomain = _this$props.onSetColorDomain;
      this.state.colorValueDomain = this.state.sortedColorBins.getValueRange([lowerPercentile, upperPercentile]);

      if (typeof onSetColorDomain === 'function') {
        onSetColorDomain(this.state.colorValueDomain);
      }

      this.getColorScale();
    }
  }, {
    key: "getElevationValueDomain",
    value: function getElevationValueDomain() {
      var _this$props2 = this.props,
          elevationLowerPercentile = _this$props2.elevationLowerPercentile,
          elevationUpperPercentile = _this$props2.elevationUpperPercentile,
          onSetElevationDomain = _this$props2.onSetElevationDomain;
      this.state.elevationValueDomain = this.state.sortedElevationBins.getValueRange([elevationLowerPercentile, elevationUpperPercentile]);

      if (typeof onSetElevationDomain === 'function') {
        onSetElevationDomain(this.state.elevationValueDomain);
      }

      this.getElevationScale();
    }
  }, {
    key: "getColorScale",
    value: function getColorScale() {
      var colorRange = this.props.colorRange;
      var colorDomain = this.props.colorDomain || this.state.colorValueDomain;
      this.state.colorScaleFunc = getQuantizeScale(colorDomain, colorRange);
    }
  }, {
    key: "getElevationScale",
    value: function getElevationScale() {
      var elevationRange = this.props.elevationRange;
      var elevationDomain = this.props.elevationDomain || this.state.elevationValueDomain;
      this.state.elevationScaleFunc = getLinearScale(elevationDomain, elevationRange);
    }
  }, {
    key: "_onGetSublayerColor",
    value: function _onGetSublayerColor(cell) {
      var _this$state2 = this.state,
          sortedColorBins = _this$state2.sortedColorBins,
          colorScaleFunc = _this$state2.colorScaleFunc,
          colorValueDomain = _this$state2.colorValueDomain;
      var cv = sortedColorBins.binMap[cell.index] && sortedColorBins.binMap[cell.index].value;
      var colorDomain = this.props.colorDomain || colorValueDomain;
      var isColorValueInDomain = cv >= colorDomain[0] && cv <= colorDomain[colorDomain.length - 1]; // if cell value is outside domain, set alpha to 0

      var color = isColorValueInDomain ? colorScaleFunc(cv) : [0, 0, 0, 0]; // add alpha to color if not defined in colorRange

      color[3] = Number.isFinite(color[3]) ? color[3] : 255;
      return color;
    }
  }, {
    key: "_onGetSublayerElevation",
    value: function _onGetSublayerElevation(cell) {
      var _this$state3 = this.state,
          sortedElevationBins = _this$state3.sortedElevationBins,
          elevationScaleFunc = _this$state3.elevationScaleFunc,
          elevationValueDomain = _this$state3.elevationValueDomain;
      var ev = sortedElevationBins.binMap[cell.index] && sortedElevationBins.binMap[cell.index].value;
      var elevationDomain = this.props.elevationDomain || elevationValueDomain;
      var isElevationValueInDomain = ev >= elevationDomain[0] && ev <= elevationDomain[elevationDomain.length - 1]; // if cell value is outside domain, set elevation to -1

      return isElevationValueInDomain ? elevationScaleFunc(ev) : -1;
    } // for subclassing, override this method to return
    // customized sub layer props

  }, {
    key: "getSubLayerProps",
    value: function getSubLayerProps() {
      var _this$props3 = this.props,
          radius = _this$props3.radius,
          elevationScale = _this$props3.elevationScale,
          extruded = _this$props3.extruded,
          coverage = _this$props3.coverage,
          lightSettings = _this$props3.lightSettings,
          fp64 = _this$props3.fp64,
          transitions = _this$props3.transitions; // return props to the sublayer constructor

      return _get(HexagonLayer.prototype.__proto__ || Object.getPrototypeOf(HexagonLayer.prototype), "getSubLayerProps", this).call(this, {
        id: 'hexagon-cell',
        data: this.state.hexagons,
        fp64: fp64,
        hexagonVertices: this.state.hexagonVertices,
        radius: radius,
        elevationScale: elevationScale,
        angle: Math.PI / 2,
        extruded: extruded,
        coverage: coverage,
        lightSettings: lightSettings,
        getColor: this._onGetSublayerColor.bind(this),
        getElevation: this._onGetSublayerElevation.bind(this),
        transitions: transitions && {
          getColor: transitions.getColorValue,
          getElevation: transitions.getElevationValue
        },
        updateTriggers: this.getUpdateTriggers()
      });
    } // for subclassing, override this method to return
    // customized sub layer class

  }, {
    key: "getSubLayerClass",
    value: function getSubLayerClass() {
      return HexagonCellLayer;
    }
  }, {
    key: "renderLayers",
    value: function renderLayers() {
      var SubLayerClass = this.getSubLayerClass();
      return new SubLayerClass(this.getSubLayerProps());
    }
  }]);

  return HexagonLayer;
}(CompositeLayer);

export { HexagonLayer as default };
HexagonLayer.layerName = 'HexagonLayer';
HexagonLayer.defaultProps = defaultProps;
//# sourceMappingURL=hexagon-layer.js.map