Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dataset exploration comparison #704

Merged
merged 2 commits into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/scripts/components/common/map/controls/coords.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const getCoords = (mapInstance?: MapRef) => {
};
};

export default function MapCoords() {
export default function MapCoordsControl() {
const { main } = useMaps();

const [position, setPosition] = useState(getCoords(main));
Expand Down
6 changes: 3 additions & 3 deletions app/scripts/components/common/map/maps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ function Maps({ children, projection }: MapsProps) {
acc.compareGenerators = Children.toArray(
child.props.children
) as ReactElement[];
} else if (['Basemap', 'RasterTimeseries'].includes(componentName)) {
acc.generators = [...acc.generators, child];
} else {
} else if (componentName.endsWith('Control')) {
acc.controls = [...acc.controls, child];
} else {
acc.generators = [...acc.generators, child];
}
return acc;
},
Expand Down
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 @@ -5,8 +5,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,10 +1,9 @@
import React, { useState } from 'react';
import { useAtomValue } from 'jotai';
import { addMonths } from 'date-fns';
import { Feature, Polygon } from 'geojson';

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 @@ -24,7 +23,7 @@ import DrawControl from '$components/common/map/controls/aoi';
import useAois from '$components/common/map/controls/hooks/use-aois';
import CustomAoIControl from '$components/common/map/controls/aoi/custom-aoi-control';

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

const {
Expand All @@ -39,6 +38,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 @@ -105,7 +107,7 @@ export function ExplorationMap(props: { comparing: boolean }) {

<ScaleControl />
<MapCoordsControl />
{props.comparing && (
{comparing && (
// Compare map layers
<Compare>
<Basemap
Expand All @@ -119,7 +121,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 @@ -24,6 +26,7 @@ import { DateAxis } from './date-axis';
import {
analysisControllerAtom,
isExpandedAtom,
selectedCompareDateAtom,
selectedDateAtom,
selectedIntervalAtom
} from '$components/exploration/atoms/atoms';
Expand Down Expand Up @@ -67,6 +70,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 { isAnalyzing } = useAtomValue(analysisControllerAtom);
const [isExpanded, setExpanded] = useAtom(isExpandedAtom);
Expand All @@ -83,20 +89,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
Loading