UNPKG

cm-chessboard

Version:

A JavaScript chessboard which is lightweight, ES6 module based, responsive, SVG rendered and without dependencies.

195 lines (180 loc) 7.76 kB
/** * Author and copyright: Stefan Haack (https://shaack.com) * Repository: https://github.com/shaack/cm-chessboard * License: MIT, see file 'LICENSE' */ import {Extension, EXTENSION_POINT} from "../../model/Extension.js" import {COLOR, PIECE} from "../../Chessboard.js" import {Svg} from "../../lib/Svg.js" import {Utils} from "../../lib/Utils.js" const DISPLAY_STATE = { hidden: "hidden", displayRequested: "displayRequested", shown: "shown" } export const PROMOTION_DIALOG_RESULT_TYPE = { pieceSelected: "pieceSelected", canceled: "canceled" } export class PromotionDialog extends Extension { /** @constructor */ constructor(chessboard) { super(chessboard) this.registerExtensionPoint(EXTENSION_POINT.afterRedrawBoard, this.extensionPointRedrawBoard.bind(this)) chessboard.showPromotionDialog = this.showPromotionDialog.bind(this) chessboard.isPromotionDialogShown = this.isPromotionDialogShown.bind(this) this.promotionDialogGroup = Svg.addElement(chessboard.view.interactiveTopLayer, "g", {class: "promotion-dialog-group"}) this.state = { displayState: DISPLAY_STATE.hidden, callback: null, dialogParams: { square: null, color: null } } } // public (chessboard.showPromotionDialog) showPromotionDialog(square, color, callback) { this.state.dialogParams.square = square this.state.dialogParams.color = color this.state.callback = callback this.setDisplayState(DISPLAY_STATE.displayRequested) setTimeout(() => { this.chessboard.view.positionsAnimationTask.then(() => { this.setDisplayState(DISPLAY_STATE.shown) }) } ) } // public (chessboard.isPromotionDialogShown) isPromotionDialogShown() { return this.state.displayState === DISPLAY_STATE.shown || this.state.displayState === DISPLAY_STATE.displayRequested } // private extensionPointRedrawBoard() { this.redrawDialog() } drawPieceButton(piece, point) { const squareWidth = this.chessboard.view.squareWidth const squareHeight = this.chessboard.view.squareHeight Svg.addElement(this.promotionDialogGroup, "rect", { x: point.x, y: point.y, width: squareWidth, height: squareHeight, class: "promotion-dialog-button", "data-piece": piece }) this.chessboard.view.drawPiece(this.promotionDialogGroup, piece, point) } redrawDialog() { while (this.promotionDialogGroup.firstChild) { this.promotionDialogGroup.removeChild(this.promotionDialogGroup.firstChild) } if (this.state.displayState === DISPLAY_STATE.shown) { const squareWidth = this.chessboard.view.squareWidth const squareHeight = this.chessboard.view.squareHeight const squareCenterPoint = this.chessboard.view.squareToPoint(this.state.dialogParams.square) squareCenterPoint.x = squareCenterPoint.x + squareWidth / 2 squareCenterPoint.y = squareCenterPoint.y + squareHeight / 2 let turned = false const rank = parseInt(this.state.dialogParams.square.charAt(1), 10) if (this.chessboard.getOrientation() === COLOR.white && rank < 5 || this.chessboard.getOrientation() === COLOR.black && rank >= 5) { turned = true } const offsetY = turned ? -4 * squareHeight : 0 const offsetX = squareCenterPoint.x + squareWidth > this.chessboard.view.width ? -squareWidth : 0 Svg.addElement(this.promotionDialogGroup, "rect", { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y + offsetY, width: squareWidth, height: squareHeight * 4, class: "promotion-dialog" }) const dialogParams = this.state.dialogParams if (turned) { this.drawPieceButton(PIECE[dialogParams.color + "q"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y - squareHeight }) this.drawPieceButton(PIECE[dialogParams.color + "r"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y - squareHeight * 2 }) this.drawPieceButton(PIECE[dialogParams.color + "b"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y - squareHeight * 3 }) this.drawPieceButton(PIECE[dialogParams.color + "n"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y - squareHeight * 4 }) } else { this.drawPieceButton(PIECE[dialogParams.color + "q"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y }) this.drawPieceButton(PIECE[dialogParams.color + "r"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y + squareHeight }) this.drawPieceButton(PIECE[dialogParams.color + "b"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y + squareHeight * 2 }) this.drawPieceButton(PIECE[dialogParams.color + "n"], { x: squareCenterPoint.x + offsetX, y: squareCenterPoint.y + squareHeight * 3 }) } } } promotionDialogOnClickPiece(event) { if (event.button !== 2) { if (event.target.dataset.piece) { if(this.state.callback) { this.state.callback({ type: PROMOTION_DIALOG_RESULT_TYPE.pieceSelected, square: this.state.dialogParams.square, piece: event.target.dataset.piece }) } this.setDisplayState(DISPLAY_STATE.hidden) } else { this.promotionDialogOnCancel(event) } } } promotionDialogOnCancel(event) { if (this.state.displayState === DISPLAY_STATE.shown) { event.preventDefault() this.setDisplayState(DISPLAY_STATE.hidden) if(this.state.callback) { this.state.callback({type: PROMOTION_DIALOG_RESULT_TYPE.canceled}) } } } contextMenu(event) { event.preventDefault() this.setDisplayState(DISPLAY_STATE.hidden) if(this.state.callback) { this.state.callback({type: PROMOTION_DIALOG_RESULT_TYPE.canceled}) } } setDisplayState(displayState) { this.state.displayState = displayState if (displayState === DISPLAY_STATE.shown) { this.clickDelegate = Utils.delegate(this.chessboard.view.svg, "pointerdown", "*", this.promotionDialogOnClickPiece.bind(this)) this.contextMenuListener = this.contextMenu.bind(this) this.chessboard.view.svg.addEventListener("contextmenu", this.contextMenuListener) } else if (displayState === DISPLAY_STATE.hidden) { this.clickDelegate.remove() this.chessboard.view.svg.removeEventListener("contextmenu", this.contextMenuListener) } this.redrawDialog() } }