[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:
parent
eabc57ac51
commit
4282ae4470
6 changed files with 179 additions and 0 deletions
|
@ -43,6 +43,12 @@ main {
|
|||
z-index: 50;
|
||||
}
|
||||
|
||||
#canvas-guage {
|
||||
position: absolute;
|
||||
bottom: 2em; right: 1em;
|
||||
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.working { cursor: progress !important; }
|
||||
|
||||
|
|
|
@ -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
93
client_src/js/Guage.mjs
Normal 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;
|
37
client_src/js/Helpers/Canvas.mjs
Normal file
37
client_src/js/Helpers/Canvas.mjs
Normal 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 };
|
28
client_src/js/Helpers/GradientHelpers.mjs
Normal file
28
client_src/js/Helpers/GradientHelpers.mjs
Normal 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 };
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue