-
Notifications
You must be signed in to change notification settings - Fork 0
/
letterbox.ts
106 lines (98 loc) · 2.94 KB
/
letterbox.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
type Size = {width: number, height: number}
type Position = {top: number, left: number}
type Frame = Position & {bottom: number, right: number}
export type Box = Frame & Size
export type Letterbox = Box & { bars: Box[] }
export default letterbox
function letterbox(aspect: number, container: Size): Letterbox {
const containerAspect = container.width / container.height
if (containerAspect > aspect) {
// Container is flatter than content, lock to container
// height and letterbox on left and right
const width = aspect * container.height
const left = (container.width - width) / 2
const height = container.height
const top = 0
return letterboxFrom(container, {
top,
left,
width,
height,
})
}
// Container is taller than content, lock to container
// width and letterbox on top and bottom
const height = container.width / aspect
const top = (container.height - height) / 2
const width = container.width
const left = 0
return letterboxFrom(container, {top, left, width, height})
}
const letterboxFrom = (container: Size, box: Size & Position): Letterbox => ({
...boxFrom(container, box),
bars: subtract(container, box),
})
const boxFrom = (container: Size, box: Size & Position): Box => ({
...box,
bottom: container.height - (box.top + box.height),
right: container.width - (box.left + box.width),
})
const subtract = (container: Size, box: Size & Position): Box[] => {
if (!box.top) {
const width = (container.width - box.width) / 2
return [
boxFrom(container, {
top: 0,
left: 0,
width,
height: container.height
}),
boxFrom(container, {
top: 0,
left: container.width - width,
width,
height: container.height
}),
]
}
const height = (container.height - box.height) / 2
return [
boxFrom(container, {
top: 0, left: 0,
width: container.width,
height,
}),
boxFrom(container, {
top: container.height - height,
left: 0,
width: container.width,
height,
})
]
}
const px = (px: number) => `${px}px`
const None = () => {}
export function applyLetterbox(aspect=16 / 9, onReshape: (box: Box) => void = None) {
function onResize() {
const box =
letterbox(aspect, {width: innerWidth, height: innerHeight})
setCSSPropertiesFrom(box)
onReshape(box)
}
window.addEventListener('resize', onResize)
onResize()
onDispose(() => window.removeEventListener('resize', onResize))
}
const setCSSPropertiesFrom = (src: any, prefix='--letterbox-', element=document.body) =>
Object.keys(src).forEach(k =>
typeof src[k] === 'object'
? setCSSPropertiesFrom(src[k], prefix + k + '-', element)
:
typeof src[k] === 'number'
? element.style.setProperty(prefix + k, px(src[k]))
:
element.style.setProperty(prefix + k, src[k])
)
function onDispose(run) {
;(module as any).hot && (module as any).hot.dispose(run)
}