2026-06-19 22:08:10 +08:00

115 lines
3.4 KiB
TypeScript

import React, { useRef } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, Platform } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
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 insets = useSafeAreaInsets();
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 — offset by safe area top */}
<View style={[styles.overlay, { top: 12 + insets.top }]}>
<Text style={styles.overlayText}>: {points.length}</Text>
{latest && (
<Text style={styles.overlayText}>
{formatCoord(latest.latitude, false)} {formatCoord(latest.longitude, true)}
</Text>
)}
</View>
{/* Center button — offset by safe area bottom */}
<TouchableOpacity style={[styles.centerBtn, { bottom: 24 + insets.bottom }]} 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',
left: 12,
backgroundColor: 'rgba(0,0,0,0.6)',
borderRadius: 8,
padding: 8,
gap: 2,
},
overlayText: { color: '#ddd', fontSize: 11 },
centerBtn: {
position: 'absolute',
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 },
});