feat: initialize drainage network frontend
This commit is contained in:
@@ -0,0 +1,291 @@
|
||||
import type {
|
||||
FilterSpecification,
|
||||
GeoJSONSource,
|
||||
GeoJSONSourceSpecification,
|
||||
StyleSpecification
|
||||
} from "maplibre-gl";
|
||||
import type { FeatureCollection, Geometry, LineString, Point, Polygon } from "geojson";
|
||||
import { createCircleCoordinates } from "./geo";
|
||||
|
||||
export const DRAWING_SOURCE_IDS = {
|
||||
features: "workbench-drawing-features",
|
||||
draft: "workbench-drawing-draft"
|
||||
} as const;
|
||||
|
||||
export const DRAWING_INTERACTIVE_LAYER_IDS = [
|
||||
"workbench-drawing-selected-polygon-outline",
|
||||
"workbench-drawing-selected-line",
|
||||
"workbench-drawing-selected-point",
|
||||
"workbench-drawing-polygon-fill",
|
||||
"workbench-drawing-polygon-outline",
|
||||
"workbench-drawing-line",
|
||||
"workbench-drawing-point"
|
||||
];
|
||||
|
||||
export type DrawingFeatureProperties = {
|
||||
id: string;
|
||||
label: string;
|
||||
kind: "point" | "line" | "polygon" | "circle";
|
||||
createdAt: string;
|
||||
};
|
||||
|
||||
export type DrawingFeatureCollection = FeatureCollection<Geometry, DrawingFeatureProperties>;
|
||||
|
||||
export const emptyDrawingFeatureCollection: DrawingFeatureCollection = {
|
||||
type: "FeatureCollection",
|
||||
features: []
|
||||
};
|
||||
|
||||
export const drawingSources = {
|
||||
features: {
|
||||
type: "geojson",
|
||||
data: emptyDrawingFeatureCollection
|
||||
} satisfies GeoJSONSourceSpecification,
|
||||
draft: {
|
||||
type: "geojson",
|
||||
data: emptyDrawingFeatureCollection
|
||||
} satisfies GeoJSONSourceSpecification
|
||||
};
|
||||
|
||||
export const drawingLayers: StyleSpecification["layers"] = [
|
||||
{
|
||||
id: "workbench-drawing-polygon-fill",
|
||||
type: "fill",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["==", ["geometry-type"], "Polygon"],
|
||||
paint: {
|
||||
"fill-color": "#2563eb",
|
||||
"fill-opacity": 0.16
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-polygon-outline",
|
||||
type: "line",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["==", ["geometry-type"], "Polygon"],
|
||||
paint: {
|
||||
"line-color": "#2563eb",
|
||||
"line-width": 2,
|
||||
"line-opacity": 0.82
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-line",
|
||||
type: "line",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["==", ["geometry-type"], "LineString"],
|
||||
paint: {
|
||||
"line-color": "#2563eb",
|
||||
"line-width": 3,
|
||||
"line-opacity": 0.88
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-point",
|
||||
type: "circle",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["==", ["geometry-type"], "Point"],
|
||||
paint: {
|
||||
"circle-color": "#2563eb",
|
||||
"circle-radius": 6,
|
||||
"circle-stroke-color": "#ffffff",
|
||||
"circle-stroke-width": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-selected-polygon-outline",
|
||||
type: "line",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["all", ["==", ["geometry-type"], "Polygon"], ["==", ["get", "id"], ""]],
|
||||
paint: {
|
||||
"line-color": "#ff7a45",
|
||||
"line-width": 4,
|
||||
"line-opacity": 0.86
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-selected-line",
|
||||
type: "line",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["all", ["==", ["geometry-type"], "LineString"], ["==", ["get", "id"], ""]],
|
||||
paint: {
|
||||
"line-color": "#ff7a45",
|
||||
"line-width": 6,
|
||||
"line-opacity": 0.72
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-selected-point",
|
||||
type: "circle",
|
||||
source: DRAWING_SOURCE_IDS.features,
|
||||
filter: ["all", ["==", ["geometry-type"], "Point"], ["==", ["get", "id"], ""]],
|
||||
paint: {
|
||||
"circle-color": "#ff7a45",
|
||||
"circle-radius": 10,
|
||||
"circle-opacity": 0.2,
|
||||
"circle-stroke-color": "#ff7a45",
|
||||
"circle-stroke-width": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-draft-polygon-fill",
|
||||
type: "fill",
|
||||
source: DRAWING_SOURCE_IDS.draft,
|
||||
filter: ["==", ["geometry-type"], "Polygon"],
|
||||
paint: {
|
||||
"fill-color": "#ff7a45",
|
||||
"fill-opacity": 0.12
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-draft-line",
|
||||
type: "line",
|
||||
source: DRAWING_SOURCE_IDS.draft,
|
||||
filter: ["any", ["==", ["geometry-type"], "LineString"], ["==", ["geometry-type"], "Polygon"]],
|
||||
paint: {
|
||||
"line-color": "#ff7a45",
|
||||
"line-width": 2,
|
||||
"line-dasharray": [2, 2],
|
||||
"line-opacity": 0.9
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "workbench-drawing-draft-vertex",
|
||||
type: "circle",
|
||||
source: DRAWING_SOURCE_IDS.draft,
|
||||
filter: ["==", ["geometry-type"], "Point"],
|
||||
paint: {
|
||||
"circle-color": "#ff7a45",
|
||||
"circle-radius": 4,
|
||||
"circle-stroke-color": "#ffffff",
|
||||
"circle-stroke-width": 1.5
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export function ensureDrawingLayers(map: {
|
||||
getSource: (id: string) => unknown;
|
||||
addSource: (id: string, source: GeoJSONSourceSpecification) => void;
|
||||
getLayer: (id: string) => unknown;
|
||||
addLayer: (layer: NonNullable<StyleSpecification["layers"]>[number]) => void;
|
||||
}) {
|
||||
if (!map.getSource(DRAWING_SOURCE_IDS.features)) {
|
||||
map.addSource(DRAWING_SOURCE_IDS.features, drawingSources.features);
|
||||
}
|
||||
|
||||
if (!map.getSource(DRAWING_SOURCE_IDS.draft)) {
|
||||
map.addSource(DRAWING_SOURCE_IDS.draft, drawingSources.draft);
|
||||
}
|
||||
|
||||
drawingLayers.forEach((layer) => {
|
||||
if (!map.getLayer(layer.id)) {
|
||||
map.addLayer(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function setDrawingSourceData(
|
||||
map: { getSource: (id: string) => unknown },
|
||||
sourceId: string,
|
||||
data: DrawingFeatureCollection
|
||||
) {
|
||||
const source = map.getSource(sourceId) as GeoJSONSource | undefined;
|
||||
source?.setData(data);
|
||||
}
|
||||
|
||||
export function setSelectedDrawingFeatureId(
|
||||
map: { getLayer: (id: string) => unknown; setFilter: (id: string, filter?: FilterSpecification) => void },
|
||||
featureId: string | null
|
||||
) {
|
||||
const id = featureId ?? "";
|
||||
|
||||
[
|
||||
["workbench-drawing-selected-polygon-outline", "Polygon"],
|
||||
["workbench-drawing-selected-line", "LineString"],
|
||||
["workbench-drawing-selected-point", "Point"]
|
||||
].forEach(([layerId, geometryType]) => {
|
||||
if (map.getLayer(layerId)) {
|
||||
map.setFilter(layerId, ["all", ["==", ["geometry-type"], geometryType], ["==", ["get", "id"], id]]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function createPointFeature(
|
||||
id: string,
|
||||
coordinates: [number, number],
|
||||
label: string
|
||||
): DrawingFeatureCollection["features"][number] {
|
||||
return {
|
||||
type: "Feature",
|
||||
id,
|
||||
properties: createDrawingProperties(id, label, "point"),
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates
|
||||
} satisfies Point
|
||||
};
|
||||
}
|
||||
|
||||
export function createLineFeature(
|
||||
id: string,
|
||||
coordinates: [number, number][],
|
||||
label: string
|
||||
): DrawingFeatureCollection["features"][number] {
|
||||
return {
|
||||
type: "Feature",
|
||||
id,
|
||||
properties: createDrawingProperties(id, label, "line"),
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates
|
||||
} satisfies LineString
|
||||
};
|
||||
}
|
||||
|
||||
export function createPolygonFeature(
|
||||
id: string,
|
||||
coordinates: [number, number][],
|
||||
label: string
|
||||
): DrawingFeatureCollection["features"][number] {
|
||||
return {
|
||||
type: "Feature",
|
||||
id,
|
||||
properties: createDrawingProperties(id, label, "polygon"),
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [[...coordinates, coordinates[0]]]
|
||||
} satisfies Polygon
|
||||
};
|
||||
}
|
||||
|
||||
export function createCircleFeature(
|
||||
id: string,
|
||||
center: [number, number],
|
||||
radiusMeters: number,
|
||||
label: string
|
||||
): DrawingFeatureCollection["features"][number] {
|
||||
const coordinates = createCircleCoordinates(center, radiusMeters);
|
||||
|
||||
return {
|
||||
type: "Feature",
|
||||
id,
|
||||
properties: createDrawingProperties(id, label, "circle"),
|
||||
geometry: {
|
||||
type: "Polygon",
|
||||
coordinates: [coordinates]
|
||||
} satisfies Polygon
|
||||
};
|
||||
}
|
||||
|
||||
function createDrawingProperties(
|
||||
id: string,
|
||||
label: string,
|
||||
kind: DrawingFeatureProperties["kind"]
|
||||
): DrawingFeatureProperties {
|
||||
return {
|
||||
id,
|
||||
label,
|
||||
kind,
|
||||
createdAt: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user