From 242d341c52b95d1b814aac82d44cbe2af0a98014 Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 10:30:49 +0100 Subject: [PATCH 01/10] Add new WidgetChartLegend component, and add support for it in the WidgetComposedChart component --- .../charts/composed-chart/component.jsx | 2 +- .../widget-chart-legend/component.jsx | 75 +++++++++++++++++++ .../components/widget-chart-legend/index.js | 3 + .../widget-chart-legend/styles.scss | 61 +++++++++++++++ .../widget-composed-chart/component.jsx | 7 +- pages/_app.js | 1 + 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 components/widget/components/widget-chart-legend/component.jsx create mode 100644 components/widget/components/widget-chart-legend/index.js create mode 100644 components/widget/components/widget-chart-legend/styles.scss diff --git a/components/charts/composed-chart/component.jsx b/components/charts/composed-chart/component.jsx index c95d23bfae..24d96b5989 100644 --- a/components/charts/composed-chart/component.jsx +++ b/components/charts/composed-chart/component.jsx @@ -46,7 +46,7 @@ const XAxisTickWithoutGap = ({ x, y, payload }) => { ); - /* + /* Work around to show number 100 in the end of X axis in the chart since the Data API sends 0 to 90 percent in the tree cover density widget 0 stands to 0%-9% as 90 stands to 90%-99% diff --git a/components/widget/components/widget-chart-legend/component.jsx b/components/widget/components/widget-chart-legend/component.jsx new file mode 100644 index 0000000000..705e8e9dda --- /dev/null +++ b/components/widget/components/widget-chart-legend/component.jsx @@ -0,0 +1,75 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; + +import cx from 'classnames'; + +class WidgetChartLegend extends PureComponent { + render() { + const { className, data = {} } = this.props; + const { columns = [] } = data; + + const anyColumnsHaveTitle = !!columns.find((column) => column.title); + + return ( +
+ {columns.map(({ title, items }, columnIdx) => { + return ( +
+ + {title} + +
    + {items.map(({ label, color, dashline }, titleIdx) => { + return ( +
  • + {dashline ? ( + + ) : ( + + )} +

    {label}

    +
  • + ); + })} +
+
+ ); + })} +
+ ); + } +} + +WidgetChartLegend.propTypes = { + className: PropTypes.string, + data: { + columns: { + title: PropTypes.string, + items: PropTypes.arrayOf( + PropTypes.shape({ + color: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + }) + ), + }, + }, +}; + +export default WidgetChartLegend; diff --git a/components/widget/components/widget-chart-legend/index.js b/components/widget/components/widget-chart-legend/index.js new file mode 100644 index 0000000000..f1d269317e --- /dev/null +++ b/components/widget/components/widget-chart-legend/index.js @@ -0,0 +1,3 @@ +import Component from './component'; + +export default Component; diff --git a/components/widget/components/widget-chart-legend/styles.scss b/components/widget/components/widget-chart-legend/styles.scss new file mode 100644 index 0000000000..80137c2d3e --- /dev/null +++ b/components/widget/components/widget-chart-legend/styles.scss @@ -0,0 +1,61 @@ +@import '~styles/settings.scss'; + +.c-widget-chart-legend { + display: flex; + margin: 20px 0 0; + width: 100%; + gap: 40px; + + &__column { + &-title { + font-weight: 500; + font-size: rem(12px); + margin-top: -rem(8px); + } + + &-items { + display: flex; + flex-direction: column; + gap: 5px; + + &.padded { + padding-top: rem(26px); + } + } + + &-item { + font-size: rem(12px); + display: flex; + + &--circle, + &--dashline { + display: inline-block; + width: rem(12px); + min-width: rem(12px); + min-height: rem(12px); + height: rem(12px); + margin-right: rem(7px); + } + + &--circle { + border-radius: 100%; + align-self: flex-start; + margin-top: 1px; + } + + &--dashline { + border-radius: 0; + border: none; + border-top: 2px dotted; + align-self: center; + transform: translateY(4px); + } + + p { + color: $slate; + font-size: rem(12px); + line-height: 1.4; + } + } + } +} diff --git a/components/widget/components/widget-composed-chart/component.jsx b/components/widget/components/widget-composed-chart/component.jsx index f4cc1106f9..6236086994 100644 --- a/components/widget/components/widget-composed-chart/component.jsx +++ b/components/widget/components/widget-composed-chart/component.jsx @@ -5,6 +5,7 @@ import debounce from 'lodash/debounce'; import ComposedChart from 'components/charts/composed-chart'; import Brush from 'components/charts/brush-chart'; import Legend from 'components/charts/components/chart-legend'; +import ChartLegend from '../widget-chart-legend'; class WidgetComposedChart extends Component { static propTypes = { @@ -72,7 +73,7 @@ class WidgetComposedChart extends Component { barBackground, toggleSettingsMenu, } = this.props; - const { brush, legend } = config; + const { brush, legend, chartLegend } = config; const showLegendSettingsBtn = settingsConfig && settingsConfig.some((conf) => conf.key === 'compareYear'); @@ -107,6 +108,10 @@ class WidgetComposedChart extends Component { onBrushEnd={this.handleBrushEnd} /> )} + + { chartLegend && ( + + )} ); } diff --git a/pages/_app.js b/pages/_app.js index 603aba4db8..5354de7a79 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -276,6 +276,7 @@ import '../components/widget/styles.scss'; import '../components/widgets/styles.scss'; import '../components/widget/components/widget-alert/styles.scss'; import '../components/widget/components/widget-body/styles.scss'; +import '../components/widget/components/widget-chart-legend/styles.scss'; import '../components/widget/components/widget-chart-and-list/styles.scss'; import '../components/widget/components/widget-chart-list/styles.scss'; import '../components/widget/components/widget-footer/styles.scss'; From 4c394995ba0a1268cdaade6c3e84e213f5cce851 Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 13:25:43 +0100 Subject: [PATCH 02/10] Add WidgetChartLegend to the treeLossPct wiodget --- .../tree-loss-primary/selectors.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/components/widgets/forest-change/tree-loss-primary/selectors.js b/components/widgets/forest-change/tree-loss-primary/selectors.js index 47f86bd964..d2098464e8 100644 --- a/components/widgets/forest-change/tree-loss-primary/selectors.js +++ b/components/widgets/forest-change/tree-loss-primary/selectors.js @@ -151,6 +151,23 @@ const parseConfig = createSelector([getColors], (colors) => ({ color: colors.primaryForestLoss, }, ], + chartLegend: { + columns: [ + { + items: [ + { + label: 'Area of tree cover loss within 2001 primary forest extent', + color: colors.primaryForestLoss, + }, + { + label: 'Total remaining area of primary forest', + color: colors.primaryForestExtent, + dashline: true, + }, + ], + }, + ], + }, })); export const parseTitle = createSelector( From 45793952691dd1e12541cc3269e1b3a6027a055c Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 13:35:21 +0100 Subject: [PATCH 03/10] Add WidgetChartLegend to the emissionsDeforestationDrivers widget --- .../selectors.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/components/widgets/climate/emissions-deforestation-drivers/selectors.js b/components/widgets/climate/emissions-deforestation-drivers/selectors.js index c6269a223a..1986fe80f2 100644 --- a/components/widgets/climate/emissions-deforestation-drivers/selectors.js +++ b/components/widgets/climate/emissions-deforestation-drivers/selectors.js @@ -161,6 +161,23 @@ export const parseConfig = createSelector( }) .reverse() ); + + const chartLegend = { + columns: [ + { + items: ['Wildfire', 'Forestry', 'Shifting agriculture']?.map( + (name) => ({ label: name, color: categoryColors[name] }) + ), + }, + { + title: 'Drivers of permanent deforestation', + items: ['Commodity driven deforestation', 'Urbanization']?.map( + (name) => ({ label: name, color: categoryColors[name] }) + ), + }, + ], + }; + const insertIndex = findIndex(tooltip, { key: 'class_Urbanization' }); if (insertIndex > -1) { tooltip.splice(insertIndex, 0, { @@ -181,6 +198,7 @@ export const parseConfig = createSelector( formatNumber({ num: value, specialSpecifier: '.2s', spaceUnit: true }), unit: 'tCO2e', tooltip, + chartLegend, }; } ); From 670b8c5c299e52b2f529e4c57a9cdeb519d03e37 Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 13:54:34 +0100 Subject: [PATCH 04/10] Minor styling tweaks for the WidgetChartLegend --- .../widget/components/widget-chart-legend/styles.scss | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/widget/components/widget-chart-legend/styles.scss b/components/widget/components/widget-chart-legend/styles.scss index 80137c2d3e..91ed0b1b83 100644 --- a/components/widget/components/widget-chart-legend/styles.scss +++ b/components/widget/components/widget-chart-legend/styles.scss @@ -4,13 +4,14 @@ display: flex; margin: 20px 0 0; width: 100%; - gap: 40px; + gap: 60px; &__column { &-title { + display: block; font-weight: 500; - font-size: rem(12px); - margin-top: -rem(8px); + font-size: rem(13px); + margin: 0 0 rem(10px) 0; } &-items { @@ -19,7 +20,7 @@ gap: 5px; &.padded { - padding-top: rem(26px); + padding-top: rem(20px); } } From 49f3d3fcdcc1999b7f7260004fc7397daa4d4e0d Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 14:01:07 +0100 Subject: [PATCH 05/10] WidgetChartLegend to support vertical mode (analysis) --- .../widget-chart-legend/component.jsx | 15 +++++++++------ .../widget-chart-legend/styles.scss | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/components/widget/components/widget-chart-legend/component.jsx b/components/widget/components/widget-chart-legend/component.jsx index 705e8e9dda..707670fff6 100644 --- a/components/widget/components/widget-chart-legend/component.jsx +++ b/components/widget/components/widget-chart-legend/component.jsx @@ -5,21 +5,23 @@ import cx from 'classnames'; class WidgetChartLegend extends PureComponent { render() { - const { className, data = {} } = this.props; + const { className, vertical = false, data = {} } = this.props; const { columns = [] } = data; const anyColumnsHaveTitle = !!columns.find((column) => column.title); return ( -
+
{columns.map(({ title, items }, columnIdx) => { return (
- - {title} - + {title && ( + + {title} + + )}
    @@ -59,6 +61,7 @@ class WidgetChartLegend extends PureComponent { WidgetChartLegend.propTypes = { className: PropTypes.string, + vertical: PropTypes.bool, data: { columns: { title: PropTypes.string, diff --git a/components/widget/components/widget-chart-legend/styles.scss b/components/widget/components/widget-chart-legend/styles.scss index 91ed0b1b83..7aca9c78bc 100644 --- a/components/widget/components/widget-chart-legend/styles.scss +++ b/components/widget/components/widget-chart-legend/styles.scss @@ -59,4 +59,23 @@ } } } + + &.vertical { + flex-direction: column; + gap: 5px; + + .c-widget-chart-legend { + &__column { + &-title { + margin-top: rem(8px); + } + + &-items { + &.padded { + padding-top: 0; + } + } + } + } + } } From bf232bb94de313d56ac4ba1f2e55e5e69199657c Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 14:19:23 +0100 Subject: [PATCH 06/10] Pass analysis prop all the way to WidgetChartLegend --- components/widget/component.jsx | 3 +++ .../widget/components/widget-composed-chart/component.jsx | 6 +++--- components/widgets/component.jsx | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/components/widget/component.jsx b/components/widget/component.jsx index 25e5324ad8..7cb4cf2fe4 100644 --- a/components/widget/component.jsx +++ b/components/widget/component.jsx @@ -13,6 +13,7 @@ class Widget extends PureComponent { title: PropTypes.string.isRequired, type: PropTypes.string, active: PropTypes.bool, + analysis: PropTypes.bool, downloadDisabled: PropTypes.bool, filterSelected: PropTypes.bool, maxSize: PropTypes.number, @@ -85,6 +86,7 @@ class Widget extends PureComponent { colors, type, active, + analysis, downloadDisabled, filterSelected, maxSize, @@ -218,6 +220,7 @@ class Widget extends PureComponent { large={large} autoHeight={autoHeight} embed={embed} + analysis={analysis} location={location} locationName={locationLabelFull} active={active} diff --git a/components/widget/components/widget-composed-chart/component.jsx b/components/widget/components/widget-composed-chart/component.jsx index 6236086994..19f7ee1f68 100644 --- a/components/widget/components/widget-composed-chart/component.jsx +++ b/components/widget/components/widget-composed-chart/component.jsx @@ -9,6 +9,7 @@ import ChartLegend from '../widget-chart-legend'; class WidgetComposedChart extends Component { static propTypes = { + analysis: PropTypes.bool, originalData: PropTypes.array, data: PropTypes.array, config: PropTypes.object, @@ -64,6 +65,7 @@ class WidgetComposedChart extends Component { render() { const { + analysis, originalData, data, config, @@ -109,9 +111,7 @@ class WidgetComposedChart extends Component { /> )} - { chartLegend && ( - - )} + {chartLegend && }
); } diff --git a/components/widgets/component.jsx b/components/widgets/component.jsx index 0113cdc2bf..16230e657c 100644 --- a/components/widgets/component.jsx +++ b/components/widgets/component.jsx @@ -31,6 +31,7 @@ class Widgets extends PureComponent { setMapSettings: PropTypes.func.isRequired, handleClickWidget: PropTypes.func.isRequired, embed: PropTypes.bool, + analysis: PropTypes.bool, dashboard: PropTypes.bool, groupBySubcategory: PropTypes.bool, modalClosing: PropTypes.bool, @@ -60,6 +61,7 @@ class Widgets extends PureComponent { groupBySubcategory = false, embed, dashboard, + analysis, simple, modalClosing, noDataMessage, @@ -112,6 +114,7 @@ class Widgets extends PureComponent { authenticated={authenticated} active={activeWidget && activeWidget.widget === w.widget} embed={embed} + analysis={analysis} dashboard={dashboard} simple={simple} location={location} From 0264ac11c1ecf5528211be436d0177a3ff519c9c Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 26 Sep 2024 14:22:18 +0100 Subject: [PATCH 07/10] Minor styling tweaks for the WidgetChartLegend --- components/widget/components/widget-chart-legend/styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widget/components/widget-chart-legend/styles.scss b/components/widget/components/widget-chart-legend/styles.scss index 7aca9c78bc..85607a35db 100644 --- a/components/widget/components/widget-chart-legend/styles.scss +++ b/components/widget/components/widget-chart-legend/styles.scss @@ -20,7 +20,7 @@ gap: 5px; &.padded { - padding-top: rem(20px); + padding-top: rem(30px); } } From 08dc89077a9f78dac08494f2a55589a7dc46ce5f Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 17 Oct 2024 12:29:08 +0100 Subject: [PATCH 08/10] Adjust paddings on the WidgetChartLegend component --- components/widget/components/widget-chart-legend/styles.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/widget/components/widget-chart-legend/styles.scss b/components/widget/components/widget-chart-legend/styles.scss index 85607a35db..20556f2722 100644 --- a/components/widget/components/widget-chart-legend/styles.scss +++ b/components/widget/components/widget-chart-legend/styles.scss @@ -11,7 +11,7 @@ display: block; font-weight: 500; font-size: rem(13px); - margin: 0 0 rem(10px) 0; + margin: 0 0 rem(8px) 0; } &-items { @@ -20,7 +20,7 @@ gap: 5px; &.padded { - padding-top: rem(30px); + padding-top: rem(2px); } } From 4d610af6c89dee26d72c2a1361a76ec11e5b2bb9 Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Thu, 24 Oct 2024 11:45:57 +0100 Subject: [PATCH 09/10] Update treeLossPct legend annotations' text --- components/widgets/forest-change/tree-loss-primary/selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/widgets/forest-change/tree-loss-primary/selectors.js b/components/widgets/forest-change/tree-loss-primary/selectors.js index d2098464e8..60effc90ae 100644 --- a/components/widgets/forest-change/tree-loss-primary/selectors.js +++ b/components/widgets/forest-change/tree-loss-primary/selectors.js @@ -160,7 +160,7 @@ const parseConfig = createSelector([getColors], (colors) => ({ color: colors.primaryForestLoss, }, { - label: 'Total remaining area of primary forest', + label: 'Percent of primary forest area in 2001 remaining', color: colors.primaryForestExtent, dashline: true, }, From 55ba6afde9337e7b2f1cb7d25de77a83c0eb44ff Mon Sep 17 00:00:00 2001 From: Simao Rodrigues Date: Mon, 28 Oct 2024 12:23:44 +0000 Subject: [PATCH 10/10] Remove chart legend from the emissionsDeforestationDrivers widget Code used only for visual example of the support of columns & titles --- .../selectors.js | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/components/widgets/climate/emissions-deforestation-drivers/selectors.js b/components/widgets/climate/emissions-deforestation-drivers/selectors.js index 1986fe80f2..8253efb859 100644 --- a/components/widgets/climate/emissions-deforestation-drivers/selectors.js +++ b/components/widgets/climate/emissions-deforestation-drivers/selectors.js @@ -162,21 +162,23 @@ export const parseConfig = createSelector( .reverse() ); - const chartLegend = { - columns: [ - { - items: ['Wildfire', 'Forestry', 'Shifting agriculture']?.map( - (name) => ({ label: name, color: categoryColors[name] }) - ), - }, - { - title: 'Drivers of permanent deforestation', - items: ['Commodity driven deforestation', 'Urbanization']?.map( - (name) => ({ label: name, color: categoryColors[name] }) - ), - }, - ], - }; + // Example on how to add columns & titles to the Chart Legend + // See: https://gfw.atlassian.net/browse/FLAG-1145 + // const chartLegend = { + // columns: [ + // { + // items: ['Wildfire', 'Forestry', 'Shifting agriculture']?.map( + // (name) => ({ label: name, color: categoryColors[name] }) + // ), + // }, + // { + // title: 'Drivers of permanent deforestation', + // items: ['Commodity driven deforestation', 'Urbanization']?.map( + // (name) => ({ label: name, color: categoryColors[name] }) + // ), + // }, + // ], + // }; const insertIndex = findIndex(tooltip, { key: 'class_Urbanization' }); if (insertIndex > -1) { @@ -198,7 +200,7 @@ export const parseConfig = createSelector( formatNumber({ num: value, specialSpecifier: '.2s', spaceUnit: true }), unit: 'tCO2e', tooltip, - chartLegend, + // chartLegend, }; } );