namespace Views { export class GoBoard extends Views . View < HTMLDivElement > { private static _defaultSize : number = 19 ; private _size : number ; private _maxWidth : number ; private _playerMinWidth : number ; private _playerMinHeight : number ; private _debounceWidth : number = 28 ; private _layoutPortrait : boolean ; private _flexRoot : JQuery ; private _goban : JQuery ; private _board : WGo . Board ; private _drawHandlers : GoBoardDrawHandlers = new GoBoardDrawHandlers ( ) ; private _treeNodeId : number ; private _position : Models . GamePosition ; public playerAway : Views . GoBoardPlayer ; public playerHome : Views . GoBoardPlayer ; public playCallback : ( x : number , y : number ) => void ; constructor ( size ? ) { super ( Templates . cloneTemplate < HTMLDivElement > ( 'go-board' ) ) ; this . _size = ( size || GoBoard . _defaultSize ) ; this . root . classList . add ( 'go-' + this . _size . toString ( ) ) ; let flexRoot = this . root . querySelector ( '.flex-absolute' ) ; this . _flexRoot = $ ( flexRoot ) ; let teamAway = flexRoot . querySelector ( '.team-away' ) as HTMLElement ; this . playerAway = new Views . GoBoardPlayer ( Models . PlayerTeam . Away ) ; this . playerAway . attach ( teamAway ) ; let goban = flexRoot . querySelector ( '.goban' ) as HTMLElement ; this . _goban = $ ( goban ) ; this . _board = new WGo . Board ( goban , { size : this . _size , background : '/img/wood.jpg' } ) ; let teamHome = flexRoot . querySelector ( '.team-home' ) as HTMLElement ; this . playerHome = new Views . GoBoardPlayer ( Models . PlayerTeam . Home ) ; this . playerHome . attach ( teamHome ) ; } public activate ( ) { this . optimiseBoard ( ) ; window . addEventListener ( "resize" , this . _onResize ) ; this . _board . addEventListener ( "click" , this . _onBoardClick ) ; this . playerHome . activate ( ) ; this . playerAway . activate ( ) ; super . activate ( ) ; } public deactivate ( ) { super . deactivate ( ) ; this . _board . removeEventListener ( "click" , this . _onBoardClick ) ; window . removeEventListener ( "resize" , this . _onResize ) ; this . playerAway . deactivate ( ) ; this . playerHome . deactivate ( ) ; } private optimiseBoard ( ) { if ( this . _maxWidth == null ) this . _maxWidth = parseFloat ( this . _goban . css ( 'max-width' ) ) ; if ( this . _playerMinWidth == null ) this . _playerMinWidth = parseFloat ( this . _flexRoot . find ( '.go-board-player' ) . css ( 'min-width' ) ) ; if ( this . _playerMinHeight == null ) this . _playerMinHeight = parseFloat ( this . _flexRoot . find ( '.go-board-player' ) . css ( 'min-height' ) ) ; let landscapeWidth = this . calculateBoardWidth ( false ) ; let portraitWidth = this . calculateBoardWidth ( true ) ; if ( this . _layoutPortrait == null ) { this . _layoutPortrait = ( portraitWidth > landscapeWidth ) ; } else if ( ( this . _layoutPortrait ) && ( landscapeWidth > ( portraitWidth + this . _debounceWidth ) ) ) { this . _layoutPortrait = false ; } else if ( ( ! this . _layoutPortrait ) && ( portraitWidth > ( landscapeWidth + this . _debounceWidth ) ) ) { this . _layoutPortrait = true ; } let boardWidth ; if ( this . _layoutPortrait ) { boardWidth = portraitWidth ; this . root . classList . add ( 'portrait' ) ; this . root . classList . remove ( 'landscape' ) ; this . _flexRoot . css ( 'height' , "" ) ; this . _flexRoot . css ( 'width' , boardWidth ) ; } else { boardWidth = landscapeWidth ; this . root . classList . remove ( 'portrait' ) ; this . root . classList . add ( 'landscape' ) ; this . _flexRoot . css ( 'height' , boardWidth ) ; this . _flexRoot . css ( 'width' , "" ) ; } this . _goban . css ( 'flex-basis' , boardWidth ) ; this . _board . setWidth ( boardWidth ) ; } private calculateBoardWidth ( portrait ) { let parent = this . parent ; let x = parent . offsetWidth ; if ( ! portrait ) x -= 2 * this . _playerMinWidth ; if ( x > this . _maxWidth ) x = this . _maxWidth ; let y = parent . offsetHeight ; if ( portrait ) y -= 2 * this . _playerMinHeight ; if ( y > this . _maxWidth ) y = this . _maxWidth ; return ( x < y ) ? x : y ; } private _onResize = ( e ) => { this . optimiseBoard ( ) ; } ; private _onBoardClick = ( x , y ) => { if ( Utils . logEnabled ( Utils . LogSeverity . Debug ) ) { let coordinateString = "(" + x . toString ( ) + ", " + y . toString ( ) + ")" ; let coordinateObject = { x : x , y : y } ; if ( this . _position ) { try { let stoneColour ; let bits = this . _position . get ( x , y ) ; if ( ( bits & Models . GameMarks . WhiteStone ) != 0 ) stoneColour = "white" ; else if ( ( bits & Models . GameMarks . BlackStone ) != 0 ) stoneColour = "black" ; Utils . log ( Utils . LogSeverity . Debug , coordinateString , coordinateObject , stoneColour ) ; } catch ( error ) { Utils . log ( Utils . LogSeverity . Debug , coordinateString , coordinateObject , error ) ; } } else { Utils . log ( Utils . LogSeverity . Debug , coordinateString , coordinateObject ) ; } } if ( this . playCallback ) this . playCallback ( x , y ) ; } ; public get size ( ) { return this . _size ; } public clear ( ) { this . _board . removeAllObjects ( ) ; this . _treeNodeId = null ; this . _position = null ; } private applyPositionChange ( change , blackBit , whiteBit , type ) { if ( ( change . set & blackBit ) == blackBit ) { this . _board . addObject ( < WGo . BoardObject > { x : change . x , y : change . y , c : WGo . B , type : type } ) ; } else if ( ( change . set & whiteBit ) == whiteBit ) { this . _board . addObject ( < WGo . BoardObject > { x : change . x , y : change . y , c : WGo . W , type : type } ) ; } else if ( ( change . unset & ( blackBit | whiteBit ) ) != 0 ) { this . _board . removeObject ( < WGo . BoardRemoveObject > { x : change . x , y : change . y , type : type } ) ; } } public updateBoard ( gameNode , soundStoneCallback , soundPassCallback ) { if ( ( gameNode == null ) || ( gameNode . position == null ) ) { if ( this . _position != null ) { this . clear ( ) ; return true ; } } else { let updated = false ; let oldPosition ; if ( this . _size != gameNode . position . size ) { this . _size = gameNode . position . size ; this . _board . setSize ( this . _size ) ; if ( this . activated ) this . optimiseBoard ( ) ; this . _position = oldPosition = null ; updated = true ; } else oldPosition = this . _position ; let changes = gameNode . position . diff ( oldPosition ) ; for ( let i = 0 ; i < changes . length ; ++ i ) { let change = changes [ i ] ; this . applyPositionChange ( change , Models . GameMarks . BlackStone , Models . GameMarks . WhiteStone , "SHELL" ) ; this . applyPositionChange ( change , Models . GameMarks . BlackTerritory , Models . GameMarks . WhiteTerritory , this . _drawHandlers . moku ) ; this . applyPositionChange ( change , Models . GameMarks . LastMove , Models . GameMarks . LastMove , this . _drawHandlers . lastMove ) ; this . applyPositionChange ( change , Models . GameMarks . Ko , Models . GameMarks . Ko , this . _drawHandlers . ko ) ; updated = true ; } if ( this . _treeNodeId == gameNode . parentId ) { switch ( gameNode . position . lastEvent ) { case Models . GamePositionEvent . Pass : soundPassCallback ( ) ; break ; case Models . GamePositionEvent . Move : soundStoneCallback ( ) ; break ; } } this . _treeNodeId = gameNode . nodeId ; if ( updated ) { this . _position = new Models . GamePosition ( gameNode . position ) ; } return updated ; } return false ; } } class GoBoardDrawHandlers { public moku : WGo . BoardDrawHandler = { stone : { draw : function ( this , args , board ) : void { let xr = board . getX ( args . x ) ; let yr = board . getY ( args . y ) ; let sr = board . stoneRadius * 0.4 ; this . beginPath ( ) ; if ( args . c == WGo . W ) { this . fillStyle = "rgba(255, 255, 255, 0.6)" ; } else { this . fillStyle = "rgba(0, 0, 0, 0.8)" ; } this . arc ( xr - board . ls , yr - board . ls , Math . max ( 0 , sr - 0.5 ) , 0 , 2 * Math . PI , true ) ; this . fill ( ) ; } } } ; public lastMove : WGo . BoardDrawHandler = { stone : { draw : function ( this , args , board ) : void { let xr = board . getX ( args . x ) ; let yr = board . getY ( args . y ) ; let sr = board . stoneRadius ; this . beginPath ( ) ; if ( board . obj_arr [ args . x ] [ args . y ] [ 0 ] . c == WGo . B ) this . fillStyle = "rgba(128, 128, 128, 0.6)" ; else this . fillStyle = "rgba(0, 0, 0, 0.2)" ; this . arc ( xr - board . ls , yr - board . ls , Math . max ( 0 , ( sr * 0.3 ) - 0.5 ) , 0 , 2 * Math . PI ) ; this . fill ( ) ; } } } ; public ko : WGo . BoardDrawHandler = { stone : { draw : function ( this , args , board ) : void { let xr = board . getX ( args . x ) ; let yr = board . getY ( args . y ) ; let sr = board . stoneRadius ; let w = sr * 0.6 ; this . strokeStyle = "rgba(0, 0, 0, 0.1)" ; this . lineWidth = 6 ; this . beginPath ( ) ; this . rect ( xr - ( w / 2 ) , yr - ( w / 2 ) , w , w ) ; this . stroke ( ) ; } } } ; } }