Math: How to reduce complexity of calculation for parallax scrolling

Transforming a progressing value to an alternating value

What I have

An input value ranging from 0 to 1

What I need

An alternating value ranging from 0 to 1 to 0 in intervals

The setup

I have a React application that uses parallax scrolling. While scrolling, I want to make elements on the screen move up and down like the bars of a carousel on a funfair.
I use a framework that gives me a progress value between 0 and 1. I need to turn this value to a value that rises from 0 to 1 to 0 smoothly and as many times as I define in a variable segments. In order to do that, I use a hook provided by the framework that uses an event listener for scrolling. That means that my function is called many times while scrolling which makes it costly.

Example

const segments = 5
const inputValues = [0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5 ... ]
const outputValues = [0, 0.5, 1, 0.5, 0, 0.5, 1, 0.5, 0, 0.5, 1 ... ]

My current solution

Vanilla JS:

function getAlternateValue(progress) { // progress value ranges from 0 to 1
        const segments = 5;
        const intervalProgress = progress % (1 / segments) * segments;
        const even = Math.floor(progress * segments) % 2 === 0;
        return even ? intervalProgress : 1 - intervalProgress;
}

JSX:

{items.map((item, idx) => (
  <div 
    key={idx}
    style={{
      transform: idx % 2 === 0 ? `translateY(${ -10 * getAlternateValue(scrollYprogress) }%)` : `translateY(${ 10 * getAlternateValue(scrollYprogress) }%)`
    }}> 
    ... 
  </div>
))}

What I’m looking for

I want to simplify the Vanilla JS function to make it less costly when called constantly by getting rid of the boolean variable.

Ok, life can be simple and time saving for people who listened in Math classes, I guess:

My simplified solution

function getAlternateValue(progress) {
    return Math.sin(31.42 * progress)
}
How I got the number 31.42
function getAlternateValue(progress) {
    const segments = 5;
    const circleAsRadiant = 360 * (Math.PI / 180) // Math.sin() expects radians
    const factor = circleAsRadiant * segments // 31.41592653589793
    return Math.sin(factor * progress)
}
2 Likes

That’s just Pi * 10.

2 Likes