Last active
September 23, 2022 20:47
-
-
Save greggman/efa3ba6ee0984684340ba0ee0e2af779 to your computer and use it in GitHub Desktop.
Canvas Resize Method Comparison (via WebGL)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 0; | |
background-color: white; | |
} | |
.outer { | |
margin: 0 auto; | |
width: 80%; | |
} | |
canvas { | |
width: 100%; | |
height: 100px; | |
display: block; | |
background-color: red; | |
} | |
.bad { | |
color: red; | |
font-weight: bold; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="outer"> | |
<div>using round(clientWidth * devicePixelRatio)</div> | |
<canvas id="use-clientWidth"></canvas> | |
<div>using round(getBoundingClientRect().width * devicePixelRatio)</div> | |
<canvas id="use-getBoundingClientRect"></canvas> | |
<div>using ResizeObserver (<span id="dpr-support"></span>)</div> | |
<canvas id="use-ResizeObserver"></canvas> | |
<div class | |
<div id="warning" style="color: red; display: none">(warning: no support for device-pixel-content-box)</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Canvas Resize Method Comparison | |
// from https://webglfundamentals.org/webgl/webgl-resize-the-canvas-comparison.html | |
function setupCanvas(canvas, resizeFn) { | |
const gl = canvas.getContext('webgl2', {antialias: false}); | |
const createShader = (gl, type, src) => { | |
const sh = gl.createShader(type); | |
gl.shaderSource(sh, src); | |
gl.compileShader(sh); | |
console.log(gl.getShaderInfoLog(sh)); | |
return sh; | |
}; | |
const prg = gl.createProgram(); | |
gl.attachShader(prg, createShader(gl, gl.VERTEX_SHADER, `#version 300 es | |
void main() { | |
ivec2 unitQuad = ivec2( | |
gl_VertexID / 6 + gl_VertexID % 2, | |
(gl_VertexID / 2 + gl_VertexID / 3) % 2); | |
gl_Position = vec4(vec2(unitQuad) * 2.0 - 1.0, 0, 1); | |
} | |
`)); | |
gl.attachShader(prg, createShader(gl, gl.FRAGMENT_SHADER, `#version 300 es | |
precision highp float; | |
uniform vec2 resolution; | |
out vec4 fragColor; | |
void main() { | |
vec2 odd = floor(mod(gl_FragCoord.xy, vec2(2))); | |
vec4 hStripe = mix(vec4(0,0,0,1), vec4(1), odd.y); | |
vec4 vStripe = mix(vec4(0,0,0,1), vec4(1), odd.x); | |
fragColor = mix(hStripe, vStripe, step(resolution.x / 2.0, gl_FragCoord.x)); | |
} | |
`)); | |
gl.linkProgram(prg); | |
gl.useProgram(prg); | |
const resolutionLoc = gl.getUniformLocation(prg, 'resolution'); | |
const drawFn = (displayWidth, displayHeight) => { | |
canvas.width = displayWidth; | |
canvas.height = displayHeight; | |
gl.viewport(0, 0, displayWidth, displayHeight); | |
gl.uniform2f(resolutionLoc, displayWidth, displayHeight); | |
gl.drawArrays(gl.TRIANGLES, 0, 6); | |
}; | |
resizeFn(canvas, drawFn); | |
} | |
setupCanvas(document.querySelector('#use-clientWidth'), (canvas, drawFn) => { | |
const resizeAndDraw = () => { | |
const dpr = window.devicePixelRatio; | |
const displayWidth = Math.round(canvas.clientWidth * dpr); | |
const displayHeight = Math.round(canvas.clientHeight * dpr); | |
drawFn(displayWidth, displayHeight); | |
}; | |
resizeAndDraw(); | |
window.addEventListener('resize', resizeAndDraw); | |
}); | |
setupCanvas(document.querySelector('#use-getBoundingClientRect'), (canvas, drawFn) => { | |
const resizeAndDraw = () => { | |
const dpr = window.devicePixelRatio; | |
const {width, height} = canvas.getBoundingClientRect(); | |
const displayWidth = Math.round(width * dpr); | |
const displayHeight = Math.round(height * dpr); | |
drawFn(displayWidth, displayHeight); | |
}; | |
resizeAndDraw(); | |
window.addEventListener('resize', resizeAndDraw); | |
}); | |
setupCanvas(document.querySelector('#use-ResizeObserver'), (canvas, drawFn) => { | |
const canvasToDisplaySizeMap = new Map([[canvas, [300, 150]]]); | |
const dprSupportElem = document.querySelector('#dpr-support'); | |
const resizeAndDraw = () => { | |
const [displayWidth, displayHeight] = canvasToDisplaySizeMap.get(canvas); | |
drawFn(displayWidth, displayHeight); | |
}; | |
function onResize(entries) { | |
for (const entry of entries) { | |
let width; | |
let height; | |
let dpr = window.devicePixelRatio; | |
let dprSupport = false; | |
if (entry.devicePixelContentBoxSize) { | |
// NOTE: Only this path gives the correct answer | |
// The other paths are an imperfect fallback | |
// for browsers that don't provide anyway to do this | |
width = entry.devicePixelContentBoxSize[0].inlineSize; | |
height = entry.devicePixelContentBoxSize[0].blockSize; | |
dpr = 1; // it's already in width and height | |
dprSupport = true; | |
} else if (entry.contentBoxSize) { | |
if (entry.contentBoxSize[0]) { | |
width = entry.contentBoxSize[0].inlineSize; | |
height = entry.contentBoxSize[0].blockSize; | |
} else { | |
// legacy | |
width = entry.contentBoxSize.inlineSize; | |
height = entry.contentBoxSize.blockSize; | |
} | |
} else { | |
// legacy | |
width = entry.contentRect.width; | |
height = entry.contentRect.height; | |
} | |
const displayWidth = Math.round(width * dpr); | |
const displayHeight = Math.round(height * dpr); | |
canvasToDisplaySizeMap.set(entry.target, [displayWidth, displayHeight]); | |
resizeAndDraw(); | |
dprSupportElem.textContent = dprSupport ? "dpr supported 😀" : "dpr not supported 😢"; | |
dprSupportElem.classList.toggle('bad', !dprSupport); | |
} | |
} | |
resizeAndDraw(); | |
const resizeObserver = new ResizeObserver(onResize); | |
resizeObserver.observe(canvas, {box: 'content-box'}); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"name":"Canvas Resize Method Comparison (via WebGL)","settings":{},"filenames":["index.html","index.css","index.js"]} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment