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 }