UNPKG

kepler.gl

Version:

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

1,468 lines (1,190 loc) 241 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.updateStateWithLayerAndData = updateStateWithLayerAndData; exports.updateStateOnLayerVisibilityChange = updateStateOnLayerVisibilityChange; exports.layerConfigChangeUpdater = layerConfigChangeUpdater; exports.layerTextLabelChangeUpdater = layerTextLabelChangeUpdater; exports.layerDataIdChangeUpdater = layerDataIdChangeUpdater; exports.layerTypeChangeUpdater = layerTypeChangeUpdater; exports.layerVisualChannelChangeUpdater = layerVisualChannelChangeUpdater; exports.layerVisConfigChangeUpdater = layerVisConfigChangeUpdater; exports.setFilterAnimationTimeUpdater = setFilterAnimationTimeUpdater; exports.setFilterAnimationWindowUpdater = setFilterAnimationWindowUpdater; exports.setFilterUpdater = setFilterUpdater; exports.interactionConfigChangeUpdater = interactionConfigChangeUpdater; exports.renameDatasetUpdater = renameDatasetUpdater; exports.closeSpecificMapAtIndex = closeSpecificMapAtIndex; exports.loadFileStepSuccessUpdater = loadFileStepSuccessUpdater; exports.loadNextFileUpdater = loadNextFileUpdater; exports.makeLoadFileTask = makeLoadFileTask; exports.processFileContentUpdater = processFileContentUpdater; exports.parseProgress = parseProgress; exports.addDefaultLayers = addDefaultLayers; exports.addDefaultTooltips = addDefaultTooltips; exports.initialFileLoadingProgress = initialFileLoadingProgress; exports.updateFileLoadingProgressUpdater = updateFileLoadingProgressUpdater; exports.updateAllLayerDomainData = updateAllLayerDomainData; exports.updateAnimationDomain = updateAnimationDomain; exports.setFeaturesUpdater = setFeaturesUpdater; exports.deleteFeatureUpdater = deleteFeatureUpdater; exports.setPolygonFilterLayerUpdater = setPolygonFilterLayerUpdater; exports.sortTableColumnUpdater = sortTableColumnUpdater; exports.pinTableColumnUpdater = pinTableColumnUpdater; exports.copyTableColumnUpdater = copyTableColumnUpdater; exports.toggleEditorVisibilityUpdater = toggleEditorVisibilityUpdater; exports.setFilterAnimationTimeConfigUpdater = setFilterAnimationTimeConfigUpdater; exports.setLayerAnimationTimeConfigUpdater = setLayerAnimationTimeConfigUpdater; exports.setSelectedFeatureUpdater = exports.setEditorModeUpdater = exports.setMapInfoUpdater = exports.applyCPUFilterUpdater = exports.loadFilesErrUpdater = exports.nextFileBatchUpdater = exports.loadFilesUpdater = exports.updateVisDataUpdater = exports.toggleLayerForMapUpdater = exports.toggleSplitMapUpdater = exports.mouseMoveUpdater = exports.mapClickUpdater = exports.layerClickUpdater = exports.layerHoverUpdater = exports.receiveMapConfigUpdater = exports.resetMapConfigUpdater = exports.showDatasetTableUpdater = exports.updateLayerBlendingUpdater = exports.removeDatasetUpdater = exports.reorderLayerUpdater = exports.duplicateLayerUpdater = exports.removeLayerUpdater = exports.addLayerUpdater = exports.removeFilterUpdater = exports.toggleFilterFeatureUpdater = exports.enlargeFilterUpdater = exports.updateLayerAnimationSpeedUpdater = exports.setLayerAnimationTimeUpdater = exports.updateFilterAnimationSpeedUpdater = exports.toggleLayerAnimationControlUpdater = exports.toggleLayerAnimationUpdater = exports.toggleFilterAnimationUpdater = exports.layerColorUIChangeUpdater = exports.addFilterUpdater = exports.setFilterPlotUpdater = exports.INITIAL_VIS_STATE = exports.DEFAULT_EDITOR = exports.DEFAULT_ANIMATION_CONFIG = void 0; var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); 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 _window = require("global/window"); var _tasks = require("react-palm/tasks"); var _lodash = _interopRequireDefault(require("lodash.clonedeep")); var _lodash2 = _interopRequireDefault(require("lodash.uniq")); var _lodash3 = _interopRequireDefault(require("lodash.get")); var _lodash4 = _interopRequireDefault(require("lodash.xor")); var _copyToClipboard = _interopRequireDefault(require("copy-to-clipboard")); var _dataUtils = require("../utils/data-utils"); var _tasks2 = require("../tasks/tasks"); var _visStateActions = require("../actions/vis-state-actions"); var _interactionUtils = require("../utils/interaction-utils"); var _filterUtils = require("../utils/filter-utils"); var _gpuFilterUtils = require("../utils/gpu-filter-utils"); var _datasetUtils = require("../utils/dataset-utils"); var _keplerTable = require("../utils/table-utils/kepler-table"); var _utils = require("../utils/utils"); var _layerUtils = require("../utils/layer-utils"); var _visStateMerger = require("./vis-state-merger"); var _splitMapUtils = require("../utils/split-map-utils"); var _layers = require("../layers"); var _layerFactory = require("../layers/layer-factory"); var _defaultSettings = require("../constants/default-settings"); var _composerHelpers = require("./composer-helpers"); var _schemas = _interopRequireDefault(require("../schemas")); function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, 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 normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); } function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } // type imports /** @typedef {import('./vis-state-updaters').Field} Field */ /** @typedef {import('./vis-state-updaters').Filter} Filter */ /** @typedef {import('./vis-state-updaters').KeplerTable} KeplerTable */ /** @typedef {import('./vis-state-updaters').VisState} VisState */ /** @typedef {import('./vis-state-updaters').Datasets} Datasets */ /** @typedef {import('./vis-state-updaters').AnimationConfig} AnimationConfig */ /** @typedef {import('./vis-state-updaters').Editor} Editor */ // 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 no-unused-vars */ // @ts-ignore var visStateUpdaters = null; /* eslint-enable no-unused-vars */ /** @type {AnimationConfig} */ var DEFAULT_ANIMATION_CONFIG = { domain: null, currentTime: null, speed: 1, isAnimating: false, timeFormat: null, timezone: null, defaultTimeFormat: null }; /** @type {Editor} */ exports.DEFAULT_ANIMATION_CONFIG = DEFAULT_ANIMATION_CONFIG; var DEFAULT_EDITOR = { mode: _defaultSettings.EDITOR_MODES.DRAW_POLYGON, features: [], selectedFeature: null, visible: true }; /** * Default initial `visState` * @memberof visStateUpdaters * @constant * @type {VisState} * @public */ exports.DEFAULT_EDITOR = DEFAULT_EDITOR; var INITIAL_VIS_STATE = { // map info mapInfo: { title: '', description: '' }, // layers layers: [], layerData: [], layerToBeMerged: [], layerOrder: [], // filters filters: [], filterToBeMerged: [], // a collection of multiple dataset datasets: {}, editingDataset: undefined, interactionConfig: (0, _interactionUtils.getDefaultInteraction)(), interactionToBeMerged: undefined, layerBlending: 'normal', hoverInfo: undefined, clicked: undefined, mousePos: {}, // 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: [], // 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 * @type {typeof import('./vis-state-updaters').updateStateWithLayerAndData} * */ exports.INITIAL_VIS_STATE = INITIAL_VIS_STATE; 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, _splitMapUtils.addNewLayersToSplitMap)(state.splitMaps, layer) : (0, _splitMapUtils.removeLayerFromSplitMaps)(state.splitMaps, layer) }); } if (layer.config.animation.enabled) { newState = updateAnimationDomain(state); } return newState; } /** * Update layer base config: dataId, label, column, isVisible * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerConfigChangeUpdater} * @returns nextState */ 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') { var _action$newConfig = action.newConfig, dataId = _action$newConfig.dataId, restConfig = (0, _objectWithoutProperties2["default"])(_action$newConfig, ["dataId"]); 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; // let newLayer; if (newLayer.shouldCalculateLayerData(props)) { var oldLayerData = state.layerData[idx]; var updateLayerDataResult = (0, _layerUtils.calculateLayerData)(newLayer, state, oldLayerData); layerData = updateLayerDataResult.layerData; newLayer = updateLayerDataResult.layer; } var newState = state; if ('isVisible' in action.newConfig) { newState = updateStateOnLayerVisibilityChange(state, newLayer); } return updateStateWithLayerAndData(newState, { layer: newLayer, layerData: layerData, idx: idx }); } function addOrRemoveTextLabels(newFields, textLabel) { 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 ? [_layerFactory.DEFAULT_TEXT_LABEL] : newTextLabel; // add newTextLabel = [].concat((0, _toConsumableArray2["default"])(newTextLabel.filter(function (tl) { return tl.field; })), (0, _toConsumableArray2["default"])(addFields.map(function (af) { return _objectSpread(_objectSpread({}, _layerFactory.DEFAULT_TEXT_LABEL), {}, { field: af }); }))); return newTextLabel; } function updateTextLabelPropAndValue(idx, prop, value, textLabel) { if (!textLabel[idx].hasOwnProperty(prop)) { return textLabel; } var newTextLabel = textLabel.slice(); if (prop && (value || textLabel.length === 1)) { newTextLabel = textLabel.map(function (tl, i) { return i === idx ? _objectSpread(_objectSpread({}, tl), {}, (0, _defineProperty2["default"])({}, prop, value)) : tl; }); } else if (prop === 'field' && value === null && textLabel.length > 1) { // remove label when field value is set to null newTextLabel.splice(idx, 1); } return newTextLabel; } /** * Update layer base config: dataId, label, column, isVisible * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerTextLabelChangeUpdater} * @returns nextState */ function layerTextLabelChangeUpdater(state, action) { var oldLayer = action.oldLayer, idx = action.idx, prop = action.prop, value = action.value; var textLabel = oldLayer.config.textLabel; 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), [_layerFactory.DEFAULT_TEXT_LABEL]); } if (idx === 'all' && prop === 'fields') { newTextLabel = addOrRemoveTextLabels(value, textLabel); } 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) { var loadedLayer = (0, _visStateMerger.serializeLayer)(layer); return (0, _visStateMerger.validateLayerWithData)(dataset, loadedLayer, layerClasses, { allowEmptyColumn: true }); } /** * Update layer config dataId * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerDataIdChangeUpdater} * @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); // if cant validate it with data create a new one if (!validated) { newLayer = new state.layerClasses[oldLayer.type]({ dataId: dataId, id: oldLayer.id }); } else { newLayer = validated; } } newLayer = newLayer.updateLayerConfig({ isVisible: oldLayer.config.isVisible, isConfigActive: true }); newLayer.updateLayerDomain(state.datasets); var _calculateLayerData = (0, _layerUtils.calculateLayerData)(newLayer, state, undefined), layerData = _calculateLayerData.layerData, layer = _calculateLayerData.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } /** * Update layer type. Previews layer config will be copied if applicable. * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerTypeChangeUpdater} * @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; } // 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 newLayer = new state.layerClasses[newType](); newLayer.assignConfigToLayer(oldLayer.config, oldLayer.visConfigSettings); newLayer.updateLayerDomain(state.datasets); var _calculateLayerData2 = (0, _layerUtils.calculateLayerData)(newLayer, state), layerData = _calculateLayerData2.layerData, layer = _calculateLayerData2.layer; var newState = updateStateWithLayerAndData(state, { 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; }) }); } return newState; } /** * Update layer visual channel * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerVisualChannelChangeUpdater} * @returns {Object} nextState * @public */ function layerVisualChannelChangeUpdater(state, action) { var oldLayer = action.oldLayer, newConfig = action.newConfig, 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); newLayer.updateLayerVisualChannel(dataset, channel); var oldLayerData = state.layerData[idx]; var _calculateLayerData3 = (0, _layerUtils.calculateLayerData)(newLayer, state, oldLayerData), layerData = _calculateLayerData3.layerData, layer = _calculateLayerData3.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } /** * Update layer `visConfig` * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerVisConfigChangeUpdater} * @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 _calculateLayerData4 = (0, _layerUtils.calculateLayerData)(newLayer, state, oldLayerData), layerData = _calculateLayerData4.layerData, layer = _calculateLayerData4.layer; return updateStateWithLayerAndData(state, { layerData: layerData, layer: layer, idx: idx }); } return updateStateWithLayerAndData(state, { layer: newLayer, idx: idx }); } /** * Update filter property * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').setFilterAnimationTimeUpdater} * @public */ function setFilterAnimationTimeUpdater(state, action) { return setFilterUpdater(state, action); } /** * Update filter animation window * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').setFilterAnimationWindowUpdater} * @public */ function setFilterAnimationWindowUpdater(state, _ref2) { var id = _ref2.id, animationWindow = _ref2.animationWindow; return _objectSpread(_objectSpread({}, state), {}, { filters: state.filters.map(function (f) { return f.id === id ? _objectSpread(_objectSpread({}, f), {}, { animationWindow: animationWindow }) : f; }) }); } /** * Update filter property * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').setFilterUpdater} * @public */ function setFilterUpdater(state, action) { var idx = action.idx, prop = action.prop, value = action.value, _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; } var newFilter = (0, _utils.set)([prop], value, oldFilter); var newState = state; var _newFilter = newFilter, dataId = _newFilter.dataId; // Ensuring backward compatibility var datasetIds = (0, _utils.toArray)(dataId); switch (prop) { // TODO: Next PR for UI if we update dataId, we need to consider two cases: // 1. dataId is empty: create a default filter // 2. Add a new dataset id case _filterUtils.FILTER_UPDATER_PROPS.dataId: // if trying to update filter dataId. create an empty new filter newFilter = (0, _filterUtils.updateFilterDataId)(dataId); break; case _filterUtils.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 = newFilter.dataId[valueIndex]; var _applyFilterFieldName = (0, _filterUtils.applyFilterFieldName)(newFilter, state.datasets[datasetId], value, valueIndex, { mergeDomain: false }), updatedFilter = _applyFilterFieldName.filter, newDataset = _applyFilterFieldName.dataset; if (!updatedFilter) { return state; } newFilter = updatedFilter; if (newFilter.gpu) { newFilter = (0, _gpuFilterUtils.setFilterGpuMode)(newFilter, state.filters); newFilter = (0, _gpuFilterUtils.assignGpuChannel)(newFilter, state.filters); } newState = (0, _utils.set)(['datasets', datasetId], newDataset, state); // only filter the current dataset break; case _filterUtils.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, _lodash4["default"])(newFilter.layerId, oldFilter.layerId); var layerDataIds = (0, _lodash2["default"])(layerIdDifference.map(function (lid) { return (0, _lodash3["default"])(state.layers.find(function (l) { return l.id === lid; }), ['config', 'dataId']); }).filter(function (d) { return d; })); // only filter datasetsIds datasetIds = layerDataIds; // Update newFilter dataIds var newDataIds = (0, _lodash2["default"])(newFilter.layerId.map(function (lid) { return (0, _lodash3["default"])(state.layers.find(function (l) { return l.id === lid; }), ['config', 'dataId']); }).filter(function (d) { return d; })); newFilter = _objectSpread(_objectSpread({}, newFilter), {}, { dataId: newDataIds }); break; default: break; } var enlargedFilter = state.filters.find(function (f) { return f.enlarged; }); if (enlargedFilter && enlargedFilter.id !== newFilter.id) { // there should be only one enlarged filter newFilter.enlarged = false; } // save new filters to newState newState = (0, _utils.set)(['filters', idx], newFilter, newState); // if we are currently setting a prop that only requires to filter the current // dataset we will pass only the current dataset to applyFiltersToDatasets and // updateAllLayerDomainData otherwise we pass the all list of datasets as defined in dataId var datasetIdsToFilter = _filterUtils.LIMITED_FILTER_EFFECT_PROPS[prop] ? [datasetIds[valueIndex]] : datasetIds; // filter data var filteredDatasets = (0, _filterUtils.applyFiltersToDatasets)(datasetIdsToFilter, newState.datasets, newState.filters, newState.layers); newState = (0, _utils.set)(['datasets'], filteredDatasets, newState); // dataId is an array // pass only the dataset we need to update newState = updateAllLayerDomainData(newState, datasetIdsToFilter, newFilter); return newState; } /** * Set the property of a filter plot * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').setFilterPlotUpdater} * @public */ var setFilterPlotUpdater = function setFilterPlotUpdater(state, _ref3) { var idx = _ref3.idx, newProp = _ref3.newProp, _ref3$valueIndex = _ref3.valueIndex, valueIndex = _ref3$valueIndex === void 0 ? 0 : _ref3$valueIndex; var newFilter = _objectSpread(_objectSpread({}, state.filters[idx]), newProp); var prop = Object.keys(newProp)[0]; if (prop === 'yAxis') { var plotType = (0, _filterUtils.getDefaultFilterPlotType)(newFilter); // TODO: plot is not supported in multi dataset filter for now if (plotType) { newFilter = _objectSpread(_objectSpread(_objectSpread({}, newFilter), (0, _filterUtils.getFilterPlot)(_objectSpread(_objectSpread({}, newFilter), {}, { plotType: plotType }), state.datasets[newFilter.dataId[valueIndex]])), {}, { plotType: plotType }); } } return _objectSpread(_objectSpread({}, state), {}, { filters: state.filters.map(function (f, i) { return i === idx ? newFilter : f; }) }); }; /** * Add a new filter * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').addFilterUpdater} * @public */ exports.setFilterPlotUpdater = setFilterPlotUpdater; var addFilterUpdater = function addFilterUpdater(state, action) { return !action.dataId ? state : _objectSpread(_objectSpread({}, state), {}, { filters: [].concat((0, _toConsumableArray2["default"])(state.filters), [(0, _filterUtils.getDefaultFilter)(action.dataId)]) }); }; /** * Set layer color palette ui state * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerColorUIChangeUpdater} */ exports.addFilterUpdater = addFilterUpdater; var layerColorUIChangeUpdater = function layerColorUIChangeUpdater(state, _ref4) { var oldLayer = _ref4.oldLayer, prop = _ref4.prop, newConfig = _ref4.newConfig; var oldVixConfig = oldLayer.config.visConfig[prop]; var newLayer = oldLayer.updateLayerColorUI(prop, newConfig); var newVisConfig = newLayer.config.visConfig[prop]; if (oldVixConfig !== newVisConfig) { return layerVisConfigChangeUpdater(state, { oldLayer: oldLayer, newVisConfig: (0, _defineProperty2["default"])({}, prop, newVisConfig) }); } return _objectSpread(_objectSpread({}, state), {}, { layers: state.layers.map(function (l) { return l.id === oldLayer.id ? newLayer : l; }) }); }; /** * Start and end filter animation * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').toggleFilterAnimationUpdater} * @public */ exports.layerColorUIChangeUpdater = layerColorUIChangeUpdater; var toggleFilterAnimationUpdater = function toggleFilterAnimationUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { filters: state.filters.map(function (f, i) { return i === action.idx ? _objectSpread(_objectSpread({}, f), {}, { isAnimating: !f.isAnimating }) : f; }) }); }; /** * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').toggleLayerAnimationUpdater} * @public */ exports.toggleFilterAnimationUpdater = toggleFilterAnimationUpdater; var toggleLayerAnimationUpdater = function toggleLayerAnimationUpdater(state) { return _objectSpread(_objectSpread({}, state), {}, { animationConfig: _objectSpread(_objectSpread({}, state.animationConfig), {}, { isAnimating: !state.animationConfig.isAnimating }) }); }; /** * Hide and show layer animation control * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').toggleLayerAnimationControlUpdater} * @public */ exports.toggleLayerAnimationUpdater = toggleLayerAnimationUpdater; var toggleLayerAnimationControlUpdater = function toggleLayerAnimationControlUpdater(state) { return _objectSpread(_objectSpread({}, state), {}, { animationConfig: _objectSpread(_objectSpread({}, state.animationConfig), {}, { hideControl: !state.animationConfig.hideControl }) }); }; /** * Change filter animation speed * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').updateFilterAnimationSpeedUpdater} * @public */ exports.toggleLayerAnimationControlUpdater = toggleLayerAnimationControlUpdater; var updateFilterAnimationSpeedUpdater = function updateFilterAnimationSpeedUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { filters: state.filters.map(function (f, i) { return i === action.idx ? _objectSpread(_objectSpread({}, f), {}, { speed: action.speed }) : f; }) }); }; /** * Reset animation config current time to a specified value * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').setLayerAnimationTimeUpdater} * @public * */ exports.updateFilterAnimationSpeedUpdater = updateFilterAnimationSpeedUpdater; var setLayerAnimationTimeUpdater = function setLayerAnimationTimeUpdater(state, _ref5) { var value = _ref5.value; return _objectSpread(_objectSpread({}, state), {}, { animationConfig: _objectSpread(_objectSpread({}, state.animationConfig), {}, { currentTime: value }) }); }; /** * Update animation speed with the vertical speed slider * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').updateLayerAnimationSpeedUpdater} * @public * */ exports.setLayerAnimationTimeUpdater = setLayerAnimationTimeUpdater; var updateLayerAnimationSpeedUpdater = function updateLayerAnimationSpeedUpdater(state, _ref6) { var speed = _ref6.speed; return _objectSpread(_objectSpread({}, state), {}, { animationConfig: _objectSpread(_objectSpread({}, state.animationConfig), {}, { speed: speed }) }); }; /** * Show larger time filter at bottom for time playback (apply to time filter only) * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').enlargeFilterUpdater} * @public */ exports.updateLayerAnimationSpeedUpdater = updateLayerAnimationSpeedUpdater; var enlargeFilterUpdater = function enlargeFilterUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { filters: state.filters.map(function (f, i) { return i === action.idx ? _objectSpread(_objectSpread({}, f), {}, { enlarged: !f.enlarged }) : f; }) }); }; /** * Toggles filter feature visibility * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').toggleFilterFeatureUpdater} */ exports.enlargeFilterUpdater = enlargeFilterUpdater; var toggleFilterFeatureUpdater = function toggleFilterFeatureUpdater(state, action) { var filter = state.filters[action.idx]; var isVisible = (0, _lodash3["default"])(filter, ['value', 'properties', 'isVisible']); var newFilter = _objectSpread(_objectSpread({}, filter), {}, { value: (0, _filterUtils.featureToFilterValue)(filter.value, filter.id, { isVisible: !isVisible }) }); return _objectSpread(_objectSpread({}, state), {}, { filters: Object.assign((0, _toConsumableArray2["default"])(state.filters), (0, _defineProperty2["default"])({}, action.idx, newFilter)) }); }; /** * Remove a filter * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').removeFilterUpdater} * @public */ exports.toggleFilterFeatureUpdater = toggleFilterFeatureUpdater; var removeFilterUpdater = function removeFilterUpdater(state, action) { var idx = action.idx; var _state$filters$idx = state.filters[idx], dataId = _state$filters$idx.dataId, id = _state$filters$idx.id; var newFilters = [].concat((0, _toConsumableArray2["default"])(state.filters.slice(0, idx)), (0, _toConsumableArray2["default"])(state.filters.slice(idx + 1, state.filters.length))); var filteredDatasets = (0, _filterUtils.applyFiltersToDatasets)(dataId, state.datasets, newFilters, state.layers); var newEditor = (0, _filterUtils.getFilterIdInFeature)(state.editor.selectedFeature) === id ? _objectSpread(_objectSpread({}, state.editor), {}, { selectedFeature: null }) : state.editor; var newState = (0, _utils.set)(['filters'], newFilters, state); newState = (0, _utils.set)(['datasets'], filteredDatasets, newState); newState = (0, _utils.set)(['editor'], newEditor, newState); return updateAllLayerDomainData(newState, dataId, undefined); }; /** * Add a new layer * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').addLayerUpdater} * @public */ exports.removeFilterUpdater = removeFilterUpdater; var addLayerUpdater = function addLayerUpdater(state, action) { var newLayer; var newLayerData; if (action.config) { newLayer = (0, _visStateMerger.createLayerFromConfig)(state, action.config); if (!newLayer) { _window.console.warn('Failed to create layer from config, it usually means the config is not be in correct format', action.config); return state; } var result = (0, _layerUtils.calculateLayerData)(newLayer, state); newLayer = result.layer; newLayerData = result.layerData; } else { // create an empty layer with the first available dataset var defaultDataset = Object.keys(state.datasets)[0]; newLayer = new _layers.Layer({ isVisible: true, isConfigActive: true, dataId: defaultDataset }); newLayerData = {}; } return _objectSpread(_objectSpread({}, state), {}, { layers: [].concat((0, _toConsumableArray2["default"])(state.layers), [newLayer]), layerData: [].concat((0, _toConsumableArray2["default"])(state.layerData), [newLayerData]), layerOrder: [].concat((0, _toConsumableArray2["default"])(state.layerOrder), [state.layerOrder.length]), splitMaps: (0, _splitMapUtils.addNewLayersToSplitMap)(state.splitMaps, newLayer) }); }; /** * remove layer * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').removeLayerUpdater} * @public */ exports.addLayerUpdater = addLayerUpdater; var removeLayerUpdater = function removeLayerUpdater(state, _ref7) { var idx = _ref7.idx; var layers = state.layers, layerData = state.layerData, clicked = state.clicked, hoverInfo = state.hoverInfo; var layerToRemove = state.layers[idx]; var newMaps = (0, _splitMapUtils.removeLayerFromSplitMaps)(state.splitMaps, layerToRemove); var newState = _objectSpread(_objectSpread({}, state), {}, { layers: [].concat((0, _toConsumableArray2["default"])(layers.slice(0, idx)), (0, _toConsumableArray2["default"])(layers.slice(idx + 1, layers.length))), layerData: [].concat((0, _toConsumableArray2["default"])(layerData.slice(0, idx)), (0, _toConsumableArray2["default"])(layerData.slice(idx + 1, layerData.length))), layerOrder: state.layerOrder.filter(function (i) { return i !== idx; }).map(function (pid) { return pid > idx ? pid - 1 : pid; }), clicked: layerToRemove.isLayerHovered(clicked) ? undefined : clicked, hoverInfo: layerToRemove.isLayerHovered(hoverInfo) ? undefined : hoverInfo, splitMaps: newMaps // TODO: update filters, create helper to remove layer form filter (remove layerid and dataid) if mapped }); return updateAnimationDomain(newState); }; /** * duplicate layer * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').duplicateLayerUpdater} * @public */ exports.removeLayerUpdater = removeLayerUpdater; var duplicateLayerUpdater = function duplicateLayerUpdater(state, _ref8) { var idx = _ref8.idx; var layers = state.layers; var original = state.layers[idx]; var originalLayerOrderIdx = state.layerOrder.findIndex(function (i) { return i === idx; }); if (!original) { _window.console.warn("layer.".concat(idx, " is undefined")); return state; } var newLabel = "Copy of ".concat(original.config.label); var postfix = 0; // eslint-disable-next-line no-loop-func while (layers.find(function (l) { return l.config.label === newLabel; })) { newLabel = "Copy of ".concat(original.config.label, " ").concat(++postfix); } // collect layer config from original var loadedLayer = (0, _visStateMerger.serializeLayer)(original); // assign new id and label to copied layer if (!loadedLayer.config) { return state; } loadedLayer.config.label = newLabel; loadedLayer.id = (0, _utils.generateHashId)(_layers.LAYER_ID_LENGTH); // add layer to state var nextState = addLayerUpdater(state, { config: loadedLayer }); // new added layer are at the end, move it to be on top of original layer var newLayerOrderIdx = nextState.layerOrder.length - 1; var newLayerOrder = (0, _utils.arrayInsert)(nextState.layerOrder.slice(0, newLayerOrderIdx), originalLayerOrderIdx, newLayerOrderIdx); nextState = _objectSpread(_objectSpread({}, nextState), {}, { layerOrder: newLayerOrder }); return updateAnimationDomain(nextState); }; /** * Reorder layer * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').reorderLayerUpdater} * @public */ exports.duplicateLayerUpdater = duplicateLayerUpdater; var reorderLayerUpdater = function reorderLayerUpdater(state, _ref9) { var order = _ref9.order; return _objectSpread(_objectSpread({}, state), {}, { layerOrder: order }); }; /** * Remove a dataset and all layers, filters, tooltip configs that based on it * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').removeDatasetUpdater} * @public */ exports.reorderLayerUpdater = reorderLayerUpdater; var removeDatasetUpdater = function removeDatasetUpdater(state, action) { // extract dataset key var datasetKey = action.dataId; var datasets = state.datasets; // check if dataset is present if (!datasets[datasetKey]) { return state; } /* eslint-disable no-unused-vars */ var layers = state.layers, _state$datasets = state.datasets, dataset = _state$datasets[datasetKey], newDatasets = (0, _objectWithoutProperties2["default"])(_state$datasets, [datasetKey].map(_toPropertyKey)); /* eslint-enable no-unused-vars */ var indexes = layers.reduce(function (listOfIndexes, layer, index) { if (layer.config.dataId === datasetKey) { // @ts-ignore listOfIndexes.push(index); } return listOfIndexes; }, []); // remove layers and datasets var _indexes$reduce = indexes.reduce(function (_ref10, idx) { var currentState = _ref10.newState, indexCounter = _ref10.indexCounter; var currentIndex = idx - indexCounter; currentState = removeLayerUpdater(currentState, { idx: currentIndex }); indexCounter++; return { newState: currentState, indexCounter: indexCounter }; }, { newState: _objectSpread(_objectSpread({}, state), {}, { datasets: newDatasets }), indexCounter: 0 }), newState = _indexes$reduce.newState; // remove filters var filters = state.filters.filter(function (filter) { return !filter.dataId.includes(datasetKey); }); // update interactionConfig var interactionConfig = state.interactionConfig; var _interactionConfig = interactionConfig, tooltip = _interactionConfig.tooltip; if (tooltip) { var config = tooltip.config; /* eslint-disable no-unused-vars */ var _config$fieldsToShow = config.fieldsToShow, fields = _config$fieldsToShow[datasetKey], fieldsToShow = (0, _objectWithoutProperties2["default"])(_config$fieldsToShow, [datasetKey].map(_toPropertyKey)); /* eslint-enable no-unused-vars */ interactionConfig = _objectSpread(_objectSpread({}, interactionConfig), {}, { tooltip: _objectSpread(_objectSpread({}, tooltip), {}, { config: _objectSpread(_objectSpread({}, config), {}, { fieldsToShow: fieldsToShow }) }) }); } return _objectSpread(_objectSpread({}, newState), {}, { filters: filters, interactionConfig: interactionConfig }); }; /** * update layer blending mode * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').updateLayerBlendingUpdater} * @public */ exports.removeDatasetUpdater = removeDatasetUpdater; var updateLayerBlendingUpdater = function updateLayerBlendingUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { layerBlending: action.mode }); }; /** * Display dataset table in a modal * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').showDatasetTableUpdater} * @public */ exports.updateLayerBlendingUpdater = updateLayerBlendingUpdater; var showDatasetTableUpdater = function showDatasetTableUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { editingDataset: action.dataId }); }; /** * reset visState to initial State * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').resetMapConfigUpdater} * @public */ exports.showDatasetTableUpdater = showDatasetTableUpdater; var resetMapConfigUpdater = function resetMapConfigUpdater(state) { return _objectSpread(_objectSpread(_objectSpread({}, INITIAL_VIS_STATE), state.initialState), {}, { initialState: state.initialState }); }; /** * Propagate `visState` reducer with a new configuration. Current config will be override. * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').receiveMapConfigUpdater} * @public */ exports.resetMapConfigUpdater = resetMapConfigUpdater; var receiveMapConfigUpdater = function receiveMapConfigUpdater(state, _ref11) { var _ref11$payload = _ref11.payload, _ref11$payload$config = _ref11$payload.config, config = _ref11$payload$config === void 0 ? {} : _ref11$payload$config, _ref11$payload$option = _ref11$payload.options, options = _ref11$payload$option === void 0 ? {} : _ref11$payload$option; if (!config.visState) { return state; } var keepExistingConfig = options.keepExistingConfig; // reset config if keepExistingConfig is falsy var mergedState = !keepExistingConfig ? resetMapConfigUpdater(state) : state; var _iterator = _createForOfIteratorHelper(state.mergers), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var merger = _step.value; if ((0, _visStateMerger.isValidMerger)(merger) && config.visState[merger.prop]) { mergedState = merger.merge(mergedState, config.visState[merger.prop], true); } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return mergedState; }; /** * Trigger layer hover event with hovered object * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerHoverUpdater} * @public */ exports.receiveMapConfigUpdater = receiveMapConfigUpdater; var layerHoverUpdater = function layerHoverUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { hoverInfo: action.info }); }; /* eslint-enable max-statements */ /** * Update `interactionConfig` * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').interactionConfigChangeUpdater} * @public */ exports.layerHoverUpdater = layerHoverUpdater; function interactionConfigChangeUpdater(state, action) { var config = action.config; var interactionConfig = _objectSpread(_objectSpread({}, state.interactionConfig), (0, _defineProperty2["default"])({}, config.id, config)); // Don't enable tooltip and brush at the same time // but coordinates can be shown at all time var contradict = ['brush', 'tooltip']; if (contradict.includes(config.id) && config.enabled && !state.interactionConfig[config.id].enabled) { // only enable one interaction at a time contradict.forEach(function (k) { if (k !== config.id) { interactionConfig[k] = _objectSpread(_objectSpread({}, interactionConfig[k]), {}, { enabled: false }); } }); } var newState = _objectSpread(_objectSpread({}, state), {}, { interactionConfig: interactionConfig }); if (config.id === 'geocoder' && !config.enabled) { return removeDatasetUpdater(newState, { dataId: 'geocoder_dataset' }); } return newState; } /** * Trigger layer click event with clicked object * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').layerClickUpdater} * @public */ var layerClickUpdater = function layerClickUpdater(state, action) { return _objectSpread(_objectSpread({}, state), {}, { mousePos: state.interactionConfig.coordinate.enabled ? _objectSpread(_objectSpread({}, state.mousePos), {}, { pinned: state.mousePos.pinned ? null : (0, _lodash["default"])(state.mousePos) }) : state.mousePos, clicked: action.info && action.info.picked ? action.info : null }); }; /** * Trigger map click event, unselect clicked object * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').mapClickUpdater} * @public */ exports.layerClickUpdater = layerClickUpdater; var mapClickUpdater = function mapClickUpdater(state) { return _objectSpread(_objectSpread({}, state), {}, { clicked: null }); }; /** * Trigger map move event * @memberof visStateUpdaters * @type {typeof import('./vis-state-updaters').mouseMoveUpdater} * @public */ exports.mapClickUpdater = mapClickUpdater; var mouseMoveUpdater = function mouseMoveUpdater(state, _ref12) { var evt = _ref12.evt; if (Obje