mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-14 06:16:20 -06:00
Reported as "rotation doesn't work correctly". It is a geometry bug, not a rendering one, which is why it reads as mysterious. #playerContainer is pinned `inset: 0`. Rotation set width:100vh, height:100vw and rotate(90deg) — leaving the box in the TOP-LEFT corner and spinning it about its own centre rather than the viewport's. On a 1920x1080 panel the content landed at x -420..1500, y 420..1500 against a viewport of 0..1920, 0..1080: correctly rotated, wrongly placed, cropped on two edges. Tizen already did this correctly — top/left 50% plus translate(-50%,-50%) — and Android does the equivalent with translationX/Y of (w-h)/2. The web player was the odd one out, and BrightSign inherited it on top of its own hardware-plane problem. The rule now lives in server/lib/orientation-style.js, served to the player from its single source, with the arithmetic pinned by tests that compute where the rotated box actually lands on 16:9 and 5:4 panels. Three things those tests hold that are easy to get wrong: the translate must come BEFORE the rotate (transforms apply right-to-left, so reversing them rotates the correction too), 180 must NOT swap dimensions (the box already fits; swapping letterboxes it), and landscape must clear EVERY property the rotated state set (a half-reset leaves the container stuck at 100vh wide, so rotation appears to persist after switching back). 1074 pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
72 lines
2.9 KiB
JavaScript
72 lines
2.9 KiB
JavaScript
'use strict';
|
|
|
|
/*
|
|
* The CSS needed to rotate a full-screen player container.
|
|
*
|
|
* This looks trivial and is not, because rotating a box does NOT move it. The web player set
|
|
* `width:100vh; height:100vw` and `rotate(90deg)` on a container pinned `inset: 0`, which leaves
|
|
* the box in the top-left corner and spins it about ITS OWN centre — not the viewport's. On a
|
|
* 1920x1080 panel that put the content 420px off-screen to the left and 420px off the bottom:
|
|
* portrait content, correctly rotated, in the wrong place and cropped on two edges.
|
|
*
|
|
* The box has to be centred on the viewport BEFORE it is turned. Tizen already does this
|
|
* (`top:50%; left:50%; translate(-50%,-50%) rotate()`), and Android does the equivalent with
|
|
* translationX/Y offsets of (w-h)/2 — so the web player was the odd one out.
|
|
*
|
|
* Returned as plain style values so the same rule can be asserted in a test without a browser,
|
|
* and shared rather than re-derived per player. Every property the rotated state sets is also
|
|
* cleared by the landscape state: a half-reset leaves a container stuck at 100vh wide.
|
|
*/
|
|
|
|
const ROTATION_DEG = {
|
|
'landscape': 0,
|
|
'portrait': 90,
|
|
'landscape-flipped': 180,
|
|
'portrait-flipped': 270,
|
|
};
|
|
|
|
/**
|
|
* @param {string} orientation landscape | portrait | landscape-flipped | portrait-flipped
|
|
* @returns {{transform:string,width:string,height:string,top:string,left:string,transformOrigin:string}}
|
|
* Values to assign directly onto element.style. Empty string means "clear it".
|
|
*/
|
|
function orientationStyle(orientation) {
|
|
const deg = ROTATION_DEG[orientation];
|
|
|
|
// Unknown orientation falls back to landscape rather than throwing: a bad value from the server
|
|
// should leave a readable screen, not a blank or sideways one.
|
|
if (!deg) {
|
|
return { transform: '', width: '', height: '', top: '', left: '', transformOrigin: '' };
|
|
}
|
|
|
|
// 180 needs no dimension swap — the box already matches the viewport, it just turns over. Giving
|
|
// it the portrait treatment would swap width and height for no reason and letterbox it.
|
|
const swap = deg === 90 || deg === 270;
|
|
if (!swap) {
|
|
return {
|
|
transform: 'rotate(180deg)',
|
|
width: '', height: '', top: '', left: '',
|
|
transformOrigin: 'center center',
|
|
};
|
|
}
|
|
|
|
return {
|
|
// translate BEFORE rotate: transforms apply right-to-left, so the box is turned about its own
|
|
// centre and then that centre is moved onto the viewport's. Reversing them rotates the offset
|
|
// as well and puts the content back off-screen.
|
|
transform: 'translate(-50%, -50%) rotate(' + deg + 'deg)',
|
|
width: '100vh',
|
|
height: '100vw',
|
|
top: '50%',
|
|
left: '50%',
|
|
transformOrigin: 'center center',
|
|
};
|
|
}
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
module.exports = { orientationStyle, ROTATION_DEG };
|
|
}
|
|
if (typeof window !== 'undefined') {
|
|
window.OrientationStyle = { orientationStyle, ROTATION_DEG };
|
|
}
|