Hiển thị tọa độ và khu vực khi tàu vi phạm
This commit is contained in:
230
components/map/ZoneInMap.tsx
Normal file
230
components/map/ZoneInMap.tsx
Normal file
@@ -0,0 +1,230 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user