index.html 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. <html>
  2. <head>
  3. <script>
  4. var dataset;
  5. function initDataset() {
  6. dataset = new vis.DataSet({queue: true});
  7. }
  8. // Bed
  9. function importRssFeed (feedUrl) {
  10. var rssRequest = new XMLHttpRequest();
  11. rssRequest.onreadystatechange = function (e) {
  12. var r = rssRequest;
  13. if (r.readyState == XMLHttpRequest.DONE) {
  14. if (r.status >= 200 && r.status < 300) {
  15. console.log("Got RSS (" + r.status + "): ");
  16. var items = importRSSDoc(r.responseXML);
  17. populateItems( items );
  18. createPlot( items );
  19. importTvFeed( "https://harlanji.com/tv.xml" );
  20. }
  21. }
  22. };
  23. //rssRequest.open("GET", "bed-harlanji.xml");
  24. rssRequest.open("GET", feedUrl);
  25. rssRequest.send();
  26. }
  27. function importRSSDoc( rssDoc ) {
  28. console.log("importRSSDoc:");
  29. console.log( rssDoc );
  30. var feedLink = rssDoc.querySelector("link").textContent.trim();
  31. console.log("bed feed link = " + feedLink);
  32. //var author = rssDoc.querySelector("generator").textContent.trim();
  33. var items = Array.from( rssDoc.querySelectorAll("item") );
  34. items = items.map(function (i) {
  35. var item = {
  36. title: i.querySelector("title").textContent.trim(),
  37. date: new Date( i.querySelector("pubDate").textContent.trim() ),
  38. description: i.querySelector("description").textContent.trim(),
  39. link: i.querySelector("link").textContent.trim(),
  40. feedLink: feedLink
  41. };
  42. var occurenceParts = splitString( item.description, ":", 2);
  43. item.occurence = parseInt( occurenceParts[0] ) || 1;
  44. item.occurenceNote = occurenceParts[1].trim();
  45. if (item.occurenceNote == "") {
  46. item.occurenceNote = "Morning routine";
  47. }
  48. return item;
  49. });
  50. items = items.sort(function (a, b) {
  51. return b.date - a.date;
  52. });
  53. console.log("items:");
  54. console.log(items);
  55. return items;
  56. }
  57. function populateItems( items ) {
  58. console.log("populateItems");
  59. console.log( items );
  60. var rows = items.map(function (item) {
  61. var row = document.createElement( "tr" );
  62. var date = document.createElement( "td" );
  63. var occurence = document.createElement( "td" );
  64. var note = document.createElement( "td" );
  65. date.textContent = dateString( item.date );
  66. occurence.textContent = item.occurence;
  67. note.textContent = item.occurenceNote;
  68. row.appendChild( date );
  69. row.appendChild( occurence );
  70. row.appendChild( note );
  71. return row;
  72. });
  73. var tableBody = document.querySelector("#bed-makings tbody");
  74. console.log("populate: ");
  75. console.log(tableBody);
  76. console.log(rows);
  77. while (tableBody.lastChild) {
  78. tableBody.removeChild(tableBody.lastChild);
  79. }
  80. rows.forEach(function (row) {
  81. tableBody.appendChild(row);
  82. });
  83. }
  84. function createPlot ( feedItems ) {
  85. console.log("createPlot");
  86. var container = document.getElementById('visualization');
  87. while( container.lastChild ) {
  88. container.removeChild( container.lastChild );
  89. }
  90. var group = feedItems[0].feedLink == "https://harlanji.com/bed.xml" ? 0 : 10;
  91. var items = feedItems.map(function (item) {
  92. var startDate = startOfDay(item.date);
  93. return {
  94. id: item.feedLink + item.link,
  95. x: startDate,
  96. y: (item.date - startDate) / (1000 * 60),
  97. group: group
  98. };
  99. });
  100. // feed items are in descending order
  101. var firstDate = startOfDay( feedItems[ feedItems.length - 1 ].date );
  102. var lastDate = startOfDay( feedItems[ 0 ].date );
  103. var firstTimes = SunCalc.getTimes(firstDate, 44.986656, -93.258133)
  104. var lastTimes = SunCalc.getTimes(lastDate, 44.986656, -93.258133)
  105. if (!dataset.get("firstSunrise")) {
  106. items.push({id: 'firstSunrise',
  107. x: firstDate,
  108. y: (firstTimes.sunrise - firstDate) / (1000 * 60),
  109. group: 1});
  110. items.push({id: 'lastSunrise',
  111. x: lastDate,
  112. y: (lastTimes.sunrise - lastDate) / (1000 * 60),
  113. group: 1});
  114. }
  115. dataset.update(items);
  116. dataset.flush();
  117. var options = {
  118. sort: false,
  119. sampling:false,
  120. style:'points',
  121. dataAxis: {
  122. left: {
  123. range: {
  124. min: 0, max: (60 * 24)
  125. }
  126. }
  127. },
  128. drawPoints: {
  129. enabled: true,
  130. size: 6,
  131. style: 'circle' // square, circle
  132. },
  133. defaultGroup: 'Scatterplot',
  134. height: '400px',
  135. width: '90%'
  136. };
  137. var graph2d = new vis.Graph2d(container, dataset, options);
  138. var tomorrow = new Date();
  139. tomorrow.setDate(tomorrow.getDate() + 1);
  140. tomorrow = startOfDay(tomorrow);
  141. graph2d.setWindow(firstDate, tomorrow, {animation: false});
  142. }
  143. // TV
  144. function importTvFeed (feedUrl) {
  145. var rssRequest = new XMLHttpRequest();
  146. rssRequest.onreadystatechange = function (e) {
  147. var r = rssRequest;
  148. if (r.readyState == XMLHttpRequest.DONE) {
  149. if (r.status >= 200 && r.status < 300) {
  150. console.log("Got TV RSS (" + r.status + "): ");
  151. var items = importTvDoc(r.responseXML);
  152. addTvToPlot( items );
  153. }
  154. }
  155. };
  156. //rssRequest.open("GET", "bed-harlanji.xml");
  157. rssRequest.open("GET", feedUrl);
  158. rssRequest.send();
  159. }
  160. function importTvDoc( rssDoc ) {
  161. console.log("importTvDoc:");
  162. console.log( rssDoc );
  163. var feedLink = rssDoc.querySelector("link").textContent.trim();
  164. console.log("tv feed link = " + feedLink);
  165. var items = Array.from( rssDoc.querySelectorAll("item") );
  166. items = items.map(function (i) {
  167. var title = i.querySelector("title").textContent.trim();
  168. var state = title.indexOf("on") > -1;
  169. var item = {
  170. title: title,
  171. state: state,
  172. date: new Date( i.querySelector("pubDate").textContent.trim() ),
  173. description: i.querySelector("description").textContent.trim(),
  174. link: i.querySelector("link").textContent.trim(),
  175. feedLink: feedLink
  176. };
  177. return item;
  178. });
  179. items = items.sort(function (a, b) {
  180. return b.date - a.date;
  181. });
  182. console.log("tv items:");
  183. console.log(items);
  184. return items;
  185. }
  186. function dateString (date) {
  187. // return "d: " + date;
  188. var str = (date.getYear() + 1900) + "-"
  189. + new String(date.getMonth() + 1).padStart(2, "0") + "-"
  190. + new String(date.getDate()).padStart(2, "0") + " "
  191. + new String(date.getHours()).padStart(2, "0") + ":"
  192. + new String(date.getMinutes()).padStart(2, "0") + ":"
  193. + new String(date.getSeconds()).padStart(2, "0") + " ";
  194. var tzOffset = date.getTimezoneOffset() / 60;
  195. if (tzOffset >= 0) {
  196. str += "+";
  197. }
  198. str += new String(tzOffset * 100).padStart(4, "0");
  199. return str;
  200. }
  201. function addTvToPlot ( feedItems ) {
  202. console.log("addTvToPlot");
  203. var items = feedItems.map(function (item) {
  204. var startDate = startOfDay(item.date);
  205. var group = item.state ? 3 : 4;
  206. return {
  207. id: item.feedLink + item.link,
  208. x: startDate,
  209. y: (item.date - startDate) / (1000 * 60),
  210. group: group
  211. };
  212. });
  213. dataset.update( items );
  214. dataset.flush();
  215. }
  216. function splitString(string, delimiter, n) {
  217. var parts = string.split(delimiter);
  218. return parts.slice(0, n - 1).concat([parts.slice(n - 1).join(delimiter)]);
  219. }
  220. </script>
  221. <!--
  222. <script defer data-domain="cityapper.com" src="https://pa.cityapper.com/js/plausible.js"></script>
  223. -->
  224. <script src="vis-timeline-graph2d.min.js"></script>
  225. <link href="vis-timeline-graph2d.min.css" rel="stylesheet" type="text/css" />
  226. <script src="suncalc.js"></script>
  227. </head>
  228. <body>
  229. <script>
  230. function importAuthorSubmitted( form ) {
  231. console.log("submitted:");
  232. console.log(form);
  233. }
  234. var authors = {
  235. "HarlanJI": "https://harlanji.com/bed.xml",
  236. "Marty": "https://harlanji.com/bed-marty.xml"
  237. }
  238. function populateAuthors () {
  239. var authorsElem = document.querySelector("#author");
  240. while(authorsElem.lastChild) {
  241. authorsElem.removeChild(authorsElem.lastChild);
  242. }
  243. Object.entries(authors).forEach(function (e, i) {
  244. var option = document.createElement("option");
  245. option.value = e[1];
  246. option.textContent = e[0];
  247. if ( i == 0 ) {
  248. option.selected = "selected";
  249. }
  250. authorsElem.appendChild(option);
  251. console.log(e);
  252. });
  253. authorsElem.dispatchEvent(new Event('change'));
  254. }
  255. function startOfDay (date) {
  256. var startDate = new Date(date);
  257. startDate.setHours(0);
  258. startDate.setMinutes(0);
  259. startDate.setSeconds(0);
  260. startDate.setMilliseconds(0);
  261. return startDate;
  262. }
  263. </script>
  264. <h1>Author Made Bed</h1>
  265. <form id="import-author" action="#" onsubmit="console.log('s')">
  266. <p>
  267. Author:
  268. <select id="author" onchange="importRssFeed(this.options[this.selectedIndex].value)">
  269. </select>
  270. </p>
  271. </form>
  272. <div id="visualization"></div>
  273. <table id="bed-makings">
  274. <thead>
  275. <tr>
  276. <th>Date Time</th>
  277. <th>#</th>
  278. <th>Note</th>
  279. </tr>
  280. </thead>
  281. <tbody>
  282. </tbody>
  283. </table>
  284. <script>
  285. //importRssFeed( document.querySelector("#author").value );
  286. initDataset();
  287. populateAuthors();
  288. </script>
  289. </body>
  290. </html>