Skip to content

Commit

Permalink
Merge pull request #1357 from wri/MAPB-157
Browse files Browse the repository at this point in the history
feat: implement ticket MAPB-157
  • Loading branch information
anthonyamaro15 authored Aug 8, 2023
2 parents 1c307d2 + 3d52612 commit 4df9b99
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 21 deletions.
86 changes: 76 additions & 10 deletions configs/translations/leftPanel.translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,34 +591,100 @@ export const dataTabConfig = {
};
export const treesMosaicConfig = {
en: {
displayLabel: ['Displaying Trees in Mosaic Landscapes with', 'tree cover.'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
az: {
displayLabel: ['Göstərir', 'örtük sıxlığı.'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
nl: {
displayLabel: ['Weergeven', 'luifeldichtheid.'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
hy: {
displayLabel: ['Ցուցադրվում է ', 'Սաղարթի խտություն '],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
ka: {
displayLabel: ['წარმოდგენილია', 'ვარჯის სიმჭიდროვე.'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
fr: {
displayLabel: ['Affichage', 'Densité de la canopée.'],
displayLabel: ['', `Affichage de >40% de probabilité d'étendue des arbres à une résolution de 10 mètres`],
},
es: {
displayLabel: ['Mostrando', 'densidad de follaje.'],
displayLabel: ['', 'Mostrando >40% de probabilidad de extensión arbórea a resolución de 10 metros'],
},
pt: {
displayLabel: ['Exibindo', 'densidade de dossel'],
displayLabel: ['', 'Exibindo uma probabilidade de >40% de extensão de árvores a uma resolução de 10 metros'],
},
id: {
displayLabel: ['Displaying Trees in Mosaic Landscapes with', 'tree cover.'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
zh: {
displayLabel: ['显示中', '林冠覆盖密度'],
displayLabel: ['', 'Displaying >40% tree extent probability at 10 meter resolution'],
},
};

export const treesMosaicHectareConfig = {
en: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
az: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
nl: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
hy: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
ka: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
fr: {
displayLabel: ['Affichage du couvert arboré à une résolution de 0,5 hectare et à', 'couvert arboré'],
},
es: {
displayLabel: ['Visualización de la cubierta arbórea con una resolución de 0,5 hectáreas y en', 'cubierta arbórea'],
},
pt: {
displayLabel: ['Exibindo a cobertura de árvores em resolução de 0,5 hectare e em', 'cobertura de árvores'],
},
id: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
zh: {
displayLabel: ['Displaying tree cover at 0.5 hectare resolution and at', 'tree cover'],
},
};

export const tropicalTreeHectareBtnCongif = {
en: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
az: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
nl: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
hy: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
ka: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
fr: {
displayLabel: ['0.5 hectare', '10×10 mètres'],
},
es: {
displayLabel: ['0.5 hectáreas', '10x10 metros'],
},
pt: {
displayLabel: ['0.5 hectare', '10x10 metros'],
},
id: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
zh: {
displayLabel: ['0.5 hectare', '10x10 meter'],
},
};

Expand Down
87 changes: 79 additions & 8 deletions src/js/components/sharedComponents/CanopyDensityPicker.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { RootState } from '../../store';
import { renderModal } from '../../store/appState/actions';
import { renderModal, setActiveTreeMosaicLayer, setTreeMosaicHectaresValue } from '../../store/appState/actions';
import { markValueMap } from '../mapWidgets/widgetContent/CanopyDensityContent';
import { treeMosaicDensityValue } from '../mapWidgets/widgetContent/TreeMosaicContent';
import {
Expand All @@ -10,20 +10,30 @@ import {
forestCarbonGrossRemovalConfig,
forestCarbonNetFluxConfig,
treesMosaicConfig,
treesMosaicHectareConfig,
tropicalTreeHectareBtnCongif,
} from '../../../../configs/translations/leftPanel.translations';
import { forestCarbonRemovalValue } from '../mapWidgets/widgetContent/ForestGrossRemovalContent';
import { forestCarbonGrossEmisionValue } from '../mapWidgets/widgetContent/ForestCarbonGrossEmissionContent';
import { forestCarbonNetFluxValue } from '../mapWidgets/widgetContent/ForesCarbonNetFlux';
import { handleCustomColorTheme } from '../../../utils';
import { mapController } from '../../controllers/mapController';
import { LayerFactory } from '../../helpers/LayerFactory';
import './canopyDensityPicker.scss';

interface CanopyDensityProps {
type?: string;
}
const CanopyDensityPicker = (props: CanopyDensityProps): JSX.Element => {
const allAvailableLayers = useSelector((store: RootState) => store.mapviewState.allAvailableLayers);

const dispatch = useDispatch();
const [selected, setSelected] = React.useState<'hectare' | 'meter'>('meter');

const customColorTheme = useSelector((store: RootState) => store.appSettings.customColorTheme);
const density = useSelector((store: RootState) => store.appState.leftPanel.density);
const hectareValue = useSelector((store: RootState) => store.appState.leftPanel.treeMosaicHectaresValue);

const selectedLanguage = useSelector((store: RootState) => store.appState.selectedLanguage);
let config = canopyDensityPickerConfig[selectedLanguage];
let densityValueMap = markValueMap[density];
Expand Down Expand Up @@ -59,15 +69,76 @@ const CanopyDensityPicker = (props: CanopyDensityProps): JSX.Element => {
}
}

const handleClick = async (type: 'meter' | 'hectare') => {
const layerConfig = allAvailableLayers.find((layer: any) => layer.id === 'TREES_MOSAIC_LANDSCAPES') as any;

if (type === selected) return;
setSelected(type);
dispatch(setActiveTreeMosaicLayer(type));

const mapview = mapController.getMapView();
mapController.removeMapLayer('TREES_MOSAIC_LANDSCAPES');
const updatedUMDLayer = await LayerFactory(mapview, layerConfig);
mapController._map?.add(updatedUMDLayer);
};

const handleSelect = async (event: any) => {
const layerConfig = allAvailableLayers.find((layer: any) => layer.id === 'TREES_MOSAIC_LANDSCAPES') as any;

const value = Number(event.target.value);
dispatch(setTreeMosaicHectaresValue(value));
const mapview = mapController.getMapView();
mapController.removeMapLayer('TREES_MOSAIC_LANDSCAPES');
const updatedUMDLayer = await LayerFactory(mapview, layerConfig);
mapController._map?.add(updatedUMDLayer);
};

return (
<div className="canopy-density-picker-wrapper">
<span>{displayLabel[0]} </span>
<button
className="canopy-density-picker"
style={{ backgroundColor: `${themeColor}` }}
onClick={handleDensityButtonClick}
>{`> ${densityValueMap}%`}</button>
<span> {displayLabel[1]}</span>
{props.type !== 'TREES_MOSAIC_LANDSCAPES' && <span> {displayLabel[0]}</span>}

{props.type === 'TREES_MOSAIC_LANDSCAPES' && (
<div className="tropical-tree-cover-toggle-wrapper">
<div className="toggle-btn">
<button onClick={() => handleClick('hectare')} className={selected === 'hectare' ? 'active' : ''}>
{tropicalTreeHectareBtnCongif[selectedLanguage]?.displayLabel[0]}
</button>
<button onClick={() => handleClick('meter')} className={selected === 'meter' ? 'active' : ''}>
{tropicalTreeHectareBtnCongif[selectedLanguage]?.displayLabel[1]}
</button>
</div>
{selected === 'hectare' && (
<>
<span>{treesMosaicHectareConfig[selectedLanguage]?.displayLabel[0]}</span>

<select onChange={handleSelect} value={hectareValue}>
<option value={10}>10</option>
<option value={20}>20</option>
<option value={30}>30</option>
<option value={40}>40</option>
<option value={50}>50</option>
<option value={60}>60</option>
<option value={70}>70</option>
<option value={80}>80</option>
<option value={90}>90</option>
</select>
<span className="tree-cover-text">{treesMosaicHectareConfig[selectedLanguage]?.displayLabel[1]}</span>
</>
)}
{selected === 'meter' && <span> {displayLabel[1]}</span>}
</div>
)}

{props.type !== 'TREES_MOSAIC_LANDSCAPES' && (
<>
<button
className="canopy-density-picker"
style={{ backgroundColor: `${themeColor}` }}
onClick={handleDensityButtonClick}
>{`> ${densityValueMap}%`}</button>
<span> {displayLabel[1]}</span>
</>
)}
</div>
);
};
Expand Down
39 changes: 39 additions & 0 deletions src/js/components/sharedComponents/canopyDensityPicker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.tropical-tree-cover-toggle-wrapper {
.toggle-btn {
border: 1px solid #f0ab00;
margin: 0.7rem auto;
width: 70%;
border-radius: 30px;
padding: 0;
display: flex;
align-items: center;

button {
font-size: 12px;
border: 1px solid transparent;
width: 50%;
border-radius: 30px;
background: transparent;
height: 100%;
color: black;

&.active {
background: #f0ab00;
border: 1px solid #f0ab00;
color: white;
}
}
}

select {
border: 1px solid #f0ab00;
border-radius: 30px;
font-size: 12px;
display: inline-block;
margin-left: 0.3rem;
}
.tree-cover-text {
display: inline-block;
margin-left: 0.5rem;
}
}
1 change: 1 addition & 0 deletions src/js/controllers/mapController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1723,6 +1723,7 @@ export class MapController {
const { mapviewState } = store.getState();
const treeCoverLayerInfo: any = mapviewState.allAvailableLayers.find((l) => l.id === 'TREE_COVER');
const treeLayer: any = this._map?.findLayerById('TREE_COVER');

if (treeLayer && treeCoverLayerInfo) {
const oldLayer = treeLayer;
oldLayer.urlTemplate = treeCoverLayerInfo.url.replace('30', value);
Expand Down
7 changes: 5 additions & 2 deletions src/js/helpers/LayerFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { forestCarbonNetFluxValue } from '../components/mapWidgets/widgetContent
import { createForestCarbonNetFlux } from '../layers/ForestCarbonNetFlux';
import { umdCoverLand } from '../layers/UmdCoverLand';
import { createBaseTileLayer } from '../layers/BaseTileLayer';
import { getUrl } from './layerFactoryHelpers';

interface LayerOptions {
id: string;
Expand Down Expand Up @@ -137,8 +138,10 @@ export async function LayerFactory(mapView: any, layerConfig: LayerProps): Promi
esriLayer.refresh();
break;
case 'tree-mosaic':
const treeDensityValue = treeMosaicDensityValue[appState.leftPanel.density];
layerConfig.url = layerConfig.url.replace(/(tcd_)(?:[^/]+)/, `tcd_${treeDensityValue}`);
const activeLayerType = appState.leftPanel.activeTreeMosaicLayer;
const hectareValue = appState.leftPanel.treeMosaicHectaresValue;
layerConfig.url = getUrl({ type: activeLayerType, hectareValue });

const constructor = await createTreeMosaicCover();
const treeMosaicLayer = new constructor({
id: layerConfig.id,
Expand Down
14 changes: 14 additions & 0 deletions src/js/helpers/layerFactoryHelpers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { TreeMosaicLayerTypes } from 'src/js/store/appState/types';

export interface GetUrlParams {
type: TreeMosaicLayerTypes;
hectareValue: number;
}

export const getUrl = ({ type, hectareValue }: GetUrlParams) => {
if (type === 'hectare') {
return `https://tiles.globalforestwatch.org/wri_tropical_tree_cover/v2020/ttcd_${hectareValue}/{z}/{x}/{y}.png`;
} else {
return 'https://tiles.globalforestwatch.org/wri_trees_in_mosaic_landscapes/v20220922/tcd_40/{z}/{x}/{y}.png';
}
};
17 changes: 17 additions & 0 deletions src/js/store/appState/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ import {
SET_GLAD_2_END,
SET_RADD_ALERT_START,
SET_RADD_ALERT_END,
SET_TREE_MOSAIC_HECTARES_VALUE,
TreeMosaicLayerTypes,
SET_ACTIVE_TREE_MOSAIC_LAYER,
} from './types';

export function setSelectedSearchWidgetLayer(payload: AppState['selectedSearchWidgetLayer']) {
Expand Down Expand Up @@ -353,3 +356,17 @@ export function setLandCoverYearValue(payload: number[]) {
payload,
};
}

export function setTreeMosaicHectaresValue(payload: number) {
return {
type: SET_TREE_MOSAIC_HECTARES_VALUE,
payload,
};
}

export function setActiveTreeMosaicLayer(payload: TreeMosaicLayerTypes) {
return {
type: SET_ACTIVE_TREE_MOSAIC_LAYER,
payload,
};
}
21 changes: 21 additions & 0 deletions src/js/store/appState/reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ import {
SET_VIIRS_END,
SET_VIIRS_START,
SET_WIND_SPEED_POTENTIAL,
SET_TREE_MOSAIC_HECTARES_VALUE,
TOGGLE_TABVIEW_PANEL,
SET_LAND_COVER_YEAR_VALUE,
SET_RADD_ALERT_START,
SET_RADD_ALERT_END,
SET_ACTIVE_TREE_MOSAIC_LAYER,
} from './types';

const initialState: AppState = {
Expand Down Expand Up @@ -89,6 +91,9 @@ const initialState: AppState = {
gfwLayerLabel: 'Integrated Deforestation Alerts',
gfwLayerSubtitle: '(daily, 10m, tropics, UMD/GLAD and WUR)',
windSpeedPotential: 50,

treeMosaicHectaresValue: 10,
activeTreeMosaicLayer: 'meter',
},
measureContent: {
activeButton: '',
Expand Down Expand Up @@ -361,6 +366,22 @@ export function appStateReducer(state = initialState, action: AppStateTypes): Ap
windSpeedPotential: action.payload,
},
};
case SET_TREE_MOSAIC_HECTARES_VALUE:
return {
...state,
leftPanel: {
...state.leftPanel,
treeMosaicHectaresValue: action.payload,
},
};
case SET_ACTIVE_TREE_MOSAIC_LAYER:
return {
...state,
leftPanel: {
...state.leftPanel,
activeTreeMosaicLayer: action.payload,
},
};
case SET_VERSIONED_LAYER: {
const versionedState = state.leftPanel.versionedLayer;
versionedState[Object.keys(action.payload)[0]] = Object.values(action.payload)[0] as string;
Expand Down
Loading

0 comments on commit 4df9b99

Please sign in to comment.