Files
sgw-owner-app/components/map/ZoneInMap.tsx

231 lines
7.8 KiB
TypeScript

import { BanzoneWithAlarm } from "@/app/(tabs)";
import {
convertWKTLineStringToLatLngArray,
convertWKTPointToLatLng,
convertWKTtoLatLngString,
} from "@/utils/geom";
import React, { useEffect, useMemo } from "react";
import { CircleWithLabel } from "./CircleWithLabel";
import { MarkerCustom } from "./MarkerCustom";
import { PolygonWithLabel } from "./PolygonWithLabel";
import { PolylineWithLabel } from "./PolylineWithLabel";
import MapView from "react-native-maps";
interface ZoneInMapProps {
banzones: BanzoneWithAlarm[];
mapRef?: React.RefObject<MapView | null>;
}
// Helper function to parse zone geometry
const parseZoneGeometry = (geometryString: string | undefined) => {
if (!geometryString) {
return null;
}
try {
const geometry: Model.Geom = JSON.parse(geometryString);
return geometry;
} catch (error) {
console.warn("Failed to parse geometry:", error);
return null;
}
};
const ZoneInMap = (data: ZoneInMapProps) => {
const { banzones, mapRef } = data;
// Auto-focus camera to first alarm location when banzones change
useEffect(() => {
if (mapRef?.current && banzones.length > 0) {
const firstAlarm = banzones[0].alarms;
if (
firstAlarm.zone.lat !== undefined &&
firstAlarm.zone.lon !== undefined
) {
setTimeout(() => {
mapRef.current?.animateToRegion(
{
latitude: firstAlarm.zone.lat as number,
longitude: firstAlarm.zone.lon as number,
latitudeDelta: 0.05,
longitudeDelta: 0.05,
},
1000
);
}, 500);
}
}
}, [banzones, mapRef]);
// Parse and render all banzones with their ship markers
const allElements = useMemo(() => {
const elements: React.ReactNode[] = [];
console.log("ZoneInMap - banzones received:", banzones);
banzones.forEach((banzone, banzoneIndex) => {
const { zone, alarms } = banzone;
console.log(`Processing banzone ${banzoneIndex}:`, {
zone: zone,
alarms: alarms,
geometry: zone?.geometry,
});
// Parse geometry with error handling
const geometry = parseZoneGeometry(zone?.geometry);
if (!geometry) {
console.warn(`No geometry for zone ${banzoneIndex}`);
return;
}
const { geom_type, geom_lines, geom_poly, geom_point, geom_radius } =
geometry;
console.log(`Parsed geometry for zone ${banzoneIndex}:`, {
geom_type,
geom_lines: geom_lines?.substring(0, 100) + "...",
geom_poly: geom_poly?.substring(0, 100) + "...",
geom_point,
geom_radius,
});
try {
if (geom_type === 2) {
// LINESTRING - use PolylineWithLabel
// console.log(`Processing LINESTRING for zone ${banzoneIndex}`);
const coordinates = convertWKTLineStringToLatLngArray(
geom_lines || ""
);
// console.log(`Converted coordinates:`, coordinates);
if (coordinates.length > 0) {
elements.push(
<PolylineWithLabel
key={`line-${zone?.id || banzoneIndex}`}
coordinates={coordinates.map((coord) => ({
latitude: coord[0],
longitude: coord[1],
}))}
label={zone?.name || alarms.zone.zone_name || ""}
content={alarms.zone.message || ""}
/>
);
// console.log(`Added PolylineWithLabel for zone ${banzoneIndex}`);
}
} else if (geom_type === 1) {
// MULTIPOLYGON - check both geom_poly and geom_lines
// console.log(`Processing MULTIPOLYGON for zone ${banzoneIndex}`);
``;
// First check if we have actual polygon data
if (geom_poly && geom_poly.trim() !== "") {
const polygons = convertWKTtoLatLngString(geom_poly);
// console.log(`Converted polygons from geom_poly:`, polygons);
polygons.forEach((polygon, polygonIndex) => {
if (polygon.length > 0) {
elements.push(
<PolygonWithLabel
key={`polygon-${zone?.id || banzoneIndex}-${polygonIndex}`}
coordinates={polygon.map((coord) => ({
latitude: coord[0],
longitude: coord[1],
}))}
label={zone?.name || alarms.zone.zone_name || ""}
content={alarms.zone.message || ""}
/>
);
// console.log(
// `Added PolygonWithLabel for zone ${banzoneIndex}-${polygonIndex}`
// );
}
});
} else if (geom_lines && geom_lines.trim() !== "") {
// If no polygon data, treat geom_lines as a line (data inconsistency fix)
// console.log(
// `No polygon data, processing as LINESTRING from geom_lines`
// );
const coordinates = convertWKTLineStringToLatLngArray(geom_lines);
console.log(`Converted coordinates from geom_lines:`, coordinates);
if (coordinates.length > 0) {
elements.push(
<PolylineWithLabel
key={`line-${zone?.id || banzoneIndex}`}
coordinates={coordinates.map((coord) => ({
latitude: coord[0],
longitude: coord[1],
}))}
label={zone?.name || alarms.zone.zone_name || ""}
content={alarms.zone.message || ""}
/>
);
// console.log(
// `Added PolylineWithLabel for zone ${banzoneIndex} (from geom_lines)`
// );
}
} else {
// console.warn(`No valid geometry data for zone ${banzoneIndex}`);
}
} else if (geom_type === 3) {
// POINT/CIRCLE - use Circle
// console.log(`Processing POINT/CIRCLE for zone ${banzoneIndex}`);
const point = convertWKTPointToLatLng(geom_point || "");
// console.log(`Converted point:`, point, `radius:`, geom_radius);
if (point && geom_radius) {
elements.push(
<CircleWithLabel
key={`circle-${zone?.id || banzoneIndex}`}
center={{
latitude: point[1], // Note: convertWKTPointToLatLng returns [lng, lat]
longitude: point[0],
}}
radius={geom_radius}
label={zone?.name || alarms.zone.zone_name || ""}
content={alarms.zone.message || ""}
/>
);
// console.log(`Added Circle for zone ${banzoneIndex}`);
}
} else {
console.warn(
`Unknown geom_type ${geom_type} for zone ${banzoneIndex}`
);
}
} catch (error) {
console.warn(
"Error processing zone geometry for zone",
zone?.id,
":",
error
);
}
// Ship marker for the alarm location
if (alarms.zone.lat && alarms.zone.lon) {
elements.push(
<MarkerCustom
key={`ship-${alarms.thing_id || banzoneIndex}`}
id={`ship-${alarms.thing_id || banzoneIndex}`}
latitude={alarms.zone.lat}
longitude={alarms.zone.lon}
shipName={alarms.ship_name || "Tàu không xác định"}
description={
alarms.zone.gps_time
? new Date(alarms.zone.gps_time * 1000).toLocaleString()
: ""
}
heading={alarms.zone.h}
zIndex={100}
/>
);
}
});
// console.log(`Total elements rendered: ${elements.length}`);
return elements;
}, [banzones]);
return <>{allElements}</>;
};
export default ZoneInMap;