This commit is contained in:
team3
2026-10-01 00:45:19 +02:00
parent bd1694528a
commit b65f4d75f4

View File

@@ -4,7 +4,7 @@
// Mitte schiebt man das ganze Fenster. Daneben zieht man den Strahl
// selbst nach links und rechts. Zeiten in Sekunden relativ zur Marke:
// 0 ist der Moment, an dem C gedrückt wurde.
import { computed, ref } from 'vue'
import { computed, onMounted, onUnmounted, ref } from 'vue'
const props = defineProps({
// Stücke der Aufnahme: [{ von, bis }] relativ zur Marke
@@ -83,9 +83,27 @@ function uhrzeit(t) {
// ── Ziehen ────────────────────────────────────────────────────────────
let griff = null
let ausgang = null
// Ob sich die Hand seit dem Anfassen bewegt hat — sonst war es ein Klick
let bewegt = false
function zeitBei(clientX) {
const box = strahl.value.getBoundingClientRect()
return links.value + ((clientX - box.left) / box.width) * spanne.value
}
// Das Fenster an eine Stelle setzen: sein Anfang liegt dort, es bleibt im Stück
function setzen(t) {
const g = stueckUm(t)
const d = Math.max(props.minDauer, Math.min(dauer.value, g.bis - g.von))
const s = Math.max(g.von, Math.min(g.bis - d, t))
vorher.value = Math.round(-s)
dauer.value = Math.round(d)
emit('ende')
}
function anfassen(e, was) {
griff = was
bewegt = false
ausgang = {
x: e.clientX,
vorher: vorher.value,
@@ -100,6 +118,7 @@ function anfassen(e, was) {
function ziehen(e) {
if (!griff || !strahl.value) return
const dt = ((e.clientX - ausgang.x) / strahl.value.clientWidth) * spanne.value
if (Math.abs(e.clientX - ausgang.x) > 4) bewegt = true
const g = ausgang.stueck
if (griff === 'bahn') {
// Den Strahl selbst schieben — die Zeiten laufen der Hand entgegen
@@ -134,9 +153,46 @@ function loslassen(e) {
const war = griff
griff = null
e.currentTarget.releasePointerCapture?.(e.pointerId)
// Nur ein verändertes Fenster braucht eine neue Vorschau
if (war !== 'bahn') emit('ende')
if (war === 'bahn') {
// Ein Klick ohne Ziehen setzt das Fenster hierhin; Schieben braucht keine neue Vorschau
if (!bewegt) setzen(zeitBei(e.clientX))
return
}
emit('ende')
}
// Mausrad: zoomen, der Punkt unter dem Zeiger bleibt stehen
function rad(e) {
const neu = Math.max(0, Math.min(ZOOMS.length - 1, zoom.value + (e.deltaY > 0 ? 1 : -1)))
if (neu === zoom.value || !strahl.value) return
const box = strahl.value.getBoundingClientRect()
const anteil = (e.clientX - box.left) / box.width
const t = links.value + anteil * spanne.value
zoom.value = neu
const r = grenzen.value
mitte.value = Math.max(r.von, Math.min(r.bis, t - (anteil - 0.5) * ZOOMS[neu]))
}
// Pfeiltasten: 1 s, mit Shift 10 s. Die Vorschau lädt erst, wenn Ruhe ist
let tastenTimer = null
function taste(e) {
if (e.target instanceof Element && e.target.matches('input, textarea')) return
if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight') return
e.preventDefault()
const schritt = (e.shiftKey ? 10 : 1) * (e.key === 'ArrowLeft' ? -1 : 1)
const g = stueckUm(start.value + dauer.value / 2)
const s = Math.max(g.von, Math.min(g.bis - dauer.value, start.value + schritt))
vorher.value = Math.round(-s)
clearTimeout(tastenTimer)
tastenTimer = setTimeout(() => emit('ende'), 400)
}
onMounted(() => window.addEventListener('keydown', taste))
onUnmounted(() => {
window.removeEventListener('keydown', taste)
clearTimeout(tastenTimer)
})
</script>
<template>
@@ -162,6 +218,7 @@ function loslassen(e) {
ref="strahl"
class="strahl"
@pointerdown="anfassen($event, 'bahn')"
@wheel.prevent="rad"
@pointermove="ziehen"
@pointerup="loslassen"
@pointercancel="loslassen"
@@ -257,6 +314,8 @@ function loslassen(e) {
.bereich {
position: absolute;
top: 0.4rem;
/* Bei vier Stunden Ansicht wäre das Fenster ein Strich — so bleibt es greifbar */
min-width: 2.2rem;
height: 1.6rem;
background: rgba(229, 9, 20, 0.35);
border: 2px solid var(--accent);