Refactor GUI rendering and align RTA axis

This commit is contained in:
Mikei386
2026-07-22 11:35:51 +02:00
parent 2e868bfa3a
commit 890a47a272
16 changed files with 1199 additions and 1415 deletions
+18
View File
@@ -0,0 +1,18 @@
// Gemeinsame Erzeugung temporärer Canvas-Flächen für Views und Meter.
export function createCanvasSurface(width, height) {
const w = Math.max(1, Math.ceil(width));
const h = Math.max(1, Math.ceil(height));
if (typeof OffscreenCanvas === 'function') {
const canvas = new OffscreenCanvas(w, h);
const ctx = canvas.getContext('2d');
if (ctx) return { canvas, ctx, width: w, height: h };
}
if (typeof document !== 'undefined') {
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
if (ctx) return { canvas, ctx, width: w, height: h };
}
return null;
}
+11 -17
View File
@@ -1,5 +1,6 @@
// core/registry.js — Lazy Loader + Safe Runner für Meter
// Lädt Meter-Module on-demand (oder via registerMeter) und kapselt Fehler.
import { createCanvasSurface } from './canvas_surface.js';
const cache = {
meters: new Map(), // id -> module
@@ -7,26 +8,12 @@ const cache = {
const meterRenderCache = new Map(); // key -> surface
const METER_CACHE_MARGIN = 32;
const METER_RENDER_CACHE_LIMIT = 48;
let activeFrameStamp = 0;
const CAN_USE_OFFSCREEN = typeof OffscreenCanvas === 'function';
function createCacheSurface(width, height) {
const w = Math.max(1, Math.ceil(width));
const h = Math.max(1, Math.ceil(height));
if (CAN_USE_OFFSCREEN) {
const canvas = new OffscreenCanvas(w, h);
const ctx = canvas.getContext('2d');
if (ctx) return { canvas, ctx, width: w, height: h, stamp: -1 };
}
if (typeof document !== 'undefined') {
const canvas = document.createElement('canvas');
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext('2d');
if (ctx) return { canvas, ctx, width: w, height: h, stamp: -1 };
}
return null;
const surface = createCanvasSurface(width, height);
return surface ? { ...surface, stamp: -1 } : null;
}
function cacheKeyForMeter(id, rect) {
@@ -40,10 +27,17 @@ function cacheKeyForMeter(id, rect) {
function ensureCacheSurface(id, rect) {
const key = cacheKeyForMeter(id, rect);
let surface = meterRenderCache.get(key);
if (surface) {
meterRenderCache.delete(key);
meterRenderCache.set(key, surface);
}
if (!surface) {
surface = createCacheSurface(rect.w + METER_CACHE_MARGIN * 2, rect.h + METER_CACHE_MARGIN * 2);
if (!surface) return null;
meterRenderCache.set(key, surface);
while (meterRenderCache.size > METER_RENDER_CACHE_LIMIT) {
meterRenderCache.delete(meterRenderCache.keys().next().value);
}
}
if (!surface.canvas || !surface.ctx) return null;
const w = Math.max(1, Math.ceil(rect.w + METER_CACHE_MARGIN * 2));
+19 -5
View File
@@ -250,7 +250,9 @@ export function drawDbfsGridRect(ctx, x0, y0, w, h, CONFIG, nyq, opts = {}) {
colorMinor = 'rgba(30,42,53,.55)',
labelColor = '#8fd3d4',
freqTicks = null,
freqTickPositions = null,
freqMin = 20,
xLeftExtension = 0,
refDb = null,
refStyle = 'rgba(0,231,255,0.35)',
refDash = [4, 3],
@@ -261,6 +263,12 @@ export function drawDbfsGridRect(ctx, x0, y0, w, h, CONFIG, nyq, opts = {}) {
const _g = Number(CONFIG && CONFIG.AXIS_GUTTER_LEFT);
const gutterL = Number.isFinite(_g) ? Math.max(8, _g) : 14;
const requestedExtension = Number(xLeftExtension);
const leftExtension = Number.isFinite(requestedExtension)
? Math.max(0, Math.min(gutterL, requestedExtension))
: 0;
const contentX = x0 - leftExtension;
const contentW = w + leftExtension;
ctx.save();
ctx.strokeStyle = '#00e7ff'; ctx.lineWidth = 2; ctx.strokeRect(x0 - gutterL, y0, w + gutterL, h);
@@ -272,7 +280,7 @@ export function drawDbfsGridRect(ctx, x0, y0, w, h, CONFIG, nyq, opts = {}) {
const y = yFromDbfs(v, y0, y0 + h, CONFIG);
const labelY = Math.min(y0 + h - 4, Math.max(y0 + 12, y + 4));
ctx.strokeStyle = colorMajor; ctx.lineWidth = 1.2;
ctx.beginPath(); ctx.moveTo(x0, y); ctx.lineTo(x0 + w, y); ctx.stroke();
ctx.beginPath(); ctx.moveTo(contentX, y); ctx.lineTo(contentX + contentW, y); ctx.stroke();
ctx.textAlign = 'right'; ctx.fillText(String(v), (x0 - gutterL) - 6, labelY);
}
@@ -282,8 +290,8 @@ export function drawDbfsGridRect(ctx, x0, y0, w, h, CONFIG, nyq, opts = {}) {
ctx.strokeStyle = refStyle;
ctx.setLineDash(Array.isArray(refDash) ? refDash : [4, 3]);
ctx.beginPath();
ctx.moveTo(x0, yRef);
ctx.lineTo(x0 + w, yRef);
ctx.moveTo(contentX, yRef);
ctx.lineTo(contentX + contentW, yRef);
ctx.stroke();
ctx.setLineDash([]);
}
@@ -299,9 +307,15 @@ export function drawDbfsGridRect(ctx, x0, y0, w, h, CONFIG, nyq, opts = {}) {
const logMin = Math.log10(minFreq);
const logSpan = Math.max(1e-6, Math.log10(nyq) - logMin);
for (const f of ticks) {
const x = x0 + ((Math.log10(Math.max(f, minFreq)) - logMin) / logSpan) * w;
const requestedPosition = freqTickPositions && typeof freqTickPositions === 'object'
? Number(freqTickPositions[String(f)])
: NaN;
const fraction = Number.isFinite(requestedPosition)
? Math.max(0, Math.min(1, requestedPosition))
: ((Math.log10(Math.max(f, minFreq)) - logMin) / logSpan);
const x = contentX + fraction * contentW;
// Linken Rand nicht doppeln: keine Vertikal-Linie auf dem linken Plot-Rand
if (x > x0 + 0.75) {
if (x > contentX + 0.75) {
ctx.strokeStyle = '#131b24';
ctx.beginPath(); ctx.moveTo(x, y0); ctx.lineTo(x, y0 + h); ctx.stroke();
}