UNPKG

kepler.gl

Version:

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

1,241 lines (1,200 loc) 447 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.INITIAL_VIS_STATE = exports.DEFAULT_EDITOR = exports.DEFAULT_ANIMATION_CONFIG = void 0; exports.addDefaultLayers = addDefaultLayers; exports.addDefaultTooltips = addDefaultTooltips; exports.applyCPUFilterUpdater = exports.addLayerUpdater = exports.addFilterUpdater = exports.addEffectUpdater = void 0; exports.applyFilterConfigUpdater = applyFilterConfigUpdater; exports.applyLayerConfigUpdater = applyLayerConfigUpdater; exports.applyMergersUpdater = applyMergersUpdater; exports.closeSpecificMapAtIndex = closeSpecificMapAtIndex; exports.copyTableColumnUpdater = copyTableColumnUpdater; exports.defaultInteractionConfig = exports.createOrUpdateFilterUpdater = exports.createNewDatasetSuccessUpdater = void 0; exports.deleteFeatureUpdater = deleteFeatureUpdater; exports.duplicateLayerUpdater = void 0; exports.initialFileLoadingProgress = initialFileLoadingProgress; exports.interactionConfigChangeUpdater = interactionConfigChangeUpdater; exports.isFilterAnimationConfig = isFilterAnimationConfig; exports.layerAnimationChangeUpdater = layerAnimationChangeUpdater; exports.layerColorUIChangeUpdater = exports.layerClickUpdater = void 0; exports.layerConfigChangeUpdater = layerConfigChangeUpdater; exports.layerDataIdChangeUpdater = layerDataIdChangeUpdater; exports.layerFilteredItemsChangeUpdater = layerFilteredItemsChangeUpdater; exports.layerHoverUpdater = void 0; exports.layerSetIsValidUpdater = layerSetIsValidUpdater; exports.layerTextLabelChangeUpdater = layerTextLabelChangeUpdater; exports.layerToggleVisibilityUpdater = layerToggleVisibilityUpdater; exports.layerTypeChangeUpdater = layerTypeChangeUpdater; exports.layerVisConfigChangeUpdater = layerVisConfigChangeUpdater; exports.layerVisualChannelChangeUpdater = layerVisualChannelChangeUpdater; exports.loadFileStepSuccessUpdater = loadFileStepSuccessUpdater; exports.loadFilesUpdater = exports.loadFilesErrUpdater = void 0; exports.loadNextFileUpdater = loadNextFileUpdater; exports.makeLoadFileTask = makeLoadFileTask; exports.nextFileBatchUpdater = exports.mouseMoveUpdater = exports.mapClickUpdater = void 0; exports.parseProgress = parseProgress; exports.pinTableColumnUpdater = pinTableColumnUpdater; exports.prepareStateForDatasetReplace = prepareStateForDatasetReplace; exports.processFileContentUpdater = processFileContentUpdater; exports.receiveMapConfigUpdater = void 0; exports.removeDatasetUpdater = removeDatasetUpdater; exports.removeFilterUpdater = exports.removeEffectUpdater = void 0; exports.removeLayerUpdater = removeLayerUpdater; exports.renameDatasetUpdater = renameDatasetUpdater; exports.reorderLayerUpdater = exports.reorderEffectUpdater = void 0; exports.replaceDatasetDepsInState = replaceDatasetDepsInState; exports.resetMapConfigUpdater = void 0; exports.setAnimationConfigUpdater = setAnimationConfigUpdater; exports.setColumnDisplayFormatUpdater = setColumnDisplayFormatUpdater; exports.setEditorModeUpdater = void 0; exports.setFeaturesUpdater = setFeaturesUpdater; exports.setFilterAnimationTimeConfigUpdater = setFilterAnimationTimeConfigUpdater; exports.setFilterAnimationTimeUpdater = setFilterAnimationTimeUpdater; exports.setFilterAnimationWindowUpdater = setFilterAnimationWindowUpdater; exports.setFilterPlotUpdater = void 0; exports.setFilterUpdater = setFilterUpdater; exports.setFilterViewUpdater = void 0; exports.setInitialLayerConfig = setInitialLayerConfig; exports.setLayerAnimationTimeConfigUpdater = setLayerAnimationTimeConfigUpdater; exports.setMapInfoUpdater = exports.setLayerAnimationTimeUpdater = void 0; exports.setPolygonFilterLayerUpdater = setPolygonFilterLayerUpdater; exports.setSelectedFeatureUpdater = void 0; exports.setTimeFilterTimelineModeUpdater = setTimeFilterTimelineModeUpdater; exports.showDatasetTableUpdater = void 0; exports.sortTableColumnUpdater = sortTableColumnUpdater; exports.syncTimeFilterWithLayerTimelineUpdater = syncTimeFilterWithLayerTimelineUpdater; exports.toggleEditorVisibilityUpdater = toggleEditorVisibilityUpdater; exports.toggleSplitMapUpdater = exports.toggleLayerForMapUpdater = exports.toggleLayerAnimationUpdater = exports.toggleLayerAnimationControlUpdater = exports.toggleFilterFeatureUpdater = exports.toggleFilterAnimationUpdater = void 0; exports.updateAllLayerDomainData = updateAllLayerDomainData; exports.updateAnimationDomain = updateAnimationDomain; exports.updateDatasetPropsUpdater = updateDatasetPropsUpdater; exports.updateEffectUpdater = void 0; exports.updateFileLoadingProgressUpdater = updateFileLoadingProgressUpdater; exports.updateOverlayBlendingUpdater = exports.updateLayerBlendingUpdater = exports.updateLayerAnimationSpeedUpdater = exports.updateFilterAnimationSpeedUpdater = void 0; exports.updateStateOnLayerVisibilityChange = updateStateOnLayerVisibilityChange; exports.updateStateWithLayerAndData = updateStateWithLayerAndData; exports.updateVisDataUpdater = exports.updateTableColorUpdater = void 0; var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _bbox = _interopRequireDefault(require("@turf/bbox")); var _copyToClipboard = _interopRequireDefault(require("copy-to-clipboard")); var _deepmerge = _interopRequireDefault(require("deepmerge")); var _window = require("global/window"); var _lodash = _interopRequireDefault(require("lodash.clonedeep")); var _lodash2 = _interopRequireDefault(require("lodash.get")); var _lodash3 = _interopRequireDefault(require("lodash.isequal")); var _lodash4 = _interopRequireDefault(require("lodash.pick")); var _lodash5 = _interopRequireDefault(require("lodash.uniq")); var _lodash6 = _interopRequireDefault(require("lodash.xor")); var _tasks = _interopRequireWildcard(require("react-palm/tasks")); var _tasks2 = require("@kepler.gl/tasks"); var _actions = require("@kepler.gl/actions"); var _utils = require("@kepler.gl/utils"); var _commonUtils = require("@kepler.gl/common-utils"); var _constants = require("@kepler.gl/constants"); var _layers = require("@kepler.gl/layers"); var _composerHelpers = require("./composer-helpers"); var _mergerHandler = require("./merger-handler"); var _visStateMerger = require("./vis-state-merger"); var _schemas = _interopRequireDefault(require("@kepler.gl/schemas")); var _table = require("@kepler.gl/table"); var _interactionUtils = require("./interaction-utils"); var _layerUtils = require("./layer-utils"); var _effects = require("@kepler.gl/effects"); var _dataUtils = require("./data-utils"); var _excluded = ["dataId"], _excluded2 = ["info"]; 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 _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return 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; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project // Tasks // Actions // Utils // Mergers // react-palm // disable capture exception for react-palm call to withTask (0, _tasks.disableStackCapturing)(); /** * Updaters for `visState` reducer. Can be used in your root reducer to directly modify kepler.gl's state. * Read more about [Using updaters](../advanced-usage/using-updaters.md) * * @public * @example * * import keplerGlReducer, {visStateUpdaters} from 'kepler.gl/reducers'; * // Root Reducer * const reducers = combineReducers({ * keplerGl: keplerGlReducer, * app: appReducer * }); * * const composedReducer = (state, action) => { * switch (action.type) { * case 'CLICK_BUTTON': * return { * ...state, * keplerGl: { * ...state.keplerGl, * foo: { * ...state.keplerGl.foo, * visState: visStateUpdaters.enlargeFilterUpdater( * state.keplerGl.foo.visState, * {idx: 0} * ) * } * } * }; * } * return reducers(state, action); * }; * * export default composedReducer; */ /* eslint-disable @typescript-eslint/no-unused-vars */ // @ts-ignore var visStateUpdaters = null; /* eslint-enable @typescript-eslint/no-unused-vars */ var defaultInteractionConfig = exports.defaultInteractionConfig = { tooltip: { id: 'tooltip', label: 'interactions.tooltip', enabled: true, config: { fieldsToShow: {}, compareMode: false, compareType: _constants.COMPARE_TYPES.ABSOLUTE } }, geocoder: { id: 'geocoder', label: 'interactions.geocoder', enabled: false, position: null }, brush: { id: 'brush', label: 'interactions.brush', enabled: false, config: { // size is in km size: 0.5 } }, coordinate: { id: 'coordinate', label: 'interactions.coordinate', enabled: false, position: null } }; var DEFAULT_ANIMATION_CONFIG = exports.DEFAULT_ANIMATION_CONFIG = { domain: null, currentTime: null, speed: 1, isAnimating: false, timeSteps: null, timeFormat: null, timezone: null, defaultTimeFormat: null, hideControl: false, duration: null }; var DEFAULT_EDITOR = exports.DEFAULT_EDITOR = { mode: _constants.EDITOR_MODES.DRAW_POLYGON, features: [], selectedFeature: null, visible: true }; /** * Default initial `visState` * @memberof visStateUpdaters * @constant * @public */ var INITIAL_VIS_STATE = exports.INITIAL_VIS_STATE = { // map info mapInfo: { title: '', description: '' }, // layers layers: [], layerData: [], layerToBeMerged: [], layerOrder: [], // filters filters: [], filterToBeMerged: [], // a collection of multiple dataset datasets: {}, editingDataset: undefined, // effects effects: [], effectOrder: [], interactionConfig: defaultInteractionConfig, interactionToBeMerged: {}, layerBlending: 'normal', overlayBlending: 'normal', hoverInfo: undefined, clicked: undefined, mousePos: {}, maxDefaultTooltips: _constants.MAX_DEFAULT_TOOLTIPS, // this is used when user split maps splitMaps: [ // this will contain a list of objects to // describe the state of layer availability and visibility for each map // [ // { // layers: {layer_id: true | false} // } // ] ], splitMapsToBeMerged: [], isMergingDatasets: {}, // defaults layer classes layerClasses: _layers.LayerClasses, // default animation // time in unix timestamp (milliseconds) (the number of seconds since the Unix Epoch) animationConfig: DEFAULT_ANIMATION_CONFIG, editor: DEFAULT_EDITOR, fileLoading: false, fileLoadingProgress: {}, loaders: [], loadOptions: {}, // visStateMergers mergers: _visStateMerger.VIS_STATE_MERGERS, // kepler schemas schema: _schemas["default"] }; /** * Update state with updated layer and layerData * */ function updateStateWithLayerAndData(state, _ref) { var layerData = _ref.layerData, layer = _ref.layer, idx = _ref.idx; return _objectSpread(_objectSpread({}, state), {}, { layers: state.layers.map(function (lyr, i) { return i === idx ? layer : lyr; }), layerData: layerData ? state.layerData.map(function (d, i) { return i === idx ? layerData : d; }) : state.layerData }); } function updateStateOnLayerVisibilityChange(state, layer) { var newState = state; if (state.splitMaps.length) { newState = _objectSpread(_objectSpread({}, state), {}, { splitMaps: layer.config.isVisible ? (0, _utils.addNewLayersToSplitMap)(state.splitMaps, layer) : (0, _utils.removeLayerFromSplitMaps)(state.splitMaps, layer) }); } if (layer.config.animation.enabled) { newState = updateAnimationDomain(newState); } return newState; } /** * Compares two objects (or arrays) and returns a new object with only the * properties that have changed between the two objects. */ function pickChangedProps(prev, next) { var changedProps = {}; var pickPropsOf = function pickPropsOf(obj) { Object.keys(obj).forEach(function (key) { if (!Object.prototype.hasOwnProperty.call(changedProps, key) && !(0, _lodash3["default"])(prev[key], next[key])) { changedProps[key] = next[key]; } }); }; pickPropsOf(prev); pickPropsOf(next); return changedProps; } var VISUAL_CHANNEL_PROP_TYPES = ['field', 'scale', 'domain', 'aggregation']; /** * Apply layer config * @memberof visStateUpdaters * @returns nextState */ // eslint-disable-next-line complexity, max-statements function applyLayerConfigUpdater(state, action) { var _serializeLayer; var oldLayerId = action.oldLayerId, newLayerConfig = action.newLayerConfig, layerIndex = action.layerIndex; var newParsedLayer = // will move visualChannels to the config prop (0, _visStateMerger.parseLayerConfig)(state.schema, newLayerConfig); var oldLayer = state.layers.find(function (l) { return l.id === oldLayerId; }); if (!oldLayer || !newParsedLayer) { return state; } if (layerIndex !== null && layerIndex !== undefined && state.layers[layerIndex] !== oldLayer) { // layerIndex is provided, but it doesn't match the oldLayer return state; } var dataset = state.datasets[newParsedLayer.config.dataId]; if (!dataset) { return state; } // Make sure the layer is valid and convert it to Layer var newLayer = (0, _visStateMerger.validateLayerWithData)(dataset, newParsedLayer, state.layerClasses); if (!newLayer) { return state; } var nextState = state; if (newLayer.type && newLayer.type !== oldLayer.type) { var oldLayerIndex = state.layers.findIndex(function (l) { return l.id === oldLayerId; }); if (oldLayerIndex >= 0) { nextState = layerTypeChangeUpdater(nextState, (0, _actions.layerTypeChange)(oldLayer, newLayer.type)); // layerTypeChangeUpdater changes the id of the layer, so we need to obtain the new id // but first make sure that the layer was not removed if (nextState.layers.length === state.layers.length) { var newLayerId = nextState.layers[oldLayerIndex].id; nextState = applyLayerConfigUpdater(nextState, (0, _actions.applyLayerConfig)(newLayerId, _objectSpread(_objectSpread({}, newLayerConfig), {}, { id: newLayerId }))); } } return nextState; } // serializeLayer() might return null if the old layer is not valid, // we should still apply the changes in that case var serializedOldLayer = (_serializeLayer = (0, _visStateMerger.serializeLayer)(oldLayer, state.schema)) !== null && _serializeLayer !== void 0 ? _serializeLayer : { config: {} }; var serializedNewLayer = (0, _visStateMerger.serializeLayer)(newLayer, state.schema); if (!serializedNewLayer) { return state; } if (!(0, _lodash3["default"])(serializedOldLayer, serializedNewLayer)) { var changed = pickChangedProps(serializedOldLayer.config, serializedNewLayer.config); if ('visConfig' in changed) { if (changed.visConfig) { nextState = layerVisConfigChangeUpdater(nextState, (0, _actions.layerVisConfigChange)(oldLayer, changed.visConfig)); } delete changed.visConfig; } Object.keys(oldLayer.visualChannels).forEach(function (channelName) { var channel = oldLayer.visualChannels[channelName]; var channelPropNames = VISUAL_CHANNEL_PROP_TYPES.map(function (prop) { return channel[prop]; }); if (channelPropNames.some(function (prop) { return prop in changed; })) { nextState = layerVisualChannelChangeUpdater(nextState, (0, _actions.layerVisualChannelConfigChange)(oldLayer, (0, _lodash4["default"])(newLayer.config, channelPropNames), channelName)); var _iterator = _createForOfIteratorHelper(channelPropNames), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var prop = _step.value; delete changed[prop]; } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } } }); if (Object.keys(changed).length > 0) { nextState = layerConfigChangeUpdater(nextState, (0, _actions.layerConfigChange)(oldLayer, (0, _lodash4["default"])(newLayer.config, Object.keys(changed)))); } } return nextState; } function updatelayerVisibilty(state, newLayer, isVisible) { var newState = updateStateOnLayerVisibilityChange(state, newLayer); var filterIndex = filterSyncedWithTimeline(state); if ((0, _utils.isLayerAnimatable)(newLayer) && filterIndex !== -1) { // if layer is going to be visible we sync with filter otherwise we need to check whether other animatable layers exists and are visible newState = syncTimeFilterWithLayerTimelineUpdater(newState, { idx: filterIndex, enable: isVisible ? isVisible : (0, _utils.getAnimatableVisibleLayers)(state.layers).length > 0 }); } return newState; } /** * Update layer base config: dataId, label, column, isVisible * @memberof visStateUpdaters * @returns nextState */ // eslint-disable-next-line complexity function layerConfigChangeUpdater(state, action) { var oldLayer = action.oldLayer; var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var props = Object.keys(action.newConfig); if (typeof action.newConfig.dataId === 'string' && action.newConfig.dataId !== oldLayer.config.dataId) { var _action$newConfig = action.newConfig, dataId = _action$newConfig.dataId, restConfig = (0, _objectWithoutProperties2["default"])(_action$newConfig, _excluded); var stateWithDataId = layerDataIdChangeUpdater(state, { oldLayer: oldLayer, newConfig: { dataId: dataId } }); var nextLayer = stateWithDataId.layers.find(function (l) { return l.id === oldLayer.id; }); return nextLayer && Object.keys(restConfig).length ? layerConfigChangeUpdater(stateWithDataId, { oldLayer: nextLayer, newConfig: restConfig }) : stateWithDataId; } var newLayer = oldLayer.updateLayerConfig(action.newConfig); var layerData; if (newLayer.shouldCalculateLayerData(props)) { var oldLayerData = state.layerData[idx]; var updateLayerDataResult = (0, _layerUtils.calculateLayerData)(newLayer, state, oldLayerData); newLayer = updateLayerDataResult.layer; layerData = updateLayerDataResult.layerData; } var newState = state; if ('isVisible' in action.newConfig) { newState = updatelayerVisibilty(newState, newLayer, action.newConfig.isVisible); } if ('columns' in action.newConfig && newLayer.config.animation.enabled) { // TODO: Shan, make the animation config function more robust newState = updateAnimationDomain(newState); } return updateStateWithLayerAndData(newState, { layer: newLayer, layerData: layerData, idx: idx }); } function layerAnimationChangeUpdater(state, action) { var oldLayer = action.oldLayer, prop = action.prop, value = action.value; var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var newLayer = oldLayer.updateLayerConfig({ animation: _objectSpread(_objectSpread({}, oldLayer.config.animation), {}, (0, _defineProperty2["default"])({}, prop, value)) }); var _calculateLayerData = (0, _layerUtils.calculateLayerData)(newLayer, state, state.layerData[idx]), layerData = _calculateLayerData.layerData, layer = _calculateLayerData.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } /** * Update layerId, isVisible, splitMapId * handles two cases: * 1) toggle the visibility of local SplitMap layer (visState.splitMap.layers) * 2) toggle the visibility of global layer (visState.layers) * @memberof visStateUpdaters * @returns nextState */ function layerToggleVisibilityUpdater(state, action) { var layerId = action.layerId, isVisible = action.isVisible, splitMapId = action.splitMapId; var layer = state.layers.find(function (d) { return d.id === layerId; }); if (!layer) { return state; } var newState = state; if (splitMapId) { // [case 1]: toggle local layer visibility for each SplitMap var mapIndex = newState.splitMaps.findIndex(function (sm) { return sm.id === splitMapId; }); if (isVisible) { // 1) if the layer is invisible globally // -> set global visibility to true newState = layerConfigChangeUpdater(newState, (0, _actions.layerConfigChange)(layer, { isVisible: true })); // -> set local visibility to true and the local visibilities of all other SplitMaps to false return _objectSpread(_objectSpread({}, newState), {}, { splitMaps: newState.splitMaps.map(function (sm) { return sm.id !== splitMapId ? _objectSpread(_objectSpread({}, sm), {}, { layers: _objectSpread(_objectSpread({}, sm.layers), {}, (0, _defineProperty2["default"])({}, layerId, false)) }) : _objectSpread(_objectSpread({}, sm), {}, { layers: _objectSpread(_objectSpread({}, sm.layers), {}, (0, _defineProperty2["default"])({}, layerId, true)) }); }) }); } // 2) else when the layer is visible globally return toggleLayerForMapUpdater(newState, (0, _actions.toggleLayerForMap)(mapIndex, layerId)); } else { // [case 2]: toggle global layer visibility var newLayer = layer.updateLayerConfig({ isVisible: isVisible }); var idx = newState.layers.findIndex(function (l) { return l.id === layerId; }); newState = updatelayerVisibilty(newState, newLayer, isVisible); return updateStateWithLayerAndData(newState, { layer: newLayer, idx: idx }); } } /** * * @param state * @returns index of the filter synced to timeline or -1 */ function filterSyncedWithTimeline(state) { return state.filters.findIndex(function (f) { return f.syncedWithLayerTimeline; }); } /** * Updates isValid flag of a layer. * Updates isVisible based on the value of isValid. * Triggers update of data for the layer in order to get errors again during next update iteration. * @memberof visStateUpdaters * @returns nextState */ function layerSetIsValidUpdater(state, action) { var oldLayer = action.oldLayer, isValid = action.isValid; var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var layerToUpdate = state.layers[idx]; if (layerToUpdate) { var newLayer; var newData = null; if (isValid) { // Trigger data update in order to show errors again if present. var _calculateLayerData2 = (0, _layerUtils.calculateLayerData)(layerToUpdate, state, undefined), layer = _calculateLayerData2.layer, layerData = _calculateLayerData2.layerData; newLayer = layer; newData = layerData; } else { newLayer = layerToUpdate.updateLayerConfig({ isVisible: false }); newLayer.isValid = false; } return updateStateWithLayerAndData(state, { idx: idx, layer: newLayer, layerData: newData }); } return state; } function addOrRemoveTextLabels(newFields, textLabel) { var defaultTextLabel = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _constants.DEFAULT_TEXT_LABEL; var newTextLabel = textLabel.slice(); var currentFields = textLabel.map(function (tl) { return tl.field && tl.field.name; }).filter(function (d) { return d; }); var addFields = newFields.filter(function (f) { return !currentFields.includes(f.name); }); var deleteFields = currentFields.filter(function (f) { return !newFields.find(function (fd) { return fd.name === f; }); }); // delete newTextLabel = newTextLabel.filter(function (tl) { return tl.field && !deleteFields.includes(tl.field.name); }); newTextLabel = !newTextLabel.length ? [defaultTextLabel] : newTextLabel; // add newTextLabel = [].concat((0, _toConsumableArray2["default"])(newTextLabel.filter(function (tl) { return tl.field; })), (0, _toConsumableArray2["default"])(addFields.map(function (af) { return _objectSpread(_objectSpread({}, defaultTextLabel), {}, { field: af }); }))); return newTextLabel; } function updateTextLabelPropAndValue(idx, prop, value, textLabel) { if (!Object.prototype.hasOwnProperty.call(textLabel[idx], prop)) { return textLabel; } var newTextLabel = textLabel.slice(); if (prop === 'field' && value === null && textLabel.length > 1) { // remove label when field value is set to null newTextLabel.splice(idx, 1); } else if (prop) { newTextLabel = textLabel.map(function (tl, i) { return i === idx ? _objectSpread(_objectSpread({}, tl), {}, (0, _defineProperty2["default"])({}, prop, value)) : tl; }); } return newTextLabel; } /** * Update layer base config: dataId, label, column, isVisible * @memberof visStateUpdaters * @returns nextState */ function layerTextLabelChangeUpdater(state, action) { var _oldLayer$getDefaultL, _oldLayer$getDefaultL2; var oldLayer = action.oldLayer, idx = action.idx, prop = action.prop, value = action.value; var textLabel = oldLayer.config.textLabel; // when adding a new empty text label, // rely on the layer's default config, or use the constant DEFAULT_TEXT_LABEL var defaultTextLabel = (_oldLayer$getDefaultL = (_oldLayer$getDefaultL2 = oldLayer.getDefaultLayerConfig({ dataId: '' })) === null || _oldLayer$getDefaultL2 === void 0 || (_oldLayer$getDefaultL2 = _oldLayer$getDefaultL2.textLabel) === null || _oldLayer$getDefaultL2 === void 0 ? void 0 : _oldLayer$getDefaultL2[0]) !== null && _oldLayer$getDefaultL !== void 0 ? _oldLayer$getDefaultL : _constants.DEFAULT_TEXT_LABEL; var newTextLabel = textLabel.slice(); if (!textLabel[idx] && idx === textLabel.length) { // if idx is set to length, add empty text label newTextLabel = [].concat((0, _toConsumableArray2["default"])(textLabel), [defaultTextLabel]); } if (idx === 'all' && prop === 'fields') { newTextLabel = addOrRemoveTextLabels(value, textLabel, defaultTextLabel); } else { newTextLabel = updateTextLabelPropAndValue(idx, prop, value, newTextLabel); } // update text label prop and value return layerConfigChangeUpdater(state, { oldLayer: oldLayer, newConfig: { textLabel: newTextLabel } }); } function validateExistingLayerWithData(dataset, layerClasses, layer, schema) { var loadedLayer = (0, _visStateMerger.serializeLayer)(layer, schema); return loadedLayer ? (0, _visStateMerger.validateLayerWithData)(dataset, loadedLayer, layerClasses, { allowEmptyColumn: true }) : null; } /** * Update layer config dataId * @memberof visStateUpdaters * @returns nextState */ function layerDataIdChangeUpdater(state, action) { var oldLayer = action.oldLayer, newConfig = action.newConfig; var dataId = newConfig.dataId; if (!oldLayer || !state.datasets[dataId]) { return state; } var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var newLayer = oldLayer.updateLayerConfig({ dataId: dataId }); // this may happen when a layer is new (type: null and no columns) but it's not ready to be saved if (newLayer.isValidToSave()) { var validated = validateExistingLayerWithData(state.datasets[dataId], state.layerClasses, newLayer, state.schema); // if cant validate it with data create a new one if (!validated) { var oldLayerType = oldLayer.type; if (oldLayerType) { newLayer = new state.layerClasses[oldLayerType]({ dataId: dataId, id: oldLayer.id }); } } else { newLayer = validated; } } newLayer = newLayer.updateLayerConfig({ isVisible: oldLayer.config.isVisible, isConfigActive: true }); newLayer.updateLayerDomain(state.datasets); var _calculateLayerData3 = (0, _layerUtils.calculateLayerData)(newLayer, state, undefined), layerData = _calculateLayerData3.layerData, layer = _calculateLayerData3.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } function setInitialLayerConfig(layer, datasets, layerClasses) { var newLayer = layer; if (!Object.keys(datasets).length) { // no data is loaded return layer; } if (!layer.config.dataId) { // set layer dataId newLayer = layer.updateLayerConfig({ dataId: Object.keys(datasets)[0] }); } var dataset = datasets[newLayer.config.dataId]; if (!dataset) { return layer; } // find defaut layer props var result = typeof layerClasses[newLayer.type].findDefaultLayerProps === 'function' ? layerClasses[newLayer.type].findDefaultLayerProps(dataset, []) : { props: [] }; // an array of possible props, use 1st one var props = Array.isArray(result) ? result : result.props || []; if (props.length) { newLayer = new layerClasses[layer.type](_objectSpread(_objectSpread({}, props[0]), {}, { label: newLayer.config.label, dataId: newLayer.config.dataId, isConfigActive: newLayer.config.isConfigActive })); } return typeof newLayer.setInitialLayerConfig === 'function' ? newLayer.setInitialLayerConfig(dataset) : newLayer; } /** * Update layer type. Previews layer config will be copied if applicable. * @memberof visStateUpdaters * @public */ function layerTypeChangeUpdater(state, action) { var oldLayer = action.oldLayer, newType = action.newType; if (!oldLayer) { return state; } var oldId = oldLayer.id; var idx = state.layers.findIndex(function (l) { return l.id === oldId; }); if (!state.layerClasses[newType]) { _window.console.error("".concat(newType, " is not a valid layer type")); return state; } var newLayer = new state.layerClasses[newType]({ // keep old layer lable and isConfigActive label: oldLayer.config.label, isConfigActive: oldLayer.config.isConfigActive, dataId: oldLayer.config.dataId }); if (!oldLayer.type) { // if setting layer type on an empty layer newLayer = setInitialLayerConfig(newLayer, state.datasets, state.layerClasses); } else { // get a mint layer, with new id and type // because deck.gl uses id to match between new and old layer. // If type has changed but id is the same, it will break var defaultLayerProps = typeof state.layerClasses[newType].findDefaultLayerProps === 'function' ? state.layerClasses[newType].findDefaultLayerProps(state.datasets[newLayer.config.dataId]) : null; newLayer.assignConfigToLayer(oldLayer.config, oldLayer.visConfigSettings, state.datasets, defaultLayerProps); newLayer.updateLayerDomain(state.datasets); } var clicked = state.clicked, hoverInfo = state.hoverInfo; var newState = _objectSpread(_objectSpread({}, state), {}, { clicked: oldLayer.isLayerHovered(clicked) ? undefined : clicked, hoverInfo: oldLayer.isLayerHovered(hoverInfo) ? undefined : hoverInfo }); var _calculateLayerData4 = (0, _layerUtils.calculateLayerData)(newLayer, newState), layerData = _calculateLayerData4.layerData, layer = _calculateLayerData4.layer; newState = updateStateWithLayerAndData(newState, { layerData: layerData, layer: layer, idx: idx }); if (layer.config.animation.enabled || oldLayer.config.animation.enabled) { newState = updateAnimationDomain(newState); } // update splitMap layer id if (state.splitMaps.length) { newState = _objectSpread(_objectSpread({}, newState), {}, { splitMaps: newState.splitMaps.map(function (settings) { var _settings$layers = settings.layers, oldLayerMap = _settings$layers[oldId], otherLayers = (0, _objectWithoutProperties2["default"])(_settings$layers, [oldId].map(_toPropertyKey)); return oldId in settings.layers ? _objectSpread(_objectSpread({}, settings), {}, { layers: _objectSpread(_objectSpread({}, otherLayers), {}, (0, _defineProperty2["default"])({}, layer.id, oldLayerMap)) }) : settings; }) }); } // update layerOrder with new id newState = _objectSpread(_objectSpread({}, newState), {}, { layerOrder: newState.layerOrder.map(function (layerId) { return layerId === oldLayer.id ? newLayer.id : layerId; }) }); return newState; } /** * Update layer visual channel * @memberof visStateUpdaters * @returns {Object} nextState * @public */ function layerVisualChannelChangeUpdater(state, action) { var oldLayer = action.oldLayer, newConfig = action.newConfig, newVisConfig = action.newVisConfig, channel = action.channel; if (!oldLayer.config.dataId) { return state; } var dataset = state.datasets[oldLayer.config.dataId]; var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var newLayer = oldLayer.updateLayerConfig(newConfig); if (newVisConfig) newLayer = newLayer.updateLayerVisConfig(newVisConfig); newLayer.updateLayerVisualChannel(dataset, channel); // calling update animation domain first to merge all layer animation domain var updatedState = updateAnimationDomain(state); var visualChannel = oldLayer.visualChannels[channel]; if ((visualChannel === null || visualChannel === void 0 ? void 0 : visualChannel.channelScaleType) === _constants.CHANNEL_SCALES.color && newConfig[visualChannel.field]) { // if color field changed, set customBreaks to false newLayer.updateLayerColorUI(visualChannel.range, { colorRangeConfig: _objectSpread(_objectSpread({}, newLayer.config.colorUI[visualChannel.range].colorRangeConfig), {}, { customBreaks: false }) }); updatedState = _objectSpread(_objectSpread({}, updatedState), {}, { layers: updatedState.layers.map(function (l) { return l.id === oldLayer.id ? newLayer : l; }) }); } var oldLayerData = updatedState.layerData[idx]; var _calculateLayerData5 = (0, _layerUtils.calculateLayerData)(newLayer, updatedState, oldLayerData), layerData = _calculateLayerData5.layerData, layer = _calculateLayerData5.layer; if ((visualChannel === null || visualChannel === void 0 ? void 0 : visualChannel.channelScaleType) === _constants.CHANNEL_SCALES.color && newConfig[visualChannel === null || visualChannel === void 0 ? void 0 : visualChannel.scale] === _constants.SCALE_TYPES.customOrdinal && !newVisConfig) { // when switching to customOrdinal scale, create a customPalette in colorUI with updated colorDomain var customPalette = (0, _utils.initCustomPaletteByCustomScale)({ scale: _constants.SCALE_TYPES.customOrdinal, field: layer.config[visualChannel.field], ordinalDomain: layer.config[layer.visualChannels[channel].domain], range: layer.config.visConfig[visualChannel.range], colorBreaks: null }); // update colorRange with new customPalette layer.updateLayerColorUI(visualChannel.range, { showColorChart: true, colorRangeConfig: _objectSpread(_objectSpread({}, layer.config.colorUI[visualChannel.range].colorRangeConfig), {}, { customBreaks: true }), customPalette: customPalette }); } return updateStateWithLayerAndData(updatedState, { layerData: layerData, layer: layer, idx: idx }); } /** * Update layer `visConfig` * @memberof visStateUpdaters * @public */ function layerVisConfigChangeUpdater(state, action) { var oldLayer = action.oldLayer; var idx = state.layers.findIndex(function (l) { return l.id === oldLayer.id; }); var props = Object.keys(action.newVisConfig); var newVisConfig = _objectSpread(_objectSpread({}, oldLayer.config.visConfig), action.newVisConfig); var newLayer = oldLayer.updateLayerConfig({ visConfig: newVisConfig }); if (newLayer.shouldCalculateLayerData(props)) { var oldLayerData = state.layerData[idx]; var _calculateLayerData6 = (0, _layerUtils.calculateLayerData)(newLayer, state, oldLayerData), layerData = _calculateLayerData6.layerData, layer = _calculateLayerData6.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } return updateStateWithLayerAndData(state, { layer: newLayer, idx: idx }); } /** * Reset animation config current time to a specified value * @memberof visStateUpdaters * @public * */ var setLayerAnimationTimeUpdater = exports.setLayerAnimationTimeUpdater = function setLayerAnimationTimeUpdater(state, _ref2) { var value = _ref2.value; var currentTime = Array.isArray(value) ? value[0] : value; var nextState = _objectSpread(_objectSpread({}, state), {}, { animationConfig: _objectSpread(_objectSpread({}, state.animationConfig), {}, { currentTime: currentTime }) }); // update animation config for each layer return state.layers.reduce(function (accu, l) { if (l.config.animation.enabled && l.type !== 'trip') { return layerAnimationChangeUpdater(accu, { oldLayer: l, prop: 'currentTime', currentTime: currentTime }); } return accu; }, nextState); }; /** * Update filter property * @memberof visStateUpdaters * @public */ function setFilterAnimationTimeUpdater(state, action) { return setFilterUpdater(state, action); } /** * Update filter animation window * @memberof visStateUpdaters * @public */ function setFilterAnimationWindowUpdater(state, _ref3) { var id = _ref3.id, animationWindow = _ref3.animationWindow; var filter = state.filters.find(function (f) { return f.id === id; }); if (!filter) { return state; } var newFilter = _objectSpread(_objectSpread({}, filter), {}, { animationWindow: animationWindow }); var newState = _objectSpread(_objectSpread({}, state), {}, { filters: (0, _composerHelpers.swap_)(newFilter)(state.filters) }); var newSyncTimelineMode = getSyncAnimationMode(newFilter); return setTimeFilterTimelineModeUpdater(newState, { id: id, mode: newSyncTimelineMode }); } function applyFilterConfigUpdater(state, action) { var _serializeFilter; var filterId = action.filterId, newFilter = action.newFilter; var oldFilter = state.filters.find(function (f) { return f.id === filterId; }); if (!oldFilter) { return state; } // Serialize the filters to only compare the saved properties var serializedOldFilter = (_serializeFilter = (0, _visStateMerger.serializeFilter)(oldFilter, state.schema)) !== null && _serializeFilter !== void 0 ? _serializeFilter : { config: {} }; var serializedNewFilter = (0, _visStateMerger.serializeFilter)(newFilter, state.schema); if (!serializedNewFilter || (0, _lodash3["default"])(serializedOldFilter, serializedNewFilter)) { return state; } // If there are any changes to the filter, apply them var changed = pickChangedProps(serializedOldFilter, serializedNewFilter); delete changed['id']; // id should not be changed var filterIndex = state.filters.findIndex(function (f) { return f.id === filterId; }); if (filterIndex < 0) { return state; } return setFilterUpdater(state, (0, _actions.setFilter)(filterIndex, Object.keys(changed), Object.values(changed))); } /** * Update filter property * @memberof visStateUpdaters * @public */ function setFilterUpdater(state, action) { var idx = action.idx, _action$valueIndex = action.valueIndex, valueIndex = _action$valueIndex === void 0 ? 0 : _action$valueIndex; var oldFilter = state.filters[idx]; if (!oldFilter) { _window.console.error("filters.".concat(idx, " is undefined")); return state; } if (Array.isArray(action.prop) && (!Array.isArray(action.value) || action.prop.length !== action.value.length)) { _window.console.error('Expecting value to be an array of the same length, since prop is an array'); return state; } // convert prop and value to array var props = (0, _commonUtils.toArray)(action.prop); var values = Array.isArray(action.prop) ? (0, _commonUtils.toArray)(action.value) : [action.value]; var newFilter = oldFilter; var newState = state; var datasetIdsToFilter = []; var _loop = function _loop() { var prop = props[i]; var value = values[i]; // We currently do not support passing in name as an array into _updateFilterProp, so we call it multiple times with each name // See the comment in there as to what should be addressed var res; if (prop === 'name' && Array.isArray(value)) { // eslint-disable-next-line no-loop-func res = value.reduce(function (accu, v) { return _updateFilterProp(accu, newFilter, prop, v, valueIndex); }, newState); } else { res = _updateFilterProp(newState, newFilter, prop, value, valueIndex); } newFilter = res.filter; newState = res.state; datasetIdsToFilter = datasetIdsToFilter.concat(res.datasetIdsToFilter); }; for (var i = 0; i < props.length; i++) { _loop(); } var enlargedFilter = state.filters.find(function (f) { return f.view === _constants.FILTER_VIEW_TYPES.enlarged; }); if (enlargedFilter && enlargedFilter.id !== newFilter.id) { // there should be only one enlarged filter newFilter.view = _constants.FILTER_VIEW_TYPES.side; } // save new filters to newState newState = (0, _utils.set)(['filters', idx], newFilter, newState); // filter data var filteredDatasets = (0, _utils.applyFiltersToDatasets)((0, _lodash5["default"])(datasetIdsToFilter), newState.datasets, newState.filters, newState.layers); newState = (0, _utils.set)(['datasets'], filteredDatasets, newState); // need to update filterPlot after filter Dataset for plot to update on filtered result var filterWithPLot = (0, _utils.updateFilterPlot)(newState.datasets, newState.filters[idx]); newState = (0, _utils.set)(['filters', idx], filterWithPLot, newState); // dataId is an array // pass only the dataset we need to update newState = updateAllLayerDomainData(newState, datasetIdsToFilter, newFilter); // If time range filter value was updated, adjust animation config if (newFilter.type === _constants.FILTER_TYPES.timeRange && props.includes('value')) { newState = adjustAnimationConfigWithFilter(newState, action.idx); } return newState; } function _updateFilterDataIdAtValueIndex(filter, valueIndex, value, datasets) { var newFilter = filter; if (filter.dataId[valueIndex]) { // if dataId already exist newFilter = _removeFilterDataIdAtValueIndex(filter, valueIndex, datasets); } if (value) { var nextValue = newFilter.dataId.slice(); nextValue[valueIndex] = value; newFilter = (0, _utils.set)(['dataId'], nextValue, newFilter); } return newFilter; } function _removeFilterDataIdAtValueIndex(filter, valueIndex, datasets) { var dataId = filter.dataId[valueIndex]; if (filter.dataId.length === 1 && valueIndex === 0) { // if remove the only dataId, create an empty filter instead; return (0, _utils.getDefaultFilter)({ id: filter.id }); } if (dataId) { filter = (0, _utils.removeFilterPlot)(filter, dataId); } for (var _i = 0, _arr = ['dataId', 'name', 'fieldIdx', 'gpuChannel']; _i < _arr.length; _i++) { var prop = _arr[_i]; if (Array.isArray(filter[prop])) { var nextVal = filter[prop].slice(); nextVal.splice(valueIndex, 1); filter = (0, _utils.set)([prop], nextVal, filter); } } // mergeFieldDomain for the remaining fields var domainSteps = (0, _utils.mergeFilterDomain)(filter, datasets); var nextFilter = _objectSpread(_objectSpread({}, filter), domainSteps ? { domain: domainSteps === null || domainSteps === void 0 ? void 0 : domainSteps.domain, step: domainSteps === null || domainSteps === void 0 ? void 0 : domainSteps.step } : {}); var nextValue = (0, _utils.adjustValueToFilterDomain)(nextFilter.value, nextFilter); return _objectSpread(_objectSpread({}, nextFilter), {}, { value: nextValue }); } /** * * Updates a single property of a filter */ function _updateFilterProp(state, filter, prop, value, valueIndex, datasetIds) { var datasetIdsToFilter = []; switch (prop) { // TODO: Next PR for UI if we update filterDataId, we need to consider two cases: // 1. dataId is empty: create a default filter // 2. Add a new dataset id case _utils.FILTER_UPDATER_PROPS.dataId: { var oldDataId = (0, _toConsumableArray2["default"])(filter.dataId); filter = _updateFilterDataIdAtValueIndex(filter, valueIndex, value, state.datasets); datasetIdsToFilter = (0, _lodash5["default"])([].concat((0, _toConsumableArray2["default"])(oldDataId), (0, _toConsumableArray2["default"])(filter.dataId))); break; } case _utils.FILTER_UPDATER_PROPS.name: { // we are supporting the current functionality // TODO: Next PR for UI filter name will only update filter name but it won't have side effects // we are gonna use pair of datasets and fieldIdx to update the filter var datasetId = filter.dataId[valueIndex]; var _applyFilterFieldName = (0, _utils.applyFilterFieldName)(filter, state.datasets, datasetId, value, valueIndex, { mergeDomain: valueIndex > 0 }), updatedFilter = _applyFilterFieldName.filter, newDataset = _applyFilterFieldName.dataset; if (updatedFilter) { filter = updatedFilter; if (filter.gpu) { filter = (0, _table.setFilterGpuMode)(filter, state.filters); filter = (0, _table.assignGpuChannel)(filter, state.filters); } state = (0, _utils.set)(['datasets', datasetId], newDataset, state); // remove filter Plot at datasetId, so it will be recalculated filter = (0, _utils.removeFilterPlot)(filter, datasetId); datasetIdsToFilter = updatedFilter.dataId; } // only filter the current dataset break; } case _utils.FILTER_UPDATER_PROPS.layerId: { // We need to update only datasetId/s if we have added/removed layers // - check for layerId changes (XOR works because of string values) // if no differences between layerIds, don't do any filtering // @ts-ignore var layerIdDifference = (0, _lodash6["default"])(value, filte