Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a ResizeObserver to detect changes in canvas size #1121

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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