是否有可能修复HTML5画布元素的宽度和高度?

通常的做法如下:

<canvas id="canvas" width="300" height="300"></canvas>

canvas DOM元素有.height和.width属性,对应于height="…"和width="…"属性。将它们设置为JavaScript代码中的数值,以调整画布的大小。例如:

var canvas = document.getElementsByTagName('canvas')[0];
canvas.width  = 800;
canvas.height = 600;

注意,这将清除画布,不过您应该在后面加上ctx。clearRect(0,0, ctx.canvas。宽度,ctx.canvas.height);来处理那些没有完全清除画布的浏览器。你需要重新绘制你想要显示的任何内容在大小改变后。

进一步注意,高度和宽度是用于绘图的逻辑画布尺寸,与样式不同。身高和风格。width CSS属性。如果你不设置CSS属性,画布的内在大小将被用作它的显示大小;如果你确实设置了CSS属性,并且它们与画布尺寸不同,你的内容将在浏览器中缩放。例如:

// Make a canvas that has a blurry pixelated zoom-in
// with each canvas pixel drawn showing as roughly 2x2 on screen
canvas.width  = 400;
canvas.height = 300; 
canvas.style.width  = '800px';
canvas.style.height = '600px';

下面是放大4倍的画布。

var c = document.getElementsByTagName('canvas')[0]; var ctx = c.getContext('2d'); ctx.lineWidth = 1; ctx.strokeStyle = '#f00'; ctx.fillStyle = '#eff'; ctx.fillRect( 10.5, 10.5, 20, 20 ); ctx.strokeRect( 10.5, 10.5, 20, 20 ); ctx.fillRect( 40, 10.5, 20, 20 ); ctx.strokeRect( 40, 10.5, 20, 20 ); ctx.fillRect( 70, 10, 20, 20 ); ctx.strokeRect( 70, 10, 20, 20 ); ctx.strokeStyle = '#fff'; ctx.strokeRect( 10.5, 10.5, 20, 20 ); ctx.strokeRect( 40, 10.5, 20, 20 ); ctx.strokeRect( 70, 10, 20, 20 ); body { background:#eee; margin:1em; text-align:center } canvas { background:#fff; border:1px solid #ccc; width:400px; height:160px } <canvas width="100" height="40"></canvas> <p>Showing that re-drawing the same antialiased lines does not obliterate old antialiased lines.</p>


非常感谢!最后,我用下面的代码解决了像素模糊的问题:

<canvas id="graph" width=326 height=240 style='width:326px;height:240px'></canvas>

加上“半像素”就可以消除线条的模糊。


一个画布有两种尺寸,一个是画布中像素的尺寸(它是backingstore或drawingBuffer),另一个是显示尺寸。像素的数量是使用canvas属性设置的。在HTML中

<canvas width="400" height="300"></canvas>

或者JavaScript

someCanvasElement.width = 400;
someCanvasElement.height = 300;

与之分开的是画布的CSS样式宽度和高度

在CSS中

canvas {  /* or some other selector */
   width: 500px;
   height: 400px;
}

或者JavaScript

canvas.style.width = "500px";
canvas.style.height = "400px";

让画布变成1x1像素的最好方法是总是使用CSS来选择大小,然后写一点JavaScript来让像素的数量与这个大小匹配。

function resizeCanvasToDisplaySize(canvas) {
   // look up the size the canvas is being displayed
   const width = canvas.clientWidth;
   const height = canvas.clientHeight;

   // If it's resolution does not match change it
   if (canvas.width !== width || canvas.height !== height) {
     canvas.width = width;
     canvas.height = height;
     return true;
   }

   return false;
}

为什么这是最好的方法?因为它在大多数情况下都可以工作,而不需要更改任何代码。

这是一个全窗口画布:

const ctx = document.querySelector("#c").getContext("2d"); function render(time) { time *= 0.001; resizeCanvasToDisplaySize(ctx.canvas); ctx.fillStyle = "#DDE"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); const spacing = 64; const size = 48; const across = ctx.canvas.width / spacing + 1; const down = ctx.canvas.height / spacing + 1; const s = Math.sin(time); const c = Math.cos(time); for (let y = 0; y < down; ++y) { for (let x = 0; x < across; ++x) { ctx.setTransform(c, -s, s, c, x * spacing, y * spacing); ctx.strokeRect(-size / 2, -size / 2, size, size); } } ctx.restore(); requestAnimationFrame(render); } requestAnimationFrame(render); function resizeCanvasToDisplaySize(canvas) { // look up the size the canvas is being displayed const width = canvas.clientWidth; const height = canvas.clientHeight; // If it's resolution does not match change it if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; return true; } return false; } body { margin: 0; } canvas { display: block; width: 100vw; height: 100vh; } <canvas id="c"></canvas>

这是一个画布,作为段落中的浮动

const ctx = document.querySelector("#c").getContext("2d"); function render(time) { time *= 0.001; resizeCanvasToDisplaySize(ctx.canvas); ctx.fillStyle = "#DDE"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); const spacing = 64; const size = 48; const across = ctx.canvas.width / spacing + 1; const down = ctx.canvas.height / spacing + 1; const s = Math.sin(time); const c = Math.cos(time); for (let y = 0; y <= down; ++y) { for (let x = 0; x <= across; ++x) { ctx.setTransform(c, -s, s, c, x * spacing, y * spacing); ctx.strokeRect(-size / 2, -size / 2, size, size); } } ctx.restore(); requestAnimationFrame(render); } requestAnimationFrame(render); function resizeCanvasToDisplaySize(canvas) { // look up the size the canvas is being displayed const width = canvas.clientWidth; const height = canvas.clientHeight; // If it's resolution does not match change it if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; return true; } return false; } span { width: 250px; height: 100px; float: left; padding: 1em 1em 1em 0; display: inline-block; } canvas { width: 100%; height: 100%; } <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent cursus venenatis metus. Mauris ac nibh at odio scelerisque scelerisque. Donec ut enim <span class="diagram"><canvas id="c"></canvas></span> vel urna gravida imperdiet id ac odio. Aenean congue hendrerit eros id facilisis. In vitae leo ullamcorper, aliquet leo a, vehicula magna. Proin sollicitudin vestibulum aliquet. Sed et varius justo. <br/><br/> Quisque tempor metus in porttitor placerat. Nulla vehicula sem nec ipsum commodo, at tincidunt orci porttitor. Duis porttitor egestas dui eu viverra. Sed et ipsum eget odio pharetra semper. Integer tempor orci quam, eget aliquet velit consectetur sit amet. Maecenas maximus placerat arcu in varius. Morbi semper, quam a ullamcorper interdum, augue nisl sagittis urna, sed pharetra lectus ex nec elit. Nullam viverra lacinia tellus, bibendum maximus nisl dictum id. Phasellus mauris quam, rutrum ut congue non, hendrerit sollicitudin urna. </p>

这是一个相当大的控制面板中的画布

const ctx = document.querySelector("#c").getContext("2d"); function render(time) { time *= 0.001; resizeCanvasToDisplaySize(ctx.canvas); ctx.fillStyle = "#DDE"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); const spacing = 64; const size = 48; const across = ctx.canvas.width / spacing + 1; const down = ctx.canvas.height / spacing + 1; const s = Math.sin(time); const c = Math.cos(time); for (let y = 0; y < down; ++y) { for (let x = 0; x < across; ++x) { ctx.setTransform(c, -s, s, c, x * spacing, y * spacing); ctx.strokeRect(-size / 2, -size / 2, size, size); } } ctx.restore(); requestAnimationFrame(render); } requestAnimationFrame(render); function resizeCanvasToDisplaySize(canvas) { // look up the size the canvas is being displayed const width = canvas.clientWidth; const height = canvas.clientHeight; // If it's resolution does not match change it if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; return true; } return false; } // ----- the code above related to the canvas does not change ---- // ---- the code below is related to the slider ---- const $ = document.querySelector.bind(document); const left = $(".left"); const slider = $(".slider"); let dragging; let lastX; let startWidth; slider.addEventListener('mousedown', e => { lastX = e.pageX; dragging = true; }); window.addEventListener('mouseup', e => { dragging = false; }); window.addEventListener('mousemove', e => { if (dragging) { const deltaX = e.pageX - lastX; left.style.width = left.clientWidth + deltaX + "px"; lastX = e.pageX; } }); body { margin: 0; } .frame { display: flex; align-items: space-between; height: 100vh; } .left { width: 70%; left: 0; top: 0; right: 0; bottom: 0; } canvas { width: 100%; height: 100%; } pre { padding: 1em; } .slider { width: 10px; background: #000; } .right { flex 1 1 auto; } <div class="frame"> <div class="left"> <canvas id="c"></canvas> </div> <div class="slider"> </div> <div class="right"> <pre> * controls * go * here &lt;- drag this </pre> </div> </div>

这是一个画布作为背景

const ctx = document.querySelector("#c").getContext("2d"); function render(time) { time *= 0.001; resizeCanvasToDisplaySize(ctx.canvas); ctx.fillStyle = "#DDE"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.save(); const spacing = 64; const size = 48; const across = ctx.canvas.width / spacing + 1; const down = ctx.canvas.height / spacing + 1; const s = Math.sin(time); const c = Math.cos(time); for (let y = 0; y < down; ++y) { for (let x = 0; x < across; ++x) { ctx.setTransform(c, -s, s, c, x * spacing, y * spacing); ctx.strokeRect(-size / 2, -size / 2, size, size); } } ctx.restore(); requestAnimationFrame(render); } requestAnimationFrame(render); function resizeCanvasToDisplaySize(canvas) { // look up the size the canvas is being displayed const width = canvas.clientWidth; const height = canvas.clientHeight; // If it's resolution does not match change it if (canvas.width !== width || canvas.height !== height) { canvas.width = width; canvas.height = height; return true; } return false; } body { margin: 0; } canvas { display: block; width: 100vw; height: 100vh; position: fixed; } #content { position: absolute; margin: 0 1em; font-size: xx-large; font-family: sans-serif; font-weight: bold; text-shadow: 2px 2px 0 #FFF, -2px -2px 0 #FFF, -2px 2px 0 #FFF, 2px -2px 0 #FFF; } <canvas id="c"></canvas> <div id="content"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent cursus venenatis metus. Mauris ac nibh at odio scelerisque scelerisque. Donec ut enim vel urna gravida imperdiet id ac odio. Aenean congue hendrerit eros id facilisis. In vitae leo ullamcorper, aliquet leo a, vehicula magna. Proin sollicitudin vestibulum aliquet. Sed et varius justo. </p> <p> Quisque tempor metus in porttitor placerat. Nulla vehicula sem nec ipsum commodo, at tincidunt orci porttitor. Duis porttitor egestas dui eu viverra. Sed et ipsum eget odio pharetra semper. Integer tempor orci quam, eget aliquet velit consectetur sit amet. Maecenas maximus placerat arcu in varius. Morbi semper, quam a ullamcorper interdum, augue nisl sagittis urna, sed pharetra lectus ex nec elit. Nullam viverra lacinia tellus, bibendum maximus nisl dictum id. Phasellus mauris quam, rutrum ut congue non, hendrerit sollicitudin urna. </p> </div>

因为我没有设置属性,所以在每个示例中唯一改变的是CSS(就画布而言)

注:

不要在画布元素上设置边框或填充。计算要从元素的维数中减去的大小是很麻烦的