UNPKG

rot-js

Version:

A roguelike toolkit in JavaScript

90 lines (89 loc) 3.09 kB
import Backend from "./backend.js"; import * as Color from "../color.js"; function clearToAnsi(bg) { return `\x1b[0;48;5;${termcolor(bg)}m\x1b[2J`; } function colorToAnsi(fg, bg) { return `\x1b[0;38;5;${termcolor(fg)};48;5;${termcolor(bg)}m`; } function positionToAnsi(x, y) { return `\x1b[${y + 1};${x + 1}H`; } function termcolor(color) { const SRC_COLORS = 256.0; const DST_COLORS = 6.0; const COLOR_RATIO = DST_COLORS / SRC_COLORS; let rgb = Color.fromString(color); let r = Math.floor(rgb[0] * COLOR_RATIO); let g = Math.floor(rgb[1] * COLOR_RATIO); let b = Math.floor(rgb[2] * COLOR_RATIO); return r * 36 + g * 6 + b * 1 + 16; } export default class Term extends Backend { constructor() { super(); this._offset = [0, 0]; this._cursor = [-1, -1]; this._lastColor = ""; } schedule(cb) { setTimeout(cb, 1000 / 60); } setOptions(options) { super.setOptions(options); let size = [options.width, options.height]; let avail = this.computeSize(); this._offset = avail.map((val, index) => Math.floor((val - size[index]) / 2)); } clear() { process.stdout.write(clearToAnsi(this._options.bg)); } draw(data, clearBefore) { // determine where to draw what with what colors let [x, y, ch, fg, bg] = data; // determine if we need to move the terminal cursor let dx = this._offset[0] + x; let dy = this._offset[1] + y; let size = this.computeSize(); if (dx < 0 || dx >= size[0]) { return; } if (dy < 0 || dy >= size[1]) { return; } if (dx !== this._cursor[0] || dy !== this._cursor[1]) { process.stdout.write(positionToAnsi(dx, dy)); this._cursor[0] = dx; this._cursor[1] = dy; } // terminals automatically clear, but if we're clearing when we're // not otherwise provided with a character, just use a space instead if (clearBefore) { if (!ch) { ch = " "; } } // if we're not clearing and not provided with a character, do nothing if (!ch) { return; } // determine if we need to change colors let newColor = colorToAnsi(fg, bg); if (newColor !== this._lastColor) { process.stdout.write(newColor); this._lastColor = newColor; } if (ch != '\t') { // write the provided symbol to the display let chars = [].concat(ch); process.stdout.write(chars[0]); } // update our position, given that we wrote a character this._cursor[0]++; if (this._cursor[0] >= size[0]) { this._cursor[0] = 0; this._cursor[1]++; } } computeFontSize() { throw new Error("Terminal backend has no notion of font size"); } eventToPosition(x, y) { return [x, y]; } computeSize() { return [process.stdout.columns, process.stdout.rows]; } }