TILE EDITOR

by rga4

HTML

<canvas id="ctop" width="320" height="320" style="position: absolute; left: 10px; top: 110px; z-index: 3;">
</canvas>

<canvas id="cgrid" width="320" height="320" style="position: absolute; left: 10px; top: 110px; z-index: 2;"></canvas>

<canvas id="cimg" width="320" height="320" style="position: absolute; left: 10px; top: 110px; z-index: 1;"></canvas>

<div>
<span>Selected: </span><span id="info">none</span><br>
<input type="file" id="loadCellButton" multiple accept="image/*" onchange="loadFilesToCell(this.files)" style="display: none;">
<label class="button" for="loadCellButton">Load image to cell</label>
</div>

<button id="saveButton" name="save" style="display: none;">Save image</button>
<label class="button" for="saveButton">Save image</label>
<input type="file" id="loadButton" multiple accept="image/*" onchange="loadFiles(this.files)" style="display: none;">
<label class="button" for="loadButton">Load image</label>

<div>
<input title="Cell size" type="text" id="tileSize" maxlength="3" size="5" value="16" />
<input title="Width (cells)" type="text" id="wSize" maxlength="3" size="5" value="16" />
<input title="Height (cells)" type="text" id="hSize" maxlength="3" size="5" value="16" />
<button id="setSize" style="display: none;" onclick="setCanvasSize()"></button><label class="button" for="setSize">Set size</label>
</div>

CSS

.button {
  display: inline-block;
  padding: 2px;
  background: #ccc;
  cursor: pointer;
  border-radius: 5px;
  border: 1px solid #b0b0b0;
}
.button:hover {
  background: #ddd;
}

JavaScript

function getById(id) {
	return document.getElementById(id);
}

info = getById('info');
TILE_SIZE = 16;
TILE_CNT_W = 16;
TILE_CNT_H = 16;
SELECTED_COLOR = "rgba(200, 0, 100, 0.8)";
CURSOR_COLOR = "rgba(0, 0, 100, 0.8)";
GRID_COLOR = "rgba(200, 200, 200, 0.8)";

topc = getById('ctop');		// TOP layer (cursor, events)
gridc = getById('cgrid');	// GRID layer
imgc = getById('cimg');		// IMAGE layer

cx = cy = -1; // mouse cell coord (-1 - out of cells)
sx = sy = -1; // selected cell coord (-1 - none)

function setCanvasSize() {
  function getX(c) {
    c.width  = TILE_SIZE * TILE_CNT_W;
    c.height = TILE_SIZE * TILE_CNT_H;
    return c.getContext('2d');
  }
  TILE_SIZE = Number(getById('tileSize').value);
  TILE_CNT_W = Number(getById('wSize').value);
  TILE_CNT_H = Number(getById('hSize').value);
	topx = getX(topc);
  gridx = getX(gridc);
  imgx = getX(imgc);
	drawGrid();
}

getById('saveButton').addEventListener('click', function(event) {
	var saveCanvasAsPNG = function(canvas, fileName) {
    canvas.toBlob(function(blob) {
        let URLObj = window.URL || window.webkitURL;
        let a = document.createElement("a");  
        a.href = URLObj.createObjectURL(blob);
        a.download = fileName + ".png";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
		});
	};
  saveCanvasAsPNG(imgc, "image");  
});

// ##################### TOP layer ###################################

var topxDrawCell = function(x, y, style) {
  if (x<0) return;
  context = topx;
  context.beginPath();
	context.strokeStyle = style;
  context.moveTo(x*TILE_SIZE, y*TILE_SIZE);
  context.lineTo(x*TILE_SIZE+TILE_SIZE, y*TILE_SIZE);
  context.lineTo(x*TILE_SIZE+TILE_SIZE, y*TILE_SIZE+TILE_SIZE);
  context.lineTo(x*TILE_SIZE, y*TILE_SIZE+TILE_SIZE);
  context.lineTo(x*TILE_SIZE, y*TILE_SIZE);
  context.stroke();
}
var topxClear = function() {
  topx.beginPath();
  topx.clearRect(0, 0, TILE_SIZE * TILE_CNT_W, TILE_SIZE * TILE_CNT_H);
}

// Listen for...