231 lines
7.8 KiB
TypeScript
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;
|