Skip to content

Commit

Permalink
[feat] Convert layer order from idx to layer IDs (#2203)
Browse files Browse the repository at this point in the history
  • Loading branch information
igorDykhta committed Apr 27, 2023
1 parent e1ccfdf commit 28fbcdb
Show file tree
Hide file tree
Showing 24 changed files with 403 additions and 367 deletions.
22 changes: 11 additions & 11 deletions src/actions/src/vis-state-actions.ts
Expand Up @@ -408,7 +408,7 @@ export function addLayer(
}

export type ReorderLayerUpdaterAction = {
order: number[];
order: string[];
};
/**
* Reorder layer, order is an array of layer indexes, index 0 will be the one at the bottom
Expand All @@ -418,12 +418,12 @@ export type ReorderLayerUpdaterAction = {
* @public
* @example
*
* // bring `layers[1]` below `layers[0]`, the sequence layers will be rendered is `1`, `0`, `2`, `3`.
* // `1` will be at the bottom, `3` will be at the top.
* this.props.dispatch(reorderLayer([1, 0, 2, 3]));
* bring `layers[1]` below `layers[0]`, the sequence layers will be rendered is `layers[1].id`, `layers[0].id`, `layers[2].id`, `layers[3].id`.
* `layers[1]` will be at the bottom, `layers[13]` will be at the top.
* this.props.dispatch(reorderLayer([`layers[1].id`, `layers[0].id`, `layers[2].id`, `layers[3].id`]));
*/
export function reorderLayer(
order: number[]
order: string[]
): Merge<ReorderLayerUpdaterAction, {type: typeof ActionTypes.REORDER_LAYER}> {
return {
type: ActionTypes.REORDER_LAYER,
Expand Down Expand Up @@ -451,7 +451,7 @@ export function removeFilter(
}

export type RemoveLayerUpdaterAction = {
id: string | number;
id: string;
};
/**
* Remove a layer
Expand All @@ -461,7 +461,7 @@ export type RemoveLayerUpdaterAction = {
* @public
*/
export function removeLayer(
id: string | number
id: string
): Merge<RemoveLayerUpdaterAction, {type: typeof ActionTypes.REMOVE_LAYER}> {
return {
type: ActionTypes.REMOVE_LAYER,
Expand All @@ -470,21 +470,21 @@ export function removeLayer(
}

export type DuplicateLayerUpdaterAction = {
idx: number;
id: string;
};
/**
* Duplicate a layer
* @memberof visStateActions
* @param idx idx of layer to be duplicated
* @param id id of layer to be duplicated
* @returns action
* @public
*/
export function duplicateLayer(
idx: number
id: string
): Merge<DuplicateLayerUpdaterAction, {type: typeof ActionTypes.DUPLICATE_LAYER}> {
return {
type: ActionTypes.DUPLICATE_LAYER,
idx
id
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/components/src/kepler-gl.tsx
Expand Up @@ -491,13 +491,13 @@ function KeplerGlFactory(
// update dndItems when layerOrder or layers change
this.setState((state, props) => {
const {
visState: {layers, layerOrder}
visState: {layerOrder}
} = props;

return {
dndItems: {
...state.dndItems,
sortablelist: layerOrder.map(layerIdx => layers[layerIdx].id)
sortablelist: layerOrder
}
};
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/side-panel/layer-manager.tsx
Expand Up @@ -56,7 +56,7 @@ type OverlayBlendingSelectorProps = {
type LayerManagerProps = {
datasets: Datasets;
layers: Layer[];
layerOrder: number[];
layerOrder: string[];
layerClasses: LayerClassesType;
layerBlending: string;
overlayBlending: string;
Expand Down
Expand Up @@ -28,7 +28,7 @@ import {KeplerTable, Datasets} from '@kepler.gl/table';
type DatasetLayerGroupProps = {
datasets: Datasets;
layers: Layer[];
layerOrder: number[];
layerOrder: string[];
layerClasses: LayerClassesType;
showDeleteDataset: boolean;
removeDataset: ActionHandler<typeof UIStateActions.openDeleteModal>;
Expand Down
Expand Up @@ -31,7 +31,7 @@ type DatasetLayerSectionProps = {
datasets: Datasets;
dataset: KeplerTable;
layers: Layer[];
layerOrder: number[];
layerOrder: string[];
layerClasses: LayerClassesType;
showDeleteDataset: boolean;
showDatasetTable: ActionHandler<typeof VisStateActions.showDatasetTable>;
Expand Down
62 changes: 31 additions & 31 deletions src/components/src/side-panel/layer-panel/layer-list.tsx
Expand Up @@ -29,11 +29,12 @@ import {UIStateActions, VisStateActions} from '@kepler.gl/actions';
import {useDroppable} from '@dnd-kit/core';
import {useSortable, SortableContext, verticalListSortingStrategy} from '@dnd-kit/sortable';
import {CSS} from '@dnd-kit/utilities';
import {findById} from '@kepler.gl/utils';

type LayerListProps = {
datasets: Datasets;
layers: Layer[];
layerOrder: number[];
layerOrder: string[];
layerClasses: LayerClassesType;
isSortable?: boolean;
uiStateActions: typeof UIStateActions;
Expand Down Expand Up @@ -79,9 +80,9 @@ LayerListFactory.deps = [LayerPanelFactory];
function LayerListFactory(LayerPanel: ReturnType<typeof LayerPanelFactory>) {
// By wrapping layer panel using a sortable element we don't have to implement the drag and drop logic into the panel itself;
// Developers can provide any layer panel implementation and it will still be sortable
const SortableItem = ({layerId, layers, layerIndex, panelProps, layerActions}) => {
const SortableItem = ({layer, layerIndex, panelProps, layerActions}) => {
const {attributes, listeners, setNodeRef, isDragging, transform, transition} = useSortable({
id: layerId
id: layer.id
});

return (
Expand All @@ -95,9 +96,9 @@ function LayerListFactory(LayerPanel: ReturnType<typeof LayerPanelFactory>) {
<LayerPanel
{...panelProps}
{...layerActions}
key={layerId}
key={layer.id}
idx={layerIndex}
layer={layers[layerIndex]}
layer={layer}
listeners={listeners}
/>
</SortableStyledItem>
Expand Down Expand Up @@ -128,15 +129,20 @@ function LayerListFactory(LayerPanel: ReturnType<typeof LayerPanelFactory>) {
isSortable = true
} = props;
const {toggleModal: openModal} = uiStateActions;
const layerOrdersToShow = useMemo(
() =>
layerOrder.filter(layerIdx => Boolean(layers[layerIdx]) && !layers[layerIdx].config.hidden),
[layers, layerOrder]
);

const layersToShow = useMemo(() => {
return layerOrder.reduce((acc, layerId) => {
const layer = findById<Layer>(layerId)(layers);
if (!layer) {
return acc;
}
return !layer.config.hidden ? [...acc, layer] : acc;
}, [] as Layer[]);
}, [layers, layerOrder]);

const sidePanelDndItems = useMemo(() => {
return layerOrdersToShow.map(layerIdx => layers[layerIdx].id);
}, [layerOrdersToShow, layers]);
return layersToShow.map(({id}) => id);
}, [layersToShow]);

const layerTypeOptions = useMemo(
() =>
Expand Down Expand Up @@ -175,34 +181,28 @@ function LayerListFactory(LayerPanel: ReturnType<typeof LayerPanelFactory>) {
<SortableList containerId="sortablelist" sidePanelDndItems={sidePanelDndItems}>
{/* warning: containerId should be similar to the first key in dndItems defined in kepler-gl.js*/}

{layerOrdersToShow.map(layerIdx => (
{layersToShow.map(layer => (
<SortableItem
key={layers[layerIdx].id}
layerId={layers[layerIdx].id}
key={layer.id}
layer={layer}
layerIndex={layers.findIndex(({id}) => id === layer.id)}
panelProps={panelProps}
layerActions={layerActions}
layers={layers}
layerIndex={layerIdx}
/>
))}
</SortableList>
</>
) : (
<>
{layerOrder.map(
layerIdx =>
layers[layerIdx] &&
!layers[layerIdx].config.hidden && (
<LayerPanel
{...panelProps}
{...layerActions}
key={layers[layerIdx].id}
idx={layerIdx}
layer={layers[layerIdx]}
isDraggable={false}
/>
)
)}
{layersToShow.map(layer => (
<LayerPanel
{...panelProps}
{...layerActions}
key={layer.id}
layer={layer}
isDraggable={false}
/>
))}
</>
);
};
Expand Down
5 changes: 2 additions & 3 deletions src/components/src/side-panel/layer-panel/layer-panel.tsx
Expand Up @@ -41,7 +41,6 @@ type LayerPanelProps = {
onTouchStart?: TouchEventHandler;
layer: Layer;
datasets: Datasets;
idx: number;
layerTypeOptions: {
id: string;
label: string;
Expand Down Expand Up @@ -133,12 +132,12 @@ function LayerPanelFactory(

_removeLayer: MouseEventHandler = e => {
e.stopPropagation();
this.props.removeLayer(this.props.idx);
this.props.removeLayer(this.props.layer.id);
};

_duplicateLayer: MouseEventHandler = e => {
e.stopPropagation();
this.props.duplicateLayer(this.props.idx);
this.props.duplicateLayer(this.props.layer.id);
};

render() {
Expand Down
2 changes: 1 addition & 1 deletion src/components/src/types.ts
Expand Up @@ -27,7 +27,7 @@ export type SidePanelProps = {
overlayBlending: string;
layers: Layer[];
layerClasses: LayerClassesType;
layerOrder: number[];
layerOrder: string[];
mapStyle: MapStyle;
onSaveMap?: () => void;
width: number;
Expand Down
34 changes: 23 additions & 11 deletions src/layers/src/mapbox-utils.ts
Expand Up @@ -21,6 +21,8 @@
import Layer, {OVERLAY_TYPE_CONST} from './base-layer';
import {Feature} from 'geojson';

import {findById} from '@kepler.gl/utils';

/**
* This function will convert layers to mapbox layers
* @param layers the layers to be converted
Expand All @@ -32,28 +34,38 @@ import {Feature} from 'geojson';
export function generateMapboxLayers(
layers: Layer[] = [],
layerData: any[] = [],
layerOrder: number[] = [],
layerOrder: string[] = [],
layersToRender: {[key: string]: boolean} = {}
): {[key: string]: Layer} {
if (layerData.length > 0) {
return layerOrder
.slice()
.reverse()
.filter(
idx =>
layers[idx].overlayType === OVERLAY_TYPE_CONST.mapboxgl && layersToRender[layers[idx].id]
)
.reduce((accu, index) => {
const layer = layers[index];
.filter(layerId => {
const layer = findById<Layer>(layerId)(layers);
return layer?.overlayType === OVERLAY_TYPE_CONST.mapboxgl && layersToRender[layerId];
})
.reduce((acc, layerId) => {
const layerIndex = layers.findIndex(l => l.id === layerId);
if (layerIndex === -1) {
return acc;
}

const layer = layers[layerId];

if (!(layer.overlayType === OVERLAY_TYPE_CONST.mapboxgl && layersToRender[layerId])) {
return acc;
}

return {
...accu,
...acc,
[layer.id]: {
id: layer.id,
data: layerData[index].data,
data: layerData[layerIndex].data,
isVisible: layer.config.isVisible,
config: layerData[index].config,
config: layerData[layerIndex].config,
hidden: layer.config.hidden,
sourceId: layerData[index].config.source
sourceId: layerData[layerIndex].config.source
}
};
}, {});
Expand Down
12 changes: 8 additions & 4 deletions src/reducers/src/composer-helpers.ts
Expand Up @@ -66,10 +66,14 @@ export function swap_<X extends {id: string}>(item: X): (arr: X[]) => X[] {
return arr => arr.map(a => (a.id === item.id ? item : a));
}

export function findById<X extends {id: string}>(id: string): (arr: X[]) => X | undefined {
return arr => arr.find(a => a.id === id);
export function map_<X, T>(fn: (state: X) => T): (arr: X[]) => T[] {
return arr => arr.map(e => fn(e));
}

export function map_<X>(fn: (state: X) => X): (arr: X[]) => X[] {
return arr => arr.map(e => fn(e));
export function filterOutById<X extends {id: string}>(id: string): (arr: X[]) => X[] {
return arr => arr.filter(e => e.id !== id);
}

export function removeElementAtIndex<X>(index: number): (arr: X[]) => X[] {
return arr => [...arr.slice(0, index), ...arr.slice(index + 1, arr.length)];
}

0 comments on commit 28fbcdb

Please sign in to comment.