Pixel Art Editor

by Ben Gillbanks

HTML

<canvas id="tilemapCanvas" width="320" height="320"></canvas>
<button id="saveButton">Save</button>
<button id="loadButton">Load</button>
<div id="tileSelection"></div>

CSS

.tile-button {
    width: 32px;
    display: inline-block;
    margin: 2px; /* Optional: Add margin to separate buttons */
    box-sizing: border-box;
    padding: 0;
}

JavaScript

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

const TILE_SIZE = 32;
const ROWS = canvas.height / TILE_SIZE;
const COLS = canvas.width / TILE_SIZE;

const tilemap = new Array(ROWS).fill().map(() => new Array(COLS).fill(0));
let selectedTile = 1;
let drawing = false;

canvas.addEventListener("mousedown", () => (drawing = true));
canvas.addEventListener("mouseup", () => (drawing = false));
canvas.addEventListener("mousemove", drawTile);
canvas.addEventListener("click", drawTile);

function drawTile(e) {
    if (drawing || e.type === "click") {
        const rect = canvas.getBoundingClientRect();
        const x = Math.floor((e.clientX - rect.left) / TILE_SIZE);
        const y = Math.floor((e.clientY - rect.top) / TILE_SIZE);
        if (x >= 0 && x < COLS && y >= 0 && y < ROWS) {
            tilemap[y][x] = selectedTile;
            drawTilemap();
        }
    }
}

function drawTilemap() {
    for (let i = 0; i < ROWS; i++) {
        for (let j = 0; j < COLS; j++) {
            const tileIndex = tilemap[i][j];
            const tileX = (tileIndex - 1) * TILE_SIZE;
            ctx.drawImage(TILEMAP_IMAGE, tileX, 0, TILE_SIZE, TILE_SIZE, j * TILE_SIZE, i * TILE_SIZE, TILE_SIZE, TILE_SIZE);
        }
    }
}

const TILEMAP_IMAGE = new Image();
TILEMAP_IMAGE.src = createTestTilemapImageURL();

function createTestTilemapImageURL() {
    const testTilemapCanvas = document.createElement("canvas");
    testTilemapCanvas.width = COLS * TILE_SIZE;
    testTilemapCanvas.height = TILE_SIZE;
    const testTilemapCtx = testTilemapCanvas.getContext("2d");

    for (let i = 0; i < COLS; i++) {
        testTilemapCtx.fillStyle = `rgb(${i * 10}, ${i * 20}, ${i * 30})`;
        testTilemapCtx.fillRect(i * TILE_SIZE, 0, TILE_SIZE, TILE_SIZE);
    }

    return testTilemapCanvas.toDataURL();
}

const tileSelection = document.getElementById("tileSelection");
TILEMAP_IMAGE.onload = () => {
    for (let i = 0; i < COLS; i++) {
       ...