Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

355
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda