Skip to content

Instantly share code, notes, and snippets.

@bobvanderlinden
Created September 25, 2017 18:47
Show Gist options
  • Select an option

  • Save bobvanderlinden/8422f92730afb8d6c29d635c6330ba53 to your computer and use it in GitHub Desktop.

Select an option

Save bobvanderlinden/8422f92730afb8d6c29d635c6330ba53 to your computer and use it in GitHub Desktop.
FrameLayout React component: scale content while maintaining aspect ratio
.framelayout {
margin: 0;
padding: 0;
border: 0;
display: flex;
align-items: center;
justify-content: center;
}
.framelayout > * {
position: absolute;
}
import React from 'react'
import ReactResizeDetector from 'react-resize-detector'
import './FrameLayout.css'
interface FrameLayoutProps {
inheritParentSize?: boolean,
aspectRatio?: number,
children?: any,
[key: string]: any
}
export class FrameLayout extends React.Component<FrameLayoutProps, {}> {
ref: HTMLElement
parentWidth: number
parentHeight: number
previousUpdate: {
width: number,
height: number,
child: HTMLElement
} | null = null
constructor () {
super()
this.handleResize = this.handleResize.bind(this)
this.handleRef = this.handleRef.bind(this)
}
get child (): HTMLElement {
const ref = this.ref
return ref && (ref.children[ref.children.length - 1] as HTMLElement)
}
handleRef (ref) {
this.ref = ref
this.updateSize()
}
handleResize (width, height) {
this.parentWidth = width
this.parentHeight = height
this.updateSize()
}
updateSize () {
const child = this.child
const parentWidth = this.parentWidth
const parentHeight = this.parentHeight
const canUpdateSize = child && (parentWidth || parentHeight)
if (!canUpdateSize) {
return
}
const needsUpdate = !this.previousUpdate || (
this.previousUpdate.child !== child ||
this.previousUpdate.width !== parentWidth ||
this.previousUpdate.height !== parentHeight
)
if (!needsUpdate) {
return
}
this.previousUpdate = {
child: child,
width: parentWidth,
height: parentHeight
}
// We can presume the parentNode is actually a <div>
const desiredAspectRatio = this.props.aspectRatio || 1
const parentAspectRatio = parentWidth / parentHeight
const isWiderThanParent = parentAspectRatio > desiredAspectRatio
const newWidth = isWiderThanParent
? parentHeight * desiredAspectRatio
: parentWidth
const newHeight = isWiderThanParent
? parentHeight
: parentWidth / desiredAspectRatio
child.style.width = `${newWidth}px`
child.style.height = `${newHeight}px`
}
componentDidUpdate () {
this.updateSize()
}
render () {
const {
inheritParentSize = false,
aspectRatio,
children,
...attrs
} = this.props
return (
<div
{...attrs}
ref={this.handleRef}
className={[
'framelayout',
inheritParentSize && 'inherit-parent-size',
aspectRatio && 'fixed-aspect-ratio',
attrs.className
].filter(Boolean).join(' ')}>
<ReactResizeDetector handleWidth handleHeight onResize={this.handleResize} />
{children}
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment