Skip to content

Commit

Permalink
[Enhancement] Save merger and schema to visState (#1235)
Browse files Browse the repository at this point in the history
* move schemas and mergers to visState
Signed-off-by: Shan He <heshan0131@gmail.com>
  • Loading branch information
heshan0131 committed Aug 18, 2020
1 parent 4d0b2f9 commit 7ff0c45
Show file tree
Hide file tree
Showing 14 changed files with 121 additions and 93 deletions.
3 changes: 1 addition & 2 deletions src/components/modal-container.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import get from 'lodash.get';
import document from 'global/document';

import ModalDialogFactory from './modals/modal-dialog';
import KeplerGlSchema from 'schemas';
import {exportJson, exportHtml, exportData, exportImage, exportMap} from 'utils/export-utils';
import {isValidMapInfo} from 'utils/map-info-utils';

Expand Down Expand Up @@ -397,7 +396,7 @@ export default function ModalContainerFactory(
};
break;
case EXPORT_MAP_ID:
const keplerGlConfig = KeplerGlSchema.getConfigToSave({
const keplerGlConfig = visState.schema.getConfigToSave({
mapStyle,
visState,
mapState,
Expand Down
3 changes: 1 addition & 2 deletions src/reducers/combined-updaters.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
import {receiveMapConfigUpdater as stateMapConfigUpdater} from './map-state-updaters';
import {receiveMapConfigUpdater as styleMapConfigUpdater} from './map-style-updaters';
import {findMapBounds} from 'utils/data-utils';
import KeplerGlSchema from 'schemas';
import {isPlainObject} from 'utils/utils';
import {filesToDataPayload} from 'processors/file-handler';
import {payload_, apply_, with_, if_, compose_, merge_, pick_} from './composer-helpers';
Expand Down Expand Up @@ -130,7 +129,7 @@ export const addDataToMapUpdater = (state, {payload}) => {

if (isValidConfig(config)) {
// if passed in saved config
parsedConfig = KeplerGlSchema.parseSavedConfig(config);
parsedConfig = state.visState.schema.parseSavedConfig(config);
}
const oldLayers = state.visState.layers;
const filterNewlyAddedLayers = layers => layers.filter(nl => !oldLayers.find(ol => ol === nl));
Expand Down
5 changes: 1 addition & 4 deletions src/reducers/provider-state-updaters.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import {
DATASET_FORMATS
} from 'constants/default-settings';
import {toArray} from 'utils/utils';
import KeplerGlSchema from 'schemas';

export const INITIAL_PROVIDER_STATE = {
isProviderLoading: false,
Expand Down Expand Up @@ -266,8 +265,6 @@ function parseLoadMapResponse(response, loadParams, provider) {
return {info, data};
});

const parsedConfig = map.config && KeplerGlSchema.parseSavedConfig(map.config);

const info = {
...map.info,
provider: provider.name,
Expand All @@ -276,7 +273,7 @@ function parseLoadMapResponse(response, loadParams, provider) {
return {
datasets: parsedDatasets,
info,
...(parsedConfig ? {config: parsedConfig} : {})
...(map.config ? {config: map.config} : {})
};
}

Expand Down
11 changes: 11 additions & 0 deletions src/reducers/vis-state-merger.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,14 @@ export function mergeSplitMaps(
): VisState;

export function mergeInteractionTooltipConfig(state: VisState);

export function isValidMerger(arg: any): boolean;
export type Merger = {
merge: (state: VisState, config: any) => VisState,
prop: string,
toMergeProp?: string
};

export type VisStateMergers = Merger[];

export const VIS_STATE_MERGERS: VisStateMergers;
21 changes: 17 additions & 4 deletions src/reducers/vis-state-merger.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import uniq from 'lodash.uniq';
import pick from 'lodash.pick';
import isEqual from 'lodash.isequal';
import flattenDeep from 'lodash.flattendeep';
import {toArray} from 'utils/utils';
import {toArray, isObject} from 'utils/utils';

import {
applyFiltersToDatasets,
Expand Down Expand Up @@ -128,7 +128,7 @@ export function mergeFilters(state, filtersToMerge) {
...state,
filters: updatedFilters,
datasets: filtered,
filterToBeMerged: unmerged
filterToBeMerged: [...state.filterToBeMerged, ...unmerged]
};
}

Expand Down Expand Up @@ -176,7 +176,7 @@ export function mergeLayers(state, layersToMerge) {
...state,
layers,
layerOrder,
layerToBeMerged: unmerged
layerToBeMerged: [...state.layerToBeMerged, ...unmerged]
};
}

Expand Down Expand Up @@ -274,7 +274,7 @@ export function mergeSplitMaps(state, splitMaps = []) {
return {
...state,
splitMaps: merged,
splitMapsToBeMerged: unmerged
splitMapsToBeMerged: [...state.splitMapsToBeMerged, ...unmerged]
};
}

Expand Down Expand Up @@ -503,3 +503,16 @@ export function validateLayerWithData({fields, id: dataId}, savedLayer, layerCla

return newLayer;
}

export function isValidMerger(merger) {
return isObject(merger) && typeof merger.merge === 'function' && typeof merger.prop === 'string';
}

export const VIS_STATE_MERGERS = [
{merge: mergeLayers, prop: 'layers', toMergeProp: 'layerToBeMerged'},
{merge: mergeFilters, prop: 'filters', toMergeProp: 'filterToBeMerged'},
{merge: mergeInteractions, prop: 'interactionConfig', toMergeProp: 'interactionToBeMerged'},
{merge: mergeLayerBlending, prop: 'layerBlending'},
{merge: mergeSplitMaps, prop: 'splitMaps', toMergeProp: 'splitMapsToBeMerged'},
{merge: mergeAnimationConfig, prop: 'animationConfig'}
];
6 changes: 5 additions & 1 deletion src/reducers/vis-state-updaters.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {ParsedConfig} from '../schemas';
import * as VisStateActions from 'actions/vis-state-actions';
import ActionTypes from 'constants/action-types';
import {LoaderObject} from '@loaders.gl/loader-utils';
import {VisStateMergers} from './vis-state-merger';
import KeplerGLSchema from 'schemas';

export type HistogramBin = {
x0: number | undefined;
Expand Down Expand Up @@ -300,12 +302,14 @@ export type VisState = {
animationConfig: AnimationConfig;
editor: Editor;
splitMaps: SplitMap[];
splitMapsToBeMerged?: SplitMap[];
splitMapsToBeMerged: SplitMap[];
fileLoading: FileLoading | false;
fileLoadingProgress: FileLoadingProgress;
loaders: LoaderObject[];
loadOptions: object;
initialState?: Partial<VisState>;
mergers: VisStateMergers;
schema: KeplerGLSchema
};

export function addDefaultLayers(
Expand Down
87 changes: 36 additions & 51 deletions src/reducers/vis-state-updaters.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,7 @@ import {set, toArray} from 'utils/utils';

import {calculateLayerData, findDefaultLayer} from 'utils/layer-utils';

import {
mergeAnimationConfig,
mergeFilters,
mergeInteractions,
mergeLayerBlending,
mergeLayers,
mergeSplitMaps
} from './vis-state-merger';
import {isValidMerger, VIS_STATE_MERGERS} from './vis-state-merger';

import {
addNewLayersToSplitMap,
Expand All @@ -80,6 +73,8 @@ import {EDITOR_MODES, SORT_ORDER} from 'constants/default-settings';
import {pick_, merge_} from './composer-helpers';
import {processFileContent} from 'actions/vis-state-actions';

import KeplerGLSchema from 'schemas';

// type imports
/** @typedef {import('./vis-state-updaters').Field} Field */
/** @typedef {import('./vis-state-updaters').Filter} Filter */
Expand Down Expand Up @@ -194,7 +189,8 @@ export const INITIAL_VIS_STATE = {
// }
// ]
],
//
splitMapsToBeMerged: [],

// defaults layer classes
layerClasses: LayerClasses,

Expand All @@ -208,7 +204,12 @@ export const INITIAL_VIS_STATE = {
fileLoadingProgress: {},

loaders: [],
loadOptions: {}
loadOptions: {},

// visStateMergers
mergers: VIS_STATE_MERGERS,

schema: KeplerGLSchema
};

/**
Expand Down Expand Up @@ -939,25 +940,15 @@ export const receiveMapConfigUpdater = (state, {payload: {config = {}, options =
return state;
}

const {
filters,
layers,
interactionConfig,
layerBlending,
splitMaps,
animationConfig
} = config.visState;

const {keepExistingConfig} = options;

// reset config if keepExistingConfig is falsy
let mergedState = !keepExistingConfig ? resetMapConfigUpdater(state) : state;
mergedState = mergeLayers(mergedState, layers);
mergedState = mergeFilters(mergedState, filters);
mergedState = mergeInteractions(mergedState, interactionConfig);
mergedState = mergeLayerBlending(mergedState, layerBlending);
mergedState = mergeSplitMaps(mergedState, splitMaps);
mergedState = mergeAnimationConfig(mergedState, animationConfig);
for (const merger of state.mergers) {
if (isValidMerger(merger) && config.visState[merger.prop]) {
mergedState = merger.merge(mergedState, config.visState[merger.prop]);
}
}

return mergedState;
};
Expand Down Expand Up @@ -1117,23 +1108,21 @@ export const toggleLayerForMapUpdater = (state, {mapIndex, layerId}) => {
* @public
*/
/* eslint-disable max-statements */
// eslint-disable-next-line complexity
export const updateVisDataUpdater = (state, action) => {
// datasets can be a single data entries or an array of multiple data entries
const {config, options} = action;

const datasets = toArray(action.datasets);

const newDataEntries = datasets.reduce(
(accu, {info = {}, data}) => ({
(accu, {info = {}, data} = {}) => ({
...accu,
...(createNewDataEntry({info, data}, state.datasets) || {})
}),
{}
);

if (!Object.keys(newDataEntries).length) {
return state;
}
const dataEmpty = Object.keys(newDataEntries).length < 1;

// apply config if passed from action
const previousState = config
Expand All @@ -1142,31 +1131,26 @@ export const updateVisDataUpdater = (state, action) => {
})
: state;

const stateWithNewData = {
let mergedState = {
...previousState,
datasets: {
...previousState.datasets,
...newDataEntries
}
};

// previously saved config before data loaded
const {
filterToBeMerged = [],
layerToBeMerged = [],
interactionToBeMerged = {},
splitMapsToBeMerged = []
} = stateWithNewData;

// We need to merge layers before filters because polygon filters requires layers to be loaded
let mergedState = mergeLayers(stateWithNewData, layerToBeMerged);

mergedState = mergeFilters(mergedState, filterToBeMerged);

// merge state with saved splitMaps
mergedState = mergeSplitMaps(mergedState, splitMapsToBeMerged);
// merge state with config to be merged
for (const merger of mergedState.mergers) {
if (isValidMerger(merger) && merger.toMergeProp && mergedState[merger.toMergeProp]) {
const toMerge = mergedState[merger.toMergeProp];
mergedState[merger.toMergeProp] = INITIAL_VIS_STATE[merger.toMergeProp];
mergedState = merger.merge(mergedState, toMerge);
}
}

let newLayers = mergedState.layers.filter(l => l.config.dataId in newDataEntries);
let newLayers = !dataEmpty
? mergedState.layers.filter(l => l.config.dataId in newDataEntries)
: [];

if (!newLayers.length && (options || {}).autoCreateLayers !== false) {
// no layer merged, find defaults
Expand All @@ -1184,9 +1168,6 @@ export const updateVisDataUpdater = (state, action) => {
};
}

// merge state with saved interactions
mergedState = mergeInteractions(mergedState, interactionToBeMerged);

// if no tooltips merged add default tooltips
Object.keys(newDataEntries).forEach(dataId => {
const tooltipFields = mergedState.interactionConfig.tooltip.config.fieldsToShow[dataId];
Expand All @@ -1195,7 +1176,11 @@ export const updateVisDataUpdater = (state, action) => {
}
});

let updatedState = updateAllLayerDomainData(mergedState, Object.keys(newDataEntries), undefined);
let updatedState = updateAllLayerDomainData(
mergedState,
dataEmpty ? Object.keys(mergedState.datasets) : Object.keys(newDataEntries),
undefined
);

// register layer animation domain,
// need to be called after layer data is calculated
Expand Down
12 changes: 11 additions & 1 deletion src/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,15 @@
// THE SOFTWARE.

// Schemas
export {default, default as KeplerGlSchema} from './schema-manager';
export {
default,
default as KeplerGlSchema,
reducerSchema,
KeplerGLSchema as KeplerGLSchemaClass
} from './schema-manager';
export {CURRENT_VERSION, VERSIONS} from './versions';
export {default as visStateSchema} from './vis-state-schema';
export {default as datasetSchema} from './dataset-schema';
export {default as mapStyleSchema} from './map-style-schema';
export {default as mapStateSchema} from './map-state-schema';
export {default as Schema} from './schema';
6 changes: 4 additions & 2 deletions src/schemas/schema-manager.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import {
SplitMap,
AnimationConfig,
VisState,
RGBColor,
RGBColor,
Merge
} from 'reducers';
import {Schema} from './schema';

import {LayerTextLabel} from 'layers/layer-factory';

export type SavedFilter = {
Expand Down Expand Up @@ -203,7 +205,7 @@ export class KeplerGLSchema {
validateVersion(version: any): string | null;
hasDataChanged(state: any): boolean;
}

export const reducerSchema: {[key: string]: Schema};
const KeplerGLSchemaManager: KeplerGLSchema;

export default KeplerGLSchemaManager;
19 changes: 12 additions & 7 deletions src/schemas/schema-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,24 @@ import mapStateSchema from './map-state-schema';
import {CURRENT_VERSION, VERSIONS} from './versions';
import {isPlainObject} from 'utils/utils';

const REDUCER_SCHEMAS = {
export const reducerSchema = {
visState: visStateSchema,
mapState: mapStateSchema,
mapStyle: mapStyleSchema
};

/** @type {typeof import('./schema-manager').KeplerGLSchema} */
class KeplerGLSchema {
constructor() {
this._validVersions = VERSIONS;
this._version = CURRENT_VERSION;
this._reducerSchemas = REDUCER_SCHEMAS;
this._datasetSchema = datasetSchema;
export class KeplerGLSchema {
constructor({
reducers = reducerSchema,
datasets = datasetSchema,
validVersions = VERSIONS,
version = CURRENT_VERSION
} = {}) {
this._validVersions = validVersions;
this._version = version;
this._reducerSchemas = reducers;
this._datasetSchema = datasets;

this._datasetLastSaved = null;
this._savedDataset = null;
Expand Down

0 comments on commit 7ff0c45

Please sign in to comment.