UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

187 lines (186 loc) 5.61 kB
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 };