Skip to content

Commit

Permalink
feat: tiles are now added to map with their correct geometry types [2…
Browse files Browse the repository at this point in the history
…025-01-19]
  • Loading branch information
CHRISCARLON committed Jan 19, 2025
1 parent 4442529 commit e29d53e
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 77 deletions.
34 changes: 0 additions & 34 deletions gridwalk-backend/src/routes/tiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,42 +88,8 @@ pub async fn tiles(

pub async fn get_geometry_type(
State(state): State<Arc<AppState>>,
cookies: Cookies,
Path((workspace_id, connection_id, source_name)): Path<(String, String, String)>,
) -> impl IntoResponse {
let token = cookies.get("sid").unwrap().value().to_string();

let session = match Session::from_id(&state.app_data, &token).await {
Ok(session) => session,
Err(_) => return (StatusCode::UNAUTHORIZED, "").into_response(),
};

// Do not allow unauthenticated users for now
if session.user_id.is_none() {
return (StatusCode::UNAUTHORIZED, "").into_response();
}

let user = match User::from_id(&state.app_data, &session.user_id.unwrap()).await {
Ok(user) => user,
Err(_) => return (StatusCode::INTERNAL_SERVER_ERROR, "").into_response(),
};

let workspace = match Workspace::from_id(&state.app_data, &workspace_id).await {
Ok(ws) => ws,
Err(_) => return "workspace not found".into_response(),
};

// Check if user is a member of the workspace
let _workspace_member = workspace
.get_member(&state.app_data, &user)
.await
.map_err(|_| (StatusCode::FORBIDDEN, ""));

// Check if workspace has access to the connection namespace
let _connection_access = ConnectionAccess::get(&state.app_data, &workspace, &connection_id)
.await
.map_err(|_| (StatusCode::NOT_FOUND, ""));

let geoconnector = state
.geo_connections
.get_connection(&connection_id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,31 +382,98 @@ export function MapClient({ apiUrl }: MapClientProps) {

// Layer management handler
const addMapLayer = useCallback(
(
async (
map: maplibregl.Map,
layerId: string,
sourceUrl: string,
sourceLayerName: string
sourceLayerName: string,
geomTypeUrl: string
) => {
if (!map.getSource(layerId)) {
map.addSource(layerId, {
type: "vector",
tiles: [sourceUrl],
minzoom: 0,
maxzoom: 22,
try {
// Fetch the geometry type from the API
const response = await fetch(geomTypeUrl);
if (!response.ok) {
throw new Error(
`Failed to fetch geometry type: ${response.statusText}`
);
}
const geomType = await response.text();

// Add the source if it doesn't exist
if (!map.getSource(layerId)) {
map.addSource(layerId, {
type: "vector",
tiles: [sourceUrl],
minzoom: 0,
maxzoom: 22,
});
}

// Configure the layer based on geometry type
// TODO ADD PROPER TYPE FOR LAYER CONFIG
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let layerConfig: any;
switch (geomType.toLowerCase().trim()) {
case "linestring":
case "multilinestring":
layerConfig = {
type: "line",
paint: {
"line-color": "#0080ff",
"line-opacity": 0.8,
"line-width": 2,
},
};
break;
case "polygon":
case "multipolygon":
layerConfig = {
type: "fill",
paint: {
"fill-color": "#0080ff",
"fill-opacity": 0.5,
"fill-outline-color": "#0066cc",
},
};
break;
case "point":
case "multipoint":
layerConfig = {
type: "circle",
paint: {
"circle-color": "#0080ff",
"circle-opacity": 0.5,
"circle-radius": 6,
},
};
break;
default:
console.warn(
`Unknown geometry type: ${geomType}, defaulting to point`
);
layerConfig = {
type: "circle",
paint: {
"circle-color": "#0080ff",
"circle-opacity": 0.5,
"circle-radius": 6,
},
};
}

// Add the layer to the map
map.addLayer({
id: layerId,
source: layerId,
"source-layer": sourceLayerName,
...layerConfig,
});
}

map.addLayer({
id: layerId,
type: "circle",
source: layerId,
"source-layer": sourceLayerName,
paint: {
"circle-color": "#0080ff",
"circle-opacity": 0.5,
},
});
return geomType;
} catch (error) {
console.error("Error adding map layer:", error);
throw error;
}
},
[]
);
Expand All @@ -417,13 +484,14 @@ export function MapClient({ apiUrl }: MapClientProps) {
if (!mapRef.current) return;
console.log("Active layers before style change:", activeLayerIds.current);

// GET CURRENT ACTIVE LAYERS
// Get current active layers
const currentLayerConfigs = activeLayerIds.current.map((layerId) => {
const layerName = layerId.replace(`layer-${workspaceId}-`, "");
return {
layerId,
layerName,
sourceUrl: `${process.env.NEXT_PUBLIC_GRIDWALK_API}/workspaces/${workspaceId}/connections/primary/sources/${layerName}/tiles/{z}/{x}/{y}`,
geomTypeUrl: `${process.env.NEXT_PUBLIC_GRIDWALK_API}/workspaces/${workspaceId}/connections/primary/sources/${layerName}/tiles/geometry`,
};
});

Expand All @@ -434,15 +502,13 @@ export function MapClient({ apiUrl }: MapClientProps) {
const map = mapRef.current;
let hasRestoredLayers = false;

// SET UP EVENT LISTENERS
// THIS BASICALLY WAITS FOR MAP TO BE IN IDLE STATE AFTER STYLE CHANGE TO THEN RELOAD THE LAYERS
const setupStyleLoadHandlers = () => {
console.log("Setting up style load handlers");

const handleIdle = () => {
const handleIdle = async () => {
if (map.isStyleLoaded() && !hasRestoredLayers) {
console.log("Style is loaded, restoring layers");
restoreLayers();
await restoreLayers();
hasRestoredLayers = true;

map.off("idle", handleIdle);
Expand All @@ -451,32 +517,38 @@ export function MapClient({ apiUrl }: MapClientProps) {

map.on("idle", handleIdle);

// Cleanup after timeout just in case
setTimeout(() => {
map.off("idle", handleIdle);
}, 5000);
};

// RESTORE LAYER FUNCTION
// TRIGGERRED BY IDLE
const restoreLayers = () => {
currentLayerConfigs.forEach(({ layerId, layerName, sourceUrl }) => {
const restoreLayers = async () => {
for (const {
layerId,
layerName,
sourceUrl,
geomTypeUrl,
} of currentLayerConfigs) {
try {
console.log(`Adding layer: ${layerName}`);
if (!map.getSource(layerId)) {
addMapLayer(map, layerId, sourceUrl, layerName);
await addMapLayer(
map,
layerId,
sourceUrl,
layerName,
geomTypeUrl
);
console.log(`Layer ${layerName} added successfully`);
}
} catch (error) {
console.error(`Error adding layer ${layerName}:`, error);
}
});
}
};

// SET UP LISTENERS
setupStyleLoadHandlers();

// FETCH THE STYLES TO BE CHANGED
fetch(MAP_STYLES[styleKey])
.then((response) => response.json())
.then((styleJson) => {
Expand All @@ -502,7 +574,7 @@ export function MapClient({ apiUrl }: MapClientProps) {
}, []);

const handleLayerToggle = useCallback(
(index: number, connection: WorkspaceConnection) => {
async (index: number, connection: WorkspaceConnection) => {
if (!mapRef?.current) return;
const map = mapRef.current;
const layerName = String(connection);
Expand All @@ -525,18 +597,20 @@ export function MapClient({ apiUrl }: MapClientProps) {
if (willBeEnabled) {
try {
const sourceLayerName = layerName;
console.log("Source layer name:", sourceLayerName);

const url = new URL(window.location.href);
const pathParts = url.pathname.split("/");
const workspaceIdFromUrl = pathParts[2];

const sourceUrl = `${process.env.NEXT_PUBLIC_GRIDWALK_API}/workspaces/${workspaceIdFromUrl}/connections/primary/sources/${layerName}/tiles/{z}/{x}/{y}`;

// TODO THIS IS WHERE WE WOULD PUT CONST 'GEOMTYPE' - NEED TO IMPLEMENT A ROUTE FOR THIS IN THE BACKEND
// THIS WOULD BE PASSED TO THE ADD MAP LAYER FUCNTION AS AN ARGUMENT

addMapLayer(map, layerId, sourceUrl, sourceLayerName);
const geomTypeUrl = `${process.env.NEXT_PUBLIC_GRIDWALK_API}/workspaces/${workspaceIdFromUrl}/connections/primary/sources/${layerName}/tiles/geometry`;

await addMapLayer(
map,
layerId,
sourceUrl,
sourceLayerName,
geomTypeUrl
);
activeLayerIds.current.push(layerId);
} catch (err) {
setSelectedLayers((prev) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ const MapModal: React.FC<ModalProps> = ({
return (
<div className="p-1">
<h2 className="text-l font-bold mb-4 text-blue-500 ">
Available Public Layers
Public Layers
</h2>
{workspaceConnections?.length > 0 ? (
<div className="mb-3">
Expand All @@ -152,7 +152,7 @@ const MapModal: React.FC<ModalProps> = ({
/>
</div>
) : (
<p className="text-gray-600">No layers available.</p>
<p className=" text-sm text-gray-600">No layers available.</p>
)}
</div>
);
Expand Down

0 comments on commit e29d53e

Please sign in to comment.