treehouse/static/js/components/tairu/editor.js
2024-02-18 23:37:31 +01:00

135 lines
3.9 KiB
JavaScript

import { Sketch } from "treehouse/sandbox.js";
export class TileEditor extends Sketch {
constructor({ tilemap, tileSize }) {
super(tilemap.width * tileSize, tilemap.height * tileSize);
this.colorScheme = {
background: "#F7F7F7",
grid: "#00000011",
tileCursor: "#222222",
tiles: [
"transparent", // never actually drawn to the screen with the default renderer!
"#eb134a",
],
};
this.tilemap = tilemap;
this.tileSize = tileSize;
this.hasFocus = false;
this.paintingTile = null;
this.tileCursor = { x: 0, y: 0 };
this.canvas.addEventListener("mousemove", event => this.mouseMoved(event));
this.canvas.addEventListener("mousedown", event => this.mousePressed(event));
this.canvas.addEventListener("mouseup", event => this.mouseReleased(event));
this.canvas.addEventListener("mouseenter", _ => this.mouseEnter());
this.canvas.addEventListener("mouseleave", _ => this.mouseLeave());
this.canvas.addEventListener("contextmenu", event => event.preventDefault());
// Only draw first frame after the constructor already runs.
// That way we can modify the color scheme however much we want without causing additional
// redraws.
requestAnimationFrame(() => this.draw());
}
draw() {
this.drawBackground();
this.drawTilemap();
this.drawGrid();
if (this.hasFocus) {
this.drawTileCursor();
}
}
drawBackground() {
this.ctx.fillStyle = this.colorScheme.background;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
}
drawTilemap() {
for (let y = 0; y < this.tilemap.height; ++y) {
for (let x = 0; x < this.tilemap.width; ++x) {
let tile = this.tilemap.at(x, y);
if (tile != 0) {
this.ctx.fillStyle = this.colorScheme.tiles[tile];
this.ctx.fillRect(x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize);
}
}
}
}
drawGrid() {
this.ctx.beginPath();
for (let x = 0; x < this.tilemap.width; ++x) {
this.ctx.moveTo(x * this.tileSize, 0);
this.ctx.lineTo(x * this.tileSize, this.canvas.height);
}
for (let y = 0; y < this.tilemap.width; ++y) {
this.ctx.moveTo(0, y * this.tileSize);
this.ctx.lineTo(this.canvas.width, y * this.tileSize);
}
this.ctx.strokeStyle = this.colorScheme.grid;
this.ctx.lineWidth = 1;
this.ctx.stroke();
}
drawTileCursor() {
this.ctx.strokeStyle = this.colorScheme.tileCursor;
this.ctx.lineWidth = 5;
this.ctx.strokeRect(this.tileCursor.x * this.tileSize, this.tileCursor.y * this.tileSize, this.tileSize, this.tileSize);
}
mouseMoved(event) {
this.tileCursor.x = Math.floor(event.offsetX / this.tileSize);
this.tileCursor.y = Math.floor(event.offsetY / this.tileSize);
this.paintTileUnderCursor();
this.draw();
}
mousePressed(event) {
event.preventDefault();
if (event.button == 0) {
this.paintingTile = 1;
} else if (event.button == 2) {
this.paintingTile = 0;
}
this.paintTileUnderCursor();
this.draw();
}
mouseReleased(_event) {
this.stopPainting();
this.draw();
}
mouseEnter() {
this.hasFocus = true;
this.draw();
}
mouseLeave() {
this.hasFocus = false;
this.stopPainting();
this.draw();
}
paintTileUnderCursor() {
if (this.paintingTile != null) {
this.tilemap.setAt(this.tileCursor.x, this.tileCursor.y, this.paintingTile);
}
}
stopPainting() {
this.paintingTile = null;
}
}