Skip to content

Commit

Permalink
[Enhancement] Add preserveLayerOrder to layer merger (#1288)
Browse files Browse the repository at this point in the history
* make best effort at preserve layer order supporting load data incrementally
Signed-off-by: Shan He <heshan0131@gmail.com>
  • Loading branch information
heshan0131 committed Sep 30, 2020
1 parent 480ead6 commit 92a2bb6
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 39 deletions.
19 changes: 12 additions & 7 deletions src/reducers/vis-state-merger.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,36 @@ import {ParsedConfig} from 'schemas';

export function mergeAnimationConfig(
state: VisState,
animation: ParsedConfig['visState']['animationConfig']
animation: ParsedConfig['visState']['animationConfig'],
fromConfig?: boolean
): VisState;
export function mergeFilters(
state: VisState,
filters: ParsedConfig['visState']['filters']
filters: ParsedConfig['visState']['filters'],
fromConfig?: boolean
): VisState;
export function mergeInteractions(
state: VisState,
interactionConfig: ParsedConfig['visState']['interactionConfig']
interactionConfig: ParsedConfig['visState']['interactionConfig'],
fromConfig?: boolean
): VisState;
export function mergeLayerBlending(
state: VisState,
layerBlending: ParsedConfig['visState']['layerBlending']
layerBlending: ParsedConfig['visState']['layerBlending'],
fromConfig?: boolean
): VisState;
export function mergeLayers(state: VisState, layers: ParsedConfig['visState']['layers']): VisState;
export function mergeLayers(state: VisState, layers: ParsedConfig['visState']['layers'], fromConfig?: boolean): VisState;
export function mergeSplitMaps(
state: VisState,
splitMaps: ParsedConfig['visState']['splitMaps']
splitMaps: ParsedConfig['visState']['splitMaps'],
fromConfig?: boolean
): VisState;

export function mergeInteractionTooltipConfig(state: VisState);

export function isValidMerger(arg: any): boolean;
export type Merger = {
merge: (state: VisState, config: any) => VisState,
merge: (state: VisState, config: any, fromConfig?: boolean) => VisState,
prop: string,
toMergeProp?: string
};
Expand Down
92 changes: 70 additions & 22 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, isObject} from 'utils/utils';
import {toArray, isObject, arrayInsert} from 'utils/utils';

import {
applyFiltersToDatasets,
Expand Down Expand Up @@ -138,7 +138,9 @@ export function mergeFilters(state, filtersToMerge) {
*
* @type {typeof import('./vis-state-merger').mergeLayers}
*/
export function mergeLayers(state, layersToMerge) {
export function mergeLayers(state, layersToMerge, fromConfig) {
const preserveLayerOrder = fromConfig ? layersToMerge.map(l => l.id) : state.preserveLayerOrder;

const mergedLayer = [];
const unmerged = [];

Expand All @@ -149,37 +151,85 @@ export function mergeLayers(state, layersToMerge) {
}

layersToMerge.forEach(layer => {
let validateLayer;
if (datasets[layer.config.dataId]) {
// datasets are already loaded
const validateLayer = validateLayerWithData(
validateLayer = validateLayerWithData(
datasets[layer.config.dataId],
layer,
state.layerClasses
);
}

if (validateLayer) {
mergedLayer.push(validateLayer);
}
if (validateLayer) {
mergedLayer.push(validateLayer);
} else {
// datasets not yet loaded
unmerged.push(layer);
}
});

const layers = [...state.layers, ...mergedLayer];
const newLayerOrder = mergedLayer.map((_, i) => state.layers.length + i);

// put new layers in front of current layers
const layerOrder = [...newLayerOrder, ...state.layerOrder];

const {newLayerOrder, newLayers} = insertLayerAtRightOrder(
state.layers,
mergedLayer,
state.layerOrder,
preserveLayerOrder
);
return {
...state,
layers,
layerOrder,
layers: newLayers,
layerOrder: newLayerOrder,
preserveLayerOrder,
layerToBeMerged: [...state.layerToBeMerged, ...unmerged]
};
}

export function insertLayerAtRightOrder(
currentLayers,
layersToInsert,
currentOrder,
preservedOrder = []
) {
// perservedOrder ['a', 'b', 'c'];
// layerOrder [1, 0, 3]
// layerOrderMap ['a', 'c']
let layerOrderQueue = currentOrder.map(i => currentLayers[i].id);
let newLayers = currentLayers;

for (const newLayer of layersToInsert) {
// find where to insert it
const expectedIdx = preservedOrder.indexOf(newLayer.id);
// if cant find place to insert, insert at the font
let insertAt = 0;

if (expectedIdx > 0) {
// look for layer to insert after
let i = expectedIdx + 1;
let preceedIdx = null;
while (i-- > 0 && preceedIdx === null) {
const preceedLayer = preservedOrder[expectedIdx - 1];
preceedIdx = layerOrderQueue.indexOf(preceedLayer);
}

if (preceedIdx > -1) {
insertAt = preceedIdx + 1;
}
}

layerOrderQueue = arrayInsert(layerOrderQueue, insertAt, newLayer.id);
newLayers = newLayers.concat(newLayer);
}

// reconstruct layerOrder after insert
const newLayerOrder = layerOrderQueue.map(id => newLayers.findIndex(l => l.id === id));

return {
newLayerOrder,
newLayers
};
}

/**
* Merge interactions with saved config
*
Expand Down Expand Up @@ -484,14 +534,13 @@ export function validateLayerWithData({fields, id: dataId}, savedLayer, layerCla
});

// find column fieldIdx
const columns = validateSavedLayerColumns(
fields,
savedLayer.config.columns,
newLayer.getLayerColumns()
);

if (!columns) {
return null;
const columnConfig = newLayer.getLayerColumns();
if (Object.keys(columnConfig).length) {
const columns = validateSavedLayerColumns(fields, savedLayer.config.columns, columnConfig);
if (!columns) {
return null;
}
newLayer.updateLayerConfig({columns});
}

// visual channel field is saved to be {name, type}
Expand All @@ -512,7 +561,6 @@ export function validateLayerWithData({fields, id: dataId}, savedLayer, layerCla
);

newLayer.updateLayerConfig({
columns,
visConfig,
textLabel
});
Expand Down
3 changes: 2 additions & 1 deletion src/reducers/vis-state-updaters.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,8 @@ export type VisState = {
loadOptions: object;
initialState?: Partial<VisState>;
mergers: VisStateMergers;
schema: KeplerGLSchema
schema: KeplerGLSchema,
preserveLayerOrder?: number[];
};

export function addDefaultLayers(
Expand Down
2 changes: 1 addition & 1 deletion src/reducers/vis-state-updaters.js
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ export const receiveMapConfigUpdater = (state, {payload: {config = {}, options =
let mergedState = !keepExistingConfig ? resetMapConfigUpdater(state) : state;
for (const merger of state.mergers) {
if (isValidMerger(merger) && config.visState[merger.prop]) {
mergedState = merger.merge(mergedState, config.visState[merger.prop]);
mergedState = merger.merge(mergedState, config.visState[merger.prop], true);
}
}

Expand Down
10 changes: 9 additions & 1 deletion src/utils/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export function toArray(item) {
* @param {*} value
* @returns {Array|Object}
*/
const insertValue = (obj, key, value) => {
export const insertValue = (obj, key, value) => {
if (Array.isArray(obj) && typeof key === 'number') {
return [...obj.slice(0, key), value, ...obj.slice(key + 1, obj.length)];
}
Expand Down Expand Up @@ -189,3 +189,11 @@ export function getError(err) {
// @ts-ignore
return null;
}

export function arrayInsert(arr, index, val) {
if (!Array.isArray(arr)) {
return arr;
}

return [...arr.slice(0, index), val, ...arr.slice(index)];
}

0 comments on commit 92a2bb6

Please sign in to comment.