Skip to content

Commit b829c6c

Browse files
committed
mobile support for scrollbox.
1 parent 1bc3a07 commit b829c6c

File tree

2 files changed

+104
-26
lines changed

2 files changed

+104
-26
lines changed

src/toolbox/scrollbox-view.ts

Lines changed: 102 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { Dom } from '../core/dom';
2+
import { readMousePosition, readTouchPosition } from '../core/event-readers';
3+
import { Vector } from '../core/vector';
24

35
export 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
}

src/toolbox/toolbox-item.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@ export class ToolboxItem {
2020

2121
private onTouchstart(e: TouchEvent) {
2222
e.preventDefault();
23+
e.stopPropagation();
2324
this.startDrag(readTouchPosition(e));
2425
}
2526

2627
private onMousedown(e: MouseEvent) {
2728
e.preventDefault();
29+
e.stopPropagation();
2830
this.startDrag(readMousePosition(e));
2931
}
3032

0 commit comments

Comments
 (0)