67 lines
2.2 KiB
JavaScript
67 lines
2.2 KiB
JavaScript
export const CANVAS_WIDTH = 800;
|
|
export const CANVAS_HEIGHT = 450;
|
|
export const SCALE_MODES = new Set(['integer', 'native', 'fit']);
|
|
export const DEFAULT_SCALE_MODE = 'native';
|
|
|
|
export function normalizeScaleMode(mode) {
|
|
if (!mode) {
|
|
return DEFAULT_SCALE_MODE;
|
|
}
|
|
|
|
const normalized = String(mode).toLowerCase();
|
|
return SCALE_MODES.has(normalized) ? normalized : DEFAULT_SCALE_MODE;
|
|
}
|
|
|
|
export function computeDisplaySize(mode, viewportWidth, viewportHeight, dpr = 1) {
|
|
const safeDpr = Number.isFinite(dpr) && dpr > 0 ? dpr : 1;
|
|
|
|
if (viewportWidth <= 0 || viewportHeight <= 0) {
|
|
return {
|
|
cssWidth: CANVAS_WIDTH / safeDpr,
|
|
cssHeight: CANVAS_HEIGHT / safeDpr,
|
|
deviceWidth: CANVAS_WIDTH,
|
|
deviceHeight: CANVAS_HEIGHT,
|
|
scale: 1,
|
|
dpr: safeDpr
|
|
};
|
|
}
|
|
|
|
// Convert viewport from CSS pixels to device pixels first so scaling is DPI/zoom aware.
|
|
const viewportDeviceWidth = Math.max(1, Math.floor(viewportWidth * safeDpr));
|
|
const viewportDeviceHeight = Math.max(1, Math.floor(viewportHeight * safeDpr));
|
|
|
|
let deviceWidth;
|
|
let deviceHeight;
|
|
let scale;
|
|
|
|
if (mode === 'native') {
|
|
// 1 source pixel -> 1 physical device pixel.
|
|
scale = 1;
|
|
deviceWidth = CANVAS_WIDTH;
|
|
deviceHeight = CANVAS_HEIGHT;
|
|
} else if (mode === 'fit') {
|
|
const fitRatio = Math.min(viewportDeviceWidth / CANVAS_WIDTH, viewportDeviceHeight / CANVAS_HEIGHT);
|
|
const safeRatio = Number.isFinite(fitRatio) && fitRatio > 0 ? fitRatio : 1;
|
|
scale = safeRatio;
|
|
deviceWidth = Math.max(1, Math.floor(CANVAS_WIDTH * safeRatio));
|
|
deviceHeight = Math.max(1, Math.floor(CANVAS_HEIGHT * safeRatio));
|
|
} else {
|
|
// integer mode
|
|
const integerScale = Math.max(1, Math.floor(Math.min(
|
|
viewportDeviceWidth / CANVAS_WIDTH,
|
|
viewportDeviceHeight / CANVAS_HEIGHT
|
|
)));
|
|
scale = integerScale;
|
|
deviceWidth = CANVAS_WIDTH * integerScale;
|
|
deviceHeight = CANVAS_HEIGHT * integerScale;
|
|
}
|
|
|
|
return {
|
|
cssWidth: deviceWidth / safeDpr,
|
|
cssHeight: deviceHeight / safeDpr,
|
|
deviceWidth,
|
|
deviceHeight,
|
|
scale,
|
|
dpr: safeDpr
|
|
};
|
|
}
|