| @@ -328,7 +328,9 @@ function applyGhost(d: NonNullable<typeof ghostDrag>, t: number) { |
| 328 | | 328 | |
| 329 | let drag: { track: Track; id: string; mode: Mode; t0: number; origin: Timeline; pts: number[]; moved: boolean; fx?: FxEnd } | null = null; | 329 | let drag: { track: Track; id: string; mode: Mode; t0: number; origin: Timeline; pts: number[]; moved: boolean; fx?: FxEnd } | null = null; |
| 330 | let rangeDrag: { a: number } | null = null; | 330 | let rangeDrag: { a: number } | null = null; |
| 331 | -let scrub = false; | 331 | +// la tête de lecture tirée sur la règle s'aimante aux coupes et aux bords des éléments (Alt : sans aimant) |
| | 332 | +let scrub: number[] | null = null; |
| | 333 | +const scrubTo = (e: PointerEvent) => emit("seek", e.altKey ? timeAt(e) : snap(timeAt(e), scrub!)); |
| 332 | | 334 | |
| 333 | function down(e: PointerEvent, track: Track, id: string, mode: Mode = "move") { | 335 | function down(e: PointerEvent, track: Track, id: string, mode: Mode = "move") { |
| 334 | if (e.button !== 0) return; | 336 | if (e.button !== 0) return; |
| @@ -465,7 +467,7 @@ function dragTo(e: PointerEvent) { |
| 465 | const a = Math.min(rangeDrag.a, t), b = Math.max(rangeDrag.a, t); | 467 | const a = Math.min(rangeDrag.a, t), b = Math.max(rangeDrag.a, t); |
| 466 | sel.value = b - a > 0.05 ? { range: [round(a), round(b)] } : null; | 468 | sel.value = b - a > 0.05 ? { range: [round(a), round(b)] } : null; |
| 467 | } else if (scrub) { | 469 | } else if (scrub) { |
| 468 | - emit("seek", timeAt(e)); | 470 | + scrubTo(e); |
| 469 | } | 471 | } |
| 470 | } | 472 | } |
| 471 | | 473 | |
| @@ -479,7 +481,7 @@ function up() { |
| 479 | } | 481 | } |
| 480 | drag = null; | 482 | drag = null; |
| 481 | rangeDrag = null; | 483 | rangeDrag = null; |
| 482 | - scrub = false; | 484 | + scrub = null; |
| 483 | lastMove = null; | 485 | lastMove = null; |
| 484 | cancelAnimationFrame(edgeRaf); | 486 | cancelAnimationFrame(edgeRaf); |
| 485 | edgeRaf = 0; | 487 | edgeRaf = 0; |
| @@ -505,8 +507,9 @@ function downRuler(e: PointerEvent) { |
| 505 | if (e.shiftKey) { | 507 | if (e.shiftKey) { |
| 506 | rangeDrag = { a: timeAt(e) }; | 508 | rangeDrag = { a: timeAt(e) }; |
| 507 | } else { | 509 | } else { |
| 508 | - scrub = true; | 510 | + // sans la tête elle-même, qui sinon resterait collée à sa position de départ |
| 509 | - emit("seek", timeAt(e)); | 511 | + scrub = snapPoints("").filter((p) => p !== props.t); |
| | 512 | + scrubTo(e); |
| 510 | } | 513 | } |
| 511 | (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); | 514 | (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); |
| 512 | } | 515 | } |