UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

925 lines (915 loc) 162 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Droppable = exports.Attribution = void 0; exports["default"] = MapContainerFactory; exports.isSplitSelector = void 0; var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _taggedTemplateLiteral2 = _interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral")); var _react = _interopRequireWildcard(require("react")); var _styledComponents = _interopRequireWildcard(require("styled-components")); var _reactMapGl = require("react-map-gl"); var _react2 = _interopRequireDefault(require("@deck.gl/react")); var _reselect = require("reselect"); var _core = require("@dnd-kit/core"); var _lodash = _interopRequireDefault(require("lodash.debounce")); var _mapPopover = _interopRequireDefault(require("./map/map-popover")); var _mapControl = _interopRequireDefault(require("./map/map-control")); var _styledComponents2 = require("./common/styled-components"); var _editor = _interopRequireDefault(require("./editor/editor")); var _layers = require("@kepler.gl/layers"); var _utils = require("@kepler.gl/utils"); var _styles = require("@kepler.gl/styles"); var _constants = require("@kepler.gl/constants"); var _mapViewStateContext = require("./map-view-state-context"); var _errorBoundary = _interopRequireDefault(require("./common/error-boundary")); var _localization = require("@kepler.gl/localization"); var _core2 = require("@deck.gl/core"); var _reducers = require("@kepler.gl/reducers"); var _loadingIndicator = _interopRequireDefault(require("./loading-indicator")); var _templateObject, _templateObject2; // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project // libraries // components // utils // default-settings // Contexts function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _callSuper(t, o, e) { return o = (0, _getPrototypeOf2["default"])(o), (0, _possibleConstructorReturn2["default"])(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], (0, _getPrototypeOf2["default"])(t).constructor) : o.apply(t, e)); } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } // Debounce the propagation of viewport change and mouse moves to redux store. // This is to avoid too many renders of other components when the map is // being panned/zoomed (leading to laggy basemap/deck syncing). var DEBOUNCE_VIEWPORT_PROPAGATE = 10; var DEBOUNCE_MOUSE_MOVE_PROPAGATE = 10; var MAP_STYLE = { container: { display: 'inline-block', position: 'relative', width: '100%', height: '100%' }, top: { position: 'absolute', top: 0, width: '100%', height: '100%', pointerEvents: 'none' } }; var LOCALE_CODES_ARRAY = Object.keys(_localization.LOCALE_CODES); var StyledMap = (0, _styledComponents["default"])(_styledComponents2.StyledMapContainer)(function (_ref) { var _ref$mixBlendMode = _ref.mixBlendMode, mixBlendMode = _ref$mixBlendMode === void 0 ? 'normal' : _ref$mixBlendMode, mapLibCssClass = _ref.mapLibCssClass; return "\n #default-deckgl-overlay {\n mix-blend-mode: ".concat(mixBlendMode, ";\n };\n *[").concat(mapLibCssClass, "-children] {\n position: absolute;\n }\n"); }); var MAPBOXGL_STYLE_UPDATE = 'style.load'; var MAPBOXGL_RENDER = 'render'; var nop = function nop() { return; }; var MapLibLogo = function MapLibLogo(_ref2) { var baseMapLibraryConfig = _ref2.baseMapLibraryConfig; return /*#__PURE__*/_react["default"].createElement("div", { className: "attrition-logo" }, "Basemap by:", /*#__PURE__*/_react["default"].createElement("a", { style: { marginLeft: '5px' }, className: "".concat(baseMapLibraryConfig.mapLibCssClass, "-ctrl-logo"), target: "_blank", rel: "noopener noreferrer", href: baseMapLibraryConfig.mapLibUrl, "aria-label": "".concat(baseMapLibraryConfig.mapLibName, " logo") })); }; var StyledDroppable = _styledComponents["default"].div(_templateObject || (_templateObject = (0, _taggedTemplateLiteral2["default"])(["\n background-color: ", ";\n width: 100%;\n height: 100%;\n position: absolute;\n pointer-events: none;\n z-index: 1;\n"])), function (props) { return props.isOver ? props.theme.dndOverBackgroundColor : 'none'; }); var isSplitSelector = exports.isSplitSelector = function isSplitSelector(props) { return props.visState.splitMaps && props.visState.splitMaps.length > 1; }; var Droppable = exports.Droppable = function Droppable(_ref3) { var containerId = _ref3.containerId; var _useDroppable = (0, _core.useDroppable)({ id: containerId, data: { type: _constants.DROPPABLE_MAP_CONTAINER_TYPE, index: containerId }, disabled: !containerId }), isOver = _useDroppable.isOver, setNodeRef = _useDroppable.setNodeRef; return /*#__PURE__*/_react["default"].createElement(StyledDroppable, { ref: setNodeRef, isOver: isOver }); }; var StyledDatasetAttributionsContainer = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = (0, _taggedTemplateLiteral2["default"])(["\n max-width: ", ";\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n color: ", ";\n margin-right: 2px;\n margin-bottom: 1px;\n line-height: ", ";\n\n &:hover {\n white-space: inherit;\n }\n"])), function (props) { return props.isPalm ? '200px' : '300px'; }, function (props) { return props.theme.labelColor; }, function (props) { return props.isPalm ? '1em' : '1.4em'; }); var DatasetAttributions = function DatasetAttributions(_ref4) { var datasetAttributions = _ref4.datasetAttributions, isPalm = _ref4.isPalm; return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, datasetAttributions !== null && datasetAttributions !== void 0 && datasetAttributions.length ? /*#__PURE__*/_react["default"].createElement(StyledDatasetAttributionsContainer, { isPalm: isPalm }, datasetAttributions.map(function (ds, idx) { return /*#__PURE__*/_react["default"].createElement("a", (0, _extends2["default"])({}, ds.url ? { href: ds.url } : null, { target: "_blank", rel: "noopener noreferrer", key: "".concat(ds.title, "_").concat(idx) }), ds.title, idx !== datasetAttributions.length - 1 ? ', ' : null); })) : null); }; var Attribution = exports.Attribution = function Attribution(_ref5) { var _ref5$showBaseMapLibL = _ref5.showBaseMapLibLogo, showBaseMapLibLogo = _ref5$showBaseMapLibL === void 0 ? true : _ref5$showBaseMapLibL, _ref5$showOsmBasemapA = _ref5.showOsmBasemapAttribution, showOsmBasemapAttribution = _ref5$showOsmBasemapA === void 0 ? false : _ref5$showOsmBasemapA, datasetAttributions = _ref5.datasetAttributions, baseMapLibraryConfig = _ref5.baseMapLibraryConfig; var isPalm = (0, _utils.hasMobileWidth)(_styles.breakPointValues); var memoizedComponents = (0, _react.useMemo)(function () { if (!showBaseMapLibLogo) { return /*#__PURE__*/_react["default"].createElement(_styledComponents2.StyledAttrbution, { mapLibCssClass: baseMapLibraryConfig.mapLibCssClass, mapLibAttributionCssClass: baseMapLibraryConfig.mapLibAttributionCssClass }, /*#__PURE__*/_react["default"].createElement(_styledComponents2.EndHorizontalFlexbox, null, /*#__PURE__*/_react["default"].createElement(DatasetAttributions, { datasetAttributions: datasetAttributions, isPalm: isPalm }), showOsmBasemapAttribution ? /*#__PURE__*/_react["default"].createElement("div", { className: "attrition-link" }, datasetAttributions !== null && datasetAttributions !== void 0 && datasetAttributions.length ? /*#__PURE__*/_react["default"].createElement("span", { className: "pipe-separator" }, "|") : null, /*#__PURE__*/_react["default"].createElement("a", { href: "http://www.openstreetmap.org/copyright", target: "_blank", rel: "noopener noreferrer" }, "\xA9 OpenStreetMap")) : null)); } return /*#__PURE__*/_react["default"].createElement(_styledComponents2.StyledAttrbution, { mapLibCssClass: baseMapLibraryConfig.mapLibCssClass, mapLibAttributionCssClass: baseMapLibraryConfig.mapLibAttributionCssClass }, /*#__PURE__*/_react["default"].createElement(_styledComponents2.EndHorizontalFlexbox, null, /*#__PURE__*/_react["default"].createElement(DatasetAttributions, { datasetAttributions: datasetAttributions, isPalm: isPalm }), /*#__PURE__*/_react["default"].createElement("div", { className: "attrition-link" }, datasetAttributions !== null && datasetAttributions !== void 0 && datasetAttributions.length ? /*#__PURE__*/_react["default"].createElement("span", { className: "pipe-separator" }, "|") : null, isPalm ? /*#__PURE__*/_react["default"].createElement(MapLibLogo, { baseMapLibraryConfig: baseMapLibraryConfig }) : null, /*#__PURE__*/_react["default"].createElement("a", { href: "https://kepler.gl/policy/", target: "_blank", rel: "noopener noreferrer" }, "\xA9 kepler.gl |", ' '), !isPalm ? /*#__PURE__*/_react["default"].createElement(MapLibLogo, { baseMapLibraryConfig: baseMapLibraryConfig }) : null))); }, [showBaseMapLibLogo, showOsmBasemapAttribution, datasetAttributions, isPalm, baseMapLibraryConfig]); return memoizedComponents; }; MapContainerFactory.deps = [_mapPopover["default"], _mapControl["default"], _editor["default"]]; function MapContainerFactory(MapPopover, MapControl, Editor) { var MapContainer = /*#__PURE__*/function (_Component) { function MapContainer(_props) { var _this; (0, _classCallCheck2["default"])(this, MapContainer); _this = _callSuper(this, MapContainer, [_props]); (0, _defineProperty2["default"])(_this, "displayName", 'MapContainer'); (0, _defineProperty2["default"])(_this, "state", { // Determines whether attribution should be visible based the result of loading the map style showBaseMapAttribution: true }); (0, _defineProperty2["default"])(_this, "_deck", null); (0, _defineProperty2["default"])(_this, "_map", null); (0, _defineProperty2["default"])(_this, "_ref", /*#__PURE__*/(0, _react.createRef)()); (0, _defineProperty2["default"])(_this, "_deckGLErrorsElapsed", {}); (0, _defineProperty2["default"])(_this, "previousLayers", { // [layers.id]: mapboxLayerConfig }); (0, _defineProperty2["default"])(_this, "_handleResize", function (dimensions) { var _this$props = _this.props, primary = _this$props.primary, index = _this$props.index; if (primary) { var mapStateActions = _this.props.mapStateActions; if (dimensions && dimensions.width > 0 && dimensions.height > 0) { mapStateActions.updateMap(dimensions, index); } } }); (0, _defineProperty2["default"])(_this, "layersSelector", function (props) { return props.visState.layers; }); (0, _defineProperty2["default"])(_this, "layerDataSelector", function (props) { return props.visState.layerData; }); (0, _defineProperty2["default"])(_this, "splitMapSelector", function (props) { return props.visState.splitMaps; }); (0, _defineProperty2["default"])(_this, "splitMapIndexSelector", function (props) { return props.index; }); (0, _defineProperty2["default"])(_this, "mapLayersSelector", (0, _reselect.createSelector)(_this.splitMapSelector, _this.splitMapIndexSelector, _utils.getMapLayersFromSplitMaps)); (0, _defineProperty2["default"])(_this, "layerOrderSelector", function (props) { return props.visState.layerOrder; }); (0, _defineProperty2["default"])(_this, "layersToRenderSelector", (0, _reselect.createSelector)(_this.layersSelector, _this.layerDataSelector, _this.mapLayersSelector, _reducers.prepareLayersToRender)); (0, _defineProperty2["default"])(_this, "layersForDeckSelector", (0, _reselect.createSelector)(_this.layersSelector, _this.layerDataSelector, _reducers.prepareLayersForDeck)); (0, _defineProperty2["default"])(_this, "filtersSelector", function (props) { return props.visState.filters; }); (0, _defineProperty2["default"])(_this, "polygonFiltersSelector", (0, _reselect.createSelector)(_this.filtersSelector, function (filters) { return filters.filter(function (f) { return f.type === _constants.FILTER_TYPES.polygon && f.enabled !== false; }); })); (0, _defineProperty2["default"])(_this, "featuresSelector", function (props) { return props.visState.editor.features; }); (0, _defineProperty2["default"])(_this, "selectedFeatureSelector", function (props) { return props.visState.editor.selectedFeature; }); (0, _defineProperty2["default"])(_this, "featureCollectionSelector", (0, _reselect.createSelector)(_this.polygonFiltersSelector, _this.featuresSelector, function (polygonFilters, features) { return { type: 'FeatureCollection', features: features.concat(polygonFilters.map(function (f) { return f.value; })) }; })); // @ts-ignore - No overload matches this call (0, _defineProperty2["default"])(_this, "selectedPolygonIndexSelector", (0, _reselect.createSelector)(_this.featureCollectionSelector, _this.selectedFeatureSelector, function (collection, selectedFeature) { return collection.features.findIndex(function (f) { return f.id === (selectedFeature === null || selectedFeature === void 0 ? void 0 : selectedFeature.id); }); })); (0, _defineProperty2["default"])(_this, "selectedFeatureIndexArraySelector", (0, _reselect.createSelector)(function (value) { return value; }, function (value) { return value < 0 ? [] : [value]; })); (0, _defineProperty2["default"])(_this, "generateMapboxLayerMethodSelector", function (props) { var _props$generateMapbox; return (_props$generateMapbox = props.generateMapboxLayers) !== null && _props$generateMapbox !== void 0 ? _props$generateMapbox : _layers.generateMapboxLayers; }); (0, _defineProperty2["default"])(_this, "mapboxLayersSelector", (0, _reselect.createSelector)(_this.layersSelector, _this.layerDataSelector, _this.layerOrderSelector, _this.layersToRenderSelector, _this.generateMapboxLayerMethodSelector, function (layer, layerData, layerOrder, layersToRender, generateMapboxLayerMethod) { return generateMapboxLayerMethod(layer, layerData, layerOrder, layersToRender); })); // merge in a background-color style if the basemap choice is NO_MAP_ID // used by <StyledMap> inline style prop (0, _defineProperty2["default"])(_this, "mapStyleTypeSelector", function (props) { return props.mapStyle.styleType; }); (0, _defineProperty2["default"])(_this, "mapStyleBackgroundColorSelector", function (props) { return props.mapStyle.backgroundColor; }); (0, _defineProperty2["default"])(_this, "styleSelector", (0, _reselect.createSelector)(_this.mapStyleTypeSelector, _this.mapStyleBackgroundColorSelector, function (styleType, backgroundColor) { return _objectSpread(_objectSpread({}, MAP_STYLE.container), styleType === _constants.NO_MAP_ID ? { backgroundColor: (0, _utils.rgbToHex)(backgroundColor) } : {}); })); /* component private functions */ (0, _defineProperty2["default"])(_this, "_onCloseMapPopover", function () { _this.props.visStateActions.onLayerClick(null); }); (0, _defineProperty2["default"])(_this, "_onLayerHover", function (_idx, info) { _this.props.visStateActions.onLayerHover(info, _this.props.index); }); (0, _defineProperty2["default"])(_this, "_onLayerSetDomain", function (idx, value) { _this.props.visStateActions.layerConfigChange(_this.props.visState.layers[idx], { colorDomain: value.domain, aggregatedBins: value.aggregatedBins }); }); (0, _defineProperty2["default"])(_this, "_onLayerFilteredItemsChange", function (idx, event) { _this.props.visStateActions.layerFilteredItemsChange(_this.props.visState.layers[idx], event); }); (0, _defineProperty2["default"])(_this, "_handleMapToggleLayer", function (layerId) { var _this$props2 = _this.props, _this$props2$index = _this$props2.index, mapIndex = _this$props2$index === void 0 ? 0 : _this$props2$index, visStateActions = _this$props2.visStateActions; visStateActions.toggleLayerForMap(mapIndex, layerId); }); (0, _defineProperty2["default"])(_this, "_onMapboxStyleUpdate", function (update) { // force refresh mapboxgl layers _this.previousLayers = {}; _this._updateMapboxLayers(); if (update && update.style) { // No attributions are needed if the style doesn't reference Mapbox sources _this.setState({ showBaseMapAttribution: (0, _utils.isStyleUsingMapboxTiles)(update.style) || !(0, _utils.isStyleUsingOpenStreetMapTiles)(update.style) }); } if (typeof _this.props.onMapStyleLoaded === 'function') { _this.props.onMapStyleLoaded(_this._map); } }); (0, _defineProperty2["default"])(_this, "_setMapRef", function (mapRef) { // Handle change of the map library if (_this._map && mapRef) { var map = mapRef.getMap(); if (map && _this._map !== map) { var _this$_map, _this$_map2; (_this$_map = _this._map) === null || _this$_map === void 0 || _this$_map.off(MAPBOXGL_STYLE_UPDATE, nop); (_this$_map2 = _this._map) === null || _this$_map2 === void 0 || _this$_map2.off(MAPBOXGL_RENDER, nop); _this._map = null; } } if (!_this._map && mapRef) { _this._map = mapRef.getMap(); // i noticed in certain context we don't access the actual map element if (!_this._map) { return; } // bind mapboxgl event listener _this._map.on(MAPBOXGL_STYLE_UPDATE, _this._onMapboxStyleUpdate); _this._map.on(MAPBOXGL_RENDER, function () { if (typeof _this.props.onMapRender === 'function') { _this.props.onMapRender(_this._map); } }); } if (_this.props.getMapboxRef) { // The parent component can gain access to our MapboxGlMap by // providing this callback. Note that 'mapbox' will be null when the // ref is unset (e.g. when a split map is closed). _this.props.getMapboxRef(mapRef, _this.props.index); } }); (0, _defineProperty2["default"])(_this, "_onBeforeRender", function (_ref6) { var gl = _ref6.gl; (0, _utils.setLayerBlending)(gl, _this.props.visState.layerBlending); }); (0, _defineProperty2["default"])(_this, "_onDeckError", function (error, layer) { var errorMessage = (error === null || error === void 0 ? void 0 : error.message) || 'unknown-error'; var layerMessage = layer !== null && layer !== void 0 && layer.id ? " in ".concat(layer.id, " layer") : ''; var errorMessageFull = errorMessage === 'WebGL context is lost' ? 'Your GPU was disconnected. This can happen if your computer goes to sleep. It can also occur for other reasons, such as if you are running too many GPU applications.' : "An error in deck.gl: ".concat(errorMessage).concat(layerMessage, "."); // Throttle error notifications, as React doesn't like too many state changes from here. var lastShown = _this._deckGLErrorsElapsed[errorMessageFull]; if (!lastShown || lastShown < Date.now() - _constants.THROTTLE_NOTIFICATION_TIME) { _this._deckGLErrorsElapsed[errorMessageFull] = Date.now(); // Mark layer as invalid var extraLayerMessage = ''; var visStateActions = _this.props.visStateActions; if (layer) { var _topMostLayer$props; var topMostLayer = layer; while (topMostLayer.parent) { topMostLayer = topMostLayer.parent; } if ((_topMostLayer$props = topMostLayer.props) !== null && _topMostLayer$props !== void 0 && _topMostLayer$props.id) { visStateActions.layerSetIsValid(topMostLayer, false); extraLayerMessage = 'The layer has been disabled and highlighted.'; } } // Create new error notification or update existing one with same id. // Update is required to preserve the order of notifications as they probably are going to "jump" based on order of errors. var uiStateActions = _this.props.uiStateActions; uiStateActions.addNotification((0, _utils.errorNotification)({ message: "".concat(errorMessageFull, " ").concat(extraLayerMessage), id: errorMessageFull // treat the error message as id })); } }); (0, _defineProperty2["default"])(_this, "_onViewportChangePropagateDebounced", (0, _lodash["default"])(function () { var _this$context; var viewState = (_this$context = _this.context) === null || _this$context === void 0 ? void 0 : _this$context.getInternalViewState(_this.props.index); (0, _utils.onViewPortChange)(viewState, _this.props.mapStateActions.updateMap, _this.props.onViewStateChange, _this.props.primary, _this.props.index); }, DEBOUNCE_VIEWPORT_PROPAGATE)); (0, _defineProperty2["default"])(_this, "_onViewportChange", function (viewport) { var viewState = viewport.viewState; if (_this.props.isExport) { // Image export map shouldn't be interactive (otherwise this callback can // lead to inadvertent changes to the state of the main map) return; } var setInternalViewState = _this.context.setInternalViewState; setInternalViewState(viewState, _this.props.index); _this._onViewportChangePropagateDebounced(); }); (0, _defineProperty2["default"])(_this, "_onLayerHoverDebounced", (0, _lodash["default"])(function (data, index) { _this.props.visStateActions.onLayerHover(data, index); }, DEBOUNCE_MOUSE_MOVE_PROPAGATE)); (0, _defineProperty2["default"])(_this, "_onMouseMoveDebounced", (0, _lodash["default"])(function (event, viewport) { _this.props.visStateActions.onMouseMove((0, _utils.normalizeEvent)(event, viewport)); }, DEBOUNCE_MOUSE_MOVE_PROPAGATE)); (0, _defineProperty2["default"])(_this, "_toggleMapControl", function (panelId) { var _this$props3 = _this.props, index = _this$props3.index, uiStateActions = _this$props3.uiStateActions; uiStateActions.toggleMapControl(panelId, Number(index)); }); return _this; } (0, _inherits2["default"])(MapContainer, _Component); return (0, _createClass2["default"])(MapContainer, [{ key: "componentDidMount", value: function componentDidMount() { if (!this._ref.current) { return; } (0, _utils.observeDimensions)(this._ref.current, this._handleResize); } }, { key: "componentWillUnmount", value: function componentWillUnmount() { // unbind mapboxgl event listener if (this._map) { var _this$_map3, _this$_map4; (_this$_map3 = this._map) === null || _this$_map3 === void 0 || _this$_map3.off(MAPBOXGL_STYLE_UPDATE, nop); (_this$_map4 = this._map) === null || _this$_map4 === void 0 || _this$_map4.off(MAPBOXGL_RENDER, nop); } if (!this._ref.current) { return; } (0, _utils.unobserveDimensions)(this._ref.current); } }, { key: "_onDeckInitialized", value: function _onDeckInitialized(gl) { if (this.props.onDeckInitialized) { this.props.onDeckInitialized(this._deck, gl); } } /** * 1) Allow effects only for the first view. * 2) Prevent effect:preRender call without valid generated viewports. * @param viewIndex View index. * @returns Returns true if effects can be used. */ }, { key: "_isOKToRenderEffects", value: function _isOKToRenderEffects(viewIndex) { var _this$_deck; return !viewIndex && Boolean((_this$_deck = this._deck) === null || _this$_deck === void 0 || (_this$_deck = _this$_deck.viewManager) === null || _this$_deck === void 0 || (_this$_deck = _this$_deck._viewports) === null || _this$_deck === void 0 ? void 0 : _this$_deck.length); } }, { key: "_renderMapPopover", value: /* component render functions */ /* eslint-disable complexity */ function _renderMapPopover() { var _this$props$visState$; // this check is for limiting the display of the `<MapPopover>` to the `<MapContainer>` the user is interacting with // the DeckGL onHover event handler adds a `mapIndex` property which is available in the `hoverInfo` object of `visState` if (this.props.index !== ((_this$props$visState$ = this.props.visState.hoverInfo) === null || _this$props$visState$ === void 0 ? void 0 : _this$props$visState$.mapIndex)) { return null; } // TODO: move this into reducer so it can be tested var _this$props4 = this.props, mapState = _this$props4.mapState, _this$props4$visState = _this$props4.visState, hoverInfo = _this$props4$visState.hoverInfo, clicked = _this$props4$visState.clicked, datasets = _this$props4$visState.datasets, interactionConfig = _this$props4$visState.interactionConfig, animationConfig = _this$props4$visState.animationConfig, layers = _this$props4$visState.layers, _this$props4$visState2 = _this$props4$visState.mousePos, mousePosition = _this$props4$visState2.mousePosition, coordinate = _this$props4$visState2.coordinate, pinned = _this$props4$visState2.pinned; var layersToRender = this.layersToRenderSelector(this.props); if (!mousePosition || !interactionConfig.tooltip) { return null; } var layerHoverProp = (0, _reducers.getLayerHoverProp)({ animationConfig: animationConfig, interactionConfig: interactionConfig, hoverInfo: hoverInfo, layers: layers, layersToRender: layersToRender, datasets: datasets }); var compareMode = interactionConfig.tooltip.config ? interactionConfig.tooltip.config.compareMode : false; var pinnedPosition = { x: 0, y: 0 }; var layerPinnedProp = null; if (pinned || clicked) { // project lnglat to screen so that tooltip follows the object on zoom var viewport = (0, _utils.getViewportFromMapState)(mapState); var lngLat = clicked ? clicked.coordinate : pinned.coordinate; pinnedPosition = this._getHoverXY(viewport, lngLat); layerPinnedProp = (0, _reducers.getLayerHoverProp)({ animationConfig: animationConfig, interactionConfig: interactionConfig, hoverInfo: clicked, layers: layers, layersToRender: layersToRender, datasets: datasets }); if (layerHoverProp && layerPinnedProp) { layerHoverProp.primaryData = layerPinnedProp.data; layerHoverProp.compareType = interactionConfig.tooltip.config.compareType; } } var commonProp = { onClose: this._onCloseMapPopover, zoom: mapState.zoom, container: this._deck ? this._deck.canvas : undefined }; return /*#__PURE__*/_react["default"].createElement(_errorBoundary["default"], null, layerPinnedProp && /*#__PURE__*/_react["default"].createElement(MapPopover, (0, _extends2["default"])({}, pinnedPosition, commonProp, { layerHoverProp: layerPinnedProp, coordinate: interactionConfig.coordinate.enabled && (pinned || {}).coordinate, frozen: true, isBase: compareMode, onSetFeatures: this.props.visStateActions.setFeatures, setSelectedFeature: this.props.visStateActions.setSelectedFeature // @ts-ignore Argument of type 'Readonly<MapContainerProps>' is not assignable to parameter of type 'never' , featureCollection: this.featureCollectionSelector(this.props) })), layerHoverProp && (!layerPinnedProp || compareMode) && /*#__PURE__*/_react["default"].createElement(MapPopover, (0, _extends2["default"])({ x: mousePosition[0], y: mousePosition[1] }, commonProp, { layerHoverProp: layerHoverProp, frozen: false, coordinate: interactionConfig.coordinate.enabled && coordinate, onSetFeatures: this.props.visStateActions.setFeatures, setSelectedFeature: this.props.visStateActions.setSelectedFeature // @ts-ignore Argument of type 'Readonly<MapContainerProps>' is not assignable to parameter of type 'never' , featureCollection: this.featureCollectionSelector(this.props) }))); } /* eslint-enable complexity */ }, { key: "_getHoverXY", value: function _getHoverXY(viewport, lngLat) { var screenCoord = !viewport || !lngLat ? null : viewport.project(lngLat); return screenCoord && { x: screenCoord[0], y: screenCoord[1] }; } }, { key: "_renderDeckOverlay", value: function _renderDeckOverlay(layersForDeck) { var _this$context2, _this2 = this; var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { primaryMap: false }; var _this$props5 = this.props, mapStyle = _this$props5.mapStyle, visState = _this$props5.visState, mapState = _this$props5.mapState, visStateActions = _this$props5.visStateActions, mapboxApiAccessToken = _this$props5.mapboxApiAccessToken, mapboxApiUrl = _this$props5.mapboxApiUrl, deckGlProps = _this$props5.deckGlProps, index = _this$props5.index, mapControls = _this$props5.mapControls, deckRenderCallbacks = _this$props5.deckRenderCallbacks, theme = _this$props5.theme, generateDeckGLLayers = _this$props5.generateDeckGLLayers, onMouseMove = _this$props5.onMouseMove; var hoverInfo = visState.hoverInfo, editor = visState.editor; var primaryMap = options.primaryMap, isInteractive = options.isInteractive, children = options.children; // disable double click zoom when editor is in any draw mode var mapDraw = mapControls.mapDraw; var _ref7 = mapDraw || {}, _ref7$active = _ref7.active, editorMenuActive = _ref7$active === void 0 ? false : _ref7$active; var isEditorDrawingMode = _layers.EditorLayerUtils.isDrawingActive(editorMenuActive, editor.mode); var internalViewState = (_this$context2 = this.context) === null || _this$context2 === void 0 ? void 0 : _this$context2.getInternalViewState(index); var internalMapState = _objectSpread(_objectSpread({}, mapState), internalViewState); var viewport = (0, _utils.getViewportFromMapState)(internalMapState); var editorFeatureSelectedIndex = this.selectedPolygonIndexSelector(this.props); var setFeatures = visStateActions.setFeatures, onLayerClick = visStateActions.onLayerClick, setSelectedFeature = visStateActions.setSelectedFeature; var generateDeckGLLayersMethod = generateDeckGLLayers !== null && generateDeckGLLayers !== void 0 ? generateDeckGLLayers : _reducers.computeDeckLayers; var deckGlLayers = generateDeckGLLayersMethod({ visState: visState, mapState: internalMapState, mapStyle: mapStyle }, { mapIndex: index, primaryMap: primaryMap, mapboxApiAccessToken: mapboxApiAccessToken, mapboxApiUrl: mapboxApiUrl, layersForDeck: layersForDeck, editorInfo: primaryMap ? { editor: editor, editorMenuActive: editorMenuActive, onSetFeatures: setFeatures, setSelectedFeature: setSelectedFeature, // @ts-ignore Argument of type 'Readonly<MapContainerProps>' is not assignable to parameter of type 'never' featureCollection: this.featureCollectionSelector(this.props), selectedFeatureIndexes: this.selectedFeatureIndexArraySelector( // @ts-ignore Argument of type 'unknown' is not assignable to parameter of type 'number'. editorFeatureSelectedIndex), viewport: viewport } : undefined }, { onLayerHover: this._onLayerHover, onSetLayerDomain: this._onLayerSetDomain, onFilteredItemsChange: this._onLayerFilteredItemsChange }, deckGlProps); var extraDeckParams = {}; if (primaryMap) { extraDeckParams.getTooltip = function (info) { return _layers.EditorLayerUtils.getTooltip(info, { editorMenuActive: editorMenuActive, editor: editor, theme: theme }); }; extraDeckParams.getCursor = function (_ref8) { var isDragging = _ref8.isDragging; var editorCursor = _layers.EditorLayerUtils.getCursor({ editorMenuActive: editorMenuActive, editor: editor, hoverInfo: hoverInfo }); if (editorCursor) return editorCursor; if (isDragging) return 'grabbing'; if (hoverInfo !== null && hoverInfo !== void 0 && hoverInfo.layer) return 'pointer'; return 'grab'; }; } var effects = this._isOKToRenderEffects(index) ? (0, _utils.computeDeckEffects)({ visState: visState, mapState: mapState }) : []; var views = deckGlProps !== null && deckGlProps !== void 0 && deckGlProps.views ? deckGlProps === null || deckGlProps === void 0 ? void 0 : deckGlProps.views() : new _core2.MapView({ legacyMeterSizes: true }); var allDeckGlProps = _objectSpread(_objectSpread({}, deckGlProps), {}, { pickingRadius: _constants.DEFAULT_PICKING_RADIUS, views: views, layers: deckGlLayers, effects: effects }); if (typeof (deckRenderCallbacks === null || deckRenderCallbacks === void 0 ? void 0 : deckRenderCallbacks.onDeckRender) === 'function') { allDeckGlProps = deckRenderCallbacks.onDeckRender(allDeckGlProps); if (!allDeckGlProps) { // if onDeckRender returns null, do not render deck.gl return null; } } return /*#__PURE__*/_react["default"].createElement("div", isInteractive ? { onMouseMove: primaryMap ? function (event) { onMouseMove === null || onMouseMove === void 0 || onMouseMove(event); _this2._onMouseMoveDebounced(event, viewport); } : undefined } : { style: { pointerEvents: 'none' } }, /*#__PURE__*/_react["default"].createElement(_react2["default"], (0, _extends2["default"])({ id: "default-deckgl-overlay", onLoad: function onLoad() { if (typeof (deckRenderCallbacks === null || deckRenderCallbacks === void 0 ? void 0 : deckRenderCallbacks.onDeckLoad) === 'function') { deckRenderCallbacks.onDeckLoad(); } } }, allDeckGlProps, { controller: isInteractive ? { doubleClickZoom: !isEditorDrawingMode, dragRotate: this.props.mapState.dragRotate } : false, initialViewState: internalViewState, onBeforeRender: this._onBeforeRender, onViewStateChange: isInteractive ? this._onViewportChange : undefined }, extraDeckParams, { onHover: isInteractive ? function (data) { var res = _layers.EditorLayerUtils.onHover(data, { editorMenuActive: editorMenuActive, editor: editor, hoverInfo: hoverInfo }); if (res) return; _this2._onLayerHoverDebounced(data, index); } : null, onClick: function onClick(data, event) { // @ts-ignore (0, _utils.normalizeEvent)(event.srcEvent, viewport); var res = _layers.EditorLayerUtils.onClick(data, event, { editorMenuActive: editorMenuActive, editor: editor, onLayerClick: onLayerClick, setSelectedFeature: setSelectedFeature, mapIndex: index }); if (res) return; visStateActions.onLayerClick(data); }, onError: this._onDeckError, ref: function ref(comp) { // @ts-ignore if (comp && comp.deck && !_this2._deck) { // @ts-ignore _this2._deck = comp.deck; } }, onWebGLInitialized: function onWebGLInitialized(gl) { return _this2._onDeckInitialized(gl); }, onAfterRender: function onAfterRender() { if (typeof (deckRenderCallbacks === null || deckRenderCallbacks === void 0 ? void 0 : deckRenderCallbacks.onDeckAfterRender) === 'function') { deckRenderCallbacks.onDeckAfterRender(allDeckGlProps); } } }), children)); } }, { key: "_updateMapboxLayers", value: function _updateMapboxLayers() { var mapboxLayers = this.mapboxLayersSelector(this.props); if (!Object.keys(mapboxLayers).length && !Object.keys(this.previousLayers).length) { return; } (0, _layers.updateMapboxLayers)(this._map, mapboxLayers, this.previousLayers); this.previousLayers = mapboxLayers; } }, { key: "_renderMapboxOverlays", value: function _renderMapboxOverlays() { if (this._map && this._map.isStyleLoaded()) { this._updateMapboxLayers(); } } }, { key: "_renderMap", value: /* eslint-disable complexity */ function _renderMap() { var _mapStyle$mapStyles, _getApplicationConfig, _this$context3, _mapStyle$bottomMapSt; var _this$props6 = this.props, visState = _this$props6.visState, mapState = _this$props6.mapState, mapStyle = _this$props6.mapStyle, mapStateActions = _this$props6.mapStateActions, _this$props6$MapCompo = _this$props6.MapComponent, MapComponent = _this$props6$MapCompo === void 0 ? _reactMapGl.Map : _this$props6$MapCompo, mapboxApiAccessToken = _this$props6.mapboxApiAccessToken, mapControls = _this$props6.mapControls, isExport = _this$props6.isExport, locale = _this$props6.locale, uiStateActions = _this$props6.uiStateActions, visStateActions = _this$props6.visStateActions, index = _this$props6.index, primary = _this$props6.primary, bottomMapContainerProps = _this$props6.bottomMapContainerProps, topMapContainerProps = _this$props6.topMapContainerProps, theme = _this$props6.theme, _this$props6$datasetA = _this$props6.datasetAttributions, datasetAttributions = _this$props6$datasetA === void 0 ? [] : _this$props6$datasetA, _this$props6$containe = _this$props6.containerId, containerId = _this$props6$containe === void 0 ? 0 : _this$props6$containe, isLoadingIndicatorVisible = _this$props6.isLoadingIndicatorVisible, activeSidePanel = _this$props6.activeSidePanel, sidePanelWidth = _this$props6.sidePanelWidth; var layers = visState.layers, datasets = visState.datasets, editor = visState.editor, interactionConfig = visState.interactionConfig; var layersToRender = this.layersToRenderSelector(this.props); var layersForDeck = this.layersForDeckSelector(this.props); // Current style can be a custom style, from which we pull the mapbox API acccess token var currentStyle = (_mapStyle$mapStyles = mapStyle.mapStyles) === null || _mapStyle$mapStyles === void 0 ? void 0 : _mapStyle$mapStyles[mapStyle.styleType]; var baseMapLibraryName = (0, _utils.getBaseMapLibrary)(currentStyle); var baseMapLibraryConfig = (_getApplicationConfig = (0, _utils.getApplicationConfig)().baseMapLibraryConfig) === null || _getApplicationConfig === void 0 ? void 0 : _getApplicationConfig[baseMapLibraryName]; var internalViewState = (_this$context3 = this.context) === null || _this$context3 === void 0 ? void 0 : _this$context3.getInternalViewState(index); var mapProps = _objectSpread(_objectSpread({}, internalViewState), {}, { preserveDrawingBuffer: true, mapboxAccessToken: (currentStyle === null || currentStyle === void 0 ? void 0 : currentStyle.accessToken) || mapboxApiAccessToken, // baseApiUrl: mapboxApiUrl, mapLib: baseMapLibraryConfig.getMapLib(), transformRequest: this.props.transformRequest || (0, _utils.transformRequest)((currentStyle === null || currentStyle === void 0 ? void 0 : currentStyle.accessToken) || mapboxApiAccessToken) }); var hasGeocoderLayer = Boolean(layers.find(function (l) { return l.id === _constants.GEOCODER_LAYER_ID; })); var isSplit = Boolean(mapState.isSplit); var deck = this._renderDeckOverlay(layersForDeck, { primaryMap: true, isInteractive: true, children: /*#__PURE__*/_react["default"].createElement(MapComponent, (0, _extends2["default"])({ key: "bottom-".concat(baseMapLibraryName) }, mapProps, { mapStyle: (_mapStyle$bottomMapSt = mapStyle.bottomMapStyle) !== null && _mapStyle$bottomMapSt !== void 0 ? _mapStyle$bottomMapSt : _constants.EMPTY_MAPBOX_STYLE }, bottomMapContainerProps, { ref: this._setMapRef })) }); if (!deck) { // deckOverlay can be null if onDeckRender returns null // in this case we don't want to render the map return null; } return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(MapControl, { mapState: mapState, datasets: datasets, availableLocales: LOCALE_CODES_ARRAY, dragRotate: mapState.dragRotate, isSplit: isSplit, primary: Boolean(primary), isExport: isExport, layers: layers, layersToRender: layersToRender, mapIndex: index || 0, mapControls: mapControls, readOnly: this.props.readOnly, scale: mapState.scale || 1, top: interactionConfig.geocoder && interactionConfig.geocoder.enabled ? theme.mapControlTop : 0, editor: editor, locale: locale, onTogglePerspective: mapStateActions.togglePerspective, onToggleSplitMap: mapStateActions.toggleSplitMap, onMapToggleLayer: this._handleMapToggleLayer, onToggleMapControl: this._toggleMapControl, onToggleSplitMapViewport: mapStateActions.toggleSplitMapViewport, onSetEditorMode: visStateActions.setEditorMode, onSetLocale: uiStateActions.setLocale, onToggleEditorVisibility: visStateActions.toggleEditorVisibility, onLayerVisConfigChange: visStateActions.layerVisConfigChange, mapHeight: mapState.height }), isSplitSelector(this.props) && /*#__PURE__*/_react["default"].createElement(Droppable, { containerId: containerId }), deck, this._renderMapboxOverlays(), /*#__PURE__*/_react["default"].createElement(Editor, { index: index || 0, datasets: datasets, editor: editor, filters: this.polygonFiltersSelector(this.props), layers: layers, onDeleteFeature: visStateActions.deleteFeature, onSelect: visStateActions.setSelectedFeature, onTogglePolygonFilter: visStateActions.setPolygonFilterLayer, onSetEditorMode: visStateActions.setEditorMode, style: { pointerEvents: 'all', position: 'absolute', display: editor.visible ? 'block' : 'none' } }), this.props.children, mapStyle.topMapStyle ? /*#__PURE__*/_react["default"].createElement(MapComponent, (0, _extends2["default"])({ key: "top-".concat(baseMapLibraryName), viewState: internalViewState, mapStyle: mapStyle.topMapStyle, style: MAP_STYLE.top, mapboxAccessToken: mapProps.mapboxAccessToken, transformRequest: mapProps.transformRequest, mapLib: baseMapLibraryConfig.getMapLib() }, topMapContainerProps)) : null, hasGeocoderLayer ? this._renderDeckOverlay((0, _defineProperty2["default"])({}, _constants.GEOCODER_LAYER_ID, hasGeocoderLayer), { primaryMap: false, isInteractive: false }) : null, this._renderMapPopover(), primary !== isSplit ? /*#__PURE__*/_react["default"].createElement(_loadingIndicator["default"], { isVisible: Boolean(isLoadingIndicatorVisible), activeSidePanel: Boolean(activeSidePanel), sidePanelWidth: sidePanelWidth }, "Loading...") : null, this.props.primary ? /*#__PURE__*/_react["default"].createElement(Attribution, { showBaseMapLibLogo: this.state.showBaseMapAttribution, showOsmBasemapAttribution: true, datasetAttributions: datasetAttributions, baseMapLibraryConfig: baseMapLibraryConfig }) : null); } }, { key: "render", value: function render() { var _mapStyle$mapStyles2, _getApplicationConfig2; var _this$props7 = this.props, visState = _this$props7.visState, mapStyle = _this$props7.mapStyle; var mapContent = this._renderMap(); if (!mapContent) { // mapContent can be null if onDeckRender returns null // in this case we don't want to render the map return null; } var currentStyle = (_mapStyle$mapStyles2 = mapStyle.mapStyles) === null || _mapStyle$mapStyles2 === void 0 ? void 0 : _mapStyle$mapStyles2[mapStyle.styleType]; var baseMapLibraryName = (0, _utils.getBaseMapLibrary)(currentStyle); var baseMapLibraryConfig = (_getApplicationConfig2 = (0, _utils.getApplicationConfig)().baseMapLibraryConfig) === null || _getApplicationConfig2 === void 0 ? void 0 : _getApplicationConfig2[baseMapLibraryName]; return /*#__PURE__*/_react["default"].createElement(StyledMap, { ref: this._ref, style: this.styleSelector(this.props), onContextMenu: function onContextMenu(event) { return event.preventDefau