Mercurial > personal > weather-server
view weather_server/static/script.js @ 12:9e6289598d8c
Add script to draw charts with initial functions.
author | Paul Fisher <paul@pfish.zone> |
---|---|
date | Sun, 06 Oct 2019 15:21:03 -0400 |
parents | |
children | 4eaa9d69c4e2 |
line wrap: on
line source
'use strict'; /** * Converts Celsius to Fahrenheit. * @param {number} tempC * @return {number} The temperature in Fahrenheit. */ function cToF(tempC) { return tempC * 9 / 5 + 32; } const MAGNUS_B = 17.62; const MAGNUS_C = 243.12; /** * The gamma function to calculate dew point. * * @param {number} tempC The temperature, in degrees Celsius. * @param {number} rhPct The relative humidity, in percent. * @return {number} The value of the gamma function. */ function gammaFn(tempC, rhPct) { return Math.log(rhPct / 100) + MAGNUS_B * tempC / (MAGNUS_C + tempC); } /** * Calculates the dew point. * * @param {number} tempC The temperature, in degrees Celsius. * @param {number} rhPct The relative humidity, in percent. * @return {number} The dew point, in degrees Celsius. */ function dewPointC(tempC, rhPct) { const gamma = gammaFn(tempC, rhPct); return MAGNUS_C * gamma / (MAGNUS_B - gamma); } /** The height of the chart in degrees. */ const CHART_HEIGHT = 15; /** * Charts some data. * * @param {CanvasRenderingContext2D} ctx The context to draw in. * @param {[number, number][]} data The data to chart, as `[x, y]` pairs. * @param {[number, number]} xRange The bounds of the X axis to draw. * @param {[number, number]} size The `[width, height]` of the context. */ function drawChart(ctx, data, xRange, size) { const yRange = calculateYRange(data.map(d => d[1])); ctx.lineWidth = 1.5; ctx.beginPath(); const first = project(data[0], size, xRange, yRange); ctx.moveTo(...first); for (const pt of data) { const projected = project(pt, size, xRange, yRange); ctx.lineTo(...projected); } ctx.stroke(); } /** * Determines what the Y range of the chart should be. * @param {number[]} ys The Y values of the chart. * @return {[number, number]} The lowest and highest values of the range. */ function calculateYRange(ys) { const yMax = Math.max(...ys); const yMin = Math.min(...ys); const yMid = (yMin + yMax) / 2; const lastY = ys[ys.length - 1]; // We want the last value to be, at most, at the top or bottom 1/4 line // 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]; } // Otherwise, clamp the chart range. if (lastY < yMid) { return [lastY - CHART_HEIGHT / 4, lastY + 3 * CHART_HEIGHT / 4]; } return [lastY - 3 * CHART_HEIGHT / 4, lastY + CHART_HEIGHT / 4]; } /** * Projects a Cartesian coordinate into Canvas space. * * @param {[number, number]} coord The `[x, y]` coordinate to project. * @param {[number, number]} size The `[width, height]` of the context. * @param {[number, number]} xRange The range of X values in the context. * @param {[number, number]} yRange The range of Y values in the context. * @return {[number, number]} The `[x, y]` coordinate in Canvas space. */ function project(coord, size, xRange, yRange) { const [x, y] = coord; const [xMin, xMax] = xRange; const xSpan = xMax - xMin; const [yMin, yMax] = yRange; const ySpan = yMax - yMin; const [xSize, ySize] = size; return [ (x - xMin) / xSpan * xSize, (yMax- y) / ySpan * ySize, ] }