UNPKG

terriajs

Version:

Geospatial data visualization platform.

171 lines 8.77 kB
import defined from "terriajs-cesium/Source/Core/defined"; import destroyObject from "terriajs-cesium/Source/Core/destroyObject"; import getTimestamp from "terriajs-cesium/Source/Core/getTimestamp"; import Matrix4 from "terriajs-cesium/Source/Core/Matrix4"; import TaskProcessor from "terriajs-cesium/Source/Core/TaskProcessor"; import loadWithXhr from "../../Core/loadWithXhr"; export default class CesiumRenderLoopPauser { cesiumWidget; postRenderCallback; /** * Gets or sets whether to output info to the console when starting and stopping rendering loop. * @type {boolean} */ verboseRendering = false; /** * Gets or sets whether the render loop is currently paused. * @type {boolean} */ get renderingIsPaused() { return !this.cesiumWidget.useDefaultRenderLoop; } set renderingIsPaused(value) { this.cesiumWidget.useDefaultRenderLoop = !value; } _boundNotifyRepaintRequired; _wheelEvent; _removePostRenderListener; _lastCameraViewMatrix = new Matrix4(); _lastCameraMoveTime = -Number.MAX_VALUE; _originalLoadWithXhr; _originalScheduleTask; constructor(cesiumWidget, postRenderCallback) { this.cesiumWidget = cesiumWidget; this.postRenderCallback = postRenderCallback; const scene = this.cesiumWidget.scene; this._removePostRenderListener = scene.postRender.addEventListener(this.postRender.bind(this)); this._boundNotifyRepaintRequired = this.notifyRepaintRequired.bind(this); const canvas = this.cesiumWidget.canvas; canvas.addEventListener("mousemove", this._boundNotifyRepaintRequired, false); canvas.addEventListener("mousedown", this._boundNotifyRepaintRequired, false); canvas.addEventListener("mouseup", this._boundNotifyRepaintRequired, false); canvas.addEventListener("touchstart", this._boundNotifyRepaintRequired, false); canvas.addEventListener("touchend", this._boundNotifyRepaintRequired, false); canvas.addEventListener("touchmove", this._boundNotifyRepaintRequired, false); if (defined(globalThis.PointerEvent)) { canvas.addEventListener("pointerdown", this._boundNotifyRepaintRequired, false); canvas.addEventListener("pointerup", this._boundNotifyRepaintRequired, false); canvas.addEventListener("pointermove", this._boundNotifyRepaintRequired, false); } // Detect available wheel event this._wheelEvent = undefined; if ("onwheel" in canvas) { // spec event type this._wheelEvent = "wheel"; } else if (defined(globalThis.onmousewheel)) { // legacy event type this._wheelEvent = "mousewheel"; } else { // older Firefox this._wheelEvent = "DOMMouseScroll"; } canvas.addEventListener(this._wheelEvent, this._boundNotifyRepaintRequired, false); window.addEventListener("resize", this._boundNotifyRepaintRequired, false); // keyup & keydown events are used by the pedestrian mode document.addEventListener("keydown", this._boundNotifyRepaintRequired, false); document.addEventListener("keyup", this._boundNotifyRepaintRequired, false); // // Hacky way to force a repaint when an async load request completes const anyLoadWithXhr = loadWithXhr; this._originalLoadWithXhr = anyLoadWithXhr.load; anyLoadWithXhr.load = (url, responseType, method, data, headers, deferred, overrideMimeType, timeout, returnType) => { deferred.promise .finally(this._boundNotifyRepaintRequired) .catch(() => { }); return this._originalLoadWithXhr(url, responseType, method, data, headers, deferred, overrideMimeType, timeout, returnType); }; // // Hacky way to force a repaint when a web worker sends something back. this._originalScheduleTask = TaskProcessor.prototype.scheduleTask; const that = this; TaskProcessor.prototype.scheduleTask = function (parameters, transferableObjects) { const result = that._originalScheduleTask.call(this, parameters, transferableObjects); if (!defined(this._originalWorkerMessageSinkRepaint) && defined(this._worker.onmessage)) { this._originalWorkerMessageSinkRepaint = this._worker.onmessage; const taskProcessor = this; this._worker.onmessage = function (event) { taskProcessor._originalWorkerMessageSinkRepaint(event); if (that.isDestroyed()) { taskProcessor._worker.onmessage = taskProcessor._originalWorkerMessageSinkRepaint; taskProcessor._originalWorkerMessageSinkRepaint = undefined; } else { that.notifyRepaintRequired(); } }; } return result; }; } destroy() { if (this._removePostRenderListener) { this._removePostRenderListener(); } if (this._boundNotifyRepaintRequired) { this.cesiumWidget.canvas.removeEventListener("mousemove", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("mousedown", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("mouseup", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("touchstart", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("touchend", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("touchmove", this._boundNotifyRepaintRequired, false); if (defined(globalThis.PointerEvent)) { this.cesiumWidget.canvas.removeEventListener("pointerdown", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("pointerup", this._boundNotifyRepaintRequired, false); this.cesiumWidget.canvas.removeEventListener("pointermove", this._boundNotifyRepaintRequired, false); } if (this._wheelEvent) { this.cesiumWidget.canvas.removeEventListener(this._wheelEvent, this._boundNotifyRepaintRequired, false); } window.removeEventListener("resize", this._boundNotifyRepaintRequired, false); document.removeEventListener("keyup", this._boundNotifyRepaintRequired, false); document.removeEventListener("keydown", this._boundNotifyRepaintRequired, false); } loadWithXhr.load = this._originalLoadWithXhr; TaskProcessor.prototype.scheduleTask = this._originalScheduleTask; return destroyObject(this); } isDestroyed() { return false; } notifyRepaintRequired() { if (this.verboseRendering && !this.cesiumWidget.useDefaultRenderLoop) { console.log("starting rendering @ " + getTimestamp()); } this._lastCameraMoveTime = getTimestamp(); this.renderingIsPaused = false; } postRender() { // We can safely stop rendering when: // - the camera position hasn't changed in over a second, // - there are no tiles waiting to load, and // - the clock is not animating // - there are no tweens in progress const now = getTimestamp(); const scene = this.cesiumWidget.scene; if (!Matrix4.equalsEpsilon(this._lastCameraViewMatrix, scene.camera.viewMatrix, 1e-5)) { this._lastCameraMoveTime = now; } const cameraMovedInLastSecond = now - this._lastCameraMoveTime < 1000; const surface = scene.globe._surface; const terrainTilesWaiting = !surface._tileProvider || surface._tileLoadQueueHigh.length > 0 || surface._tileLoadQueueMedium.length > 0 || surface._tileLoadQueueLow.length > 0 || surface._debug.tilesWaitingForChildren > 0; const tweens = scene.tweens; if (!cameraMovedInLastSecond && !terrainTilesWaiting && !this.cesiumWidget.clock.shouldAnimate && tweens.length === 0) { if (this.verboseRendering) { console.log("stopping rendering @ " + getTimestamp()); } this.renderingIsPaused = true; } Matrix4.clone(scene.camera.viewMatrix, this._lastCameraViewMatrix); this.postRenderCallback(); } } //# sourceMappingURL=CesiumRenderLoopPauser.js.map