This commit is contained in:
zhangzheng
2026-02-27 18:35:40 +08:00
parent adef8b4cce
commit 1bb1fee5cc
265 changed files with 104076 additions and 92 deletions

View File

@@ -0,0 +1,124 @@
export const LetterBoxType = {
Vertical: 0,
Horizontal: 1
};
export class PointerCorrector {
/**
* @param {Number} videoWidth
* @param {Number} videoHeight
* @param {HTMLVideoElement} videoElem
*/
constructor(videoWidth, videoHeight, videoElem) {
this.reset(videoWidth, videoHeight, videoElem);
}
/**
* @param {Number[]} position MouseEvent.clientX, MouseEvent.clientY
* @returns {Number[]}
*/
map(position) {
var rect = this._videoElem.getBoundingClientRect();
const _position = new Array(2);
// (1) set origin point to zero
_position[0] = position[0] - rect.left;
_position[1] = position[1] - rect.top;
// (2) translate Unity coordinate system (reverse y-axis)
_position[1] = rect.height - _position[1];
// (3) add offset of letterbox
_position[0] -= this._contentRect.x;
_position[1] -= this._contentRect.y;
// (4) mapping element rectangle to video rectangle
_position[0] = _position[0] / this._contentRect.width * this._videoWidth;
_position[1] = _position[1] / this._contentRect.height * this._videoHeight;
return _position;
}
/**
* @param {Number} videoWidth
*/
setVideoWidth(videoWidth) {
this._videoWidth = videoWidth;
this._reset();
}
/**
* @param {Number} videoHeight
*/
setVideoHeight(videoHeight) {
this._videoHeight = videoHeight;
this._reset();
}
/**
* @param {HTMLVideoElement} videoElem
*/
setRect(videoElem) {
this._videoElem = videoElem;
this._reset();
}
/**
* @param {Number} videoWidth
* @param {Number} videoHeight
* @param {HTMLVideoElement} videoElem
*/
reset(videoWidth, videoHeight, videoElem) {
this._videoWidth = videoWidth;
this._videoHeight = videoHeight;
this._videoElem = videoElem;
this._reset();
}
get letterBoxType() {
const videoRatio = this._videoHeight / this._videoWidth;
var rect = this._videoElem.getBoundingClientRect();
const rectRatio = rect.height / rect.width;
return videoRatio > rectRatio ? LetterBoxType.Vertical : LetterBoxType.Horizontal;
}
get letterBoxSize() {
var rect = this._videoElem.getBoundingClientRect();
switch(this.letterBoxType) {
case LetterBoxType.Horizontal: {
const ratioWidth = rect.width / this._videoWidth;
const height = this._videoHeight * ratioWidth;
return (rect.height - height) * 0.5;
}
case LetterBoxType.Vertical: {
const ratioHeight = rect.height / this._videoHeight;
const width = this._videoWidth * ratioHeight;
return (rect.width - width) * 0.5;
}
}
throw 'invalid status';
}
/**
* Returns rectangle for displaying video with the origin at the left-top of the element.
* Not considered applying CSS like `object-fit`.
* @returns {Object}
*/
get contentRect() {
const letterBoxType = this.letterBoxType;
const letterBoxSize = this.letterBoxSize;
var rect = this._videoElem.getBoundingClientRect();
const x = letterBoxType == LetterBoxType.Vertical ? letterBoxSize : 0;
const y = letterBoxType == LetterBoxType.Horizontal ? letterBoxSize : 0;
const width = letterBoxType == LetterBoxType.Vertical ? rect.width - letterBoxSize * 2 : rect.width;
const height = letterBoxType == LetterBoxType.Horizontal ? rect.height - letterBoxSize * 2 : rect.height;
return {x: x, y: y, width: width, height: height};
}
_reset() {
this._contentRect = this.contentRect;
}
}