Mercurial > personal > weather-server
comparison 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 |
comparison
equal
deleted
inserted
replaced
11:52ef21607b31 | 12:9e6289598d8c |
---|---|
1 'use strict'; | |
2 | |
3 /** | |
4 * Converts Celsius to Fahrenheit. | |
5 * @param {number} tempC | |
6 * @return {number} The temperature in Fahrenheit. | |
7 */ | |
8 function cToF(tempC) { | |
9 return tempC * 9 / 5 + 32; | |
10 } | |
11 | |
12 const MAGNUS_B = 17.62; | |
13 const MAGNUS_C = 243.12; | |
14 | |
15 /** | |
16 * The gamma function to calculate dew point. | |
17 * | |
18 * @param {number} tempC The temperature, in degrees Celsius. | |
19 * @param {number} rhPct The relative humidity, in percent. | |
20 * @return {number} The value of the gamma function. | |
21 */ | |
22 function gammaFn(tempC, rhPct) { | |
23 return Math.log(rhPct / 100) + MAGNUS_B * tempC / (MAGNUS_C + tempC); | |
24 } | |
25 | |
26 /** | |
27 * Calculates the dew point. | |
28 * | |
29 * @param {number} tempC The temperature, in degrees Celsius. | |
30 * @param {number} rhPct The relative humidity, in percent. | |
31 * @return {number} The dew point, in degrees Celsius. | |
32 */ | |
33 function dewPointC(tempC, rhPct) { | |
34 const gamma = gammaFn(tempC, rhPct); | |
35 return MAGNUS_C * gamma / (MAGNUS_B - gamma); | |
36 } | |
37 | |
38 /** The height of the chart in degrees. */ | |
39 const CHART_HEIGHT = 15; | |
40 | |
41 /** | |
42 * Charts some data. | |
43 * | |
44 * @param {CanvasRenderingContext2D} ctx The context to draw in. | |
45 * @param {[number, number][]} data The data to chart, as `[x, y]` pairs. | |
46 * @param {[number, number]} xRange The bounds of the X axis to draw. | |
47 * @param {[number, number]} size The `[width, height]` of the context. | |
48 */ | |
49 function drawChart(ctx, data, xRange, size) { | |
50 const yRange = calculateYRange(data.map(d => d[1])); | |
51 | |
52 ctx.lineWidth = 1.5; | |
53 | |
54 ctx.beginPath(); | |
55 const first = project(data[0], size, xRange, yRange); | |
56 ctx.moveTo(...first); | |
57 for (const pt of data) { | |
58 const projected = project(pt, size, xRange, yRange); | |
59 ctx.lineTo(...projected); | |
60 } | |
61 ctx.stroke(); | |
62 } | |
63 | |
64 /** | |
65 * Determines what the Y range of the chart should be. | |
66 * @param {number[]} ys The Y values of the chart. | |
67 * @return {[number, number]} The lowest and highest values of the range. | |
68 */ | |
69 function calculateYRange(ys) { | |
70 const yMax = Math.max(...ys); | |
71 const yMin = Math.min(...ys); | |
72 const yMid = (yMin + yMax) / 2; | |
73 const lastY = ys[ys.length - 1]; | |
74 | |
75 // We want the last value to be, at most, at the top or bottom 1/4 line | |
76 // of the chart. | |
77 | |
78 // If the middle of the range is already close enough, just use that. | |
79 if (CHART_HEIGHT / 4 <= Math.abs(yMid - lastY)) { | |
80 return [yMid - CHART_HEIGHT / 2, yMid + CHART_HEIGHT / 2]; | |
81 } | |
82 // Otherwise, clamp the chart range. | |
83 if (lastY < yMid) { | |
84 return [lastY - CHART_HEIGHT / 4, lastY + 3 * CHART_HEIGHT / 4]; | |
85 } | |
86 return [lastY - 3 * CHART_HEIGHT / 4, lastY + CHART_HEIGHT / 4]; | |
87 } | |
88 | |
89 /** | |
90 * Projects a Cartesian coordinate into Canvas space. | |
91 * | |
92 * @param {[number, number]} coord The `[x, y]` coordinate to project. | |
93 * @param {[number, number]} size The `[width, height]` of the context. | |
94 * @param {[number, number]} xRange The range of X values in the context. | |
95 * @param {[number, number]} yRange The range of Y values in the context. | |
96 * @return {[number, number]} The `[x, y]` coordinate in Canvas space. | |
97 */ | |
98 function project(coord, size, xRange, yRange) { | |
99 const [x, y] = coord; | |
100 const [xMin, xMax] = xRange; | |
101 const xSpan = xMax - xMin; | |
102 const [yMin, yMax] = yRange; | |
103 const ySpan = yMax - yMin; | |
104 const [xSize, ySize] = size; | |
105 return [ | |
106 (x - xMin) / xSpan * xSize, | |
107 (yMax- y) / ySpan * ySize, | |
108 ] | |
109 } |