0

I'm trying to make a typing speed test counter. The goal is to move the blinking cursor throughout the text only if the correct character is entered. I'm unable to understand how to move through the text. I shall then count the number of minutes taken and calculate wpm.

function timer() {
  var seconds = 3;
  var element = document.getElementById('timer');
  var timerId = setInterval(countdown, 1000);

  function countdown() {
    if (seconds == -1) {
      clearTimeout(timerId);
      element.innerHTML = "Time Up";
      var value = 1;
      wpm();
    } else {
      element.innerHTML = "Time Left: " + seconds + " " + "seconds";
      seconds--;
    }
  }
}
body {
  font-family: monospace;
}

.title-of-page>h1 {
  text-align: center;
  font-family: monospace;
}

.title-of-page {
  background-color: #414a4c;
  color: #ced3db;
}

.jumbotron {
  margin: 0;
}

.navigation-bar {
  background-color: #46494f;
}

a {
  color: green;
}

.nav>li>a:hover {
  background-color: #878f9b;
}

.navbar-nav>li {
  text-align: center;
  float: none;
  display: table-cell;
}

.navbar-nav {
  display: table;
  width: 100%;
  margin: 0;
}

.navbar {
  margin: 0;
  padding: 0;
  border-radius: 0;
}

.typing-field {
  width: 60em;
  height: 8em;
  background-color: #7e7e7f;
  opacity: 0.4;
  margin-left: 15em;
  margin-top: 5em;
  border: 3px solid black;
  padding: 0.8em;
}

#display-text {
  color: white;
  font-size: 2em;
}

.user-input {
  font-size: 1em;
  padding-left: 35em;
  padding-top: 2em;
}

#timer {
  padding-top: 4em;
  padding-left: 10em;
  font-size: 1.5em;
  color: red;
}

.typed-cursor {
  opacity: 1;
  -webkit-animation: blink 0.7s infinite;
  -moz-animation: blink 0.7s infinite;
  animation: blink 0.7s infinite;
  color: black;
}

@keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-webkit-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-moz-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<body>
  <div class="jumbotron title-of-page container-fluid">
    <h1>Typing Counter</h1>
  </div>
  <nav class="navbar navigation-bar container-fluid">
    <div class="">
      <ul class="nav navbar-nav">
        <li><a href="#">Home</a></li>
        <li><a href="#">Contest</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Leaderboard</a></li>
      </ul>
    </div>
  </nav>
  <div>
    <div id="timer">
      <button type="button" class="btn" onclick="timer();">Start</button>
    </div>
    <div class="typing-field">
      <p id="display-text"><span class="typed-cursor">T</span>his is to test your typing speed. So type like you'll never type again.</p>
    </div>
    <div class="user-input">
      <input type="text" name="user-input-text-box" id="user-input" />
    </div>
  </div>
</body>

For javascript I tried to do something like this. It's mostly wrong. I'm still a beginner.

window.onload = function wpm() {
  var text = document.getElementById('user-input').innerHTML;
  var i=0;
  document.getElementById('user-input').onkeyup = function() {
    var letter = this.value;
    if(letter==text[i])
    {
      letter.style.color="green";
      i++;
    }
  }
}
3.14159
  • 267
  • 6
  • 22
  • Could you please explain what problem are you getting? Maye also basic idea behind your solution? Are you struggling with implementation or with a design decision? Be more specific and it will be easier to get help. Thanks. – matiit May 14 '18 at 14:57
  • I'm struggling with the implementation. I do not know how to modify the text(as in traverse through it using the blinker) by checking if the user enters the correct input. – 3.14159 May 14 '18 at 14:59
  • 1
    You don't have control over the cursor placement within a ` – Randy Casburn May 14 '18 at 15:03
  • @RandyCasburn The way I understand the code, the cursor he talks about is within the `

    `, so it's not a `textarea` or `input`. You can run the snippet to see the "blinking" letter.

    – Takit Isy May 14 '18 at 15:10
  • Yes that's what I meant – 3.14159 May 14 '18 at 15:11
  • All I get with the snippet is a runtime error: `cannot find wpm` - so didn't waste time investigating that. – Randy Casburn May 14 '18 at 15:18
  • it seems more complicated since it isn't just a `
    ` tag, but a `

    ` with a `` that apparently would need to be removed and replaced during each character addition. Would this be correct?

    – Randy Casburn May 14 '18 at 15:20
  • This is likely a duplicate of: https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript – Randy Casburn May 14 '18 at 15:21

2 Answers2

1

Here is what I ended up with after playing a little with your code:

var display = document.getElementById('display-text');
var userInput = document.getElementById('user-input');

userInput.onkeyup = function() {
  for (var i = 0; i < userInput.value.length; i++) { // Counts correct letters
    if (display.innerText[i] != userInput.value[i])
      break; // Exit loop if incorrect
  }
  display.innerHTML = '<span style="color: green;">' + display.innerText.substr(0, i) + '</span>' + '<span class="typed-cursor">' + display.innerText.substr(i, 1) + '</span>' + display.innerText.substr(i + 1);
}
body {
  font-family: monospace;
}

.typing-field {
  width: auto;
  /* Modified for snippet */
  height: auto;
  /* Modified for snippet */
  background-color: #7e7e7f;
  opacity: 0.4;
  margin-left: 0;
  /* Modified for snippet */
  margin-top: 0;
  /* Modified for snippet */
  border: 3px solid black;
  padding: 0.8em;
}

#display-text {
  color: white;
  font-size: 2em;
}

.user-input {
  font-size: 1em;
  padding-left: 0;
  /* Modified for snippet */
  padding-top: 0;
  /* Modified for snippet */
}

#timer {
  padding-left: 0;
  /* Modified for snippet */
  padding-top: 0;
  /* Modified for snippet */
  font-size: 1.5em;
  color: red;
}

.typed-cursor {
  opacity: 1;
  -webkit-animation: blink 0.7s infinite;
  -moz-animation: blink 0.7s infinite;
  animation: blink 0.7s infinite;
  color: black;
}

@keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-webkit-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-moz-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<body>
  <div>
    <div id="timer">
      <button type="button" class="btn" onclick="timer();">Start</button>
    </div>
    <div class="typing-field">
      <p id="display-text"><span class="typed-cursor">T</span>his is to test your typing speed. So type like you'll never type again.</p>
    </div>
    <div class="user-inputs">
      <input type="text" name="user-input-text-box" id="user-input" />
    </div>
  </div>
</body>

This code compares the displayed and the typed strings, highlights in green the correct letters and put the blinking cursor on the one to be typed.

I hope it helps. :)

Takit Isy
  • 9,688
  • 3
  • 23
  • 47
0

If you want to track the letters typed and then turn them a different color, you can save the text string in a variable and queue through it dumping the typed letters into another array, then merge them together into the output field:

    let textToType = "This is what I want you to type.";
    const typedLetters = [];

    document.getElementById('user-input').addEventListener("keypress", function(event) {
      const key = event.which || event.keyCode;
      const nextLetter = textToType[0].charCodeAt();
      const outputTarget = document.getElementById("display-text");
      
      const greenWrapper = document.createElement("span");
      greenWrapper.classList.add("typed-cursor");

      if (key === nextLetter) {
        typedLetters.push(String.fromCharCode(nextLetter));
        textToType = textToType.substr(1);
        greenWrapper.textContent = typedLetters.join("");
        outputTarget.textContent = textToType;
        outputTarget.prepend(greenWrapper);
        
        
      };
    })
body {
  font-family: monospace;
}

.title-of-page>h1 {
  text-align: center;
  font-family: monospace;
}

.title-of-page {
  background-color: #414a4c;
  color: #ced3db;
}

.jumbotron {
  margin: 0;
}

.navigation-bar {
  background-color: #46494f;
}

a {
  color: green;
}

.nav>li>a:hover {
  background-color: #878f9b;
}

.navbar-nav>li {
  text-align: center;
  float: none;
  display: table-cell;
}

.navbar-nav {
  display: table;
  width: 100%;
  margin: 0;
}

.navbar {
  margin: 0;
  padding: 0;
  border-radius: 0;
}

.typing-field {
  width: 60em;
  height: 8em;
  background-color: #7e7e7f;
  opacity: 0.4;
  margin-left: 15em;
  margin-top: 5em;
  border: 3px solid black;
  padding: 0.8em;
}

#display-text {
  color: white;
  font-size: 2em;
}

.user-input {
  font-size: 1em;
  padding-left: 35em;
  padding-top: 2em;
}

#timer {
  padding-top: 4em;
  padding-left: 10em;
  font-size: 1.5em;
  color: red;
}

.typed-cursor {
  opacity: 1;
  -webkit-animation: blink 0.7s infinite;
  -moz-animation: blink 0.7s infinite;
  animation: blink 0.7s infinite;
  color: black;
}

@keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-webkit-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

@-moz-keyframes blink {
  0% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
  <div class="jumbotron title-of-page container-fluid">
    <h1>Typing Counter</h1>
  </div>
  <nav class="navbar navigation-bar container-fluid">
    <div class="">
      <ul class="nav navbar-nav">
        <li><a href="#">Home</a></li>
        <li><a href="#">Contest</a></li>
        <li><a href="#">About</a></li>
        <li><a href="#">Leaderboard</a></li>
      </ul>
    </div>
  </nav>
  <div>
    <div id="timer">
      <button type="button" class="btn" onclick="timer();">Start</button>
    </div>
    <div class="typing-field">
      <p id="display-text">This is what I want you to type.
    </div>
    <div class="user-input">
      <input type="text" name="user-input-text-box" id="user-input" />
    </div>
  </div>
Jonathan Rys
  • 1,782
  • 1
  • 13
  • 25