diff --git a/src/__stories__/meter-story.tsx b/src/__stories__/meter-story.tsx index 5ca2b2968..279636435 100644 --- a/src/__stories__/meter-story.tsx +++ b/src/__stories__/meter-story.tsx @@ -71,7 +71,6 @@ export const MeterStory: StoryComponent = ({ ...valuesArgs }) => { const values = Object.values(valuesArgs).slice(0, valuesCount); - console.log('values', values); return ( @@ -82,7 +81,9 @@ export const MeterStory: StoryComponent = ({ /> )} - +
+ +
); diff --git a/src/meter.tsx b/src/meter.tsx index dd2ad36cc..219e2a09c 100644 --- a/src/meter.tsx +++ b/src/meter.tsx @@ -6,6 +6,7 @@ import {vars} from './skins/skin-contract.css'; import bezier from 'cubic-bezier'; import {getPrefixedDataAttributes} from './utils/dom'; import {useThemeVariant} from './theme-variant-context'; +import {useTheme} from './hooks'; import type {DataAttributes} from './utils/types'; @@ -20,7 +21,7 @@ const ANIMATION_DELAY_MS = 200; const ANIMATION_DURATION_MS = 1000; const ANIMATION_EPSILON = 1000 / 60 / ANIMATION_DURATION_MS / 4; -const SMALL_VALUE_THRESHOLD = Math.PI / 1000; +const SMALL_VALUE_THRESHOLD = Math.PI / 10000; const TYPE_LINEAR = 'linear'; const TYPE_ANGULAR = 'angular'; @@ -138,38 +139,49 @@ const MeterComponent = ({ 'aria-hidden': ariaHidden, dataAttributes, }: MeterProps): JSX.Element => { - const values = React.useMemo(() => valuesFromProps.map((v) => v / MAX_SEGMENT_VALUE), [valuesFromProps]); + const theme = useTheme(); + const hasRoundLineCaps = theme.borderRadii.bar !== '0px'; const themeVariant = useThemeVariant(); const isOverMedia = themeVariant === 'media'; const isInverse = themeVariant === 'inverse'; const segmentColors = colors || (isInverse || isOverMedia ? DEFAULT_COLORS_INVERSE : DEFAULT_COLORS); const scaleFactor = VIEW_BOX_WIDTH / width; + const lineCapRadiusPx = hasRoundLineCaps ? STROKE_WIDTH_PX / 2 : 0; + const lineCapRadius = lineCapRadiusPx * scaleFactor; const strokeWidth = STROKE_WIDTH_PX * scaleFactor; const maxValue = - type === TYPE_LINEAR ? VIEW_BOX_WIDTH - strokeWidth : type === TYPE_CIRCULAR ? 2 * Math.PI : Math.PI; + type === TYPE_LINEAR + ? VIEW_BOX_WIDTH - lineCapRadius * 2 + : type === TYPE_CIRCULAR + ? 2 * Math.PI + : Math.PI; const radius = type === TYPE_LINEAR ? 0 : CENTER_X - strokeWidth / 2; const separation = SEPARATION_PX * scaleFactor; const segmentSeparation = type === TYPE_LINEAR ? separation / VIEW_BOX_WIDTH : separation / radius / maxValue; + const height = - type === TYPE_LINEAR - ? STROKE_WIDTH_PX - : type === TYPE_CIRCULAR - ? width - : width / 2 + STROKE_WIDTH_PX / 2; + type === TYPE_LINEAR ? STROKE_WIDTH_PX : type === TYPE_CIRCULAR ? width : width / 2 + lineCapRadiusPx; + const viewBoxHeight = type === TYPE_LINEAR ? strokeWidth : type === TYPE_CIRCULAR ? VIEW_BOX_WIDTH - : VIEW_BOX_WIDTH / 2 + strokeWidth / 2; + : CENTER_X + lineCapRadius; const trackbarColor = isOverMedia ? vars.colors.inverse : isInverse - ? vars.colors.barTrack // @FIXME. Should be: barTrackInverse + ? vars.colors.barTrackInverse : vars.colors.barTrack; + /** scale values to the range [0, 1] */ + const values = React.useMemo(() => { + return valuesFromProps.map((v) => v / MAX_SEGMENT_VALUE); + }, [valuesFromProps]); + + /** the animation starts with these values */ const initialValuesRef = React.useRef>( Array.from({length: values.length}, () => (reverse ? 1 : 0)) ); @@ -209,9 +221,9 @@ const MeterComponent = ({ const getX = React.useCallback( (value: number) => type === TYPE_LINEAR - ? strokeWidth / 2 + maxValue * value + ? lineCapRadius + maxValue * value : CENTER_X - radius * Math.cos(value * maxValue), - [maxValue, radius, strokeWidth, type] + [lineCapRadius, maxValue, radius, type] ); const getY = React.useCallback( @@ -227,62 +239,85 @@ const MeterComponent = ({ viewBox={`0 0 ${VIEW_BOX_WIDTH} ${viewBoxHeight}`} width={width} height={height} - style={{transform: `rotate(${type === TYPE_CIRCULAR ? '90deg' : 0})`}} + style={{transform: `rotate(${type === TYPE_CIRCULAR ? '90deg' : 0})`, display: 'block'}} aria-hidden={ariaHidden} role="meter" {...getPrefixedDataAttributes(dataAttributes, 'Meter')} > - - - - - - + {hasRoundLineCaps && ( + <> + + + + + + + + )} {firstNonZeroIndex >= 0 && lastSegment && ( <> = 0.5 : 0, })} /> - - {type === TYPE_CIRCULAR && ( + {type === TYPE_CIRCULAR && hasRoundLineCaps && ( )} - {type === TYPE_CIRCULAR && lastSegment.end <= 0.5 && (