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

Display selected datasets on the map #668

Merged
merged 7 commits into from
Oct 2, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { useMemo } from 'react';
import { BaseGeneratorParams } from '../types';

export default function useGeneratorParams(props: BaseGeneratorParams) {
return useMemo(() => {
return props;
// Memoize only required abse params
}, [props.generatorOrder, props.hidden, props.opacity]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ import {
FIT_BOUNDS_PADDING,
getFilterPayload,
getMergedBBox,
requestQuickCache,
requestQuickCache
} from '../utils';
import useFitBbox from '../hooks/use-fit-bbox';
import useLayerInteraction from '../hooks/use-layer-interaction';
import { MARKER_LAYOUT } from '../hooks/use-custom-marker';
import useMaps from '../hooks/use-maps';
import useGeneratorParams from '../hooks/use-generator-params';

import {
ActionStatus,
Expand All @@ -32,7 +33,6 @@ import {
S_SUCCEEDED
} from '$utils/status';


// Whether or not to print the request logs.
const LOG = true;

Expand Down Expand Up @@ -70,16 +70,16 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
onStatusChange,
isPositionSet,
hidden,
opacity
} = props;


const { current: mapInstance } = useMaps();

const theme = useTheme();
const { updateStyle } = useMapStyle();

const minZoom = zoomExtent?.[0] ?? 0;
const generatorId = 'raster-timeseries' + id;
const generatorId = `raster-timeseries-${id}`;

// Status tracking.
// A raster timeseries layer has a base layer and may have markers.
Expand Down Expand Up @@ -288,11 +288,7 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
}
LOG &&
/* eslint-disable-next-line no-console */
console.log(
'RasterTimeseries %cAborted Mosaic',
'color: red;',
id
);
console.log('RasterTimeseries %cAborted Mosaic', 'color: red;', id);
return;
}
};
Expand Down Expand Up @@ -331,6 +327,8 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
[sourceParams]
);

const generatorParams = useGeneratorParams(props);

useEffect(
() => {
const controller = new AbortController();
Expand All @@ -343,7 +341,7 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
const tileParams = qs.stringify(
{
assets: 'cog_default',
...sourceParams
...(sourceParams ?? {})
},
// Temporary solution to pass different tile parameters for hls data
{
Expand Down Expand Up @@ -376,12 +374,14 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
url: tilejsonUrl
};

const rasterOpacity = typeof opacity === 'number' ? opacity / 100 : 1;

const mosaicLayer: RasterLayer = {
id: id,
type: 'raster',
source: id,
paint: {
'raster-opacity': Number(!hidden),
'raster-opacity': hidden ? 0 : rasterOpacity,
'raster-opacity-transition': {
duration: 320
}
Expand Down Expand Up @@ -416,7 +416,7 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
id: pointsSourceId,
source: pointsSourceId,
layout: {
...MARKER_LAYOUT as any,
...(MARKER_LAYOUT as any),
'icon-allow-overlap': true
},
paint: {
Expand All @@ -440,7 +440,7 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
generatorId,
sources,
layers,
params: props as BaseGeneratorParams
params: generatorParams
});
}

Expand All @@ -450,16 +450,16 @@ export function RasterTimeseries(props: RasterTimeseriesProps) {
controller.abort();
};
},
// sourceParams not included, but using a stringified version of it to detect changes (haveSourceParamsChanged)
// sourceParams not included, but using a stringified version of it to
// detect changes (haveSourceParamsChanged)
[
updateStyle,
id,
mosaicUrl,
minZoom,
points,
haveSourceParamsChanged,
hidden,
generatorId
generatorParams
]
);

Expand Down
17 changes: 11 additions & 6 deletions app/scripts/components/common/map/styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React, {
} from 'react';
import {
ExtendedLayer,
ExtendedMetadata,
GeneratorStyleParams,
LayerOrderPosition
} from './types';
Expand Down Expand Up @@ -52,7 +53,7 @@ const generateStyle = (stylesData: Record<string, GeneratorStyleParams>) => {
};

const generatorLayers = generatorParams.layers.map((generatorLayer) => {
const metadata = generatorLayer.metadata ?? {};
const metadata: ExtendedMetadata = generatorLayer.metadata ?? {};
metadata.generatorId = generatorId;

const mapLayer = { ...generatorLayer, metadata } as Layer;
Expand All @@ -76,13 +77,17 @@ const generateStyle = (stylesData: Record<string, GeneratorStyleParams>) => {
const layerBOrder = layerB.metadata?.layerOrderPosition;
const layerAIndex = LAYER_ORDER.indexOf(layerAOrder);
const layerBIndex = LAYER_ORDER.indexOf(layerBOrder);
const sortDeltaOrder = layerAIndex - layerBIndex;
const sortDeltaGeneratorId = layerA.metadata?.generatorId.localeCompare(
layerB.metadata?.generatorId
);
const layerOrder = layerAIndex - layerBIndex;
const generatorA = stylesData[layerA.metadata?.generatorId];
const generatorB = stylesData[layerB.metadata?.generatorId];
const generatorOrder =
generatorA.params?.generatorOrder !== undefined &&
generatorB.params?.generatorOrder !== undefined
? generatorA.params.generatorOrder - generatorB.params.generatorOrder
: 0;
// If compared layers have different layer orders, sort by layer order, otherwise
// fallback on generatorId to ensure layer stacks from the same generator stay contiguous
return sortDeltaOrder !== 0 ? sortDeltaOrder : sortDeltaGeneratorId;
return layerOrder !== 0 ? layerOrder : generatorOrder;
});

return {
Expand Down
12 changes: 8 additions & 4 deletions app/scripts/components/common/map/types.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { AnyLayer, AnySourceImpl } from "mapbox-gl";

export interface ExtendedMetadata {
layerOrderPosition?: LayerOrderPosition;
[key: string]: any;
}

export type ExtendedLayer = AnyLayer & {
metadata?: {
layerOrderPosition?: LayerOrderPosition;
[key: string]: any;
};
metadata?: ExtendedMetadata;
};

export interface BaseGeneratorParams {
hidden?: boolean;
generatorOrder?: number;
opacity?: number;
}
export interface GeneratorStyleParams {
generatorId: string;
Expand Down
79 changes: 68 additions & 11 deletions app/scripts/components/common/map/utils.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
import axios, { Method } from 'axios';
import { Map as MapboxMap } from 'mapbox-gl';
import { MapRef } from 'react-map-gl';
import { endOfDay, startOfDay } from "date-fns";
import { StacFeature } from "./types";
import { userTzDate2utcString } from "$utils/date";
import { validateRangeNum } from "$utils/utils";
import { endOfDay, startOfDay } from 'date-fns';
import {
DatasetDatumFn,
DatasetDatumFnResolverBag,
DatasetDatumReturnType
} from 'veda';

import { StacFeature } from './types';

import { userTzDate2utcString } from '$utils/date';
import { validateRangeNum } from '$utils/utils';

export const FIT_BOUNDS_PADDING = 32;

export const validateLon = validateRangeNum(-180, 180);
export const validateLat = validateRangeNum(-90, 90);



export function getMergedBBox(features: StacFeature[]) {
const mergedBBox = [
Number.POSITIVE_INFINITY,
Expand All @@ -32,8 +36,6 @@ export function getMergedBBox(features: StacFeature[]) {
) as [number, number, number, number];
}



export function checkFitBoundsFromLayer(
layerBounds?: [number, number, number, number],
mapInstance?: MapboxMap | MapRef
Expand All @@ -58,8 +60,6 @@ export function checkFitBoundsFromLayer(
return layerExtentSmaller || isOutside;
}



/**
* Creates the appropriate filter object to send to STAC.
*
Expand Down Expand Up @@ -87,7 +87,6 @@ export function getFilterPayload(date: Date, collection: string) {
};
}


// There are cases when the data can't be displayed properly on low zoom levels.
// In these cases instead of displaying the raster tiles, we display markers to
// indicate whether or not there is data in a given location. When the user
Expand Down Expand Up @@ -123,3 +122,61 @@ export async function requestQuickCache({
return quickCache.get(key);
}

type Fn = (...args: any[]) => any;

type ObjResMap<T> = {
[K in keyof T]: Res<T[K]>;
};

type Res<T> = T extends Fn
? T extends DatasetDatumFn<DatasetDatumReturnType>
? DatasetDatumReturnType
: never
: T extends any[]
? Res<T[number]>[]
: T extends object
? ObjResMap<T>
: T;

Comment on lines +125 to +140
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move to types.d.ts ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These types are only ever used for the resolveConfigFunctions function declaration and are not needed elsewhere so I think they can live with the declaration. However feel free to move them if you like

export function resolveConfigFunctions<T>(
datum: T,
bag: DatasetDatumFnResolverBag
): Res<T>;
export function resolveConfigFunctions<T extends any[]>(
datum: T,
bag: DatasetDatumFnResolverBag
): Res<T[number]>[];
export function resolveConfigFunctions(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I'm struggling to understand what this does. resolveConfigFunctions can call itself if datum is iterable, that I get. but then in other situations, it calls datum as a function? How is that related to the call in index.tsx line 220? What does bag mean exactly?

Sorry, might just be a case of Friday afternoon.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically resolves the functions in the dataset config and is needed to support this behavior.
The docs show some examples and explain the behavior. If it is not clear, we should improve the docs.

This was used in the past for the customization of the compare map message. Although it is a neat little power user functionality, not sure it is used (known/needed) a lot.

datum: any,
bag: DatasetDatumFnResolverBag
): any {
if (Array.isArray(datum)) {
return datum.map((v) => resolveConfigFunctions(v, bag));
}

if (datum != null && typeof datum === 'object') {
// Use for loop instead of reduce as it faster.
const ready = {};
for (const [k, v] of Object.entries(datum as object)) {
ready[k] = resolveConfigFunctions(v, bag);
}
return ready;
}

if (typeof datum === 'function') {
try {
return datum(bag);
} catch (error) {
/* eslint-disable-next-line no-console */
console.error(
'Failed to resolve function %s(%o) with error %s',
datum.name,
bag,
error.message
);
return null;
}
}

return datum;
}
16 changes: 6 additions & 10 deletions app/scripts/components/exploration/atoms/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,13 @@ export function useTimelineDatasetAtom(id: string) {
return datasetAtom as PrimitiveAtom<TimelineDataset>;
}

type Settings = TimelineDataset['settings'];

type TimelineDatasetSettingsReturn = [
(
prop: keyof TimelineDataset['settings']
) => TimelineDataset['settings'][keyof TimelineDataset['settings']],
(
prop: keyof TimelineDataset['settings'],
value:
| TimelineDataset['settings'][keyof TimelineDataset['settings']]
| ((
prev: TimelineDataset['settings'][keyof TimelineDataset['settings']]
) => TimelineDataset['settings'][keyof TimelineDataset['settings']])
<T extends keyof Settings>(prop: T) => Settings[T],
<T extends keyof Settings>(
prop: T,
value: Settings[T] | ((prev: Settings[T]) => Settings[T])
) => void
];

Expand Down
Loading
Loading