11import { Dom } from '../core/dom' ;
2+ import { readMousePosition , readTouchPosition } from '../core/event-readers' ;
3+ import { Vector } from '../core/vector' ;
24
35export class ScrollBoxView {
46 public static create ( parent : HTMLElement , viewport : HTMLElement ) : ScrollBoxView {
@@ -10,48 +12,59 @@ export class ScrollBoxView {
1012 const view = new ScrollBoxView ( root , viewport ) ;
1113 window . addEventListener ( 'resize' , view . onResizeHandler ) ;
1214 root . addEventListener ( 'wheel' , e => view . onWheel ( e ) ) ;
15+ root . addEventListener ( 'touchstart' , e => view . onTouchStart ( e ) ) ;
16+ root . addEventListener ( 'mousedown' , e => view . onMouseDown ( e ) ) ;
1317 return view ;
1418 }
1519
1620 private readonly onResizeHandler = ( ) => this . onResize ( ) ;
17- private current ?: {
18- content : HTMLElement ;
21+ private readonly onTouchMoveHandler = ( e : TouchEvent ) => this . onTouchMove ( e ) ;
22+ private readonly onMouseMoveHandler = ( e : MouseEvent ) => this . onMouseMove ( e ) ;
23+ private readonly onTouchEndHandler = ( e : TouchEvent ) => this . onTouchEnd ( e ) ;
24+ private readonly onMouseUpHandler = ( e : MouseEvent ) => this . onMouseUp ( e ) ;
25+
26+ private content ?: {
27+ element : HTMLElement ;
1928 height : number ;
2029 } ;
30+ private scroll ?: {
31+ startPositionY : number ;
32+ startScrollTop : number ;
33+ } ;
2134
2235 public constructor ( private readonly root : HTMLElement , private readonly viewport : HTMLElement ) { }
2336
24- public setContent ( content : HTMLElement ) {
25- if ( this . current ) {
26- this . root . removeChild ( this . current . content ) ;
37+ public setContent ( element : HTMLElement ) {
38+ if ( this . content ) {
39+ this . root . removeChild ( this . content . element ) ;
2740 }
28- content . classList . add ( 'sqd-scrollbox-body' ) ;
29- this . root . appendChild ( content ) ;
30- this . reload ( content ) ;
41+ element . classList . add ( 'sqd-scrollbox-body' ) ;
42+ this . root . appendChild ( element ) ;
43+ this . reload ( element ) ;
3144 }
3245
3346 public refresh ( ) {
34- if ( this . current ) {
35- this . reload ( this . current . content ) ;
47+ if ( this . content ) {
48+ this . reload ( this . content . element ) ;
3649 }
3750 }
3851
3952 public destroy ( ) {
4053 window . removeEventListener ( 'resize' , this . onResizeHandler ) ;
4154 }
4255
43- private reload ( content : HTMLElement ) {
56+ private reload ( element : HTMLElement ) {
4457 const maxHeightPercent = 0.7 ;
4558 const minDistance = 200 ;
4659
47- let height = Math . min ( this . viewport . clientHeight * maxHeightPercent , content . clientHeight ) ;
60+ let height = Math . min ( this . viewport . clientHeight * maxHeightPercent , element . clientHeight ) ;
4861 height = Math . min ( height , this . viewport . clientHeight - minDistance ) ;
4962
5063 this . root . style . height = height + 'px' ;
51- content . style . top = '0px' ;
64+ element . style . top = '0px' ;
5265
53- this . current = {
54- content ,
66+ this . content = {
67+ element ,
5568 height
5669 } ;
5770 }
@@ -64,25 +77,88 @@ export class ScrollBoxView {
6477 e . preventDefault ( ) ;
6578 e . stopPropagation ( ) ;
6679
67- if ( this . current ) {
80+ if ( this . content ) {
6881 const delta = e . deltaY > 0 ? - 25 : 25 ;
69- const currentY = this . readScrollY ( ) ;
70- this . setScrollY ( currentY + delta ) ;
82+ const scrollTop = this . getScrollTop ( ) ;
83+ this . setScrollTop ( scrollTop + delta ) ;
84+ }
85+ }
86+
87+ private onTouchStart ( e : TouchEvent ) {
88+ e . preventDefault ( ) ;
89+ this . startScroll ( readTouchPosition ( e ) ) ;
90+ }
91+
92+ private onMouseDown ( e : MouseEvent ) {
93+ e . preventDefault ( ) ;
94+ this . startScroll ( readMousePosition ( e ) ) ;
95+ }
96+
97+ private onTouchMove ( e : TouchEvent ) {
98+ e . preventDefault ( ) ;
99+ this . moveScroll ( readTouchPosition ( e ) ) ;
100+ }
101+
102+ private onMouseMove ( e : MouseEvent ) {
103+ e . preventDefault ( ) ;
104+ this . moveScroll ( readMousePosition ( e ) ) ;
105+ }
106+
107+ private onTouchEnd ( e : TouchEvent ) {
108+ e . preventDefault ( ) ;
109+ this . stopScroll ( ) ;
110+ }
111+
112+ private onMouseUp ( e : MouseEvent ) {
113+ e . preventDefault ( ) ;
114+ this . stopScroll ( ) ;
115+ }
116+
117+ private startScroll ( startPosition : Vector ) {
118+ if ( this . scroll ) {
119+ this . stopScroll ( ) ;
120+ return ;
121+ }
122+
123+ window . addEventListener ( 'touchmove' , this . onTouchMoveHandler ) ;
124+ window . addEventListener ( 'mousemove' , this . onMouseMoveHandler ) ;
125+ window . addEventListener ( 'touchend' , this . onTouchEndHandler ) ;
126+ window . addEventListener ( 'mouseup' , this . onMouseUpHandler ) ;
127+ this . scroll = {
128+ startPositionY : startPosition . y ,
129+ startScrollTop : this . getScrollTop ( )
130+ } ;
131+ }
132+
133+ private moveScroll ( position : Vector ) {
134+ if ( this . scroll ) {
135+ const delta = position . y - this . scroll . startPositionY ;
136+ this . setScrollTop ( this . scroll . startScrollTop + delta ) ;
137+ }
138+ }
139+
140+ private stopScroll ( ) {
141+ if ( this . scroll ) {
142+ window . removeEventListener ( 'touchmove' , this . onTouchMoveHandler ) ;
143+ window . removeEventListener ( 'mousemove' , this . onMouseMoveHandler ) ;
144+ window . removeEventListener ( 'touchend' , this . onTouchEndHandler ) ;
145+ window . removeEventListener ( 'mouseup' , this . onMouseUpHandler ) ;
146+ this . scroll = undefined ;
71147 }
72148 }
73149
74- private readScrollY ( ) : number {
75- if ( this . current && this . current . content . style . top ) {
76- return parseInt ( this . current . content . style . top ) ;
150+ private getScrollTop ( ) : number {
151+ if ( this . content && this . content . element . style . top ) {
152+ return parseInt ( this . content . element . style . top ) ;
77153 }
78154 return 0 ;
79155 }
80156
81- private setScrollY ( y : number ) {
82- if ( this . current ) {
83- const maxY = this . current . content . clientHeight - this . current . height ;
84- const newTop = Math . max ( Math . min ( y , 0 ) , - maxY ) ;
85- this . current . content . style . top = newTop + 'px' ;
157+ private setScrollTop ( scrollTop : number ) {
158+ if ( this . content ) {
159+ const max = this . content . element . clientHeight - this . content . height ;
160+ const limited = Math . max ( Math . min ( scrollTop , 0 ) , - max ) ;
161+ this . content . element . style . top = limited + 'px' ;
86162 }
87163 }
88164}
0 commit comments