Skip to content

Commit

Permalink
Store exploration dates on url
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfdsilva committed Oct 26, 2023
1 parent 52a1252 commit 568157f
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 19 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([]));
});
});
95 changes: 88 additions & 7 deletions app/scripts/components/exploration/atoms/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ 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;
};

// 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 +48,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 @@ -81,21 +93,89 @@ 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: Date | null | (<T extends Date | null>(prev: T) => T)
) => {
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: Date | null | (<T extends Date | null>(prev: T) => T)
) => {
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: DateRange | null | (<T extends DateRange | null>(prev: T) => T)
) => {
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 +189,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 568157f

Please sign in to comment.