[web interface] Add guage to the side

This is ported over from the air quality web interface.

Proof I wrote this is, of course, available upon request.
This commit is contained in:
Starbeamrainbowlabs 2019-08-07 16:58:06 +01:00
parent eabc57ac51
commit 4282ae4470
6 changed files with 179 additions and 0 deletions

View file

@ -43,6 +43,12 @@ main {
z-index: 50;
}
#canvas-guage {
position: absolute;
bottom: 2em; right: 1em;
z-index: 1000;
}
.working { cursor: progress !important; }

View file

@ -17,6 +17,8 @@
</main>
<canvas id="canvas-guage" width="50" height="300"></canvas>
<!---------------->
<link rel="stylesheet" href="app.css" />
<script src="app.js" type="module" charset="utf-8"></script>

93
client_src/js/Guage.mjs Normal file
View file

@ -0,0 +1,93 @@
"use strict";
import { set_hidpi_canvas, pixel_ratio } from './Helpers/Canvas.mjs';
import { RenderGradient } from './Helpers/GradientHelpers.mjs';
import { normalise_rssi } from '../../common/Normalisers.mjs';
class Guage {
constructor(in_canvas) {
this.canvas = in_canvas;
set_hidpi_canvas(this.canvas);
this.context = this.canvas.getContext("2d");
}
set_spec({ gradient: spec }) {
this.spec = spec;
}
render() {
let guage_size = {
x: this.canvas.width * 0.6,
y: this.canvas.height * 0.05,
width: this.canvas.width * 0.3,
height: this.canvas.height * 0.9
};
this.clear_canvas();
this.render_gauge(guage_size);
this.render_labels(guage_size);
}
clear_canvas() {
this.context.clearRect(
0, 0,
this.canvas.width, this.canvas.height
);
}
render_gauge(guage_size) {
this.context.save();
let gradient_spec = RenderGradient(this.spec);
// console.log(gradient_spec);
let gradient = this.context.createLinearGradient(
0, guage_size.y + guage_size.height,
0, guage_size.y
);
for (let point in gradient_spec)
gradient.addColorStop(parseFloat(point), gradient_spec[point]);
this.context.fillStyle = gradient;
this.context.fillRect(
guage_size.x, guage_size.y,
guage_size.width, guage_size.height
);
this.context.restore();
}
render_labels(guage_size) {
this.context.save();
this.context.font = "12px Ubuntu, sans-serif";
this.context.textBaseline = "middle";
this.context.strokeStyle = "rgba(0, 0, 0, 0.5)";
this.context.lineWidth = 1.5 * pixel_ratio;
for (let point in this.spec) {
let value = 1 - normalise_rssi(parseFloat(point));
let text_width = this.context.measureText(point).width;
let draw_x = guage_size.x - 5 - text_width;
let draw_y = guage_size.y + (value * guage_size.height);
// console.log(`Writing '${point}' to (${draw_x}, ${draw_y})`);
this.context.fillText(point, draw_x, draw_y);
this.context.beginPath();
this.context.moveTo(guage_size.x + guage_size.width, draw_y);
this.context.lineTo(draw_x + text_width, draw_y);
this.context.stroke();
}
this.context.restore();
}
}
export default Guage;

View file

@ -0,0 +1,37 @@
"use strict";
// From https://stackoverflow.com/a/15666143/1460422
let pixel_ratio = (function () {
let ctx = document.createElement("canvas").getContext("2d"),
dpr = window.devicePixelRatio || 1,
bsr = ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio || 1;
return dpr / bsr;
})();
/**
* De-blurrificates a canvas on Hi-DPI screens.
* @param {HTMLCanvasElement} canvas The canvas element to alter.
* @param {Number} width=canvas.width Optional. The width of the canvas in question.
* @param {Number} height=canvas.height Optional. The height of the canvas in question.
* @returns {HTMLCanvasElement} The canvas we operated on. Useful for daisy-chaining.
*/
function set_hidpi_canvas(canvas, width, height) {
width = width || canvas.width;
height = height || canvas.height;
canvas.width = width * pixel_ratio;
canvas.height = height * pixel_ratio;
canvas.style.width = width + "px";
canvas.style.height = height + "px";
// canvas.getContext("2d").setTransform(pixel_ratio, 0, 0, pixel_ratio, 0, 0);
return canvas;
}
export { pixel_ratio, set_hidpi_canvas };

View file

@ -0,0 +1,28 @@
"use strict";
import { normalise_rssi } from '../../../common/Normalisers.mjs';
function RenderGradient(stops) {
let result = {};
for(let value in stops)
result[normalise_rssi(value)] = stops[value];
return result;
}
/**
* Generates a CSS gradient, given the output of RenderGradient().
* @param {[string, string]} stops The stops specification to create a css linear-gradient from. Should be the output of RenderGradient().
* @returns {string} The rendered CSS linear-gradient.
*/
function GenerateCSSGradient(stops) {
let stops_processed = [];
for(let value in stops) {
let valueNumber = parseFloat(value);
stops_processed.push(`${stops[value]} ${(valueNumber*100).toFixed(3).replace(/\.?[0]+$/, "")}%`);
}
return `linear-gradient(to bottom, ${stops_processed.join(", ")})`;
}
export { RenderGradient, GenerateCSSGradient };

View file

@ -6,6 +6,7 @@ import L from 'leaflet';
import LayerGateways from './LayerGateways.mjs';
import LayerAI from './LayerAI.mjs';
import Guage from './Guage.mjs';
class MapManager {
constructor() {
@ -30,12 +31,15 @@ class MapManager {
this.layer_gateways = new LayerGateways(this.map);
await this.layer_gateways.setup();
this.setup_guage();
// Add the AI coverage prediction layer
this.layer_ai = new LayerAI(this.map);
await this.layer_ai.setup();
this.setup_layer_control();
document.querySelector("main").classList.remove("working", "working-visual");
}
@ -52,6 +56,15 @@ class MapManager {
});
this.layer_control.addTo(this.map);
}
setup_guage() {
this.guage = new Guage(document.getElementById("canvas-guage"));
this.guage.set_spec({
gradient: Config.colour_scale,
max: -30
});
this.guage.render();
}
}
export default MapManager;