2026-06-06 22:13:00 +08:00

115 lines
3.2 KiB
TypeScript

import React, { useRef } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import MapView, { Marker, Polyline, type Region } from 'react-native-maps';
import { useDataStore } from '../../src/stores/dataStore';
import { formatCoord } from '../../src/utils/format';
export default function MapScreen() {
const history = useDataStore((s) => s.history);
const mapRef = useRef<MapView>(null);
const points = history
.filter((f) => f.meta && f.meta.latitude !== 0 && f.meta.longitude !== 0)
.map((f) => ({
latitude: f.meta!.latitude,
longitude: f.meta!.longitude,
frameId: f.frameId,
}))
.reverse(); // oldest first for polyline
const latest = points[points.length - 1];
const centerOnCurrent = () => {
if (!latest || !mapRef.current) return;
mapRef.current.animateToRegion(
{ latitude: latest.latitude, longitude: latest.longitude, latitudeDelta: 0.005, longitudeDelta: 0.005 },
600,
);
};
return (
<View style={styles.container}>
<MapView
ref={mapRef}
style={styles.map}
mapType="satellite"
showsUserLocation
initialRegion={
latest
? { latitude: latest.latitude, longitude: latest.longitude, latitudeDelta: 0.01, longitudeDelta: 0.01 }
: { latitude: 30, longitude: 115, latitudeDelta: 10, longitudeDelta: 10 }
}
>
{/* GPS track polyline */}
{points.length > 1 && (
<Polyline coordinates={points} strokeColor="#4a9eff" strokeWidth={2} />
)}
{/* Measurement point markers */}
{points.map((p) => (
<Marker
key={p.frameId}
coordinate={{ latitude: p.latitude, longitude: p.longitude }}
anchor={{ x: 0.5, y: 0.5 }}
title={`帧 #${p.frameId}`}
>
<View style={styles.markerDot} />
</Marker>
))}
</MapView>
{/* Overlay info */}
<View style={styles.overlay}>
<Text style={styles.overlayText}>: {points.length}</Text>
{latest && (
<Text style={styles.overlayText}>
{formatCoord(latest.latitude, false)} {formatCoord(latest.longitude, true)}
</Text>
)}
</View>
{/* Center button */}
<TouchableOpacity style={styles.centerBtn} onPress={centerOnCurrent}>
<Text style={styles.centerBtnText}></Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1 },
map: { flex: 1 },
markerDot: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: '#4a9eff',
borderWidth: 1,
borderColor: '#fff',
},
overlay: {
position: 'absolute',
top: 12,
left: 12,
backgroundColor: 'rgba(0,0,0,0.6)',
borderRadius: 8,
padding: 8,
gap: 2,
},
overlayText: { color: '#ddd', fontSize: 11 },
centerBtn: {
position: 'absolute',
bottom: 24,
right: 16,
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: 'rgba(10,10,10,0.85)',
justifyContent: 'center',
alignItems: 'center',
borderWidth: 1,
borderColor: '#444',
},
centerBtnText: { color: '#4a9eff', fontSize: 22 },
});