cedro
Version:
Javascript library to build user interfece based on widgets.
187 lines (157 loc) • 6.63 kB
text/typescript
import { OrientationTypes } from "../types/orientation.type";
import "./styles/scroll.css";
import { Widget } from "./widget.ui";
import { Draggable } from "./draggable.ui";
import { WidgetTypes } from "./widget.types";
const SCROLL_SIZE = 10;
type ScrollData = {
scrollHeight: number;
areaHeight: number;
scrollBarHeight: number;
scrollWidth: number;
areaWidth: number;
scrollBarWidth: number;
scrollWidt: number;
availablePositionSize: number;
ratioScroll: number;
position: number;
scrollPositionY: number;
};
export class Scroll extends Widget {
contentArea: Widget;
orientation: OrientationTypes;
drag: Draggable;
constructor(id: string, contentArea: Widget, orientation: OrientationTypes = "vertical") {
super(id, "div");
this.contentArea = contentArea;
this.orientation = orientation;
this.setType(WidgetTypes.CUSTOM);
this.getBody().style.overflow = "hidden";
this.getBody().style.position = "fixed";
this.addClass("WUIScrollbar");
this.drag = new Draggable(this, orientation);
this.contentArea.subscribe({
event: "wheel",
then: (e, _w) => {
const wheel = e as WheelEvent;
this.contentArea.getBody().scrollBy(0, wheel.deltaY);
this.render();
},
});
this.subscribe({
event: "drag",
then: (_e, _w) => {
this.updateScrollPositionByScrollbar();
},
});
}
private getScrollData(): ScrollData {
let returnData: ScrollData = {
scrollHeight: 0,
areaHeight: 0,
scrollBarHeight: 0,
scrollWidth: 0,
areaWidth: 0,
scrollBarWidth: 0,
scrollWidt: 0,
availablePositionSize: 0,
ratioScroll: 0,
position: 0,
scrollPositionY: 0,
};
if (this.orientation === "vertical") {
returnData.scrollHeight = this.contentArea.getBody().scrollHeight;
returnData.areaHeight = this.contentArea.getH();
returnData.scrollBarHeight =
returnData.areaHeight * (returnData.areaHeight / returnData.scrollHeight);
returnData.availablePositionSize =
returnData.areaHeight - returnData.scrollBarHeight - 1;
returnData.ratioScroll =
this.contentArea.getBody().scrollTop /
(returnData.areaHeight - returnData.scrollBarHeight);
returnData.position = returnData.availablePositionSize * returnData.ratioScroll;
if (returnData.scrollBarHeight >= returnData.areaHeight) {
returnData.scrollBarHeight = returnData.areaHeight;
}
} else if (this.orientation === "horizontal") {
returnData.scrollWidth = this.contentArea.getBody().scrollWidth;
returnData.areaWidth = this.contentArea.getW();
returnData.scrollBarWidth =
returnData.areaWidth * (returnData.areaWidth / returnData.scrollWidth);
returnData.availablePositionSize = returnData.areaWidth - returnData.scrollBarWidth - 1;
returnData.ratioScroll =
this.contentArea.getBody().scrollLeft /
(returnData.areaWidth - returnData.scrollBarWidth);
returnData.position = returnData.availablePositionSize * returnData.ratioScroll;
returnData.scrollPositionY = this.contentArea.getH() + this.contentArea.getY();
if (returnData.scrollBarWidth >= returnData.areaWidth) {
returnData.scrollBarWidth = returnData.areaWidth;
}
}
return returnData;
}
private updateScrollPositionByScrollbar(): void {
const scrollData = this.getScrollData();
if (this.orientation === "vertical") {
const recorrido = scrollData.scrollHeight - scrollData.areaHeight;
const maxY = this.drag.maxY ? this.drag.maxY : 1;
const ratio = (this.getY() - this.contentArea.getY(true)) / maxY;
this.contentArea.getBody().scrollTop = recorrido * ratio;
} else if (this.orientation === "horizontal") {
const recorrido = scrollData.scrollWidth - scrollData.areaWidth;
const maxX = this.drag.maxX ? this.drag.maxX : 1;
const ratio = (this.getX() - this.contentArea.getX(true)) / maxX;
this.contentArea.getBody().scrollLeft = recorrido * ratio;
}
this.run("scroll");
}
public render(): void {
super.render();
const scrollData = this.getScrollData();
if (this.orientation === "vertical") {
if (scrollData.areaHeight < scrollData.scrollHeight) {
this.setVisible(true);
} else {
this.setVisible(false);
return;
}
this.setX(this.contentArea.getX(true) + this.contentArea.getW() - SCROLL_SIZE - 1);
this.setY(1 + this.contentArea.getY(true) + scrollData.position);
this.setH(scrollData.scrollBarHeight);
this.setW(SCROLL_SIZE);
this.raisteTop();
const minY = 1 + this.contentArea.getY(true);
const maxY = this.contentArea.getY(true) + scrollData.availablePositionSize;
this.drag.setMinY(minY);
this.drag.setMaxY(maxY);
if (this.getY() > maxY) {
this.setY(maxY);
}
if (this.getY() < minY) {
this.setY(minY);
}
} else if (this.orientation === "horizontal") {
if (scrollData.areaWidth < scrollData.scrollWidth) {
this.setVisible(true);
} else {
this.setVisible(false);
return;
}
this.setX(1 + this.contentArea.getX(true) + scrollData.position);
this.setY(this.contentArea.getY(true) + scrollData.scrollPositionY - SCROLL_SIZE - 1);
this.setW(scrollData.scrollBarWidth);
this.setH(SCROLL_SIZE);
this.raisteTop();
const minX = 1 + this.contentArea.getX(true);
const maxX = this.contentArea.getX(true) + scrollData.availablePositionSize;
this.drag.setMinX(minX);
this.drag.setMaxX(maxX);
if (this.getX() > maxX) {
this.setX(maxX);
}
if (this.getX() < minX) {
this.setX(minX);
}
}
}
}