ngx-chess-board
Version:
Chess game component
311 lines (267 loc) • 10.4 kB
text/typescript
import { CdkDragEnd, CdkDragMove, CdkDragStart } from '@angular/cdk/drag-drop';
import {
AfterViewInit,
Component,
ElementRef,
EventEmitter,
HostListener,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
ViewChild,
} from '@angular/core';
import { AbstractEngineFacade } from './engine/abstract-engine-facade';
import { BoardLoader } from './engine/board-state-provider/board-loader/board-loader';
import {
NotationProcessorFactory, NotationType,
} from './engine/board-state-provider/board-loader/notation-processors/notation-processor-factory';
import { ClickUtils } from './engine/click/click-utils';
import { EngineFacade } from './engine/engine-facade';
import { MoveChange } from './engine/outputs/move-change/move-change';
import { HistoryMove } from './history-move-provider/history-move';
import { Board } from './models/board';
import { Piece } from './models/pieces/piece';
import { NgxChessBoardView } from './ngx-chess-board-view';
import { PiecePromotionModalComponent } from './piece-promotion/piece-promotion-modal/piece-promotion-modal.component';
import { NgxChessBoardService } from './service/ngx-chess-board.service';
import { Constants } from './utils/constants';
import { PieceIconInput } from './utils/inputs/piece-icon-input';
import { PieceIconInputManager } from './utils/inputs/piece-icon-input-manager';
import { ColorInput, PieceTypeInput } from './utils/inputs/piece-type-input';
export class NgxChessBoardComponent
implements OnInit, OnChanges, NgxChessBoardView, AfterViewInit {
darkTileColor = Constants.DEFAULT_DARK_TILE_COLOR;
lightTileColor: string = Constants.DEFAULT_LIGHT_TILE_COLOR;
showCoords = true;
sourcePointColor: string = Constants.DEFAULT_SOURCE_POINT_COLOR;
destinationPointColor: string = Constants.DEFAULT_DESTINATION_POINT_COLOR;
legalMovesPointColor: string = Constants.DEFAULT_LEGAL_MOVE_POINT_COLOR;
showLastMove = true;
showLegalMoves = true;
showActivePiece = true;
showPossibleCaptures = true;
/**
* Enabling free mode removes turn-based restriction and allows to move any piece freely!
*/
moveChange = new EventEmitter<MoveChange>();
checkmate = new EventEmitter<void>();
stalemate = new EventEmitter<void>();
boardRef: ElementRef;
modal: PiecePromotionModalComponent;
pieceSize: number;
selected = false;
boardLoader: BoardLoader;
pieceIconManager: PieceIconInputManager;
isDragging = false;
startTransition = '';
engineFacade: AbstractEngineFacade;
constructor(private ngxChessBoardService: NgxChessBoardService) {
this.engineFacade = new EngineFacade(
new Board(),
this.moveChange
);
}
public set size(size: number) {
if (
size &&
size >= Constants.MIN_BOARD_SIZE &&
size <= Constants.MAX_BOARD_SIZE
) {
this.engineFacade.heightAndWidth = size;
} else {
this.engineFacade.heightAndWidth = Constants.DEFAULT_SIZE;
}
this.engineFacade.drawProvider.clear();
this.calculatePieceSize();
}
public set freeMode(freeMode: boolean) {
this.engineFacade.freeMode = freeMode;
}
public set dragDisabled(dragDisabled: boolean) {
this.engineFacade.dragDisabled = dragDisabled;
}
public set drawDisabled(drawDisabled: boolean) {
this.engineFacade.drawDisabled = drawDisabled;
}
public set pieceIcons(pieceIcons: PieceIconInput) {
this.engineFacade.pieceIconManager.pieceIconInput = pieceIcons;
}
public set lightDisabled(lightDisabled: boolean) {
this.engineFacade.lightDisabled = lightDisabled;
}
public set darkDisabled(darkDisabled: boolean) {
this.engineFacade.darkDisabled = darkDisabled;
}
onRightClick(event: MouseEvent) {
event.preventDefault();
}
ngOnChanges(changes: SimpleChanges) {
if (
(changes.lightDisabled &&
this.lightDisabled &&
this.engineFacade.board.currentWhitePlayer) ||
(changes.darkDisabled &&
this.darkDisabled &&
!this.engineFacade.board.currentWhitePlayer)
) {
this.engineFacade.board.possibleCaptures = [];
this.engineFacade.board.possibleMoves = [];
}
}
ngOnInit() {
this.ngxChessBoardService.componentMethodCalled$.subscribe(() => {
this.engineFacade.reset();
});
}
ngAfterViewInit(): void {
this.engineFacade.modal = this.modal;
this.calculatePieceSize();
}
onMouseUp(event: MouseEvent) {
this.engineFacade.onMouseUp(
event,
this.getClickPoint(event),
this.boardRef.nativeElement.getBoundingClientRect().left,
this.boardRef.nativeElement.getBoundingClientRect().top
);
}
reverse(): void {
this.selected = false;
this.engineFacade.board.reverse();
this.engineFacade.coords.reverse();
}
updateBoard(board: Board) {
this.engineFacade.board = board;
this.boardLoader.setEngineFacade(this.engineFacade);
this.engineFacade.board.possibleCaptures = [];
this.engineFacade.board.possibleMoves = [];
}
setFEN(fen: string): void {
try {
this.engineFacade.boardLoader.setNotationProcessor(
NotationProcessorFactory.getProcessor(NotationType.FEN)
);
this.engineFacade.boardLoader.loadFEN(fen);
this.engineFacade.board.possibleCaptures = [];
this.engineFacade.board.possibleMoves = [];
this.engineFacade.coords.reset();
} catch (exception) {
this.engineFacade.boardLoader.addPieces();
}
}
setPGN(pgn: string): void {
try {
this.engineFacade.pgnProcessor.reset();
this.engineFacade.boardLoader.setNotationProcessor(
NotationProcessorFactory.getProcessor(NotationType.PGN)
);
this.engineFacade.boardLoader.loadPGN(pgn);
this.engineFacade.board.possibleCaptures = [];
this.engineFacade.board.possibleMoves = [];
this.engineFacade.coords.reset();
} catch (exception) {
console.log(exception);
this.engineFacade.boardLoader.addPieces();
}
}
getFEN(): string {
return this.engineFacade.board.fen;
}
dragEnded(event: CdkDragEnd): void {
this.isDragging = false;
this.engineFacade.dragEndStrategy.process(
event,
this.engineFacade.moveDone,
this.startTransition
);
}
dragStart(event: CdkDragStart): void {
this.isDragging = true;
let trans = event.source.getRootElement().style.transform.split(') ');
// this.startTrans= trans;
this.startTransition = trans.length === 2 ? trans[1] : trans[0];
this.engineFacade.dragStartStrategy.process(event);
}
onMouseDown(event: MouseEvent) {
this.engineFacade.onMouseDown(event, this.getClickPoint(event),
this.boardRef.nativeElement.getBoundingClientRect().left,
this.boardRef.nativeElement.getBoundingClientRect().top
);
}
getClickPoint(event) {
return ClickUtils.getClickPoint(
event,
this.boardRef.nativeElement.getBoundingClientRect().top,
this.boardRef.nativeElement.getBoundingClientRect().height,
this.boardRef.nativeElement.getBoundingClientRect().left,
this.boardRef.nativeElement.getBoundingClientRect().width
);
}
private calculatePieceSize() {
this.pieceSize = this.engineFacade.heightAndWidth / 8;
}
getCustomPieceIcons(piece: Piece) {
return JSON.parse(
`{ "background-image": "url('${this.engineFacade.pieceIconManager.getPieceIcon(
piece
)}')"}`
);
}
move(coords: string): void {
this.engineFacade.move(coords);
}
getMoveHistory(): HistoryMove[] {
return this.engineFacade.getMoveHistory();
}
reset(): void {
this.engineFacade.reset();
}
undo(): void {
this.engineFacade.undo();
}
addPiece(
pieceTypeInput: PieceTypeInput,
colorInput: ColorInput,
coords: string
) {
this.engineFacade.addPiece(pieceTypeInput, colorInput, coords);
}
getPGN() {
return this.engineFacade.pgnProcessor.getPGN();
}
dragMoved($event: CdkDragMove<any>) {
let x = ($event.pointerPosition.x - $event.source.getRootElement().parentElement.getBoundingClientRect().left) - (this.pieceSize / 2);
let y = ($event.pointerPosition.y - $event.source.getRootElement().parentElement.getBoundingClientRect().top) - (this.pieceSize / 2);
$event.source.getRootElement().style.transform = 'translate3d(' + x + 'px, '
+ (y) + 'px,0px)';
}
getTileBackgroundColor(i, j): string {
let color = ((i + j) % 2 === 0) ? this.lightTileColor : this.darkTileColor;
if (this.showLastMove) {
if (this.engineFacade.board.isXYInSourceMove(i, j)) {
color = this.sourcePointColor;
}
if (this.engineFacade.board.isXYInDestMove(i, j)) {
color = this.destinationPointColor;
}
}
return color;
}
}