X-Git-Url: https://git.auder.net/?a=blobdiff_plain;f=client%2Fsrc%2Fcomponents%2FBoard.vue;h=a7920d358ba1c1ad977a176999935bc8dd73fa0a;hb=aafe9f160744bf8f507d1cebd398cc11d798e090;hp=8d429a34014951c428bd9ef92481443e5ef844e5;hpb=83c6c2c96e7d34c79db20827f56b51040ef39392;p=vchess.git diff --git a/client/src/components/Board.vue b/client/src/components/Board.vue index 8d429a34..a7920d35 100644 --- a/client/src/components/Board.vue +++ b/client/src/components/Board.vue @@ -14,7 +14,6 @@ export default { choices: [], //promotion pieces, or checkered captures... (as moves) selectedPiece: null, //moving piece (or clicked piece) start: {}, //pixels coordinates + id of starting square (click or drag) - currentSquare: null, settings: store.state.settings, }; }, @@ -37,53 +36,6 @@ export default { let incheckSq = ArrayFun.init(sizeX, sizeY, false); this.incheck.forEach(sq => { incheckSq[sq[0]][sq[1]] = true; }); - let boardElt = document.querySelector(".game"); - const squareWidth = (!!boardElt - ? boardElt.offsetWidth / sizeY - : 40); //arbitrary value (not relevant) - const offset = (!!boardElt - ? [boardElt.offsetTop, boardElt.offsetLeft] - : [0, 0]); - const choices = h( - 'div', - { - attrs: { "id": "choices" }, - 'class': { 'row': true }, - style: { - "display": (this.choices.length > 0 ? "block" : "none"), - "top": (offset[0] + (sizeY/2)*squareWidth-squareWidth/2) + "px", - "left": (offset[1] + squareWidth*(sizeY - this.choices.length)/2) + "px", - "width": (this.choices.length * squareWidth) + "px", - "height": squareWidth + "px", - }, - }, - this.choices.map(m => { //a "choice" is a move - return h('div', - { - 'class': { - 'board': true, - ['board'+sizeY]: true, - }, - style: { - 'width': (100/this.choices.length) + "%", - 'padding-bottom': (100/this.choices.length) + "%", - }, - }, - [h('img', - { - attrs: { "src": '/images/pieces/' + - V.getPpath(m.appear[0].c+m.appear[0].p) + '.svg' }, - 'class': { 'choice-piece': true }, - on: { - "click": e => { this.play(m); this.choices=[]; }, - // NOTE: add 'touchstart' event to fix a problem on smartphones - "touchstart": e => { this.play(m); this.choices=[]; }, - }, - }) - ] - ); - }) - ); // Create board element (+ reserves if needed by variant or mode) const lm = this.lastMove; const showLight = this.settings.highlight && this.vname != "Dark"; @@ -170,8 +122,8 @@ export default { ); }) ); + let elementArray = [gameDiv]; const playingColor = this.userColor || "w"; //default for an observer - let elementArray = [choices, gameDiv]; if (!!this.vr.reserve) { const shiftIdx = (playingColor=="w" ? 0 : 1); @@ -247,92 +199,122 @@ export default { ); elementArray.push(reserves); } - return h( - 'div', - { - // NOTE: click = mousedown + mouseup + const boardElt = document.querySelector(".game"); + if (this.choices.length > 0 && !!boardElt) //no choices to show at first drawing + { + const squareWidth = boardElt.offsetWidth / sizeY; + const offset = [boardElt.offsetTop, boardElt.offsetLeft]; + const choices = h( + 'div', + { + attrs: { "id": "choices" }, + 'class': { 'row': true }, + style: { + "top": (offset[0] + (sizeY/2)*squareWidth-squareWidth/2) + "px", + "left": (offset[1] + squareWidth*(sizeY - this.choices.length)/2) + "px", + "width": (this.choices.length * squareWidth) + "px", + "height": squareWidth + "px", + }, + }, + this.choices.map(m => { //a "choice" is a move + return h('div', + { + 'class': { + 'board': true, + ['board'+sizeY]: true, + }, + style: { + 'width': (100/this.choices.length) + "%", + 'padding-bottom': (100/this.choices.length) + "%", + }, + }, + [h('img', + { + attrs: { "src": '/images/pieces/' + + V.getPpath(m.appear[0].c+m.appear[0].p) + '.svg' }, + 'class': { 'choice-piece': true }, + on: { + "click": e => { this.play(m); this.choices=[]; }, + }, + }) + ] + ); + }) + ); + elementArray.unshift(choices); + } + let onEvents = {}; + // NOTE: click = mousedown + mouseup + if ('ontouchstart' in window) + { + onEvents = { on: { - mousedown: this.mousedown, - mousemove: this.mousemove, - mouseup: this.mouseup, touchstart: this.mousedown, touchmove: this.mousemove, touchend: this.mouseup, }, - }, + }; + } + else + { + onEvents = { + on: { + mousedown: this.mousedown, + mousemove: this.mousemove, + mouseup: this.mouseup, + }, + }; + } + return h( + 'div', + onEvents, elementArray ); }, methods: { mousedown: function(e) { - e = e || window.event; - let ingame = false; - let elem = e.target; - while (!ingame && elem !== null) - { - if (elem.classList.contains("game")) - { - ingame = true; - break; - } - elem = elem.parentElement; - } - if (!ingame) //let default behavior (click on button...) + // Abort if a piece is already being processed, or target is not a piece. + // NOTE: just looking at classList[0] because piece is the first assigned class + if (!!this.selectedPiece || e.target.classList[0] != "piece") return; e.preventDefault(); //disable native drag & drop - if (!this.selectedPiece && e.target.classList.contains("piece")) - { - let parent = e.target.parentNode; - // Mark selected square - this.currentSquare = parent; - this.currentSquare.classList.add("selected"); - // Next few lines to center the piece on mouse cursor - let rect = parent.getBoundingClientRect(); - this.start = { - x: rect.x + rect.width/2, - y: rect.y + rect.width/2, - id: parent.id - }; - this.selectedPiece = e.target.cloneNode(); - this.selectedPiece.style.position = "absolute"; - this.selectedPiece.style.top = 0; - this.selectedPiece.style.display = "inline-block"; - this.selectedPiece.style.zIndex = 3000; - const startSquare = getSquareFromId(parent.id); - this.possibleMoves = []; - const color = (this.analyze ? this.vr.turn : this.userColor); - if (this.vr.canIplay(color,startSquare)) - this.possibleMoves = this.vr.getPossibleMovesFrom(startSquare); - // Next line add moving piece just after current image - // (required for Crazyhouse reserve) - parent.insertBefore(this.selectedPiece, e.target.nextSibling); - } + let parent = e.target.parentNode; //the surrounding square + // Next few lines to center the piece on mouse cursor + let rect = parent.getBoundingClientRect(); + this.start = { + x: rect.x + rect.width/2, + y: rect.y + rect.width/2, + id: parent.id, + }; + this.selectedPiece = e.target.cloneNode(); + let spStyle = this.selectedPiece.style + spStyle.position = "absolute"; + spStyle.top = 0; + spStyle.display = "inline-block"; + spStyle.zIndex = 3000; + const startSquare = getSquareFromId(parent.id); + this.possibleMoves = []; + const color = (this.analyze ? this.vr.turn : this.userColor); + if (this.vr.canIplay(color,startSquare)) + this.possibleMoves = this.vr.getPossibleMovesFrom(startSquare); + // Next line add moving piece just after current image + // (required for Crazyhouse reserve) + parent.insertBefore(this.selectedPiece, e.target.nextSibling); }, mousemove: function(e) { if (!this.selectedPiece) return; - e = e || window.event; - // If there is an active element, move it around - if (!!this.selectedPiece) - { - // Mousemove => drag & drop, no need to keep initial square highlighted - if (!!this.currentSquare) - { - this.currentSquare.classList.remove("selected"); - this.currentSquare = null; - } - const [offsetX,offsetY] = !!e.clientX - ? [e.clientX,e.clientY] //desktop browser - : [e.changedTouches[0].pageX, e.changedTouches[0].pageY]; //smartphone - this.selectedPiece.style.left = (offsetX-this.start.x) + "px"; - this.selectedPiece.style.top = (offsetY-this.start.y) + "px"; - } + // There is an active element: move it around + const [offsetX,offsetY] = !!e.clientX + ? [e.clientX,e.clientY] //desktop browser + : [e.changedTouches[0].pageX, e.changedTouches[0].pageY]; //smartphone + this.selectedPiece.style.left = (offsetX-this.start.x) + "px"; + this.selectedPiece.style.top = (offsetY-this.start.y) + "px"; }, mouseup: function(e) { if (!this.selectedPiece) return; - e = e || window.event; - // Read drop target (or iterate parentNode if type == "img") + // There is an active element: obtain the move from start and end squares this.selectedPiece.style.zIndex = -3000; //HACK to find square from final coords const [offsetX,offsetY] = !!e.clientX ? [e.clientX,e.clientY] @@ -342,18 +324,9 @@ export default { // Next condition: classList.contains(piece) fails because of marks while (landing.tagName == "IMG") landing = landing.parentNode; - if (this.start.id == landing.id) - { - // A click: selectedPiece and possibleMoves are already filled + if (this.start.id == landing.id) //one or multi clicks on same piece return; - } - // Reset initial square color (if not mousemove: smartphone) - if (!!this.currentSquare) - { - this.currentSquare.classList.remove("selected"); - this.currentSquare = null; - } - // OK: process move attempt + // OK: process move attempt, landing is a square node let endSquare = getSquareFromId(landing.id); let moves = this.findMatchingMoves(endSquare); this.possibleMoves = []; @@ -394,24 +367,6 @@ export default { // NOTE: no variants with reserve of size != 8 -div.board - float: left - height: 0 - display: inline-block - position: relative - -div.board8 - width: 12.5% - padding-bottom: 12.5% - -div.board10 - width: 10% - padding-bottom: 10% - -div.board11 - width: 9.09% - padding-bottom: 9.1% - .game width: 100% margin: 0 @@ -434,22 +389,6 @@ div.board11 height: auto display: block -img.piece - width: 100% - -img.piece, img.mark-square - max-width: 100% - height: auto - display: block - -img.mark-square - opacity: 0.6 - width: 76% - position: absolute - top: 12% - left: 12% - opacity: .7 - img.ghost position: absolute opacity: 0.4 @@ -458,15 +397,9 @@ img.ghost .highlight background-color: #00cc66 !important -.in-shadow - filter: brightness(50%) - .incheck background-color: #cc3300 !important -.selected - background-color: #f7acf7 !important - .light-square.lichess background-color: #f0d9b5; .dark-square.lichess