Skip to content

Commit

Permalink
refactor(frontend): tooltip components
Browse files Browse the repository at this point in the history
- refactor tooltip components to recieve a view layer and either a raster or vector target.
- simplify interaction group config and remove the `tooltipLayers` map.
  • Loading branch information
eatyourgreens committed Jul 1, 2024
1 parent 8d71116 commit 09bfc38
Show file tree
Hide file tree
Showing 13 changed files with 90 additions and 111 deletions.
15 changes: 6 additions & 9 deletions frontend/src/config/assets/AssetHoverDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import { FC } from 'react';

import { InteractionTarget, VectorTarget } from 'lib/data-map/types';
import { VectorTarget } from 'lib/data-map/types';
import { VectorHoverDescription } from 'map/tooltip/content/VectorHoverDescription';
import { ViewLayer } from 'lib/data-map/view-layers';

export const AssetHoverDescription: FC<{ hoveredObject: InteractionTarget<VectorTarget> }> = ({
hoveredObject,
export const AssetHoverDescription: FC<{ target: VectorTarget; viewLayer: ViewLayer }> = ({
target,
viewLayer,
}) => {
const {
viewLayer,
target: { feature },
} = hoveredObject;

return <VectorHoverDescription viewLayer={viewLayer} feature={feature} />;
return <VectorHoverDescription viewLayer={viewLayer} feature={target.feature} />;
};
44 changes: 18 additions & 26 deletions frontend/src/config/drought/DroughtHoverDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Typography } from '@mui/material';
import { DataItem } from 'details/features/detail-components';
import { InteractionTarget, VectorTarget } from 'lib/data-map/types';
import { VectorTarget } from 'lib/data-map/types';
import { FC, useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import {
Expand All @@ -10,15 +10,12 @@ import {
droughtRegionsFieldSpecState,
} from 'state/layers/modules/drought';
import { DataDescription } from 'map/tooltip/DataDescription';
import { ViewLayer } from 'lib/data-map/view-layers';

const DroughtRiskDescription: FC<{
hoveredObject: InteractionTarget<VectorTarget>;
}> = ({ hoveredObject }) => {
const {
viewLayer,
target: { feature },
} = hoveredObject;

target: VectorTarget;
viewLayer: ViewLayer;
}> = ({ target, viewLayer }) => {
const fieldSpec = useRecoilValue(droughtRegionsFieldSpecState);
const colorSpec = useRecoilValue(droughtRegionsColorSpecState);

Expand All @@ -34,20 +31,16 @@ const DroughtRiskDescription: FC<{
<>
<Typography variant="body2">Drought Risk</Typography>

<DataItem label="Region" value={feature.properties.HYDROLOGIC} />
<DataDescription viewLayer={viewLayer} feature={feature} colorMap={colorMap} />
<DataItem label="Region" value={target.feature.properties.HYDROLOGIC} />
<DataDescription viewLayer={viewLayer} feature={target.feature} colorMap={colorMap} />
</>
);
};

const DroughtOptionDescription: FC<{
hoveredObject: InteractionTarget<VectorTarget>;
}> = ({ hoveredObject }) => {
const {
viewLayer,
target: { feature },
} = hoveredObject;

target: VectorTarget;
viewLayer: ViewLayer;
}> = ({ target, viewLayer }) => {
const fieldSpec = useRecoilValue(droughtOptionsFieldSpecState);
const colorSpec = useRecoilValue(droughtOptionsColorSpecState);

Expand All @@ -63,21 +56,20 @@ const DroughtOptionDescription: FC<{
<>
<Typography variant="body2">Drought Adaptation Option</Typography>

<DataItem label="Name" value={feature.properties.project_name} />
<DataItem label="Type" value={feature.properties.project_type} />
<DataDescription viewLayer={viewLayer} feature={feature} colorMap={colorMap} />
<DataItem label="Name" value={target.feature.properties.project_name} />
<DataItem label="Type" value={target.feature.properties.project_type} />
<DataDescription viewLayer={viewLayer} feature={target.feature} colorMap={colorMap} />
</>
);
};

export const DroughtHoverDescription: FC<{
hoveredObject: InteractionTarget<VectorTarget>;
}> = ({ hoveredObject }) => {
const { viewLayer } = hoveredObject;

target: VectorTarget;
viewLayer: ViewLayer;
}> = ({ target, viewLayer }) => {
if (viewLayer.id === 'drought_risk') {
return <DroughtRiskDescription hoveredObject={hoveredObject} />;
return <DroughtRiskDescription target={target} viewLayer={viewLayer} />;
} else if (viewLayer.id === 'drought_options') {
return <DroughtOptionDescription hoveredObject={hoveredObject} />;
return <DroughtOptionDescription target={target} viewLayer={viewLayer} />;
}
};
10 changes: 5 additions & 5 deletions frontend/src/config/hazards/HazardHoverDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { FC } from 'react';

import { InteractionTarget, RasterTarget } from 'lib/data-map/types';
import { RasterTarget } from 'lib/data-map/types';
import { RasterHoverDescription } from 'map/tooltip/content/RasterHoverDescription';

import { HAZARDS_METADATA, HAZARD_COLOR_MAPS } from './metadata';
import { ViewLayer } from 'lib/data-map/view-layers';

export const HazardHoverDescription: FC<{ hoveredObject: InteractionTarget<RasterTarget> }> = ({
hoveredObject,
export const HazardHoverDescription: FC<{ target: RasterTarget; viewLayer: ViewLayer }> = ({
target,
viewLayer,
}) => {
const { target, viewLayer } = hoveredObject;

const { label, dataUnit } = HAZARDS_METADATA[viewLayer.id];
const { scheme, range } = HAZARD_COLOR_MAPS[viewLayer.id];
return (
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/config/hazards/hazard-view-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,8 @@ export function hazardViewLayer(hazardType: string, hazardParams: HazardParams):
viewLayer: this,
});
},
renderTooltip(hover: InteractionTarget<RasterTarget>) {
return createElement(HazardHoverDescription, {
hoveredObject: hover,
});
renderTooltip({ target, viewLayer }: InteractionTarget<RasterTarget>) {
return createElement(HazardHoverDescription, { target, viewLayer });
},
};
}
26 changes: 6 additions & 20 deletions frontend/src/config/interaction-groups.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,4 @@
import { FC } from 'react';
import {
InteractionGroupConfig,
InteractionTarget,
VectorTarget,
RasterTarget,
} from 'lib/data-map/types';
import { InteractionGroupConfig } from 'lib/data-map/types';

import { AssetHoverDescription } from './assets/AssetHoverDescription';
import { HazardHoverDescription } from './hazards/HazardHoverDescription';
Expand All @@ -21,6 +15,7 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
pickingRadius: 8,
pickMultiple: false,
usesAutoHighlight: true,
Component: AssetHoverDescription,
},
],
[
Expand All @@ -29,6 +24,7 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
id: 'hazards',
type: 'raster',
pickMultiple: true,
Component: HazardHoverDescription,
},
],
[
Expand All @@ -38,6 +34,7 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
type: 'vector',
pickingRadius: 8,
pickMultiple: false,
Component: RegionHoverDescription,
},
],
[
Expand All @@ -48,6 +45,7 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
pickingRadius: 8,
usesAutoHighlight: true,
pickMultiple: false,
Component: SolutionHoverDescription,
},
],
[
Expand All @@ -58,19 +56,7 @@ export const INTERACTION_GROUPS = new Map<string, InteractionGroupConfig>([
pickingRadius: 8,
usesAutoHighlight: true,
pickMultiple: false,
Component: DroughtHoverDescription,
},
],
]);

type MapDataLayer = InteractionTarget<VectorTarget | RasterTarget>;

export const tooltipLayers: Map<string, FC<{ hoveredObject: MapDataLayer }>> = new Map<
string,
FC<{ hoveredObject: MapDataLayer }>
>([
['assets', AssetHoverDescription],
['hazards', HazardHoverDescription],
['regions', RegionHoverDescription],
['solutions', SolutionHoverDescription],
['drought', DroughtHoverDescription],
]);
14 changes: 8 additions & 6 deletions frontend/src/config/regions/RegionHoverDescription.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
import { FC } from 'react';

import { REGIONS_METADATA } from './metadata';
import { InteractionTarget, VectorTarget } from 'lib/data-map/types';
import { VectorTarget } from 'lib/data-map/types';
import { useRecoilValue } from 'recoil';
import { showPopulationState } from 'state/regions';
import { DataItem } from 'details/features/detail-components';
import { ViewLayer } from 'lib/data-map/view-layers';

export const RegionHoverDescription: FC<{
hoveredObject: InteractionTarget<VectorTarget>;
}> = ({ hoveredObject }) => {
const metadata = REGIONS_METADATA[hoveredObject.viewLayer.params.regionLevel];
target: VectorTarget;
viewLayer: ViewLayer;
}> = ({ target, viewLayer }) => {
const metadata = REGIONS_METADATA[viewLayer.params.regionLevel];

const showPopulation = useRecoilValue(showPopulationState);

return (
<>
<DataItem
label={metadata.labelSingular}
value={hoveredObject.target.feature.properties[metadata.fieldName]}
value={target.feature.properties[metadata.fieldName]}
/>
{showPopulation && (
<DataItem
label="Population"
value={hoveredObject.target.feature.properties.population.toLocaleString()}
value={target.feature.properties.population.toLocaleString()}
/>
)}
</>
Expand Down
29 changes: 13 additions & 16 deletions frontend/src/config/solutions/SolutionHoverDescription.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { Typography } from '@mui/material';
import { VECTOR_COLOR_MAPS } from 'config/color-maps';
import { MARINE_HABITATS_LOOKUP } from 'config/solutions/domains';
import { DataItem } from 'details/features/detail-components';
import { InteractionTarget, VectorTarget } from 'lib/data-map/types';
import { VectorTarget } from 'lib/data-map/types';
import startCase from 'lodash/startCase';
import { FC } from 'react';
import { habitatColorMap } from 'state/layers/modules/marine';
import { landuseColorMap } from 'state/layers/modules/terrestrial';
import { DataDescription } from 'map/tooltip/DataDescription';
import { ColorBox } from 'map/tooltip/content/ColorBox';
import { ViewLayer } from 'lib/data-map/view-layers';

const slopeFieldSpec = {
fieldGroup: 'properties',
Expand All @@ -21,13 +22,9 @@ const elevationFieldSpec = {
};

export const SolutionHoverDescription: FC<{
hoveredObject: InteractionTarget<VectorTarget>;
}> = ({ hoveredObject }) => {
const {
viewLayer,
target: { feature },
} = hoveredObject;

target: VectorTarget;
viewLayer: ViewLayer;
}> = ({ target, viewLayer }) => {
return (
<>
<Typography variant="body2">{startCase(viewLayer.id)}</Typography>
Expand All @@ -36,16 +33,16 @@ export const SolutionHoverDescription: FC<{
<>
<DataItem
label="Cell ID"
value={feature.properties.cell_id}
value={target.feature.properties.cell_id}
maximumSignificantDigits={21}
/>
{/* not using DataDescription for Land Use because currently it only works for colorSpec-based color maps (not categorical) */}
<DataItem
label="Land Use"
value={
<>
<ColorBox color={landuseColorMap(feature.properties.landuse_desc)} />
{feature.properties.landuse_desc}
<ColorBox color={landuseColorMap(target.feature.properties.landuse_desc)} />
{target.feature.properties.landuse_desc}
</>
}
/>
Expand All @@ -54,15 +51,15 @@ export const SolutionHoverDescription: FC<{
fieldSpec: slopeFieldSpec,
colorSpec: VECTOR_COLOR_MAPS.terrestrialSlope,
}}
feature={feature}
feature={target.feature}
viewLayer={viewLayer}
/>
<DataDescription
colorMap={{
fieldSpec: elevationFieldSpec,
colorSpec: VECTOR_COLOR_MAPS.terrestrialElevation,
}}
feature={feature}
feature={target.feature}
viewLayer={viewLayer}
/>
</>
Expand All @@ -74,9 +71,9 @@ export const SolutionHoverDescription: FC<{
label="Habitat"
value={
<>
<ColorBox color={habitatColorMap(feature.properties.habitat)} />
{feature.properties.habitat
? MARINE_HABITATS_LOOKUP[feature.properties.habitat]
<ColorBox color={habitatColorMap(target.feature.properties.habitat)} />
{target.feature.properties.habitat
? MARINE_HABITATS_LOOKUP[target.feature.properties.habitat]
: 'Buffer Zone'}
</>
}
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/lib/data-map/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export interface InteractionGroupConfig {
pickingRadius?: number;
pickMultiple?: boolean;
usesAutoHighlight?: boolean;
Component: React.ComponentType<{
target: RasterTarget | VectorTarget;
viewLayer: ViewLayer;
}>;
}

export interface InteractionTarget<T> {
Expand All @@ -27,3 +31,5 @@ export interface RasterTarget {
export interface VectorTarget {
feature: any;
}

export type InteractionLayer = InteractionTarget<VectorTarget> | InteractionTarget<RasterTarget>;
2 changes: 1 addition & 1 deletion frontend/src/lib/data-map/view-layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export interface ViewLayer {
spatialType?: string;
interactionGroup?: string;
renderLegend?: () => JSX.Element;
renderTooltip?: (hoveredObject: InteractionTarget<RasterTarget>) => JSX.Element;
renderTooltip?: ({ target, viewLayer }: InteractionTarget<RasterTarget>) => JSX.Element;
}

export function viewOnlyLayer(id, fn): ViewLayer {
Expand Down
9 changes: 1 addition & 8 deletions frontend/src/lib/state/interactions/interaction-state.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import forEach from 'lodash/forEach';
import { atom, atomFamily, selector } from 'recoil';

import { InteractionTarget, RasterTarget, VectorTarget } from 'lib/data-map/types';
import { InteractionLayer } from 'lib/data-map/types';
import { isReset } from 'lib/recoil/is-reset';

type InteractionLayer = InteractionTarget<VectorTarget> | InteractionTarget<RasterTarget>;
type IT = InteractionLayer | InteractionLayer[];

export function hasHover(target: IT) {
Expand All @@ -19,12 +18,6 @@ export const hoverState = atomFamily<IT, string>({
default: null,
});

type LayerHoverState = {
isHovered: boolean;
target: IT;
Component: React.ComponentType<{ hoveredObject: InteractionLayer }>;
};

export const hoverPositionState = atom({
key: 'hoverPosition',
default: null,
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/lib/state/interactions/use-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ import { useCallback, useEffect, useMemo } from 'react';
import { useRecoilCallback, useSetRecoilState } from 'recoil';

import { ViewLayer } from 'lib/data-map/view-layers';
import { InteractionGroupConfig, InteractionStyle, InteractionTarget, RasterTarget, VectorTarget } from 'lib/data-map/types';
import {
InteractionGroupConfig,
InteractionStyle,
InteractionTarget,
RasterTarget,
VectorTarget,
} from 'lib/data-map/types';

import {
hoverState,
Expand Down
Loading

0 comments on commit 09bfc38

Please sign in to comment.