Search code examples
javascriptshake

Why does en IF statement make my function repeat?


<!DOCTYPE html>

<html lang="sv">

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Sensor Assignment</title>
    <meta name="description" content="Demo av en animerad bil som kan manipuleras med mobiltelefoners gyro-sensor">
    <meta name="author" content="b22thohe">

    <script src="https://raw.githack.com/HGustavs/Shaker.js/master/shaker.js"></script>

    <script>
      var toggle = 0;

      function changeBackground(edata) {
        /* Debug output */
        document.getElementById("printout").innerHTML += "Detected SHAKES: " + edata.shakes + "<BR>"; /* print out # shakes registered */

        if (toggle == 0) {
          document.getElementById("svg").style.background = 'linear-gradient(0deg, rgba(150,150,150,1) 43%, rgba(0,187,255,1) 62%, rgba(0,63,255,1) 93%)'; // Ändrar bakgrunden i viewboxen
          document.getElementById("sun").transform.fill('yellow'); // Ändrar bakgrunden på solen   
          toggle = 1;
        } else if (toggle == 1) {
          document.getElementById("svg").style.background = 'linear-gradient(0deg, rgba(23,16,198,1) 7%, rgba(30,10,138,1) 39%, rgba(56,56,59,1) 100%)'; // Ändrar bakgrunden i viewboxen
          document.getElementById("sun").transform.fill('lightgrey'); // Ändrar bakgrunden på solen
          toggle = 0;
        }
      };

      function initShake() {
        shaker.on("shake", function(edata) {
          changeBackground(edata);
        });
      }

    </script>

    <style>
      /* Skapar en gradient som bakgrund och centrerar elementet */
      svg {
        display: block;
        margin: auto;
        background: linear-gradient(0deg, rgba(150, 150, 150, 1) 43%, rgba(0, 187, 255, 1) 62%, rgba(0, 63, 255, 1) 93%);
      }

      /* flyttar ut alla SVG-objekt till startposition */
      #grp-body {
        transform: translate(275px, 235px);
      }

      #grp-cockpit {
        transform: translate(237.5px, 210px);
      }

      #grp-back-tire {
        transform: translate(187.5px, 260px);
      }

      #grp-front-tire {
        transform: translate(362.5px, 260px);
      }

      #grp-back-hubcap {
        transform: translate(187.5px, 260px);
      }

      #grp-front-hubcap {
        transform: translate(362.5px, 260px);
      }

      #grp-back-wing {
        transform: translate(137.5px, 197.5px);
      }

      #grp-front-wing {
        transform: translate(418.75px, 203.75px);
      }

      #grp-smoke {
        transform: translate(75px, 205px);
        transition: opacity 9s;
      }

      #grp-exhaust {
        transform: translate(112.5px, 247.5px)
      }

      #grp-exhaust-flame {
        transform: translate(86px, 246px);
      }


      /* Animerar rökpuffen */
      @keyframes smoke {
        0% {
          transform: translate(75px, 205px) scale(1);
          opacity: 1;
        }

        33.3% {
          transform: translate(3px, 93px) scale(0.3);
          opacity: 0;
        }

        66.6% {
          transform: translate(-69px, -19px) scale(0.2);
        }

        75% {
          transform: translate(-107.5px, -82.5px) scale(0.1);
        }

        100% {
          transform: translate(-146px, -146px) scale(0);
        }
      }

      #grp-smoke {
        animation-name: smoke;
        animation-duration: 12000ms;
        animation-iteration-count: 1;
        animation-timing-function: linear;
        animation-fill-mode: forwards;
        animation-play-state: paused;
        opacity: 0;
      }

      /* Animerar bilens rörelse */
      @keyframes drive {
        0% {
          transform: translateX(-460px);
        }

        100% {
          transform: translateX(1260px);
        }
      }

      #grp-entire-vehicle {
        animation-name: drive;
        animation-duration: 9000ms;
        animation-iteration-count: 1;
        animation-timing-function: linear;
        animation-play-state: paused;
      }

    </style>

  </head>

  <body id="content" onload="initShake();">
    <!-- Skapar en rityta -->
    <svg id="svg" width="100%" viewbox="0 0 900 300" style="border:1px solid black;">

      <defs>
        <!-- Skapar gradient för däcken -->
        <radialGradient id="tire-gradient">
          <stop offset="50%" stop-color="#6f6e6e" />
          <stop offset="75%" stop-color="#000000" />
          <stop offset="100%" stop-color="#6f6e6e" />
        </radialGradient>

        <!-- Förbereder animerad bild för bakgrund till navkapslarna -->
        <pattern id="hubcap-img" x="0" y="0" height="15" width="15">
          <image x="0" y="0" width="15" height="15" xlink:href="./img/hubcap.png"></image>
          <animateTransform id="hubcapAnim" attributeType="xml" attributeName="patternTransform" type="rotate" from="0" to="360" begin="0" dur="9s" repeatCount="indefinite" />
        </pattern>
      </defs>

      <!-- Ritar ut bilkroppen -->
      <g id="grp-entire-vehicle">
        <!-- FÖRARHYTT -->
        <g id="grp-cockpit">
          <path id="cockpit" d="M 0 0 A 25 18.75 0 0 1 100 0" fill="lightblue" stroke="blue" stroke-width="1" stroke-miterlimit="5" />
        </g>
        <!-- DÄCK -->
        <g id="grp-back-tire">
          <circle id="back-tire" stroke-miterlimit="5" cx="0" cy="0" r="15" fill="url(#tire-gradient)" stroke="blue" stroke-width="2"></circle>
        </g>
        <g id="grp-front-tire">
          <circle id="front-tire" stroke-miterlimit="5" cx="0" cy="0" r="15" fill="url(#tire-gradient)" stroke="blue" stroke-width="2"></circle>
        </g>
        <!-- NAVKAPSLAR -->
        <g id="grp-back-hubcap">
          <circle id="back-hubcap" stroke-miterlimit="5" cx="0" cy="0" r="7.5" fill="url(#hubcap-img)" stroke="blue" stroke-width="2"></circle>
        </g>
        <g id="grp-front-hubcap">
          <circle id="front-hubcap" stroke-miterlimit="5" cx="0" cy="0" r="7.5" fill="url(#hubcap-img)" stroke="blue" stroke-width="2"></circle>
        </g>
        <!-- KAROSS -->
        <g id="grp-body">
          <rect id="main-body" x="-150" y="-25" width="300" height="50" stroke="blue" stroke-width="2" fill="lightblue"></rect>
        </g>
        <!-- KAROSS-VINGAR -->
        <g id="grp-back-wing">
          <polygon id="back-wing" stroke-miterlimit="5" points="-12.5,12.5 12.5,12.5 -12.5,-12.5 -12.5,12.5" fill="lightblue" stroke="blue" stroke-width="2"></polygon>
        </g>
        <g id="grp-front-wing">
          <polygon id="front-wing" stroke-miterlimit="5" points="6.25,6.25 -6.25,6.25 6.25,-6.25 6.25,6.25" fill="lightblue" stroke="blue" stroke-width="2"></polygon>
        </g>
        <!-- RÖKPUFF -->
        <g id="grp-smoke">
          <circle cx="9.162" cy="8.185" r="25" fill="rgb(79,77,76,1)" />
          <circle cx="-5.838" cy="3.185" r="25" fill="rgb(79,77,76,1)" />
          <circle cx="-15.838" cy="11.815" r="21" fill="rgb(79,77,76,1)" />
        </g>
        <!-- AVGASRÖR -->
        <g id="grp-exhaust">
          <polygon id="exhaust" stroke-miterlimit="5" points="-12.5,-9.375 -12.5,9.375 -3.125,6.25 3.125,3.125 12.5,3.125 12.5,-3.125 3.125,-3.125 -3.125,-6.25 -12.5,-9.375" fill="lightgray" stroke="black" stroke-width="0.5"></polygon>
        </g>
        <!-- AVGAS-FLAMMOR -->
        <g id="grp-exhaust-flame">
          <polygon id="exhaust-flame" stroke-miterlimit="5" points="-25,-23.4375 -12.5,-17.25 -3.125,-11 6.25,-4.75 12.5,-4.75 12.5,7.75 6.25,7.75 -3.125,14 -9.375,20.25 -15.625,23.375 -12.5,17.125 -6.25,7.75 -12.5,10.875 -18.75,14 -31.25,17.125 -25,7.75 -12.5,-1.625 -25,-7.875 -37.5,-14.125 -31.25,-17.25 -12.5,-7.875 -18.75,-17.25 -25,-23.5" fill="yellow" stroke="red" stroke-width="2"></polygon>
        </g>
      </g>

      <!-- SOL -->
      <g id="sun">
        <circle cx="500" cy="50" r="50" fill="yellow" />
      </g>
      <!-- Start-knapp -->
      <g id="grp-start-button" onClick="startAnimation()">
        <a href="#">
          <rect x="30" y="30" width="100" height="50" stroke="black" fill="green" stroke-width="3" />
          <text x="53" y="63" font-family="helvetica neue" font-size="25" fill="yellow">Start</text>
        </a>
      </g>
      <g id="grp-stop-button" onClick="stopAnimation()">
        <!-- Stopp-knapp -->
        <a href="#">
          <rect x="140" y="30" width="100" height="50" stroke="black" fill="red" stroke-width="3" />
          <text x="163" y="63" font-family="helvetica neue" font-size="25" fill="yellow">Stop</text>
        </a>
      </g>
    </svg>

    <pre id="printout">Shaker Events Printout<br></pre>

  </body>

</html>

I've been banging my head against a wall for awhile now so I'm not even sure what I'm doing anymore. The basis is this: I'm using a javascript library to identify when the user "shakes" the phone.

The initShake() function is called on body load. From there I call changeBackground function that outputs the number of shakes registered. This all works fine until I put an IF/ELSE IF statement inside the changeBackground statement, because then the number of shakes output starts repeating seemingly infinitely. And I can't wrap my head around why?

I would like to know why this happens, and of course good ways to remedy this. Is it because of faulty IF statements or something else? Is it because of faulty IF statements or something else?

This is my HTML with the body onload call and element for outputting number of shakes:

<body id="content" onload="initShake();">
   <pre id="printout">Shaker Events Printout<br></pre>
</body>

This is the initShake() function:

function initShake() {
    shaker.on("shake",function(edata){
        changeBackground(edata);
    });
}

And this is the changeBackground function:

function changeBackground(edata) {
    /* Debug output */
    document.getElementById("printout").innerHTML+="Detected SHAKES: "+edata.shakes+"<BR>"; /* print out # shakes registered */
};

And here's where I load the shaker script:

<script src="https://raw.githack.com/HGustavs/Shaker.js/master/shaker.js"></script>

This is the IF/ELSE IF statement that I put inside the changeBackground function:

if (toggle == 0) {
    document.getElementById("svg").style.background = 'linear-gradient(0deg, rgba(150,150,150,1) 43%, rgba(0,187,255,1) 62%, rgba(0,63,255,1) 93%)'; // Ändrar bakgrunden i viewboxen
    document.getElementById("sun").transform.fill('yellow'); // Ändrar bakgrunden på solen   
    toggle = 1;
} else if (toggle == 1) {
    document.getElementById("svg").style.background = 'linear-gradient(0deg, rgba(23,16,198,1) 7%, rgba(30,10,138,1) 39%, rgba(56,56,59,1) 100%)'; // Ändrar bakgrunden i viewboxen
    document.getElementById("sun").transform.fill('lightgrey'); // Ändrar bakgrunden på solen
}

Solution

  • I don't know why this works exactly, but could you try changing:

    document.getElementById("sun").transform.fill('yellow');
    

    to

    document.getElementById("sun").querySelector("circle").style.fill = 'yellow';
    

    (and do the same for the lightgrey version).

    For anyone who wants to try this in the browser here's a hacky bit of code to do the shaking:

    for(let i = 0; i < 200; i++) {
        setTimeout(() => {
          let event = new DeviceMotionEvent('devicemotion', {accelerationIncludingGravity:{ x: 50 * (i % 2 === 0 ? -1 : 1), y: 0, z: 0 }});
    
          window.dispatchEvent(event);
        }, i * 100 + (i % 2 === 0 ? 50 : 0));
    }