[feat](trx-frontend-http): draw APRS symbols from the sprite sheets
CI / lint (pull_request) Successful in 2m16s
CI / test (pull_request) Successful in 8m12s
CI / frontend (pull_request) Successful in 3m2s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m24s
CI / test (push) Successful in 7m28s
CI / frontend (push) Successful in 2m11s
CI / reuse (push) Successful in 3s
CI / lint (pull_request) Successful in 2m16s
CI / test (pull_request) Successful in 8m12s
CI / frontend (pull_request) Successful in 3m2s
CI / reuse (pull_request) Successful in 3s
CI / lint (push) Successful in 2m24s
CI / test (push) Successful in 7m28s
CI / frontend (push) Successful in 2m11s
CI / reuse (push) Successful in 3s
Resolve a table/code pair to a sprite cell in aprs-shared, and use it from both the packet lists and the map markers, which had each been printing the raw symbol character in a bordered box. A table identifier of / or \ selects the primary or alternate sheet directly. Anything else is an overlay character, which the APRS spec draws on top of the alternate symbol -- so those stack the overlay sheet over the alternate one rather than picking a sheet. Codes outside 0x21..0x7E have no cell and keep the old character box. The sheet URLs stay in the stylesheet so a min-resolution query can swap in the retina sheets; only the cell offset is computed and set inline. Map markers share the helper through the plugin chunk, so the map stays free of any remote symbol fetch. Verified in a browser against the real stylesheet and sheets: /> is a car, /_ a WX circle, /& an igate diamond, \n a red triangle, and the overlays S> and 7# carry their character on the alternate symbol. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018huL1ELyr86yVqfAabtioA Signed-off-by: Stan Grams <sjg@haxx.space>
This commit was merged in pull request #37.
This commit is contained in:
@@ -7,7 +7,7 @@ import {
|
||||
normalizeAprsPacket,
|
||||
renderAprsInfo,
|
||||
renderLocalAprsSymbol
|
||||
} from "./chunk-M2I6DH4X.js";
|
||||
} from "./chunk-ROTCLFXS.js";
|
||||
import {
|
||||
hostCore,
|
||||
hostState
|
||||
|
||||
+44
@@ -75,8 +75,51 @@ function escapeAprsCharacter(character) {
|
||||
if (character === '"') return """;
|
||||
return character;
|
||||
}
|
||||
var APRS_SPRITE_COLUMNS = 16;
|
||||
var APRS_SPRITE_CELL_PX = 24;
|
||||
var APRS_SPRITE_FIRST_CODE = 33;
|
||||
var APRS_SPRITE_LAST_CODE = 126;
|
||||
function aprsSpriteOffset(code) {
|
||||
if (code.length !== 1) return null;
|
||||
const point = code.charCodeAt(0);
|
||||
if (point < APRS_SPRITE_FIRST_CODE || point > APRS_SPRITE_LAST_CODE) return null;
|
||||
const index = point - APRS_SPRITE_FIRST_CODE;
|
||||
const column = index % APRS_SPRITE_COLUMNS;
|
||||
const row = Math.floor(index / APRS_SPRITE_COLUMNS);
|
||||
return `${String(-column * APRS_SPRITE_CELL_PX)}px ${String(-row * APRS_SPRITE_CELL_PX)}px`;
|
||||
}
|
||||
function aprsSymbolSprite(symbolTable, symbolCode) {
|
||||
if (!symbolTable || !symbolCode) return null;
|
||||
const symbolOffset = aprsSpriteOffset(symbolCode);
|
||||
if (!symbolOffset) return null;
|
||||
if (symbolTable === "/") {
|
||||
return {
|
||||
className: "aprs-symbol-primary",
|
||||
backgroundPosition: symbolOffset,
|
||||
label: `Primary APRS symbol ${symbolTable}${symbolCode}`
|
||||
};
|
||||
}
|
||||
if (symbolTable === "\\") {
|
||||
return {
|
||||
className: "aprs-symbol-alternate",
|
||||
backgroundPosition: symbolOffset,
|
||||
label: `Alternate APRS symbol ${symbolTable}${symbolCode}`
|
||||
};
|
||||
}
|
||||
const overlayOffset = aprsSpriteOffset(symbolTable);
|
||||
if (!overlayOffset) return null;
|
||||
return {
|
||||
className: "aprs-symbol-overlaid",
|
||||
backgroundPosition: `${overlayOffset}, ${symbolOffset}`,
|
||||
label: `Alternate APRS symbol \\${symbolCode} with overlay ${symbolTable}`
|
||||
};
|
||||
}
|
||||
function renderLocalAprsSymbol(packet, escapeHtml) {
|
||||
if (!packet.symbolTable || !packet.symbolCode) return "";
|
||||
const sprite = aprsSymbolSprite(packet.symbolTable, packet.symbolCode);
|
||||
if (sprite) {
|
||||
return `<span class="aprs-symbol ${sprite.className}" role="img" style="background-position:${sprite.backgroundPosition}" title="${escapeHtml(sprite.label)}" aria-label="${escapeHtml(sprite.label)}"></span>`;
|
||||
}
|
||||
const symbol = escapeHtml(packet.symbolCode);
|
||||
const table = packet.symbolTable === "/" ? "Primary" : "Alternate";
|
||||
return `<span class="aprs-symbol aprs-symbol-local" title="${table} APRS symbol ${symbol}">${symbol}</span>`;
|
||||
@@ -107,6 +150,7 @@ export {
|
||||
collapseAprsDuplicates,
|
||||
aprsHexBytes,
|
||||
renderAprsInfo,
|
||||
aprsSymbolSprite,
|
||||
renderLocalAprsSymbol,
|
||||
normalizeAprsPacket
|
||||
};
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
normalizeAprsPacket,
|
||||
renderAprsInfo,
|
||||
renderLocalAprsSymbol
|
||||
} from "./chunk-M2I6DH4X.js";
|
||||
} from "./chunk-ROTCLFXS.js";
|
||||
import {
|
||||
hostCore,
|
||||
hostState
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
aprsSymbolSprite
|
||||
} from "./chunk-ROTCLFXS.js";
|
||||
|
||||
// src/map-core.ts
|
||||
function mapEl(id) {
|
||||
const element = document.querySelector(`#${CSS.escape(id)}`);
|
||||
@@ -1660,10 +1664,11 @@ var mapWindow = window;
|
||||
}
|
||||
function aprsSymbolIcon(symbolTable, symbolCode) {
|
||||
if (!symbolTable || !symbolCode) return null;
|
||||
const table = symbolTable === "/" ? "primary" : "alternate";
|
||||
const sprite = aprsSymbolSprite(symbolTable, symbolCode);
|
||||
const html = sprite ? `<div class="aprs-symbol aprs-symbol-marker ${sprite.className}" role="img" style="background-position:${sprite.backgroundPosition}" title="${escapeMapHtml(sprite.label)}" aria-label="${escapeMapHtml(sprite.label)}"></div>` : `<div class="aprs-symbol aprs-symbol-marker aprs-symbol-local" title="${symbolTable === "/" ? "primary" : "alternate"} APRS symbol ${escapeMapHtml(symbolCode)}">${escapeMapHtml(symbolCode)}</div>`;
|
||||
return L.divIcon({
|
||||
className: "",
|
||||
html: `<div class="aprs-symbol-local" title="${table} APRS symbol ${escapeMapHtml(symbolCode)}">${escapeMapHtml(symbolCode)}</div>`,
|
||||
html,
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
popupAnchor: [0, -12]
|
||||
|
||||
@@ -2533,7 +2533,21 @@ body.map-fake-fullscreen-active {
|
||||
font-size: 0.75rem;
|
||||
word-break: break-all;
|
||||
}
|
||||
.aprs-symbol { display: inline-block; width: 24px; height: 24px; background-size: 384px 192px; vertical-align: middle; margin-right: 0.3rem; }
|
||||
/* APRS symbols are drawn from the vendored hessu/aprs-symbols sprite sheets:
|
||||
16x6 grids of 24px cells, indexed by `symbol code - 0x21`. The cell offset
|
||||
is set inline by the APRS/map bundles; the sheet URL stays here so retina
|
||||
displays can swap in the @2x variants. */
|
||||
.aprs-symbol { display: inline-block; width: 24px; height: 24px; background-repeat: no-repeat; background-size: 384px 144px; vertical-align: middle; margin-right: 0.3rem; }
|
||||
.aprs-symbol-marker { margin-right: 0; }
|
||||
.aprs-symbol-primary { background-image: url('/vendor/aprs-symbols-24-0.png'); }
|
||||
.aprs-symbol-alternate { background-image: url('/vendor/aprs-symbols-24-1.png'); }
|
||||
.aprs-symbol-overlaid { background-image: url('/vendor/aprs-symbols-24-2.png'), url('/vendor/aprs-symbols-24-1.png'); }
|
||||
@media (min-resolution: 2dppx) {
|
||||
.aprs-symbol-primary { background-image: url('/vendor/aprs-symbols-24-0-2x.png'); }
|
||||
.aprs-symbol-alternate { background-image: url('/vendor/aprs-symbols-24-1-2x.png'); }
|
||||
.aprs-symbol-overlaid { background-image: url('/vendor/aprs-symbols-24-2-2x.png'), url('/vendor/aprs-symbols-24-1-2x.png'); }
|
||||
}
|
||||
/* Fallback for symbol codes outside the sprite sheets: show the raw character. */
|
||||
.aprs-symbol-local { border: 1px solid var(--border); border-radius: 4px; background: var(--surface-raised); color: var(--text); font: 700 0.8rem/22px ui-monospace, monospace; text-align: center; }
|
||||
.aprs-pos { color: var(--accent-green); text-decoration: none; margin-left: 0.3rem; font-size: 0.8rem; }
|
||||
.aprs-pos:hover { text-decoration: underline; }
|
||||
|
||||
Reference in New Issue
Block a user