diff --git a/docs/programming/logging.md b/docs/programming/logging.md
index a39eec8a0b3..3dd9200d39f 100644
--- a/docs/programming/logging.md
+++ b/docs/programming/logging.md
@@ -11,7 +11,7 @@ The logger class can be found here: [https://github.com/Canadian-Geospatial-Pla
The `logger` provides functions for high-level logging abstraction following best-practices concepts and the following constants:
```ts
// The most detailed messages. Disabled by default. Only shows if actually running in dev environment, never shown otherwise.
-export const LOG_TRACE_DETAILED 1;
+export const LOG_TRACE_DETAILED = 1;
// For tracing useEffect unmounting. Disabled by default. Only shows if running in dev environment or GEOVIEW_LOG_ACTIVE key is set in local storage.
export const LOG_TRACE_USE_EFFECT_UNMOUNT = 2;
// For tracing rendering. Disabled by default. Only shows if running in dev environment or GEOVIEW_LOG_ACTIVE key is set in local storage.
diff --git a/packages/geoview-core/public/configs/package-footer-panel-geochart-map1-config-geochart.json b/packages/geoview-core/public/configs/package-footer-panel-geochart-map1-config-geochart.json
index cfb75decb96..9bc3a7637b5 100644
--- a/packages/geoview-core/public/configs/package-footer-panel-geochart-map1-config-geochart.json
+++ b/packages/geoview-core/public/configs/package-footer-panel-geochart-map1-config-geochart.json
@@ -137,7 +137,7 @@
{
"layers": [
{
- "layerId": "geojsonLYR5/polygons.json"
+ "layerId": "geojsonLYR5/geojsonLYR5/polygons.json"
}
],
"chart": "pie",
@@ -232,7 +232,7 @@
{
"layers": [
{
- "layerId": "geojsonLYR5/point-feature-group/points.json"
+ "layerId": "geojsonLYR5/geojsonLYR5/point-feature-group/points.json"
}
],
"chart": "bar",
diff --git a/packages/geoview-core/public/configs/package-footer-panel-geochart-map2-config-geochart.json b/packages/geoview-core/public/configs/package-footer-panel-geochart-map2-config-geochart.json
index cfb75decb96..9bc3a7637b5 100644
--- a/packages/geoview-core/public/configs/package-footer-panel-geochart-map2-config-geochart.json
+++ b/packages/geoview-core/public/configs/package-footer-panel-geochart-map2-config-geochart.json
@@ -137,7 +137,7 @@
{
"layers": [
{
- "layerId": "geojsonLYR5/polygons.json"
+ "layerId": "geojsonLYR5/geojsonLYR5/polygons.json"
}
],
"chart": "pie",
@@ -232,7 +232,7 @@
{
"layers": [
{
- "layerId": "geojsonLYR5/point-feature-group/points.json"
+ "layerId": "geojsonLYR5/geojsonLYR5/point-feature-group/points.json"
}
],
"chart": "bar",
diff --git a/packages/geoview-core/public/templates/package-footer-panel-geochart.html b/packages/geoview-core/public/templates/package-footer-panel-geochart.html
index d9dbcecdd29..6c88e8c5fcd 100644
--- a/packages/geoview-core/public/templates/package-footer-panel-geochart.html
+++ b/packages/geoview-core/public/templates/package-footer-panel-geochart.html
@@ -40,7 +40,7 @@
Package Footer Panel With Geo-Chart
-
+
diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts
new file mode 100644
index 00000000000..359e658b64c
--- /dev/null
+++ b/packages/geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor.ts
@@ -0,0 +1,59 @@
+import { GeoviewStoreType } from '@/core/stores/geoview-store';
+import { AbstractEventProcessor } from '../abstract-event-processor';
+import { getGeoViewStore } from '@/core/stores/stores-managers';
+import { TypeJsonObject } from '@/core/types/global-types';
+import { GeoChartStoreByLayerPath } from '@/core/stores/store-interface-and-intial-values/geochart-state';
+
+export class GeochartEventProcessor extends AbstractEventProcessor {
+ onInitialize(store: GeoviewStoreType) {
+ store.getState();
+
+ // add to arr of subscriptions so it can be destroyed later
+ this.subscriptionArr.push();
+ }
+
+ // **********************************************************
+ // Static functions for Typescript files to access store actions
+ // **********************************************************
+ //! Typescript MUST always use store action to modify store - NEVER use setState!
+ //! Some action does state modifications AND map actions.
+ //! ALWAYS use map event processor when an action modify store and IS NOT trap by map state event handler
+
+ // #region
+
+ /**
+ * Set the default layers from configuration.
+ * In the store, the GeoChart configurations are stored in an object with layerPath as its property name
+ * (to retrieve the configuration per layer faster).
+ *
+ * @param {string} mapId the map id
+ * @param {TypeJsonObject} charts The array of JSON configuration for geochart
+ */
+ static setGeochartCharts(mapId: string, charts: TypeJsonObject[]): void {
+ // The store object representation
+ const chartData: GeoChartStoreByLayerPath = {};
+
+ // Loop on the charts
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ charts.forEach((chartInfo: any) => {
+ // For each layer path
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ chartInfo.layers.forEach((layer: any) => {
+ // Get the layer path
+ const layerPath = layer.layerId;
+ chartData[layerPath] = chartInfo;
+ });
+ });
+
+ // set store charts config
+ getGeoViewStore(mapId).getState().geochartState.actions.setGeochartCharts(chartData);
+ }
+
+ // #endregion
+
+ // **********************************************************
+ // Static functions for Store Map State to action on API
+ // **********************************************************
+ //! NEVER add a store action who does set state AND map action at a same time.
+ //! Review the action in store state to make sure
+}
diff --git a/packages/geoview-core/src/api/event-processors/index.ts b/packages/geoview-core/src/api/event-processors/index.ts
deleted file mode 100644
index 2034644e339..00000000000
--- a/packages/geoview-core/src/api/event-processors/index.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-import { AppEventProcessor } from '@/api/event-processors/event-processor-children/app-event-processor';
-import { FeatureInfoEventProcessor } from '@/api/event-processors/event-processor-children/feature-info-event-processor';
-import { GeoviewStoreType } from '@/core/stores/geoview-store';
-import { LegendEventProcessor } from '@/api/event-processors/event-processor-children/legend-event-processor';
-import { MapEventProcessor } from '@/api/event-processors/event-processor-children/map-event-processor';
-import { TimeSliderEventProcessor } from '@/api/event-processors/event-processor-children/time-slider-event-processor';
-
-const appEventProcessor = new AppEventProcessor();
-const featureInfoEventProcessor = new FeatureInfoEventProcessor();
-const legendEventProcessor = new LegendEventProcessor();
-const mapEventProcessor = new MapEventProcessor();
-const timeSliderEventProcessor = new TimeSliderEventProcessor();
-
-export function initializeEventProcessors(store: GeoviewStoreType) {
- // core stores
- appEventProcessor.onInitialize(store);
- featureInfoEventProcessor.onInitialize(store);
- legendEventProcessor.onInitialize(store);
- mapEventProcessor.onInitialize(store);
-
- // package stores, only create if needed
- // TODO: Change this check for something more generic that checks in appBarTabs too
- if (store.getState().mapConfig!.footerTabs?.tabs.core.includes('time-slider')) timeSliderEventProcessor.onInitialize(store);
-}
-
-export function destroyEventProcessors(store: GeoviewStoreType) {
- // core stores
- appEventProcessor.onDestroy(store);
- featureInfoEventProcessor.onDestroy(store);
- legendEventProcessor.onDestroy(store);
- mapEventProcessor.onDestroy(store);
-
- // package stores, only destroy if created
- // TODO: Change this check for something more generic that checks in appBarTabs too
- if (store.getState().mapConfig!.footerTabs?.tabs.core.includes('time-slider')) timeSliderEventProcessor.onDestroy(store);
-}
diff --git a/packages/geoview-core/src/core/app-start.tsx b/packages/geoview-core/src/core/app-start.tsx
index 7f44ec483d8..7a33e895e17 100644
--- a/packages/geoview-core/src/core/app-start.tsx
+++ b/packages/geoview-core/src/core/app-start.tsx
@@ -1,4 +1,4 @@
-import React, { Suspense, useMemo } from 'react';
+import { createContext, Suspense, useMemo } from 'react';
import './translation/i18n';
import i18n from 'i18next';
@@ -15,7 +15,7 @@ import { api, useAppDisplayLanguageById, useAppDisplayThemeById } from '@/app';
// create a state that will hold map config information
// TODO: use store, only keep map id on context for store manager to gather right store on hooks
-export const MapContext = React.createContext({
+export const MapContext = createContext({
mapId: '',
mapFeaturesConfig: undefined,
});
@@ -76,7 +76,9 @@ function AppStart(props: AppStartProps): JSX.Element {
+ {/* */}
+ {/* */}
diff --git a/packages/geoview-core/src/core/components/common/layer-list.tsx b/packages/geoview-core/src/core/components/common/layer-list.tsx
index e167d5bf794..683b8aa8904 100644
--- a/packages/geoview-core/src/core/components/common/layer-list.tsx
+++ b/packages/geoview-core/src/core/components/common/layer-list.tsx
@@ -7,9 +7,9 @@ import { IconStack } from '@/app';
export interface LayerListEntry {
layerName: string;
layerPath: string;
- layerFeatures?: ReactNode | undefined;
- mapFilteredIcon?: ReactNode | undefined;
- tooltip?: ReactNode | undefined;
+ layerFeatures?: ReactNode;
+ mapFilteredIcon?: ReactNode;
+ tooltip?: ReactNode;
numOffeatures?: number;
}
diff --git a/packages/geoview-core/src/core/components/common/layout.tsx b/packages/geoview-core/src/core/components/common/layout.tsx
index ffa991475c0..6530d882df8 100644
--- a/packages/geoview-core/src/core/components/common/layout.tsx
+++ b/packages/geoview-core/src/core/components/common/layout.tsx
@@ -57,7 +57,7 @@ export function Layout({ children, layerList, handleLayerList, selectedLayerPath
/>
);
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [selectedLayerPath, isEnlargeDataTable]);
+ }, [selectedLayerPath, isEnlargeDataTable, layerList]);
return (
diff --git a/packages/geoview-core/src/core/stores/geoview-store.ts b/packages/geoview-core/src/core/stores/geoview-store.ts
index 9a476f1d156..e71dcc4a0be 100644
--- a/packages/geoview-core/src/core/stores/geoview-store.ts
+++ b/packages/geoview-core/src/core/stores/geoview-store.ts
@@ -10,6 +10,7 @@ import { ILayerState, initializeLayerState } from './store-interface-and-intial-
import { IMapState, initializeMapState } from './store-interface-and-intial-values/map-state';
import { IMapDataTableState, initialDataTableState } from './store-interface-and-intial-values/data-table-state';
import { ITimeSliderState, initializeTimeSliderState } from './store-interface-and-intial-values/time-slider-state';
+import { IGeochartState, initializeGeochartState } from './store-interface-and-intial-values/geochart-state';
import { IUIState, initializeUIState } from './store-interface-and-intial-values/ui-state';
import { TypeMapFeaturesConfig } from '@/core/types/global-types';
@@ -26,14 +27,17 @@ export interface IGeoviewState {
mapId: string;
setMapConfig: (config: TypeMapFeaturesConfig) => void;
- // state interfaces
+ // core state interfaces
appState: IAppState;
detailsState: IDetailsState;
dataTableState: IMapDataTableState;
layerState: ILayerState;
mapState: IMapState;
- timeSliderState: ITimeSliderState;
uiState: IUIState;
+
+ // packages state interface
+ geochartState: IGeochartState;
+ timeSliderState: ITimeSliderState;
}
export const geoviewStoreDefinition = (set: TypeSetStore, get: TypeGetStore) => {
@@ -56,6 +60,7 @@ export const geoviewStoreDefinition = (set: TypeSetStore, get: TypeGetStore) =>
// packages states, only create if needed
// TODO: Change this check for something more generic that checks in appBarTabs too
if (config.footerTabs?.tabs.core.includes('time-slider')) set({ timeSliderState: initializeTimeSliderState(set, get) });
+ if (config.footerTabs?.tabs.core.includes('geochart')) set({ geochartState: initializeGeochartState(set, get) });
},
// core states
diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts
new file mode 100644
index 00000000000..812453f1795
--- /dev/null
+++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state.ts
@@ -0,0 +1,55 @@
+import { useStore } from 'zustand';
+import { useGeoViewStore } from '../stores-managers';
+import { TypeGetStore, TypeSetStore } from '../geoview-store';
+
+export type GeoChartStoreByLayerPath = {
+ [layerPath: string]: ChartInfo;
+};
+
+export type ChartInfo = unknown; // unknown, because the definition is in the external package
+
+// #region INTERFACES
+export interface IGeochartState {
+ geochartChartsConfig: GeoChartStoreByLayerPath;
+ // geochartLayers: TypeJsonObject[];
+ // visibleGeochartLayers: string[];
+
+ actions: {
+ setGeochartCharts: (charts: GeoChartStoreByLayerPath) => void;
+ // setGeochartLayers: (layers: TypeJsonObject) => void;
+ };
+}
+// #endregion INTERFACES
+
+export function initializeGeochartState(set: TypeSetStore, get: TypeGetStore): IGeochartState {
+ const init = {
+ geochartChartsConfig: {},
+ // geochartLayers: {},
+ // geochartChartsConfig: [],
+ // visibleGeochartLayers: [],
+
+ // #region ACTIONS
+ actions: {
+ setGeochartCharts(charts: GeoChartStoreByLayerPath): void {
+ set({
+ geochartState: {
+ ...get().geochartState,
+ geochartChartsConfig: charts,
+ },
+ });
+ },
+ // #endregion ACTIONS
+ },
+ } as IGeochartState;
+
+ return init;
+}
+
+// **********************************************************
+// Layer state selectors
+// **********************************************************
+export const useGeochartConfigs = () => useStore(useGeoViewStore(), (state) => state.geochartState.geochartChartsConfig);
+// export const useGeochartLayers = () => useStore(useGeoViewStore(), (state) => state.geochartState.geochartLayers);
+// export const useVisibleGeochartLayers = () => useStore(useGeoViewStore(), (state) => state.geochartState.visibleGeochartLayers);
+
+export const useGeochartStoreActions = () => useStore(useGeoViewStore(), (state) => state.geochartState.actions);
diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/layer-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/layer-state.ts
index 4c777589af6..3ae53a368d7 100644
--- a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/layer-state.ts
+++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/layer-state.ts
@@ -303,7 +303,7 @@ function findLayerByPath(layers: TypeLegendLayer[], layerPath: string): TypeLege
if (layerPath === l.layerPath) {
return l;
}
- if (layerPath.startsWith(l.layerPath) && l.children?.length > 0) {
+ if (layerPath?.startsWith(l.layerPath) && l.children?.length > 0) {
const result: TypeLegendLayer | undefined = findLayerByPath(l.children, layerPath);
if (result) {
return result;
diff --git a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/time-slider-state.ts b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/time-slider-state.ts
index 086c711ccbd..aa421d9b7f7 100644
--- a/packages/geoview-core/src/core/stores/store-interface-and-intial-values/time-slider-state.ts
+++ b/packages/geoview-core/src/core/stores/store-interface-and-intial-values/time-slider-state.ts
@@ -3,6 +3,7 @@ import { useGeoViewStore } from '../stores-managers';
import { TypeGetStore, TypeSetStore } from '../geoview-store';
import { TimeSliderEventProcessor } from '@/api/event-processors/event-processor-children/time-slider-event-processor';
+// #region INTERFACES
export interface TypeTimeSliderValues {
title?: string;
description?: string;
@@ -23,6 +24,7 @@ export interface TypeTimeSliderValues {
export interface ITimeSliderState {
timeSliderLayers: { [index: string]: TypeTimeSliderValues };
visibleTimeSliderLayers: string[];
+
actions: {
addTimeSliderLayer: (newLayer: { [index: string]: TypeTimeSliderValues }) => void;
applyFilters: (layerPath: string, values: number[]) => void;
@@ -38,11 +40,14 @@ export interface ITimeSliderState {
setVisibleTimeSliderLayers: (visibleLayerPaths: string[]) => void;
};
}
+// #endregion INTERFACES
export function initializeTimeSliderState(set: TypeSetStore, get: TypeGetStore): ITimeSliderState {
const init = {
timeSliderLayers: {},
visibleTimeSliderLayers: [],
+
+ // #region ACTIONS
actions: {
addTimeSliderLayer(newLayer: { [index: string]: TypeTimeSliderValues }): void {
set({
@@ -157,6 +162,7 @@ export function initializeTimeSliderState(set: TypeSetStore, get: TypeGetStore):
},
});
},
+ // #endregion ACTIONS
},
} as ITimeSliderState;
@@ -168,4 +174,5 @@ export function initializeTimeSliderState(set: TypeSetStore, get: TypeGetStore):
// **********************************************************
export const useTimeSliderLayers = () => useStore(useGeoViewStore(), (state) => state.timeSliderState.timeSliderLayers);
export const useVisibleTimeSliderLayers = () => useStore(useGeoViewStore(), (state) => state.timeSliderState.visibleTimeSliderLayers);
+
export const useTimeSliderStoreActions = () => useStore(useGeoViewStore(), (state) => state.timeSliderState.actions);
diff --git a/packages/geoview-core/src/ui/autocomplete/autocomplete.tsx b/packages/geoview-core/src/ui/autocomplete/autocomplete.tsx
index a3d9942833e..5ed8482a48c 100644
--- a/packages/geoview-core/src/ui/autocomplete/autocomplete.tsx
+++ b/packages/geoview-core/src/ui/autocomplete/autocomplete.tsx
@@ -9,10 +9,7 @@ export interface TypeAutocompleteProps<
DisableClearable extends boolean | undefined = undefined,
FreeSolo extends boolean | undefined = undefined
> extends AutocompleteProps {
- // eslint-disable-next-line react/require-default-props
- mapId?: string;
- // eslint-disable-next-line react/require-default-props
- fullWidth?: boolean;
+ fullWidth: boolean;
}
/**
diff --git a/packages/geoview-geochart/src/geochart-panel.tsx b/packages/geoview-geochart/src/geochart-panel.tsx
index e816fa7c034..bc4315c82e6 100644
--- a/packages/geoview-geochart/src/geochart-panel.tsx
+++ b/packages/geoview-geochart/src/geochart-panel.tsx
@@ -1,21 +1,24 @@
+import { useTranslation } from 'react-i18next';
+import { useTheme } from '@mui/material/styles';
import { TypeWindow } from 'geoview-core';
import { ChartType, SchemaValidator } from 'geochart';
import { LayerListEntry, Layout } from 'geoview-core/src/core/components/common';
+import { TypeArrayOfLayerData, TypeLayerData } from 'geoview-core/src/api/events/payloads';
+import { Typography } from 'geoview-core/src/ui/typography/typography';
+import { Paper } from 'geoview-core/src/ui';
+import { logger } from 'geoview-core/src/core/utils/logger';
+import { useMapVisibleLayers } from 'geoview-core/src/core/stores/store-interface-and-intial-values/map-state';
+import { useDetailsStoreLayerDataArray } from 'geoview-core/src/core/stores';
+import { useGeochartConfigs } from 'geoview-core/src/core/stores/store-interface-and-intial-values/geochart-state';
import { GeoChart } from './geochart';
-import { PluginGeoChartConfig } from './geochart-types';
+import { GeoViewGeoChartConfig } from './geochart-types';
+
+import { getSxClasses } from './geochart-style';
interface GeoChartPanelProps {
mapId: string;
- configObj: PluginGeoChartConfig;
- layerList: LayerListEntry[];
}
-const { cgpv } = window as TypeWindow;
-
-type GeoChartLayerChartConfig = {
- [layerPath: string]: PluginGeoChartConfig;
-};
-
/**
* Geo Chart tab
*
@@ -23,41 +26,130 @@ type GeoChartLayerChartConfig = {
* @returns {JSX.Element} Geo Chart tab
*/
export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element {
- const { mapId, configObj, layerList } = props;
- const { react, ui } = cgpv;
- const { useState } = react;
- const { Box } = ui.elements;
+ // Log
+ logger.logTraceRender('geochart/geochart-panel');
+
+ const { cgpv } = window as TypeWindow;
+ const { mapId } = props;
+ const { react } = cgpv;
+ const { useState, useCallback, useEffect } = react;
+
+ const { t } = useTranslation();
+ const theme = useTheme();
+ const sxClasses = getSxClasses(theme);
+
+ // Prepare the states
const [selectedLayerPath, setSelectedLayerPath] = useState('');
+ const [geoChartLayersList, setGeoChartLayersList] = useState([]);
- // For a GeoChart to be used in a footer panel with a layer selection happening independently from the GeoChart itself,
- // we want 1 chart per layer, so this splits the main config in multiple chunks for each chart layer
- const layerChartConfigsState: GeoChartLayerChartConfig = {};
- configObj.charts.forEach((chart) => {
- // Retrieve a chart config for each layer
- const specificChartConfig = { charts: [chart] };
- const lyrPaths = chart.layers?.map((lyr) => {
- return lyr.layerId;
- });
- lyrPaths?.forEach((lyrPath) => {
- if (!(lyrPath in layerChartConfigsState)) {
- layerChartConfigsState[lyrPath] = specificChartConfig;
- }
- });
- });
- const [layerChartConfigs] = useState(layerChartConfigsState);
+ // get store geochart info
+ const configObj = useGeochartConfigs();
+ const visibleLayers = useMapVisibleLayers() as string[];
+ const arrayOfLayerData = useDetailsStoreLayerDataArray() as TypeArrayOfLayerData;
// Create the validator shared for all the charts in the footer
const [schemaValidator] = useState(new SchemaValidator());
+ /**
+ * Get number of features of a layer.
+ * @returns string
+ */
+ const getFeaturesOfLayer = useCallback(
+ (layer: TypeLayerData): string => {
+ const numOfFeatures = layer.features?.length ?? 0;
+ return `${numOfFeatures} ${t('details.feature')}${numOfFeatures > 1 ? 's' : ''}`;
+ },
+ [t]
+ );
+
/**
* Handles clicks to layers in left panel. Sets selected layer.
*
* @param {LayerListEntry} layer The data of the selected layer
*/
- const handleLayerChange = (layer: LayerListEntry): void => {
+ const handleLayerChange = useCallback((layer: LayerListEntry): void => {
+ // Log
+ logger.logTraceUseCallback('GEOCHART-PANEL - layer', layer);
+
+ // Set the selected layer path
setSelectedLayerPath(layer.layerPath);
- };
+
+ // Don't redraw for now, it's a bit overkill and annoying.
+ // We don't need to redraw on every change of the layer.
+ // We need to redraw when the canvas isn't 'ready' in the DOM. The canvas is essentially
+ // not ready upon first load and when the user resizes the canvas placeholder.
+ // cgpv.api.maps[mapId].plugins.geochart.redrawChart();
+ }, []);
+
+ useEffect(() => {
+ // Log, leaving the logDebug here, because there's something funky going on across branches and this helps figuring it out
+ logger.logDebug('selected layer path changed', selectedLayerPath);
+ }, [selectedLayerPath]);
+
+ // Reacts when the array of layer data updates
+ useEffect(() => {
+ // Log
+ logger.logTraceUseEffect('GEOCHART-PANEL - ArrayOfLayerData', arrayOfLayerData);
+
+ // Update the layers list information
+ const layerListEntry: LayerListEntry[] = [];
+ arrayOfLayerData.forEach((layer) => {
+ // If the layer is visible and has a chart in the config
+ if (visibleLayers.includes(layer.layerPath) && configObj[layer.layerPath]) {
+ layerListEntry.push({
+ layerName: layer.layerName ?? '',
+ layerPath: layer.layerPath,
+ numOffeatures: layer.features?.length ?? 0,
+ layerFeatures: getFeaturesOfLayer(layer),
+ tooltip: `${layer.layerName}, ${getFeaturesOfLayer(layer)}`,
+ });
+ }
+ });
+
+ // Set the list
+ setGeoChartLayersList(layerListEntry);
+ }, [arrayOfLayerData, configObj, getFeaturesOfLayer, visibleLayers]);
+
+ // Reacts when the list of layers being officially listed changed
+ useEffect(() => {
+ // Log
+ logger.logTraceUseEffect('GEOCHART-PANEL - GeoChartLayersList', geoChartLayersList, selectedLayerPath);
+
+ // If there was a selected layer path already
+ let changeSelectedLayerPath = false;
+ if (selectedLayerPath) {
+ // Get the layer list entry for that layer path
+ const geoChartLayerEntry = geoChartLayersList.find((geoChartLayer: LayerListEntry) => geoChartLayer.layerPath === selectedLayerPath);
+
+ // If found
+ if (geoChartLayerEntry) {
+ // Check if there's nothing currently selected on that layer path
+ if (!geoChartLayerEntry.numOffeatures) {
+ changeSelectedLayerPath = true;
+ } else {
+ // There is something, stay on it.
+ }
+ }
+ } else {
+ // Find another layer with features
+ changeSelectedLayerPath = true;
+ }
+
+ // If changing
+ if (changeSelectedLayerPath) {
+ // Find another layer with features
+ const anotherGeoChartLayerEntry = geoChartLayersList.find((geoChartLayer: LayerListEntry) => geoChartLayer.numOffeatures);
+ // If found
+ if (anotherGeoChartLayerEntry) {
+ // Select that one
+ setSelectedLayerPath(anotherGeoChartLayerEntry.layerPath);
+ } else {
+ // None found, select none
+ setSelectedLayerPath('');
+ }
+ }
+ }, [geoChartLayersList, selectedLayerPath]);
/**
* Renders a single GeoChart component
@@ -65,31 +157,50 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element {
* @param sx CSSProperties Styling to apply (basically if the GeoChart should be visible or not depending on the selected layer)
* @returns JSX.Element
*/
- const renderChart = (chartConfig: PluginGeoChartConfig, sx: React.CSSProperties, key: string) => {
- return ;
+ const renderChart = (chartConfig: GeoViewGeoChartConfig, sx: React.CSSProperties, key: string) => {
+ return ;
};
- // Loop on the layers to find out which is selected and grab the chart associated with the selected layer by moving its position to 0px
- // TODO: Remove the TEMP REDRAW button, obviously. Maybe think of a better way to handle the chart rendering? Leaving it like this for now.
- return (
-
-
- {
- cgpv.api.maps[mapId].plugins.geochart.redrawChart();
- }}
- />
-
- {Object.entries(layerChartConfigs).map(([layerPath, layerChartConfig], index) => {
- const sx: React.CSSProperties = { position: 'absolute', top: '-5000px' };
- if (layerPath === selectedLayerPath) {
- sx.top = '0px';
- }
- return renderChart(layerChartConfig, sx, index.toString());
- })}
-
- );
+ /**
+ * Renders the complete GeoChart Panel component
+ * @returns JSX.Element
+ */
+ const renderComplete = () => {
+ if (geoChartLayersList) {
+ if (geoChartLayersList.length > 0) {
+ return (
+
+ {selectedLayerPath &&
+ Object.entries(configObj).map(([layerPath, layerChartConfig], index) => {
+ const sx: React.CSSProperties = { position: 'absolute', top: '-5000px' };
+ if (layerPath === selectedLayerPath) {
+ sx.top = '0px';
+ }
+ return renderChart(layerChartConfig as GeoViewGeoChartConfig, sx, index.toString());
+ })}
+ {!selectedLayerPath && (
+
+
+ {t('geochart.chartPanel.noLayers')}
+
+
+ {t('geochart.chartPanel.noLayers')}
+
+
+ )}
+
+ );
+ }
+
+ // No layers
+ return {t('chartPanel.panel.noLayers')};
+ }
+
+ // Loading UI
+ return {t('chartPanel.panel.loadingUI')};
+ // return ;
+ };
+
+ // Render
+ return renderComplete();
}
diff --git a/packages/geoview-geochart/src/geochart-style.ts b/packages/geoview-geochart/src/geochart-style.ts
new file mode 100644
index 00000000000..0b3d98775f4
--- /dev/null
+++ b/packages/geoview-geochart/src/geochart-style.ts
@@ -0,0 +1,11 @@
+import { Theme } from '@mui/material/styles';
+
+export const getSxClasses = (theme: Theme) => ({
+ detailsInstructionsTitle: {
+ font: theme.footerPanel.titleFont,
+ fontSize: '1.5rem',
+ },
+ detailsInstructionsBody: {
+ fontSize: '1rem',
+ },
+});
diff --git a/packages/geoview-geochart/src/geochart.tsx b/packages/geoview-geochart/src/geochart.tsx
index e96ae62f7e5..1ef6dfe63ed 100644
--- a/packages/geoview-geochart/src/geochart.tsx
+++ b/packages/geoview-geochart/src/geochart.tsx
@@ -46,7 +46,7 @@ export function GeoChart(props: GeoChartProps): JSX.Element {
// Tweak the default colors based on the theme
const defaultColors: GeoChartDefaultColors = {
backgroundColor: theme.palette.background.default,
- borderColor: theme.palette.border.primary,
+ borderColor: 'black', // theme.palette.primary,
color: theme.palette.primary.main,
};
diff --git a/packages/geoview-geochart/src/index-appbar.tsx b/packages/geoview-geochart/src/index-appbar.tsx
index a57b48c537c..990b5af7366 100644
--- a/packages/geoview-geochart/src/index-appbar.tsx
+++ b/packages/geoview-geochart/src/index-appbar.tsx
@@ -1,12 +1,11 @@
import { Cast, AnySchemaObject, TypeIconButtonProps, TypePanelProps, toJsonObject, TypeJsonObject } from 'geoview-core';
import { AppBarPlugin } from 'geoview-core/src/api/plugin/appbar-plugin';
-import { ChartType, SchemaValidator } from 'geochart';
+import { ChartType } from 'geochart';
import { ChartIcon } from 'geoview-core/src/ui/icons';
import { PayloadBaseClassChart, EVENT_CHART_REDRAW } from './geochart-event-base';
import { PayloadChartConfig } from './geochart-event-config';
import { PluginGeoChartConfig } from './geochart-types';
-import { GeoChart } from './geochart';
import schema from '../schema.json';
import defaultConfig from '../default-config-geochart.json';
@@ -70,7 +69,9 @@ export class GeoChartAppBarPlugin extends AppBarPlugin {
onCreateContent(): JSX.Element {
// Fetch cgpv
- return ;
+ // TODO: Create a geochart-appbar-panel equivalent to geochart-panel to hold the GeoChart itself and hook on the useGeochartConfigs store the same way geochart-panel does it
+ // return ;
+ return Not implemented
;
}
/**
diff --git a/packages/geoview-geochart/src/index.tsx b/packages/geoview-geochart/src/index.tsx
index 7622432789c..7d4ffe0714b 100644
--- a/packages/geoview-geochart/src/index.tsx
+++ b/packages/geoview-geochart/src/index.tsx
@@ -2,9 +2,9 @@ import { Cast, AnySchemaObject, toJsonObject, TypeJsonObject } from 'geoview-cor
import { FooterPlugin } from 'geoview-core/src/api/plugin/footer-plugin';
import { TypeTabs } from 'geoview-core/src/ui/tabs/tabs';
import { ChartType } from 'geochart';
-import { LayerListEntry } from 'geoview-core/src/core/components/common';
import { ChartIcon } from 'geoview-core/src/ui/icons';
+import { GeochartEventProcessor } from 'geoview-core/src/api/event-processors/event-processor-children/geochart-event-processor';
import { PayloadBaseClassChart, EVENT_CHART_REDRAW } from './geochart-event-base';
import { PayloadChartConfig } from './geochart-event-config';
import { PluginGeoChartConfig } from './geochart-types';
@@ -37,54 +37,32 @@ class GeoChartFooterPlugin extends FooterPlugin {
en: {
chartPanel: {
title: 'Chart',
+ panel: {
+ noLayers: 'No layers with chart data',
+ },
},
},
fr: {
chartPanel: {
title: 'Graphique',
+ panel: {
+ noLayers: 'Pas de couches avec des données graphiques',
+ },
},
},
});
- onCreateContentProps(): TypeTabs {
- // Cast the config
- const chartConfig: PluginGeoChartConfig | undefined = this.configObj;
-
- // Create content
- const layerList = chartConfig?.charts
- .map((chart) => {
- const layerIds =
- chart.layers?.map((layer) => {
- return layer.layerId;
- }) ?? [];
-
- return layerIds;
- })
- .flat()
- .reduce((acc, curr) => {
- if (this.api.maps[this.pluginProps.mapId].layer.registeredLayers[curr]) {
- const currLayer = this.api.maps[this.pluginProps.mapId].layer.registeredLayers[curr];
- const layerName =
- currLayer.layerName && this.displayLanguage() in currLayer.layerName
- ? currLayer.layerName[this.displayLanguage()]
- : currLayer.layerName;
- const layerData = {
- layerName,
- layerPath: curr,
- tooltip: layerName,
- };
- acc.push(layerData);
- }
+ onAdd(): void {
+ // Initialize the store with geochart provided configuration
+ GeochartEventProcessor.setGeochartCharts(this.pluginProps.mapId, this.configObj.charts);
- return acc;
- }, [] as LayerListEntry[]);
+ // Call parent
+ super.onAdd();
+ }
- // If any layers list
- let content = No layers in config
;
- if (layerList) {
- // Create element
- content = ;
- }
+ onCreateContentProps(): TypeTabs {
+ // Create element
+ const content = ;
return {
id: 'geochart',
diff --git a/packages/geoview-time-slider/src/time-slider-panel.tsx b/packages/geoview-time-slider/src/time-slider-panel.tsx
index 2d69a9e928c..699a589be74 100644
--- a/packages/geoview-time-slider/src/time-slider-panel.tsx
+++ b/packages/geoview-time-slider/src/time-slider-panel.tsx
@@ -2,6 +2,7 @@ import { TypeWindow } from 'geoview-core';
import { LayerListEntry, Layout } from 'geoview-core/src/core/components/common';
import { useVisibleTimeSliderLayers, useTimeSliderLayers } from 'geoview-core/src/core/stores';
import { getLocalizedMessage } from 'geoview-core/src/core/utils/utilities';
+import { Typography } from 'geoview-core/src/ui';
import { TimeSlider } from './time-slider';
import { ConfigProps } from './time-slider-types';
@@ -20,9 +21,8 @@ const { cgpv } = window as TypeWindow;
*/
export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element {
const { mapId, configObj } = props;
- const { react, ui } = cgpv;
- const { useState, useEffect } = react;
- const { Box } = ui.elements;
+ const { react } = cgpv;
+ const { useState, useEffect, useCallback } = react;
// internal state
const [selectedLayerPath, setSelectedLayerPath] = useState();
@@ -44,18 +44,19 @@ export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [visibleTimeSliderLayers]);
- if (!visibleTimeSliderLayers.length) return {getLocalizedMessage(mapId, 'timeSlider.panel.noLayers')};
+ const renderLayerList = useCallback(() => {
+ const array = visibleTimeSliderLayers.map((layerPath: string) => {
+ return { layerName: timeSliderLayers[layerPath].name, layerPath, tooltip: timeSliderLayers[layerPath].name };
+ });
+
+ return array;
+ }, [timeSliderLayers, visibleTimeSliderLayers]);
+
return selectedLayerPath ? (
- {
- return { layerName: timeSliderLayers[layerPath].name, layerPath, tooltip: timeSliderLayers[layerPath].name };
- })}
- >
+
) : (
-
+ {getLocalizedMessage(mapId, 'timeSlider.panel.noLayers')}
);
}