react-depth-of-field
Version:
A React component that applies a depth of field effect to its children
92 lines (84 loc) • 2.21 kB
JavaScript
/**
* React Depth of Field
* (c) 2018-present Thomas Trinca
*/
import React, { Component } from "react";
import PropTypes from "prop-types";
function createAnimationNode(
child,
nodeIndex,
currentIndex,
blurIncrement,
animationTime
) {
const style = {
filter: `blur(${Math.abs((nodeIndex - currentIndex) * blurIncrement)}px)`,
transition: `${animationTime}ms linear all`
};
return <div style={style}>{child}</div>;
}
export default class DepthOfField extends Component {
constructor(props) {
super(props);
this.state = {
currentIndex: this.props.focus
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.focus !== this.state.currentIndex) {
this.move(nextProps);
}
}
move({ focus, animationStep, animationTime }) {
const { currentIndex } = this.state;
if (currentIndex === focus) {
// Done, no need to move
this.isMoving = false;
return;
}
if (currentIndex > focus) {
// Move down the children
this.setState({ currentIndex: currentIndex - animationStep });
}
if (currentIndex < focus) {
// Move up the children
this.setState({ currentIndex: currentIndex + animationStep });
}
if (this.movingTimer) {
clearTimeout(this.movingTimer);
this.movingTimer = null;
}
this.movingTimer = setTimeout(() => {
this.move({ focus, animationStep, animationTime });
}, animationTime);
}
render() {
const { currentIndex } = this.state;
const { blurIncrement, animationTime, children } = this.props;
return (
<div className="depth-of-field-container">
{React.Children.map(children, (child, nodeIndex) =>
createAnimationNode(
child,
nodeIndex,
currentIndex,
blurIncrement,
animationTime
)
)}
</div>
);
}
}
DepthOfField.propTypes = {
animationTime: PropTypes.number,
animationStep: PropTypes.number,
blurIncrement: PropTypes.number,
focus: PropTypes.number.isRequired,
children: PropTypes.node.isRequired
};
DepthOfField.defaultProps = {
animationTime: 300,
animationStep: 1,
blurIncrement: 1
};