Hone logo
Hone
Problems

Animated Vue.js Counter with Dynamic Interval

Build an animated Vue.js component that displays a counter which increments at a user-defined interval. This challenge focuses on integrating JavaScript animation techniques within a Vue.js environment, allowing for dynamic control over animation speed.

Problem Description

You are tasked with creating a Vue.js component called AnimatedCounter. This component should display a numerical counter that gradually increases from 0 to a specified target value. The speed at which the counter increments should be controlled by a duration prop, which dictates the total time in milliseconds for the animation to complete. The counter's current value should be displayed as it animates.

Key Requirements:

  • The component must accept two props:
    • target: A number representing the final value the counter should reach.
    • duration: A number representing the total animation time in milliseconds.
  • The counter should start at 0 and animate smoothly towards the target value.
  • The animation should be driven by JavaScript's requestAnimationFrame for smooth, efficient rendering.
  • The current value of the counter should be updated and displayed in real-time during the animation.
  • If the target or duration props change while an animation is in progress, the existing animation should be stopped, and a new one should begin with the updated values.

Expected Behavior:

When the AnimatedCounter component is mounted or when its target or duration props change:

  1. An animation should begin.
  2. The displayed number should increment incrementally.
  3. The total time taken to reach the target value should be approximately equal to the duration prop.
  4. The counter should display the target value upon completion.

Edge Cases:

  • target is 0: The counter should immediately display 0.
  • duration is 0 or negative: The counter should immediately display the target value.
  • target is a negative number: The counter should animate downwards to the negative target.
  • Rapidly changing target or duration props: The component should handle these changes gracefully by restarting the animation.

Examples

Example 1:

Input Props:
target: 100
duration: 2000 (milliseconds)

Expected Output (Visual):
The number displayed will animate from 0 to 100 over approximately 2 seconds.
Intermediate values might include: 0, 10, 25, 40, 60, 80, 100 (depending on animation steps).

Example 2:

Input Props:
target: 50
duration: 1000 (milliseconds)

Expected Output (Visual):
The number displayed will animate from 0 to 50 over approximately 1 second.

Example 3: Dynamic Prop Change

Initial State:
target: 100
duration: 2000

After 1 second, props are updated:
target: 50
duration: 1000

Expected Output (Visual):
The counter starts animating towards 100. After 1 second (it might be around 50), the animation resets. It then begins animating from its current value (around 50) towards the new target of 50, completing within the new duration of 1000ms (minus the time already elapsed if the calculation is sophisticated, or simply restarting from 0 towards 50). For simplicity, restarting from 0 towards the new target is acceptable.

Constraints

  • The target prop will be an integer.
  • The duration prop will be a non-negative integer.
  • Animations should aim for a smooth visual update rate, ideally matching the browser's refresh rate (e.g., 60 frames per second).
  • Avoid using CSS transitions or Vue's built-in transition components for the numerical animation itself; the core animation logic must be implemented using JavaScript requestAnimationFrame.

Notes

  • requestAnimationFrame is the preferred method for creating performant JavaScript animations as it synchronizes with the browser's rendering cycle.
  • Consider how to calculate the increment amount per frame based on the total target value and duration.
  • You'll need to manage the animation state (e.g., whether it's running, the start time, current progress) using component data properties.
  • A common approach is to record the start time of the animation and then calculate the elapsed time in each requestAnimationFrame callback.
  • Remember to clear the animation frame when the component is unmounted or when props change to prevent memory leaks and unexpected behavior.
Loading editor...
javascript