Skip to content

Instantly share code, notes, and snippets.

@nderscore
Last active October 16, 2024 18:12
Show Gist options
  • Save nderscore/a0d00419b511f2baa9812dc37f820908 to your computer and use it in GitHub Desktop.
Save nderscore/a0d00419b511f2baa9812dc37f820908 to your computer and use it in GitHub Desktop.
import { getVariable, ThemeTokens, useTheme } from '@tamagui/core';
import { Path, Svg } from 'react-native-svg';
const AR = 2;
export type MeterProps = {
color: ThemeTokens;
min: number;
max: number;
value?: number | null;
width?: number;
height?: number;
};
const startAngle = 270;
const radius = 125;
const centerX = 150;
const centerY = 150;
const polarToCartesian = (angleInDegrees: number) => {
const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
return [
centerX + radius * Math.cos(angleInRadians),
centerY + radius * Math.sin(angleInRadians),
];
};
const calculateArc = (percentage: number) => {
const endAngle = (Math.round(175 * percentage) + startAngle + 5) % 360;
const [startX, startY] = polarToCartesian(endAngle);
const [endX, endY] = polarToCartesian(startAngle);
const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;
const d = [
'M',
startX,
startY,
'A',
radius,
radius,
0,
largeArcFlag,
0,
endX,
endY,
].join(' ');
return d;
};
const backPath = calculateArc(1);
export const Meter = ({
color: colorProp,
width,
height,
min,
max,
value,
}: MeterProps) => {
const theme = useTheme();
const color = getVariable(
colorProp in theme ? theme[colorProp as keyof typeof theme] : colorProp
);
if (typeof width === 'number' && !height) {
height = Number((width / AR).toPrecision(6));
} else if (typeof height === 'number' && !width) {
width = Number((height * AR).toPrecision(6));
}
const cleanValue = Math.max(min, Math.min(max, value ?? 0));
const path = calculateArc((cleanValue - min) / (max - min));
return (
<Svg viewBox="0 0 300 150" width={width} height={height}>
<Path
d={backPath}
fill="none"
stroke={theme.bgNeutralTertiary.val}
strokeWidth={25}
/>
<Path d={path} fill="none" stroke={color} strokeWidth={25} />
</Svg>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment