web-dev-qa-db-ja.com

HTML5のキャンバスの幅と高さ

HTML5のcanvas要素の幅と高さを固定することは可能ですか?

通常の方法は次のとおりです。

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

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.width, ctx.canvas.height);を使用する必要がありますが、これによってキャンバスがクリアされます。サイズ変更後に表示したいコンテンツを再描画する必要があります。

高さと幅は描画に使用される論理的なキャンバスの寸法であり、CSS属性のstyle.heightおよびstyle.widthとは異なっています。 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>
343
Phrogz

キャンバスには2つのサイズがあります。キャンバス内のピクセルのサイズ(バッキングストアまたはdrawingBuffer)と表示サイズです。ピクセル数は、キャンバス属性を使用して設定されます。 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";

キャンバスを1×1ピクセルにする最も確実な方法は、常に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です(キャンバスに関する限り)。

ノート:

  • キャンバス要素にボーダーやパディングを付けないでください。要素の次元数から差し引くサイズを計算するのは面倒です。
39
gman

どうもありがとうございました!最後に、このコードを使ってぼやけたピクセルの問題を解決しました。

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

「ハーフピクセル」を追加すると、ラインのぼかしが解消されます。

21
user1463699

それを行うための最善の方法:

<canvas id="myChart" style="height: 400px; width: 100px;"></canvas>
0
rohan parab