react-scroll-animator
v0.0.7
Published
System for creating animations based on scroll location in react
Downloads
23
Readme
react-scroll-animator
This package aims to provide a minimal set of generic tools that allow complicated scroll animation sequences to be defined in a concise way using the power of React. The progress of these animations is determined by the scroll location of the page.
Please execuse the looks of the examples to follow, little time was spent on their appearance, the main goal was to show the features.
Installation
npm install react-scroll-animator --save
import {Animator} from "react-scroll-animator";
Usage
The core aspect of scroll-animator is the actual Animator component. This component allows you to define multiple sections of the animation, and at what scroll offset, relative to the previous section, they should start. The corresponding variables will increase from 0-1 in sequence, as the user scrolls the specified distance.
Consider this basic example, and its result
{/* Create an animator instance and specify the animation sections and their ranges */}
<Animator sections={[{$margin: 300}, {$text: 200}]}>
{({$margin, $text}) => (
// Create the content to show, uusing the passed section variables whose values range from 0 to 1
<div
style={{
backgroundColor: "orange",
position: "relative",
top: 800,
height: 20,
/* Use map to map the values from 0-200 and apply easing (argument 0 may be left out) */
marginLeft: map($margin, 0, 200, {easing: "easeInOutSin"})
}}>
{/* Use the map function to map 0-1 to the integers 0-lengthOfText */}
{text.substring(0, map($text, text.length, {digits: 0}))}
</div>
)}
</Animator>
Map
The package contains a simple map function, that takes 4 arguments, of which the second is optional:
map(progress, start, end, options);
progress: value from 0-1
start: the value that progress 0 should map to (optional, defaults to 0)
end: the value that progress 1 should map to
options: {
digits: The number of decimals to round to (no rounding by default)
easing: The name of a easing function to apply (linear by default)
}
See the available easing methods here
Once
Animations that you don't want to reset when the user scrolls back up, can use the second callbackParameter. This parameter will be the greatest value that each section has had so far.
<Animator sections={[{$margin: 300}, {$text: 200}]}>
{({$margin, $text}, {$margin: $marginMax, $text: $textMax}) => (
// $marginMax will be the largetst value for $margin that has been passed so far, the same applies to $textMax and $text
<div>...</div>
)}
</Animator>
Latest
latest can be used to pick the latest value from a set of variables, this way you can animate the same property, using multiple sections. This is usefull when you want a break in a transition, or reverse it at some moment.
latest(sections, values);
sections: A list of the section variables that map to the values
values: A list of values to use to return the latest from
<div
style={{
marginLeft: latest(
[$left1, $left2],
[
map($left1, 0, 200),
map($left2, 200, 400),
]
)
}}>
...
</div>
Stagger
The animator component also allows sections to define an offset, in order to start a section some delay before or after the previous one has finished.
<Animator
sections={[
{$s1: 300},
{$s2: 300, offset: -250},
{$s3: 300, offset: -250},
{$s4: 300, offset: -250},
{$s5: 300, offset: -250},
{$d: 300},
]}>
...
</Animator>
Parallel
The animator component allows sequences of sections to be executed in parallel, by putting a sequence (array of sections) in an array. This can be useful when animating different independent components that move at the same time.
<Animator
sections={[
{$start: 300},
[
[{$1s1: 150}, {$2s1: 100}, {$3s1: 100}],
[{$1s2: 100}, {$2s2: 100}, {$3s2: 100}],
],
{$end: 100}
]}>
...
</Animator>
Css
As one might expect, this library can easily be used together with css animations. One can easily activate the animation at a certain point by adding or removing a class at some threshold.
<div className={"box1" + ($box1 == 1 ? " active" : "")} />
Pin
When you want an element to only scroll at certain moments on the page, you can make use of the Pin component. This component will only scroll during the passed sections.
The Animator component allows for a section's range to be defined as a start
and end
value, such that the actual animation scroll distance will be its delta. And the Pin component can then read these start
and end
values to determine what locations to scroll to.
const h = document.body.clientHeight;
<Animator
sections={[
{$scrollIn: [h, h / 2]},
{$something: 300},
{$scrollOut: [h / 2, -30]}
]}>
{({$scrollIn, $something, $scrollOut}) => (
<Pin sections={{$scrollIn, $scrollOut}}>
...
</Pin>
)}
</Animator>
Page offset
When you want to add an element without a pin to come into view at the moment a section starts, you can use the third callback parameter. This parameter will simply be the sum of the ranges of sections that came before.
const h = document.body.clientHeight;
<Animator
sections={[
{$scrollIn: [h, h / 2]},
{$something: 300},
{$scrollOut: [h / 2, -30]}
]}>
{({$scrollIn, $something, $scrollOut}, _, {$scrollInOffset, $somethingOffset, $scrollOutOffset}) => (
<div>...</div>
)}
</Animator>
in the example above, the offset variables will have values 0, h/2, h/2+300
respectively.
Reference
Since you probably don't want to hardcode in locations for elements (assuming you want a design that's at least somewhat responsive) a method for creating element references is provided. This allows you to wrap your element in a Reference
component, and retrieve the location and size of that reference.
<RefCreator>
{([Ref]) => (
<div>
{/* Create a refence element */}
<Ref>
<div
style={{display: "inline-block"}}>
Hello text
<br /> test
</div>
</Ref>
{/* Create an element with the same size as the reference element*/}
<div
style={{
width: Ref.width,
height: Ref.height,
display: "inline-block"
}}>
Yes
</div>
</div>
)}
</RefCreator>
The RefCreator
has one property count
, which defines the number of Reference components you want to retrieve in the passed array.
Each reference will contain the variables x
, y
, width
, height
and the referenced element element
, where the x
and y
are relative to the page. They also contain a method update
for updating these variables, since they won't update as the element changes, and refresh
to call the render method of RefCreator
again, in order to update all dependencies on the reference.
Templating
These references can be used very neatly to create a template of what you want your page in different 'scenes' to look like, while allowing for a responsive design, and then make complex transitions between these.
In the example below, try making the view port small enough such that the 2 containers don't fit next to each other, the animation will still work properly.
This can be seen in this example and its code
Contributing
Any contributions to the package are welcome. Currently the main points of interests however are:
- Making type declaration cleaner, and trying to support the nested parallel sequences
- Trying to improve performance by only recomputing percenteges that have changed
- Making nicer looking examples, and potentially a proper website