mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
merge main f13c60c into feat/voice-outlines
reconcile voice outlines with main f13c60c, retaining German/Japanese,
Operator HUD retirement and Context/Radio cleanup, named-building
containment, courtyard-hole, non-Latin identity, attribution, cancellation
and antimeridian repairs
keep outline callouts above the open voice preview when an above-panel
slot fits without colliding with another callout,
and clip the compact dock location label on narrow screens
This commit is contained in:
commit
578ebdc030
449 files changed
+30400
-3429
No files matched your search
@@ -653,6 +653,7 @@ export function createScreenAnnotationRenderer(
|
||||
}
|
||||
}
|
||||
if (placed.length > 1) decollideCallouts(placed);
|
||||
placeCalloutsAboveVoicePreview(placed, svg, w, h);
|
||||
|
||||
// Tracked-entity z-order — runs AFTER all geometry + callout de-collision so each
|
||||
// group's bbox reflects its final on-screen extent. Any mark whose bbox INTERSECTS
|
||||
@@ -855,6 +856,70 @@ function decollideCallouts(callouts) {
|
||||
}
|
||||
}
|
||||
|
||||
/** Keep an overlapping callout above the actual open Voice Preview, when it fits. */
|
||||
function placeCalloutsAboveVoicePreview(callouts, svg, width, height) {
|
||||
if (!callouts.length) return;
|
||||
const panel = document.getElementById('gev-voice-panel');
|
||||
if (
|
||||
!panel ||
|
||||
panel.hidden ||
|
||||
panel.dataset.view !== 'preview' ||
|
||||
panel.checkVisibility?.({
|
||||
opacityProperty: true,
|
||||
visibilityProperty: true,
|
||||
}) === false
|
||||
)
|
||||
return;
|
||||
const rect = panel.getBoundingClientRect(),
|
||||
bounds = svg.getBoundingClientRect();
|
||||
if (
|
||||
rect.width <= 0 ||
|
||||
rect.height <= 0 ||
|
||||
bounds.width <= 0 ||
|
||||
bounds.height <= 0
|
||||
)
|
||||
return;
|
||||
// The overlay uses preserveAspectRatio="none": each axis scales independently.
|
||||
const sx = width / bounds.width,
|
||||
sy = height / bounds.height;
|
||||
const blocked = {
|
||||
_x: (rect.left - bounds.left) * sx,
|
||||
_y: (rect.top - bounds.top) * sy,
|
||||
width: rect.width * sx,
|
||||
height: rect.height * sy,
|
||||
};
|
||||
const intersects = (a, b) =>
|
||||
a._x < b._x + b.width &&
|
||||
a._x + a.width > b._x &&
|
||||
a._y < b._y + b.height &&
|
||||
a._y + a.height > b._y;
|
||||
for (const callout of callouts) {
|
||||
if (!intersects(callout, blocked) || callout.width > width - 16) continue;
|
||||
const candidate = {
|
||||
_x: Math.max(8, Math.min(callout._x, width - callout.width - 8)),
|
||||
_y: blocked._y - callout.height - 8,
|
||||
width: callout.width,
|
||||
height: callout.height,
|
||||
};
|
||||
if (
|
||||
candidate._y < 8 ||
|
||||
candidate._y + candidate.height > height - 8 ||
|
||||
callouts.some(
|
||||
(other) => other !== callout && intersects(candidate, other),
|
||||
)
|
||||
)
|
||||
continue;
|
||||
positionCallout(callout, candidate._x, candidate._y, false);
|
||||
if (callout._leader) {
|
||||
callout._leader.setAttribute('x2', candidate._x.toFixed(1));
|
||||
callout._leader.setAttribute(
|
||||
'y2',
|
||||
(candidate._y + candidate.height).toFixed(1),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ensureArrowMarker(defs, key, c) {
|
||||
if (defs.querySelector(`#gev-arrow-${key}`)) return;
|
||||
const marker = document.createElementNS(SVGNS, 'marker');
|
||||
|
||||
Reference in new issue
Block a user