|
@@ -1,15 +1,15 @@
|
|
|
-import React, { useEffect, useState } from 'react';
|
|
|
-import { StyleSheet, View, Text, Dimensions } from 'react-native';
|
|
|
+import React, { useEffect } from 'react';
|
|
|
+import { StyleSheet, Text, Dimensions } from 'react-native';
|
|
|
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';
|
|
|
import { Colors } from 'src/theme';
|
|
|
|
|
|
const FEET_PER_METER = 3.28084;
|
|
|
const FEET_PER_MILES = 5280;
|
|
|
-const SCALE_SCREEN_RATIO = 0.3;
|
|
|
+const SCALE_SCREEN_RATIO = 0.25;
|
|
|
const TILE_SIZE_METERS_AT_0_ZOOM = 156543.034;
|
|
|
|
|
|
const SCALE_STEPS_IN_METERS = [
|
|
|
- 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
|
|
|
+ 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
|
|
|
1000000, 2000000, 3000000
|
|
|
];
|
|
|
|
|
@@ -39,22 +39,40 @@ const SCALE_STEPS_IN_FEET = [
|
|
|
interface ScaleBarProps {
|
|
|
zoom: number;
|
|
|
latitude: number;
|
|
|
+ isVisible: boolean;
|
|
|
bottom?: any;
|
|
|
}
|
|
|
|
|
|
-const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) => {
|
|
|
+const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, isVisible, bottom = '21%' }) => {
|
|
|
const metricWidth = useSharedValue(0);
|
|
|
const imperialWidth = useSharedValue(0);
|
|
|
const metricText = useSharedValue('');
|
|
|
const imperialText = useSharedValue('');
|
|
|
const screenWidth = Dimensions.get('window').width;
|
|
|
+ const opacity = useSharedValue(isVisible ? 1 : 0);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (isVisible) {
|
|
|
+ opacity.value = withTiming(1, { duration: 100 });
|
|
|
+ } else {
|
|
|
+ opacity.value = withTiming(0, { duration: 1500 });
|
|
|
+ }
|
|
|
+ }, [isVisible]);
|
|
|
+
|
|
|
+ const animatedStyle = useAnimatedStyle(() => ({
|
|
|
+ opacity: opacity.value
|
|
|
+ }));
|
|
|
|
|
|
const getResolutionFromZoomAndLatitude = (zoom: number, latitude: number) =>
|
|
|
(TILE_SIZE_METERS_AT_0_ZOOM * Math.cos((latitude * Math.PI) / 180)) / Math.pow(2, zoom);
|
|
|
|
|
|
- const getBestStepFromResolution = (resolution: number, steps: number[]) => {
|
|
|
+ const getBestStepFromResolution = (
|
|
|
+ resolution: number,
|
|
|
+ steps: number[],
|
|
|
+ multiplier: number = 1
|
|
|
+ ) => {
|
|
|
return steps.reduce((bestStep, currentStep) => {
|
|
|
- const scaleSize = (2 * currentStep) / resolution;
|
|
|
+ const scaleSize = (2 * currentStep * multiplier) / resolution;
|
|
|
return scaleSize / screenWidth < SCALE_SCREEN_RATIO ? currentStep : bestStep;
|
|
|
});
|
|
|
};
|
|
@@ -63,7 +81,7 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
|
|
|
const resolution = getResolutionFromZoomAndLatitude(zoom, latitude);
|
|
|
|
|
|
const metricStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_METERS);
|
|
|
- const imperialStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_FEET);
|
|
|
+ const imperialStep = getBestStepFromResolution(resolution, SCALE_STEPS_IN_FEET, 0.4);
|
|
|
|
|
|
const metricScaleSize = (2 * metricStep) / resolution;
|
|
|
const imperialScaleSize = (2 * imperialStep) / resolution / FEET_PER_METER;
|
|
@@ -85,19 +103,21 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
|
|
|
}, [zoom, latitude]);
|
|
|
|
|
|
const animatedMetricLineStyle = useAnimatedStyle(() => ({
|
|
|
- right: metricWidth.value
|
|
|
+ left: metricWidth.value
|
|
|
}));
|
|
|
|
|
|
const animatedImperialLineStyle = useAnimatedStyle(() => ({
|
|
|
- right: imperialWidth.value
|
|
|
+ left: imperialWidth.value
|
|
|
}));
|
|
|
|
|
|
const animatedCombinedStyle = useAnimatedStyle(() => ({
|
|
|
width: Math.max(metricWidth.value, imperialWidth.value)
|
|
|
}));
|
|
|
|
|
|
+ if (!metricText.value || !imperialText.value) return null;
|
|
|
+
|
|
|
return (
|
|
|
- <View style={[styles.container, { bottom }]}>
|
|
|
+ <Animated.View style={[styles.container, { bottom }, animatedStyle]}>
|
|
|
<Text style={[styles.text, { bottom: 0 }]}>{metricText.value}</Text>
|
|
|
|
|
|
<Animated.View style={[styles.scaleBar, animatedCombinedStyle]}>
|
|
@@ -106,14 +126,14 @@ const ScaleBar: React.FC<ScaleBarProps> = ({ zoom, latitude, bottom = '25%' }) =
|
|
|
</Animated.View>
|
|
|
|
|
|
<Text style={[styles.text, { top: 0 }]}>{imperialText.value}</Text>
|
|
|
- </View>
|
|
|
+ </Animated.View>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
container: {
|
|
|
position: 'absolute',
|
|
|
- right: 10,
|
|
|
+ left: 16,
|
|
|
alignItems: 'center'
|
|
|
},
|
|
|
scaleBar: {
|
|
@@ -135,7 +155,7 @@ const styles = StyleSheet.create({
|
|
|
color: Colors.TEXT_GRAY,
|
|
|
marginVertical: 4,
|
|
|
position: 'absolute',
|
|
|
- right: 0
|
|
|
+ left: 0
|
|
|
}
|
|
|
});
|
|
|
|