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/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-chart-legend/component.jsx b/components/widget/components/widget-chart-legend/component.jsx
new file mode 100644
index 0000000000..707670fff6
--- /dev/null
+++ b/components/widget/components/widget-chart-legend/component.jsx
@@ -0,0 +1,78 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+
+import cx from 'classnames';
+
+class WidgetChartLegend extends PureComponent {
+ render() {
+ 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}
+
+ )}
+
+ {items.map(({ label, color, dashline }, titleIdx) => {
+ return (
+ -
+ {dashline ? (
+
+ ) : (
+
+ )}
+
{label}
+
+ );
+ })}
+
+
+ );
+ })}
+
+ );
+ }
+}
+
+WidgetChartLegend.propTypes = {
+ className: PropTypes.string,
+ vertical: PropTypes.bool,
+ 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..20556f2722
--- /dev/null
+++ b/components/widget/components/widget-chart-legend/styles.scss
@@ -0,0 +1,81 @@
+@import '~styles/settings.scss';
+
+.c-widget-chart-legend {
+ display: flex;
+ margin: 20px 0 0;
+ width: 100%;
+ gap: 60px;
+
+ &__column {
+ &-title {
+ display: block;
+ font-weight: 500;
+ font-size: rem(13px);
+ margin: 0 0 rem(8px) 0;
+ }
+
+ &-items {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+
+ &.padded {
+ padding-top: rem(2px);
+ }
+ }
+
+ &-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;
+ }
+ }
+ }
+
+ &.vertical {
+ flex-direction: column;
+ gap: 5px;
+
+ .c-widget-chart-legend {
+ &__column {
+ &-title {
+ margin-top: rem(8px);
+ }
+
+ &-items {
+ &.padded {
+ padding-top: 0;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/components/widget/components/widget-composed-chart/component.jsx b/components/widget/components/widget-composed-chart/component.jsx
index f4cc1106f9..19f7ee1f68 100644
--- a/components/widget/components/widget-composed-chart/component.jsx
+++ b/components/widget/components/widget-composed-chart/component.jsx
@@ -5,9 +5,11 @@ 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 = {
+ analysis: PropTypes.bool,
originalData: PropTypes.array,
data: PropTypes.array,
config: PropTypes.object,
@@ -63,6 +65,7 @@ class WidgetComposedChart extends Component {
render() {
const {
+ analysis,
originalData,
data,
config,
@@ -72,7 +75,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 +110,8 @@ class WidgetComposedChart extends Component {
onBrushEnd={this.handleBrushEnd}
/>
)}
+
+ {chartLegend && }
);
}
diff --git a/components/widgets/climate/emissions-deforestation-drivers/selectors.js b/components/widgets/climate/emissions-deforestation-drivers/selectors.js
index c6269a223a..8253efb859 100644
--- a/components/widgets/climate/emissions-deforestation-drivers/selectors.js
+++ b/components/widgets/climate/emissions-deforestation-drivers/selectors.js
@@ -161,6 +161,25 @@ export const parseConfig = createSelector(
})
.reverse()
);
+
+ // 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) {
tooltip.splice(insertIndex, 0, {
@@ -181,6 +200,7 @@ export const parseConfig = createSelector(
formatNumber({ num: value, specialSpecifier: '.2s', spaceUnit: true }),
unit: 'tCO2e',
tooltip,
+ // 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}
diff --git a/components/widgets/forest-change/tree-loss-primary/selectors.js b/components/widgets/forest-change/tree-loss-primary/selectors.js
index 47f86bd964..60effc90ae 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: 'Percent of primary forest area in 2001 remaining',
+ color: colors.primaryForestExtent,
+ dashline: true,
+ },
+ ],
+ },
+ ],
+ },
}));
export const parseTitle = createSelector(
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';