changeset 13:4eaa9d69c4e2

Extremely basic version of the graph drawer.
author Paul Fisher <paul@pfish.zone>
date Sun, 06 Oct 2019 17:09:23 -0400
parents 9e6289598d8c
children dd77a7ee02c1
files weather_server/static/script.js weather_server/static/style.css weather_server/templates/location.html
diffstat 3 files changed, 119 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/weather_server/static/script.js	Sun Oct 06 15:21:03 2019 -0400
+++ b/weather_server/static/script.js	Sun Oct 06 17:09:23 2019 -0400
@@ -35,8 +35,73 @@
     return MAGNUS_C * gamma / (MAGNUS_B - gamma);
 }
 
+const HISTORY_SECONDS = 86400;
+
+/**
+ * Sets up everything.
+ * @param {HTMLElement} tempElement The element where temperature data is.
+ * @param {HTMLElement} dewPointElement The element where the dew point is.
+ */
+async function setUp(tempElement, dewPointElement) {
+    const nowTS = new Date().getTime() / 1000;
+    const startTS = nowTS - HISTORY_SECONDS;
+    const query = new URL(location.href);
+    query.pathname = query.pathname + '/recent';
+    query.search = '';
+    query.searchParams.set('seconds', String(HISTORY_SECONDS));
+    const results = await fetch(query.href);
+    if (!results.ok) return;
+    const data = await results.json();
+    if (data.length === 0) return;
+
+    const tempsF = data.map(s => [s.sample_time, cToF(s.temp_c)]);
+    const dewPointsF = data.map(
+        s => [s.sample_time, cToF(dewPointC(s.temp_c, s.rh_pct))]);
+    setUpElement(tempElement, [startTS, nowTS], tempsF);
+    setUpElement(dewPointElement, [startTS, nowTS], dewPointsF);
+}
+
+/**
+ * Sets up charting for this element.
+ * @param {HTMLElement} element The element to put a graph in.
+ * @param {[number, number]} timeRange The `[start, end]` of the time range.
+ * @param {[number, number][]} data The data to chart.
+ */
+function setUpElement(element, timeRange, data) {
+    element.insertBefore(document.createElement('canvas'), element.firstChild);
+    element.classList.remove('plain');
+    element.classList.add('fancy');
+    const doDraw = () => redrawCanvas(element, data, timeRange);
+    doDraw();
+    addEventListener('resize', doDraw);
+}
+
+/**
+ *
+ * @param {HTMLElement} element The parent element to put the `<canvas>` in.
+ * @param {[number, number][]} data The data to chart.
+ * @param {[number, number]} xRange The `[start, end]` of the X range to plot.
+ */
+function redrawCanvas(element, data, xRange) {
+    let canvas = element.getElementsByTagName('canvas')[0];
+    if (!canvas) {
+        canvas = document.createElement('canvas');
+        element.insertBefore(canvas, element.firstChild);
+    }
+    const dpr = window.devicePixelRatio || 1;
+    const cssSize = element.getBoundingClientRect();
+    const pxSize = [cssSize.width * dpr, cssSize.height * dpr];
+    canvas.width = pxSize[0];
+    canvas.height = pxSize[1];
+    const ctx = canvas.getContext('2d');
+    ctx.clearRect(0, 0, pxSize[0], pxSize[1]);
+    const computed = getComputedStyle(element);
+    ctx.strokeStyle = computed.color;
+    drawChart(ctx, data, xRange, pxSize);
+}
+
 /** The height of the chart in degrees. */
-const CHART_HEIGHT = 15;
+const CHART_RANGE_DEGREES = 15;
 
 /**
  * Charts some data.
@@ -76,14 +141,14 @@
     // of the chart.
 
     // If the middle of the range is already close enough, just use that.
-    if (CHART_HEIGHT / 4 <= Math.abs(yMid - lastY)) {
-        return [yMid - CHART_HEIGHT / 2, yMid + CHART_HEIGHT / 2];
+    if (CHART_RANGE_DEGREES / 4 <= Math.abs(yMid - lastY)) {
+        return [yMid - CHART_RANGE_DEGREES / 2, yMid + CHART_RANGE_DEGREES / 2];
     }
     // Otherwise, clamp the chart range.
     if (lastY < yMid) {
-        return [lastY - CHART_HEIGHT / 4, lastY + 3 * CHART_HEIGHT / 4];
+        return [lastY - CHART_RANGE_DEGREES / 4, lastY + 3 * CHART_RANGE_DEGREES / 4];
     }
-    return [lastY - 3 * CHART_HEIGHT / 4, lastY + CHART_HEIGHT / 4];
+    return [lastY - 3 * CHART_RANGE_DEGREES / 4, lastY + CHART_RANGE_DEGREES / 4];
 }
 
 /**
--- a/weather_server/static/style.css	Sun Oct 06 15:21:03 2019 -0400
+++ b/weather_server/static/style.css	Sun Oct 06 17:09:23 2019 -0400
@@ -1,12 +1,24 @@
-html, body {
+html {
+    margin: 0;
+    padding: 0;
+    height: 100%;
+    width: 100%;
+
+    font-family: Roboto, sans-serif;
+
+    --temp-background: #0d47a1;
+    --temp-text: white;
+    --dewpoint-background: #5472d3;
+    --dewpoint-text: white;
+}
+
+body {
     margin: 0;
     padding: 0;
     display: flex;
     flex-flow: column nowrap;
     width: 100%;
     height: 100%;
-
-    font-family: Roboto, sans-serif;
 }
 
 h1 {
@@ -35,6 +47,9 @@
     padding: 0;
     font: inherit;
     flex: auto;
+}
+
+p.plain {
     position: relative;
     display: flex;
     flex-direction: column;
@@ -43,34 +58,49 @@
     line-height: 1;
 }
 
-p.important .key {
+p.plain.important .key {
     display: block;
     opacity: 75%;
     font-size: 18px;
 }
 
-p.important .value {
+p.plain.important .value {
     margin-top: 0;
     font-size: 150px;
     display: flex;
     flex-flow: row nowrap;
 }
 
-p.important .value .unit {
+p.plain.important .value .unit {
     font-size: 33%;
     font-weight: bold;
     opacity: 66%;
     padding-top: 0.25em;
 }
 
+p.fancy {
+    position: relative;
+}
+
+p.fancy canvas {
+    display: block;
+    position: absolute;
+    top: 0;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+}
+
 #temp {
-    background: #0d47a1;
-    color: white;
+    background: var(--temp-background);
+    color: var(--temp-text);
 }
 
 #dewpoint {
-    background: #5472d3;
-    color: white;
+    background: var(--dewpoint-background);
+    color: var(--dewpoint-text);
 }
 
 #timestamp {
--- a/weather_server/templates/location.html	Sun Oct 06 15:21:03 2019 -0400
+++ b/weather_server/templates/location.html	Sun Oct 06 17:09:23 2019 -0400
@@ -10,7 +10,7 @@
     <body>
         <h1><span>{{ location.name }} conditions</span></h1>
         {% if last_reading %}
-            <p class="important" id="temp">
+            <p class="plain important" id="temp">
                 <span class="key">Temperature</span>
                 <span class="value">
                     <span class="pad"> </span>
@@ -20,7 +20,7 @@
                     <span class="unit">&deg;F</span>
                 </span>
             </p>
-            <p class="important" id="dewpoint">
+            <p class="plain important" id="dewpoint">
                 <span class="key">Dew point</span>
                 <span class="value">
                     <span class="pad"> </span>
@@ -40,5 +40,12 @@
             <p id="big-question-mark">?</p>
         {% endif %}
         <script src="{{ url_for('static', filename='script.js') }}"></script>
+        <!--
+            <script>
+                setUp(
+                    document.getElementById('temp'),
+                    document.getElementById('dewpoint'));
+            </script>
+        -->
     </body>
 </html>