Skip to content

Commit

Permalink
Add scrollTo methods to UIScrollContainer renderer (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
jcormont authored Oct 14, 2021
1 parent 28d7942 commit 075f49d
Showing 1 changed file with 56 additions and 41 deletions.
97 changes: 56 additions & 41 deletions src/renderers/UIContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
UIRow,
UIScrollContainer,
UIScrollEvent,
UIScrollTargetEvent,
UIStyle,
} from "typescene";
import { DOMRenderContext } from "../DOMRenderContext";
Expand Down Expand Up @@ -71,51 +72,56 @@ class UIContainerRenderer extends RendererBase<UIContainer, HTMLElement> {
let pending = false;
let wentUp: boolean | undefined;
let wentDown: boolean | undefined;
let wentLeft: boolean | undefined;
let wentRight: boolean | undefined;
let checkAndEmit = (e: Event) => {
let wentXStart: boolean | undefined;
let wentXEnd: boolean | undefined;
let checkAndEmit = () => {
let tDiffSec = (Date.now() - lastT) / 1000;
let vertDist = element.scrollTop - lastTop;
let horzDist = element.scrollLeft - lastLeft;
let horzDist = Math.abs(element.scrollLeft) - Math.abs(lastLeft);
if (vertDist < 0) wentDown = !(wentUp = true);
if (vertDist > 0) wentDown = !(wentUp = false);
if (horzDist < 0) wentRight = !(wentLeft = true);
if (horzDist > 0) wentRight = !(wentLeft = false);
if (horzDist < 0) wentXEnd = !(wentXStart = true);
if (horzDist > 0) wentXEnd = !(wentXStart = false);
lastTop = element.scrollTop;
lastLeft = element.scrollLeft;
lastT = Date.now();
let event: UIScrollEvent;
if (lastEventT < lastT - 200) {
event = new UIScrollEvent("ScrollEnd", scrollContainer, undefined, e);
pending = false;
} else {
event = new UIScrollEvent("Scroll", scrollContainer, undefined, e);
setTimeout(checkAndEmit, 250);
pending = true;
}
event.scrolledDown = wentDown;
event.scrolledUp = wentUp;
event.scrolledLeft = wentLeft;
event.scrolledRight = wentRight;
event.atTop = lastTop <= scrollContainer.topThreshold;
event.atLeft = lastLeft <= scrollContainer.leftThreshold;
event.atBottom =
lastTop + element.clientHeight >=
element.scrollHeight - scrollContainer.bottomThreshold;
event.atRight =
lastLeft + element.clientWidth >=
element.scrollWidth - scrollContainer.rightThreshold;
event.verticalVelocity =
Math.abs(vertDist / (window.innerHeight || 1)) / (tDiffSec || 0.1);
event.horizontalVelocity =
Math.abs(horzDist / (window.innerWidth || 1)) / (tDiffSec || 0.1);
const makeEvent = (name: string) => {
let event = new UIScrollEvent(name, scrollContainer);
event.yOffset = lastTop;
event.xOffset = lastLeft;
lastLeft = Math.abs(lastLeft);
event.scrolledDown = wentDown;
event.scrolledUp = wentUp;
event.scrolledHorizontalStart = wentXStart;
event.scrolledHorizontalEnd = wentXEnd;
event.atTop = lastTop <= scrollContainer.topThreshold;
event.atHorizontalStart = lastLeft <= scrollContainer.horizontalThreshold;
event.atBottom =
lastTop + element.clientHeight >=
element.scrollHeight - scrollContainer.bottomThreshold;
event.atHorizontalEnd =
lastLeft + element.clientWidth >=
element.scrollWidth - scrollContainer.horizontalThreshold;
event.verticalVelocity =
Math.abs(vertDist / (window.innerHeight || 1)) / (tDiffSec || 0.1);
event.horizontalVelocity =
Math.abs(horzDist / (window.innerWidth || 1)) / (tDiffSec || 0.1);
return event.freeze();
};
if (scrollContainer.managedState) {
scrollContainer.emit(event.freeze());
scrollContainer.emit(makeEvent("Scroll"));
if (lastEventT < lastT - 200) {
scrollContainer.emit(makeEvent("ScrollEnd"));
pending = false;
} else {
setTimeout(checkAndEmit, 250);
pending = true;
}
}
};
element.onscroll = (e: Event) => {
lastEventT = Date.now();
if (!pending) checkAndEmit(e);
if (!pending) checkAndEmit();
};
}
}
Expand Down Expand Up @@ -157,6 +163,17 @@ class UIContainerRenderer extends RendererBase<UIContainer, HTMLElement> {
}
}

/** Scroll to top/bottom or coordinates */
onUIScrollTarget(e: UIScrollTargetEvent) {
let element = this.getElement();
if (element) {
if (e.target === "top") element.scrollTo({ top: 0 });
if (e.target === "bottom") element.scrollTo({ top: element.scrollHeight });
if (e.yOffset !== undefined) element.scrollTo({ top: e.yOffset });
if (e.xOffset !== undefined) element.scrollTo({ left: e.xOffset });
}
}

/** Handle content changes asynchronously */
async onContentChangeAsync() {
if (!this.component.content) {
Expand Down Expand Up @@ -303,13 +320,13 @@ class UIContainerRenderer extends RendererBase<UIContainer, HTMLElement> {
}
if (
e.name === "ScrollEnd" ||
e.name === "ScrollSnapLeft" ||
e.name === "ScrollSnapRight"
e.name === "ScrollSnapStart" ||
e.name === "ScrollSnapEnd"
) {
// snap horizontally
// snap horizontally (TODO: this probably doesn't work with RTL yet)
let targetLeft: number | undefined;
let furthest = rect.width;
let skew = e.name === "ScrollEnd" ? 0 : e.name === "ScrollSnapLeft" ? 0.25 : -0.25;
let skew = e.name === "ScrollEnd" ? 0 : e.name === "ScrollSnapStart" ? 0.25 : -0.25;
switch (container.horizontalSnap) {
case "start":
for (let r of rects) {
Expand Down Expand Up @@ -363,14 +380,12 @@ class UIContainerRenderer extends RendererBase<UIContainer, HTMLElement> {
this.onScrollEnd(e);
}
}
onScrollSnapLeft(e: UIComponentEvent) {
// TODO: localize for RTL containers (?)
onScrollSnapStart(e: UIComponentEvent) {
if ((this.component as UIScrollContainer).horizontalSnap === "start") {
this.onScrollEnd(e);
}
}
onScrollSnapRight(e: UIComponentEvent) {
// TODO: localize for RTL containers (?)
onScrollSnapEnd(e: UIComponentEvent) {
if ((this.component as UIScrollContainer).horizontalSnap === "end") {
this.onScrollEnd(e);
}
Expand Down

0 comments on commit 075f49d

Please sign in to comment.