Compare commits
No commits in common. "f671f2605c3150fac2ae042173cb1c281ca87473" and "295ccb2e62a49858d8961890abcfef2108c20c65" have entirely different histories.
f671f2605c
...
295ccb2e62
4 changed files with 37 additions and 232 deletions
|
|
@ -138,47 +138,17 @@
|
||||||
belegt: belegteKanaele.has(t.channel),
|
belegt: belegteKanaele.has(t.channel),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
/*
|
// SSID-Beschriftung: nach Signalstärke absteigend, Kollision durch
|
||||||
* SSID-Beschriftung entzerren.
|
// Ausweichen in eine tiefere Zeile — und wer dann immer noch kollidiert,
|
||||||
*
|
// bekommt gar kein Label (statt eines unlesbaren Textstapels).
|
||||||
* Das Kernproblem, gemeldet vom Anwender: die Wunsch-Höhe eines Labels
|
|
||||||
* hängt am Messwert, und reale Nachbarnetze liegen fast alle zwischen
|
|
||||||
* −65 und −85 dBm — also in einem Band von nur ~40 Einheiten. Dort
|
|
||||||
* drängeln sich bei einer Wohnhaus-Nachbarschaft zehn und mehr Namen
|
|
||||||
* übereinander und werden unlesbar.
|
|
||||||
*
|
|
||||||
* Die Blöcke dürfen dabei NICHT verschoben werden — ihre Höhe IST der
|
|
||||||
* Messwert, sie zu spreizen würde die dBm-Achse zur Falschaussage
|
|
||||||
* machen. Verschoben wird ausschließlich die Beschriftung; eine dünne
|
|
||||||
* Zuordnungslinie führt zum zugehörigen Block.
|
|
||||||
*
|
|
||||||
* Verfahren: stärkstes Netz zuerst (das interessiert am meisten und
|
|
||||||
* bekommt deshalb die beste Position), dann für jedes weitere Label vom
|
|
||||||
* Wunschplatz aus abwechselnd nach oben und unten die nächste freie
|
|
||||||
* Zeile suchen. Zwei Labels stören sich nur, wenn sie sich AUCH
|
|
||||||
* waagerecht überlappen — nebeneinander liegende Netze dürfen dieselbe
|
|
||||||
* Höhe behalten. Findet ein Label gar keinen Platz, bleibt sein Block
|
|
||||||
* farbig stehen und wird über die Netzliste zugeordnet; die Anzahl der
|
|
||||||
* unbeschrifteten Netze wird ausgewiesen statt sie zu verschweigen.
|
|
||||||
*/
|
|
||||||
const ZEILE = FS_LABEL + 2;
|
|
||||||
const belegteLabel: { x1: number; x2: number; y: number }[] = [];
|
const belegteLabel: { x1: number; x2: number; y: number }[] = [];
|
||||||
const labels: {
|
const labels: {
|
||||||
text: string;
|
text: string;
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
farbe: ReturnType<typeof netColor>;
|
farbe: ReturnType<typeof netColor>;
|
||||||
leader: { x: number; y: number } | null;
|
leader: number | null;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
let ohneLabel = 0;
|
|
||||||
|
|
||||||
const frei = (y: number, x1: number, x2: number) =>
|
|
||||||
y >= PLOT_TOP + 2 &&
|
|
||||||
y <= BASELINE - 2 &&
|
|
||||||
!belegteLabel.some(
|
|
||||||
(l) => Math.abs(l.y - y) < ZEILE && x1 < l.x2 + 2 && x2 > l.x1 - 2,
|
|
||||||
);
|
|
||||||
|
|
||||||
for (const b of [...bloecke].sort((a, c) => c.n.rssi - a.n.rssi)) {
|
for (const b of [...bloecke].sort((a, c) => c.n.rssi - a.n.rssi)) {
|
||||||
const text = kuerzeSsid(b.n.ssid || b.n.bssid.slice(-8));
|
const text = kuerzeSsid(b.n.ssid || b.n.bssid.slice(-8));
|
||||||
const breite = textWidth(text, FS_LABEL);
|
const breite = textWidth(text, FS_LABEL);
|
||||||
|
|
@ -187,48 +157,33 @@
|
||||||
PAD_L + plotW - breite / 2 - 1,
|
PAD_L + plotW - breite / 2 - 1,
|
||||||
Math.max(PAD_L + breite / 2 + 1, b.mitte),
|
Math.max(PAD_L + breite / 2 + 1, b.mitte),
|
||||||
);
|
);
|
||||||
const x1 = cx - breite / 2;
|
let y = b.y - 4;
|
||||||
const x2 = cx + breite / 2;
|
let versuche = 0;
|
||||||
const wunschY = b.y - 4;
|
while (
|
||||||
|
versuche < 4 &&
|
||||||
let y: number | null = frei(wunschY, x1, x2) ? wunschY : null;
|
belegteLabel.some(
|
||||||
// abwechselnd nach oben und unten suchen — nach oben zuerst, weil
|
(l) =>
|
||||||
// dort der Platz über den Blöcken frei ist
|
Math.abs(l.y - y) < FS_LABEL + 1 &&
|
||||||
for (let stufe = 1; y === null && stufe <= 12; stufe++) {
|
cx - breite / 2 < l.x2 + 2 &&
|
||||||
const hoch = wunschY - stufe * ZEILE;
|
cx + breite / 2 > l.x1 - 2,
|
||||||
if (frei(hoch, x1, x2)) { y = hoch; break; }
|
)
|
||||||
const runter = wunschY + stufe * ZEILE;
|
) {
|
||||||
if (frei(runter, x1, x2)) { y = runter; break; }
|
y -= FS_LABEL + 2;
|
||||||
|
versuche++;
|
||||||
}
|
}
|
||||||
if (y === null) {
|
if (y < PLOT_TOP - 2) continue; // kein Platz mehr — lieber weglassen
|
||||||
ohneLabel++;
|
belegteLabel.push({ x1: cx - breite / 2, x2: cx + breite / 2, y });
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
belegteLabel.push({ x1, x2, y });
|
|
||||||
const versetzt = Math.abs(y - wunschY) > 2 || Math.abs(cx - b.mitte) > 2;
|
|
||||||
labels.push({
|
labels.push({
|
||||||
text,
|
text,
|
||||||
x: cx,
|
x: cx,
|
||||||
y,
|
y,
|
||||||
farbe: b.farbe,
|
farbe: b.farbe,
|
||||||
// Zuordnungslinie zum Scheitel des eigenen Blocks, sobald das Label
|
// Zuordnungslinie, sobald das Label vom eigenen Block weggerückt ist
|
||||||
// weggerückt werden musste — sonst rät man, welcher Name zu welchem
|
leader: Math.abs(y - (b.y - 4)) > 2 || Math.abs(cx - b.mitte) > 2 ? b.mitte : null,
|
||||||
// Block gehört.
|
|
||||||
leader: versetzt ? { x: b.mitte, y: b.y } : null,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { seg, plotW, bloecke, ticks, labels, leer: nets.length === 0, anzahl: nets.length };
|
||||||
seg,
|
|
||||||
plotW,
|
|
||||||
bloecke,
|
|
||||||
ticks,
|
|
||||||
labels,
|
|
||||||
ohneLabel,
|
|
||||||
leer: nets.length === 0,
|
|
||||||
anzahl: nets.length,
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -270,18 +225,16 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Zuordnungslinien: vom weggerückten Namen zum Scheitel seines Blocks.
|
<!-- Zuordnungslinien zu weggerückten Beschriftungen -->
|
||||||
In der Farbe des Netzes, damit die Zuordnung auch dann eindeutig
|
|
||||||
bleibt, wenn mehrere Linien nebeneinander verlaufen. -->
|
|
||||||
{#each s.labels.filter((l) => l.leader != null) as l, i (i)}
|
{#each s.labels.filter((l) => l.leader != null) as l, i (i)}
|
||||||
<line
|
<line
|
||||||
x1={l.x}
|
x1={l.x}
|
||||||
y1={l.y + 2}
|
y1={l.y + 2}
|
||||||
x2={l.leader?.x}
|
x2={l.leader}
|
||||||
y2={l.leader?.y}
|
y2={l.y + 6}
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
class="{l.farbe.text} opacity-40"
|
class="text-zinc-600"
|
||||||
stroke-width="0.6"
|
stroke-width="0.5"
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
|
|
@ -323,11 +276,10 @@
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<!-- Blockunterschrift. Unbeschriftete Netze werden ausgewiesen — sonst
|
<!-- Blockunterschrift -->
|
||||||
entstünde der Eindruck, es wären weniger Netze als tatsächlich da. -->
|
|
||||||
<text x={PAD_L} y={BASELINE + 28} class="fill-zinc-500" style="font-size: {FS_LABEL}px">
|
<text x={PAD_L} y={BASELINE + 28} class="fill-zinc-500" style="font-size: {FS_LABEL}px">
|
||||||
{s.seg.name}{s.seg.dfs ? ' · DFS' : ''} · {s.anzahl}
|
{s.seg.name}{s.seg.dfs ? ' · DFS' : ''} · {s.anzahl}
|
||||||
{s.anzahl === 1 ? 'Netz' : 'Netze'}{s.ohneLabel > 0 ? ` · ${s.ohneLabel} ohne Namen` : ''}
|
{s.anzahl === 1 ? 'Netz' : 'Netze'}
|
||||||
</text>
|
</text>
|
||||||
<text x={W - PAD_R} y={BASELINE + 28} text-anchor="end" class="fill-zinc-600" style="font-size: {FS_LABEL}px">
|
<text x={W - PAD_R} y={BASELINE + 28} text-anchor="end" class="fill-zinc-600" style="font-size: {FS_LABEL}px">
|
||||||
Kanal
|
Kanal
|
||||||
|
|
|
||||||
|
|
@ -89,33 +89,6 @@ export const DEMO_NETWORKS: WifiNetwork[] = [
|
||||||
rssi: -68, band: '5 GHz', widthMhz: 160, centerFreq0: 5775,
|
rssi: -68, band: '5 GHz', widthMhz: 160, centerFreq0: 5775,
|
||||||
standard: 'Wi-Fi 6 (802.11ax)', security: 'WPA2', ageMs: 1800,
|
standard: 'Wi-Fi 6 (802.11ax)', security: 'WPA2', ageMs: 1800,
|
||||||
},
|
},
|
||||||
// Weitere Nachbarn — erst mit dieser Dichte zeigt sich, ob Beschriftung und
|
|
||||||
// Netzauswahl im Diagramm wirklich tragen. In einem Mehrfamilienhaus oder
|
|
||||||
// Gewerbegebiet sind 15 sichtbare Netze der Normalfall, nicht die Ausnahme.
|
|
||||||
{
|
|
||||||
ssid: 'Telekom_FMK_5EA1', bssid: 'DD:EE:FF:30:40:08', channel: 1, frequency: 2412,
|
|
||||||
rssi: -71, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 4800,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ssid: 'WLAN-Gast-Praxis', bssid: 'DD:EE:FF:30:40:09', channel: 1, frequency: 2412,
|
|
||||||
rssi: -74, band: '2.4 GHz', widthMhz: 20, security: 'offen', ageMs: 5300,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ssid: 'EasyBox-99AF', bssid: 'DD:EE:FF:30:40:0A', channel: 6, frequency: 2437,
|
|
||||||
rssi: -76, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 4 (802.11n)', security: 'WPA2', ageMs: 6100,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ssid: 'devolo-1122', bssid: 'DD:EE:FF:30:40:0B', channel: 7, frequency: 2442,
|
|
||||||
rssi: -72, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 4 (802.11n)', security: 'WPA2', ageMs: 3700,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ssid: 'Kabel-Box-2231', bssid: 'DD:EE:FF:30:40:0C', channel: 11, frequency: 2462,
|
|
||||||
rssi: -66, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 2400,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ssid: 'HUAWEI-B535-A1', bssid: 'DD:EE:FF:30:40:0D', channel: 11, frequency: 2462,
|
|
||||||
rssi: -75, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 5600,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { ChevronDown, RefreshCw, Camera, MapPin, EyeOff } from 'lucide-svelte';
|
import { ChevronDown, RefreshCw, Camera, MapPin } from 'lucide-svelte';
|
||||||
import AppHeader from '$lib/components/AppHeader.svelte';
|
import AppHeader from '$lib/components/AppHeader.svelte';
|
||||||
import WifiChannelChart from '$lib/components/WifiChannelChart.svelte';
|
import WifiChannelChart from '$lib/components/WifiChannelChart.svelte';
|
||||||
import WifiTimelineChart from '$lib/components/WifiTimelineChart.svelte';
|
import WifiTimelineChart from '$lib/components/WifiTimelineChart.svelte';
|
||||||
|
|
@ -61,47 +61,6 @@
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
* Netzauswahl fürs Diagramm.
|
|
||||||
*
|
|
||||||
* In einer Wohnhaus-Nachbarschaft sind 15 und mehr Netze sichtbar; das
|
|
||||||
* Diagramm wird dann selbst mit entzerrten Beschriftungen voll. Hier kann
|
|
||||||
* man einzelne Netze ausblenden, um sich auf die interessanten zu
|
|
||||||
* beschränken.
|
|
||||||
*
|
|
||||||
* WICHTIG: Das Ausblenden betrifft NUR die Zeichnung. Kanalempfehlung und
|
|
||||||
* Warnregeln rechnen weiterhin mit ALLEN sichtbaren Netzen — sonst würde
|
|
||||||
* das Ausblenden eines starken Störers plötzlich dessen Kanal als „frei"
|
|
||||||
* empfehlen. Genau diese Falle wäre der teuerste Fehler an dieser Stelle.
|
|
||||||
*
|
|
||||||
* `versteckt` enthält die abgewählten BSSIDs; Vorgabe ist „alles sichtbar".
|
|
||||||
*/
|
|
||||||
let versteckt = $state<Set<string>>(new Set());
|
|
||||||
|
|
||||||
const sichtbareNetze = $derived(networks.filter((n) => !versteckt.has(n.bssid)));
|
|
||||||
const anzahlVersteckt = $derived(networks.length - sichtbareNetze.length);
|
|
||||||
|
|
||||||
function toggleNetz(bssid: string) {
|
|
||||||
const s = new Set(versteckt);
|
|
||||||
if (s.has(bssid)) s.delete(bssid);
|
|
||||||
else s.add(bssid);
|
|
||||||
versteckt = s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Alle einblenden */
|
|
||||||
function alleZeigen() {
|
|
||||||
versteckt = new Set();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Nur das eigene Netz und die stärksten Störer zeigen */
|
|
||||||
function nurStarke() {
|
|
||||||
const grenze = -70;
|
|
||||||
versteckt = new Set(
|
|
||||||
networks.filter((n) => n.bssid !== connectedBssid && n.rssi < grenze).map((n) => n.bssid),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empfehlung und Warnungen bewusst auf ALLEN Netzen, nicht auf der Auswahl
|
|
||||||
const foreignNetworks = $derived(networks.filter((n) => n.bssid !== connectedBssid));
|
const foreignNetworks = $derived(networks.filter((n) => n.bssid !== connectedBssid));
|
||||||
const recommendation = $derived(recommend24GhzChannels(foreignNetworks));
|
const recommendation = $derived(recommend24GhzChannels(foreignNetworks));
|
||||||
const warnings = $derived(channelWarnings(networks));
|
const warnings = $derived(channelWarnings(networks));
|
||||||
|
|
@ -379,31 +338,11 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if anzahlVersteckt > 0}
|
|
||||||
<div class="mt-2 flex items-center gap-2 rounded-lg bg-sky-900/30 p-2 text-xs text-sky-300">
|
|
||||||
<EyeOff size={14} class="shrink-0" />
|
|
||||||
<span class="flex-1">
|
|
||||||
{anzahlVersteckt} von {networks.length} Netzen ausgeblendet — Kanalempfehlung und
|
|
||||||
Hinweise rechnen weiterhin mit allen.
|
|
||||||
</span>
|
|
||||||
<button
|
|
||||||
class="shrink-0 rounded bg-sky-800/60 px-2 py-1 font-medium active:bg-sky-800"
|
|
||||||
onclick={alleZeigen}
|
|
||||||
>
|
|
||||||
Alle zeigen
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if bandsPresent.length > 0}
|
{#if bandsPresent.length > 0}
|
||||||
{#each bandsPresent as b (b)}
|
{#each bandsPresent as b (b)}
|
||||||
<div class="mt-3 rounded-lg bg-zinc-900 p-2.5">
|
<div class="mt-3 rounded-lg bg-zinc-900 p-2.5">
|
||||||
<p class="mb-1 text-xs font-semibold text-zinc-300">{b}</p>
|
<p class="mb-1 text-xs font-semibold text-zinc-300">{b}</p>
|
||||||
<WifiChannelChart
|
<WifiChannelChart networks={networks.filter((n) => n.band === b)} band={b} highlightBssid={connectedBssid ?? undefined} />
|
||||||
networks={sichtbareNetze.filter((n) => n.band === b)}
|
|
||||||
band={b}
|
|
||||||
highlightBssid={connectedBssid ?? undefined}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
{:else if !scanning && !errorMsg}
|
{:else if !scanning && !errorMsg}
|
||||||
|
|
@ -417,23 +356,7 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<div class="mb-1 mt-4 flex items-center gap-2">
|
<h2 class="mb-1 mt-4 text-sm font-semibold text-zinc-300">Netze ({groups.length})</h2>
|
||||||
<h2 class="flex-1 text-sm font-semibold text-zinc-300">Netze ({groups.length})</h2>
|
|
||||||
<!-- Schnellauswahl: in einer dichten Nachbarschaft will man meist nur
|
|
||||||
das eigene Netz und die wirklich störenden Nachbarn im Diagramm -->
|
|
||||||
<button
|
|
||||||
class="rounded bg-zinc-800 px-2 py-1 text-[11px] text-zinc-300 active:bg-zinc-700"
|
|
||||||
onclick={nurStarke}
|
|
||||||
>
|
|
||||||
nur starke
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="rounded bg-zinc-800 px-2 py-1 text-[11px] text-zinc-300 active:bg-zinc-700"
|
|
||||||
onclick={alleZeigen}
|
|
||||||
>
|
|
||||||
alle
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-1.5">
|
<div class="flex flex-col gap-1.5">
|
||||||
{#each groups as g (g.ssid)}
|
{#each groups as g (g.ssid)}
|
||||||
<div class="rounded-lg bg-zinc-900 p-2.5">
|
<div class="rounded-lg bg-zinc-900 p-2.5">
|
||||||
|
|
@ -446,29 +369,19 @@
|
||||||
{#each g.nets as n (n.bssid)}
|
{#each g.nets as n (n.bssid)}
|
||||||
{@const rating = rssiRating(n.rssi)}
|
{@const rating = rssiRating(n.rssi)}
|
||||||
{@const farbe = netColor(n.bssid, n.bssid === connectedBssid)}
|
{@const farbe = netColor(n.bssid, n.bssid === connectedBssid)}
|
||||||
{@const sichtbar = !versteckt.has(n.bssid)}
|
<div class="mt-1 flex items-center justify-between text-[11px] text-zinc-500">
|
||||||
<label class="mt-1 flex items-center justify-between gap-2 text-[11px] text-zinc-400">
|
|
||||||
<span class="flex min-w-0 items-center gap-1.5">
|
<span class="flex min-w-0 items-center gap-1.5">
|
||||||
<!-- Kästchen steuert ausschließlich die Zeichnung im Diagramm -->
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
class="h-3.5 w-3.5 shrink-0 accent-sky-500"
|
|
||||||
checked={sichtbar}
|
|
||||||
onchange={() => toggleNetz(n.bssid)}
|
|
||||||
/>
|
|
||||||
<!-- gleiche Farbe wie im Kanalgraph — macht die Zuordnung
|
<!-- gleiche Farbe wie im Kanalgraph — macht die Zuordnung
|
||||||
zwischen Diagramm und Liste ohne Suchen möglich -->
|
zwischen Diagramm und Liste ohne Suchen möglich -->
|
||||||
<span
|
<span class="h-1.5 w-1.5 shrink-0 rounded-full {farbe.dot}"></span>
|
||||||
class="h-1.5 w-1.5 shrink-0 rounded-full {farbe.dot} {sichtbar ? '' : 'opacity-30'}"
|
<span class="truncate">
|
||||||
></span>
|
|
||||||
<span class="{sichtbar ? '' : 'opacity-50'} min-w-0 overflow-hidden text-ellipsis whitespace-nowrap">
|
|
||||||
Kanal {n.channel} · {n.band}{n.widthMhz ? ` · ${n.widthMhz} MHz` : ''}{n.standard
|
Kanal {n.channel} · {n.band}{n.widthMhz ? ` · ${n.widthMhz} MHz` : ''}{n.standard
|
||||||
? ` · ${n.standard}`
|
? ` · ${n.standard}`
|
||||||
: ''}{n.security ? ` · ${n.security}` : ''}
|
: ''}{n.security ? ` · ${n.security}` : ''}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span class="shrink-0 {rating.colorClass} tabular-nums">{n.rssi} dBm</span>
|
<span class="shrink-0 {rating.colorClass} tabular-nums">{n.rssi} dBm</span>
|
||||||
</label>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
||||||
|
|
@ -90,26 +90,6 @@ const SZENARIEN = [
|
||||||
nets: [36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165].map((ch, i) => ({
|
nets: [36,40,44,48,52,56,60,64,100,104,108,112,116,120,124,128,132,136,140,144,149,153,157,161,165].map((ch, i) => ({
|
||||||
ssid: `AP-${ch}`, bssid: `EE:00:${String(i).padStart(2,'0')}`, channel: ch,
|
ssid: `AP-${ch}`, bssid: `EE:00:${String(i).padStart(2,'0')}`, channel: ch,
|
||||||
frequency: 5000 + ch*5, rssi: -50 - (i % 8) * 5, band: '5 GHz', widthMhz: 20 })) },
|
frequency: 5000 + ch*5, rssi: -50 - (i % 8) * 5, band: '5 GHz', widthMhz: 20 })) },
|
||||||
{ name: 'dicht24', band: '2.4 GHz', self: 'FF:00:01',
|
|
||||||
nets: [
|
|
||||||
['FRITZ!Box 7590 AX', 1, 2412, -48, 20],
|
|
||||||
['Telekom_FMK_5EA1', 1, 2412, -71, 20],
|
|
||||||
['WLAN-Gast-Praxis', 1, 2412, -74, 20],
|
|
||||||
['o2-WLAN-8812', 2, 2417, -69, 20],
|
|
||||||
['Vodafone-4C2A', 5, 2432, -73, 20],
|
|
||||||
['FRITZ!Box Gastzugang', 6, 2437, -52, 20],
|
|
||||||
['Nachbar-oben', 6, 2437, -70, 20],
|
|
||||||
['EasyBox-99AF', 6, 2437, -76, 20],
|
|
||||||
['devolo-1122', 7, 2442, -72, 20],
|
|
||||||
['TP-LINK_5G_ext', 9, 2452, -78, 20],
|
|
||||||
['Kabel-Box-2231', 11, 2462, -66, 20],
|
|
||||||
['Praxis-Intern', 11, 2462, -72, 20],
|
|
||||||
['HUAWEI-B535-A1', 11, 2462, -75, 20],
|
|
||||||
['Repeater-Flur', 11, 2462, -79, 20],
|
|
||||||
['Gaeste-WLAN-Cafe', 13, 2472, -81, 20],
|
|
||||||
].map(([ssid, ch, f, rssi, w], i) => ({
|
|
||||||
ssid, bssid: `FF:00:${String(i + 1).padStart(2, '0')}`, channel: ch,
|
|
||||||
frequency: f, rssi, band: '2.4 GHz', widthMhz: w })) },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const FARBEN = [
|
const FARBEN = [
|
||||||
|
|
@ -132,21 +112,8 @@ const FARBEN = [
|
||||||
[/fill-teal-400\/25/, 'fill:rgba(45,212,191,.25)'], [/stroke-teal-400/, 'stroke:#2dd4bf'], [/fill-teal-300/, 'fill:#5eead4'],
|
[/fill-teal-400\/25/, 'fill:rgba(45,212,191,.25)'], [/stroke-teal-400/, 'stroke:#2dd4bf'], [/fill-teal-300/, 'fill:#5eead4'],
|
||||||
[/fill-fuchsia-400\/25/, 'fill:rgba(232,121,249,.25)'], [/stroke-fuchsia-400/, 'stroke:#e879f9'], [/fill-fuchsia-300/, 'fill:#f0abfc'],
|
[/fill-fuchsia-400\/25/, 'fill:rgba(232,121,249,.25)'], [/stroke-fuchsia-400/, 'stroke:#e879f9'], [/fill-fuchsia-300/, 'fill:#f0abfc'],
|
||||||
[/fill-sky-500\/40/, 'fill:rgba(14,165,233,.4)'], [/stroke-sky-300/, 'stroke:#7dd3fc'], [/fill-sky-200/, 'fill:#bae6fd'],
|
[/fill-sky-500\/40/, 'fill:rgba(14,165,233,.4)'], [/stroke-sky-300/, 'stroke:#7dd3fc'], [/fill-sky-200/, 'fill:#bae6fd'],
|
||||||
// Zuordnungslinien nutzen die TEXT-Farbe des Netzes als stroke (currentColor)
|
|
||||||
[/opacity-40/, 'opacity:.4'],
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Fuer <line class="fill-xxx-300 opacity-40"> muss die Textfarbe als stroke wirken
|
|
||||||
function lineStroke(svg) {
|
|
||||||
return svg.replace(/<line([^>]*?)style="([^"]*)"([^>]*)>/g, (m, a, st, b) => {
|
|
||||||
const f = st.match(/fill:(#[0-9a-f]{6})/i);
|
|
||||||
if (f && /stroke="currentColor"/.test(m)) {
|
|
||||||
return `<line${a}style="${st};stroke:${f[1]}"${b}>`;
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function farbig(svg) {
|
function farbig(svg) {
|
||||||
return svg.replace(/class="([^"]*)"/g, (_m, cls) => {
|
return svg.replace(/class="([^"]*)"/g, (_m, cls) => {
|
||||||
const styles = FARBEN.filter(([re]) => re.test(cls)).map(([, v]) => v).join(';');
|
const styles = FARBEN.filter(([re]) => re.test(cls)).map(([, v]) => v).join(';');
|
||||||
|
|
@ -168,7 +135,7 @@ for (const s of SZENARIEN) {
|
||||||
let yOff = 0;
|
let yOff = 0;
|
||||||
const teile = svgs.map((sv, i) => {
|
const teile = svgs.map((sv, i) => {
|
||||||
const g = `<g transform="translate(0,${yOff})">` +
|
const g = `<g transform="translate(0,${yOff})">` +
|
||||||
lineStroke(farbig(sv)).replace(/^<svg[^>]*>/, '').replace(/<\/svg>$/, '') + `</g>`;
|
farbig(sv).replace(/^<svg[^>]*>/, '').replace(/<\/svg>$/, '') + `</g>`;
|
||||||
yOff += hoehen[i];
|
yOff += hoehen[i];
|
||||||
return g;
|
return g;
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue