const BOX_SIDE = 80; const INDEX_MARGIN = BOX_SIDE / 2; const INDEX_LETTERS = "abcdefgh"; export class Canvas { constructor() { this._canvas = document.createElement("canvas"); this._ctx = this._canvas.getContext("2d"); let boardSide = BOX_SIDE * 8 + INDEX_MARGIN; this._canvas.width = boardSide; this._canvas.height = boardSide; document.body.appendChild(this._canvas); this.drawChessBoard(); } decideColor(r, c) { if ((r + c) % 2) return "#c0c0c0"; else return "#ffffff"; } drawSquareColor(color, r, c) { const crtStyle = this._ctx.fillStyle; this._ctx.fillStyle = color; this._ctx.fillRect( c * BOX_SIDE + INDEX_MARGIN, r * BOX_SIDE + INDEX_MARGIN, BOX_SIDE, BOX_SIDE ); this._ctx.fillStyle = crtStyle; } drawChessBoard() { // Draw squares for (let r = 0; r < 8; r++) { for (let c = 0; c < 8; c++) { this.drawSquareColor(this.decideColor(r, c), r, c); } } // Draw letters this._ctx.fillStyle = "black"; let fontsize = INDEX_MARGIN / 2; this._ctx.font = `${fontsize}px Monospace`; for (let idx = 0; idx < 8; idx++) { this._ctx.fillText( INDEX_LETTERS[idx], BOX_SIDE * idx + BOX_SIDE / 2 + INDEX_MARGIN - fontsize / 4, INDEX_MARGIN / 2 ); this._ctx.fillText( (8 - idx).toString(), INDEX_MARGIN / 2 - fontsize / 4, BOX_SIDE * idx + BOX_SIDE / 2 + INDEX_MARGIN + fontsize / 4 ); } } screenCoordsToRowCol(cx, cy) { let canvasRect = this._canvas.getBoundingClientRect(); if (cx > canvasRect.right || cy > canvasRect.bottom) { return null; } let canvasX = cx - canvasRect.left; let canvasY = cy - canvasRect.top; let row = Math.floor((canvasY - INDEX_MARGIN) / BOX_SIDE); let col = Math.floor((canvasX - INDEX_MARGIN) / BOX_SIDE); return [row, col]; } rowColToScreenCoords(row, col) { let canvasRect = this._canvas.getBoundingClientRect(); let topPx = canvasRect.top + INDEX_MARGIN + row * BOX_SIDE + window.pageYOffset; let leftPx = canvasRect.left + INDEX_MARGIN + col * BOX_SIDE + window.pageXOffset; return [topPx, leftPx]; } } function boardIndexToRowCol(boardIndex) { let [colLetter, rowDigit] = boardIndex; let row = 8 - parseInt(rowDigit); let col = INDEX_LETTERS.indexOf(colLetter); return [row, col]; } export function rowColToBoardIndex(row, col) { let rowDigit = 8 - row; let colLetter = INDEX_LETTERS[col]; return `${colLetter}${rowDigit}`; } export class ActiveSquares { constructor() { this.selectedSquare = null; this.moveSquares = []; } selectSquare(canvas, position) { let [r, c] = boardIndexToRowCol(position); canvas.drawSquareColor("#c0c0ff", r, c); this.selectedSquare = position; } setMoveSquares(canvas, moveSquares) { moveSquares.forEach((position) => { let [r, c] = boardIndexToRowCol(position); canvas.drawSquareColor("#ffffc0", r, c); this.moveSquares.push(position); }); } unsetMoveSquares(canvas) { this.moveSquares.forEach((position) => { let [r, c] = boardIndexToRowCol(position); canvas.drawSquareColor(canvas.decideColor(r, c), r, c); }); this.moveSquares = []; } unselectSquare(canvas) { if (this.selectedSquare === null) return; let [r, c] = boardIndexToRowCol(this.selectedSquare); canvas.drawSquareColor(canvas.decideColor(r, c), r, c); this.selectedSquare = null; } } class PieceVis { constructor(piece) { this.piece = piece; this.im = null; } get ["icon"]() { return `./icons/${this.piece.piece_type}_${this.piece.color}.svg`; } draw(canvas, position) { let [topPx, leftPx] = canvas.rowColToScreenCoords( ...boardIndexToRowCol(position), canvas ); if (this.im === null) { let im = new Image(BOX_SIDE, BOX_SIDE); im.src = this.icon; im.onload = () => { im.style.position = "absolute"; im.style.top = `${topPx}px`; im.style.left = `${leftPx}px`; }; document.body.appendChild(im); this.im = im; } else { this.im.style.top = `${topPx}px`; this.im.style.left = `${leftPx}px`; } } undraw() { if (this.im !== null) { this.im.remove(); this.im = null; } } } export class ConfigVis { constructor(configuration) { this.configuration = configuration; this.piecesVis = new Map(); } draw(canvas) { for (let [position, piece] of this.configuration.board) { if (this.piecesVis.has(position)) { if (this.piecesVis.get(position).piece == piece) { continue; } } let pv = this.piecesVis.get(position); if (pv !== undefined) { pv.undraw(); } pv = new PieceVis(piece); pv.draw(canvas, position); this.piecesVis.set(position, pv); } for (let [position, pv] of this.piecesVis) { if (!this.configuration.board.has(position)) { pv.undraw(); this.piecesVis.delete(position); } } } undraw() { for (let pv of this.piecesVis.values()) { pv.undraw(); } this.piecesVis.clear(); } }