2

I want my countdown to be visualised by an arc growing the more time passes. Like this enter image description here

There are four circles (days, hours, minutes and seconds). The countdown is already working. This is the code I already have.

const getTimeRemaining = (endtime) =>{
  let t = Date.parse(endtime) - Date.parse(new Date());
  let seconds = Math.floor((t / 1000) % 60);
  let minutes = Math.floor((t / 1000 / 60) % 60);
  let hours = Math.floor((t / (1000 * 60 * 60)) % 24);
  let days = Math.floor(t / (1000 * 60 * 60 * 24));
  return {
    'total': t,
    'days': days,
    'hours': hours,
    'minutes': minutes,
    'seconds': seconds
  };
}

const initializeClock = (id, endtime) =>{
  let clock = document.getElementById(id);
  let daysTime = document.querySelector('.dagen');
  let hoursTime = document.querySelector('.uren');
  let minutesTime = document.querySelector('.minuten');
  let secondsTime = document.querySelector('.seconden');
  
  const updateClock = () =>{
    var t = getTimeRemaining(endtime);

    daysTime.innerHTML = t.days;
    hoursTime.innerHTML = ('0' + t.hours).slice(-2);
    minutesTime.innerHTML = ('0' + t.minutes).slice(-2);
    secondsTime.innerHTML = ('0' + t.seconds).slice(-2);

    if (t.total <= 0) {
      clearInterval(timeinterval);
    }
  }
  updateClock();
  let timeinterval = setInterval(updateClock, 1000);
}

let eind = 'july 20 2016 10:00:00 GMT+0100';
initializeClock('clockdiv', eind);
.klokjes{ 
  width: 800px;
  margin: 0 auto;
  display: -webkit-flex;
  display: flex;
  align-items: center;
  flex-direction: row;
  justify-content: space-around;
  font-family: 'aller_lightregular';
  color: #fff;
  text-align: center;
}

.klokjes > div{
  width: 130px;
  height: 130px;
  margin: 20px;
  border-radius: 90px;
  background: #00BF96;
}

.klokjes div > span{
  font-size:38px;
  padding-top: 15px;
  display: inline-block;
}

.klokjes .g{
  background-color: #78D722;
}

.klokjes .y{
  background-color: #F5C239;
}

.klokjes .b{
  background-color: #3ADDD2;
}

.klokjes .p{
  background-color: #EF5570;
}
<section class="homeCountdown">
  <h4>Aanvang van het festival</h4>
  <div class="klokjes">
    <div class="g">
      <span class="dagen"></span>
      <div class="vasteTekst">dagen</div>
    </div>
    <div class="y">
      <span class="uren"></span>
      <div class="vasteTekst">uren</div>
    </div>
    <div class="b">
      <span class="minuten"></span>
      <div class="vasteTekst">minuten</div>
    </div>
    <div class="p">
      <span class="seconden"></span>
      <div class="vasteTekst">seconden</div>
    </div>
  </div>
</section>

Is there a way to make an ark (maybe using an svg) to visualise this better?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Lou.db
  • 65
  • 1
  • 7
  • The answer is yes. You could do it with an SVG. Have you tried? There is plenty of information on the web (including this site) on how to draw and animate circular arcs. Have a go, and if you get stuck come back and ask a specific question. Good luck! – Paul LeBeau Jun 12 '16 at 11:28
  • @Lou.db Does it really make sense to use arcs for this? Which start date would you use? – Midas Jun 12 '16 at 20:51
  • I didn't mean path arcs (A path command). I was referring to the visual concept of an arc. – Paul LeBeau Jun 13 '16 at 02:30

2 Answers2

0

I used the code found here : How to calculate the SVG Path for an arc (of a circle)

Inside a setInterval call. I think it gives the basis of what you are looking for visually.

EDIT NOTES:

Based on @PaulLeBeau's suggestion, I have updated the example to include a CSS only solution that is very straight forward. While the animation is lovely, I am unsure how to set the correct initial state or to force a sysnc of the animation with the actual time. My gut tells me that eventually, the animation will fall out of sync, but that could be a false assumption.

The left circle in the demo is synced every 500ms with your time, the right is a CSS animation that draws a circle nicely over 60 seconds.

function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
  var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;
  return {
    x: centerX + (radius * Math.cos(angleInRadians)),
    y: centerY + (radius * Math.sin(angleInRadians))
  };
}

function describeArc(x, y, radius, startAngle, endAngle){
    var start = polarToCartesian(x, y, radius, endAngle);
    var end = polarToCartesian(x, y, radius, startAngle);
    var arcSweep = endAngle - startAngle <= 180 ? "0" : "1";

    var d = [
        "M", start.x, start.y, 
        "A", radius, radius, 0, arcSweep, 0, end.x, end.y
    ].join(" ");

    return d;       
}

var arc = document.getElementById("arc1");

setInterval(function(){
  var sec = new Date().getSeconds();
  var deg = 6 * sec;
  arc.setAttribute("d", describeArc(60, 60, 50, 0, deg));
}, 500 );
svg {
  height: 200px;
  width: 200px;
}

@keyframes dash {
  from { stroke-dashoffset: -314; }
  to { stroke-dashoffset: -0; }
}

#arc2 {
  stroke-dasharray: 314;
  stroke-dashoffset: -314;
  animation: dash 60s linear infinite;
}
<svg>
  <path id="arc1" fill="none" stroke="#446688" stroke-width="20" />
</svg>

<svg>
  <path id="arc2" class="path" fill="none" stroke="#446688" stroke-width="20" d="M 60 10 a 50 50 0 1 0 0.001 0"></path>
</svg>
Community
  • 1
  • 1
JonSG
  • 10,542
  • 2
  • 25
  • 36
  • There is no need to go to this amount of effort. Just use stroke-dashpattern/stroke-dashoffset. – Paul LeBeau Jun 12 '16 at 06:04
  • @PaulLeBeau, while a css only solution is clean and simple, is it possible to set in to the proper time and/or not have it fall out of sync if this is for a "clock"? Not that setInterval should be used to directly set the "clock" either, but say to check the time every 100ms and use the time to set the clock animation. I'll add a css only version as well, but I am not sure how to properly set the initial time or keep it in sync. If you wanted to edit what I have feel free. – JonSG Jun 12 '16 at 17:45
0

Here's how to make a circular countdown graph using SVG.

We draw the graph using a dash pattern on a circle. We calculate the length the dash has to be to represent the correct number of seconds and then set the dash based on that.

The only slightly non-obvious thing we have to do is rotate the circle 90 degrees anti-clockwise. This is because in SVG circles, the dash pattern is defined to start at the 3 o'clock position.

function setCounter(id, value, max)
{
  var elem = document.getElementById(id);
  // Get the radius ("r" attribute)
  var radius = elem.r.baseVal.value;
  // Calculate the circumference of the circle
  var circumference = radius * 2 * Math.PI;
  // How long the bar has to be
  var barLength = value * circumference / max;

  // Set a dash pattern for the stroke.
  // The dash pattern consists of a dash of the right length,
  // followed by a gap big enough to ensure that we don't see the next dash.
  elem.setAttribute("stroke-dasharray", barLength + " " + circumference);
}
  
  
var  secondCount = 60;
setCounter("seconds", secondCount, 60);

// Set an interval timer to decrement the count and redraw the graph every second
window.setInterval(function() {
    secondCount--;
    if (secondCount < 0) secondCount = 59;
    setCounter("seconds", secondCount, 60);
  }, 1000);
<svg width="300px" height="300px" viewBox="0 0 300 300">
  <g fill="none" stroke-width="20">
    <circle cx="150" cy="150" r="100" stroke="#ccc"/>
    <circle id="seconds" cx="150" cy="150" r="100" stroke="dodgerblue" transform="rotate(-90 150 150)"/>
  </g>
</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181