Bu Javascript kronometre saatinde stop-start sürecini nasıl düzeltebilirim?

Sep 30 2020

Burada bir JavaScript kronometrem var, devam ederken aynı zamanı korumak için başlat-durdur düğmesinin gerekli olduğunu düşünüyorum. Şu anda, durup devam edersem saat farkını '-19330839: -3: -53' gibi saçma bir şey

Bunun nasıl düzeltildiğini kimse açıklayabilir mi?

Yaptığım çeşitli yöntem kronometrelerim var; ancak bir sayaç yerine gerçek tarih saati kullanmayı tercih ederim, bunun nedeni (bunun farkına vardıktan sonra test ettim) sayaçların belirli bir süre boyunca çok yanlış olmasıdır.

Herhangi bir yardım çok takdir edilmektedir.

html:

Lütfen şimdilik sıfırlama düğmesini dikkate almayın. Bunu daha sonra yapılandıracağım.

        <input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
        <input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>   
        <div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>

JS:

    const outputElement = document.getElementById("outputt");
    var startTime = 0;
    var running = false;
    var splitcounter = 0;
    
    
    function startstop() {
      if (running == false) {
        running = true;
        startTime = new Date(sessionStorage.getItem("time"))
        if (isNaN(startTime)) startTime = Date.now();
        startstopbutton.value = 'Stop';
        document.getElementById("outputt").style.backgroundColor = "#2DB37B";
        updateTimer();
      } else {
        running = false;
        logTime();
        startstopbutton.value = 'Start';
        document.getElementById("outputt").style.backgroundColor = "#B3321B";
      }
    }
    
    function updateTimer() {
      if (running == true) {
        let differenceInMillis = Date.now() - startTime;
        sessionStorage.setItem("time", differenceInMillis)
        let {
          hours,
          minutes,
          seconds
        } = calculateTime(differenceInMillis);
        let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
        
        outputElement.innerText = timeStr;
        requestAnimationFrame(updateTimer);
      }
    }
    
    function calculateTime(milliS) {
      const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
      const MINUTES = 60;
      const HOURS = 60;
      const RESET = 60;
      
      let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
      let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
      let seconds = Math.floor(milliS / SECONDS) % RESET;
      
      return {
        hours,
        minutes,
        seconds
      };
    }
    
    function pad(time) {
      return time.toString().padStart(2, '0');
    }

Sadece durduğu yerden devam etmek için zamanlayıcıya ihtiyacım var.

Yanıtlar

2 Rajesh Sep 30 2020 at 18:12

Kodunuzla ilgili sorun:

  • Olarak sessionStorage için başlangıç ​​değeri ile başlarsınız, Date.nowancak daha sonra güncellemedeki farkı kaydedersiniz .
  • Oturum depolamayla çok etkileşim halindesiniz. Harici API ile herhangi bir iletişim pahalıdır. Bunun yerine yerel değişkenleri kullanın ve değerleri başlatmak için bir olay bulun.
  • Zaman farkı mantığı biraz yanlış.
    • Date.now - startTime eylemi durdur ve eylemi başlat arasındaki farkı dikkate almaz.
    • Bu mantığı kullanabilirsiniz: Eğer startTime tanımlanmışsa, farkı hesaplayın ve başlangıç ​​saatine ekleyin. Değilse, onu başlatDate.now()

Öneriler:

  • Stil eklemek yerine sınıfları kullanın. Bu, sıfırlama işlevselliğinde size yardımcı olacaktır
  • Küçük özellikleri tanımlayın ve buna göre küçük fonksiyonları tanımlayın. Bu yeniden kullanılabilirliği kolaylaştırır
  • Bağımsız değişkenler ileterek ve yalnızca onlara güvenerek işlevleri bağımsız yapmaya çalışın. Bu şekilde yan etkileri azaltacaksınız

Not: SO, Oturum Depolamasına erişime izin vermediğinden, ilgili tüm kodu kaldırdım.

const outputElement = document.getElementById("outputt");
var running = false;
var splitcounter = 0;
var lastTime = 0;
var startTime = 0;

function logTime() {
  console.log('Time: ', lastTime)
}

function resetclock() {
  running = false;
  startTime = 0;
  printTime(Date.now())
  applyStyles(true)
}

function applyStyles(isReset) {
  startstopbutton.value = running ? 'Stop' : 'Start';
  document.getElementById("outputt").classList.remove('red', 'green')
  if (!isReset) {
    document.getElementById("outputt").classList.add(running ? 'red' : 'green')
  }
}
function startstop() {
  running = !running;
  applyStyles();
  if (running) {
    if (startTime) {
      const diff = Date.now() - lastTime;
      startTime = startTime + diff;
    } else {
      startTime = Date.now()
    }
    
    updateTimer(startTime);
  } else {
    lastTime = Date.now()
    logTime();
  }
}

function printTime(startTime) {
  let differenceInMillis = Date.now() - startTime;
  let {
    hours,
    minutes,
    seconds
  } = calculateTime(differenceInMillis);
  let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
  outputElement.innerText = timeStr;
}

function updateTimer(startTime) {
  if (running == true) {
    printTime(startTime)
    requestAnimationFrame(() => updateTimer(startTime));
  }
}

function calculateTime(milliS) {
  const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
  const MINUTES = 60;
  const HOURS = 60;
  const RESET = 60;

  let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
  let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
  let seconds = Math.floor(milliS / SECONDS) % RESET;

  return {
    hours,
    minutes,
    seconds
  };
}

function pad(time) {
  return time.toString().padStart(2, '0');
}
.red {
  background-color: #2DB37B
}

.green {
  background-color: #B3321B
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();" />
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>

1 joseph Sep 30 2020 at 18:31

basit kronometre örneği

<!DOCTYPE html>
<html>
<head>
    <title></title>
</head>
<body>
<input class="startstop" style="width: 120px;" type="button" value="Start" onclick="startstop();">
<input class="reset" style="width: 120px;" type="button" value="Reset" onclick="reset();"/>   
<div class="timerClock" value="00:00:00">00:00:00</div>
<script type="text/javascript">
    var second = 0
    var minute = 0
    var hour = 0
    var interval
    var status = false
    var element = document.querySelector('.startstop')
    var clock = document.querySelector('.timerClock')
    var string = ''
    function startstop() 
    {
        if(status == 'false')
        {
            element.value = 'Stop'
            clock.style.backgroundColor = "#2DB37B";
            status = true
            interval = setInterval(function()
            {
                string = ''
                second += 1
                if(second >= 60)
                {
                    minute += 1
                    second = 0
                }
                if(minute >= 60)
                {
                    hour += 1
                    minute = 0
                }

                if(hour < 10)
                    string += `0${hour}:` else string += `${hour}:`

                if(minute < 10)
                    string += `0${minute}:` else string += `${minute}:`

                if(second < 10)
                    string += `0${second}` else string += `${second}`

                clock.innerHTML = string
            },1000)         
        }
        else
        {
            clock.style.backgroundColor = "#B3321B";
            element.value = 'Start'
            status = false
            clearInterval(interval)
        }
    }
    function reset()
    {
        second = 0
        minute = 0
        hour = 0
        status = false
        element.value = 'Start'
        clearInterval(interval)
        clock.innerHTML = `00:00:00`
        clock.style.backgroundColor = "transparent";
    }
</script>
</body>
</html>

RickardElimää Oct 01 2020 at 00:24

RequestAnimationFrame hakkında bilinmesi gereken bir şey, bir sonraki animasyona referans olan bir tamsayı döndürmesidir. Bunu ile bir sonraki bekleyen animasyonu iptal etmek için kullanabilirsiniz cancelAnimationFrame.

@Rajesh tarafından belirtildiği gibi, mevcut süreci (çok) kısa bir süre için durduracağı için her güncellemenin saatini kaydetmemelisiniz. Bu durumda, çalışana kadar bekleyecek bir olayı, tercihen her saniye tetiklemek daha iyidir. Bunu hesaba katmak için kodu güncellemedim, sadece şimdilik yorum yaptım.

Ayrıca, öğe stillerini güncellemektense sınıfları kullanmak daha iyidir. Öğedeki tüm sınıfların üzerine yazan özensiz bir kod yazdım #outputt("çıktı" olarak yazılır). Bu kötü bir programlama çünkü başka sınıfların eklenmesini imkansız kılıyor, ama şimdilik amaca hizmet ediyor. @Rajesh kodu bu amaç için daha iyi yazılır.

İki değişken ekledim - diffTimeve animationId. İlki startTime, kullanıcı duraklatırsa düzeltir . İkincisi, devam eden bir zamanlayıcı animasyonu olup olmadığını izler.

Tarz güncellemelerinizi kendi yöntemlerine göre yeniden düzenledim. Kontrol etmelisiniz, çünkü standart değerleri tanımlar ve sonra bunları bir if ifadesiyle değiştirir. document.getElementById("outputt").style...Farklı satırlara yazmaktan daha az kod .

Bir resetclockyöntem de ekledim .

const outputElement = document.getElementById("outputt");
var startTime = 0;
var diffTime = 0;
var animationId = 0;

function startstop() {
  const PAUSED = 0;
  let paused = animationId == PAUSED;
  //diffTime = new Date(sessionStorage.getItem("time")) || 0;
  startTime = Date.now() - diffTime;

  if (paused) {
    updateTimer();
  } else {
    cancelAnimationFrame(animationId);
    animationId = PAUSED;
  }  

  updateTimerClass(paused);
}

function updateTimerClass(paused) {
  var outputClass = 'red';
  var buttonText = 'Start';
  
  if (paused) {
    outputClass = 'green';
    buttonText = 'Stop';
  } 
  
  startstopbutton.value = buttonText;
  outputElement.classList = outputClass;
}

function updateTimer() {
  let differenceInMillis = Date.now() - startTime;
  //sessionStorage.setItem("time", differenceInMillis)
  let {
    hours,
    minutes,
    seconds
  } = calculateTime(differenceInMillis);
  let timeStr = `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;

  outputElement.innerText = timeStr;
  diffTime = differenceInMillis;
  animationId = requestAnimationFrame(updateTimer);
}

function calculateTime(milliS) {
  const SECONDS = 1000; // should be 1000 - only 10 to speed up the timer
  const MINUTES = 60;
  const HOURS = 60;
  const RESET = 60;

  let hours = Math.floor(milliS / SECONDS / MINUTES / HOURS);
  let minutes = Math.floor(milliS / SECONDS / MINUTES) % RESET;
  let seconds = Math.floor(milliS / SECONDS) % RESET;

  return {
    hours,
    minutes,
    seconds
  };
}

function pad(time) {
  return time.toString().padStart(2, '0');
}

function resetclock() {
  let paused = animationId == 0;
  
  startTime = Date.now();
  diffTime = 0;
  
  if (paused) {
    const REMOVE_ALL_CLASSES = '';
    outputElement.className = REMOVE_ALL_CLASSES;
    outputElement.innerText = '00:00:00';
  }
}
#outputt.green {
  background-color: #2DB37B;
}

#outputt.red {
  background-color: #B3321B;
}
<input id="startstopbutton" class="buttonZ" style="width: 120px;" type="button" name="btn" value="Start" onclick="startstop();">
<input id="resetbutton" class="buttonZ" style="width: 120px;" type="button" name="btnRst1" id='btnRst1' value="Reset" onclick="resetclock();"/>   
<div id="outputt" class="timerClock" value="00:00:00">00:00:00</div>

AjinJoseph Sep 30 2020 at 18:52

class Stopwatch {
    constructor(display, results) {
        this.running = false;
        this.display = display;
        this.results = results;
        this.laps = [];
        this.reset();
        this.print(this.times);
    }
    
    reset() {
        this.times = [ 0, 0, 0 ];
    }
  click(){
    var x=document.getElementById('ctrl');
    if(x.value=="start"){
     this.start();
     x.value="stop";
     document.getElementById("outputt").style.backgroundColor = "#2DB37B";
    }
    else{
     x.value="start";
     this.stop();
     document.getElementById("outputt").style.backgroundColor = "#B3321B";
    }
  }
    start() {
        if (!this.time) this.time = performance.now();
        if (!this.running) {
            this.running = true;
            requestAnimationFrame(this.step.bind(this));
        }
    }
    
    stop() {
        this.running = false;
        this.time = null;
    }

    resets() {
        document.getElementById("outputt").style.backgroundColor = "#2DB37B";
        if (!this.time) this.time = performance.now();
        if (!this.running) {
            this.running = true;
            requestAnimationFrame(this.step.bind(this));
        }
        this.reset();
    }
    
    
    step(timestamp) {
        if (!this.running) return;
        this.calculate(timestamp);
        this.time = timestamp;
        this.print();
        requestAnimationFrame(this.step.bind(this));
    }
    
    calculate(timestamp) {
        var diff = timestamp - this.time;
        // Hundredths of a second are 100 ms
        this.times[2] += diff / 1000;
        // Seconds are 100 hundredths of a second
        if (this.times[2] >= 100) {
            this.times[1] += 1;
            this.times[2] -= 100;
        }
        // Minutes are 60 seconds
        if (this.times[1] >= 60) {
            this.times[0] += 1;
            this.times[1] -= 60;
        }
    }
    
    print() {
        this.display.innerText = this.format(this.times);
    }
    
    format(times) {
        return `\
${pad0(times[0], 2)}:\ ${pad0(times[1], 2)}:\
${pad0(Math.floor(times[2]), 2)}`;
    }
}

function pad0(value, count) {
    var result = value.toString();
    for (; result.length < count; --count)
        result = '0' + result;
    return result;
}

function clearChildren(node) {
    while (node.lastChild)
        node.removeChild(node.lastChild);
}

let stopwatch = new Stopwatch(
    document.querySelector('.stopwatch'),
    document.querySelector('.results'));
<input  type="button" id="ctrl" value="start" onClick="stopwatch.click();">
<input  type="button" value="Reset" onClick="stopwatch.resets();">
<div id="outputt"  class="stopwatch"></div>