Mercurial > personal > weather-server
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">°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>