Search code examples
javascriptdesign-patternstimer

Complex Timers in javascript and design pattern


I'm currently building an app that is an overlay to a game. This app takes in game events and creates objects to make timers. Every timer is different depending on what events the app took from the game. What is the best design pattern for this situation?

this is the timer and the other one is a function that writes in a html file

function startTimer(duration, display) {
    var timer = duration;
    var minutes, seconds;
    setInterval(function () {
        minutes = parseInt(timer / 60, 10)
        seconds = parseInt(timer % 60, 10);

        minutes = minutes < 10 ? "0" + minutes : minutes;
        seconds = seconds < 10 ? "0" + seconds : seconds;

        display.textContent = minutes + ":" + seconds;

        if (--timer < 0) {
            timer = duration;
        }
    }, 1000);
}

var writeSum = function(sums, champ){
    var height = "height: 25px;";  
    var width = "width: 25px;";
    var size = "background-size: 25px 25px;";
    var image = "background-image: url( '../../icons/summoner spells/"+sums.path + "\' );";
    var display = "display: inline;";
    var click = "onclick =\"startTimer("+ sums.cd+", document.getElementById('"+ champ.name+ sums.name+"'\)\)\" ";

    return tag("div","",tag("button", click+style(height+width+image+size),"")+ tag("p","id = \""+champ.name+ sums.name + "\" "+style(display),"Ready"));
};

Solution

  • Simple demo of keeping track of multiple timers with an array of objects. Just decide on a well-formed structure that is easy to work with to represent your data model. Be it classes or functions or plain objects.

    I strongly recommend refactoring your string building. Especially the onclick= with JavaScript code generated through string concatenation. And ideally you need to keep track of timers, which startTimer should return and should be mergeable into and transformable with your data structure for representing each timer.
    Right now it looks like you'd probably end up devolving into using globals to pass parameters around.
    If it's just a simple task, keeping a global list of timers probably isn't a big deal.

    tag = (x,y,z)=>`<${x} ${y||''}>${z||''}</${x}>`
    
    
        function startTimer(duration, display) {
            var timer = duration;
            var minutes, seconds;
            setInterval(function () {
                minutes = parseInt(timer / 60, 10)
                seconds = parseInt(timer % 60, 10);
    
                minutes = minutes < 10 ? "0" + minutes : minutes;
                seconds = seconds < 10 ? "0" + seconds : seconds;
    
                display.textContent = minutes + ":" + seconds;
    
                if (--timer < 0) {
                    timer = duration;
                }
            }, 1000);
        }
    
        var writeSum = function(sums, champ){
            var height = "height: 25px;";  
            var width = "width: 25px;";
            var size = "background-size: 25px 25px;";
            var image = "background-image: url( '../../icons/summoner spells/"+sums.path + "\' );";
            var display = "display: inline;";
            var click = "onclick =\"startTimer("+ sums.cd+", document.getElementById('"+ champ.name+ sums.name+"'\)\)\" ";
    
            return tag("div","",tag("button", click+style(height+width+image+size),"")+ tag("p","id = \""+champ.name+ sums.name + "\" "+style(display),"Ready"));
        };
    
        function style(x){return `style="${x}"`}
    
    let entities = [
        {sums: {path:'spath1',cd:'10',name:'sname1'}, champ: {name:'cname1'}},
        {sums: {path:'spath2',cd:'10',name:'sname2'}, champ: {name:'cname2'}},
        {sums: {path:'spath3',cd:'10',name:'sname3'}, champ: {name:'cname3'}},
        {sums: {path:'spath4',cd:'10',name:'sname4'}, champ: {name:'cname4'}}
    ]
    document.body.innerHTML=entities.map(({sums, champ})=>writeSum(sums, champ)).join('')