fix: scale time ruler tick marks to prevent overlap, use HH:MM:SS format

Dynamically calculate tick intervals to maintain ~80px minimum spacing between
marks regardless of zoom level. Prevents overlapping labels at high zoom.

Change time format from adaptive (m/s/·) to consistent HH:MM:SS or MM:SS format.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-06-30 16:07:05 -04:00
parent d93b92f4a5
commit 1cdb0de042

View file

@ -305,29 +305,30 @@
;; --- timeline ruler ------------------------------------------------------- ;; --- timeline ruler -------------------------------------------------------
(defn- format-time-hhmmss [seconds]
"Format seconds as HH:MM:SS or MM:SS if < 1 hour"
(let [h (int (/ seconds 3600))
m (int (mod (/ seconds 60) 60))
s (int (mod seconds 60))]
(if (> h 0)
(str h ":" (if (< m 10) "0" "") m ":" (if (< s 10) "0" "") s)
(str m ":" (if (< s 10) "0" "") s))))
(defn- time-ruler [len fps zoom] (defn- time-ruler [len fps zoom]
"Generate tick marks and labels for the timeline ruler. "Generate tick marks and labels for the timeline ruler.
Returns a vector of {:frame :px :label} with major/minor ticks." Scales tick intervals to maintain ~80px minimum spacing and uses HH:MM:SS format."
(let [px-per-sec (* fps zoom) (let [px-per-sec (* fps zoom)
;; choose tick interval in frames based on zoom level ;; Ensure minimum ~80px between ticks for readability
tick-frames (cond min-px-spacing 80
(< px-per-sec 10) (* 30 fps) ; 30 sec intervals ;; Calculate tick interval in seconds that gives good spacing
(< px-per-sec 20) (* 10 fps) ; 10 sec intervals sec-per-tick (js/Math.max 0.5 (js/Math.ceil (/ min-px-spacing px-per-sec)))
(< px-per-sec 40) (* 5 fps) ; 5 sec intervals tick-frames (* sec-per-tick fps)]
(< px-per-sec 80) fps ; 1 sec intervals
:else (/ fps 2)) ; 0.5 sec intervals
sec-per-tick (/ tick-frames fps)]
(loop [frame 0 tick-num 0 ticks []] (loop [frame 0 tick-num 0 ticks []]
(if (>= frame len) (if (>= frame len)
ticks ticks
(let [px (* (/ frame fps) zoom) (let [px (* (/ frame fps) zoom)
total-sec (* tick-num sec-per-tick) total-sec (* tick-num sec-per-tick)
label (cond label (format-time-hhmmss total-sec)]
(>= sec-per-tick 10) (let [m (int (/ total-sec 60))
s (int (mod total-sec 60))]
(if (> s 0) (str m ":" (if (< s 10) "0" "") s) (str m "m")))
(>= sec-per-tick 1) (str (int total-sec) "s")
:else (str (js/Math.round (* total-sec 10)) "·"))]
(recur (+ frame tick-frames) (inc tick-num) (recur (+ frame tick-frames) (inc tick-num)
(conj ticks {:frame frame :px px :label label}))))))) (conj ticks {:frame frame :px px :label label})))))))