search

Home  >  Q&A  >  body text

Why using devicePixelRatio doesn't work in context

My question is about using devicePixelRatio. Consider the following example:

const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const size = 5;

  canvas.style.width = `${size}px`;
  canvas.style.height = `${size}px`;

  const scale = window.devicePixelRatio;
  canvas.width = Math.floor(size * scale);
  canvas.height = Math.floor(size * scale);
  canvas.style.backgroundColor="red";
  ctx.fillStyle = "black";
  ctx.fillRect( 3, 3, 1,1 );

What I want is this:

My screen's devicePixelRatio is equal to 2.

My goal is to display points of size 1x1 in a canvas of size 5x5.

I applied what I understood, I doubled the size of the drawing buffer compared to the size of the display buffer.

For point size: 1x1, the results are good.

But the canvas is still twice the size. 10x10 For what? The explanation is of course obvious...


Rewritten my question on May 1st, unclear

The window.devicePixelRatio value returned by my screen is equal to 2

My goal is to write code that displays pixels in a square.

The size of the square is 5x5 pixels.

I tried using the following code:

  const canvas = document.getElementById("canvas");
  const ctx = canvas.getContext("2d");
  const size = 5;

  canvas.style.width = `${size}px`;
  canvas.style.height = `${size}px`;

  const scale = window.devicePixelRatio;
  canvas.width = Math.floor(size * scale);
  canvas.height = Math.floor(size * scale);
  canvas.style.backgroundColor="red";
  ctx.fillStyle = "black";
  ctx.fillRect( 3, 3, 1,1 );

This is the result: I copied and pasted the screenshot

It's under Gimp, I zoomed in and added a grid

Black dot, the result of ctx.fillRect(3, 3, 1,1) is exactly the size I want.

But the size of the red background is 10 x 10. I want it to be 5x5

P粉757432491P粉757432491352 days ago402

reply all(1)I'll reply

  • P粉529245050

    P粉5292450502024-01-11 14:01:10

    From what I understand, what the OP wants is a canvas with physical pixels of 5x5px and points of 1x1px, here is another attempt without using .scale:

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const size = 5;
    const scale = window.devicePixelRatio;
    
    canvas.style.width = `${size}px`;
    canvas.style.height = `${size}px`;
    canvas.style.transform = `scale(${1 / scale })`;
    canvas.style.transformOrigin = 'top left';
    
    canvas.width = size;
    canvas.height = size;
    canvas.style.backgroundColor = 'red';
    ctx.fillStyle = 'black';
    ctx.fillRect(3, 3, 1, 1);
    <canvas id="canvas" />


    Original solution

    By default, the context and canvas maintain two different logics. The context is the drawing buffer, and the canvas is only responsible for scaling the results of the drawing buffer to the correct size.

    In order to draw on the canvas for high device pixel ratio devices while ensuring that the canvas maintains the same drawing buffer, you can use the ctx.scale method which should be based on your Value passed in (e.g. devicePixelRatio):

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const size = 5;
    
    canvas.style.width = `${size}px`;
    canvas.style.height = `${size}px`;
    
    const scale = window.devicePixelRatio;
    canvas.width = Math.floor(size * scale);
    canvas.height = Math.floor(size * scale);
    canvas.style.backgroundColor = 'red';
    ctx.scale(scale, scale);
    ctx.fillStyle = 'black';
    ctx.fillRect(3, 3, 1, 1);
    <canvas id="canvas" />

    reply
    0
  • Cancelreply