refactor: point view
This commit is contained in:
@@ -2,10 +2,8 @@ import maplibregl from "maplibre-gl";
|
||||
import { BACKGROUND_LAYER_OPTIONS, BackgroundLayerVisibility } from "@/uhm/lib/map/styles/backgroundLayers";
|
||||
import { Feature, FeatureCollection, Geometry } from "@/uhm/lib/editor/state/useEditorState";
|
||||
import {
|
||||
DEFAULT_POINT_ICON_ID,
|
||||
FEATURE_STATE_SOURCE_IDS,
|
||||
PATH_ARROW_ICON_ID,
|
||||
POINT_ICON_URL,
|
||||
RASTER_BASE_INSERT_BEFORE_LAYER_ID,
|
||||
RASTER_BASE_LAYER_ID,
|
||||
RASTER_BASE_SOURCE_ID,
|
||||
@@ -188,6 +186,19 @@ export function splitDraftFeatures(fc: FeatureCollection) {
|
||||
return { polygons, points };
|
||||
}
|
||||
|
||||
export function decoratePointFeaturesWithLabels(fc: FeatureCollection): FeatureCollection {
|
||||
return {
|
||||
...fc,
|
||||
features: fc.features.map((feature) => ({
|
||||
...feature,
|
||||
properties: {
|
||||
...feature.properties,
|
||||
point_label: getSingleEntityPointLabel(feature),
|
||||
},
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export function setSelectedFeatureState(
|
||||
map: maplibregl.Map,
|
||||
id: string | number | null,
|
||||
@@ -520,47 +531,6 @@ export function createPathArrowImageData(): ImageData | null {
|
||||
return ctx.getImageData(0, 0, size, size);
|
||||
}
|
||||
|
||||
export function addPointSymbolLayer(map: maplibregl.Map) {
|
||||
void ensurePointAssetIcon(map).then((hasPointIcon) => {
|
||||
try {
|
||||
if (!hasPointIcon || !map.getSource("places") || map.getLayer("places-symbol")) return;
|
||||
|
||||
map.addLayer({
|
||||
id: "places-symbol",
|
||||
type: "symbol",
|
||||
source: "places",
|
||||
layout: {
|
||||
"icon-image": DEFAULT_POINT_ICON_ID,
|
||||
"icon-size": 0.06,
|
||||
"icon-anchor": "center",
|
||||
"icon-allow-overlap": true,
|
||||
},
|
||||
});
|
||||
|
||||
if (map.getLayer("places-circle")) {
|
||||
map.setLayoutProperty("places-circle", "visibility", "none");
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn("Add point symbol layer skipped", err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function ensurePointAssetIcon(map: maplibregl.Map): Promise<boolean> {
|
||||
if (map.hasImage(DEFAULT_POINT_ICON_ID)) return true;
|
||||
|
||||
try {
|
||||
const image = await map.loadImage(POINT_ICON_URL);
|
||||
if (!map.hasImage(DEFAULT_POINT_ICON_ID)) {
|
||||
map.addImage(DEFAULT_POINT_ICON_ID, image.data);
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Failed to load point icon asset: ${POINT_ICON_URL}`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function buildTypeMatchExpression(
|
||||
valueByType: Record<string, string | number | boolean>,
|
||||
fallback: string | number | boolean
|
||||
@@ -588,6 +558,29 @@ export function roundZoom(value: number): number {
|
||||
return Math.round(value * 10) / 10;
|
||||
}
|
||||
|
||||
function getSingleEntityPointLabel(feature: Feature): string | null {
|
||||
const rawEntityIds = Array.isArray(feature.properties.entity_ids)
|
||||
? feature.properties.entity_ids
|
||||
: (typeof feature.properties.entity_id === "string" && feature.properties.entity_id.trim().length > 0
|
||||
? [feature.properties.entity_id]
|
||||
: []);
|
||||
|
||||
const entityIds = Array.from(new Set(
|
||||
rawEntityIds
|
||||
.filter((id): id is string => typeof id === "string")
|
||||
.map((id) => id.trim())
|
||||
.filter((id) => id.length > 0)
|
||||
));
|
||||
|
||||
if (entityIds.length !== 1) return null;
|
||||
|
||||
const name = typeof feature.properties.entity_name === "string"
|
||||
? feature.properties.entity_name.trim()
|
||||
: "";
|
||||
|
||||
return name.length ? name : null;
|
||||
}
|
||||
|
||||
export function buildClientFeatureId(): string {
|
||||
return newId();
|
||||
}
|
||||
|
||||
@@ -11,9 +11,8 @@ import {
|
||||
} from "@/uhm/lib/map/styles/style";
|
||||
import { EMPTY_FEATURE_COLLECTION } from "@/uhm/lib/map/geo/constants";
|
||||
import { PATH_ARROW_ICON_ID, PATH_ARROW_SOURCE_ID } from "@/uhm/lib/map/constants";
|
||||
import { getAllGeotypeLayers } from "@/uhm/lib/map/styles/geotypes";
|
||||
import { ensurePointGeotypeIcons, getAllGeotypeLayers } from "@/uhm/lib/map/styles/geotypes";
|
||||
import {
|
||||
addPointSymbolLayer,
|
||||
applyBackgroundLayerVisibility,
|
||||
buildTypeMatchExpression,
|
||||
ensurePathArrowIcon,
|
||||
@@ -326,7 +325,8 @@ export function setupMapLayers(
|
||||
promoteId: "id",
|
||||
});
|
||||
|
||||
|
||||
ensurePointGeotypeIcons(map);
|
||||
|
||||
const geotypeLayers = getAllGeotypeLayers("countries", PATH_ARROW_SOURCE_ID, "places");
|
||||
for (const layer of geotypeLayers) {
|
||||
map.addLayer(layer);
|
||||
@@ -411,7 +411,5 @@ export function setupMapLayers(
|
||||
"circle-opacity": 1,
|
||||
},
|
||||
});
|
||||
|
||||
addPointSymbolLayer(map);
|
||||
applyHighlightToMap(highlightFeatures || EMPTY_FEATURE_COLLECTION);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { FEATURE_STATE_SOURCE_IDS, PATH_ARROW_SOURCE_ID } from "@/uhm/lib/map/co
|
||||
import {
|
||||
applyBackgroundLayerVisibility,
|
||||
buildPathArrowFeatureCollection,
|
||||
decoratePointFeaturesWithLabels,
|
||||
filterDraftByBinding,
|
||||
filterDraftByGeometryVisibility,
|
||||
fitMapToFeatureCollection,
|
||||
@@ -28,7 +29,7 @@ type UseMapSyncProps = {
|
||||
focusRequestKey?: string | number | null;
|
||||
focusPadding?: number | maplibregl.PaddingOptions;
|
||||
allowGeometryEditing: boolean;
|
||||
editingEngineRef: React.MutableRefObject<any>;
|
||||
editingEngineRef: React.MutableRefObject<unknown>;
|
||||
geolocationCenteredRef: React.MutableRefObject<boolean>;
|
||||
};
|
||||
|
||||
@@ -97,10 +98,11 @@ export function useMapSync({
|
||||
: fc;
|
||||
const visibleDraft = filterDraftByGeometryVisibility(visibleDraftRaw, geometryVisibilityRef.current);
|
||||
const { polygons, points } = splitDraftFeatures(visibleDraft);
|
||||
const labeledPoints = decoratePointFeaturesWithLabels(points);
|
||||
const pathArrowShapes = buildPathArrowFeatureCollection(visibleDraft);
|
||||
|
||||
countriesSource.setData(polygons);
|
||||
placesSource.setData(points);
|
||||
placesSource.setData(labeledPoints);
|
||||
(map.getSource(PATH_ARROW_SOURCE_ID) as maplibregl.GeoJSONSource | undefined)?.setData(pathArrowShapes);
|
||||
|
||||
const currentSelectedIds = selectedFeatureIdsRef.current;
|
||||
|
||||
Reference in New Issue
Block a user