Skip to content

Commit

Permalink
feat(basemap): satellite basemap added
Browse files Browse the repository at this point in the history
Closes #1849
  • Loading branch information
DamonU2 committed Jul 12, 2024
1 parent fb8df41 commit 99f3682
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 153 deletions.
10 changes: 10 additions & 0 deletions packages/geoview-basemap-panel/default-config-basemap-panel.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
"shaded": true,
"labeled": false
},
{
"basemapId": "satellite",
"shaded": false,
"labeled": false
},
{
"basemapId": "osm",
"shaded": true,
Expand Down Expand Up @@ -51,6 +56,11 @@
"shaded": true,
"labeled": false
},
{
"basemapId": "satellite",
"shaded": false,
"labeled": false
},
{
"basemapId": "osm",
"shaded": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-basemap-panel/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
"basemapId": {
"type": "string",
"description": "the basemap id",
"enum": ["transport", "simple", "shaded", "osm", "nogeom"]
"enum": ["transport", "simple", "shaded", "osm", "nogeom", "satellite"]
},
"shaded": {
"type": "boolean",
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-basemap-panel/src/basemap-panel-style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export const getSxClasses = (theme): any => ({
height: '100%',
width: '100%',
position: 'absolute',
backgroundColor: theme.palette.geoViewColor.grey.lighten(0.5, 0.85),
backgroundColor: theme.palette.geoViewColor.grey.lighten(0.5, 0.6),
transition: 'all 0.3s ease-in-out',
},
},
Expand Down
116 changes: 62 additions & 54 deletions packages/geoview-basemap-panel/src/basemap-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
const theme = ui.useTheme();
const sxClasses = getSxClasses(theme);

// internal state and store values
// Internal state and store values
const [basemapList, setBasemapList] = useState<TypeBasemapProps[]>([]);
const [activeBasemapId, setActiveBasemapId] = useState<string>('');
const [canSwichProjection] = useState(config.canSwichProjection);
Expand All @@ -37,14 +37,13 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
const language = useAppDisplayLanguage();

// #region PRIVATE UTILITY FUNCTIONS

/**
* Get basemap thumbnail url
*
* @param {string[]} basemapTypes basemap layer type (shaded, transport, label, simple)
* @param {TypeValidMapProjectionCodes} projection basemap projection
* @param {TypeDisplayLanguage} displayLanguage basemap language
*
* @returns {string[]} array of thumbnail urls
* Get basemap thumbnail url.
* @param {string[]} basemapTypes - Basemap layer type (shaded, transport, label, simple, satellite).
* @param {TypeValidMapProjectionCodes} projection - Basemap projection.
* @param {TypeDisplayLanguage} displayLanguage - Basemap language.
* @returns {string[]} Array of thumbnail urls.
*/
function getThumbnailUrl(
basemapTypes: string[],
Expand Down Expand Up @@ -100,16 +99,26 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
if (type === 'osm') {
thumbnailUrls.push('https://tile.openstreetmap.org/0/0/0.png');
}

if (type === 'satellite') {
if (myMap.basemap.basemapsList[projection].satellite?.url) {
thumbnailUrls.push(
(myMap.basemap.basemapsList[projection].satellite?.url as string)
.replace('{z}', '8')
.replace('{y}', projection === 3978 ? '285' : '91')
.replace('{x}', projection === 3978 ? '268' : '74')
);
}
}
}

return thumbnailUrls;
}

/**
* Get basemap information (name and description)
*
* @param {string[]} basemapTypes basemap layer type (shaded, transport, label, simple)
* @returns { name: string; description: string } array with information [name, description]
* Get basemap information (name and description).
* @param {string[]} basemapTypes - Basemap layer type (shaded, transport, label, simple).
* @returns { name: string; description: string } Array with information [name, description].
*/
function getInfo(basemapTypes: string[]): { name: string; description: string } {
let name = '';
Expand All @@ -127,6 +136,8 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
description = getLocalizedMessage('basemapPanel.info.shaded.description', language);
} else if (basemapTypes.includes('nogeom')) {
name = getLocalizedMessage('basemapPanel.info.nogeom.name', language);
} else if (basemapTypes.includes('satellite')) {
name = getLocalizedMessage('basemapPanel.info.satellite.name', language);
}

if (basemapTypes.includes('label')) name = `${name} ${getLocalizedMessage('basemapPanel.info.label.name', language)}`;
Expand All @@ -136,94 +147,91 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
// #endregion

/**
* Update the basemap with the layers on the map
*
* @param {string} id update the basemap on the map
* Update the basemap with the layers on the map.
* @param {string} basemapId - The id to update the basemap on the map.
*/
const setBasemap = (basemapId: string): void => {
// get basemap from id
// Get basemap from id
const basemap = basemapList.find((item) => item.basemapId === basemapId);

// set the new basemap and update the active basemap variable
// Set the new basemap and update the active basemap variable
if (basemap !== undefined) {
myMap.basemap.setBasemap(basemap);
setActiveBasemapId(basemapId);
}
};

/**
* Add basemaps from configuration for selected projection
*
* @param {number} projection the projection to create basemaps for
* Add basemaps from configuration for selected projection.
* @param {number} projection - The projection to create basemaps for.
* @returns {Promise<void>}
*/
const createBasemapArray = async (projection: TypeValidMapProjectionCodes): Promise<void> => {
const basemapsArray = toJsonObject(
(config.supportedProjections as Array<TypeJsonObject>).find((obj: TypeJsonObject) => obj.projectionCode === projection)
);

let isInit = false;

// reset the basemaps array
// Reset the basemaps array
setBasemapList([]);

// create the custom config basemap
for (let basemapIndex = 0; basemapIndex < (basemapsArray.customBasemaps.length as number); basemapIndex++) {
const customBasemap = basemapsArray.customBasemaps[basemapIndex] as TypeJsonObject;
const basemap = api.maps[mapId].basemap.createCustomBasemap(customBasemap as unknown as TypeBasemapProps, projection);
if (basemap) setBasemapList((prevArray) => [...prevArray, basemap]);

// custom basemap are provided set it by default (can't be set as basemap from geoview config)
if (basemap && basemapIndex === 0 && activeBasemapId === '') {
setBasemap(basemap.basemapId!);
isInit = true;
}
}

// create the core basemap
// Create the core basemaps
const coreBasemaps: TypeBasemapProps[] = [];
for (let basemapIndex = 0; basemapIndex < (basemapsArray.coreBasemaps.length as number); basemapIndex++) {
const basemapOptions = basemapsArray.coreBasemaps[basemapIndex] as TypeJsonObject;
const basemapTypes = coreBasemaps.map((listedBasemap) => listedBasemap.type);
const basemapOptions = basemapsArray.coreBasemaps[basemapIndex] as TypeJsonObject as unknown as TypeBasemapOptions;
// TODO: Check - Should probably move the await outside of the loop so that all core basemaps start processing in parallel?
// TO.DOCONT: If doing so, be mindful of the isInit which seems to prioritize the first basemap in the list (and maybe why this await is in the loop?)
// eslint-disable-next-line no-await-in-loop
const basemap = await api.maps[mapId].basemap.createCoreBasemap(basemapOptions as unknown as TypeBasemapOptions, projection);

if (basemap) {
// get thumbnail and info (name and description) for core basemap
const basemap = await api.maps[mapId].basemap.createCoreBasemap(basemapOptions, projection);
if (basemap && !basemapTypes.includes(basemap.type)) {
// Get thumbnail and info (name and description) for core basemap
const { name, description } = getInfo(basemap.type.split('-'));
basemap.thumbnailUrl = getThumbnailUrl(basemap.type.split('-'), storeProjection, language);
basemap.name = name;
basemap.description = description;

setBasemapList((prevArray) => [...prevArray, basemap]);
coreBasemaps.push(basemap);
}
}

// set basemap if previously selected in previous projection
const id = `${basemapOptions.shaded ? 'shaded' : ''}${basemapOptions.id}${basemapOptions.labeled ? 'label' : ''}`;
if (basemap && id === activeBasemapId && !isInit) {
setBasemap(activeBasemapId);
isInit = true;
}
// Create the custom config basemap
const customBasemaps: TypeBasemapProps[] = [];
for (let basemapIndex = 0; basemapIndex < (basemapsArray.customBasemaps.length as number); basemapIndex++) {
const customBasemap = basemapsArray.customBasemaps[basemapIndex];
const basemap = api.maps[mapId].basemap.createCustomBasemap(customBasemap, projection);
const basemapTypes = customBasemaps.map((listedBasemap) => listedBasemap.type);
if (basemap && !basemapTypes.includes(basemap.type)) customBasemaps.push(basemap);
}

setBasemapList([...coreBasemaps, ...customBasemaps]);

// Set to previous basemap, if it is in new basemaps
const prevSetBaseMap = [...customBasemaps, ...coreBasemaps].filter((basemap) => basemap.basemapId === activeBasemapId);
if (prevSetBaseMap) {
setBasemap(activeBasemapId);
isInit = true;
}

// if previous basemap does not exist in previous projection, init first one
// If previous basemap does not exist in current projection, init first one
if (!isInit) setBasemap(basemapList[0] as unknown as string);
};

/**
* Set new projection view and basemap array
*
* @param {SelectChangeEvent} event select change element event
* Set new projection view and basemap array.
* @param {SelectChangeEvent} event - Select change element event.
*/
const setSelectedProjection = (event: SelectChangeEvent<unknown>): void => {
const projection = event.target.value as TypeValidMapProjectionCodes;

// set basemap to no geom to clean up the view
// Set basemap to no geom to clean up the view
setBasemap('nogeom');
setMapProjection(projection as TypeValidMapProjectionCodes);

createBasemapArray(projection)
.then(() => {
// emit an event to let know map view projection as changed
// Set projection through map viewer
myMap.setProjection(projection);
})
.catch((error) => {
Expand All @@ -233,7 +241,7 @@ export function BasemapPanel(props: BaseMapPanelProps): JSX.Element {
};

/**
* load existing basemaps and create new basemaps
* Load existing basemaps and create new basemaps
*/
useEffect(() => {
createBasemapArray(mapProjection).catch((error) => {
Expand Down
8 changes: 8 additions & 0 deletions packages/geoview-basemap-panel/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class BasemapPanelPlugin extends AppBarPlugin {
osm: {
name: 'Open Street Maps',
},
satellite: {
name: 'Satellite Image',
description: `World Imagery provides one meter or better satellite and aerial imagery in many parts of the world and lower resolution satellite imagery worldwide.`,
},
nogeom: {
name: 'No geometry',
},
Expand Down Expand Up @@ -82,6 +86,10 @@ class BasemapPanelPlugin extends AppBarPlugin {
osm: {
name: 'Carte - Open Street Maps',
},
satellite: {
name: 'Image satellite',
description: `World Imagery fournit des images aériennes et satellitaires d'un mètre ou plus dans de nombreuses régions du monde, ainsi que des images satellitaires à plus faible résolution dans le monde entier.`,
},
nogeom: {
name: 'Pas de géométrie',
},
Expand Down
4 changes: 2 additions & 2 deletions packages/geoview-core/public/templates/layers/geojson.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ <h4 id="HLYR1">1. Many GeoJSON Layers</h4>
'projection': 3978
},
'basemapOptions': {
'basemapId': 'transport',
'shaded': true,
'basemapId': 'satellite',
'shaded': false,
'labeled': false
},
'listOfGeoviewLayerConfig': [
Expand Down
2 changes: 1 addition & 1 deletion packages/geoview-core/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1374,7 +1374,7 @@
"required": ["basemapId", "shaded", "labeled"]
},
"TypeBasemapId": {
"enum": ["transport", "osm", "simple", "nogeom", "shaded"],
"enum": ["transport", "osm", "simple", "nogeom", "shaded", "satellite"],
"default": "transport",
"description": "Id of the basemap to use."
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ export const VALID_PROJECTION_CODES = [3978, 3857];
/**
* Definition of the basemap options type.
*/
export const CV_VALID_BASEMAP_ID: TypeBasemapId[] = ['transport', 'osm', 'simple', 'nogeom', 'shaded'];
export const CV_VALID_BASEMAP_ID: TypeBasemapId[] = ['transport', 'osm', 'simple', 'nogeom', 'shaded', 'satellite'];

/** default configuration if provided configuration is missing or wrong */
// valid basemap ids
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@
},
"TypeBasemapId": {
"description": "Id of the basemap to use.",
"enum": ["transport", "osm", "simple", "nogeom", "shaded"],
"enum": ["transport", "osm", "simple", "nogeom", "shaded", "satellite"],
"default": "transport"
},
"TypeInteraction": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export type TypeBasemapOptions = {
};

/** Definition of the basemap options type. */
export type TypeBasemapId = 'transport' | 'osm' | 'simple' | 'nogeom' | 'shaded';
export type TypeBasemapId = 'transport' | 'osm' | 'simple' | 'nogeom' | 'shaded' | 'satellite';

/** Definition of the valid map interactiom values. If map is dynamic (pan/zoom) or static to act as a thumbnail (no nav bar). */
export type TypeInteraction = 'static' | 'dynamic';
Expand Down
Loading

0 comments on commit 99f3682

Please sign in to comment.