Skip to content

Commit

Permalink
[PR] Allow for legend to show more values
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfdsilva authored Jun 21, 2023
2 parents 3e7ac89 + ad521c5 commit f5a7236
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 18 deletions.
74 changes: 62 additions & 12 deletions app/scripts/components/common/mapbox/layer-legend.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode, Fragment } from 'react';
import React, { ReactNode, Fragment, useState, useCallback } from 'react';
import styled from 'styled-components';
import { LayerLegendCategorical, LayerLegendGradient } from 'veda';
import { AccordionFold, AccordionManager } from '@devseed-ui/accordion';
Expand All @@ -11,9 +11,15 @@ import {
import { CollecticonCircleInformation } from '@devseed-ui/collecticons';
import { Toolbar, ToolbarIconButton } from '@devseed-ui/toolbar';
import { ShadowScrollbar } from '@devseed-ui/shadow-scrollbar';
import { followCursor } from 'tippy.js';
import { scaleLinear } from 'd3';

import { Tip } from '../tip';
import { formatThousands } from '$utils/format';
import {
formatAsScientificNotation,
formatThousands,
round
} from '$utils/format';
import { variableBaseType, variableGlsp } from '$styles/variable-utils';
import {
WidgetItemBodyInner,
Expand Down Expand Up @@ -44,8 +50,27 @@ const makeGradient = (stops: string[]) => {
return `linear-gradient(to right, ${steps.join(', ')})`;
};

const printLegendVal = (val: string | number) =>
typeof val === 'number' ? formatThousands(val, { shorten: true }) : val;
const printLegendVal = (val: string | number) => {
const number = Number(val);
if (isNaN(number)) return val;

if (Math.abs(number) < 1000 && Math.abs(number) > 0.001) {
return formatThousands(number, { decimals: 3 });
} else {
return formatAsScientificNotation(number, 2);
}
};

const formatTooltipValue = (rawVal, unit) => {
let value;
if (Math.abs(rawVal) < 1000 && Math.abs(rawVal) > 0.001) {
value = round(rawVal, 3);
} else {
value = formatAsScientificNotation(rawVal, 2);
}

return unit?.label ? `${value} ${unit.label}` : value;
};

export const LegendContainer = styled.div`
position: absolute;
Expand Down Expand Up @@ -146,6 +171,9 @@ const LegendList = styled.dl`
`;

const LegendSwatch = styled.span<LegendSwatchProps>`
/* position is needed to ensure that the layerX on the event is relative to
this element */
position: relative;
display: block;
font-size: 0;
height: 0.5rem;
Expand Down Expand Up @@ -209,6 +237,7 @@ export function LayerLegend(
<LayerGradientGraphic
type='gradient'
stops={props.stops}
unit={props.unit}
min={props.min}
max={props.max}
/>
Expand Down Expand Up @@ -237,9 +266,7 @@ export function LayerLegend(
export function LayerLegendContainer(props: LayerLegendContainerProps) {
return (
<LegendContainer>
<AccordionManager>
{props.children}
</AccordionManager>
<AccordionManager>{props.children}</AccordionManager>
</LegendContainer>
);
}
Expand Down Expand Up @@ -276,17 +303,40 @@ function LayerCategoricalGraphic(props: LayerLegendCategorical) {
}

function LayerGradientGraphic(props: LayerLegendGradient) {
const { stops, min, max } = props;
const { stops, min, max, unit } = props;

const [hoverVal, setHoverVal] = useState(0);

const moveListener = useCallback(
(e) => {
const width = e.nativeEvent.target.clientWidth;
const scale = scaleLinear()
.domain([0, width])
.range([Number(min), Number(max)]);
setHoverVal(scale(e.nativeEvent.layerX));
},
[min, max]
);

const hasNumericLegend = !isNaN(Number(min) + Number(max));
const tipText = formatTooltipValue(hoverVal, unit);

return (
<LegendList>
<dt>
<LegendSwatch stops={stops}>
{stops[0]} to {stops[stops.length - 1]}
</LegendSwatch>
<Tip
disabled={!hasNumericLegend}
content={tipText}
followCursor='horizontal'
plugins={[followCursor]}
>
<LegendSwatch stops={stops} onMouseMove={moveListener}>
{stops[0]} to {stops[stops.length - 1]}
</LegendSwatch>
</Tip>
</dt>
<dd>
<span>{printLegendVal(min)}</span>
<span>{printLegendVal(min)} {unit?.label}</span>
<i></i>
<span>{printLegendVal(max)}</span>
</dd>
Expand Down
11 changes: 7 additions & 4 deletions app/scripts/utils/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ interface FormatThousandsOptions {
* formatThousands(1/2, { decimals: 5, forceDecimals: true}) 0.50000
*
*/
export function formatThousands(num: number, options: FormatThousandsOptions) {
export function formatThousands(num: number, options?: FormatThousandsOptions) {
const opts = {
decimals: 2,
separator: ',',
Expand All @@ -86,7 +86,10 @@ export function formatThousands(num: number, options: FormatThousandsOptions) {
return str;
};

let [int, dec] = Number(round(num, opts.decimals)).toString().split('.');
const sign = num < 0 ? '-' : '';
const absNum = Math.abs(num);

let [int, dec] = Number(round(absNum, opts.decimals)).toString().split('.');

let largeNumUnit = '';
if (opts.shorten) {
Expand All @@ -105,8 +108,8 @@ export function formatThousands(num: number, options: FormatThousandsOptions) {
: dec;

return dec !== ''
? `${int}.${dec} ${largeNumUnit}`
: `${int} ${largeNumUnit}`;
? `${sign}${int}.${dec} ${largeNumUnit}`
: `${sign}${int} ${largeNumUnit}`;
}

/**
Expand Down
6 changes: 4 additions & 2 deletions mock/datasets/no2.data.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ layers:
return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`;
}
legend:
unit:
label: molecules/cm3
type: gradient
min: "< -3"
max: "> 3"
min: "-3934857984753"
max: "3348573489573"
stops:
- "#3A88BD"
- "#C9E0ED"
Expand Down

0 comments on commit f5a7236

Please sign in to comment.