Skip to content

Commit

Permalink
Merge pull request #1121 from tribiahq/resize-observer-for-canvas-siz…
Browse files Browse the repository at this point in the history
…e-update

Use a `ResizeObserver` to detect changes in canvas size
  • Loading branch information
xeolabs authored Aug 14, 2023
2 parents 5a97623 + 8f73899 commit d54611d
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 99 deletions.
2 changes: 2 additions & 0 deletions src/viewer/scene/camera/Perspective.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class Perspective extends Component {

this.glRedraw();

this.camera._updateScheduled = true;

this.fire("matrix", this._state.matrix);
}

Expand Down
123 changes: 24 additions & 99 deletions src/viewer/scene/canvas/Canvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,6 @@ class Canvas extends Component {
*/
this.transparent = !!cfg.transparent;

// data-textures: avoid to continuos DOM layout calculations
this.optimizeResizeDetection = true;

/**
* Attributes for the WebGL context
*
Expand Down Expand Up @@ -155,111 +152,39 @@ class Canvas extends Component {
},
false);

// Publish canvas size and position changes on each scene tick

let lastResolutionScale = null;

let lastWindowWidth = null;
let lastWindowHeight = null;

let lastCanvasWidth = null;
let lastCanvasHeight = null;

let lastCanvasOffsetLeft = null;
let lastCanvasOffsetTop = null;

let lastParent = null;

let tickCount = 0;

this._tick = this.scene.on("tick", () => {

tickCount++;

self._canvasSizeChanged = false;
// Attach to resize events on the canvas
let dirtyBoundary = true; // make sure we publish the 1st boundary event

if (self.optimizeResizeDetection) {
if (tickCount < 10) {
return;
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
dirtyBoundary = true;
}
}
});

resizeObserver.observe(this.canvas);

tickCount = 0;

const canvas = this.canvas;

const newResolutionScale = (this._resolutionScale !== lastResolutionScale);
const newWindowSize = (window.innerWidth !== lastWindowWidth || window.innerHeight !== lastWindowHeight);

if (!newWindowSize) {
// This return caused the canvas to never resize in xeokit-bim-viewer
// return;
// Publish canvas size and position changes on each scene tick
this._tick = this.scene.on("tick", () => {
// Only publish if the canvas bounds changed
if (!dirtyBoundary) {
return;
}

const newCanvasSize = (canvas.clientWidth !== lastCanvasWidth || canvas.clientHeight !== lastCanvasHeight);
const newCanvasPos = (canvas.offsetLeft !== lastCanvasOffsetLeft || canvas.offsetTop !== lastCanvasOffsetTop);

const parent = canvas.parentElement;
const newParent = (parent !== lastParent);
dirtyBoundary = false;

if (newResolutionScale || newWindowSize || newCanvasSize || newCanvasPos || newParent) {
// Set the real size of the canvas (the drawable w*h)
self.canvas.width = Math.round(self.canvas.clientWidth * self._resolutionScale);
self.canvas.height = Math.round(self.canvas.clientHeight * self._resolutionScale);

self._canvasSizeChanged = true;
// Publish the boundary change
self.boundary[0] = self.canvas.offsetLeft;
self.boundary[1] = self.canvas.offsetTop;
self.boundary[2] = self.canvas.clientWidth;
self.boundary[3] = self.canvas.clientHeight;

this._spinner._adjustPosition();

if (newResolutionScale || newCanvasSize || newCanvasPos) {

const newWidth = canvas.clientWidth;
const newHeight = canvas.clientHeight;

// TODO: Wasteful to re-count pixel size of each canvas on each canvas' resize
if (newResolutionScale || newCanvasSize) {
let countPixels = 0;
let scene;
for (const sceneId in core.scenes) {
if (core.scenes.hasOwnProperty(sceneId)) {
scene = core.scenes[sceneId];
countPixels += Math.round((scene.canvas.canvas.clientWidth * this._resolutionScale) * (scene.canvas.canvas.clientHeight * this._resolutionScale));
}
}
stats.memory.pixels = countPixels;

canvas.width = Math.round(canvas.clientWidth * this._resolutionScale);
canvas.height = Math.round(canvas.clientHeight * this._resolutionScale);
}

const boundary = this.boundary;

boundary[0] = canvas.offsetLeft;
boundary[1] = canvas.offsetTop;
boundary[2] = newWidth;
boundary[3] = newHeight;

if (!newResolutionScale) {
this.fire("boundary", boundary);
}

lastCanvasWidth = newWidth;
lastCanvasHeight = newHeight;
}

if (newResolutionScale) {
lastResolutionScale = this._resolutionScale;
}

if (newWindowSize) {
lastWindowWidth = window.innerWidth;
lastWindowHeight = window.innerHeight;
}

if (newCanvasPos) {
lastCanvasOffsetLeft = canvas.offsetLeft;
lastCanvasOffsetTop = canvas.offsetTop;
}

lastParent = parent;
}
self.fire("boundary", self.boundary);
});

this._spinner = new Spinner(this.scene, {
Expand Down

0 comments on commit d54611d

Please sign in to comment.