playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
187 lines (186 loc) • 5.61 kB
JavaScript
import { math } from "../../../core/math/math.js";
import { ORIENTATION_HORIZONTAL } from "../../../scene/constants.js";
import { GraphNode } from "../../../scene/graph-node.js";
import { Component } from "../component.js";
import { ElementDragHelper } from "../element/element-drag-helper.js";
class ScrollbarComponent extends Component {
static EVENT_SETVALUE = "set:value";
_orientation = ORIENTATION_HORIZONTAL;
_value = 0;
_handleSize = 0;
_handleEntity = null;
_evtHandleEntityElementAdd = null;
_evtHandleEntityChanges = [];
_handleDragHelper = null;
set orientation(arg) {
if (this._orientation === arg) {
return;
}
this._orientation = arg;
if (this._handleEntity?.element) {
this._handleEntity.element[this._getOppositeDimension()] = 0;
this._rebuildDragHelper();
this._updateHandlePositionAndSize();
}
}
get orientation() {
return this._orientation;
}
set value(arg) {
if (Math.abs(arg - this._value) > 1e-5) {
this._value = math.clamp(arg, 0, 1);
this._updateHandlePositionAndSize();
this.fire("set:value", this._value);
}
}
get value() {
return this._value;
}
set handleSize(arg) {
if (Math.abs(arg - this._handleSize) > 1e-5) {
this._handleSize = math.clamp(arg, 0, 1);
this._updateHandlePositionAndSize();
}
}
get handleSize() {
return this._handleSize;
}
set handleEntity(arg) {
let newEntity;
if (arg instanceof GraphNode) {
newEntity = arg;
} else if (typeof arg === "string") {
newEntity = this.system.app.getEntityFromIndex(arg) ?? null;
} else {
newEntity = null;
}
if (this._handleEntity === newEntity) {
return;
}
if (this._handleEntity) {
this._handleEntityUnsubscribe();
}
this._handleEntity = newEntity;
if (newEntity) {
this._handleEntitySubscribe();
}
}
get handleEntity() {
return this._handleEntity;
}
_handleEntitySubscribe() {
this._evtHandleEntityElementAdd = this._handleEntity.on("element:add", this._onHandleElementGain, this);
if (this._handleEntity.element) {
this._onHandleElementGain();
}
}
_handleEntityUnsubscribe() {
this._evtHandleEntityElementAdd?.off();
this._evtHandleEntityElementAdd = null;
if (this._handleEntity?.element) {
this._onHandleElementLose();
}
}
_handleEntityElementSubscribe() {
const element = this._handleEntity.element;
const handles = this._evtHandleEntityChanges;
handles.push(element.once("beforeremove", this._onHandleElementLose, this));
handles.push(element.on("set:anchor", this._updateHandlePositionAndSize, this));
handles.push(element.on("set:margin", this._updateHandlePositionAndSize, this));
handles.push(element.on("set:pivot", this._updateHandlePositionAndSize, this));
}
_handleEntityElementUnsubscribe() {
for (let i = 0; i < this._evtHandleEntityChanges.length; i++) {
this._evtHandleEntityChanges[i].off();
}
this._evtHandleEntityChanges.length = 0;
}
_onHandleElementGain() {
this._handleEntityElementSubscribe();
this._rebuildDragHelper();
this._updateHandlePositionAndSize();
}
_rebuildDragHelper() {
this._destroyDragHelper();
this._handleDragHelper = new ElementDragHelper(this._handleEntity.element, this._getAxis());
this._handleDragHelper.enabled = this.enabled && this.entity.enabled;
this._handleDragHelper.on("drag:move", this._onHandleDrag, this);
}
_onHandleElementLose() {
this._handleEntityElementUnsubscribe();
this._destroyDragHelper();
}
_onHandleDrag(position) {
if (this._handleEntity && this.enabled && this.entity.enabled) {
this.value = this._handlePositionToScrollValue(position[this._getAxis()]);
}
}
_updateHandlePositionAndSize() {
const handleEntity = this._handleEntity;
if (!handleEntity) return;
const position = handleEntity.getLocalPosition();
position[this._getAxis()] = this._getHandlePosition();
handleEntity.setLocalPosition(position);
if (handleEntity.element) {
handleEntity.element[this._getDimension()] = this._getHandleLength();
}
}
_handlePositionToScrollValue(handlePosition) {
return handlePosition * this._getSign() / this._getUsableTrackLength();
}
_scrollValueToHandlePosition(value) {
return value * this._getSign() * this._getUsableTrackLength();
}
_getUsableTrackLength() {
return Math.max(this._getTrackLength() - this._getHandleLength(), 1e-3);
}
_getTrackLength() {
if (this.entity.element) {
return this._orientation === ORIENTATION_HORIZONTAL ? this.entity.element.calculatedWidth : this.entity.element.calculatedHeight;
}
return 0;
}
_getHandleLength() {
return this._getTrackLength() * this._handleSize;
}
_getHandlePosition() {
return this._scrollValueToHandlePosition(this._value);
}
_getSign() {
return this._orientation === ORIENTATION_HORIZONTAL ? 1 : -1;
}
_getAxis() {
return this._orientation === ORIENTATION_HORIZONTAL ? "x" : "y";
}
_getDimension() {
return this._orientation === ORIENTATION_HORIZONTAL ? "width" : "height";
}
_getOppositeDimension() {
return this._orientation === ORIENTATION_HORIZONTAL ? "height" : "width";
}
_destroyDragHelper() {
this._handleDragHelper?.destroy();
this._handleDragHelper = null;
}
onEnable() {
if (this._handleDragHelper) {
this._handleDragHelper.enabled = true;
}
}
onDisable() {
if (this._handleDragHelper) {
this._handleDragHelper.enabled = false;
}
}
onRemove() {
this._destroyDragHelper();
}
resolveDuplicatedEntityReferenceProperties(oldScrollbar, duplicatedIdsMap) {
if (oldScrollbar.handleEntity) {
this.handleEntity = duplicatedIdsMap[oldScrollbar.handleEntity.guid];
}
}
}
export {
ScrollbarComponent
};