Created
March 10, 2025 05:38
Calculates an ideal viewBox that centers on a target object
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Calculates an ideal viewBox that centers on a target object | |
* @param objectBBox - Bounding box of the target object | |
* @param assetWidth - Width of the asset | |
* @param assetHeight - Height of the asset | |
* @param targetCoverage - target percentage of the viewport width or height the object should take up | |
* @param viewportAspectRatio - Aspect ratio of the viewport | |
* @param minFit - Minimum width and height of the viewport | |
* @returns - [offsetX, offsetY, viewportWidth, viewportHeight] | |
*/ | |
export function perfectFit( | |
objectBBox: [number, number, number, number], | |
assetWidth: number, | |
assetHeight: number, | |
targetCoverage = 0.5, | |
viewportAspectRatio = assetWidth / assetHeight, | |
minFit = Math.min(assetWidth, assetHeight, 100) | |
): [number, number, number, number] { | |
const sliceAssetWidth = Math.min( | |
assetHeight * viewportAspectRatio, | |
assetWidth | |
); | |
const sliceAssetHeight = Math.min( | |
assetWidth / viewportAspectRatio, | |
assetHeight | |
); | |
// target width/height at least minFit and at most slice asset width/height | |
const targetWidth = Math.min( | |
Math.max(minFit, (objectBBox[2] - objectBBox[0]) / targetCoverage), | |
sliceAssetWidth | |
); | |
const targetHeight = Math.min( | |
Math.max(minFit, (objectBBox[3] - objectBBox[1]) / targetCoverage), | |
sliceAssetHeight | |
); | |
// viewport zoom in on target width/height but meets aspect ratio | |
const viewportWidth = Math.max( | |
targetHeight * viewportAspectRatio, | |
targetWidth | |
); | |
const viewportHeight = Math.max( | |
targetWidth / viewportAspectRatio, | |
targetHeight | |
); | |
// offset viewport to center on target | |
const offsetX = Math.min( | |
Math.max(0, (objectBBox[0] + objectBBox[2] - viewportWidth) / 2), | |
assetWidth - viewportWidth | |
); | |
const offsetY = Math.min( | |
Math.max(0, (objectBBox[1] + objectBBox[3] - viewportHeight) / 2), | |
assetHeight - viewportHeight | |
); | |
return [offsetX, offsetY, viewportWidth, viewportHeight]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment