App for tracking weeks passed in an average lifespan

Below is and chart in which each box corresponds to one week in an average 88-year lifespan, and every filled-in box is one that’s already been lived. This idea came from an article that I will link to down below.

I’m super confident that I can build out these boxes in HTML and CSS, however I’m wondering how I would automate this process with JavaScript so that every passing week from the date of my birth would automatically swap out the image of the next blank box for one that is filled-in.

Any thoughts on this?

Here’s the inspiration for this project

1 Like

So what I would do is:
1: Render the field of empty boxes with HTML
2: Have Javascript figure out the number of weeks since my birth. Ignoring leap-seconds, this is a simple calculation of the number of seconds between now and a fixed date, both of which can be rendered as a timestamp , and then dividing by 604800, and probably flooring the result (or rounding, take your pick)
3: For i = 0, i < number of weeks, i++, color in a box. (The mechanism for doing this depends a little bit on whether you use images or CSS, so… probably best to make a design decision there first!

3 Likes

Hi @CooKachoo , you can get the date of death by setting the year to 88 from the date of birth… e.g.:

const birth = new Date('1980-07-20')
const death = new Date(birth.getTime())

death.setFullYear(birth.getFullYear() + 88)

To get the difference (in ms), date objects can be added and subtracted like numbers:

const now = new Date()
const passed = now - birth
const remaining = death - now

Here’s a pen with a simple text output:

Edit: Oops sorry @m_hutley I didn’t realise you already answered… I had left the tab open for a while. ^^

3 Likes

I like that you phrase it as “weeks left to chill”, when the original article is about using the chart to avoid procrastinating :stuck_out_tongue:

4 Likes

You could use CSS grid to build the boxes roughly like this at 52 per row:

You still have to connect the dots between the JS and the html but there should be enough clues to attempt this now :slight_smile:

4 Likes

Another excellent disscussion thank you so much everyone.

3 Likes

I’ve added some JS to fill the boxes, letting us use setTimeout to give a visual depiction of the weeks being filled out disturbingly rapidly.

First, have HAML only show all the boxes as not being filled, so that JS can fill them instead:

<div class="wrap">
- (1...4591).each do |i|
  %div{:class => "box" }
</div>

Then, use the array every method to go through every array item until the condition isn’t met.

const currentWeeks = 3576;
const delay = 0; // try 0 to 5
const boxes = document.querySelectorAll("div.box");
Array.from(boxes).every(function (box, week) {
  setInterval(function () {
    boxes[week].classList.add("filled");
  }, delay * week);
  return week <= currentWeeks;
});

This works without the setInterval too, but with it there delay can help to achieve different speeds of the weeks being filled out.

2 Likes

That’s clever, I guess you could similarly use find (every reads better though)

['a','b','c','d','e','f','g','h']
  .find((elem, i) => (console.log(elem), i === 5))
// a, b, c, d, e, f
2 Likes

Agreed. Though find works, the some array method is equivalent to an OR operation that keeps on processing until it gets a truthy value, and the every method is equivalent to an AND operation that keeps on processing while it continues to get truthy values.

2 Likes
<!DOCTYPE HTML>
<html lang="en">
<head>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width,height=device-height,initial-scale=1">

<title>Past and Future</title>

<!--
The internal CSS should be transferred to an external file
 <link rel="stylesheet" href="screen.css" media="screen">
-->

<style media="screen">
body {
    background-color: #f0f0f0;
    font: normal 1em / 1.62em sans-serif;
 } 
#info {
 	text-align: center;
 }
#info input {
 	width: 6em;
 	margin-bottom: 0.5em;
 }
noscript {
 	font-size:2em;
 	text-align: center;
 	text-transform: capitalize;
 }
table {
 	margin:auto;
 	background-color: #fff;
 }
td {
	padding:0.25em;
	border: 1px solid #333;
 }
.past{
	background-color: #999;
 }
</style>

</head>
<body>
	
 <div id="info" hidden>
  <label for="past"> your past: </label>
  <input type="text" id="past">
  <label for="future"> your future: </label>
  <input type="text" id="future">
 </div>

 <noscript>
  <p>This project requires  JavaScript</p>
 </noscript>

<script>
(function(d) {
   'use strict';

/* allow for javaScript being enabled */

    d.querySelector('#info').hidden='';

/* trs equates to hopeful life span in years */

    var trs = 88, tds = 52, c, i, tr, td,
	    tbl = d.createElement('table'),

        birth = '2000,1,1', /*  yyyy, mm, dd - adjust this value to suit  birth date */

        then, now, weeks, fill;

/* build table */

	for ( c = 0; c < trs; c ++ ){
		  tr = d.createElement('tr');
	for ( i = 0; i < tds; i ++ ) {
		  td = d.createElement('td');
		  tr.appendChild(td);
		}
		tbl.appendChild(tr);

	}

/* append the table to the HTML  */

		d.body.insertBefore(tbl, d.querySelector('noscript'));

/* create the weeks - 88 years = 4576 weeks -  (approximately ) trs x tds */

		then = new Date(birth).getTime(); /* day of birth */
		 now = new Date().getTime();       /* today */
	   weeks = Math.floor( Math.abs( then - now )/( 1000*60*60*24*7 ));

		d.querySelector('#past').value = weeks + ' weeks'; 
		d.querySelector('#future').value= trs*tds - weeks + ' weeks';		

/* colour the weeks past */

	fill = d.querySelectorAll('td');	

	for ( c = 0; c < weeks; c ++ ){
		  fill[c].classList.add('past');
	}			
}(document));
</script>  

</body>
</html>

… and let the devil take the hindmost. :rofl:

coothead

3 Likes

p.s.
If you just want to match your posted image, then
use the 18th to 24th October, 1993 for the date. :biggrin:

coothead

2 Likes

Thank you everyone. I appreciate the help and the code samples!

1 Like

Can you explain to me what’s happening here?

1 Like

That is an HAML loop. I modified what @PaulOB had done.

It seems to be better than having an endlessly scrolling repeat of the following:

<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
3 Likes