Skip to content

Commit

Permalink
Implement controls for dataset compare
Browse files Browse the repository at this point in the history
Fix #523
  • Loading branch information
danielfdsilva committed Oct 17, 2023
1 parent 47f9405 commit 825f3df
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 98 deletions.
4 changes: 3 additions & 1 deletion app/scripts/components/exploration/atoms/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { DateRange, TimelineDataset, ZoomTransformPlain } from '../types.d.ts';

// Datasets to show on the timeline and their settings
export const timelineDatasetsAtom = atom<TimelineDataset[]>([]);
// Main timeline date. This date defines the datasets shown on the map.
// Main timeline date. This is the date for the datasets shown on the map.
export const selectedDateAtom = atom<Date | null>(null);
// Compare date. This is the compare date for the datasets shown on the map.
export const selectedCompareDateAtom = atom<Date | null>(null);
// Date range for L&R playheads.
export const selectedIntervalAtom = atom<DateRange | null>(null);
// Zoom transform for the timeline. Values as object instead of d3.ZoomTransform
Expand Down
12 changes: 7 additions & 5 deletions app/scripts/components/exploration/components/map/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import React, { useState } from 'react';
import { useAtomValue } from 'jotai';
import { addMonths } from 'date-fns';

import { useStacMetadataOnDatasets } from '../../hooks/use-stac-metadata-datasets';
import { selectedDateAtom, timelineDatasetsAtom } from '../../atoms/atoms';
import { selectedCompareDateAtom, selectedDateAtom, timelineDatasetsAtom } from '../../atoms/atoms';
import {
TimelineDatasetStatus,
TimelineDatasetSuccess
Expand All @@ -21,7 +20,7 @@ import { useBasemap } from '$components/common/map/controls/hooks/use-basemap';
import DrawControl from '$components/common/map/controls/aoi';
import useAois from '$components/common/map/controls/hooks/use-aois';

export function ExplorationMap(props: { comparing: boolean }) {
export function ExplorationMap() {
const [projection, setProjection] = useState(projectionDefault);

const {
Expand All @@ -36,6 +35,9 @@ export function ExplorationMap(props: { comparing: boolean }) {

const datasets = useAtomValue(timelineDatasetsAtom);
const selectedDay = useAtomValue(selectedDateAtom);
const selectedCompareDay = useAtomValue(selectedCompareDateAtom);

const comparing = !!selectedCompareDay;

// Reverse the datasets order to have the "top" layer, list-wise, at the "top" layer, z-order wise
// Disabled eslint rule as slice() creates a shallow copy
Expand Down Expand Up @@ -96,7 +98,7 @@ export function ExplorationMap(props: { comparing: boolean }) {

<ScaleControl />
<MapCoordsControl />
{props.comparing && (
{comparing && (
// Compare map layers
<Compare>
<Basemap
Expand All @@ -110,7 +112,7 @@ export function ExplorationMap(props: { comparing: boolean }) {
key={dataset.data.id}
id={`${dataset.data.id}-compare`}
dataset={dataset}
selectedDay={addMonths(selectedDay, 1)}
selectedDay={selectedCompareDay}
order={idx}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { scaleTime, ScaleTime } from 'd3';
import { glsp, themeVal } from '@devseed-ui/theme-provider';
import {
CollecticonChevronDownSmall,
CollecticonPlusSmall,
CollecticonResizeIn,
CollecticonResizeOut
CollecticonResizeOut,
CollecticonTrashBin
} from '@devseed-ui/collecticons';
import { Button } from '@devseed-ui/button';
import { DatePicker } from '@devseed-ui/date-picker';
Expand All @@ -26,6 +28,7 @@ import {
activeAnalysisMetricsAtom,
isAnalysisAtom,
isExpandedAtom,
selectedCompareDateAtom,
selectedDateAtom,
selectedIntervalAtom
} from '$components/exploration/atoms/atoms';
Expand Down Expand Up @@ -69,6 +72,9 @@ export function TimelineControls(props: TimelineControlsProps) {
const { xScaled, width } = props;

const [selectedDay, setSelectedDay] = useAtom(selectedDateAtom);
const [selectedCompareDay, setSelectedCompareDay] = useAtom(
selectedCompareDateAtom
);
const [selectedInterval, setSelectedInterval] = useAtom(selectedIntervalAtom);
const [activeMetrics, setActiveMetrics] = useAtom(activeAnalysisMetricsAtom);
const isAnalysis = useAtomValue(isAnalysisAtom);
Expand All @@ -86,20 +92,65 @@ export function TimelineControls(props: TimelineControlsProps) {
<TimelineControlsSelf>
<ControlsToolbar>
<Toolbar>
<DatePicker
id='date-picker-p'
value={{ start: selectedDay, end: selectedDay }}
onConfirm={(d) => {
setSelectedDay(d.start!);
}}
renderTriggerElement={(props, label) => (
<DatePickerButton {...props} size='small' disabled={!xScaled}>
<span className='head-reference'>P</span>
<span>{label}</span>
<CollecticonChevronDownSmall />
</DatePickerButton>
<ToolbarGroup>
<DatePicker
id='date-picker-a'
value={{ start: selectedDay, end: selectedDay }}
onConfirm={(d) => {
setSelectedDay(d.start!);
}}
renderTriggerElement={(props, label) => (
<DatePickerButton {...props} size='small' disabled={!xScaled}>
<span className='head-reference'>A</span>
<span>{label}</span>
<CollecticonChevronDownSmall />
</DatePickerButton>
)}
/>
<VerticalDivider />
{selectedCompareDay ? (
<>
<DatePicker
id='date-picker-b'
value={{ start: selectedCompareDay, end: selectedCompareDay }}
onConfirm={(d) => {
setSelectedCompareDay(d.start!);
}}
renderTriggerElement={(props, label) => (
<DatePickerButton
{...props}
size='small'
disabled={!xScaled}
>
<span className='head-reference'>B</span>
<span>{label}</span>
<CollecticonChevronDownSmall />
</DatePickerButton>
)}
/>
<ToolbarIconButton
size='small'
onClick={() => {
setSelectedCompareDay(null);
}}
>
<CollecticonTrashBin
meaningful
title='Stop comparing dates'
/>
</ToolbarIconButton>
</>
) : (
<ToolbarIconButton
size='small'
onClick={() => {
setSelectedCompareDay(selectedDay);
}}
>
<CollecticonPlusSmall meaningful title='Add comparison date' />
</ToolbarIconButton>
)}
/>
</ToolbarGroup>
<ToolbarGroup>
<DatePicker
id='date-picker-lr'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const TimelineHeadSVG = styled.svg`
const dropShadowFilter =
'drop-shadow(0px 2px 2px rgba(44, 62, 80, 0.08)) drop-shadow(0px 0px 4px rgba(44, 62, 80, 0.08))';

interface TimelineHeadProps {
interface TimelineHeadBaseProps {
domain: [Date, Date];
xScaled: ScaleTime<number, number>;
selectedDay: Date;
Expand All @@ -32,7 +32,11 @@ interface TimelineHeadProps {
children: React.ReactNode;
}

export function TimelineHead(props: TimelineHeadProps) {
type TimelineHeadProps = Omit<TimelineHeadBaseProps, 'children'> & {
label?: string;
};

export function TimelineHeadBase(props: TimelineHeadBaseProps) {
const { domain, xScaled, selectedDay, width, onDayChange, children } = props;

const theme = useTheme();
Expand Down Expand Up @@ -81,13 +85,7 @@ export function TimelineHead(props: TimelineHeadProps) {
return (
<TimelineHeadSVG width={width + SVG_PADDING * 2}>
<g transform={`translate(${SVG_PADDING}, 0)`}>
<line
x1={xPos}
x2={xPos}
y1={0}
y2='100%'
stroke={theme.color?.base}
/>
<line x1={xPos} x2={xPos} y1={0} y2='100%' stroke={theme.color?.base} />
<g transform={`translate(${xPos}, 0)`} ref={rectRef}>
{children}
</g>
Expand All @@ -96,11 +94,12 @@ export function TimelineHead(props: TimelineHeadProps) {
);
}

export function TimelineHeadP(props: Omit<TimelineHeadProps, 'children'>) {
export function TimelineHeadPoint(props: TimelineHeadProps) {
const theme = useTheme();
const { label, ...rest } = props;

return (
<TimelineHead {...props}>
<TimelineHeadBase {...rest}>
<path
transform='translate(-14, -4)'
d='M4 14.6459C4 15.4637 4.4979 16.1992 5.25722 16.5029L13.2572 19.7029C13.734 19.8936 14.266 19.8936 14.7428 19.7029L22.7428 16.5029C23.5021 16.1992 24 15.4637 24 14.6459L24 6C24 4.89543 23.1046 4 22 4L6 4C4.89543 4 4 4.89543 4 6L4 14.6459Z'
Expand All @@ -112,17 +111,18 @@ export function TimelineHeadP(props: Omit<TimelineHeadProps, 'children'>) {
}}
/>
<text fill={theme.color?.base} fontSize='0.75rem' y='0' x='-4' dy='1em'>
P
{label ?? 'P'}
</text>
</TimelineHead>
</TimelineHeadBase>
);
}

export function TimelineHeadL(props: Omit<TimelineHeadProps, 'children'>) {
export function TimelineHeadIn(props: TimelineHeadProps) {
const theme = useTheme();
const { label, ...rest } = props;

return (
<TimelineHead {...props}>
<TimelineHeadBase {...rest}>
<path
transform='translate(-6, -4)'
d='M4 6C4 4.89543 4.89543 4 6 4H15.1716C15.702 4 16.2107 4.21071 16.5858 4.58579L22.5858 10.5858C23.3668 11.3668 23.3668 12.6332 22.5858 13.4142L16.5858 19.4142C16.2107 19.7893 15.702 20 15.1716 20H6C4.89543 20 4 19.1046 4 18V6Z'
Expand All @@ -134,16 +134,18 @@ export function TimelineHeadL(props: Omit<TimelineHeadProps, 'children'>) {
}}
/>
<text fill={theme.color?.base} fontSize='0.75rem' y='0' x='2' dy='1em'>
L
{label ?? 'L'}
</text>
</TimelineHead>
</TimelineHeadBase>
);
}

export function TimelineHeadR(props: Omit<TimelineHeadProps, 'children'>) {
export function TimelineHeadOut(props: TimelineHeadProps) {
const theme = useTheme();
const { label, ...rest } = props;

return (
<TimelineHead {...props}>
<TimelineHeadBase {...rest}>
<path
transform='translate(-22, -4)'
d='M24 6C24 4.89543 23.1046 4 22 4H12.8284C12.298 4 11.7893 4.21071 11.4142 4.58579L5.41421 10.5858C4.63316 11.3668 4.63317 12.6332 5.41421 13.4142L11.4142 19.4142C11.7893 19.7893 12.298 20 12.8284 20H22C23.1046 20 24 19.1046 24 18V6Z'
Expand All @@ -162,9 +164,9 @@ export function TimelineHeadR(props: Omit<TimelineHeadProps, 'children'>) {
dy='1em'
textAnchor='end'
>
R
{label ?? 'R'}
</text>
</TimelineHead>
</TimelineHeadBase>
);
}

Expand Down
Loading

0 comments on commit 825f3df

Please sign in to comment.