fix vertical alignment

This commit is contained in:
Tamius Han 2024-12-30 03:05:47 +01:00
parent 25222c7310
commit cd89cca984
2 changed files with 65 additions and 58 deletions

View File

@ -278,7 +278,7 @@ class Resizer {
}
if ([AspectRatioType.Reset, AspectRatioType.Initial].includes(ar.type)) {
console.log('run level is UI only because aspect ratio type is', ar.type)
// console.log('run level is UI only because aspect ratio type is', ar.type)
this.eventBus.send('set-run-level', RunLevel.UIOnly);
} else {
this.eventBus.send('set-run-level', RunLevel.CustomCSSActive);
@ -307,7 +307,7 @@ class Resizer {
return;
}
let stretchFactors: {xFactor: number, yFactor: number, arCorrectionFactor?: number, ratio?: number} | any;
let stretchFactors: VideoDimensions | any;
// reset zoom, but only on aspect ratio switch. We also know that aspect ratio gets converted to
// AspectRatioType.Fixed when zooming, so let's keep that in mind
@ -419,10 +419,10 @@ class Resizer {
);
}
this.applyScaling(stretchFactors);
this.applyScaling(stretchFactors as VideoDimensions);
}
applyScaling(stretchFactors, options?: {noAnnounce?: boolean}) {
applyScaling(stretchFactors: VideoDimensions, options?: {noAnnounce?: boolean, ar?: Ar}) {
this.stretcher.chromeBugMitigation(stretchFactors);
// let the UI know
@ -430,7 +430,7 @@ class Resizer {
this.videoData.eventBus.send('announce-zoom', {x: stretchFactors.xFactor, y: stretchFactors.yFactor});
}
let translate = this.computeOffsets(stretchFactors);
let translate = this.computeOffsets(stretchFactors, options?.ar);
this.applyCss(stretchFactors, translate);
}
@ -457,7 +457,7 @@ class Resizer {
if(!this.videoData.player || !this.videoData.player.element) {
return;
}
// dont allow weird floats
// don't allow weird floats
this.videoAlignment.x = VideoAlignmentType.Center;
// because non-fixed aspect ratios reset panning:
@ -501,14 +501,14 @@ class Resizer {
setVideoAlignment(videoAlignmentX: VideoAlignmentType, videoAlignmentY?: VideoAlignmentType) {
// if aspect ratio is unset or initial, CSS fixes are inactive by design.
// because of that, we need to set a manual aspect ratio first.
console.log('last aspect ratio:', this.lastAr);
if (!this.lastAr) {
console.warn('[Resizer.js::setVideoAlignment] Aspect ratio not set. This is illegal. This function will do nothing.');
if (!this.lastAr?.ratio) {
this.setAr({
type: AspectRatioType.Fixed,
type: AspectRatioType.AutomaticUpdate,
ratio: this.getFileAr()
});
}
if ([AspectRatioType.Reset, AspectRatioType.Initial].includes(this.lastAr.type)) {
if (this.lastAr.ratio) {
this.lastAr.type = AspectRatioType.Fixed;
@ -659,36 +659,6 @@ class Resizer {
}
}
computeCroppedAreas(stretchFactors) {
// PSA: offsetWidth and offsetHeight DO NOT INCLUDE
// ZOOM APPLIED THROUGH THE MAGIC OF CSS TRANSFORMS
const sourceWidth = this.videoData.video.offsetWidth;
const sourceHeight = this.videoData.video.offsetHeight;
// this is the size of the video AFTER zooming was applied but does
// not account for cropping. It may be bigger than the player in
// both dimensions. It may be smaller than player in both dimensions
const postZoomWidth = sourceWidth * stretchFactors.xFactor;
const postZoomHeight = sourceHeight * stretchFactors.yFactor;
// this is the size of the video after crop is applied
const displayedWidth = Math.min(this.videoData.player.dimensions.width, postZoomWidth);
const displayedHeight = Math.min(this.videoData.player.dimensions.height, postZoomHeight);
// these two are cropped areas. Negative values mean additional
// letterboxing or pillarboxing. We assume center alignment for
// the time being - we will correct that later if need be
const croppedX = (postZoomWidth - displayedWidth) * 0.5;
const croppedY = (postZoomHeight - displayedHeight) * 0.5;
return {
sourceVideoDimensions: {width: sourceWidth, height: sourceHeight},
postZoomVideoDimensions: {width: postZoomWidth, height: postZoomHeight},
displayedVideoDimensions: {width: displayedWidth, height: displayedHeight},
crop: {left: croppedX, top: croppedY},
};
}
/**
* Sometimes, sites (e.g. new reddit) will guarantee that video fits width of its container
* and let the browser figure out the height through the magic of height:auto. This is bad,
@ -716,14 +686,12 @@ class Resizer {
}
private _computeOffsetsRecursionGuard: boolean = false;
computeOffsets(stretchFactors: VideoDimensions){
computeOffsets(stretchFactors: VideoDimensions, ar?: Ar){
this.logger.log('info', 'debug', "[Resizer::computeOffsets] <rid:"+this.resizerId+"> video will be aligned to ", this.videoAlignment);
const {realVideoWidth, realVideoHeight, marginX, marginY} = this.computeVideoDisplayedDimensions();
const {postZoomVideoDimensions, displayedVideoDimensions, crop} = this.computeCroppedAreas(stretchFactors);
// correct any remaining element size discrepencies (applicable only to certain crop strategies!)
// correct any remaining element size discrepancies (applicable only to certain crop strategies!)
// NOTE: it's possible that we might also need to apply a similar measure for CropPillarbox strategy
// (but we'll wait for bug reports before doing so).
// We also don't compensate for height:auto if height is provided via element style
@ -732,7 +700,11 @@ class Resizer {
stretchFactors.cropStrategy === CropStrategy.CropLetterbox
&& (!stretchFactors.styleHeightCompensationFactor || stretchFactors.styleHeightCompensationFactor === 1)
) {
autoHeightCompensationFactor = this.computeAutoHeightCompensationFactor(realVideoWidth, realVideoHeight, this.videoData.player.dimensions.width, this.videoData.player.dimensions.height, 'height');
autoHeightCompensationFactor = this.computeAutoHeightCompensationFactor(
realVideoWidth, realVideoHeight,
this.videoData.player.dimensions.width, this.videoData.player.dimensions.height,
'height'
);
stretchFactors.xFactor *= autoHeightCompensationFactor;
stretchFactors.yFactor *= autoHeightCompensationFactor;
}
@ -759,17 +731,21 @@ class Resizer {
}
} else {
// correct horizontal alignment according to the settings
if (this.videoAlignment.x == VideoAlignmentType.Left) {
translate.x += alignXOffset;
} else if (this.videoAlignment.x == VideoAlignmentType.Right) {
translate.x -= alignXOffset
if (!stretchFactors.preventAlignment?.x) {
if (this.videoAlignment.x == VideoAlignmentType.Left) {
translate.x += stretchFactors?.relativeCropLimits?.left ? (this.videoData.player.dimensions.width * stretchFactors.relativeCropLimits.left): alignXOffset;
} else if (this.videoAlignment.x == VideoAlignmentType.Right) {
translate.x -= stretchFactors?.relativeCropLimits?.left ? (this.videoData.player.dimensions.width * stretchFactors.relativeCropLimits.left): alignXOffset
}
}
// correct vertical alignment according to the settings
if (this.videoAlignment.y == VideoAlignmentType.Top) {
translate.y += alignYOffset;
} else if (this.videoAlignment.y == VideoAlignmentType.Bottom) {
translate.y -= alignYOffset;
if (!stretchFactors.preventAlignment?.y) {
if (this.videoAlignment.y == VideoAlignmentType.Top) {
translate.y += stretchFactors?.relativeCropLimits?.top ? (this.videoData.player.dimensions.height * stretchFactors?.relativeCropLimits?.top): alignYOffset;
} else if (this.videoAlignment.y == VideoAlignmentType.Bottom) {
translate.y -= stretchFactors?.relativeCropLimits?.top ? (this.videoData.player.dimensions.height * stretchFactors?.relativeCropLimits?.top): alignYOffset;
}
}
}

View File

@ -29,6 +29,14 @@ export type VideoDimensions = {
styleHeightCompensationFactor?: number;
actualWidth?: number;
actualHeight?: number;
relativeCropLimits?: {
top: number;
left: number;
},
preventAlignment?: {
x: boolean,
y: boolean
}
}
// does video size calculations for zooming/cropping
@ -92,7 +100,7 @@ class Scaler {
return null;
}
calculateCrop(ar: {type: AspectRatioType, ratio?: number}) {
calculateCrop(ar: {type: AspectRatioType, ratio?: number}): VideoDimensions | {error: string, [x: string]: any} {
/**
* STEP 1: NORMALIZE ASPECT RATIO
*
@ -142,7 +150,16 @@ class Scaler {
}
if (ar.type === AspectRatioType.Reset){
return {xFactor: arCorrectionFactor, yFactor: arCorrectionFactor, arCorrectionFactor: arCorrectionFactor};
return {
xFactor: arCorrectionFactor,
yFactor: arCorrectionFactor,
arCorrectionFactor: arCorrectionFactor,
relativeCropLimits: {
top: 0,
left: 0,
}
};
}
// handle fuckie-wuckies
@ -175,7 +192,11 @@ class Scaler {
actualWidth: 0, // width of the video (excluding pillarbox) when <video> tag height is equal to width
actualHeight: 0, // height of the video (excluding letterbox) when <video> tag height is equal to height
arCorrectionFactor: arCorrectionFactor,
styleHeightCompensationFactor: heightCompensationFactor
styleHeightCompensationFactor: heightCompensationFactor,
relativeCropLimits: {
top: 0,
left: 0
}
}
this.calculateCropCore(videoDimensions, ar.ratio, streamAr, playerAr)
@ -223,14 +244,24 @@ class Scaler {
}
}
this.logger.log('info', 'scaler', "[Scaler::calculateCrop] Crop factor calculated — ", videoDimensions.xFactor);
// correct the scale factor
if (videoDimensions.arCorrectionFactor) {
videoDimensions.xFactor *= videoDimensions.arCorrectionFactor;
videoDimensions.yFactor *= videoDimensions.arCorrectionFactor;
}
// Add crop limits — needed for vertical alignment in order to
const letterboxRatio = (1 - (playerAr / ar));
videoDimensions.relativeCropLimits = {
top: ar > streamAr ? ( ar > playerAr ? (letterboxRatio * -0.5) : 0) : 0,
left: ar < streamAr ? ( ar < playerAr ? (-0.5 / letterboxRatio) : 0) : 0,
}
videoDimensions.preventAlignment = {
x: ar > playerAr, // video is wider than player, so it's full width already
y: ar < playerAr, // video is narrower than player, so it's full height already
}
return videoDimensions;
}
}