From c2fb0b4e5c06f77f84ef04046f5a4923f4ce40a4 Mon Sep 17 00:00:00 2001 From: Willian Viana Date: Wed, 8 Jan 2025 18:05:36 -0300 Subject: [PATCH 1/5] feat(drivers): split drivers in different groups --- .../components/pie-chart-legend/component.jsx | 56 ++++++++++++++++++- .../forest-change/_tree-loss-drivers/index.js | 39 ++++++------- .../_tree-loss-drivers/selectors.js | 29 +++++++--- components/widgets/manifest.js | 2 +- 4 files changed, 98 insertions(+), 28 deletions(-) diff --git a/components/charts/components/pie-chart-legend/component.jsx b/components/charts/components/pie-chart-legend/component.jsx index 0810ee12b1..7c153ee016 100644 --- a/components/charts/components/pie-chart-legend/component.jsx +++ b/components/charts/components/pie-chart-legend/component.jsx @@ -3,10 +3,12 @@ import PropTypes from 'prop-types'; import { formatNumber } from 'utils/format'; import cx from 'classnames'; +import groupBy from 'lodash/groupBy'; + class PieChartLegend extends PureComponent { render() { const { data, chartSettings = {}, config, className, simple } = this.props; - const { size, legend } = chartSettings; + const { size, legend, groupedLegends } = chartSettings; const sizeClass = (() => { if (size) return size; @@ -24,6 +26,58 @@ class PieChartLegend extends PureComponent { })}`?.length > 9 ); + if (groupedLegends) { + const groupedItems = groupBy(data, 'category'); + + return ( +
+ {Object.entries(groupedItems).map(([category, categoryItems]) => ( +
+

{category}

+
    + {categoryItems.map((item, index) => { + const value = `${formatNumber({ + num: item[config.key], + unit: item.unit ? item.unit : config.unit, + spaceUnit: item.unit !== '%' && config.unit !== 'countsK', + })}`; + + return ( +
  • +
    + {} +

    + {item.label} + {sizeClass === 'x-small' && `- ${value}`} +

    +
    + {sizeClass !== 'x-small' && ( +
    + {value} +
    + )} +
  • + ); + })} +
+
+ ))} +
+ ); + } + return (
state.colors; const getSettings = (state) => state.settings; const getTitle = (state) => state.title; const getSentences = (state) => state.sentences; -const getCaution = (state) => state.caution; const getLocationLabel = (state) => state.locationLabel; -const getAdm0 = (state) => state.adm0; const getSortedCategories = () => tscLossCategories.sort((a, b) => (a.position > b.position ? 1 : -1)); +const groupedLegends = { + 'commodity driven deforestation': 'Drivers of temporary deforestation', + forestry: 'Drivers of temporary deforestation', + 'forest management': 'Drivers of temporary deforestation', + 'shifting cultivation': 'Drivers of temporary deforestation', + 'shifting agriculture': 'Drivers of temporary deforestation', + wildfire: 'Drivers of temporary deforestation', + 'other natural disasters': 'Drivers of temporary deforestation', + 'hard commodities': 'Drivers of permanent deforestation', + 'Drivers of permanent deforestation agriculture': + 'Drivers of permanent deforestation', + 'settlements and infrastructure': 'Drivers of permanent deforestation', + urbanization: 'Drivers of permanent deforestation', + unknown: 'Drivers of permanent deforestation', +}; + export const getPermanentCategories = createSelector( [getSortedCategories], (sortedCategories) => @@ -47,6 +61,7 @@ export const parseData = createSelector( return { label: driver_type, value: loss_area_ha, + category: groupedLegends[driver_type.toLowerCase()], color: categoryColors[driver_type], percentage: (loss_area_ha * 100) / totalLoss, }; @@ -112,14 +127,14 @@ export const parseSentence = createSelector( } ); -export const parseCaution = createSelector( - [getCaution, getAdm0], - (caution, adm0) => (adm0 === 'IDN' ? caution.indonesia : caution.default) -); +// export const parseCaution = createSelector( +// [getCaution, getAdm0], +// (caution, adm0) => (adm0 === 'IDN' ? caution.indonesia : caution.default) +// ); export default createStructuredSelector({ data: parseData, title: parseTitle, sentence: parseSentence, - caution: parseCaution, + // caution: parseCaution, }); diff --git a/components/widgets/manifest.js b/components/widgets/manifest.js index d9c8a2f725..c3e59b32b7 100644 --- a/components/widgets/manifest.js +++ b/components/widgets/manifest.js @@ -10,7 +10,7 @@ import treeCoverGainOutsidePlantations from 'components/widgets/forest-change/tr import treeGainLocated from 'components/widgets/forest-change/tree-gain-located'; import treeLossLocated from 'components/widgets/forest-change/tree-loss-located'; import treeLossPlantations from 'components/widgets/forest-change/tree-loss-plantations'; -import treeLossTsc from 'components/widgets/forest-change/tree-loss-drivers'; +import treeLossTsc from 'components/widgets/forest-change/_tree-loss-drivers'; import treeCoverGainSimple from 'components/widgets/forest-change/tree-cover-gain-simple'; import glads from 'components/widgets/forest-change/glads'; // import gladRanked from 'components/widgets/forest-change/glad-ranked'; From cddba9e2e35d14a863879914945c97faf7408636 Mon Sep 17 00:00:00 2001 From: Willian Viana Date: Wed, 8 Jan 2025 18:41:31 -0300 Subject: [PATCH 2/5] feat(drivers): add new class for grouped-legend blocks --- .../charts/components/pie-chart-legend/component.jsx | 8 ++++++-- components/charts/components/pie-chart-legend/styles.scss | 5 +++++ .../widgets/forest-change/_tree-loss-drivers/index.js | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/components/charts/components/pie-chart-legend/component.jsx b/components/charts/components/pie-chart-legend/component.jsx index 7c153ee016..e590dcca21 100644 --- a/components/charts/components/pie-chart-legend/component.jsx +++ b/components/charts/components/pie-chart-legend/component.jsx @@ -36,9 +36,13 @@ class PieChartLegend extends PureComponent { > {Object.entries(groupedItems).map(([category, categoryItems]) => (
-

{category}

+

{category}

    {categoryItems.map((item, index) => { diff --git a/components/charts/components/pie-chart-legend/styles.scss b/components/charts/components/pie-chart-legend/styles.scss index ffbc404ea7..e692e27886 100644 --- a/components/charts/components/pie-chart-legend/styles.scss +++ b/components/charts/components/pie-chart-legend/styles.scss @@ -4,6 +4,11 @@ display: inline-block; width: 100%; + .legend-group-title { + margin-bottom: 15px; + font-weight: 500; + } + .legend-title { font-size: rem(12px); line-height: 1; diff --git a/components/widgets/forest-change/_tree-loss-drivers/index.js b/components/widgets/forest-change/_tree-loss-drivers/index.js index 8907c2c0c8..768505dbb2 100644 --- a/components/widgets/forest-change/_tree-loss-drivers/index.js +++ b/components/widgets/forest-change/_tree-loss-drivers/index.js @@ -113,7 +113,6 @@ export default { display: 'flex', height: 'auto', alignItems: 'center', - paddingRight: '14%', }, }, }), @@ -122,6 +121,7 @@ export default { getData: (params) => getTreeCoverLossByDriverType(params).then((response) => { const { data } = (response && response.data) || {}; + return data; }), getDataURL: (params) => [ From 27ff9b228db10f0ddf6adffc6c700989f38a02d3 Mon Sep 17 00:00:00 2001 From: Willian Viana Date: Thu, 9 Jan 2025 14:34:01 -0300 Subject: [PATCH 3/5] feat(drivers): stylize drivers widget on the map/dashboard --- .../components/pie-chart-legend/component.jsx | 32 ++++++++------ .../components/pie-chart-legend/styles.scss | 43 ++++++++++++++----- .../widget-pie-chart-legend/component.jsx | 13 +++++- .../widget-pie-chart-legend/styles.scss | 4 ++ .../forest-change/_tree-loss-drivers/index.js | 9 +--- 5 files changed, 69 insertions(+), 32 deletions(-) diff --git a/components/charts/components/pie-chart-legend/component.jsx b/components/charts/components/pie-chart-legend/component.jsx index e590dcca21..39be8f4752 100644 --- a/components/charts/components/pie-chart-legend/component.jsx +++ b/components/charts/components/pie-chart-legend/component.jsx @@ -7,7 +7,14 @@ import groupBy from 'lodash/groupBy'; class PieChartLegend extends PureComponent { render() { - const { data, chartSettings = {}, config, className, simple } = this.props; + const { + data, + chartSettings = {}, + config, + className, + simple, + onMap, + } = this.props; const { size, legend, groupedLegends } = chartSettings; const sizeClass = (() => { @@ -31,20 +38,19 @@ class PieChartLegend extends PureComponent { return (
    {Object.entries(groupedItems).map(([category, categoryItems]) => ( -
    +

    {category}

    -
      +
        {categoryItems.map((item, index) => { const value = `${formatNumber({ num: item[config.key], @@ -127,12 +133,14 @@ class PieChartLegend extends PureComponent { } PieChartLegend.propTypes = { + onMap: PropTypes.bool, data: PropTypes.array, config: PropTypes.object, chartSettings: PropTypes.shape({ size: PropTypes.oneOf(['small', 'x-small']), legend: PropTypes.shape({ style: PropTypes.object }), chart: PropTypes.shape({ style: PropTypes.object }), + groupedLegends: PropTypes.bool, }), simple: PropTypes.bool, className: PropTypes.string, diff --git a/components/charts/components/pie-chart-legend/styles.scss b/components/charts/components/pie-chart-legend/styles.scss index e692e27886..5b458342e7 100644 --- a/components/charts/components/pie-chart-legend/styles.scss +++ b/components/charts/components/pie-chart-legend/styles.scss @@ -4,13 +4,30 @@ display: inline-block; width: 100%; - .legend-group-title { - margin-bottom: 15px; - font-weight: 500; + &-grouped { + flex-direction: column; + } + + .legend-group { + display: flex; + flex-direction: column; + + .legend-group-title { + margin-bottom: 0.9375rem; + font-weight: 500; + font-size: 0.875rem; + } + + .legend-group-list { + display: flex; + justify-content: space-between; + flex-wrap: wrap; + margin-bottom: 1.25rem; + } } .legend-title { - font-size: rem(12px); + font-size: 0.75rem; line-height: 1; color: $slate; position: relative; @@ -19,19 +36,19 @@ span { display: inline-block; - width: rem(12px); - min-width: rem(12px); - min-height: rem(12px); - height: rem(12px); - margin-right: rem(7px); + width: 0.75rem; + min-width: 0.75rem; + min-height: 0.75rem; + height: 0.75rem; + margin-right: 0.4375rem; border-radius: 100%; align-self: flex-start; - margin-top: 1px; + margin-top: 0.0625rem; } p { color: $slate; - font-size: rem(12px); + font-size: 0.75rem; line-height: 1.4; } } @@ -77,3 +94,7 @@ } } } + +.top-margin-20 { + margin-top: 1.25rem; +} diff --git a/components/widget/components/widget-pie-chart-legend/component.jsx b/components/widget/components/widget-pie-chart-legend/component.jsx index 2bd78ae222..8d076717d3 100644 --- a/components/widget/components/widget-pie-chart-legend/component.jsx +++ b/components/widget/components/widget-pie-chart-legend/component.jsx @@ -2,6 +2,8 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { formatNumber } from 'utils/format'; +import cx from 'classnames'; + import PieChart from 'components/charts/pie-chart'; import PieChartLegend from 'components/charts/components/pie-chart-legend'; import Button from 'components/ui/button'; @@ -21,6 +23,9 @@ class WidgetPieChart extends PureComponent { } = this.props; const { pathname } = location; const { chartHeight } = settings; + const { groupedLegends } = chartSettings; + + const onMap = pathname.indexOf('map') !== -1; const showSettingsBtn = settingsBtnConfig && @@ -47,7 +52,12 @@ class WidgetPieChart extends PureComponent { {settingsBtnConfig.text} )} -
        +
        diff --git a/components/widget/components/widget-pie-chart-legend/styles.scss b/components/widget/components/widget-pie-chart-legend/styles.scss index 66da13325c..b190a59ee1 100644 --- a/components/widget/components/widget-pie-chart-legend/styles.scss +++ b/components/widget/components/widget-pie-chart-legend/styles.scss @@ -6,6 +6,10 @@ flex-direction: row; justify-content: space-between; gap: 4%; + + &-grouped { + flex-direction: column-reverse; + } } .cover-legend { diff --git a/components/widgets/forest-change/_tree-loss-drivers/index.js b/components/widgets/forest-change/_tree-loss-drivers/index.js index 768505dbb2..9f105eca64 100644 --- a/components/widgets/forest-change/_tree-loss-drivers/index.js +++ b/components/widgets/forest-change/_tree-loss-drivers/index.js @@ -99,15 +99,7 @@ export default { return { ...((dashboard || embed) && { - groupedLegends: true, size: 'small', - legend: { - style: { - display: 'flex', - justifyContent: 'center', - paddingLeft: '8%', - }, - }, chart: { style: { display: 'flex', @@ -116,6 +108,7 @@ export default { }, }, }), + groupedLegends: true, }; }, getData: (params) => From 874379dff88b8cf437fbbb467957c4833a945e89 Mon Sep 17 00:00:00 2001 From: Willian Viana Date: Thu, 9 Jan 2025 14:35:35 -0300 Subject: [PATCH 4/5] chore(comment): remove commented code --- .../forest-change/_tree-loss-drivers/index.js | 19 ------------------- .../_tree-loss-drivers/selectors.js | 6 ------ 2 files changed, 25 deletions(-) diff --git a/components/widgets/forest-change/_tree-loss-drivers/index.js b/components/widgets/forest-change/_tree-loss-drivers/index.js index 9f105eca64..0a1e39943b 100644 --- a/components/widgets/forest-change/_tree-loss-drivers/index.js +++ b/components/widgets/forest-change/_tree-loss-drivers/index.js @@ -20,25 +20,6 @@ export default { }, types: ['global', 'country'], admins: ['global', 'adm0'], - // alerts: { - // default: [ - // { - // id: 'tree-loss-drivers-alert-1', - // text: `The methods behind this data have changed over time. Be cautious comparing old and new, data especially before/after 2015. [Read more here](https://www.globalforestwatch.org/blog/data-and-research/tree-cover-loss-satellite-data-trend-analysis/).`, - // icon: 'warning', - // visible: ['global', 'country', 'geostore', 'aoi', 'wdpa', 'use'], - // }, - // ], - // indonesia: [ - // { - // id: 'tree-loss-drivers-indonesia-alert-1', - // text: `Indonesia’s rates of deforestation have slowed significantly in recent years (2016-2021), largely due to reductions in commodity-driven expansion. Much of the primary forest loss from commodity-driven deforestation in Indonesia according to the GFW data actually took place in areas legally classified as secondary forests, not primary forests. Please note that ground verification is recommended before any hard conclusions are drawn about the type of forest affected, or cause of loss, in specific patches of loss on the GFW map.`, - // icon: 'warning', - // visible: ['global', 'country', 'geostore', 'aoi', 'wdpa', 'use'], - // areaWhitelist: ['IDN'], - // }, - // ], - // }, categories: ['summary', 'forest-change'], subcategories: ['forest-loss'], large: true, diff --git a/components/widgets/forest-change/_tree-loss-drivers/selectors.js b/components/widgets/forest-change/_tree-loss-drivers/selectors.js index 4815d7a7d5..204d53e7a3 100644 --- a/components/widgets/forest-change/_tree-loss-drivers/selectors.js +++ b/components/widgets/forest-change/_tree-loss-drivers/selectors.js @@ -127,14 +127,8 @@ export const parseSentence = createSelector( } ); -// export const parseCaution = createSelector( -// [getCaution, getAdm0], -// (caution, adm0) => (adm0 === 'IDN' ? caution.indonesia : caution.default) -// ); - export default createStructuredSelector({ data: parseData, title: parseTitle, sentence: parseSentence, - // caution: parseCaution, }); From d9b26f1da12c97a914aee7f019a088cc83698d53 Mon Sep 17 00:00:00 2001 From: Willian Viana Date: Tue, 14 Jan 2025 14:24:46 -0300 Subject: [PATCH 5/5] chore(widget): turn off the new tcl drivers widget --- components/widgets/manifest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widgets/manifest.js b/components/widgets/manifest.js index c3e59b32b7..d9c8a2f725 100644 --- a/components/widgets/manifest.js +++ b/components/widgets/manifest.js @@ -10,7 +10,7 @@ import treeCoverGainOutsidePlantations from 'components/widgets/forest-change/tr import treeGainLocated from 'components/widgets/forest-change/tree-gain-located'; import treeLossLocated from 'components/widgets/forest-change/tree-loss-located'; import treeLossPlantations from 'components/widgets/forest-change/tree-loss-plantations'; -import treeLossTsc from 'components/widgets/forest-change/_tree-loss-drivers'; +import treeLossTsc from 'components/widgets/forest-change/tree-loss-drivers'; import treeCoverGainSimple from 'components/widgets/forest-change/tree-cover-gain-simple'; import glads from 'components/widgets/forest-change/glads'; // import gladRanked from 'components/widgets/forest-change/glad-ranked';