Mercurial > hg > index.fcgi > www > www-1
diff life_calendar/index.html @ 81:256b8df1c686
add life_calendar
author | paulo |
---|---|
date | Fri, 17 Jun 2016 22:24:17 -0700 |
parents | |
children | a0fdf2cf1d53 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/life_calendar/index.html Fri Jun 17 22:24:17 2016 -0700 1.3 @@ -0,0 +1,386 @@ 1.4 +<html> 1.5 + <head> 1.6 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 1.7 + <title>Life Calendar</title> 1.8 + <style type="text/css"> 1.9 + body { 1.10 + padding: 0; 1.11 + margin: 0; 1.12 + position: relative; 1.13 + font-family: sans-serif; 1.14 + background-size: cover; 1.15 + } 1.16 + 1.17 + a, a:visited { 1.18 + color: #70BCF9; 1.19 + } 1.20 + 1.21 + table { 1.22 + width: 100%; 1.23 + height: 100%; 1.24 + } 1.25 + 1.26 + table, td { 1.27 + border: 1px solid; 1.28 + border-collapse: collapse; 1.29 + padding: 0; 1.30 + margin: 0; 1.31 + } 1.32 + 1.33 + div#welcome { 1.34 + display: none; 1.35 + 1.36 + width: 50vw; 1.37 + margin: 8vh auto 0; 1.38 + } 1.39 + 1.40 + div#welcome h1 { 1.41 + text-align: center; 1.42 + text-transform: uppercase; 1.43 + font-family: serif; 1.44 + font-size: 4em; 1.45 + } 1.46 + div#welcome form { 1.47 + border: 1px solid #999999; 1.48 + padding: 10px 20px; 1.49 + } 1.50 + 1.51 + div#welcome .settings { 1.52 + margin-left: 5px; 1.53 + padding: 5px; 1.54 + } 1.55 + 1.56 + div#welcome div#footer { 1.57 + color: #a6a6a6; 1.58 + padding-top: 50px; 1.59 + text-align: center; 1.60 + } 1.61 + 1.62 + #settingsForm span.unhappyMessage { 1.63 + font-size: 0.8em; 1.64 + padding-left: 10px; 1.65 + } 1.66 + 1.67 + div#tooltip { 1.68 + background-color: #5070D0; 1.69 + padding: 0.5em; 1.70 + } 1.71 + 1.72 + div#tooltip h1 { 1.73 + color: #DFDFDF; 1.74 + font-size: 1.25em; 1.75 + margin: 1px; 1.76 + } 1.77 + 1.78 + div#tooltip h2 { 1.79 + color: #AAAAAA; 1.80 + font-size: 0.75em; 1.81 + font-weight: normal; 1.82 + margin: 1px; 1.83 + } 1.84 + 1.85 + td { 1.86 + border-color: #FFFFFF; 1.87 + } 1.88 + 1.89 + table { 1.90 + border-color: #FFFFFF; 1.91 + } 1.92 + 1.93 + tr.previous td { 1.94 + background-color: #BBBBBB; 1.95 + } 1.96 + 1.97 + tr.current td.partial { 1.98 + background-color: #CCDDCC; 1.99 + } 1.100 + 1.101 + tr.current td.today { 1.102 + background-color: #DDDDCC; 1.103 + } 1.104 + 1.105 + tr.current td.future { 1.106 + background-color: #DDCCCC; 1.107 + } 1.108 + 1.109 + tr.future { 1.110 + background-color: #DDDDDD; 1.111 + } 1.112 + 1.113 + </style> 1.114 + <script src="jquery-2.1.3.min.js"></script> 1.115 + <script src="happy.js"></script> 1.116 + <script src="tooltip.js"></script> 1.117 + 1.118 + <script type="text/javascript"> 1.119 + var nWeeks = 52; 1.120 + var nMsPerDay = 3600 * 24 * 1000; 1.121 + var nMsPerWeek = 7 * nMsPerDay; 1.122 + var QSParams; 1.123 + 1.124 + var birthday; 1.125 + var birthdayString; 1.126 + var birthdayDate; 1.127 + 1.128 + var lifespan; 1.129 + 1.130 + var age; 1.131 + var ageYears; 1.132 + var remainder; 1.133 + 1.134 + var previousYears; 1.135 + var futureYears; 1.136 + var remainderWeeks; 1.137 + var restOfYearWeeks; 1.138 + 1.139 + function validateBirthday(birthday) { 1.140 + var birthdayPattern = /^[0-9]{4}-[0-9]{2}-[0-9]{2}$/; 1.141 + return birthdayPattern.test( $("#birthday").val()); 1.142 + } 1.143 + 1.144 + function validateLifespan(lifespan) { 1.145 + var lifespanPattern = /^[0-9]{1,3}$/; 1.146 + return lifespanPattern.test( $("#lifespan").val()); 1.147 + } 1.148 + 1.149 + // Read a page's GET URL variables and return them as an associative array. 1.150 + // From http://jquery-howto.blogspot.ca/2009/09/get-url-parameters-values-with-jquery.html 1.151 + function getQSParams() 1.152 + { 1.153 + var vars = [], hash; 1.154 + var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); 1.155 + for(var i = 0; i < hashes.length; i++) 1.156 + { 1.157 + hash = hashes[i].split('='); 1.158 + vars.push(hash[0]); 1.159 + vars[hash[0]] = hash[1]; 1.160 + } 1.161 + return vars; 1.162 + } 1.163 + 1.164 + function isLeapYear(year) { 1.165 + var d = new Date(year, 1, 28); 1.166 + d.setDate(d.getDate() + 1); 1.167 + return d.getMonth() == 1; 1.168 + } 1.169 + 1.170 + function getAge(date) { 1.171 + var d = new Date(date), now = new Date(); 1.172 + var years = now.getFullYear() - d.getFullYear(); 1.173 + d.setFullYear(d.getFullYear() + years); 1.174 + if (d > now) { 1.175 + years--; 1.176 + d.setFullYear(d.getFullYear() - 1); 1.177 + } 1.178 + var days = (now.getTime() - d.getTime()) / nMsPerDay; 1.179 + return years + days / (isLeapYear(now.getFullYear()) ? 366 : 365); 1.180 + } 1.181 + 1.182 + function getCalendar(d, week, year) { 1.183 + var c = new Date(d); 1.184 + c.setFullYear(d.getFullYear() + year); 1.185 + c.setTime(c.getTime() + (week * nMsPerWeek)); 1.186 + return c; 1.187 + } 1.188 + 1.189 + function getWeekYearCal(e, week) { 1.190 + var yearParent = e.parentNode; 1.191 + var calParent = yearParent.parentNode; 1.192 + var year; 1.193 + for (year = 0; year < calParent.childNodes.length; year++) { 1.194 + if (calParent.childNodes[year] === yearParent) { 1.195 + break; 1.196 + } 1.197 + } 1.198 + var cal = getCalendar(birthdayDate, week, year); 1.199 + return { 1.200 + week: week, 1.201 + year: year, 1.202 + cal: cal, 1.203 + } 1.204 + } 1.205 + 1.206 + function loop(x, f) { 1.207 + for (var i = 0; i < x; f(i++)); 1.208 + } 1.209 + 1.210 + function mapLoop(x, f) { 1.211 + var ret = []; 1.212 + for (var i = 0; i < x; i++) { 1.213 + ret.push(f(i)); 1.214 + } 1.215 + return ret; 1.216 + } 1.217 + 1.218 + function cycleColors(e) { 1.219 + var colors = [ 1.220 + undefined, 1.221 + "black", 1.222 + "red", 1.223 + "green", 1.224 + "blue", 1.225 + "white", 1.226 + ]; 1.227 + 1.228 + var i = 0; 1.229 + for (; i < colors.length, colors[i] != e._fill_color; i++); 1.230 + e._fill_color = colors[(i + 1) % colors.length]; 1.231 + if (e._fill_color != undefined) { 1.232 + e.setAttribute("style", "background-color: " + e._fill_color); 1.233 + } else { 1.234 + e.setAttribute("style", undefined); 1.235 + } 1.236 + } 1.237 + 1.238 + function _createElement(tagName, className) { 1.239 + var e = document.createElement(tagName); 1.240 + if (className) { 1.241 + e.className = className; 1.242 + } 1.243 + return e; 1.244 + } 1.245 + 1.246 + function weekElem(className) { 1.247 + return _createElement("td", className); 1.248 + } 1.249 + 1.250 + function yearElem(className) { 1.251 + return _createElement("tr", className); 1.252 + } 1.253 + 1.254 + function yearWeekElems() { 1.255 + return mapLoop(nWeeks, function(i) { 1.256 + var e = weekElem(); 1.257 + addWeekMouseEvents(e, i); 1.258 + return e; 1.259 + }); 1.260 + } 1.261 + 1.262 + function addWeekMouseEvents(e, i) { 1.263 + e.addEventListener("mouseover", function(evt) { 1.264 + var wyc = getWeekYearCal(e, i); 1.265 + var calYear = wyc.cal.getFullYear(); 1.266 + var calMonth = wyc.cal.getMonth() + 1; 1.267 + var calDay = wyc.cal.getDate(); 1.268 + createTooltip(evt, calYear + '-' + calMonth + '-' + calDay, "(Week: " + wyc.week + ", Year: " + wyc.year + ")"); 1.269 + }); 1.270 + e.addEventListener("click", function() { 1.271 + cycleColors(e); 1.272 + }); 1.273 + } 1.274 + 1.275 + $( document ).ready(function() { 1.276 + $( "#settingsForm" ).isHappy({ 1.277 + fields: { 1.278 + '#birthday': { 1.279 + required: true, 1.280 + test: validateBirthday, 1.281 + message: 'Please enter your birthday (like YYYY-MM-DD).' 1.282 + }, 1.283 + '#lifespan': { 1.284 + required: true, 1.285 + test: validateLifespan, 1.286 + message: 'Please enter your expected lifespan (like 90)' 1.287 + } 1.288 + } 1.289 + }); 1.290 + 1.291 + QSParams = getQSParams(); 1.292 + 1.293 + if(!("birthday" in QSParams) | !("lifespan" in QSParams)) { 1.294 + // Show the form 1.295 + $("#welcome").css("display", "block"); 1.296 + 1.297 + // Give the first field focus 1.298 + $("#birthday").focus(); 1.299 + return; 1.300 + } 1.301 + 1.302 + $("body").append( '<table id="calendar"></table>' ); 1.303 + 1.304 + birthday = QSParams["birthday"]; 1.305 + birthdayString = birthday + "T00:00:00"; 1.306 + birthdayDate = new Date(birthdayString); 1.307 + 1.308 + lifespan = QSParams["lifespan"]; 1.309 + 1.310 + age = getAge(birthdayDate); 1.311 + ageYears = Math.floor(age); 1.312 + remainder = age - ageYears; 1.313 + 1.314 + previousYears = (ageYears).toFixed(0); 1.315 + 1.316 + if( lifespan > ageYears) { 1.317 + futureYears = lifespan - ageYears - 1; 1.318 + remainderWeeks = Math.floor(remainder * nWeeks); 1.319 + restOfYearWeeks = Math.ceil(nWeeks - remainderWeeks) - 1; 1.320 + } else { 1.321 + futureYears = 0; 1.322 + remainderWeeks = nWeeks; 1.323 + restOfYearWeeks = 0; 1.324 + } 1.325 + 1.326 + // Fill in lived years 1.327 + loop(previousYears, function() { 1.328 + var tr = yearElem("previous"); 1.329 + $(tr).append(yearWeekElems()); 1.330 + $("#calendar").append(tr); 1.331 + }) 1.332 + 1.333 + // Fill in the current birth-year (the number of weeks elapsed since the most recent birthday.) 1.334 + var current_tr = yearElem("current"); 1.335 + loop(remainderWeeks, function(i) { 1.336 + var e = weekElem("partial"); 1.337 + addWeekMouseEvents(e, i); 1.338 + $(current_tr).append(e); 1.339 + }) 1.340 + var e = weekElem("today"); 1.341 + addWeekMouseEvents(e, remainderWeeks); 1.342 + $(current_tr).append(e); 1.343 + loop(restOfYearWeeks, function(i) { 1.344 + var e = weekElem("future"); 1.345 + addWeekMouseEvents(e, remainderWeeks + 1 + i); 1.346 + $(current_tr).append(e); 1.347 + }) 1.348 + $("#calendar").append(current_tr); 1.349 + 1.350 + // Fill in future years 1.351 + loop(futureYears, function() { 1.352 + var tr = yearElem("future"); 1.353 + $(tr).append(yearWeekElems()); 1.354 + $("#calendar").append(tr); 1.355 + }) 1.356 + }); 1.357 + </script> 1.358 + </head> 1.359 + <body> 1.360 + <div id="welcome"> 1.361 + <h1>Life Calendar</h1> 1.362 + <p> 1.363 + A minimalist life calendar. Shows the number of weeks you've lived and the number of weeks you 1.364 + have left. 1.365 + </p> 1.366 + <form method="get" action="" id="settingsForm"> 1.367 + <p> 1.368 + <label for="birthday">Birthday: 1.369 + <input class="settings" id="birthday" name="birthday" placeholder="1985-01-01"/> 1.370 + </label> 1.371 + </p> 1.372 + <p> 1.373 + <label for="lifespan">Life expectancy: 1.374 + <input class="settings" id="lifespan" name="lifespan" placeholder="90"/> 1.375 + </label> 1.376 + </p> 1.377 + <p> 1.378 + <input type="submit" id="submit" value="Show calendar" /> 1.379 + </p> 1.380 + </form> 1.381 + <div id="footer"> 1.382 + <p> 1.383 + Based on <a href="http://waitbutwhy.com/2014/05/life-weeks.html">Your Life in Weeks</a> 1.384 + and <a href="http://count.life">count.life</a>. 1.385 + </p> 1.386 + </div> 1.387 + </div> 1.388 + </body> 1.389 +</html>