简体   繁体   English

将 canvas 调整为视口而不损失质量

[英]Resize canvas to viewport without loosing quality

I am trying to have a canvas fill the entire viewport and resize, whenever the user resizes the browser window.每当用户调整浏览器 window 的大小时,我都试图让 canvas 填充整个视口并调整大小。 However, when I try to use a size of 100% , it looses quality.但是,当我尝试使用100%的大小时,它会降低质量。

I am kind of a newb in JavaScript programming.我是 JavaScript 编程的新手。

Can someone please help me?有人可以帮帮我吗?

I figured out a way:我想出了一个办法:

I calculate a scaling factor, by which I scale the size, but not the position of each element drawn.我计算一个缩放因子,通过它我缩放大小,但不是每个绘制元素的 position。 I do not want to scale the position, because then some elements might be off screen.我不想缩放 position,因为这样一些元素可能会不在屏幕上。 Thus I can not use setTransform , as suggested in the comments.因此,正如评论中所建议的,我不能使用setTransform Here is the code I used for calculating the scaling factor.这是我用于计算比例因子的代码。 If someone has improvements, please share them in the comments below!如果有人有改进,请在下面的评论中分享!

if (window.screen.width > window.screen.height)
    scalingFactor = window.screen.width * window.devicePixelRatio / 1280;
else
    scalingFactor = window.screen.height * window.devicePixelRatio / 720;

The easiest way to resize a canvas with losing the data currently on it is to store the data, then resize the canvas (which clears it), then redraw the data into the canvas.在丢失当前数据的情况下调整 canvas 大小的最简单方法是存储数据,然后调整 canvas 的大小(将其清除),然后将数据重新绘制到 ZFCC790C72A86190DE1ZB549D0DDC6F55C 中。 That would look something like this:看起来像这样:

const data = ctx.getImageData( 0, 0, canvas.width, canvas.height );
canvas.width = innerWidth;
canvas.height = innerHeight;
ctx.putImageData( data, 0, 0 );

In its purest, simplest example it would look something like this:在最纯粹、最简单的例子中,它看起来像这样:

 /* This method does the resize by storing the data and redrawing it. It loses any data outside of the screen, though. */ function onResize( event ){ const data = ctx.getImageData( 0, 0, canvas.width, canvas.height ); canvas.width = innerWidth; canvas.height = innerHeight; ctx.putImageData( data, 0, 0 ); } /* This method is for drawing some content to help visualisation. */ function onRedraw(){ const r = v => Math.floor(Math.random() * v); canvas.width = innerWidth; canvas.height = innerHeight; ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth, innerHeight ); ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth / 2, innerHeight / 2 ); ctx.fillRect( innerWidth / 2, innerHeight / 2, innerWidth / 2, innerHeight / 2 ); } window.addEventListener( 'resize', onResize ); const canvas = document.createElement( 'canvas' ); const ctx = canvas.getContext( '2d' ); const reset = document.getElementById( 'reset' ); document.body.appendChild( canvas ); onRedraw(); redraw.addEventListener( 'click', onRedraw );
 body { padding: 0; margin: 0; overflow: hidden; } button { position: fixed; top: 20px; left: 20px; z-index: 1; }
 <button id="redraw">Redraw</button>

However, you lose data drawn outside the canvas when your window grows and shrinks, as the data is never saved.但是,当您的 window 增长和收缩时,您会丢失在 canvas 之外绘制的数据,因为数据永远不会保存。 We could hold a buffer with our graphics, which could simplify things a bit but makes the code slightly more complicated.我们可以用我们的图形保存一个缓冲区,这可以简化一些事情,但会使代码稍微复杂一些。 In this case, we can use a second canvas that holds all our previously drawn maximum sized screen data, just for reference:在这种情况下,我们可以使用第二个 canvas 来保存我们之前绘制的所有最大屏幕数据,仅供参考:

 /* This method does the resize by storing the data and redrawing it. It retains data outside the screen in a buffer that holds the maximum size ever drawn. */ function onResize( event ){ const data = bufferCtx.getImageData( 0, 0, bufferCanvas.width, bufferCanvas.height ); bufferCanvas.width = Math.max( bufferCanvas.width, innerWidth ); bufferCanvas.height = Math.max( bufferCanvas.height, innerHeight ); bufferCtx.putImageData( data, 0, 0 ); bufferCtx.drawImage( canvas, 0, 0 ); canvas.width = innerWidth; canvas.height = innerHeight; ctx.drawImage( bufferCanvas, 0, 0 ); } /* This method is for drawing some content to help visualisation. */ function onRedraw(){ const r = v => Math.floor(Math.random() * v); canvas.width = innerWidth; canvas.height = innerHeight; ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth, innerHeight ); ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth / 2, innerHeight / 2 ); ctx.fillRect( innerWidth / 2, innerHeight / 2, innerWidth / 2, innerHeight / 2 ); } window.addEventListener( 'resize', onResize ); const canvas = document.createElement( 'canvas' ); const ctx = canvas.getContext( '2d' ); const bufferCanvas = document.createElement( 'canvas' ); const bufferCtx = bufferCanvas.getContext( '2d' ); const reset = document.getElementById( 'reset' ); document.body.appendChild( canvas ); onRedraw(); redraw.addEventListener( 'click', onRedraw );
 body { padding: 0; margin: 0; overflow: hidden; } button { position: fixed; top: 20px; left: 20px; z-index: 1; }
 <button id="redraw">Redraw</button>

If you'de rather use lose no data at all and 'rescale' the canvas the best it can, perhaps best to use something like this:如果您宁愿使用完全不丢失数据并“重新调整” canvas 最好,也许最好使用这样的东西:

 /* This method does the resize by just redrawing the canvas from a buffer: */ function onResize( event ){ bufferCanvas.width = canvas.width; bufferCanvas.height = canvas.height; bufferCtx.drawImage( canvas, 0, 0 ); canvas.width = innerWidth; canvas.height = innerHeight; ctx.drawImage( bufferCanvas, 0, 0, canvas.width, canvas.height ); } /* This method is for drawing some content to help visualisation. */ function onRedraw(){ const r = v => Math.floor(Math.random() * v); canvas.width = innerWidth; canvas.height = innerHeight; ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth, innerHeight ); ctx.fillStyle = `rgb(${r(255)},${r(255)},${r(255)})`; ctx.fillRect( 0, 0, innerWidth / 2, innerHeight / 2 ); ctx.fillRect( innerWidth / 2, innerHeight / 2, innerWidth / 2, innerHeight / 2 ); } window.addEventListener( 'resize', onResize ); const canvas = document.createElement( 'canvas' ); const ctx = canvas.getContext( '2d' ); const bufferCanvas = document.createElement( 'canvas' ); const bufferCtx = bufferCanvas.getContext( '2d' ); const reset = document.getElementById( 'reset' ); document.body.appendChild( canvas ); onRedraw(); redraw.addEventListener( 'click', onRedraw );
 body { padding: 0; margin: 0; overflow: hidden; } button { position: fixed; top: 20px; left: 20px; z-index: 1; }
 <button id="redraw">Redraw</button>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM