I'm trying to make this animation be a circle segment instead of a rectangle that gets filled where the degrees of the segment could be picked e.g 40 like:
This is what the animation currently looks like:
I've tried using <Group clip={...}> but I couldn't find a way to make it work without the whole circle segment jiggling.
The code comes from this video: https://www.youtube.com/watch?v=I6elFawLceY&t=372s
Thank you!
import React from "react";
import {
Alert,
Dimensions,
SafeAreaView,
View,
StyleSheet,
Text as RNText,
TouchableOpacity,
} from "react-native";
import {
Skia,
Canvas,
Path,
vec,
useComputedValue,
useClockValue,
useValue,
useTouchHandler,
LinearGradient,
Text,
useFont,
rrect,rect,
} from "@shopify/react-native-skia";
import { line, curveBasis } from "d3";
const dimens = Dimensions.get("screen");
const width = 150;
const frequency = 2;
const initialAmplitude = 5;
const verticalShiftConst = 100;
const height = 600;
const horizontalShift = (dimens.width - width) / 2;
const indicatorArray = Array.from({ length: 11 }, (_, i) => i);
export const WaveMeter = () => {
const verticalShift = useValue(verticalShiftConst);
const amplitude = useValue(initialAmplitude);
const clock = useClockValue();
const touchHandler = useTouchHandler({
onActive: ({ y }) => {
if (y > verticalShiftConst) {
verticalShift.current = Math.min(height, y);
amplitude.current = Math.max(
0,
(height - verticalShift.current) * 0.025
);
}
},
});
const createWavePath = (phase = 20) => {
let points = Array.from({ length: width + horizontalShift }, (_, index) => {
const angle =
((index - horizontalShift) / width) * (Math.PI * frequency) + phase;
return [
index,
amplitude.current * Math.sin(angle) + verticalShift.current,
];
});
const shiftedPoints = points.slice(horizontalShift, 300);
const lineGenerator = line().curve(curveBasis);
const waveLine = lineGenerator(shiftedPoints);
const bottomLine = `L${
width + horizontalShift
},${height} L${horizontalShift},${height}`;
const extendedWavePath = `${waveLine} ${bottomLine} Z`;
return extendedWavePath;
};
const animatedPath = useComputedValue(() => {
const speedFactor = 0.5;
const current = (clock.current / 225) % 225;
const start = Skia.Path.MakeFromSVGString(createWavePath(current));
const end = Skia.Path.MakeFromSVGString(createWavePath(Math.PI * current * speedFactor));
return start.interpolate(end, 0.5);
}, [clock, verticalShift]);
const trianglePath = useComputedValue(() => {
return [
vec(horizontalShift * 2.6, verticalShift.current - 20),
vec(horizontalShift * 2.6, verticalShift.current + 20),
vec(horizontalShift * 2.3, verticalShift.current),
];
}, [verticalShift]);
const font = useFont( require('../../../../shared/assets/fonts/Hammersmith_One/HammersmithOne-Regular.ttf'))
const gradientStart = useComputedValue(() => {
return vec(0, verticalShift.current);
}, [verticalShift]);
const gradientEnd = useComputedValue(() => {
return vec(0, verticalShift.current + 150);
}, [verticalShift]);
const getLabelYValueOffset = (position) => {
return verticalShiftConst + 50 * position;
};
const getYLabelValue = (position) => {
return `${(100 - position * 10)/10}`;
};
const alertValue = () => {
const adjustedShift =
(verticalShiftConst - verticalShift.current) /
(height - verticalShiftConst) +
1;
Alert.alert("VALUE", `Your value is: ${Math.round(adjustedShift * 10)}`);
};
const size = 600
const r = size / 2;
const padding = size / 30;
const innerCircleSize = size - padding * 2;
const roundedRectangle =
rrect(
rect(padding, padding, innerCircleSize, innerCircleSize),
r/2,
r,
);
return (
<SafeAreaView style={styles.container}>
<Canvas style={styles.canvas} onTouch={touchHandler}>
<Path path={animatedPath} style="fill">
<LinearGradient
start={gradientStart}
end={gradientEnd}
colors={['cyan', 'blue']}
/>
</Path>
</Canvas>
<TouchableOpacity style={styles.buttonContainer} onPress={alertValue}>
<RNText style={styles.buttonText}>GET VALUE</RNText>
</TouchableOpacity>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
canvas: {
flex: 1,
},
buttonContainer: {
height: 60,
borderRadius: 8,
backgroundColor: "#FF5349",
marginHorizontal: 50,
marginBottom: 20,
justifyContent: "center",
alignItems: "center",
},
buttonText: {
color: "white",
fontSize: 20,
fontWeight: "bold",
},
});

