Skip to content

Commit

Permalink
Merge branch 'feature/analysis-presets' of github.com:NASA-IMPACT/del…
Browse files Browse the repository at this point in the history
…ta-ui into feature/download-csv
  • Loading branch information
nerik committed Nov 17, 2022
2 parents 88cb954 + c41ef54 commit ed47b3e
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 91 deletions.
65 changes: 44 additions & 21 deletions app/scripts/components/analysis/define/aoi-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useEffect, useMemo, useRef } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState
} from 'react';
import styled from 'styled-components';
import { Feature, MultiPolygon, Polygon } from 'geojson';
import bbox from '@turf/bbox';
Expand All @@ -22,6 +28,7 @@ import {
CollecticonUpload2
} from '@devseed-ui/collecticons';
import { multiPolygonToPolygon } from '../utils';
import { FeatureByRegionPreset, RegionPreset } from './constants';
import {
Fold,
FoldHeader,
Expand All @@ -35,6 +42,7 @@ import {
AoiChangeListenerOverload,
AoiState
} from '$components/common/aoi/types';
import DropMenuItemButton from '$styles/drop-menu-item-button';

const MapContainer = styled.div`
position: relative;
Expand All @@ -50,32 +58,52 @@ interface AoiSelectorProps {
onAoiEvent: AoiChangeListenerOverload;
}

export default function AoiSelector(props: AoiSelectorProps) {
const { onAoiEvent, qsFeature, aoiDrawState } = props;
export default function AoiSelector({
onAoiEvent,
qsFeature,
aoiDrawState
}: AoiSelectorProps) {
const { selected, drawing, feature } = aoiDrawState;
const mapRef = useRef<MapboxMapRef>(null);

// Technical debt
// Despite the query parameters support for multiple features on the aoi, the
// AOI drawing tool only supports one.
// Keeping just the first one.
const polygon: Feature<Polygon> | null = useMemo(() => {
const qsPolygon: Feature<Polygon> | null = useMemo(() => {
return qsFeature
? { ...multiPolygonToPolygon(qsFeature), id: 'qs-feature' }
: null;
}, [qsFeature]);

// Use the feature from the url qs as the initial state to center the map.
useEffect(() => {
if (polygon) {
onAoiEvent('aoi.set-feature', { feature: polygon });
const featureBbox = bbox(polygon) as [number, number, number, number];
const setFeature = useCallback(
(feature: Feature<Polygon>) => {
onAoiEvent('aoi.set-feature', { feature });
const featureBbox = bbox(feature) as [number, number, number, number];
mapRef.current?.instance?.fitBounds(featureBbox, { padding: 32 });
},
[onAoiEvent]
);

const onRegionPresetClick = useCallback(
(preset: RegionPreset) => {
setFeature({
...FeatureByRegionPreset[preset],
id: 'region-preset-feature'
});
},
[setFeature]
);

// Use the feature from the url qs or the region preset as the initial state to center the map.
useEffect(() => {
if (qsPolygon) {
setFeature(qsPolygon);
} else {
onAoiEvent('aoi.clear');
mapRef.current?.instance?.flyTo({ zoom: 1, center: [0, 0] });
}
}, [onAoiEvent, polygon]);
}, [onAoiEvent, qsPolygon, setFeature]);

return (
<Fold>
Expand Down Expand Up @@ -115,19 +143,14 @@ export default function AoiSelector(props: AoiSelectorProps) {
</ToolbarIconButton>
)}
>
<DropTitle>Select a country</DropTitle>
<DropTitle>Select a region</DropTitle>
<DropMenu>
<li>
<DropMenuItem href='#'>Country name A</DropMenuItem>
</li>
<li>
<DropMenuItem href='#'>Country name B</DropMenuItem>
</li>
<li>
<DropMenuItem href='#'>Country name C</DropMenuItem>
</li>
<li>
<DropMenuItem href='#'>Country name D</DropMenuItem>
<DropMenuItemButton
onClick={() => onRegionPresetClick('world')}
>
World
</DropMenuItemButton>
</li>
</DropMenu>
</Dropdown>
Expand Down
22 changes: 22 additions & 0 deletions app/scripts/components/analysis/define/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Feature, Polygon } from 'geojson';

export type RegionPreset = 'world';

export const FeatureByRegionPreset: Record<RegionPreset, Feature<Polygon>> = {
world: {
type: 'Feature',
properties: {},
geometry: {
coordinates: [
[
[-180, -89],
[180, -89],
[180, 89],
[-180, 89],
[-180, -89]
]
],
type: 'Polygon'
}
}
};
44 changes: 38 additions & 6 deletions app/scripts/components/analysis/define/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo } from 'react';
import React, { useCallback, useEffect, useMemo, MouseEvent } from 'react';
import styled from 'styled-components';
import { uniqBy } from 'lodash';
import { media, multiply, themeVal } from '@devseed-ui/theme-provider';
Expand Down Expand Up @@ -42,7 +42,13 @@ import {
} from '$components/common/fold';
import { S_FAILED, S_LOADING, S_SUCCEEDED } from '$utils/status';
import { useAoiControls } from '$components/common/aoi/use-aoi-controls';
import { dateToInputFormat, inputFormatToDate } from '$utils/date';
import {
DateRangePreset,
dateToInputFormat,
getRangeFromPreset,
inputFormatToDate
} from '$utils/date';
import DropMenuItemButton from '$styles/drop-menu-item-button';

const FormBlock = styled.div`
display: flex;
Expand Down Expand Up @@ -129,6 +135,16 @@ export default function Analysis() {
[setAnalysisParam]
);

const onDatePresetClick = useCallback(
(e: MouseEvent, preset: DateRangePreset) => {
e.preventDefault();
const { start, end } = getRangeFromPreset(preset);
setAnalysisParam('start', start);
setAnalysisParam('end', end);
},
[setAnalysisParam]
);

const allAvailableDatasetsLayers: DatasetLayer[] = useMemo(
() =>
uniqBy(
Expand Down Expand Up @@ -253,16 +269,32 @@ export default function Analysis() {
<DropTitle>Select a date preset</DropTitle>
<DropMenu>
<li>
<DropMenuItem href='#'>Preset A</DropMenuItem>
<DropMenuItemButton
onClick={(e) => onDatePresetClick(e, 'yearToDate')}
>
This year
</DropMenuItemButton>
</li>
<li>
<DropMenuItem href='#'>Preset B</DropMenuItem>
<DropMenuItemButton
onClick={(e) => onDatePresetClick(e, 'last30Days')}
>
Last 30 days
</DropMenuItemButton>
</li>
<li>
<DropMenuItem href='#'>Preset C</DropMenuItem>
<DropMenuItemButton
onClick={(e) => onDatePresetClick(e, 'lastYear')}
>
Last year
</DropMenuItemButton>
</li>
<li>
<DropMenuItem href='#'>Preset D</DropMenuItem>
<DropMenuItemButton
onClick={(e) => onDatePresetClick(e, 'last10Years')}
>
Last 10 years
</DropMenuItemButton>
</li>
</DropMenu>
</Dropdown>
Expand Down
14 changes: 7 additions & 7 deletions app/scripts/components/common/aoi/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ export type AoiChangeListener = (
}
) => void;

export type AoiChangeListenerOverload = {
(action: 'aoi.draw-click', payload?: never): void;
(action: 'aoi.set-feature', payload: { feature: AoiFeature }): void;
(action: 'aoi.clear', payload?: never): void;
(action: 'aoi.draw-finish', payload: { feature: AoiFeature }): void;
export interface AoiChangeListenerOverload {
(action: 'aoi.draw-click' | 'aoi.clear', payload?: never): void;
(
action: 'aoi.draw-finish' | 'aoi.set-feature' | 'aoi.update',
payload: { feature: AoiFeature }
): void;
(action: 'aoi.selection', payload: { selected: boolean }): void;
(action: 'aoi.update', payload: { feature: AoiFeature }): void;
};
}
6 changes: 4 additions & 2 deletions app/scripts/components/common/chart/analysis/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ const syncId = 'analysis';

export default React.forwardRef<AnalysisChartRef, AnalysisChartProps>(
function AnalysisChart(props, ref) {
const { timeSeriesData, dates, uniqueKeys, dateFormat, xKey } = props;
const { timeSeriesData, dates, uniqueKeys, dateFormat, xKey, altTitle } =
props;

const chartRef = useRef<ChartWrapperRef>(null);

Expand All @@ -48,6 +49,7 @@ export default React.forwardRef<AnalysisChartRef, AnalysisChartProps>(
if (!chartRef.current) return;

const chartImageUrl = await exportImage({
title: altTitle,
svgWrapperRef: chartRef,
legendSvgString: getLegendStringForScreenshot({
uniqueKeys,
Expand All @@ -57,7 +59,7 @@ export default React.forwardRef<AnalysisChartRef, AnalysisChartProps>(
FileSaver.saveAs(chartImageUrl, `${name}.jpg`);
}
}),
[uniqueKeys, props.colors]
[uniqueKeys, props.colors, altTitle]
);

return (
Expand Down
8 changes: 4 additions & 4 deletions app/scripts/components/common/chart/analysis/svg-legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { renderToStaticMarkup } from 'react-dom/server';
// Creating SVG version of legend for exporting purpose
export function getLegendStringForScreenshot({ uniqueKeys, lineColors }) {
const legendWidth = 80;
const legendHeight = 40;
const legendHeight = 16;

return renderToStaticMarkup(
<svg
Expand All @@ -19,10 +19,10 @@ export function getLegendStringForScreenshot({ uniqueKeys, lineColors }) {
.map((entry, idx) => (
<g
key={entry.label}
transform={`translate(${idx * legendWidth}, 10)`}
transform={`translate(${idx * legendWidth}, 0)`}
>
<rect width={12} height={12} fill={lineColors[idx]} />
<text x={20} y={10} fontSize='12px'>
<circle cx={6} cy={8} r={6} fill={lineColors[idx]} />
<text x={20} y={0} dy='1em' fontSize='12px'>
{entry.label}
</text>
</g>
Expand Down
Loading

0 comments on commit ed47b3e

Please sign in to comment.