property.eta 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. <% layout("/en/panel/stations/history/layout", { title: it.meteostanica.name }) %>
  2. <%~ include("/en/panel/partials/navbar") %>
  3. <% const backIcon = `
  4. <svg class="icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
  5. <path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m12 19l-7-7l7-7m7 7H5" />
  6. </svg>
  7. ` %>
  8. <%~ include("/en/panel/stations/partials/details", { meteostanica: it.meteostanica }) %>
  9. <div class="container-row">
  10. <a role="button" href="/en/panel/stations/<%= it.meteostanica.id %>/history"><%~ backIcon %></a>
  11. <h2><%~ it?.lang?.stations?.history.properties?.[it?.property]() %></h2>
  12. </div>
  13. <div class="historyLinks">
  14. <a role="button" href="/en/panel/stations/<%= it.meteostanica.id %>/history/<%= it.property %>/daily">daily</a>
  15. <a role="button" href="/en/panel/stations/<%= it.meteostanica.id %>/history/<%= it.property %>/monthly">monthly</a>
  16. <a role="button" href="/en/panel/stations/<%= it.meteostanica.id %>/history/<%= it.property %>/yearly">yearly</a>
  17. <a role="button" href="/en/panel/stations/<%= it.meteostanica.id %>/history/<%= it.property %>/allTime">all time</a>
  18. </div>
  19. <% if (it.data?.[0]) { %>
  20. <% if (it?.dateMap?.years) { %>
  21. <form id="historyForm">
  22. <% if (it?.dateMap?.days) { %>
  23. <div>
  24. <label for="day">day</label>
  25. <select id="day" name="day">
  26. <% for (const item of it?.dateMap?.days) { %>
  27. <option value="<%= item %>" <%= item === it?.selected?.day ? `selected` : `` %> ><%= item %></option>
  28. <% } %>
  29. </select>
  30. </div>
  31. <% } %>
  32. <% if (it?.dateMap?.months) { %>
  33. <div>
  34. <label for="month">month</label>
  35. <select id="month" name="month">
  36. <% for (const item of it?.dateMap?.months) { %>
  37. <option value="<%= item %>" <%= item === it?.selected?.month ? `selected` : `` %> > <%= it?.lang?.general.dateFormats.months?.[item]() %></option>
  38. <% } %>
  39. </select>
  40. </div>
  41. <% } %>
  42. <div>
  43. <label for="year">year</label>
  44. <select id="year" name="year">
  45. <% for (const item of it?.dateMap?.years) { %>
  46. <option value="<%= item %>" <%= item === it?.selected?.year ? `selected` : `` %> > <%= item %></option>
  47. <% } %>
  48. </select>
  49. </div>
  50. <button type="submit">load</button>
  51. </form>
  52. <% } %>
  53. <% const time = [] %>
  54. <% const data = [] %>
  55. <% for (const item of it.data) { %>
  56. <% time.push(item.timeMark) %>
  57. <% if (it.property === "outdoorConnected") {%>
  58. <% data.push(item.value) %>
  59. <% continue %>
  60. <% } %>
  61. <% data.push(item.value / 100) %>
  62. <% } %>
  63. <div>
  64. <canvas id="historyChart"></canvas>
  65. </div>
  66. <script>
  67. const dateMap = <%~ JSON.stringify(it?.dateMap.raw, null, 2) %>
  68. const monthLang = <%~ serializeToCode(it?.lang?.general.dateFormats.months) %>
  69. const daySelect = document.querySelector("#historyForm select#day")
  70. const monthSelect = document.querySelector("#historyForm select#month")
  71. const yearSelect = document.querySelector("#historyForm select#year")
  72. if (monthSelect) {
  73. monthSelect.addEventListener('change', resetHistoryForm)
  74. }
  75. if (yearSelect) {
  76. yearSelect.addEventListener('change', resetHistoryForm)
  77. }
  78. function resetHistoryForm(e) {
  79. daySelect.textContent = ''
  80. if (e.target.id === "year") monthSelect.textContent = ''
  81. const years = Object.keys(dateMap)
  82. const selectedYear = years.find(i => i === yearSelect.value) ?? years[years.length - 1]
  83. const months = Object.keys(dateMap[selectedYear])
  84. const selectedMonth = months.find(i => i === monthSelect.value) ?? months[months.length - 1]
  85. const days = dateMap[selectedYear][selectedMonth]
  86. if (daySelect) {
  87. for (const day of days) {
  88. const option = document.createElement('option')
  89. option.textContent = day
  90. option.value = day
  91. daySelect.append(option)
  92. }
  93. }
  94. if (monthSelect) {
  95. if (e.target.id === "year") {
  96. for (const [key, value] of Object.entries(months)) {
  97. const option = document.createElement('option')
  98. option.textContent = monthLang[key]()
  99. option.value = key
  100. monthSelect.append(option)
  101. }
  102. }
  103. }
  104. }
  105. const ctx = document.querySelector('#historyChart');
  106. new Chart(ctx, {
  107. type: 'bar',
  108. data: {
  109. labels: <%~ JSON.stringify(time, null, 2) %>,
  110. datasets: [{
  111. label: `<%= it.property %>`,
  112. data: <%~ JSON.stringify(data, null, 2) %>,
  113. borderWidth: 1
  114. }]
  115. },
  116. options: {
  117. scales: {
  118. y: {
  119. beginAtZero: true
  120. }
  121. }
  122. }
  123. });
  124. </script>
  125. <% } else { %>
  126. <div id="mainStats">
  127. <p>no data :( send some using your websocket key above.</p>
  128. </div>
  129. <% } %>
  130. <% function serializeToCode(obj) { %>
  131. <% // Handle null/primitive types %>
  132. <% if (obj === null) return 'null'; %>
  133. <% if (typeof obj === 'string') return `'${obj.replace(/'/g, "\\'")}'`; %>
  134. <% if (typeof obj !== 'object') return obj.toString(); %>
  135. <% // Handle Arrays %>
  136. <% if (Array.isArray(obj)) { %>
  137. <% return `[${obj.map(item => serializeToCode(item)).join(',')}]`; %>
  138. <% } %>
  139. <% // Handle Objects %>
  140. <% const entries = Object.entries(obj).map(([key, value]) => { %>
  141. <% // Ensure keys are safe (quoted if they contain special characters) %>
  142. <% const safeKey = /^[a-z$_][a-z0-9$_]*$/i.test(key) ? key : `'${key}'`; %>
  143. <% return `${safeKey}: ${serializeToCode(value)}`; %>
  144. <% }); %>
  145. <% return `{${entries.join(',')}}`; %>
  146. <% } %>