Merge p10-w1-resolution-slider into dev (P10 W1: fix zoom slider stacking-context occlusion)
This commit is contained in:
@@ -9,8 +9,14 @@
|
|||||||
|
|
||||||
<div class="mix-waveform-bg">
|
<div class="mix-waveform-bg">
|
||||||
<canvas @ref="_canvas" class="mix-waveform-canvas"></canvas>
|
<canvas @ref="_canvas" class="mix-waveform-canvas"></canvas>
|
||||||
|
</div>
|
||||||
|
|
||||||
@* Viewing control only — never a seek surface. Hidden until a datum is present. *@
|
@* Viewing control only — never a seek surface. Hidden until a datum is present.
|
||||||
|
Deliberately a SIBLING of .mix-waveform-bg, not a child: the backdrop is position:fixed and so
|
||||||
|
forms its own stacking context, which would trap any descendant below the page's z-index:1
|
||||||
|
foreground (.mix-detail-foreground) and let that foreground swallow the slider's pointer events.
|
||||||
|
As a top-level sibling with its own z-index, the slider stacks above the foreground and stays
|
||||||
|
draggable. *@
|
||||||
@if (_hasDatum)
|
@if (_hasDatum)
|
||||||
{
|
{
|
||||||
<div class="mix-waveform-zoom">
|
<div class="mix-waveform-zoom">
|
||||||
@@ -25,4 +31,3 @@
|
|||||||
aria-label="Waveform zoom" />
|
aria-label="Waveform zoom" />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ public partial class MixWaveformVisualizer : ComponentBase, IAsyncDisposable
|
|||||||
private async Task OnZoomFractionChanged(double fraction)
|
private async Task OnZoomFractionChanged(double fraction)
|
||||||
{
|
{
|
||||||
ZoomState.VisibleSeconds = MixZoomMapping.FractionToSeconds(fraction);
|
ZoomState.VisibleSeconds = MixZoomMapping.FractionToSeconds(fraction);
|
||||||
|
DebugLog($"zoom slider changed — raw fraction={fraction:F3} → visibleSeconds={ZoomState.VisibleSeconds:F3}s; pushing setZoom (handle={(_handle is null ? "null" : "ready")}).");
|
||||||
await PushZoomAsync();
|
await PushZoomAsync();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,13 +21,18 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Zoom slider — a small viewing control pinned to the top-right, clear of the player bar at
|
/* Zoom slider — a small viewing control pinned to the top-right, clear of the player bar at
|
||||||
the bottom and the nav bar at the top. Pointer events are re-enabled here only (the backdrop
|
the bottom and the nav bar at the top. It is never a seek surface. top: 5rem sits just below the
|
||||||
stays inert), and it is never a seek surface. top: 5rem sits just below the fixed nav bar
|
fixed nav bar (~4.5rem tall) so neither the expanded player bar nor the nav occludes it.
|
||||||
(~4.5rem tall) so neither the expanded player bar nor the nav occludes it. */
|
|
||||||
|
position: fixed (not absolute) because the slider is now a top-level sibling of the backdrop, not
|
||||||
|
a child of it — see the comment in the .razor. z-index: 10 lifts it above the page foreground
|
||||||
|
(.mix-detail-foreground, z-index: 1) so the foreground can't intercept its pointer events; that
|
||||||
|
occlusion was the resolution-slider regression. */
|
||||||
.mix-waveform-zoom {
|
.mix-waveform-zoom {
|
||||||
position: absolute;
|
position: fixed;
|
||||||
right: 1.5rem;
|
right: 1.5rem;
|
||||||
top: 5rem;
|
top: 5rem;
|
||||||
|
z-index: 10;
|
||||||
width: 180px;
|
width: 180px;
|
||||||
max-width: 40vw;
|
max-width: 40vw;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
|
|||||||
@@ -795,7 +795,12 @@ export function create(canvas: HTMLCanvasElement): MixVisualizerHandle {
|
|||||||
setZoom(seconds: number): void {
|
setZoom(seconds: number): void {
|
||||||
// Clamp into the supported span so a stray value can't break the math.
|
// Clamp into the supported span so a stray value can't break the math.
|
||||||
visibleSeconds = Math.min(MAX_VISIBLE_SECONDS, Math.max(MIN_VISIBLE_SECONDS, seconds));
|
visibleSeconds = Math.min(MAX_VISIBLE_SECONDS, Math.max(MIN_VISIBLE_SECONDS, seconds));
|
||||||
if (!playback.isPlaying) redrawOnce();
|
// While playing, the running rAF loop uploads uVisibleSeconds next frame; while idle the
|
||||||
|
// loop is stopped (spec §E), so a zoom change must force one still frame here or the new
|
||||||
|
// span is uploaded only on the next unrelated redraw (theme/datum/resize) — i.e. never.
|
||||||
|
const idleRedraw = !playback.isPlaying;
|
||||||
|
debugLog(`setZoom — requested ${seconds.toFixed(3)}s, clamped ${visibleSeconds.toFixed(3)}s; idleRedraw=${idleRedraw} (isPlaying=${playback.isPlaying}).`);
|
||||||
|
if (idleRedraw) redrawOnce();
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshTheme(): void {
|
refreshTheme(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user