import { IBlock } from '../training/types' import { calculateDuration } from '../training/utils' import { IExerciseItem } from './types' /** * Find the right exercise given a certain time. * @param exerciseList * @param time */ export function getPosition(exerciseList: IExerciseItem[], time: number) { const index = exerciseList.findIndex( exercise => time < exercise.offset + exercise.duration ) const previousExercise = index >= 1 ? exerciseList[index - 1] : null const currentExercise = index >= 0 ? exerciseList[index] : null const nextExercise = index >= 0 && index < exerciseList.length - 1 ? exerciseList[index + 1] : null const values = { currentExercise, nextExercise, previousExercise, exerciseTime: 0 } if (currentExercise !== null) { values.exerciseTime = Math.max(time - currentExercise.offset, 0) } return values } /** * Takes a (nested) block of exercises and returns a flat array of exercises. * @param blocks * @param initialOffset - used for recursive application */ export function getExerciseList( blocks: IBlock[], initialOffset = 0, toplevelBlock: undefined | string = undefined ): IExerciseItem[] { let offset = initialOffset return blocks .map(block => { if (block.blocks) { const blockArray = [] for (let i = 0; i < (block.repetitions || 1); i++) { const subBlocks = getExerciseList( block.blocks, offset, toplevelBlock || block.title ) const lastItem = subBlocks[subBlocks.length - 1] offset = lastItem.offset + lastItem.duration if (block.rest) { if (lastItem.exercise === 'Rest') { lastItem.duration += block.rest offset += block.rest } else { subBlocks.push({ exercise: 'Rest', toplevelBlock: toplevelBlock || block.title, duration: block.rest, offset }) offset += block.rest } } blockArray.push(subBlocks) } return blockArray.flat() } else if (block.exercises) { const blockArray: IExerciseItem[] = [] const newItem = { exercise: block.exercises .map(exercise => exercise.repetitions > 1 ? `${exercise.repetitions}x ${exercise.name}` : exercise.name ) .join(' - '), duration: calculateDuration(block), video: block.video, description: block.description, toplevelBlock: toplevelBlock || block.title, offset } for (let i = 0; i < (block.repetitions || 1); i++) { blockArray.push({ ...newItem, offset }) offset += newItem.duration } return blockArray.flat() } }) .flat() } export function getTrainingTime(exercises: IExerciseItem[]) { return exercises.reduce( (accumulator, exercise) => accumulator + exercise.duration, 0 ) } export function polarToCartesian( centerX: number, centerY: number, radius: number, angleInDegrees: number ) { const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0 return { x: centerX + radius * Math.cos(angleInRadians), y: centerY + radius * Math.sin(angleInRadians) } } export function describeArc( x: number, y: number, radius: number, startAngle: number, endAngle: number ) { const start = polarToCartesian(x, y, radius, endAngle) const end = polarToCartesian(x, y, radius, startAngle) const largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1' const arcString = `M ${start.x} ${start.y} A ${radius} ${radius} 0 ${largeArcFlag} 0 ${end.x} ${end.y}` return arcString } export function limit(value: number, min: number, max: number) { return Math.min(Math.max(min, value), max) }