fix(web): face editor coordinates on a not-yet-loaded video (#31083)

This commit is contained in:
bo0tzz 2026-08-28 11:20:54 +02:00 committed by GitHub
parent c1a88dd9a3
commit 1a8fcf1b9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 27 additions and 2 deletions

View file

@ -76,6 +76,7 @@
let videoPlayer: HTMLVideoElement | undefined = $state();
let isLoading = $state(true);
let hasLoadedMetadata = $state(false);
let assetFileUrl = $derived.by(() => {
if (featureFlagsManager.value.realtimeTranscoding) {
return getAssetHlsUrl(assetId);
@ -241,6 +242,7 @@
$effect(() => {
// reactive on `assetFileUrl` changes
hasLoadedMetadata = false;
if (videoPlayer && assetFileUrl) {
hasFocused = false;
rebuildCount = 0;
@ -385,6 +387,7 @@
{...useSwipe(onSwipe)}
class="h-full object-contain"
oncanplay={(e: Event) => handleCanPlay(e.currentTarget as HTMLVideoElement)}
onloadedmetadata={() => (hasLoadedMetadata = true)}
onended={onVideoEnded}
onseeking={onSeeking}
onplaying={(e: Event) => {
@ -410,6 +413,7 @@
{...useSwipe(onSwipe)}
class="h-full object-contain"
oncanplay={(e) => handleCanPlay(e.currentTarget)}
onloadedmetadata={() => (hasLoadedMetadata = true)}
onended={onVideoEnded}
onseeking={onSeeking}
onplaying={(e) => {
@ -489,7 +493,7 @@
</div>
{/if}
{#if assetViewerManager.isFaceEditMode && videoPlayer}
{#if assetViewerManager.isFaceEditMode && videoPlayer && hasLoadedMetadata}
<FaceEditor htmlElement={videoPlayer} {containerWidth} {containerHeight} {assetId} />
{/if}
{/if}

View file

@ -29,7 +29,12 @@ export type ContentMetrics = {
offsetY: number;
};
const isMeasurable = (dimensions: Size) => dimensions.width > 0 && dimensions.height > 0;
export const scaleToCover = (dimensions: Size, container: Size): Size => {
if (!isMeasurable(dimensions)) {
return { width: 0, height: 0 };
}
const scaleX = container.width / dimensions.width;
const scaleY = container.height / dimensions.height;
const scale = Math.max(scaleX, scaleY);
@ -40,6 +45,9 @@ export const scaleToCover = (dimensions: Size, container: Size): Size => {
};
export const scaleToFit = (dimensions: Size, container: Size): Size => {
if (!isMeasurable(dimensions)) {
return { width: 0, height: 0 };
}
const scaleX = container.width / dimensions.width;
const scaleY = container.height / dimensions.height;
const scale = Math.min(scaleX, scaleY);

View file

@ -1,4 +1,4 @@
import { scaleToFit } from '$lib/utils/container-utils';
import { scaleToCover, scaleToFit } from '$lib/utils/container-utils';
describe('scaleToFit', () => {
const tests = [
@ -51,4 +51,17 @@ describe('scaleToFit', () => {
expect(scaleToFit(dimensions, container)).toEqual(expected);
});
}
const unmeasurable = [
{ name: 'zero width and height', dimensions: { width: 0, height: 0 } },
{ name: 'zero width', dimensions: { width: 0, height: 1000 } },
{ name: 'zero height', dimensions: { width: 1000, height: 0 } },
];
for (const { name, dimensions } of unmeasurable) {
it(`should return an empty size for ${name}`, () => {
expect(scaleToFit(dimensions, { width: 500, height: 500 })).toEqual({ width: 0, height: 0 });
expect(scaleToCover(dimensions, { width: 500, height: 500 })).toEqual({ width: 0, height: 0 });
});
}
});