Friday, February 20, 2015

10 Minute Web App Challenge - Multiple Instructions Timer

In the morning of a clinical study, I made up my mind to quickly build an app that will count down a set of instructions according to the time per instruction set. This is kind of like when you do a workout at home and need to time differently to specific workout sets without having to manually keep track of which one you're on and resetting the timer to the one you need. During the last study, I discovered that I had too many things to keep track of and I would forget to press the counter button, make mistakes on the stopwatch time, subjects would be talking and not paying attention, and generally everything would be a mess. This time, I figured I'll just have something that will let them know when to move on to the next action, so I would only have one thing to do - explain the next step to them. And hence is the birth of the MotionOx Companion app. Took me 10 minutes of whipping up messy Javascript code but it worked and it made the clinical study that much easier for me and the other researchers.

Using a combination of JQuery slide and fade effects, I've created something I believe is visually appealing (the gif down sampling really killed the smoothness of the fade-in and slide-up animations. And what's fantastic about this web-app is that it's cross-platform compatible and the clinical study was done running this app on an iPhone 5.


It turned out that was not the smartest idea as the iPhone 5 battery couldn't even last longer than the Dell Venue tablets that's actually doing the sensor data collection. But... that's beside the point. Here's my web-app code.


<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
    <meta content='yes' name='mobile-web-app-capable'/>
    <title> MotionOx</title>
    <script src='jquery.min.js'> </script>
    <link href='http://fonts.googleapis.com/css?family=Roboto:100,300,400,700' rel='stylesheet' type='text/css'/>
    <link rel="stylesheet" type="text/css" href="style.css">
  </head>
  
  <style>
    
    .instruction,
    .time{
      font-size: 30px;
      font-weight: 100;
      font-family: "Roboto", sans-serif;
      margin-top: 20px;
    }
    
    .time{
      width: 100%;
      font-size: 60px;
      margin-top: -10px;
      font-weight: 100 !important;
      text-align: right;
    }
    
    #start-record{
      margin-bottom: 10px;
      opacity: 1;
    }
  </style>
  
  <script>
    $(document).ready(function(){
      
      var allListing;
      var fadeOpacity = "0.15";
      
      // Hide the entire list
      allListing = $("div:has(.instruction)");
      allListing.hide();
      
      // Show the first three
      $(allListing[0]).show();
      $(allListing[1]).show();
      $(allListing[2]).show().css("opacity", fadeOpacity);
      
      var numOfSteps = allListing.length;      
      
      function step(i){
          var timer;
          var timerCounter;
          
          // show current one
          $(allListing[i]).show();
          
          // show the one after
          if (i != (numOfSteps - 1)) {
              $(allListing[i+1]).css("opacity", 1);
          }
          
          // show the one after after
          if (i < (numOfSteps - 2)) {
              $(allListing[i+2]).css("opacity", fadeOpacity).delay(200).fadeIn(300);
          }
          
          // hide the one before
          if (i != 0) {
              $(allListing[i-1]).slideUp(400);
          }
          
          // if this isn't the last one
          if (i != (numOfSteps - 1)) {
            timer = parseInt($(allListing[i]).find('.time').text().trim());
            timerCounter = timer * 1000;
            
            // Create an interval timer that will recur once every second 
            // and we drop the timer count down, when it gets to 0, we do
            // a recursive call to the next step and clear the current interval
            var myTimer = setInterval(function(){
              if (timerCounter >= 1000) {
                $(allListing[i]).find('.time').html((timerCounter/1000 - 1).toString() + "");
              }
              timerCounter -= 1000;
              
              if (timerCounter < 0) {
                step(i+1);
                clearInterval(myTimer);
              }
            }, 1000);
          }
      }
      
      //~ step(0);
      
      var hasStarted = false;
      
      // Have the touch and brighten effect
      $("#start-record").on("touchstart mousedown", function(){
        $(this).css("opacity", "0.2");
      });
      
      // Release effect + actually start the timer
      $("#start-record").on("touchend mouseup", function(){
        $(this).css("opacity", "1");
        
        if (!hasStarted) {
            step(0);
            $(this).html("Running");
            hasStarted = true;
        }
      });
    });
    

  
  </script>
  
  <div>
    <center>
      <button id="start-record">MotionOx Companion Timer</button>
    </center>
  </div>
  
  <div>
    <div class="instruction">
      1. Rest
    </div>
    <div class="time">
      5
    </div>
  </div>
  
  <div>
    <div class="instruction">
      2. Wave
    </div>
    <div class="time">
      45
    </div>
  </div>
  
  <div>
    <div class="instruction">
      3. Rest
    </div>
    <div class="time">
      20
    </div>
  </div>
  
  <div>
    <div class="instruction">
      4. Scratch
    </div>
    <div class="time">
      45
    </div>
  </div>
  
  <div>
    <div class="instruction">
      5. Rest
    </div>
    <div class="time">
      20
    </div>
  </div>
  
  <div>
    <div class="instruction">
      6. Flexion-extension
    </div>
    <div class="time">
      45
    </div>
  </div>  
  
  <div>S
    <div class="instruction">
      7. Rest
    </div>
    <div class="time">
      20
    </div>
  </div>
  
  <div>
    <div class="instruction">
      8. Squeeze
    </div>
    <div class="time">
      45
    </div>
  </div>  
  
  <div>
    <div class="instruction">
      9. Rest
    </div>
    <div class="time">
      20
    </div>
  </div>

  <div>
    <div class="instruction">
      10. Tapping
    </div>
    <div class="time">
      45
    </div>
  </div>  
  
  <div>
    <div class="instruction">
      11. Rest
    </div>
    <div class="time">
      20
    </div>
  </div>
  
  <div>
    <div class="instruction">
      12. Side Hanging Position
    </div>
    <div class="time">
      45
    </div>
  </div>  

  <div>
    <div class="instruction">
      13. Touch your heart
    </div>
    <div class="time">
      45
    </div>
  </div>  

  <div>
    <div class="instruction">
      14. Touch your head
    </div>
    <div class="time">
      45
    </div>
  </div>  

  <div>
    <div class="instruction">
      15. Arm Straight Up
    </div>
    <div class="time">
      45
    </div>
  </div>
  
  <div>
    <div class="instruction">
      16. Complete
    <div class="time">
      0
    </div>
  </div>  
  <body>
  </body>
</html>



Also, just for fun, here is what the tablet-connected sensor apparatus looks like:

No comments :

Post a Comment