Skip to content

Instantly share code, notes, and snippets.

@jaredpalmer
Last active December 19, 2017 14:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaredpalmer/92adbbd499713d016994547a2e023e4e to your computer and use it in GitHub Desktop.
Save jaredpalmer/92adbbd499713d016994547a2e023e4e to your computer and use it in GitHub Desktop.
Vjeux's 2013 Viewport Image Resizer as a Render Prop
import * as React from 'react';
import { throttle } from 'common/utils/throttle';
export interface ScaleToViewportProps {
height: number;
width: number;
verticalPadding: number;
horizontalPadding: number;
throttle: number;
render: (props: ScaleToViewportState) => React.ReactNode;
}
export interface ScaleToViewportState {
height?: number;
width?: number;
}
export class ScaleToViewport extends React.Component<
ScaleToViewportProps,
ScaleToViewportState
> {
state: ScaleToViewportState = {};
componentDidMount() {
window.addEventListener('resize', this.throttledResize);
this.sizePhoto(null, this.props);
}
componentWillUnmount() {
window.removeEventListener('resize', this.throttledResize);
}
componentWillReceiveProps(
nextProps: ScaleToViewportProps,
nextState: ScaleToViewportState
) {
if (
nextProps.height !== this.props.height ||
nextProps.width !== this.props.width
) {
this.setState({ height: undefined, width: undefined });
this.sizePhoto(null, nextProps);
}
}
/**
* Resize photo using @Vjeux's / Facebook's 2013 technique
* @see http://blog.vjeux.com/2013/image/css-container-and-cover.html
*/
sizePhoto = (e: any, props?: ScaleToViewportProps) => {
const { height, width, verticalPadding, horizontalPadding } =
props || this.props;
// We want to offset by the height of the Navbar / Appbar
const viewportHeight = window.innerHeight - verticalPadding;
const viewportWidth = window.innerWidth - horizontalPadding;
// Aspect ratio of the viewport
const viewportRatio = viewportWidth / viewportHeight;
// Aspect ratio of the image
const imageRatio = width / height;
let imageHeight, imageWidth;
// calculated sizes
if (imageRatio <= viewportRatio) {
imageWidth = Math.min(viewportHeight * imageRatio, width);
imageHeight = Math.min(viewportHeight, height);
} else {
imageWidth = Math.min(viewportWidth, width);
imageHeight = Math.min(viewportWidth / imageRatio, height);
}
this.setState({ width: imageWidth, height: imageHeight });
};
throttledResize = throttle(this.sizePhoto, this.props.throttle);
render() {
return this.state.height && this.state.width
? (this.props.render as any)(this.state)
: null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment