Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2e1eabf
CDP #428 - Updating Typesense utils to accept hash map of geometry data
dleadbetter Jan 21, 2026
e96ee50
CDP #428 - Updating Typesense utils to accept hash map of geometry data
dleadbetter Jan 21, 2026
d2d96d3
CDP #428 - Switching logic for retrieving geometry data
dleadbetter Jan 21, 2026
366b68d
CDP #428 - Adding check for geometryObject
dleadbetter Jan 21, 2026
cfd0ff2
CDP #428 - Updating to truncate coordinate precision
dleadbetter Jan 21, 2026
5b197b2
CDP #428 - Adding experimental getFeatures function to Typesense utils
dleadbetter Jan 22, 2026
39dc33e
CDP #428 - Adding experimental createFeatureCollection function
dleadbetter Jan 22, 2026
192bca3
CDP #428 - Updating Typesense utils getFeatures function to remove pl…
dleadbetter Jan 22, 2026
25a76af
CDP #428 - Updating getFeatures function to remove records from "item…
dleadbetter Jan 22, 2026
91b79fd
CDP #428 - Updating to only include items in the feature if not alrea…
dleadbetter Jan 22, 2026
aa4b6b1
CDP #428 - Adding check for record before getting items
dleadbetter Jan 22, 2026
e3c5d54
CDP #428 - Updating Typesense util trimResult function to be more agg…
dleadbetter Jan 22, 2026
714ab7a
CDP #428 - Updating Typesense utils getFeatures function to include a…
dleadbetter Jan 23, 2026
9ceeecb
CDP #428 - Adding visible prop to LocationMarkers
dleadbetter Jan 23, 2026
2507233
CDP #428 - Adding GeoJSONLayerTest component to test Peripleo bug
dleadbetter Jan 23, 2026
ce36631
CDP #428 - Updating Peripleo version
dleadbetter Jan 23, 2026
4864a9e
CDP #428 - Removing Zoom component from stories
dleadbetter Jan 23, 2026
cf07b3c
CDP #428 - Fixing typos in GeoJSONLayer Test
dleadbetter Jan 23, 2026
6836841
CDP #428 - Updating Typesense utils getFeatures to expect geometries …
dleadbetter Jan 23, 2026
68e5d16
CDP #428 - Updating Typesense utils to not truncate empty geometries
dleadbetter Jan 23, 2026
c441334
CDP #428 - Adding visibility prop to GeoJSONLayerTest
dleadbetter Jan 23, 2026
f437ea3
CDP #428 - Adding layerId property to features
dleadbetter Jan 27, 2026
3a0e474
CDP #428 - Adding layerId property to features
dleadbetter Jan 27, 2026
c5b8ed8
CDP #428 - Refactoring utility classes
dleadbetter Jan 28, 2026
cabdfda
CDP #428 - Making getFeatures options argument optional
dleadbetter Jan 28, 2026
573500c
CDP #428 - Updating toFeature function to truncate geometry data, rat…
dleadbetter Jan 28, 2026
d5507da
CDP #428 - Fixing an issue with place geometries in getFeatures
dleadbetter Jan 29, 2026
a91f06e
CDP #428 - Removing GeoJSONLayerTest component; Updating Peripleo pac…
dleadbetter Jan 29, 2026
4514180
CDP #428 - Reverting beta package versions
dleadbetter Jan 29, 2026
e370d4f
CDP #428 - Updating Storybook Peripleo dependency to the latest version
dleadbetter Jan 29, 2026
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
4 changes: 2 additions & 2 deletions packages/core-data/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"peerDependencies": {
"@performant-software/geospatial": "^3.1.12",
"@performant-software/shared-components": "^3.1.12",
"@peripleo/maplibre": "^0.8.7",
"@peripleo/peripleo": "^0.8.7",
"@peripleo/maplibre": "^0.8.9",
"@peripleo/peripleo": "^0.8.9",
"react": ">= 16.13.1 < 19.0.0",
"react-dom": ">= 16.13.1 < 19.0.0",
"tailwindcss": "^4.1.4"
Expand Down
123 changes: 120 additions & 3 deletions packages/core-data/src/utils/Typesense.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
// @flow

import { ObjectJs as ObjectUtils } from '@performant-software/shared-components';
import { feature, featureCollection } from '@turf/turf';
import { Map as MapUtils } from '@performant-software/geospatial';
import { feature, featureCollection, truncate } from '@turf/turf';
import { history } from 'instantsearch.js/es/lib/routers';
import TypesenseInstantsearchAdapter from 'typesense-instantsearch-adapter';
import _ from 'underscore';
import type { Event as EventType } from '../types/Event';
import type { TypesenseSearchResult } from '../types/typesense/SearchResult';

type Options = {
geometries: {
[uuid: string]: any
},
type?: string
};

Expand Down Expand Up @@ -163,6 +167,31 @@ const getFieldId = (attribute: string) => {
return value;
};

/**
* Returns the geometry object for the passed place/path.
*
* @param place
* @param path
*
* @returns {*}
*/
const getGeometry = (place, path) => {
return _.get(place, path);
};

/**
* Returns the geometry URL for the passed place.
*
* @param place
* @param hash
*
* @returns {*}
*/
const getGeometryUrl = (place, hash) => {
const object = hash[place?.uuid];
return object?.url;
};

/**
* Takes a <relationship-uuid>.<field-uuid>_facet formatted attribute and returns the parsed relationship UUID.
*
Expand All @@ -186,6 +215,8 @@ const getRelationshipId = (attribute: string) => {
* @param geometry
*
* @returns {Feature<*, {ccode: [], record_id: *, names: *, name: *, id: *, title: *, type: *, uuid: *, items: [*]}>}
*
* @deprecated
*/
const toFeature = (record: any, item: any, geometry: any) => {
const properties = {
Expand All @@ -197,11 +228,19 @@ const toFeature = (record: any, item: any, geometry: any) => {
name: record.name,
names: record.names?.map((toponym: string) => ({ toponym })),
type: record.type,
items: [item]
items: [item],
url: record.url,
layerId: record.layerId
};

const id = parseInt(record.record_id, 10);
return feature(geometry, properties, { id });
let data = feature(geometry, properties, { id });

if (geometry) {
data = truncate(data, { precision: 3, coordinates: 2 });
}

return data;
};

/**
Expand All @@ -212,6 +251,8 @@ const toFeature = (record: any, item: any, geometry: any) => {
* @param options
*
* @returns {FeatureCollection<Geometry, Properties>}
*
* @deprecated
*/
const toFeatureCollection = (results: Array<any>, path: string, options: Options = {}) => {
const features = [];
Expand Down Expand Up @@ -265,11 +306,87 @@ const toFeatureCollection = (results: Array<any>, path: string, options: Options
return featureCollection(features);
};

/**
* Returns a set of GeoJSON features for the passed results.
*
* @param features
* @param results
* @param path
* @param options
*
* @returns {*}
*/
const getFeatures = (features, results, path, options = {}) => {
const newFeatures = [...features];

const objectPath = path.substring(0, path.lastIndexOf(ATTRIBUTE_DELIMITER));
const geometryPath = path.substring(path.lastIndexOf(ATTRIBUTE_DELIMITER) + 1, path.length);

const placeIds = [];
const recordIds = [];

_.each(results, (result) => {
recordIds.push(result.uuid);

const places = _.isEmpty(objectPath) ? [result] : ObjectUtils.getNestedValue(result, objectPath);

_.each(places, (place) => {
placeIds.push(place.uuid);

let geometry;
let geometryUrl;
let layerId;

if (options.geometries) {
geometryUrl = getGeometryUrl(place, options.geometries);
} else {
geometry = getGeometry(place, geometryPath);
}

const include = geometryUrl || (geometry && (!options.type || geometry.type === options.type));

if (include) {
const record = _.find(newFeatures, (f) => f.properties?.uuid === place.uuid);
const trimmedResult = trimResult(result, objectPath);

if (record) {
const item = _.find(record.properties?.items, (item) => item.uuid === trimmedResult.uuid);

if (!item) {
record.properties?.items.push(trimmedResult);
}
} else {
newFeatures.push(MapUtils.toFeature({ ...place, layerId, url: geometryUrl }, trimmedResult, geometry));
}
}
});
});

return _.map(newFeatures, (feature) => ({
...feature,
properties: {
...feature.properties,
visible: placeIds.includes(feature.properties.uuid),
items: _.filter(feature.properties.items, (item) => recordIds.includes(item.uuid))
}
}));
};

/**
* Trims the Typesense document to only include data needed for map visualizations.
*
* @param result
*
* @returns {*}
*/
const trimResult = (result) => _.pick(result, 'id', 'uuid', 'record_id', 'name', 'names');

export default {
createCachedHits,
createRouting,
createTypesenseAdapter,
getDate,
getFeatures,
getFieldId,
getRelationshipId,
toFeature,
Expand Down
2 changes: 1 addition & 1 deletion packages/geospatial/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"underscore": "^1.13.7"
},
"peerDependencies": {
"@peripleo/maplibre": "^0.8.7",
"@peripleo/maplibre": "^0.8.9",
"react": ">= 16.13.1 < 19.0.0",
"react-dom": ">= 16.13.1 < 19.0.0"
},
Expand Down
8 changes: 7 additions & 1 deletion packages/geospatial/src/components/LocationMarkers.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ type Props = {
/**
* GeoJSON layer stroke style
*/
strokeStyle?: { [key: string]: any }
strokeStyle?: { [key: string]: any },

/**
* If true, the layer will be visible on the map.
*/
visible?: boolean
};

const DEFAULT_BUFFER = 2;
Expand Down Expand Up @@ -141,6 +146,7 @@ const LocationMarkers = (props: Props) => {
interactive={props.interactive}
strokeStyle={props.strokeStyle}
pointStyle={props.pointStyle}
visible={props.visible}
/>
</>
);
Expand Down
53 changes: 52 additions & 1 deletion packages/geospatial/src/utils/Map.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

import { WarpedMapLayer } from '@allmaps/maplibre';
import { bbox, bboxPolygon, buffer } from '@turf/turf';
import { bbox, bboxPolygon, buffer, feature, featureCollection, truncate } from '@turf/turf';
import _ from 'underscore';

const MIN_LATITUDE = -90;
Expand Down Expand Up @@ -73,6 +73,55 @@ const getBoundingBox = (data, bufferDistance = null) => {
*/
const removeLayer = (map, layerId) => map && map.removeLayer(layerId);

/**
* Wraps the passed record in a feature.
*
* @param record
* @param item
* @param geometry
*
* @returns {Feature<Geometry, {
* id: *,
* ccode: [],
* title: *,
* uuid: *,
* record_id: *,
* name: *,
* names: *,
* type: *,
* items: [*],
* url: *
* }>}
*/
const toFeature = (record: any, item: any, geometry: any) => {
const properties = {
id: record.record_id,
ccode: [],
title: record.name,
uuid: record.uuid,
record_id: record.record_id,
name: record.name,
names: record.names?.map((toponym: string) => ({ toponym })),
type: record.type,
items: [item],
url: record.url
};

const id = parseInt(record.record_id, 10);
const data = geometry ? truncate(geometry, { precision: 3, coordinates: 2 }) : geometry;

return feature(data, properties, { id });
};

/**
* Returns a feature collection for the passed set of features.
*
* @param features
*
* @returns {FeatureCollection<Geometry, GeoJsonProperties>}
*/
const toFeatureCollection = (features: Array<any>) => featureCollection(features);

/**
* Validates that the passed bounding box contains finite coordinates.
*
Expand Down Expand Up @@ -108,6 +157,8 @@ export default {
addGeoreferenceLayer,
getBoundingBox,
removeLayer,
toFeature,
toFeatureCollection,
validateBoundingBox,
validateCoordinates
};
4 changes: 2 additions & 2 deletions packages/storybook/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
"@bunchtogether/vite-plugin-flow": "^1.0.2",
"@faker-js/faker": "^8.0.2",
"@headlessui/react": "^1.7.18",
"@peripleo/maplibre": "^0.4.2",
"@peripleo/peripleo": "^0.4.2",
"@peripleo/maplibre": "^0.8.9",
"@peripleo/peripleo": "^0.8.9",
"@storybook/addon-a11y": "9.0.17",
"@storybook/addon-docs": "9.0.17",
"@storybook/addon-links": "9.0.17",
Expand Down
9 changes: 2 additions & 7 deletions packages/storybook/src/core-data/EventDetails.stories.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// @flow

import { faker } from '@faker-js/faker';
import { Map, Zoom } from '@peripleo/maplibre';
import { Controls, Peripleo } from '@peripleo/peripleo';
import { Map } from '@peripleo/maplibre';
import { Peripleo } from '@peripleo/peripleo';
import { action } from 'storybook/actions';
import React from 'react';
import _ from 'underscore';
Expand Down Expand Up @@ -48,11 +48,6 @@ export const RelatedRecords = withCoreDataContextProvider(() => {
<Map
style={mapStyle}
>
<Controls
position='topright'
>
<Zoom />
</Controls>
<div
style={{
width: '100%',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

import { Map, Zoom } from '@peripleo/maplibre';
import { Controls, Peripleo } from '@peripleo/peripleo';
import { Map } from '@peripleo/maplibre';
import { Peripleo } from '@peripleo/peripleo';
import React from 'react';
import LocationMarkers from '../../../geospatial/src/components/LocationMarkers';
import mapStyle from '../data/MapStyles.json';
Expand All @@ -18,11 +18,6 @@ export const Default = () => (
<Map
style={mapStyle}
>
<Controls
position='topright'
>
<Zoom />
</Controls>
<div
style={{
width: '100%',
Expand Down
19 changes: 2 additions & 17 deletions packages/storybook/src/core-data/PlaceMarkers.stories.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow

import { Map, Zoom } from '@peripleo/maplibre';
import { Controls, Peripleo } from '@peripleo/peripleo';
import { Map } from '@peripleo/maplibre';
import { Peripleo } from '@peripleo/peripleo';
import React from 'react';
import _ from 'underscore';
import mapStyle from '../data/MapStyles.json';
Expand All @@ -17,11 +17,6 @@ export const Default = () => (
<Map
style={mapStyle}
>
<Controls
position='topright'
>
<Zoom />
</Controls>
<div
style={{
width: '100%',
Expand All @@ -43,11 +38,6 @@ export const MultiplePlaces = () => (
<Map
style={mapStyle}
>
<Controls
position='topright'
>
<Zoom />
</Controls>
<div
style={{
width: '100%',
Expand All @@ -67,11 +57,6 @@ export const LargerBuffer = () => (
<Map
style={mapStyle}
>
<Controls
position='topright'
>
<Zoom />
</Controls>
<div
style={{
width: '100%',
Expand Down
Loading