UNPKG

kepler.gl.geoiq

Version:

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

196 lines (177 loc) 6.97 kB
// Copyright (c) 2023 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import {toggleModalUpdater, loadFilesSuccessUpdater} from './ui-state-updaters'; import { updateVisDataUpdater as visStateUpdateVisDataUpdater, setFeaturesUpdater as visStateFeaturesUpdater, deleteFeatureUpdater as visDeleteFeatureUpdater } from './vis-state-updaters'; import {receiveMapConfigUpdater as stateMapConfigUpdater} from './map-state-updaters'; import {receiveMapConfigUpdater as styleMapConfigUpdater} from './map-style-updaters'; import { setFeaturesUpdater as uiStateFeaturesUpdater, deleteFeatureUpdater as uiDeleteFeatureUpdater } from './ui-state-updaters'; import {findMapBounds} from 'utils/data-utils'; import KeplerGlSchema from 'schemas'; import {isPlainObject} from 'utils/utils'; // compose action to apply result multiple reducers, with the output of one /** * Some actions will affect the entire kepler.lg instance state. * The updaters for these actions is exported as `combinedUpdaters`. These updater take the entire instance state * as the first argument. Read more about [Using updaters](../advanced-usage/using-updaters.md) * @public * @example * * import keplerGlReducer, {combinedUpdaters} from 'kepler.gl/reducers'; * // Root Reducer * const reducers = combineReducers({ * keplerGl: keplerGlReducer, * app: appReducer * }); * * const composedReducer = (state, action) => { * switch (action.type) { * // add data to map after receiving data from remote sources * case 'LOAD_REMOTE_RESOURCE_SUCCESS': * return { * ...state, * keplerGl: { * ...state.keplerGl, * // pass in kepler.gl instance state to combinedUpdaters * map: combinedUpdaters.addDataToMapUpdater( * state.keplerGl.map, * { * payload: { * datasets: action.datasets, * options: {readOnly: true}, * config: action.config * } * } * ) * } * }; * } * return reducers(state, action); * }; * * export default composedReducer; */ /* eslint-disable no-unused-vars */ const combinedUpdaters = null; /* eslint-enable no-unused-vars */ export const isValidConfig = config => isPlainObject(config) && isPlainObject(config.config) && config.version; export const defaultAddDataToMapOptions = { centerMap: true, keepExistingConfig: false }; /** * Combine data and full configuration update in a single action * * @memberof combinedUpdaters * @param {Object} state kepler.gl instance state, containing all subreducer state * @param {Object} action * @param {Object} action.payload `{datasets, options, config}` * @param {Array<Object>|Object} action.payload.datasets - ***required** datasets can be a dataset or an array of datasets * Each dataset object needs to have `info` and `data` property. * @param {Object} action.payload.datasets.info -info of a dataset * @param {string} action.payload.datasets.info.id - id of this dataset. If config is defined, `id` should matches the `dataId` in config. * @param {string} action.payload.datasets.info.label - A display name of this dataset * @param {Object} action.payload.datasets.data - ***required** The data object, in a tabular format with 2 properties `fields` and `rows` * @param {Array<Object>} action.payload.datasets.data.fields - ***required** Array of fields, * @param {string} action.payload.datasets.data.fields.name - ***required** Name of the field, * @param {Array<Array>} action.payload.datasets.data.rows - ***required** Array of rows, in a tabular format with `fields` and `rows` * @param {Object} action.payload.options option object `{centerMap: true}` * @param {Object} action.payload.config map config * @returns {Object} nextState * @public */ export const addDataToMapUpdater = (state, {payload}) => { const {datasets, config} = payload; const options = { ...defaultAddDataToMapOptions, ...payload.options }; let parsedConfig = config; if (isValidConfig(config)) { // if passed in saved config parsedConfig = KeplerGlSchema.parseSavedConfig(config); } const oldLayers = state.visState.layers; // Update visState store let mergedState = { ...state, visState: visStateUpdateVisDataUpdater(state.visState, { datasets, options, config: parsedConfig }) }; let bounds; if (options.centerMap) { // find map bounds for new layers const newLayers = mergedState.visState.layers.filter( nl => !oldLayers.find(ol => ol === nl) ); // bounds = findMapBounds(newLayers); bounds = null; } // Update mapState store mergedState = { ...mergedState, mapState: stateMapConfigUpdater(mergedState.mapState, { payload: {config: parsedConfig, options, bounds} }) }; // Update mapStyle store mergedState = { ...mergedState, mapStyle: styleMapConfigUpdater(mergedState.mapStyle, { payload: {config: parsedConfig, options} }) }; // Update uiState mergedState = { ...mergedState, uiState: { ...toggleModalUpdater(loadFilesSuccessUpdater(mergedState.uiState), { payload: null }), ...(options.hasOwnProperty('readOnly') ? {readOnly: options.readOnly} : {}) } }; return mergedState; }; export const addDataToMapComposed = addDataToMapUpdater; export const setFeaturesUpdater = (state, payload) => ({ ...state, visState: visStateFeaturesUpdater(state.visState, payload), uiState: uiStateFeaturesUpdater(state.uiState, payload) }); export const setFeaturesComposed = setFeaturesUpdater; export const deleteFeatureUpdater = (state, payload) => ({ ...state, visState: visDeleteFeatureUpdater(state.visState, payload), uiState: uiDeleteFeatureUpdater(state.uiState, payload) }); export const deleteFeatureComposed = deleteFeatureUpdater;