Created
June 19, 2017 22:45
-
-
Save kirked/140c2023b610ed5e07b83eea791ce817 to your computer and use it in GitHub Desktop.
Scroll an HTML container to its bottom over a period of time (dashboard use, no user input required)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn element-with-id | |
"Return the element with the given ID." | |
[id] | |
(js/document.getElementById id)) | |
(defn resolve-element | |
"Given an ID or a CSS selector or an element, return the first matching document element." | |
[selector] | |
(cond | |
(string? selector) (or (element-with-id selector) | |
(js/document.querySelector selector)) | |
:else selector)) | |
(defn clear-interval-atom | |
[*interval] | |
(when @*interval | |
(do | |
(js/window.clearInterval @*interval) | |
(reset! *interval nil)))) | |
(defn step-and-interval | |
"Given a distance in pixels, and duration in millis, calculate | |
the animation step distance and interval frequency, with | |
a minimum interval of 20ms (50Hz)." | |
[distance duration] | |
(let [step (/ (* 20 distance) duration) | |
[step multiplier] (if (< step 1) [1 (/ 1 step)] [step 1]) | |
interval (* (/ duration distance) multiplier)] | |
[step interval])) | |
;; Based on | |
;; https://github.com/StevenIseki/scroll-element/blob/master/src/index.js | |
;; | |
;; This version doesn't compute window offsets, | |
;; since we're using a fixed 1080p display. | |
(defn scroll-to-bottom | |
"Scroll 'container' to the bottom, placing the timer into '*timer'. | |
optional: | |
:duration ms scroll duration (default 1000) | |
:on-done no-arg fn to call when scroll is done." | |
[container *timer & {:keys [duration on-done] :or {duration 1000}}] | |
(let [top-of (fn [e] (-> e .getBoundingClientRect .-top)) | |
container (resolve-element container) | |
target-top (- (.-scrollHeight container) (-> container .getBoundingClientRect .-height)) | |
[step interval] (step-and-interval target-top duration) | |
*last-top (atom -1) | |
scroller (fn [] | |
(let [current-top (.-scrollTop container)] | |
(if (and (< current-top target-top) (< @*last-top current-top)) | |
(do | |
(set! (.-scrollTop container) (+ current-top step)) | |
(reset! *last-top current-top)) | |
(do | |
(clear-interval-atom *timer) | |
(reset! *last-top -1) | |
(when (fn? on-done) | |
(on-done))))))] | |
;(js/console.info "scrolling" (.-id container) "to target-top:" target-top "moving" step "pixels every" interval "ms") | |
(reset! *timer (js/window.setInterval scroller interval)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment