Initial Phoenix analyzer

This commit is contained in:
Mikei386
2026-06-02 20:56:19 +02:00
commit e499bac928
62 changed files with 28893 additions and 0 deletions
+169
View File
@@ -0,0 +1,169 @@
// views/panel.js — Zentrales Mehrmeter-Panel (wie in deinem Original)
// Nutzt bis zu fünf HUD-Slots und zeichnet mittig ein breites Panel mit Rahmen.
import { DEFAULT_TOP_INSET, FRAME_COLOR, FRAME_COLOR_DIM, LABEL_COLOR } from '../core/theme.js';
export const id = 'panel';
export function init() {
return { staticLayer: null };
}
export function resize() {}
export function destroy(state) {
state.staticLayer = null;
}
export async function render(env, state) {
const { ctx: g, rect, config: CONFIG, meters } = env;
const W = rect.w, H = rect.h;
const mWidth = Math.max(200, Math.floor(W * 1));
const mPX = 0;
const topInset = Number.isFinite(env?.topInset) ? Number(env.topInset) : DEFAULT_TOP_INSET;
const mTop = Number.isFinite(env?.topInset) ? Math.max(0, Math.floor(topInset + 10)) : 80;
const mBot = H - 10;
const labelY = mTop - 25; // aktuell ungenutzt, Meter zeichnen eigene Labels
// Slots nebeneinander (leere Slots werden ausgeblendet)
const inner = 0;
const gap = 12;
const meterPadTop = 18;
const meterPadBottom = 10;
const slotsRaw = env.slots?.('panel') || ['vu','ppm-ebu','tp','rms','lufs'];
const slots = slotsRaw.filter((v) => v && v !== 'none');
const n = slots.length;
const setX0 = mPX + inner;
if (!n) {
g.save();
g.fillStyle = LABEL_COLOR;
g.textAlign = 'left';
g.font = 'bold 16px ui-monospace, monospace';
g.fillText('Keine Slots aktiv', setX0 + 10, mTop + 20);
g.restore();
return;
}
const setW = Math.floor((mWidth - (n - 1) * gap - inner * 2) / n);
const staticLayout = {
mPX,
mTop,
mWidth,
H,
gap,
slots: n,
setX0,
setW,
meterPadTop,
meterPadBottom,
dividersEnabled: !!CONFIG.PANEL_DIVIDERS_ENABLED,
hasSlots: n > 0,
};
for (let i = 0; i < n; i++) {
const x = setX0 + i * (setW + gap);
const rectM = {
x,
y: mTop + meterPadTop,
w: setW,
h: Math.max(0, (mBot - mTop) - meterPadTop - meterPadBottom)
};
if (i > 0 && CONFIG.PANEL_DIVIDERS_ENABLED) {
const dividerX = x - gap / 2;
g.save();
g.strokeStyle = FRAME_COLOR_DIM;
g.lineWidth = 1;
g.setLineDash([4, 3]);
g.beginPath();
g.moveTo(dividerX, mTop + meterPadTop - 6);
g.lineTo(dividerX, mBot - meterPadBottom + 6);
g.stroke();
g.restore();
}
try {
await meters.draw(g, rectM, slots[i], CONFIG);
} catch (e) {
// Slot neutral markieren, damit die anderen nicht leiden
g.save();
g.strokeStyle = 'rgba(200,80,80,.8)';
g.setLineDash([6,4]);
g.strokeRect(rectM.x+0.5, rectM.y+0.5, rectM.w-1, rectM.h-1);
g.setLineDash([]);
g.restore();
}
}
drawCachedPanelStaticLayer(g, state, staticLayout);
}
function drawCachedPanelStaticLayer(g, state, layout) {
const {
mPX,
mTop,
mWidth,
H,
gap,
slots,
setX0,
setW,
meterPadTop,
meterPadBottom,
dividersEnabled,
} = layout;
const key = [
Math.round(mPX),
Math.round(mTop),
Math.round(mWidth),
Math.round(H),
gap,
slots,
Math.round(setX0),
Math.round(setW),
meterPadTop,
meterPadBottom,
dividersEnabled ? 1 : 0,
].join('|');
const strokePad = 2;
const width = Math.max(1, Math.round(mWidth + strokePad * 2));
const height = Math.max(1, Math.round((H - (mTop - 10)) + strokePad * 2));
const needsRebuild = !state.staticLayer
|| state.staticLayer.key !== key
|| state.staticLayer.width !== width
|| state.staticLayer.height !== height;
if (needsRebuild) {
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const cg = canvas.getContext('2d');
if (cg) {
cg.save();
cg.translate(strokePad - mPX, strokePad - (mTop - 10));
cg.strokeStyle = FRAME_COLOR;
cg.lineWidth = 2;
cg.strokeRect(mPX, mTop - 10, mWidth, H - (mTop - 10));
if (dividersEnabled) {
const mBot = H - 10;
for (let i = 1; i < slots; i++) {
const x = setX0 + i * (setW + gap);
const dividerX = x - gap / 2;
cg.save();
cg.strokeStyle = FRAME_COLOR_DIM;
cg.lineWidth = 1;
cg.setLineDash([4, 3]);
cg.beginPath();
cg.moveTo(dividerX, mTop + meterPadTop - 6);
cg.lineTo(dividerX, mBot - meterPadBottom + 6);
cg.stroke();
cg.restore();
}
}
cg.restore();
}
state.staticLayer = { key, canvas, width, height };
}
g.drawImage(state.staticLayer.canvas, mPX - strokePad, (mTop - 10) - strokePad);
}