UNPKG

rot-js

Version:

A roguelike toolkit in JavaScript

137 lines (136 loc) 4.86 kB
import Canvas from "./canvas.js"; import { mod } from "../util.js"; /** * @class Hexagonal backend * @private */ export default class Hex extends Canvas { constructor() { super(); this._spacingX = 0; this._spacingY = 0; this._hexSize = 0; } draw(data, clearBefore) { let [x, y, ch, fg, bg] = data; let px = [ (x + 1) * this._spacingX, y * this._spacingY + this._hexSize ]; if (this._options.transpose) { px.reverse(); } if (clearBefore) { this._ctx.fillStyle = bg; this._fill(px[0], px[1]); } if (!ch) { return; } this._ctx.fillStyle = fg; let chars = [].concat(ch); for (let i = 0; i < chars.length; i++) { this._ctx.fillText(chars[i], px[0], Math.ceil(px[1])); } } computeSize(availWidth, availHeight) { if (this._options.transpose) { availWidth += availHeight; availHeight = availWidth - availHeight; availWidth -= availHeight; } let width = Math.floor(availWidth / this._spacingX) - 1; let height = Math.floor((availHeight - 2 * this._hexSize) / this._spacingY + 1); return [width, height]; } computeFontSize(availWidth, availHeight) { if (this._options.transpose) { availWidth += availHeight; availHeight = availWidth - availHeight; availWidth -= availHeight; } let hexSizeWidth = 2 * availWidth / ((this._options.width + 1) * Math.sqrt(3)) - 1; let hexSizeHeight = availHeight / (2 + 1.5 * (this._options.height - 1)); let hexSize = Math.min(hexSizeWidth, hexSizeHeight); // compute char ratio let oldFont = this._ctx.font; this._ctx.font = "100px " + this._options.fontFamily; let width = Math.ceil(this._ctx.measureText("W").width); this._ctx.font = oldFont; let ratio = width / 100; hexSize = Math.floor(hexSize) + 1; // closest larger hexSize // FIXME char size computation does not respect transposed hexes let fontSize = 2 * hexSize / (this._options.spacing * (1 + ratio / Math.sqrt(3))); // closest smaller fontSize return Math.ceil(fontSize) - 1; } _normalizedEventToPosition(x, y) { let nodeSize; if (this._options.transpose) { x += y; y = x - y; x -= y; nodeSize = this._ctx.canvas.width; } else { nodeSize = this._ctx.canvas.height; } let size = nodeSize / this._options.height; y = Math.floor(y / size); if (mod(y, 2)) { /* odd row */ x -= this._spacingX; x = 1 + 2 * Math.floor(x / (2 * this._spacingX)); } else { x = 2 * Math.floor(x / (2 * this._spacingX)); } return [x, y]; } /** * Arguments are pixel values. If "transposed" mode is enabled, then these two are already swapped. */ _fill(cx, cy) { let a = this._hexSize; let b = this._options.border; const ctx = this._ctx; ctx.beginPath(); if (this._options.transpose) { ctx.moveTo(cx - a + b, cy); ctx.lineTo(cx - a / 2 + b, cy + this._spacingX - b); ctx.lineTo(cx + a / 2 - b, cy + this._spacingX - b); ctx.lineTo(cx + a - b, cy); ctx.lineTo(cx + a / 2 - b, cy - this._spacingX + b); ctx.lineTo(cx - a / 2 + b, cy - this._spacingX + b); ctx.lineTo(cx - a + b, cy); } else { ctx.moveTo(cx, cy - a + b); ctx.lineTo(cx + this._spacingX - b, cy - a / 2 + b); ctx.lineTo(cx + this._spacingX - b, cy + a / 2 - b); ctx.lineTo(cx, cy + a - b); ctx.lineTo(cx - this._spacingX + b, cy + a / 2 - b); ctx.lineTo(cx - this._spacingX + b, cy - a / 2 + b); ctx.lineTo(cx, cy - a + b); } ctx.fill(); } _updateSize() { const opts = this._options; const charWidth = Math.ceil(this._ctx.measureText("W").width); this._hexSize = Math.floor(opts.spacing * (opts.fontSize + charWidth / Math.sqrt(3)) / 2); this._spacingX = this._hexSize * Math.sqrt(3) / 2; this._spacingY = this._hexSize * 1.5; let xprop; let yprop; if (opts.transpose) { xprop = "height"; yprop = "width"; } else { xprop = "width"; yprop = "height"; } this._ctx.canvas[xprop] = Math.ceil((opts.width + 1) * this._spacingX); this._ctx.canvas[yprop] = Math.ceil((opts.height - 1) * this._spacingY + 2 * this._hexSize); } }