Tile map editor - drag version

Due to popular demand :), here is a version of my Tile map editor that let's paint in multiple cells by dragging the mouse while holding the button down. The right button clears the tiles.

Having to handle both the 'mousedown' and 'click' events introduced some complexity, so the code got a bit longer:



<html>
<body>
<canvas id='myCanvaswidth='600height='800style='position:absoluteleft:0top:0'></canvas>
<label id='resultstyle='position:absoluteleft:0top:550'>Click on the image at the bottom to select a tilethen click on the grid to draw.</label>
<script>
let image = new Image();
image.src = 'Tiles_32x32.png';
const tileWidth = 32,
  tileHeight = 32;
const mapRows = 8,
  mapColumns = 18;
const sourceWidth = 256,
  sourceHeight = 256;
let tiles = new Array(mapColumns * mapRows);
let mapHeight = mapRows * tileHeight;
let mapWidth = mapColumns * tileWidth;
let sourceXsourceYsourceTile;
let canvas = document.getElementById('myCanvas');
let context = canvas.getContext('2d');
let mouseDown;
canvas.addEventListener('mousedown', doMouseDown);
document.addEventListener('contextmenu', event => event.preventDefault());
canvas.addEventListener('mousemove', doMouseMove);
canvas.addEventListener('click', doMouseClick);
canvas.addEventListener('mouseup', doMouseUp);
image.addEventListener('load', redrawSource);
// draw the grid
 
for (let i = 0i <= mapColumnsi++) {
  context.moveTo(i * tileWidth0);
  context.lineTo(i * tileWidthmapHeight);
}
context.stroke();
for (let i = 0i <= mapRowsi++) {
  context.moveTo(0i * tileHeight);
  context.lineTo(mapWidthi * tileHeight);
}
context.stroke();
 
function redrawSource() {
  context.drawImage(image00sourceWidthsourceHeight0mapHeightsourceWidthsourceHeight);
}
 
function doMouseUp(e) {
  mouseDown = false;
  // update the string    
  let string = 'let tiles = [';
  for (let i = 0i < mapColumns * mapRowsi++) {
    if (tiles[i] != undefinedstring = string + tiles[i];
    string = string + ',';
  }
  string = string + '];';
  document.getElementById('result').innerHTML = string;
}
 
function doMouseDown(e) {
  mouseDown = true;
  let x = e.clientX;
  let y = e.clientY;
  let gridX = Math.floor(x / tileWidth) * tileWidth;
  let gridY = Math.floor(y / tileHeight) * tileHeight;
 
  if (y > mapHeight && y < (mapHeight + sourceHeight) && x < sourceWidth) { // source
    let tileX = Math.floor(x / tileWidth);
    let tileY = Math.floor((y - mapHeight) / tileHeight);
    sourceTile = tileY * (sourceWidth / tileWidth) + tileX;
    sourceX = gridX;
    sourceY = gridY - mapHeight;
    redrawSource();
    drawBox();
  }
}
 
function doMouseMove(e) {
  let x = e.clientX;
  let y = e.clientY;
  let gridXgridY;
  gridX = Math.floor(x / tileWidth) * tileWidth;
  gridY = Math.floor(y / tileHeight) * tileHeight;
 
 
  if (y > mapHeight && y < (mapHeight + sourceHeight) && x < sourceWidth) { // source
    context.clearRect(0mapHeightsourceWidthsourceHeight);
    redrawSource();
    context.beginPath();
    context.strokeStyle = 'blue';
    context.rect(gridXgridYtileWidthtileHeight);
    context.stroke();
    drawBox();
 
  }
 
  if (mouseDown == truedrawTile(e);
}
 
function drawBox() {
  context.beginPath();
  context.strokeStyle = 'red';
  context.rect(sourceXsourceY + mapHeighttileWidthtileHeight);
  context.stroke();
}
 
function doMouseClick(e) {
  drawTile(e);
}
 
function drawTile(e) {
  let x = e.clientX;
  let y = e.clientY;
  let gridXgridY;
  gridX = Math.floor(x / tileWidth) * tileWidth;
  gridY = Math.floor(y / tileHeight) * tileHeight;
  if (y < mapHeight && x < mapWidth) { // target
    context.clearRect(gridXgridYtileWidthtileHeight);
    context.drawImage(imagesourceXsourceYtileWidthtileHeightgridXgridYtileWidthtileHeight);
    let tileX = Math.floor(x / tileWidth);
    let tileY = Math.floor(y / tileHeight);
    let targetTile = tileY * mapColumns + tileX;
    tiles[targetTile] = sourceTile;
    if (e.button == 2) {
      context.clearRect(gridXgridYtileWidthtileHeight);
      context.beginPath();
      context.strokeStyle = 'black';
      context.rect(gridXgridYtileWidthtileHeight);
      context.stroke();
      tiles[targetTile] = null
    };
  }
}
</script>
</body></html>





Check out these programming tutorials:

JavaScript:

Optical illusion (18 lines)

Oldschool fire effect (20 lines)

Fireworks (60 lines)

Animated fractal (32 lines)

Physics engine for beginners

Starfield (21 lines)

Yin Yang with a twist (4 circles and 20 lines)

Interactive animated sprites

Your first program in JavaScript: you need 5 minutes and a notepad


Fractals in Excel

Python in Blender 3d:

Domino effect (10 lines)


Wrecking ball effect (14 lines)

3d fractal in Blender Python