Files
SeaGateway-App/components/map/PolylineWithLabel.tsx
2025-11-04 16:24:54 +07:00

114 lines
2.8 KiB
TypeScript

import { ANDROID_PLATFORM } from "@/constants";
import { usePlatform } from "@/hooks/use-platform";
import {
calculateTotalDistance,
getMiddlePointOfPolyline,
} from "@/utils/polyline";
import React, { useRef } from "react";
import { StyleSheet, Text, View } from "react-native";
import { MapMarker, Marker, Polyline } from "react-native-maps";
export interface PolylineWithLabelProps {
coordinates: {
latitude: number;
longitude: number;
}[];
label?: string;
content?: string;
strokeColor?: string;
strokeWidth?: number;
showDistance?: boolean;
zIndex?: number;
}
/**
* Component render Polyline kèm Label/Text ở giữa
*/
export const PolylineWithLabel: React.FC<PolylineWithLabelProps> = ({
coordinates,
label,
content,
strokeColor = "#FF5733",
strokeWidth = 4,
showDistance = false,
zIndex = 50,
}) => {
if (!coordinates || coordinates.length < 2) {
return null;
}
const middlePoint = getMiddlePointOfPolyline(coordinates);
const distance = calculateTotalDistance(coordinates);
const platform = usePlatform();
const markerRef = useRef<MapMarker>(null);
let displayText = label || "";
if (showDistance) {
displayText += displayText
? ` (${distance.toFixed(2)}km)`
: `${distance.toFixed(2)}km`;
}
markerRef.current?.showCallout();
return (
<>
<Polyline
coordinates={coordinates}
strokeColor={strokeColor}
strokeWidth={strokeWidth}
zIndex={zIndex}
/>
{displayText && (
<Marker
ref={markerRef}
coordinate={middlePoint}
zIndex={zIndex + 10}
tracksViewChanges={false}
anchor={{ x: 0.5, y: 0.5 }}
title={platform === ANDROID_PLATFORM ? label : undefined}
description={platform === ANDROID_PLATFORM ? content : undefined}
>
<View style={styles.markerContainer}>
<View style={styles.labelContainer}>
<Text
style={styles.labelText}
numberOfLines={2}
adjustsFontSizeToFit
>
{displayText}
</Text>
</View>
</View>
</Marker>
)}
</>
);
};
const styles = StyleSheet.create({
markerContainer: {
alignItems: "center",
justifyContent: "center",
},
labelContainer: {
backgroundColor: "rgba(255, 87, 51, 0.95)",
paddingHorizontal: 5,
paddingVertical: 5,
borderRadius: 18,
borderWidth: 1,
borderColor: "#fff",
shadowColor: "#000",
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.4,
shadowRadius: 5,
elevation: 8,
minWidth: 80,
maxWidth: 180,
},
labelText: {
color: "#fff",
fontSize: 14,
fontWeight: "bold",
letterSpacing: 0.3,
textAlign: "center",
},
});