Skip to content

Commit

Permalink
Store exploration dates on url
Browse files Browse the repository at this point in the history
Contributes to #527
  • Loading branch information
danielfdsilva authored Oct 31, 2023
2 parents a89b14a + b5bab98 commit 67f6aaf
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 24 deletions.
25 changes: 13 additions & 12 deletions app/scripts/components/common/map/controls/aoi/atoms.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import { atom } from "jotai";
import { atomWithLocation } from "jotai-location";
import { Feature, Polygon } from "geojson";
import { AoIFeature } from "../../types";
import { decodeAois, encodeAois } from "$utils/polygon-url";
import { atom } from 'jotai';
import { atomWithLocation } from 'jotai-location';
import { Feature, Polygon } from 'geojson';
import { AoIFeature } from '../../types';
import { decodeAois, encodeAois } from '$utils/polygon-url';

// This is the atom acting as a single source of truth for the AOIs.
export const aoisAtom = atomWithLocation();

const aoisSerialized = atom(
(get) => get(aoisAtom).searchParams?.get("aois"),
(get) => get(aoisAtom).searchParams?.get('aois'),
(get, set, aois) => {
set(aoisAtom, (prev) => ({
...prev,
searchParams: new URLSearchParams([["aois", aois as string]])
}));
set(aoisAtom, (prev) => {
const searchParams = prev.searchParams ?? new URLSearchParams();
searchParams.set('aois', aois as string);

return { ...prev, searchParams };
});
}
);


// Getter atom to get AoiS as GeoJSON features from the hash.
export const aoisFeaturesAtom = atom<AoIFeature[]>((get) => {
const hash = get(aoisSerialized);
Expand Down Expand Up @@ -69,4 +70,4 @@ export const aoisDeleteAtom = atom(null, (get, set, ids: string[]) => {

export const aoiDeleteAllAtom = atom(null, (get, set) => {
set(aoisSerialized, encodeAois([]));
});
});
91 changes: 79 additions & 12 deletions app/scripts/components/exploration/atoms/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@ import {
// This is the atom acting as a single source of truth for the AOIs.
const locAtom = atomWithLocation();

const setUrlParam = (name: string, value: string) => (prev) => {
const searchParams = prev.searchParams ?? new URLSearchParams();
searchParams.set(name, value);

return { ...prev, searchParams };
};

const getValidDateOrNull = (value: any) => {
if (!value) {
return null;
}
const date = new Date(value);
return isNaN(date.getTime()) ? null : date;
};

type ValueUpdater<T> = T | ((prev: T) => T);

// Dataset data that is serialized to the url. Only the data needed to
// reconstruct the dataset (and user interaction data like settings) is stored
// in the url, otherwise it would be too long.
Expand All @@ -33,10 +50,7 @@ const datasetsUrlConfig = atom(
(get, set, datasets: TimelineDataset[]) => {
// Extract need properties from the datasets and encode them.
const encoded = urlDatasetsDehydrate(datasets);
set(locAtom, (prev) => ({
...prev,
searchParams: new URLSearchParams([['datasets', encoded]])
}));
set(locAtom, setUrlParam('datasets', encoded));
}
);

Expand Down Expand Up @@ -67,11 +81,7 @@ export const timelineDatasetsAtom = atom(
return reconciled;
});
},
(
get,
set,
updates: TimelineDataset[] | (<T extends TimelineDataset>(prev: T[]) => T[])
) => {
(get, set, updates: ValueUpdater<TimelineDataset[]>) => {
const newData =
typeof updates === 'function'
? updates(get(timelineDatasetsStorageAtom))
Expand All @@ -81,21 +91,77 @@ export const timelineDatasetsAtom = atom(
set(timelineDatasetsStorageAtom, newData);
}
);

// Main timeline date. This date defines the datasets shown on the map.
export const selectedDateAtom = atom<Date | null>(null);
export const selectedDateAtom = atom(
(get) => {
const txtDate = get(locAtom).searchParams?.get('date');
return getValidDateOrNull(txtDate);
},
(get, set, updates: ValueUpdater<Date | null>) => {
const newData =
typeof updates === 'function'
? updates(get(selectedCompareDateAtom))
: updates;

set(locAtom, setUrlParam('date', newData?.toISOString() ?? ''));
}
);

// Compare date. This is the compare date for the datasets shown on the map.
export const selectedCompareDateAtom = atom<Date | null>(null);
export const selectedCompareDateAtom = atom(
(get) => {
const txtDate = get(locAtom).searchParams?.get('dateCompare');
return getValidDateOrNull(txtDate);
},
(get, set, updates: ValueUpdater<Date | null>) => {
const newData =
typeof updates === 'function'
? updates(get(selectedCompareDateAtom))
: updates;

set(locAtom, setUrlParam('dateCompare', newData?.toISOString() ?? ''));
}
);

// Date range for L&R playheads.
export const selectedIntervalAtom = atom<DateRange | null>(null);
export const selectedIntervalAtom = atom(
(get) => {
const txtDate = get(locAtom).searchParams?.get('dateRange');
const [start, end] = txtDate?.split('|') ?? [];

const dateStart = getValidDateOrNull(start);
const dateEnd = getValidDateOrNull(end);

if (!dateStart || !dateEnd) return null;

return { start: dateStart, end: dateEnd };
},
(get, set, updates: ValueUpdater<DateRange | null>) => {
const newData =
typeof updates === 'function'
? updates(get(selectedIntervalAtom))
: updates;

const value = newData
? `${newData.start.toISOString()}|${newData.end.toISOString()}`
: '';

set(locAtom, setUrlParam('dateRange', value));
}
);

// Zoom transform for the timeline. Values as object instead of d3.ZoomTransform
export const zoomTransformAtom = atom<ZoomTransformPlain>({
x: 0,
y: 0,
k: 1
});

// Width of the whole timeline item. Set via a size observer and then used to
// compute the different element sizes.
export const timelineWidthAtom = atom<number | undefined>(undefined);

// Derived atom with the different sizes of the timeline elements.
export const timelineSizesAtom = atom((get) => {
const totalWidth = get(timelineWidthAtom);
Expand All @@ -109,6 +175,7 @@ export const timelineSizesAtom = atom((get) => {
)
};
});

// Whether or not the dataset rows are expanded.
export const isExpandedAtom = atom<boolean>(false);

Expand Down

0 comments on commit 67f6aaf

Please sign in to comment.