skip to Main Content

I am currently working on creating a Tic Tac Toe game and have the code to make the x and o’s appear. However, the onclick event isn’t always being called when the squares are clicked, and randomly decide to work after many clicks. What am I doing wrong?
The javascript is at the top and the SVG elements are at the bottom

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <script lang="javascript">
        let whosTurn = "o";

        function clickedSquare(x1,x2, o) {

            console.log('hi!')
            var eleX = document.getElementById(x1);
            var eleXR = document.getElementById(x2)
            var eleO = document.getElementById(o);
           
            var eleXstyle = eleX.getAttribute("stroke");
            var eleXRstyle = eleXR.getAttribute("stroke");
            var eleOstyle = eleO.getAttribute("stroke");


            if (eleXstyle == "transparent" && eleOstyle == "transparent") {
                if (whosTurn = "x") {
                     eleXstyle == "black"
                     eleXRstyle =="black"
                eleX.setAttribute( "stroke", "black");
                eleXR.setAttribute( "stroke", "black");
                    whosTurn = "o"
                   
                } else {
                 eleOstyle == "black"
                    eleO.setAttribute( "stroke", "black");
                    whosTurn = "x"

                }
            }
            console.log(whosTurn)
        }
      function checkForWinner() {
        
      }
    </script>
</head>
<body>
    <svg width="500" height="500" style="background-color: black;" viewBox="0 0 500 500">
        <rect width="160" height="160" x="0" y="0" fill="red" onclick="clickedSquare('x1l','x1r','circle1');"></rect>
        <rect width="160" height="160" x="170" y="0" fill="white" onclick="clickedSquare('x2l','x2r','circle2'); checkForWinner();"></rect>
        <rect width="160" height="160" x="340" y="0" fill="white" onclick="clickedSquare('x3l','x3r','circle3'); checkForWinner();"></rect>
        <rect width="160" height="160" x="0" y="170" fill="white" onclick="clickedSquare('x4l','x4r','circle4'); checkForWinner();"></rect>
        <rect width="160" height="160" x="170" y="170" fill="white" onclick="clickedSquare('x5l','x5r','circle5'); checkForWinner();"></rect>
        <rect width="160" height="160" x="340" y="170" fill="white" onclick="clickedSquare('x6l','x6r','circle6'); checkForWinner();"></rect>
        <rect width="160" height="160" x="0" y="340" fill="white" onclick="clickedSquare('x7l','x7r','circle7'); checkForWinner();"></rect>
        <rect width="160" height="160" x="170" y="340" fill="white" onclick="clickedSquare('x8l','x8r','circle8'); checkForWinner();"></rect>
        <rect width="160" height="160" x="340" y="340" fill="white" onclick="clickedSquare('x9l','x9r','circle9'); checkForWinner();"></rect>

        <line x1="20" y1="20" x2="130" y2="120" stroke="transparent" stroke-width="5px" class="exes x1" id="x1l"></line>
        <line x1="130" y1="20" x2="20" y2="120" stroke="transparent" stroke-width="5px" class="exes x1" id="x1r"></line>

        <line x1="190" y1="20" x2="300" y2="120" stroke="transparent" stroke-width="5px" class="exes x2" id="x2l"></line>
        <line x1="300" y1="20" x2="190" y2="120" stroke="transparent" stroke-width="5px" class="exes x2" id="x2r"></line>
        
        <line x1="360" y1="20" x2="470" y2="120" stroke="transparent" stroke-width="5px" class="exes x3" id="x3l"></line>
        <line x1="470" y1="20" x2="360" y2="120" stroke="transparent" stroke-width="5px" class="exes x3" id="x3r"></line>


        <line x1="20" y1="190" x2="130" y2="290" stroke="transparent" stroke-width="5px" class="exes x4" id="x4l"></line>
        <line x1="130" y1="190" x2="20" y2="290" stroke="transparent" stroke-width="5px" class="exes x4" id="x4r"></line>

        <line x1="190" y1="190" x2="300" y2="290" stroke="transparent" stroke-width="5px" class="exes x5" id="x5l"></line>
        <line x1="300" y1="190" x2="190" y2="290" stroke="transparent" stroke-width="5px" class="exes x5" id="x5r"></line>
        
        <line x1="360" y1="190" x2="470" y2="290" stroke="transparent" stroke-width="5px" class="exes x6" id="x6l"></line>
        <line x1="470" y1="190" x2="360" y2="290" stroke="transparent" stroke-width="5px" class="exes x6" id="x6r"></line>
        
        
        <line x1="20" y1="360" x2="130" y2="470" stroke="transparent" stroke-width="5px" class="exes x7" id="x7l"></line>
        <line x1="130" y1="360" x2="20" y2="470" stroke="transparent" stroke-width="5px" class="exes x7" id="x7r"></line>

        <line x1="190" y1="360" x2="300" y2="470" stroke="transparent" stroke-width="5px" class="exes x8" id="x8l"></line>
        <line x1="300" y1="360" x2="190" y2="470" stroke="transparent" stroke-width="5px" class="exes x8" id="x8r"></line>
        
        <line x1="360" y1="360" x2="470" y2="470" stroke="transparent" stroke-width="5px" class="exes x9" id="x9l"></line>
        <line x1="470" y1="360" x2="360" y2="470" stroke="transparent" stroke-width="5px" class="exes x9" id="x9r"></line>
       
        <circle cx="70" cy="70" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle1"></circle>
        <circle cx="250" cy="70" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle2"></circle>
        <circle cx="430" cy="70" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle3"></circle>

        <circle cx="70" cy="250" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle4"></circle>
        <circle cx="250" cy="250" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle5"></circle>
        <circle cx="430" cy="250" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle6"></circle>

        <circle cx="70" cy="430" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle7"></circle>
        <circle cx="250" cy="430" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle8"></circle>
        <circle cx="430" cy="430" r="60" stroke="transparent" stroke-width="5px" fill="transparent" class="circle" id="circle9"></circle>

    </svg>
    <script>
    </script>
</body>
</html>

2

Answers


  1. The main problem was: in the SVG version 1.1 the rendering order happens based on the order of items. So, in your implementation you can click only in the surrounding area in every rect.
    I solved the problem by using the display attribute (equals to null). Which will remove the element from the document. As a result, you can click anywhere inside the rect element.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Document</title>
    
        <script lang="javascript">
            let whosTurn = "o";
    
            function clickedSquare(x1, x2, o) {
    
                console.log('hi!')
                var eleX = document.getElementById(x1);
                var eleXR = document.getElementById(x2)
                var eleO = document.getElementById(o);
    
                var eleXstyle = eleX.getAttribute("display");
                var eleXRstyle = eleXR.getAttribute("display");
                var eleOstyle = eleO.getAttribute("display");
    
                console.log("whosTurn=", whosTurn)
                console.log("eleXstyle=", eleXstyle)
                console.log("eleXRstyle=", eleXRstyle)
                console.log("eleOstyle=", eleOstyle)
                if (eleXstyle === "none" && eleOstyle === "none") {
                    if (whosTurn === "x") {
                        eleXstyle = "inline"
                        eleXRstyle = "inline"
                        eleX.setAttribute("display", "inline");
                        eleXR.setAttribute("display", "inline");
                        whosTurn = "o"
    
                    } else {
                        eleOstyle = "inline"
                        eleO.setAttribute("display", "inline");
                        whosTurn = "x"
    
                    }
                }
                console.log(whosTurn)
            }
            function checkForWinner() {
    
            }
        </script>
    </head>
    
    <body>
        <svg width="500" height="500" style="background-color: black" viewBox="0 0 500 500">
            <rect width="160" height="160" x="0" y="0" fill="red" onclick="clickedSquare('x1l','x1r','circle1');"></rect>
            <rect width="160" height="160" x="170" y="0" fill="white"
                onclick="clickedSquare('x2l','x2r','circle2'); checkForWinner();"></rect>
            <rect width="160" height="160" x="340" y="0" fill="white"
                onclick="clickedSquare('x3l','x3r','circle3'); checkForWinner();"></rect>
            <rect width="160" height="160" x="0" y="170" fill="white"
                onclick="clickedSquare('x4l','x4r','circle4'); checkForWinner();"></rect>
            <rect width="160" height="160" x="170" y="170" fill="white"
                onclick="clickedSquare('x5l','x5r','circle5'); checkForWinner();"></rect>
            <rect width="160" height="160" x="340" y="170" fill="white"
                onclick="clickedSquare('x6l','x6r','circle6'); checkForWinner();"></rect>
            <rect width="160" height="160" x="0" y="340" fill="white"
                onclick="clickedSquare('x7l','x7r','circle7'); checkForWinner();"></rect>
            <rect width="160" height="160" x="170" y="340" fill="white"
                onclick="clickedSquare('x8l','x8r','circle8'); checkForWinner();"></rect>
            <rect width="160" height="160" x="340" y="340" fill="white"
                onclick="clickedSquare('x9l','x9r','circle9'); checkForWinner();"></rect>
    
            <line x1="20" y1="20" x2="130" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x1"
                id="x1l"></line>
            <line x1="130" y1="20" x2="20" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x1"
                id="x1r"></line>
    
            <line x1="190" y1="20" x2="300" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x2"
                id="x2l">
            </line>
            <line x1="300" y1="20" x2="190" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x2"
                id="x2r">
            </line>
    
            <line x1="360" y1="20" x2="470" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x3"
                id="x3l">
            </line>
            <line x1="470" y1="20" x2="360" y2="120" display="none" stroke="black" stroke-width="5px" class="exes x3"
                id="x3r">
            </line>
    
            <line x1="20" y1="190" x2="130" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x4"
                id="x4l">
            </line>
            <line x1="130" y1="190" x2="20" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x4"
                id="x4r">
            </line>
    
            <line x1="190" y1="190" x2="300" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x5"
                id="x5l">
            </line>
            <line x1="300" y1="190" x2="190" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x5"
                id="x5r">
            </line>
    
            <line x1="360" y1="190" x2="470" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x6"
                id="x6l">
            </line>
            <line x1="470" y1="190" x2="360" y2="290" display="none" stroke="black" stroke-width="5px" class="exes x6"
                id="x6r">
            </line>
    
            <line x1="20" y1="360" x2="130" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x7"
                id="x7l">
            </line>
            <line x1="130" y1="360" x2="20" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x7"
                id="x7r">
            </line>
    
            <line x1="190" y1="360" x2="300" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x8"
                id="x8l">
            </line>
            <line x1="300" y1="360" x2="190" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x8"
                id="x8r">
            </line>
    
            <line x1="360" y1="360" x2="470" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x9"
                id="x9l">
            </line>
            <line x1="470" y1="360" x2="360" y2="470" display="none" stroke="black" stroke-width="5px" class="exes x9"
                id="x9r">
            </line>
    
            <circle cx="70" cy="70" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle1"></circle>
            <circle cx="250" cy="70" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle2"></circle>
            <circle cx="430" cy="70" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle3"></circle>
    
            <circle cx="70" cy="250" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle4"></circle>
            <circle cx="250" cy="250" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle5"></circle>
            <circle cx="430" cy="250" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle6"></circle>
    
            <circle cx="70" cy="430" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle7"></circle>
            <circle cx="250" cy="430" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle8"></circle>
            <circle cx="430" cy="430" r="60" display="none" stroke="black" stroke-width="5px" fill="transparent"
                class="circle" id="circle9"></circle>
        </svg>
        <script></script>
    </body>
    
    </html>
    
    Login or Signup to reply.
  2. just for a start:

    const
      svgNS         = 'http://www.w3.org/2000/svg'
    , TicTacToeGrid = document.querySelector('#Tic-Tac-Toe-grid')
    , virtualGrid   = [['','',''],['','',''],['','','']]
    , rects_Delta   = 170
      ;
    var setPlaying = set_X;
    function set_O(x,y)
      {
      const calcPos = p => (p * rects_Delta) + 80;
    
      if (virtualGrid[x][y] !== '') return;
    
      virtualGrid[x][y] = 'o';
      nCircle = document.createElementNS(svgNS, 'circle');
      nCircle.setAttribute( 'cx', calcPos(x));
      nCircle.setAttribute( 'cy', calcPos(y));
      nCircle.setAttribute( 'r', 60);
      TicTacToeGrid.appendChild(nCircle);
      
      setPlaying = set_X;
      }
    function set_X(x,y)
      {
      const 
        calc_TopRight = p => (p * rects_Delta) + 30
      , calc_BotLeft  = p => (p * rects_Delta) + 140
        ;  
      if (virtualGrid[x][y] !== '') return;
    
      virtualGrid[x][y] = 'x';
      bar_1 = document.createElementNS(svgNS, 'line');
      bar_2 = document.createElementNS(svgNS, 'line');
    
      bar_1.setAttribute( 'x1', calc_TopRight(x));
      bar_1.setAttribute( 'x2', calc_BotLeft(x));
      bar_1.setAttribute( 'y1', calc_TopRight(y));
      bar_1.setAttribute( 'y2', calc_BotLeft(y));
    
      bar_2.setAttribute( 'x2', calc_TopRight(x));
      bar_2.setAttribute( 'x1', calc_BotLeft(x));
      bar_2.setAttribute( 'y1', calc_TopRight(y));
      bar_2.setAttribute( 'y2', calc_BotLeft(y));
    
      TicTacToeGrid.appendChild(bar_1);
      TicTacToeGrid.appendChild(bar_2);
      
      setPlaying = set_O;
      }
    
    TicTacToeGrid.onclick = ({target: clikedElement}) =>
      {
      if (!clikedElement.matches('rect')) return;
      
      setPlaying( +clikedElement.getAttribute('x') / rects_Delta, +clikedElement.getAttribute('y') / rects_Delta );
      } 
    svg {
      --sqSize   : 250px;
      width      : var(--sqSize);
      height     : var(--sqSize);
      background : black;
      }
    svg rect {
      cursor : pointer;
      fill   : white;
      }
    svg rect:hover {
      fill   : lightblue;
      }
    svg circle {
      stroke       : green;
      stroke-width : 10;
      fill         : transparent;
      }
    svg line {
      stroke       : red;
      stroke-width : 10;
      }
    <svg viewBox="0 0 500 500" id="Tic-Tac-Toe-grid">
      <rect x="0"   y="0"   width="160" height="160" />
      <rect x="170" y="0"   width="160" height="160" />
      <rect x="340" y="0"   width="160" height="160" />
      <rect x="0"   y="170" width="160" height="160" />
      <rect x="170" y="170" width="160" height="160" />
      <rect x="340" y="170" width="160" height="160" />
      <rect x="0"   y="340" width="160" height="160" />
      <rect x="170" y="340" width="160" height="160" />
      <rect x="340" y="340" width="160" height="160" />
    </svg>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search