fix: polish pass for traffic, nav, icons, contact email reveal and dashcam robustness
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { bucharestClock } from '@/lib/operations';
|
||||
import { maintenanceClock } from '@/journey/maintenance-progress';
|
||||
import { quantiseRoute } from '@/journey/tab-feed';
|
||||
|
||||
/**
|
||||
* DASHCAM telemetry and the postcard (lazy dashcam chunk only). Every value
|
||||
@@ -27,10 +28,9 @@ export const DASHCAM_COORDINATES = "N44°26' E26°06'";
|
||||
export const POSTCARD_WIDTH = 1600;
|
||||
export const POSTCARD_HEIGHT = 900;
|
||||
|
||||
export const routePercent = (progress: number): number =>
|
||||
Math.round(Math.min(1, Math.max(0, Number.isFinite(progress) ? progress : 0)) * 100);
|
||||
|
||||
export const chapterLabel = (chapter: string): string => chapter.replaceAll('-', ' ').toUpperCase();
|
||||
/** Whole percent on the tab title's 5% step, so the frame, the dashcam's
|
||||
* title and the route title never disagree (47% vs 45%). */
|
||||
export const routePercent = (progress: number): number => Math.round(quantiseRoute(progress) * 100);
|
||||
|
||||
/** Live Bucharest time; inside Infrastructure the maintenance window's clock. */
|
||||
export function dashcamClock(sectionId: string, maintenance: number | null, now: Date): string {
|
||||
@@ -52,8 +52,9 @@ export function postcardFilename(sectionId: string, clock: string): string {
|
||||
export const postcardCredit = (name: string, city: string): string =>
|
||||
`NIGHT SHIFT · ${name.toUpperCase()} · ${city.toUpperCase()}`;
|
||||
|
||||
export const frameTopLeft = (t: DashcamTelemetry): string =>
|
||||
`DASHCAM · ${chapterLabel(t.chapter)} · EXIT ${t.exit}`;
|
||||
/* One vocabulary in the frame: the navigation's exit and chapter name (the
|
||||
scene's internal chapter ids, e.g. "pre-dawn", are not shown). */
|
||||
export const frameTopLeft = (t: DashcamTelemetry): string => `DASHCAM · EXIT ${t.exit}`;
|
||||
export const frameBottomLeft = (t: DashcamTelemetry): string =>
|
||||
`ROUTE ${t.routePercent}% · ${t.sectionLabel.toUpperCase()}`;
|
||||
|
||||
@@ -66,6 +67,20 @@ export function coverCrop(sw: number, sh: number, dw: number, dh: number): { sx:
|
||||
return { sx: (sw - cropW) / 2, sy: (sh - cropH) / 2, sw: cropW, sh: cropH };
|
||||
}
|
||||
|
||||
/** Widest postcard written: a 2x buffer at 1440 is downsampled to this. */
|
||||
export const POSTCARD_MAX_WIDTH = 2560;
|
||||
|
||||
/**
|
||||
* The postcard's size for a sw x sh drawing buffer: the largest 16:9 crop of
|
||||
* the buffer at its own pixels, never upscaled (a 1440 x 900 buffer stretched
|
||||
* to 1600 read soft), downsampled only beyond POSTCARD_MAX_WIDTH.
|
||||
*/
|
||||
export function postcardSize(sw: number, sh: number): { w: number; h: number } {
|
||||
if (!(sw > 0 && sh > 0)) return { w: POSTCARD_WIDTH, h: POSTCARD_HEIGHT };
|
||||
const w = Math.min(POSTCARD_MAX_WIDTH, sw, (sh * 16) / 9);
|
||||
return { w: Math.round(w), h: Math.round((w * 9) / 16) };
|
||||
}
|
||||
|
||||
/** Frame chrome geometry for a w x h postcard (proportional to 1600 x 900). */
|
||||
export function postcardLayout(w = POSTCARD_WIDTH, h = POSTCARD_HEIGHT) {
|
||||
const unit = Math.min(w / POSTCARD_WIDTH, h / POSTCARD_HEIGHT);
|
||||
@@ -180,11 +195,13 @@ export function savePostcard(source: Source, t: DashcamTelemetry): Promise<Postc
|
||||
let canvas: HTMLCanvasElement;
|
||||
try {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.width = POSTCARD_WIDTH;
|
||||
canvas.height = POSTCARD_HEIGHT;
|
||||
const { w, h } = postcardSize(source.width, source.height);
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (ctx === null) return Promise.resolve('failed');
|
||||
drawPostcard(ctx as unknown as PostcardContext, source, t);
|
||||
ctx.imageSmoothingQuality = 'high';
|
||||
drawPostcard(ctx as unknown as PostcardContext, source, t, w, h);
|
||||
} catch {
|
||||
return Promise.resolve('failed');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user