Source

Modified ago
# TODO: This is kind of a mess import {$class} from './utils' class Scroller wrapper: undefined trackX: undefined handleX: undefined track: undefined handle: undefined barHeight: 0 barSize: 0 mouseX: 0 mouseY: 0 clickedX: 0 clickedY: 0 pressing: null constructor: (@el) -> @el.classList.add 'scroller_initiated' @wrapper = @el.querySelector '.scroller__wrapper' @track = @el.querySelector '.scrollbar_direction_vertical' @handle = @track.querySelector '.scrollbar__handle' @trackX = @el.querySelector '.scrollbar_direction_horizontal' @handleX = @trackX.querySelector '.scrollbar__handle' @barSize = @wrapper.offsetWidth - @wrapper.clientWidth @wrapper.style.paddingRight = "#{@barSize}px" @wrapper.style.paddingBottom = "#{@barSize}px" do @adjustSize @wrapper.addEventListener 'scroll', @onScroll self = @ # Have to wrap it in a function or else it won't recognize the "this" do (self) -> document.addEventListener 'mousemove', (e) -> # Update mouse position self.mouseX = e.clientX self.mouseY = e.clientY # Only need to update height when mouse is in the scroller since its is transparent when the scroller is being hovered do self.adjustSize return self.handleX.addEventListener 'mousedown', (e) -> do e.stopPropagation # Avoid slecting everthing while dragging the handle self.el.style.userSelect = 'none' # Gt pressed handle self.pressing = e.target # Get clicked position self.clickedX = e.clientX - self.pressing.getBoundingClientRect().left requestAnimationFrame self.dragScrollX false self.handle.addEventListener 'mousedown', (e) -> do e.stopPropagation # Avoid slecting everthing while dragging the handle self.el.style.userSelect = 'none' # Gt pressed handle self.pressing = e.target # Get clicked position self.clickedY = e.clientY - self.pressing.getBoundingClientRect().top requestAnimationFrame self.dragScrollY false document.addEventListener 'mouseup', (e) -> # Allow selecting again self.el.style.userSelect = 'auto' self.pressing = null return return onScroll: => @handleX.style.transform = "translateX(#{@wrapper.scrollLeft / @wrapper.scrollWidth * @wrapper.clientWidth}px)" @handle.style.transform = "translateY(#{@wrapper.scrollTop / @wrapper.scrollHeight * @wrapper.clientHeight}px)" return adjustSize: => height = @wrapper.clientHeight / @wrapper.scrollHeight * @wrapper.clientHeight @handle.style.height = "#{height}px" if @track.clientHeight <= height + 1 @track.classList.add 'scrollbar_maxed' else @track.classList.remove 'scrollbar_maxed' width = @wrapper.clientWidth / @wrapper.scrollWidth * @wrapper.clientWidth @handleX.style.width = "#{width}px" if @trackX.clientWidth <= width + 1 @trackX.classList.add 'scrollbar_maxed' else @trackX.classList.remove 'scrollbar_maxed' return dragScrollX: => if @pressing and @pressing.classList.contains 'scrollbar__handle_direction_horizontal' # Handle bounds bound = do @pressing.getBoundingClientRect # Element bounds scbound = do @wrapper.getBoundingClientRect x = undefined if @mouseX < scbound.left # If exceeded the left x = 0 else if @mouseX > scbound.right # If exceeded the right x = @wrapper.clientwidth - @pressing.clientwidth - 1 else x = @mouseX - @clickedX - scbound.left if x >= 0 and x < @wrapper.clientWidth - @pressing.clientWidth # If X handle is within limits @pressing.style.transform = "translateX(#{x}px)" @wrapper.scrollLeft = (bound.left - scbound.left) * @wrapper.scrollWidth / @wrapper.clientWidth requestAnimationFrame @dragScrollX return dragScrollY: => if @pressing and @pressing.classList.contains 'scrollbar__handle_direction_vertical' # Handle bounds bound = do @pressing.getBoundingClientRect # Element bounds scbound = do @wrapper.getBoundingClientRect y = undefined if @mouseY < scbound.top # If exceeded the top y = 0 else if @mouseY > scbound.bottom # If exceeded the bottom y = @wrapper.clientHeight - @pressing.clientHeight - 1 else y = @mouseY - @clickedY - scbound.top if y >= 0 and y < @wrapper.clientHeight - @pressing.clientHeight # If Y handle is within limits @pressing.style.transform = "translateY(#{y}px)" @wrapper.scrollTop = (bound.top - scbound.top) * @wrapper.scrollHeight / @wrapper.clientHeight requestAnimationFrame @dragScrollY return # Helper functions export addScrollers = -> for el in $class 'scroller' unless el.classList.contains 'scroller_initiated' addScroller el export addScroller = (el) -> new Scroller el # Export Scroller class export default Scroller