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
JavaScript
"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