Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

353
Visualizações
JavaScript's drawContext is not mathematically correct

I have a tileset that uses 32x32 tiles:

a tileset

I paint it on a canvas to purport a 32x32 tile map. However, it seems that the mathematics isn't right. Why does the canvas paint the tiles that are clearly not within the 32x32 confines of a tile?

For example:

enter image description here

As you can see, the top left of the canvas's 32x32 grid should be ONE tile... however it's cut off:

const appDiv = document.getElementById('app');

const tileSize = 32;
const canvasSize = 480; // 32 (tiles) * 15 (columns) = 480 pixels
const tilesAcross = canvasSize / tileSize; // (Size of Canvas [480] / Tile size [32]) = 15 columns

appDiv.innerHTML = `<h2>Canvas</h2><canvas id="map" width="${canvasSize}" height="${canvasSize}">`;

function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

resizeCanvas();

// Regenerate map on resize
window.onresize = resizeCanvas;

function resizeCanvas() {
  const ctx = document.getElementById('map').getContext('2d');
  const image = new Image();
  image.src = 'https://i.postimg.cc/k4KBLBJh/terrain.png'; // Tileset

  image.onload = () => {
    for (let column = 0; column < tilesAcross; column++) {
      for (let row = 0; row < tilesAcross; row++) {
        ctx.drawImage(
          image, // Image elemnt
          randomIntFromInterval(0, 5) * 32, // sx - The x-axis of top left corner of the rect of the image to draw into context.
          randomIntFromInterval(0, 5) * 32, // sy - The y-axis of top left corner of the rect of the image to draw into context.
          32, // sWidth - The width of the rect of the image to draw into context.
          32, //  sHeight - The height of the rect of the image to draw into the destination context.
          row * 32, // dx - The x-axis coordinate in the canvas at which to place the top-left corner of the image.
          column * 32, // dy - The y-axis coordinate in the canvas at which to place the top-left corner of the image.
          32, // dWidth - The width to draw the image in the canvas. This allows scaling of the drawn image.
          32 // dHeight- The width to draw the image in the canvas. This allows scaling of the drawn image.
        );
      }
    }
  };
}
canvas {
  background: black;
}
<div id="app"></div>

<style src="./style.css"></style>

about 4 years ago · Juan Pablo Isaza
1 Respostas
Responde à pergunta

0

The tiles in your image are not 32x32px, more like 28.56px.

I think you need to re-render the spritesheet. You won't get happy with this one because you'll always have lines at the edges where for one row/column the pixels of two tiles have been interpolated.

And if you stretch them then they will get blurry.

const appDiv = document.getElementById('app');

const tileSize = 32;
const canvasSize = 480; // 32 (tiles) * 15 (columns) = 480 pixels
const tilesAcross = canvasSize / tileSize; // (Size of Canvas [480] / Tile size [32]) = 15 columns

appDiv.innerHTML = `<h2>Canvas</h2><canvas id="map" width="${canvasSize}" height="${canvasSize}">`;

function randomIntFromInterval(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

resizeCanvas();

// Regenerate map on resize
window.onresize = resizeCanvas;

function resizeCanvas() {
  const ctx = document.getElementById('map').getContext('2d');
  const image = new Image();
  image.src = 'https://i.postimg.cc/k4KBLBJh/terrain.png'; // Tileset

  image.onload = () => {
    const {naturalWidth, naturalHeight} = image;
    
    const tileWidth = image.naturalWidth / 9;
    const tileHeight = image.naturalHeight / 28;
      
    console.log({
      tileWidth, 
      tileHeight,
      naturalWidth, 
      naturalHeight,
    })
      
    for (let column = 0; column < tilesAcross; column++) {
      for (let row = 0; row < tilesAcross; row++) {
        ctx.drawImage(
          image, // Image elemnt
          randomIntFromInterval(0, 5) * tileWidth, // sx - The x-axis of top left corner of the rect of the image to draw into context.
          randomIntFromInterval(0, 5) * tileHeight, // sy - The y-axis of top left corner of the rect of the image to draw into context.
          tileWidth, // sWidth - The width of the rect of the image to draw into context.
          tileHeight, //  sHeight - The height of the rect of the image to draw into the destination context.
          row * 32, // dx - The x-axis coordinate in the canvas at which to place the top-left corner of the image.
          column * 32, // dy - The y-axis coordinate in the canvas at which to place the top-left corner of the image.
          32, // dWidth - The width to draw the image in the canvas. This allows scaling of the drawn image.
          32 // dHeight- The width to draw the image in the canvas. This allows scaling of the drawn image.
        );
      }
    }
  };
}
canvas {
  background: black;
}
<div id="app"></div>

<style src="./style.css"></style>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda