This is a short little weekend project to create a ’tile stamper’, or an application that allows you to stamp tiles onto canvas. It can be adapted for use in various projects ranging from image editing to game tile sheets. Right now it is preloaded with a tile sheet that can be used for stamping. Later on I’ll probably add functionality to support uploading of custom tile sheets.

Note that this editor is designed to work with tiles that are 32×32, or 1024 bytes (1 KB) in size.

The JavaScript

$(document).ready(function() {  
  // Uses Modernizr.js to check for canvas support
  function canvasSupport() {
    return Modernizr.canvas;
  }

  canvasApp();

  function canvasApp() {
    // Check for canvas support
    if (!canvasSupport()) {
      return;
    } else {
      // Grab the canvas and set the context to 2d
      var theCanvas = document.getElementById('canvasOne');
      var context = theCanvas.getContext("2d"); 
    }

    // Variables
    var mouseX;
    var mouseY;
    var tileLength = 32; // Both height and width of tile are 32

    var tileSheet = new Image();
    tileSheet.addEventListener('load', startUp, false);
    tileSheet.src = "./img/tanks_sheet.png";

    var imageData = context.createImageData(32, 32);

    // Event handlers
    function startUp() {
      context.fillStyle = "#aaaaaa";
      context.fillRect(0, 0, 256, 256);
      drawTileSheet();
    }

    function drawTileSheet() {
      context.drawImage(tileSheet, 0, 0);
    }

    function highlightTile(tileId, x, y) {
      // redraw tilesheet and highlight selected tile
      context.fillStyle = "#aaaaaa";
      context.fillRect(0, 0, 256, 128);
      drawTileSheet();

      imageData = context.getImageData(x, y, 32, 32);
      // set alpha to 128
      for (j = 3; j < imageData.data.length; j += 4) {
        imageData.data[j] = 128;
      }

      // draw red line around selected tile
      var startX = Math.floor(tileId % 8 ) * 32;
      var startY = Math.floor(tileId / 8 ) * 32;
      context.strokeStyle = "red";
      context.strokeRect(startX, startY, 32, 32);
    }

    function onMouseMove(e) {
      // Accounts for the canvas not being at the top left of screen
      mouseX = e.clientX - theCanvas.offsetLeft;
      mouseY = e.clientY - theCanvas.offsetTop;
    }

    function onMouseClick(e) {
      console.log("click: " + mouseX + "," + mouseY);
      if (mouseY < 128) {
        // Find tile to highlight
        var totalRows = 7; // 8 total rows, but relative zero means we use 7
        var col = Math.floor(mouseX / tileLength);
        var row = Math.floor(mouseY / tileLength);
        var tileId = (row * totalRows) + (col + row);
        highlightTile(tileId, col * tileLength, row * tileLength);
      } else {
        // stamp the selected tile
        var col = Math.floor(mouseX / tileLength);
        var row = Math.floor(mouseY / tileLength);
        context.putImageData(imageData, col * tileLength, row * tileLength);
      }
    }

    // Event listeners
	  theCanvas.addEventListener("mousemove", onMouseMove, false);
    theCanvas.addEventListener("click", onMouseClick, false);
  }

});

The App

You can find a live working version of the current app here: https://www.zesix.com/html5/tileStamper