@mpxjs/webpack-plugin
Version:
mpx compile core
115 lines (100 loc) • 3.12 kB
text/typescript
/**
* Borrowed from open-source code: https://github.com/quidone/react-native-wheel-picker
* Special thanks to the authors for their contribution to the open-source community.
*/
export type Faces = {
index: number
deg: number
offsetY: number
opacity: number
scale: number
screenHeight: number
}
export const degToRad = (deg: number) => (Math.PI * deg) / 180
// Calculates the height of the element after rotating it relative to the user's screen.
const calcHeight = (degree: number, itemHeight: number) =>
itemHeight * Math.cos(degToRad(degree))
export const calcPickerHeight = (faces: Faces[], itemHeight: number) => {
if (faces.length === 7) {
return itemHeight * 5
}
return faces.reduce((r, v) => r + calcHeight(Math.abs(v.deg), itemHeight), 0)
}
export const calcHeightOffsets = (itemHeight: number) => {
const h1 = itemHeight / 2
const h2 = h1 + calcHeight(30, itemHeight)
const h3 = h2 + calcHeight(60, itemHeight)
return [h1, h2, h3]
}
export const createFaces = (
itemHeight: number,
visibleCount: number
): Faces[] => {
// e.g [30, 60, 90]
const getDegreesRelativeCenter = () => {
const maxStep = Math.trunc((visibleCount + 2) / 2) // + 2 because there are 2 more faces at 90 degrees
const stepDegree = 90 / maxStep
const result: number[] = []
for (let i = 1; i <= maxStep; i++) {
result.push(i * stepDegree)
}
return result
}
const getScreenHeightsAndOffsets = <T extends readonly number[]>(
degrees: T
): [T, T] => {
const screenHeights = degrees.map((deg) =>
calcHeight(deg, itemHeight)
) as unknown as T
const freeSpaces = screenHeights.map(
(screenHeight) => itemHeight - screenHeight
)
const offsets = freeSpaces.map((freeSpace, index) => {
let offset = freeSpace / 2
for (let i = 0; i < index; i++) {
offset += freeSpaces[i]
}
return offset
}) as unknown as T
return [screenHeights, offsets]
}
const getOpacity = (index: number) => {
const map: Record<number, number> = {
0: 0,
1: 0.8,
2: 0.9
}
return map[index] ?? Math.min(1, map[2] + index * 0.05)
}
const degrees = getDegreesRelativeCenter()
const [screenHeight, offsets] = getScreenHeightsAndOffsets(degrees)
const scales = [0.973, 0.9, 0.8]
return [
// top items
...degrees
.map<Faces>((degree, index) => {
return {
index: -1 * (index + 1),
deg: degree,
opacity: getOpacity(degrees.length - 1 - index),
offsetY: -1 * offsets[index],
scale: scales[index],
screenHeight: screenHeight[index]
}
})
.reverse(),
// center item
{ index: 0, deg: 0, opacity: 1, offsetY: 0, scale: 1, screenHeight: itemHeight },
// bottom items
...degrees.map<Faces>((degree, index) => {
return {
index: index + 1,
deg: -1 * degree,
opacity: getOpacity(degrees.length - 1 - index),
offsetY: offsets[index],
scale: scales[index],
screenHeight: screenHeight[index]
}
})
]
}