Skip to content

Commit

Permalink
refactor schema to make layers props of prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
buckhalt committed Dec 16, 2024
1 parent 1563e06 commit 38d657d
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 96 deletions.
61 changes: 35 additions & 26 deletions lib/interviewer/containers/Interfaces/Geospatial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ export default function GeospatialInterface({
const { prompts } = stage;
const { promptIndex } = usePrompts();
const currentPrompt = prompts[promptIndex];
const { center, token: tokenId, layers, initialZoom } = stage.mapOptions;
const filterLayer = layers.find((layer) => layer.filter);
const { center, token: tokenId, initialZoom } = stage.mapOptions;
const layers = currentPrompt?.layers;
const selectionLayer = layers.find((layer) => layer.type === 'fill');

const getAssetUrl = useSelector(getAssetUrlFromId);

Expand All @@ -103,10 +104,14 @@ export default function GeospatialInterface({
}, [center, initialZoom]);

const handleResetSelection = useCallback(() => {
if (filterLayer && mapRef.current) {
mapRef.current.setFilter(filterLayer.id, ['==', filterLayer.filter, '']);
if (selectionLayer && mapRef.current) {
mapRef.current.setFilter(selectionLayer.id, [
'==',
selectionLayer.filter,
'',
]);
}
}, [filterLayer]);
}, [selectionLayer]);

const getNodeIndex = useCallback(() => activeIndex - 1, [activeIndex]);
const stageNodes = usePropSelector(getNetworkNodesForType, {
Expand Down Expand Up @@ -219,24 +224,24 @@ export default function GeospatialInterface({
'line-width': layer.width! ?? 1,
},
});
} else if (layer.type === 'fill' && !layer.filter) {
} else if (layer.type === 'fill') {
// add the fill layer that can be selected
mapRef.current?.addLayer({
id: layer.id,
id: 'layerToSelect',
type: 'fill',
source: 'geojson-data',
paint: {
'fill-color': color,
'fill-opacity': layer.opacity,
'fill-color': 'black', // must have a color to be used even when transparent
'fill-opacity': 0,
},
});
} else if (layer.type === 'fill' && layer.filter) {
mapRef.current?.addLayer({
id: layer.id,
type: 'fill',
source: 'geojson-data',
paint: {
'fill-color': color,
'fill-opacity': layer.opacity,
'fill-opacity': layer.opacity ?? 0.5,
},
filter: ['==', layer.filter, ''],
});
Expand All @@ -263,31 +268,33 @@ export default function GeospatialInterface({

// handle map selections
useEffect(() => {
if (!isMapLoaded || !currentPrompt || !filterLayer || !accessToken) return;
if (!isMapLoaded || !currentPrompt || !selectionLayer || !accessToken)
return;

const mapInstance = mapRef.current;
if (!mapInstance) return;

// Set initial filter if node has a value
const initialFilterValue =
const initialSelectionValue =
currentPrompt?.variable && stageNodes[activeIndex]?.attributes
? (stageNodes[activeIndex].attributes as Record<string, unknown>)[
currentPrompt.variable
]
: undefined;

if (initialFilterValue) {
mapInstance.setFilter(filterLayer.id, [
if (initialSelectionValue) {
mapInstance.setFilter(selectionLayer.id, [
'==',
filterLayer.filter,
initialFilterValue,
selectionLayer.filter,
initialSelectionValue,
]);
}

const handleMapClick = (e: MapMouseEvent) => {
if (!e?.features?.length) return;
const feature = e.features[0];
const propToSelect = currentPrompt.mapVariable;
const propToSelect = selectionLayer.filter;

const selected = feature?.properties
? feature.properties[propToSelect]
: null;
Expand All @@ -300,28 +307,30 @@ export default function GeospatialInterface({
},
);

mapInstance.setFilter(filterLayer.id, [
'==',
filterLayer.filter,
selected,
]);
if (selectionLayer && mapInstance) {
mapInstance.setFilter(selectionLayer.id, [
'==',
selectionLayer.filter,
selected,
]);
}
};

// add click event listener to map
mapInstance.on('click', currentPrompt.layer, handleMapClick);
mapInstance.on('click', 'layerToSelect', handleMapClick);

// cleanup
return () => {
mapInstance.off('click', currentPrompt.layer, handleMapClick);
mapInstance.off('click', 'layerToSelect', handleMapClick);
};
}, [
isMapLoaded,
currentPrompt,
filterLayer,
stageNodes,
activeIndex,
updateNode,
accessToken,
selectionLayer,
]);

if (!accessToken) {
Expand Down
28 changes: 13 additions & 15 deletions lib/protocol-validation/schemas/src/8.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -473,25 +473,23 @@ const geospatialStage = baseStageSchema.extend({
center: z.tuple([z.number(), z.number()]),
token: z.string(),
initialZoom: z.number().int(),
layers: z.array(
z
.object({
id: z.string(),
data: z.string(),
type: z.enum(['line', 'fill']),
color: z.string(),
opacity: z.number().optional(),
filter: z.string().optional(),
width: z.number().optional(),
})
.strict(),
),
}),
prompts: z
.array(
promptSchema.extend({
layer: z.string(),
mapVariable: z.string(),
layers: z.array(
z
.object({
id: z.string(),
data: z.string(),
type: z.enum(['line', 'fill']),
color: z.string(),
opacity: z.number().optional(),
filter: z.string().optional(),
width: z.number().optional(),
})
.strict(),
),
variable: z.string(),
}),
)
Expand Down
106 changes: 51 additions & 55 deletions lib/test-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,45 +30,51 @@ export const protocol: Protocol = {
center: [-87.6298, 41.8781],
token: 'asset3',
initialZoom: 12,
layers: [
{
id: 'censusTractsOutlineLayer',
data: 'asset1',
type: 'line',
color: 'primary-color-seq-1',
width: 1,
},
{
id: 'censusTractsFillLayer', // a fill layer is needed to have something to select
data: 'asset1',
type: 'fill',
color: 'primary-color-seq-1',
opacity: 0,
},
{
id: 'selectedCensusTract',
data: 'asset1',
type: 'fill',
color: 'primary-color-seq-1',
opacity: 0.5,
filter: 'namelsad10',
},
],
},
prompts: [
{
id: 'prompt1',
mapVariable: 'namelsad10', // variable from geojson data
text: 'Select the census tract this person lives in',
variable: 'e0b5901f-bf78-4538-882b-c4dd955603d5',
layer: 'censusTractsFillLayer',
layers: [
{
id: 'outline',
data: 'asset1',
type: 'line',
color: 'primary-color-seq-1',
width: 1,
},
{
id: 'selection',
data: 'asset1',
type: 'fill',
color: 'primary-color-seq-2',
opacity: 0.5,
filter: 'namelsad10', // variable from geojson data
},
],
},
{
id: 'prompt2',
mapVariable: 'namelsad10', // variable from geojson data
text: 'Select the census tract this person works in',
variable: '1de0750b-b718-44bd-95d6-07b85b03bb76',
layer: 'censusTractsFillLayer',
layers: [
{
id: 'outline',
data: 'asset1',
type: 'line',
color: 'primary-color-seq-3',
width: 1,
},
{
id: 'selection',
data: 'asset1',
type: 'fill',
color: 'primary-color-seq-3',
opacity: 0.5,
filter: 'namelsad10', // variable from geojson data
},
],
},
],
},
Expand All @@ -84,39 +90,29 @@ export const protocol: Protocol = {
center: [-74.006, 40.7128],
initialZoom: 14,
token: 'asset3',
layers: [
{
id: 'censusTractsOutlineLayer',
data: 'asset2',
type: 'line',
color: 'primary-color-seq-4',
width: 1,
},
// needed to have something to select
{
id: 'censusTractsFillLayer',
data: 'asset2',
type: 'fill',
color: 'primary-color-seq-4',
opacity: 0,
},
{
id: 'selectedCensusTract',
data: 'asset2',
type: 'fill',
color: 'primary-color-seq-4',
filter: 'NTAName',
opacity: 0.5,
},
],
},
prompts: [
{
id: 'censusTractPrompt',
mapVariable: 'NTAName', // variable from geojson data
text: 'Select the neighborhood this person lives in',
variable: '1de0750b-b718-44bd-95d6-07b85b03bb76',
layer: 'censusTractsFillLayer',
layers: [
{
id: 'outline',
data: 'asset2',
type: 'line',
color: 'primary-color-seq-4',
width: 1,
},
{
id: 'selection',
data: 'asset2',
type: 'fill',
color: 'primary-color-seq-4',
opacity: 0.5,
filter: 'NTAName',
},
],
},
],
},
Expand Down

0 comments on commit 38d657d

Please sign in to comment.