From ff90c3b2c12c91ce718555b0bdf97b0293d93159 Mon Sep 17 00:00:00 2001 From: Ruben Thoms Date: Tue, 20 Aug 2024 13:58:15 +0200 Subject: [PATCH] wip --- .../src/lib/components/SortableList/index.ts | 4 +- .../modules/2DViewer/layers/SurfaceLayer.ts | 6 +- .../layerSettings/faultPolygonLayer.tsx | 5 +- .../components/layerSettings/polygonLayer.tsx | 5 +- .../components/layerSettings/surfaceLayer.tsx | 4 +- .../modules/2DViewer/settings/settings.tsx | 8 +- frontend/src/modules/2DViewer/view/view.tsx | 17 +- .../Intersection/settings/settings.tsx | 2 +- .../src/modules/Intersection/view/view.tsx | 5 +- .../components/Layers/addLayerDropdown.tsx | 4 +- .../Layers/layerGroupComponents.tsx | 33 ++-- .../_shared/components/Layers/layersPanel.tsx | 55 ++---- .../_shared/components/Layers/utils.tsx | 140 ++++++++++++++ .../src/modules/_shared/layers/BaseLayer.ts | 13 +- .../src/modules/_shared/layers/LayerGroup.ts | 84 ++++---- .../modules/_shared/layers/LayerManager.ts | 181 ++---------------- 16 files changed, 287 insertions(+), 279 deletions(-) create mode 100644 frontend/src/modules/_shared/components/Layers/utils.tsx diff --git a/frontend/src/lib/components/SortableList/index.ts b/frontend/src/lib/components/SortableList/index.ts index d1b7d12b3..463916058 100644 --- a/frontend/src/lib/components/SortableList/index.ts +++ b/frontend/src/lib/components/SortableList/index.ts @@ -1,7 +1,7 @@ -export { SortableList } from "./sortableList"; +export { SortableList, ItemType } from "./sortableList"; export { SortableListItem } from "./sortableListItem"; export { SortableListGroup } from "./sortableListGroup"; -export type { SortableListProps } from "./sortableList"; +export type { SortableListProps, IsMoveAllowedArgs } from "./sortableList"; export type { SortableListItemProps } from "./sortableListItem"; export type { SortableListGroupProps } from "./sortableListGroup"; diff --git a/frontend/src/modules/2DViewer/layers/SurfaceLayer.ts b/frontend/src/modules/2DViewer/layers/SurfaceLayer.ts index a7bdfa72d..138f0807d 100644 --- a/frontend/src/modules/2DViewer/layers/SurfaceLayer.ts +++ b/frontend/src/modules/2DViewer/layers/SurfaceLayer.ts @@ -13,7 +13,7 @@ import { QueryClient } from "@tanstack/query-core"; import { isEqual } from "lodash"; import { SurfaceDataPng } from "src/api/models/SurfaceDataPng"; -import { EnsembleStage, EnsembleStageType } from "../settings/components/ensembleStageSelect"; +import { EnsembleStageType } from "../settings/components/ensembleStageSelect"; const STALE_TIME = 60 * 1000; const CACHE_TIME = 60 * 1000; @@ -35,10 +35,6 @@ export class SurfaceLayer extends BaseLayer(cloneDeep(settings)); const [prevSettings, setPrevSettings] = React.useState(cloneDeep(settings)); diff --git a/frontend/src/modules/2DViewer/settings/components/layerSettings/polygonLayer.tsx b/frontend/src/modules/2DViewer/settings/components/layerSettings/polygonLayer.tsx index 140e91d9f..c0c423b2d 100644 --- a/frontend/src/modules/2DViewer/settings/components/layerSettings/polygonLayer.tsx +++ b/frontend/src/modules/2DViewer/settings/components/layerSettings/polygonLayer.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { PolygonsAttributeType_api, PolygonsMeta_api, SurfaceAttributeType_api, SurfaceMetaSet_api } from "@api"; +import { PolygonsAttributeType_api, PolygonsMeta_api } from "@api"; import { apiService } from "@framework/ApiService"; import { EnsembleIdent } from "@framework/EnsembleIdent"; import { EnsembleSet } from "@framework/EnsembleSet"; @@ -12,7 +12,6 @@ import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; import { PendingWrapper } from "@lib/components/PendingWrapper"; import { PolygonLayer, PolygonLayerSettings } from "@modules/2DViewer/layers/PolygonLayer"; import { useLayerSettings } from "@modules/_shared/layers/BaseLayer"; -import { LayerManagerTopic, useLayerManagerTopicValue } from "@modules/_shared/layers/LayerManager"; import { UseQueryResult, useQuery } from "@tanstack/react-query"; import { cloneDeep, isEqual } from "lodash"; @@ -28,7 +27,7 @@ export type PolygonLayerSettingsComponentProps = { const faultPolygonAttributeTypes = [PolygonsAttributeType_api.FAULT_LINES, PolygonsAttributeType_api.DEPTH]; export function PolygonLayerSettingsComponent(props: PolygonLayerSettingsComponentProps): React.ReactNode { - useLayerManagerTopicValue(props.layer.getLayerManager(), LayerManagerTopic.SETTINGS_CHANGED); + //useLayerManagerTopicValue(props.layer.getLayerManager(), LayerManagerTopic.SETTINGS_CHANGED); const settings = useLayerSettings(props.layer); const [newSettings, setNewSettings] = React.useState(cloneDeep(settings)); const [prevSettings, setPrevSettings] = React.useState(cloneDeep(settings)); diff --git a/frontend/src/modules/2DViewer/settings/components/layerSettings/surfaceLayer.tsx b/frontend/src/modules/2DViewer/settings/components/layerSettings/surfaceLayer.tsx index d4e5e46cd..f8813b79d 100644 --- a/frontend/src/modules/2DViewer/settings/components/layerSettings/surfaceLayer.tsx +++ b/frontend/src/modules/2DViewer/settings/components/layerSettings/surfaceLayer.tsx @@ -9,10 +9,8 @@ import { WorkbenchSettings } from "@framework/WorkbenchSettings"; import { EnsembleDropdown } from "@framework/components/EnsembleDropdown"; import { Dropdown, DropdownOption } from "@lib/components/Dropdown"; import { PendingWrapper } from "@lib/components/PendingWrapper"; -import { Select } from "@lib/components/Select"; import { SurfaceLayer, SurfaceLayerSettings } from "@modules/2DViewer/layers/SurfaceLayer"; import { useLayerSettings } from "@modules/_shared/layers/BaseLayer"; -import { LayerManagerTopic, useLayerManagerTopicValue } from "@modules/_shared/layers/LayerManager"; import { UseQueryResult, useQuery } from "@tanstack/react-query"; import { cloneDeep, isEqual } from "lodash"; @@ -29,7 +27,7 @@ export type SurfaceLayerSettingsComponentProps = { }; export function SurfaceLayerSettingsComponent(props: SurfaceLayerSettingsComponentProps): React.ReactNode { - useLayerManagerTopicValue(props.layer.getLayerManager(), LayerManagerTopic.SETTINGS_CHANGED); + //useLayerManagerTopicValue(props.layer.getLayerManager(), LayerManagerTopic.SETTINGS_CHANGED); const settings = useLayerSettings(props.layer); const [newSettings, setNewSettings] = React.useState(cloneDeep(settings)); const [prevSettings, setPrevSettings] = React.useState(cloneDeep(settings)); diff --git a/frontend/src/modules/2DViewer/settings/settings.tsx b/frontend/src/modules/2DViewer/settings/settings.tsx index e48c12ae3..6380f6256 100644 --- a/frontend/src/modules/2DViewer/settings/settings.tsx +++ b/frontend/src/modules/2DViewer/settings/settings.tsx @@ -12,6 +12,7 @@ import { MenuHeading } from "@lib/components/MenuHeading"; import { MenuItem } from "@lib/components/MenuItem"; import { LayersPanel } from "@modules/_shared/components/Layers"; import { BaseLayer } from "@modules/_shared/layers/BaseLayer"; +import { LayerGroup } from "@modules/_shared/layers/LayerGroup"; import { LayerSettingFactory } from "@modules/_shared/layers/settings/LayerSettingFactory"; import { SETTING_TYPE_TO_STRING_MAPPING, SettingType } from "@modules/_shared/layers/settings/SettingTypes"; import { Dropdown, MenuButton } from "@mui/base"; @@ -51,16 +52,17 @@ export function Settings(props: ModuleSettingsProps): Re const statusWriter = useViewStatusWriter(props.viewContext); const layerManager = props.viewContext.useSettingsToViewInterfaceValue("layerManager"); const allItems = useLayerManagerTopicValue(layerManager, LayerManagerTopic.ITEMS_CHANGED); - const layerItems = useLayerManagerTopicValue(layerManager, LayerManagerTopic.LAYERS_CHANGED_RECURSIVELY); - const layers = useLayers(layerItems); + const [prevLayerItems, setPrevLayerItems] = React.useState[]>([]); + + const currentLayerItems = allItems.filter((item) => item instanceof BaseLayer) as BaseLayer[]; + if (!isEqual(currentLayerItems, prevLayerItems)) { + setPrevLayerItems(currentLayerItems); + } + + const layers = useLayers(prevLayerItems); const layersStatuses = useLayersStatuses(layers); statusWriter.setLoading(layersStatuses.some((status) => status.status === LayerStatus.LOADING)); @@ -75,9 +82,12 @@ export function View(props: ModuleViewProps): Re } } } else if (item instanceof LayerGroup) { - const layers = item.getLayers(); + const layers = item.getItems(); const groupLayers: Layer[] = []; for (const layer of layers) { + if (!(layer instanceof BaseLayer)) { + continue; + } if (!layer.getIsVisible()) { continue; } @@ -154,7 +164,6 @@ export function View(props: ModuleViewProps): Re viewports: viewports, showLabel: true, }; - console.log(views); return (
item instanceof BaseLayer) as BaseLayer[]; - const layersStatuses = useLayersStatuses(layers.filter((el) => el instanceof BaseLayer) as BaseLayer[]); + const layers = useLayerManagerTopicValue(layerManager, LayerManagerTopic.ITEMS_CHANGED) as BaseLayer[]; + const layersStatuses = useLayersStatuses(layers); const intersectionExtensionLength = props.viewContext.useSettingsToViewInterfaceValue("intersectionExtensionLength"); diff --git a/frontend/src/modules/_shared/components/Layers/addLayerDropdown.tsx b/frontend/src/modules/_shared/components/Layers/addLayerDropdown.tsx index 99ad94a73..cd8b44218 100644 --- a/frontend/src/modules/_shared/components/Layers/addLayerDropdown.tsx +++ b/frontend/src/modules/_shared/components/Layers/addLayerDropdown.tsx @@ -11,7 +11,7 @@ import { Add, ArrowDropDown } from "@mui/icons-material"; import { LayerFactory } from "./layersPanel"; export type AddLayerDropdownProps = { - parent: LayerGroup | LayerManager; + parent: LayerGroup; layerManager: LayerManager; layerTypeToStringMapping: Record; layerFactory: LayerFactory; @@ -19,7 +19,7 @@ export type AddLayerDropdownProps = { export function AddLayerDropdown(props: AddLayerDropdownProps): React.ReactNode { function handleAddLayer(type: TLayerType) { - props.parent.addLayer(props.layerFactory.makeLayer(type, props.layerManager)); + props.parent.prependItem(props.layerFactory.makeLayer(type, props.layerManager)); } return ( diff --git a/frontend/src/modules/_shared/components/Layers/layerGroupComponents.tsx b/frontend/src/modules/_shared/components/Layers/layerGroupComponents.tsx index bcd9712b1..1b56f695c 100644 --- a/frontend/src/modules/_shared/components/Layers/layerGroupComponents.tsx +++ b/frontend/src/modules/_shared/components/Layers/layerGroupComponents.tsx @@ -9,8 +9,8 @@ import { LayerManager } from "@modules/_shared/layers/LayerManager"; import { Add, Delete, Folder, Visibility, VisibilityOff } from "@mui/icons-material"; import { AddLayerDropdown } from "./addLayerDropdown"; -import { LayerComponent } from "./layerComponents"; import { LayerFactory, MakeSettingsContainerFunc } from "./layersPanel"; +import { makeContent } from "./utils"; export type LayerGroupComponentProps = { layerManager: LayerManager; @@ -28,10 +28,12 @@ export type LayerGroupComponentProps = { export function LayerGroupComponent( props: LayerGroupComponentProps ): React.ReactNode { - const layers = useLayerGroupTopicValue(props.group, LayerGroupTopic.LAYERS_CHANGED); + useLayerGroupTopicValue(props.group, LayerGroupTopic.ITEMS_CHANGED); - function handleRemoveLayer(layerId: string) { - props.group.removeLayer(layerId); + const items = props.group.getItems(); + + function handleRemoveItem(layerId: string) { + props.group.removeItem(layerId); } return ( @@ -57,17 +59,18 @@ export function LayerGroupComponent(
} > - {layers.map((layer) => ( - - ))} + {makeContent( + items, + props.layerManager, + props.icon, + props.layerFactory, + props.layerTypeToStringMapping, + handleRemoveItem, + props.makeSettingsContainerFunc, + props.ensembleSet, + props.workbenchSession, + props.workbenchSettings + )} ); } diff --git a/frontend/src/modules/_shared/components/Layers/layersPanel.tsx b/frontend/src/modules/_shared/components/Layers/layersPanel.tsx index 797c16c4d..d9cad2e5d 100644 --- a/frontend/src/modules/_shared/components/Layers/layersPanel.tsx +++ b/frontend/src/modules/_shared/components/Layers/layersPanel.tsx @@ -3,13 +3,12 @@ import React from "react"; import { EnsembleSet } from "@framework/EnsembleSet"; import { WorkbenchSession } from "@framework/WorkbenchSession"; import { WorkbenchSettings } from "@framework/WorkbenchSettings"; -import { SortableList, SortableListItemProps } from "@lib/components/SortableList"; -import { IsMoveAllowedArgs, ItemType } from "@lib/components/SortableList/sortableList"; +import { IsMoveAllowedArgs, ItemType, SortableList, SortableListItemProps } from "@lib/components/SortableList"; import { BaseLayer } from "@modules/_shared/layers/BaseLayer"; import { LayerGroup } from "@modules/_shared/layers/LayerGroup"; import { + LayerItem, LayerManager, - LayerManagerItem, LayerManagerTopic, useLayerManagerTopicValue, } from "@modules/_shared/layers/LayerManager"; @@ -50,14 +49,15 @@ export type LayersPanelProps = { }; export function LayersPanel(props: LayersPanelProps): React.ReactNode { - const items = useLayerManagerTopicValue(props.layerManager, LayerManagerTopic.ITEMS_CHANGED); + useLayerManagerTopicValue(props.layerManager, LayerManagerTopic.ITEMS_CHANGED); + const items = props.layerManager.getMainGroup().getItems(); const layerSettingFactory = new LayerSettingContentFactory( props.ensembleSet, props.workbenchSession, props.workbenchSettings ); - const [prevItems, setPrevItems] = React.useState(items); + const [prevItems, setPrevItems] = React.useState(items); const [itemsOrder, setItemsOrder] = React.useState(items.map((item) => item.getId())); if (!isEqual(prevItems, items)) { @@ -65,52 +65,39 @@ export function LayersPanel(props: LayersPanelProps layer.getId())); } - function handleRemoveGroup(id: string) { - props.layerManager.removeGroup(id); - } - function handleRemoveItem(id: string) { - props.layerManager.removeLayer(id); + props.layerManager.getMainGroup().removeItem(id); } function handleItemMove(itemId: string, originId: string | null, destinationId: string | null, position: number) { - let origin: LayerGroup | LayerManager | null = props.layerManager; + let origin: LayerGroup | null = props.layerManager.getMainGroup(); if (originId) { - origin = props.layerManager.getGroup(originId) ?? null; + const candidate = props.layerManager.getItem(originId); + if (candidate instanceof LayerGroup) { + origin = candidate; + } } - let destination: LayerGroup | LayerManager | null = props.layerManager; + let destination: LayerGroup | null = props.layerManager.getMainGroup(); if (destinationId) { - destination = props.layerManager.getGroup(destinationId) ?? null; + const candidate = props.layerManager.getItem(destinationId); + if (candidate instanceof LayerGroup) { + destination = candidate; + } } if (origin === null || destination === null) { return; } - let isLayerOrSetting: boolean = true; - let item: BaseLayer | LayerGroup | undefined = origin.getLayer(itemId); - - if (!item && origin instanceof LayerManager) { - item = origin.getGroup(itemId); - isLayerOrSetting = false; - } + const item: LayerItem | undefined = origin.getItem(itemId); if (!item) { return; } - if (isLayerOrSetting) { - if (item instanceof BaseLayer) { - origin.removeLayer(itemId); - destination.insertLayer(item, position); - } - } else if (origin instanceof LayerManager) { - origin.removeGroup(itemId); - if (destination instanceof LayerManager && item instanceof LayerGroup) { - destination.insertGroup(item, position); - } - } + origin.removeItem(itemId); + destination.insertItem(item, position); } function makeLayerElement(layer: BaseLayer): React.ReactElement { @@ -136,7 +123,7 @@ export function LayersPanel(props: LayersPanelProps(props: LayersPanelProps items.find((el) => el.getId() === id)) - .filter((el) => el) as LayerManagerItem[]; + .filter((el) => el) as LayerItem[]; for (let i = 0; i < orderedItems.length; i++) { const item = orderedItems[i]; diff --git a/frontend/src/modules/_shared/components/Layers/utils.tsx b/frontend/src/modules/_shared/components/Layers/utils.tsx new file mode 100644 index 000000000..c305f227d --- /dev/null +++ b/frontend/src/modules/_shared/components/Layers/utils.tsx @@ -0,0 +1,140 @@ +import React from "react"; + +import { EnsembleSet } from "@framework/EnsembleSet"; +import { WorkbenchSession } from "@framework/WorkbenchSession"; +import { WorkbenchSettings } from "@framework/WorkbenchSettings"; +import { SortableListItemProps } from "@lib/components/SortableList"; +import { BaseLayer } from "@modules/_shared/layers/BaseLayer"; +import { LayerGroup } from "@modules/_shared/layers/LayerGroup"; +import { LayerItem, LayerManager } from "@modules/_shared/layers/LayerManager"; +import { BaseSetting } from "@modules/_shared/layers/settings/BaseSetting"; + +import { LayerSettingContentFactory } from "./LayerSettingContentFactory"; +import { LayerComponent } from "./layerComponents"; +import { LayerGroupComponent } from "./layerGroupComponents"; +import { LayerFactory, MakeSettingsContainerFunc } from "./layersPanel"; +import { LayerSettingComponent } from "./settingComponents"; + +function makeLayerElement( + layer: BaseLayer, + handleRemoveItem: (id: string) => void, + makeSettingsContainerFunc: MakeSettingsContainerFunc, + ensembleSet: EnsembleSet, + workbenchSession: WorkbenchSession, + workbenchSettings: WorkbenchSettings +): React.ReactElement { + return ( + + ); +} + +function makeLayerGroup( + group: LayerGroup, + layerManager: LayerManager, + icon: React.ReactNode, + layerFactory: LayerFactory, + layerTypeToStringMapping: Record, + handleRemoveItem: (id: string) => void, + makeSettingsContainerFunc: MakeSettingsContainerFunc, + ensembleSet: EnsembleSet, + workbenchSession: WorkbenchSession, + workbenchSettings: WorkbenchSettings +): React.ReactElement { + return ( + + ); +} + +function makeSettingElement( + setting: BaseSetting, + handleRemoveItem: (id: string) => void, + ensembleSet: EnsembleSet, + workbenchSession: WorkbenchSession, + workbenchSettings: WorkbenchSettings +): React.ReactElement { + const layerSettingFactory = new LayerSettingContentFactory(ensembleSet, workbenchSession, workbenchSettings); + return ( + + {layerSettingFactory.createLayerSetting(setting)} + + ); +} + +export function makeContent( + items: LayerItem[], + layerManager: LayerManager, + icon: React.ReactNode, + layerFactory: LayerFactory, + layerTypeToStringMapping: Record, + handleRemoveItem: (id: string) => void, + makeSettingsContainerFunc: MakeSettingsContainerFunc, + ensembleSet: EnsembleSet, + workbenchSession: WorkbenchSession, + workbenchSettings: WorkbenchSettings +): React.ReactElement[] { + const nodes: React.ReactElement[] = []; + + for (let i = 0; i < items.length; i++) { + const item = items[i]; + + if (item instanceof LayerGroup) { + nodes.push( + makeLayerGroup( + item, + layerManager, + icon, + layerFactory, + layerTypeToStringMapping, + handleRemoveItem, + makeSettingsContainerFunc, + ensembleSet, + workbenchSession, + workbenchSettings + ) + ); + } else if (item instanceof BaseLayer) { + nodes.push( + makeLayerElement( + item as BaseLayer, + handleRemoveItem, + makeSettingsContainerFunc, + ensembleSet, + workbenchSession, + workbenchSettings + ) + ); + } else if (item instanceof BaseSetting) { + nodes.push( + makeSettingElement( + item as BaseSetting, + handleRemoveItem, + ensembleSet, + workbenchSession, + workbenchSettings + ) + ); + } + } + + return nodes; +} diff --git a/frontend/src/modules/_shared/layers/BaseLayer.ts b/frontend/src/modules/_shared/layers/BaseLayer.ts index 75d0d8404..e030363ff 100644 --- a/frontend/src/modules/_shared/layers/BaseLayer.ts +++ b/frontend/src/modules/_shared/layers/BaseLayer.ts @@ -72,19 +72,20 @@ export class BaseLayer { } getSettings(): TSettings { - const settingsOverrides = this._layerManager.getSettingsOverridesForLayer(this); - const relevantOverrides = settingsOverrides.filter((setting) => + //const settingsOverrides = this._layerManager.getSettingsOverridesForLayer(this); + /*const relevantOverrides = settingsOverrides.filter((setting) => Object.keys(this._settings).includes(setting.getKey()) ); const overrides: Record = {}; for (const setting of relevantOverrides) { overrides[setting.getKey()] = setting.getValue(); - } - const settings = { ...this._settings, ...overrides }; - return settings; + }*/ + // const settings = { ...this._settings }; //, ...overrides }; + return this._settings; } getOverridenSettingsKeys(): Partial[] { + /* const settingsOverrides = this._layerManager.getSettingsOverridesForLayer(this); const relevantOverrides = settingsOverrides.filter((setting) => Object.keys(this._settings).includes(setting.getKey()) @@ -94,6 +95,8 @@ export class BaseLayer { overrides.push(setting.getKey()); } return overrides; + */ + return []; } getStatus(): LayerStatus { diff --git a/frontend/src/modules/_shared/layers/LayerGroup.ts b/frontend/src/modules/_shared/layers/LayerGroup.ts index 5a438bd67..c4f3819fc 100644 --- a/frontend/src/modules/_shared/layers/LayerGroup.ts +++ b/frontend/src/modules/_shared/layers/LayerGroup.ts @@ -2,27 +2,28 @@ import React from "react"; import { v4 } from "uuid"; -import { BaseLayer } from "./BaseLayer"; -import { LayerManager } from "./LayerManager"; +import { LayerItem, LayerManager } from "./LayerManager"; export enum LayerGroupTopic { NAME_CHANGED = "name-changed", - LAYERS_CHANGED = "layer-ids-changed", + ITEMS_CHANGED = "layer-ids-changed", VISIBILITY_CHANGED = "visibility-changed", } export type LayerGroupTopicValueTypes = { - [LayerGroupTopic.LAYERS_CHANGED]: BaseLayer[]; + [LayerGroupTopic.ITEMS_CHANGED]: void; [LayerGroupTopic.NAME_CHANGED]: string; [LayerGroupTopic.VISIBILITY_CHANGED]: boolean; }; export class LayerGroup { - private _layerManager: LayerManager; private _id: string; private _name: string; + private _layerManager: LayerManager; + private _subscribers: Map void>> = new Map(); - private _layers: BaseLayer[] = []; + private _childrenIds: string[] = []; + private _isVisible: boolean = true; private _isExpanded: boolean = true; @@ -62,44 +63,61 @@ export class LayerGroup { this.notifySubscribers(LayerGroupTopic.NAME_CHANGED); } - getLayer(id: string): BaseLayer | undefined { - return this._layers.find((layer) => layer.getId() === id); + getItem(id: string): LayerItem | undefined { + if (this._childrenIds.includes(id)) { + return this._layerManager.getItem(id); + } + return undefined; + } + + getItems(): LayerItem[] { + const items: LayerItem[] = []; + for (const id of this._childrenIds) { + const item = this._layerManager.getItem(id); + if (item) { + items.push(item); + } + } + return items; } - getLayers(): BaseLayer[] { - return this._layers; + prependItem(item: LayerItem): void { + this._childrenIds = [item.getId(), ...this._childrenIds]; + this._layerManager.addItem(item); + this.notifySubscribers(LayerGroupTopic.ITEMS_CHANGED); } - addLayer(layer: BaseLayer): void { - layer.setName(this._layerManager.makeUniqueLayerName(layer.getName())); - layer.setQueryClient(this._layerManager.getQueryClient()); - this._layers = [...this._layers, layer]; - this.notifySubscribers(LayerGroupTopic.LAYERS_CHANGED); + appendItem(item: LayerItem): void { + this._childrenIds = [...this._childrenIds, item.getId()]; + this._layerManager.addItem(item); + this.notifySubscribers(LayerGroupTopic.ITEMS_CHANGED); } - removeLayer(id: string): void { - this._layers = this._layers.filter((layer) => layer.getId() !== id); - this.notifySubscribers(LayerGroupTopic.LAYERS_CHANGED); + insertItem(item: LayerItem, position: number): void { + const items = [...this._childrenIds]; + items.splice(position, 0, item.getId()); + this._childrenIds = items; + this._layerManager.addItem(item); + this.notifySubscribers(LayerGroupTopic.ITEMS_CHANGED); } - moveLayer(id: string, position: number): void { - const layer = this._layers.find((layer) => layer.getId() === id); - if (!layer) { - throw new Error(`Layer with id ${id} not found`); + moveItem(id: string, position: number): void { + const item = this._childrenIds.find((childId) => childId === id); + if (!item) { + throw new Error(`Child with id ${id} not found`); } - const layers = this._layers.filter((layer) => layer.getId() !== id); - layers.splice(position, 0, layer); + const items = this._childrenIds.filter((childId) => childId !== id); + items.splice(position, 0, item); - this._layers = layers; - this.notifySubscribers(LayerGroupTopic.LAYERS_CHANGED); + this._childrenIds = items; + this.notifySubscribers(LayerGroupTopic.ITEMS_CHANGED); } - insertLayer(layer: BaseLayer, position: number): void { - const layers = [...this._layers]; - layers.splice(position, 0, layer); - this._layers = layers; - this.notifySubscribers(LayerGroupTopic.LAYERS_CHANGED); + removeItem(id: string): void { + this._childrenIds = this._childrenIds.filter((childId) => childId !== id); + this._layerManager.removeItem(id); + this.notifySubscribers(LayerGroupTopic.ITEMS_CHANGED); } subscribe(topic: LayerGroupTopic, subscriber: () => void): void { @@ -135,8 +153,8 @@ export class LayerGroup { if (topic === LayerGroupTopic.NAME_CHANGED) { return this.getName(); } - if (topic === LayerGroupTopic.LAYERS_CHANGED) { - return this.getLayers(); + if (topic === LayerGroupTopic.ITEMS_CHANGED) { + return this._childrenIds; } if (topic === LayerGroupTopic.VISIBILITY_CHANGED) { return this.getIsVisible(); diff --git a/frontend/src/modules/_shared/layers/LayerManager.ts b/frontend/src/modules/_shared/layers/LayerManager.ts index 151c46495..86ddb6bbc 100644 --- a/frontend/src/modules/_shared/layers/LayerManager.ts +++ b/frontend/src/modules/_shared/layers/LayerManager.ts @@ -3,32 +3,25 @@ import React from "react"; import { QueryClient } from "@tanstack/query-core"; import { BaseLayer } from "./BaseLayer"; -import { LayerGroup, LayerGroupTopic } from "./LayerGroup"; -import { BaseSetting, SettingTopic } from "./settings/BaseSetting"; -import { SettingType } from "./settings/SettingTypes"; +import { LayerGroup } from "./LayerGroup"; +import { BaseSetting } from "./settings/BaseSetting"; export enum LayerManagerTopic { ITEMS_CHANGED = "items-changed", - LAYERS_CHANGED = "layers-changed", - LAYERS_CHANGED_RECURSIVELY = "layers-changed-recursively", - SETTINGS_CHANGED = "settings-changed", } export type LayerManagerTopicValueTypes = { - [LayerManagerTopic.ITEMS_CHANGED]: LayerManagerItem[]; - [LayerManagerTopic.LAYERS_CHANGED_RECURSIVELY]: BaseLayer[]; - [LayerManagerTopic.LAYERS_CHANGED]: BaseLayer[]; - [LayerManagerTopic.SETTINGS_CHANGED]: void; + [LayerManagerTopic.ITEMS_CHANGED]: LayerItem[]; }; -export type LayerManagerItem = BaseLayer | LayerGroup | BaseSetting; +export type LayerItem = BaseLayer | LayerGroup | BaseSetting; export class LayerManager { private _queryClient: QueryClient | null = null; private _subscribers: Map void>> = new Map(); - private _items: LayerManagerItem[] = []; - private _allLayers: BaseLayer[] = []; - private _settingsIteration: number = 0; + private _items: LayerItem[] = []; + + private _mainGroup: LayerGroup = new LayerGroup("Main", this); setQueryClient(queryClient: QueryClient): void { this._queryClient = queryClient; @@ -41,128 +34,24 @@ export class LayerManager { return this._queryClient; } - addLayer(layer: BaseLayer): void { - if (!this._queryClient) { - throw new Error("Query client not set"); - } - layer.setName(this.makeUniqueLayerName(layer.getName())); - layer.setQueryClient(this._queryClient); - this._items = [layer, ...this._items]; - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - this._allLayers = this.getAllLayersRecursively(); + getMainGroup(): LayerGroup { + return this._mainGroup; } - insertLayer(layer: BaseLayer, position: number): void { - if (!this._queryClient) { - throw new Error("Query client not set"); + addItem(item: LayerItem) { + if (item instanceof LayerGroup || item instanceof BaseLayer) { + item.setName(this.makeUniqueName(item.getName())); } - layer.setQueryClient(this._queryClient); - layer.setName(this.makeUniqueLayerName(layer.getName())); - this._items = [...this._items.slice(0, position), layer, ...this._items.slice(position)]; - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - this._allLayers = this.getAllLayersRecursively(); - } - - addGroup(name: string): void { - const uniqueName = this.makeUniqueGroupName(name); - const group = new LayerGroup(uniqueName, this); - this._items = [group, ...this._items]; - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - group.subscribe(LayerGroupTopic.LAYERS_CHANGED, () => { - this._allLayers = this.getAllLayersRecursively(); - this.notifySubscribers(LayerManagerTopic.LAYERS_CHANGED_RECURSIVELY); - }); - } - - insertGroup(group: LayerGroup, position: number): void { - this._items = [...this._items.slice(0, position), group, ...this._items.slice(position)]; - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - } - - addSetting(setting: BaseSetting): void { - this._items = [setting, ...this._items]; + this._items = [...this._items, item]; this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - setting.subscribe(SettingTopic.VALUE, () => { - this._settingsIteration++; - this.notifySubscribers(LayerManagerTopic.SETTINGS_CHANGED); - }); } - insertSetting(setting: BaseSetting, position: number): void { - this._items = [...this._items.slice(0, position), setting, ...this._items.slice(position)]; - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - setting.subscribe(SettingTopic.VALUE, () => { - this._settingsIteration++; - this.notifySubscribers(LayerManagerTopic.SETTINGS_CHANGED); - }); - } - - getSettings(): BaseSetting[] { - return this._items.filter((item) => item instanceof BaseSetting) as BaseSetting[]; - } - - getSettingOfType(type: SettingType): BaseSetting | undefined { - return this.getSettings().find((setting) => setting.getKey() === type); - } - - getSettingsOverridesForLayer(layer: BaseLayer): BaseSetting[] { - const settingsOverrides: BaseSetting[] = []; - for (const setting of this.getSettings()) { - settingsOverrides.push(setting); - } - - for (const group of this.getAllGroups()) { - if (group.getLayers().includes(layer)) { - for (const setting of this.getSettings()) { - settingsOverrides.push(setting); - } - } - } - - return settingsOverrides; - } - - removeLayer(id: string): void { - this._items = this._items.filter((item) => item.getId() !== id); - this._allLayers = this.getAllLayersRecursively(); - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - } - - removeGroup(id: string): void { - this._items = this._items.filter((item) => item.getId() !== id); - this._allLayers = this.getAllLayersRecursively(); - this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); - } - - getItem(id: string): LayerManagerItem | undefined { + getItem(id: string): LayerItem | undefined { return this._items.find((item) => item.getId() === id); } - getLayer(id: string): BaseLayer | undefined { - const item = this.getItem(id); - if (item instanceof BaseLayer) { - return item; - } - return undefined; - } - - getGroup(id: string): LayerGroup | undefined { - const item = this.getItem(id); - if (item instanceof LayerGroup) { - return item; - } - return undefined; - } - - getItems(): LayerManagerItem[] { - return this._items; - } - - changeOrder(order: string[]): void { - this._items = order.map((id) => this._items.find((item) => item.getId() === id)).filter(Boolean) as BaseLayer< - any, - any - >[]; + removeItem(id: string): void { + this._items = this._items.filter((item) => item.getId() !== id); this.notifySubscribers(LayerManagerTopic.ITEMS_CHANGED); } @@ -179,38 +68,10 @@ export class LayerManager { } } - private getAllLayersRecursively(): BaseLayer[] { - const layers: BaseLayer[] = []; - for (const item of this._items) { - if (item instanceof BaseLayer) { - layers.push(item); - } else if (item instanceof LayerGroup) { - layers.push(...item.getLayers()); - } - } - return layers; - } - - private getAllGroups(): LayerGroup[] { - return this._items.filter((item) => item instanceof LayerGroup) as LayerGroup[]; - } - - makeUniqueLayerName(name: string): string { + makeUniqueName(name: string): string { let potentialName = name; let i = 1; - const allLayers = this.getAllLayersRecursively(); - while (allLayers.some((layer) => layer.getName() === potentialName)) { - potentialName = `${name} (${i})`; - i++; - } - return potentialName; - } - - private makeUniqueGroupName(name: string): string { - let potentialName = name; - let i = 1; - const allGroups = this.getAllGroups(); - while (allGroups.some((group) => group.getName() === potentialName)) { + while (this._items.some((item) => item.getName() === potentialName)) { potentialName = `${name} (${i})`; i++; } @@ -237,12 +98,6 @@ export class LayerManager { if (topic === LayerManagerTopic.ITEMS_CHANGED) { return this._items; } - if (topic === LayerManagerTopic.LAYERS_CHANGED_RECURSIVELY) { - return this._allLayers; - } - if (topic === LayerManagerTopic.SETTINGS_CHANGED) { - return this._settingsIteration; - } }; return snapshotGetter;