mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-10-23 11:32:23 +00:00
## Summary Animations on the live map (packet pulses, hop-to-hop trails, drawAnimatedLine, pulseNode rings, matrix chars) render BEHIND the node base layer — community-confirmed by @EldoonNemar in #1485 after pulling latest and rebuilding. The live map looks completely static because every node marker paints on top of moving packets. Closes #1485 ## Root cause PR #1334 ("role-aware marker shapes + outline-ring highlight") swapped node markers: - **Before:** `L.circleMarker([n.lat, n.lon], {...})` — rendered into the default Leaflet `overlayPane` (z=400) alongside other vector shapes. - **After:** `L.marker([n.lat, n.lon], { icon: L.divIcon({...}) })` — rendered into the default Leaflet `markerPane` (z=600). `animLayer` and `pathsLayer` (built from `L.polyline` / `L.circleMarker` shapes) still default to `overlayPane` @ 400. With nodes now in pane 600, every node marker occluded every animation. CDP confirmed pre-fix: ``` overlayPane z=400 (animations live here) ← 2 children markerPane z=600 (nodes live here) ← 516 children ← occludes ``` ## Fix Create a custom Leaflet pane `liveAnimPane` at `z-index: 650` (strictly above markerPane) and pin both `animLayer` and `pathsLayer` to it via the `{ pane: 'liveAnimPane' }` option on `L.layerGroup`. Polylines + circleMarkers added to those groups inherit the pane from their parent, so all `drawAnimatedLine` / `pulseNode` / `animatePath` / matrix-char shapes now paint above markers. `pointerEvents: 'none'` on the pane so it does not steal hover/click events from the markerPane beneath (`clickablePathsLayer` keeps the default overlayPane and continues to handle path clicks). Diff is +14 / -2 in `public/live.js`. No CSS changes, no API changes, no protocol changes. ## TDD Red commit (`b7ca794f`): test asserts on `public/live.js` source — 1. `map.createPane('liveAnimPane')` is called in init 2. that pane is assigned `style.zIndex` ≥ 650 (strictly above markerPane @ 600) 3. `animLayer` AND `pathsLayer` are constructed with `{ pane: 'liveAnimPane' }` 4. (sanity) animLayer still hosts ≥3 animation shapes, pathsLayer ≥3 trail shapes — regression detector if someone moves circles to the default pane. CI must fail on `b7ca794f` (RED). Fix lands in `627ce341` (GREEN). Test reruns 5× clean — non-flaky (source invariants). ## Browser verified Local headless chromium (CDP) against `http://analyzer-stg.00id.net/#/live`: - **Before fix:** overlayPane z=400 (2 anim children), markerPane z=600 (516 marker children) — animations buried. - **After hot-deploy:** liveAnimPane z=650 above markerPane z=600 — animations visible on top. Will attach screenshot post-merge once staging redeploys. E2E assertion added: `test-issue-1485-live-anim-z.js:54` (`liveAnimPane z-index >= 650`). ## Test wiring `test-all.sh` line 51 added; CI runs the new test alongside the existing 1418/1420/1438/1470 suite. ## Credit Reported by @EldoonNemar in #1485 — pulled via git, built the docker image, noticed the regression same day. Bug-report quality was excellent (concise repro: "live map now shows the animated packets behind the node base layer so you can't actually see the nodes moving"). --------- Co-authored-by: mc-bot <bot@meshcore.local>
This commit is contained in:
1 parent
ca2c3d6c79
commit
268751ff56
3 files changed
+109
-2
No files matched your search
+14
-2
@@ -1226,9 +1226,21 @@
|
||||
});
|
||||
L.control.zoom({ position: 'topright' }).addTo(map);
|
||||
|
||||
// #1485 — animations + trails need their own pane above markerPane.
|
||||
// PR #1334 moved node markers from L.circleMarker (overlayPane @ 400)
|
||||
// to L.marker+divIcon (markerPane @ 600); animations stayed in the
|
||||
// default overlayPane and were occluded by every node marker. Custom
|
||||
// pane @ 650 puts them strictly above all nodes. (tooltipPane shares
|
||||
// 650 — tooltips are user-triggered, harmless to share.)
|
||||
map.createPane('liveAnimPane');
|
||||
map.getPane('liveAnimPane').style.zIndex = 650;
|
||||
// Pointer-events default to none so the pane doesn't steal clicks
|
||||
// from the marker pane underneath (clickablePathsLayer handles that).
|
||||
map.getPane('liveAnimPane').style.pointerEvents = 'none';
|
||||
|
||||
nodesLayer = L.layerGroup().addTo(map);
|
||||
pathsLayer = L.layerGroup().addTo(map);
|
||||
animLayer = L.layerGroup().addTo(map);
|
||||
pathsLayer = L.layerGroup({ pane: 'liveAnimPane' }).addTo(map);
|
||||
animLayer = L.layerGroup({ pane: 'liveAnimPane' }).addTo(map);
|
||||
clickablePathsLayer = L.layerGroup().addTo(map);
|
||||
|
||||
injectSVGFilters();
|
||||
|
||||
@@ -48,6 +48,7 @@ node test-issue-1456-score-labels.js
|
||||
# #1461 mobile UX overhaul + #1470 node-detail tile helper (#1468 covered by E2E)
|
||||
node test-issue-1461-mobile-page-actions.js
|
||||
node test-issue-1470-node-tile-helper.js
|
||||
node test-issue-1485-live-anim-z.js
|
||||
node test-issue-1473-reserved-prefixes.js
|
||||
node test-issue-1473-prefix-generator.js
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* #1485 — Live map: animated packets render BEHIND the node base layer.
|
||||
*
|
||||
* Regression introduced by PR #1334 (commit 0f7c03cc), which swapped node
|
||||
* markers from L.circleMarker (lives in `overlayPane`, z=400) to L.marker
|
||||
* with divIcons (lives in `markerPane`, z=600). Animations stayed in the
|
||||
* default overlayPane (z=400 — polylines + circleMarkers) so once node
|
||||
* markers populated the map, they painted ON TOP of the animation layer,
|
||||
* hiding moving packets entirely.
|
||||
*
|
||||
* Fix invariant: the animation layers (animLayer + pathsLayer) must be
|
||||
* created on a CUSTOM Leaflet pane whose z-index is strictly greater than
|
||||
* the default markerPane (600). The conventional CoreScope choice is a
|
||||
* pane named `liveAnimPane` at z=650 (tooltipPane sits at 650 too, but
|
||||
* tooltips are user-triggered and harmless to share).
|
||||
*
|
||||
* Strategy: source-invariant assertions on public/live.js. We pin:
|
||||
* 1. A custom pane is created via map.createPane('liveAnimPane', ...).
|
||||
* 2. Its z-index >= 650 (covers markerPane @ 600).
|
||||
* 3. Both animLayer and pathsLayer are constructed with `pane:`
|
||||
* pointing at that custom pane (so polylines + circleMarkers inherit
|
||||
* the pane, not the default overlayPane).
|
||||
*
|
||||
* Behavioural check via vm sandbox: simulate the layer-creation calls
|
||||
* and assert addTo()/L.layerGroup() receive the pane option.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
let passed = 0, failed = 0;
|
||||
function assert(cond, msg) {
|
||||
if (cond) { passed++; console.log(' ✓ ' + msg); }
|
||||
else { failed++; console.error(' ✗ ' + msg); }
|
||||
}
|
||||
|
||||
const liveSrc = fs.readFileSync(path.join(__dirname, 'public', 'live.js'), 'utf8');
|
||||
|
||||
console.log('\n=== #1485 live anim z-order A: custom pane created ===');
|
||||
|
||||
const paneMatch = liveSrc.match(
|
||||
/map\.createPane\(\s*['"](liveAnimPane|animPane)['"]\s*\)/
|
||||
);
|
||||
assert(!!paneMatch,
|
||||
'map.createPane(\'liveAnimPane\') (or animPane) called in live.js init');
|
||||
|
||||
const paneName = paneMatch ? paneMatch[1] : 'liveAnimPane';
|
||||
|
||||
// z-index assignment, e.g. .style.zIndex = 650 or = '650'
|
||||
const zMatch = liveSrc.match(
|
||||
/getPane\(\s*['"](?:liveAnimPane|animPane)['"]\s*\)[\s\S]{0,80}?style\.zIndex\s*=\s*['"]?(\d+)/
|
||||
);
|
||||
assert(!!zMatch, 'liveAnimPane.style.zIndex assigned a numeric value');
|
||||
if (zMatch) {
|
||||
const z = parseInt(zMatch[1], 10);
|
||||
assert(z >= 650,
|
||||
'liveAnimPane z-index >= 650 — strictly above markerPane (600) (got ' + z + ')');
|
||||
}
|
||||
|
||||
console.log('\n=== #1485 live anim z-order B: layers bound to the pane ===');
|
||||
|
||||
// animLayer must be created with { pane: 'liveAnimPane' }
|
||||
const animLayerRe = new RegExp(
|
||||
'animLayer\\s*=\\s*L\\.layerGroup\\(\\s*\\{[^}]*pane\\s*:\\s*[\'"]' +
|
||||
paneName + '[\'"]'
|
||||
);
|
||||
assert(animLayerRe.test(liveSrc),
|
||||
'animLayer = L.layerGroup({ pane: \'' + paneName + '\' }) — animation layer bound to anim pane');
|
||||
|
||||
const pathsLayerRe = new RegExp(
|
||||
'pathsLayer\\s*=\\s*L\\.layerGroup\\(\\s*\\{[^}]*pane\\s*:\\s*[\'"]' +
|
||||
paneName + '[\'"]'
|
||||
);
|
||||
assert(pathsLayerRe.test(liveSrc),
|
||||
'pathsLayer = L.layerGroup({ pane: \'' + paneName + '\' }) — trail layer bound to anim pane');
|
||||
|
||||
console.log('\n=== #1485 live anim z-order C: per-shape inheritance ===');
|
||||
|
||||
// At least one polyline/circleMarker addTo(animLayer) call exists — we're
|
||||
// trusting Leaflet pane inheritance from the LayerGroup parent. Sanity
|
||||
// check that the four animLayer / pathsLayer addTo sites still exist
|
||||
// (regression detector if someone moves circles to the default pane).
|
||||
const animAddTo = (liveSrc.match(/\.addTo\(animLayer\)/g) || []).length;
|
||||
const pathsAddTo = (liveSrc.match(/\.addTo\(pathsLayer\)/g) || []).length;
|
||||
assert(animAddTo >= 3,
|
||||
'animLayer still hosts >=3 .addTo() animation shapes (got ' + animAddTo + ')');
|
||||
assert(pathsAddTo >= 3,
|
||||
'pathsLayer still hosts >=3 .addTo() trail shapes (got ' + pathsAddTo + ')');
|
||||
|
||||
console.log('\n=== Summary ===');
|
||||
console.log(' Passed: ' + passed);
|
||||
console.log(' Failed: ' + failed);
|
||||
process.exit(failed === 0 ? 0 : 1);
|
||||
Reference in new issue
Block a user