Properly fix resizing
This commit is contained in:
parent
81e7bd98ff
commit
034c2a2c3f
|
@ -19,6 +19,7 @@ class Renderer {
|
||||||
|
|
||||||
private lastFrameTime: number;
|
private lastFrameTime: number;
|
||||||
private dTime: number;
|
private dTime: number;
|
||||||
|
private nextAnimationFrame?: number;
|
||||||
|
|
||||||
private rotation: number;
|
private rotation: number;
|
||||||
|
|
||||||
|
@ -53,13 +54,63 @@ class Renderer {
|
||||||
this.buffers = {};
|
this.buffers = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
resize() {
|
resizeAndDraw(
|
||||||
this.canvas.width = this.canvas.parentElement!.clientWidth;
|
gl: WebGL2RenderingContext,
|
||||||
this.canvas.height = this.canvas.parentElement!.clientHeight;
|
shader: Shader,
|
||||||
|
observerData: ResizeObserverEntry | null
|
||||||
|
) {
|
||||||
|
if (this.canvas.parentElement === null) {
|
||||||
|
throw new Error("renderer has been removed from dom");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.nextAnimationFrame) {
|
||||||
|
cancelAnimationFrame(this.nextAnimationFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: For this to work, it's *incredibly important* for the
|
||||||
|
// canvas to be overflowable by its parent, and its parent to
|
||||||
|
// have `overflow: hidden` set. If using a flexbox, this means
|
||||||
|
// that the canvas has to be `position: absolute`.
|
||||||
|
let width: number;
|
||||||
|
let height: number;
|
||||||
|
|
||||||
|
if (observerData !== null && observerData.devicePixelContentBoxSize) {
|
||||||
|
width = observerData.devicePixelContentBoxSize[0].inlineSize;
|
||||||
|
height = observerData.devicePixelContentBoxSize[0].blockSize;
|
||||||
|
} else {
|
||||||
|
// Fallback; the above API is even newer than
|
||||||
|
// ResizeObserver, and by setting the observerData to null
|
||||||
|
// we can manually resize at least once without going
|
||||||
|
// through the API.
|
||||||
|
if (this.canvas.parentElement === null) {
|
||||||
|
throw new Error("canvas parent disappeared");
|
||||||
|
}
|
||||||
|
// Note: This *requires* `box-sizing: border-box`
|
||||||
|
({ width, height } =
|
||||||
|
this.canvas.parentElement.getBoundingClientRect());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.canvas.width = width;
|
||||||
|
this.canvas.height = height;
|
||||||
|
|
||||||
|
gl.viewport(0, 0, this.canvas.clientWidth, this.canvas.clientHeight);
|
||||||
|
this.updateProjection(gl, shader);
|
||||||
|
|
||||||
|
// ResizeObserver will call when we should draw, so do our own
|
||||||
|
// time calculation and draw the scene.
|
||||||
|
this.updateTime(performance.now());
|
||||||
|
this.drawScene(gl, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTime(time: number) {
|
||||||
|
this.dTime = time - this.lastFrameTime;
|
||||||
|
this.lastFrameTime = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
initializeScene() {
|
initializeScene() {
|
||||||
this.resize();
|
if (this.canvas.parentElement === null) {
|
||||||
|
throw new Error("canvas was not added to page");
|
||||||
|
}
|
||||||
|
|
||||||
const gl = this.canvas.getContext("webgl2");
|
const gl = this.canvas.getContext("webgl2");
|
||||||
if (gl === null) {
|
if (gl === null) {
|
||||||
|
@ -78,12 +129,30 @@ class Renderer {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
this.initGL(gl, shader);
|
this.initGL(gl, shader);
|
||||||
this.initMatrices(gl, shader);
|
this.updateProjection(gl, shader);
|
||||||
this.initBuffers(gl);
|
this.initBuffers(gl);
|
||||||
this.drawScene(gl, shader);
|
|
||||||
|
try {
|
||||||
|
const observer = new ResizeObserver((elements) => {
|
||||||
|
// We only observe one element
|
||||||
|
const element = elements[0];
|
||||||
|
this.resizeAndDraw(gl, shader, element);
|
||||||
|
});
|
||||||
|
observer.observe(this.canvas.parentElement);
|
||||||
|
} catch (error) {
|
||||||
|
// If the browser does not support ResizeObserver, we
|
||||||
|
// simply don't resize. Resizing is hard enough, just use
|
||||||
|
// a modern browser.
|
||||||
|
if (error instanceof ReferenceError) {
|
||||||
|
console.warn(
|
||||||
|
"Browser does not support `ResizeObserver`. Canvas resizing will be disabled."
|
||||||
|
);
|
||||||
|
} else throw error;
|
||||||
|
}
|
||||||
|
this.resizeAndDraw(gl, shader, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
initMatrices(gl: WebGLRenderingContext, shader: Shader) {
|
updateProjection(gl: WebGLRenderingContext, shader: Shader) {
|
||||||
const projectionMatrix = mat4.create();
|
const projectionMatrix = mat4.create();
|
||||||
mat4.perspective(
|
mat4.perspective(
|
||||||
projectionMatrix,
|
projectionMatrix,
|
||||||
|
@ -264,9 +333,8 @@ class Renderer {
|
||||||
this.overlay.innerText = `${dTime}ms (${cpuTime}ms / ${gpuTime}ms)`;
|
this.overlay.innerText = `${dTime}ms (${cpuTime}ms / ${gpuTime}ms)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
requestAnimationFrame((time) => {
|
this.nextAnimationFrame = requestAnimationFrame((time) => {
|
||||||
this.dTime = time - this.lastFrameTime;
|
this.updateTime(time);
|
||||||
this.lastFrameTime = time;
|
|
||||||
|
|
||||||
this.drawScene(gl, shader);
|
this.drawScene(gl, shader);
|
||||||
});
|
});
|
||||||
|
|
|
@ -101,7 +101,13 @@ function Visualizer({
|
||||||
ref={visualizer}
|
ref={visualizer}
|
||||||
className="is-flex-grow-1 is-clipped is-relative"
|
className="is-flex-grow-1 is-clipped is-relative"
|
||||||
>
|
>
|
||||||
<canvas style={{ display: "block" }}></canvas>
|
<canvas
|
||||||
|
style={{
|
||||||
|
display: "block",
|
||||||
|
position: "absolute",
|
||||||
|
boxSizing: "border-box",
|
||||||
|
}}
|
||||||
|
></canvas>
|
||||||
<span
|
<span
|
||||||
className="is-bottom-left"
|
className="is-bottom-left"
|
||||||
style={{ display: "relative" }}
|
style={{ display: "relative" }}
|
||||||
|
|
Reference in a new issue