theluyuan 38ba663466
Some checks failed
Close stale issues and PRs / stale (push) Has been cancelled
init
2025-09-02 14:49:16 +08:00

84 lines
2.3 KiB
TypeScript

import React, { Component } from 'react';
/**
* The number of dots to display in AudioLevelIndicator.
*
* IMPORTANT: AudioLevelIndicator assumes that this is an odd number.
*/
const AUDIO_LEVEL_DOTS = 5;
/**
* The index of the dot that is at the direct middle of all other dots.
*/
const CENTER_DOT_INDEX = Math.floor(AUDIO_LEVEL_DOTS / 2);
/**
* The type of the React {@code Component} props of {@link AudioLevelIndicator}.
*/
interface IProps {
/**
* The current audio level to display. The value should be a number between
* 0 and 1.
*/
audioLevel: number;
}
/**
* Creates a ReactElement responsible for drawing audio levels.
*
* @augments {Component}
*/
class AudioLevelIndicator extends Component<IProps> {
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
override render() {
const { audioLevel: passedAudioLevel } = this.props;
// First make sure we are sensitive enough.
const audioLevel = typeof passedAudioLevel === 'number' && !isNaN(passedAudioLevel)
? Math.min(passedAudioLevel * 1.2, 1) : 0;
// Let's now stretch the audio level over the number of dots we have.
const stretchedAudioLevel = AUDIO_LEVEL_DOTS * audioLevel;
const audioLevelDots = [];
for (let i = 0; i < AUDIO_LEVEL_DOTS; i++) {
const distanceFromCenter = CENTER_DOT_INDEX - i;
const audioLevelFromCenter
= stretchedAudioLevel - Math.abs(distanceFromCenter);
const cappedOpacity = Math.min(
1, Math.max(0, audioLevelFromCenter));
let className;
if (distanceFromCenter === 0) {
className = 'audiodot-middle';
} else if (distanceFromCenter < 0) {
className = 'audiodot-top';
} else {
className = 'audiodot-bottom';
}
audioLevelDots.push(
<span
className = { className }
key = { i }
style = {{ opacity: cappedOpacity }} />
);
}
return (
<span className = 'audioindicator in-react'>
{ audioLevelDots }
</span>
);
}
}
export default AudioLevelIndicator;