Initial Phoenix analyzer
This commit is contained in:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user