Skip to content

Instantly share code, notes, and snippets.

@callumlocke
Last active April 12, 2024 03:25
Show Gist options
  • Star 53 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save callumlocke/cc258a193839691f60dd to your computer and use it in GitHub Desktop.
Save callumlocke/cc258a193839691f60dd to your computer and use it in GitHub Desktop.
How to fix a canvas so it will look good on retina/high-DPI screens.
/*
UPDATED for 2023 - Now much simpler. The old tricks are no longer needed.
The following code makes an 800×600 canvas that is always as sharp as possible for the device.
You still draw on it as if it's the logical size (800×600 in this case), but everything just
looks sharper on high-DPI screens. Regular non-sharp screens are not affected.
*/
const width = 800
const height = 600
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
// 1. Multiply the canvas's width and height by the devicePixelRatio
const ratio = window.devicePixelRatio || 1
canvas.width = width * ratio
canvas.height = height * ratio
// 2. Force it to display at the original (logical) size with CSS or style attributes
canvas.style.width = width + 'px'
canvas.style.height = height + 'px'
// 3. Scale the context so you can draw on it without considering the ratio.
ctx.scale(ratio, ratio)
@sghall
Copy link

sghall commented Dec 20, 2018

Sweet. Still works. Thanks!

@dzimmermann-tgm
Copy link

I love you.

@handeyeco
Copy link

Thank you!!

@AndriiShtoiko
Copy link

Thanks!

@AndriiShtoiko
Copy link

Couldn't find proper docs if still need/ allow to use .backingStorePixelRatio? Seems to be deprecated? Instead, just use .devicePixelRatio? Pls check this

@DjulLau
Copy link

DjulLau commented Sep 23, 2020

Thanks! Every snippet I found was missing the "scale back down in CSS" part...

@JamesDernie
Copy link

Legend, it works perfectly! Thanks!

@j2is
Copy link

j2is commented Jan 2, 2022

Nice

  • I didn't pass in the width and height but grab that from within the function

  • did a check when there might not be a window (SSR)

  • call this function on resize

    const devicePixelRatio = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
    
    // get current size of the canvas
    const rect = canvas.getBoundingClientRect();
    
    // get width and height
    const { width, height } = rect;
    

@mittnavnermike
Copy link

Thanks, this saved me a lot of time!

If it helps anyone I did a lil' refactor in typescript also including some of @j2is changes.
Seems to me that the .backingStorePixelRatio is deprecated(?), so I removed that as well.

function scaleCanvas(
  canvas: HTMLCanvasElement,
  context: CanvasRenderingContext2D,
  width: number,
  height: number
) {
  // Handle window for SSR
  if (typeof window === 'undefined') return null
  
  // determine the actual ratio we want to draw at
  const ratio = window.devicePixelRatio || 1

  if (devicePixelRatio !== 1) {
    // set the 'real' canvas size to the higher width/height
    canvas.width = width * ratio
    canvas.height = height * ratio

    // ...then scale it back down with CSS
    canvas.style.width = width + 'px'
    canvas.style.height = height + 'px'
  } else {
    // this is a normal 1:1 device; just scale it simply
    canvas.width = width
    canvas.height = height
    canvas.style.width = ''
    canvas.style.height = ''
  }

  // scale the drawing context so everything will work at the higher ratio
  context.scale(ratio, ratio)
}

@atlasan
Copy link

atlasan commented Mar 8, 2023

This worked better for me because it scale the context too! :

function createHiPPICanvas(width, height) {
    const ratio = window.devicePixelRatio;
    const canvas = document.createElement("canvas");
    canvas.width = width * ratio;
    canvas.height = height * ratio;
    canvas.style.width = width + "px";
    canvas.style.height = height + "px";
    canvas.getContext("2d").scale(ratio, ratio);
    return canvas;
}

from https://stackoverflow.com/questions/15661339/how-do-i-fix-blurry-text-in-my-html5-canvas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment