247 lines
		
	
	
		
			No EOL
		
	
	
		
			6.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
			
		
		
	
	
			247 lines
		
	
	
		
			No EOL
		
	
	
		
			6.4 KiB
		
	
	
	
		
			HTML
		
	
	
	
	
	
<!DOCTYPE html>
 | 
						|
<meta charset="utf-8">
 | 
						|
<title>succd</title>
 | 
						|
<meta name="viewport" content="width=device-width, initial-scale=1" />
 | 
						|
<style>
 | 
						|
body {
 | 
						|
    font-size: 14px;
 | 
						|
	padding: 2em;
 | 
						|
}
 | 
						|
table {
 | 
						|
	font-size: 40px;
 | 
						|
}
 | 
						|
th, td {
 | 
						|
	background-color: #e8e8e8;
 | 
						|
	padding: 0.4em;
 | 
						|
}
 | 
						|
th {
 | 
						|
	font-weight: 100;
 | 
						|
	text-align: right;
 | 
						|
	font-size: 30px;
 | 
						|
}
 | 
						|
td {
 | 
						|
	text-align: left;
 | 
						|
}
 | 
						|
td {
 | 
						|
	font-weight: 800;
 | 
						|
}
 | 
						|
h2 { 
 | 
						|
	font-style: italic;
 | 
						|
	font-weight: 100;
 | 
						|
}
 | 
						|
</style>
 | 
						|
 | 
						|
<h1>succd</h1>
 | 
						|
<h2>nothing more permanent than a temporary solution</h2>
 | 
						|
 | 
						|
<p style="margin-top: 5em;">
 | 
						|
	<table>
 | 
						|
		<tr>
 | 
						|
			<th>Voltage</th>
 | 
						|
			<td id="volts">{{.volts}}</td>
 | 
						|
		</tr>
 | 
						|
		<tr>
 | 
						|
			<th>Pressure</th>
 | 
						|
			<td id="mbar">{{.mbar}}</td>
 | 
						|
		</tr>
 | 
						|
		<tr>
 | 
						|
			<th>Status</th>
 | 
						|
			<td id="status">OK</td>
 | 
						|
		</tr>
 | 
						|
	</table>
 | 
						|
</p>
 | 
						|
<p style="margin-top: 2em;">
 | 
						|
    <canvas id="graph" width="1024" height="512" style="max-width: 100%;"></canvas>
 | 
						|
</p>
 | 
						|
 | 
						|
<p style="font-style: italic; font-size: 12px; margin-top: 5em;">
 | 
						|
	{{.hostname}} | load: {{.load}} | <a href="/debug/pprof">pprof</a> | <a href="/metrics">metrics</a> | ws ping: <span id="ping">…</span>
 | 
						|
</p>
 | 
						|
 | 
						|
<script>
 | 
						|
 | 
						|
let historical = [];
 | 
						|
let canvas = null;
 | 
						|
 | 
						|
// Push a datapoint (in mbar) to the historical buffer, maintaining enough data
 | 
						|
// for ~10 minutes.
 | 
						|
let historicalPush = (v) => {
 | 
						|
    historical.push({v: v, time: Date.now() / 1000});
 | 
						|
    let len = historical.length;
 | 
						|
    // TODO(q3k): trim based on recorded timestamp, not constant buffer size.
 | 
						|
    let trim = len - 8192;
 | 
						|
    if (trim > 0) {
 | 
						|
        historical = historical.slice(trim);
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
// Draw the historical graph and schedule next draw in 100msec.
 | 
						|
let historicalDraw = (w, h) => {
 | 
						|
    const now = Date.now() / 1000;
 | 
						|
 | 
						|
    // TODO(q3k): better use canvas API to not have so much silly math around
 | 
						|
    // coordinate calculation.
 | 
						|
 | 
						|
    canvas.clearRect(0, 0, w, h);
 | 
						|
    canvas.fillStyle = "#f0f0f0";
 | 
						|
    canvas.fillRect(0, 0, w, h);
 | 
						|
 | 
						|
    // Margins of the main graph window.
 | 
						|
    const marginLeft = 64;
 | 
						|
    const marginRight = 32;
 | 
						|
    const marginTop = 32;
 | 
						|
    const marginBottom = 32;
 | 
						|
 | 
						|
    // Draw main graph window.
 | 
						|
    canvas.fillStyle = "#f8f8f8";
 | 
						|
    canvas.strokeStyle = "#444";
 | 
						|
    canvas.lineWidth = 1;
 | 
						|
    canvas.fillRect(marginLeft, marginTop, w-(marginLeft+marginRight), h-(marginTop+marginBottom));
 | 
						|
    canvas.strokeRect(marginLeft, marginTop, w-(marginLeft+marginRight), h-(marginTop+marginBottom));
 | 
						|
 | 
						|
    // Range of decades for Y value.
 | 
						|
    const ymin = -4;
 | 
						|
    const ymax = 4;
 | 
						|
    // Pixels per decade.
 | 
						|
    const yscale = (h - (marginTop+marginBottom)) / (ymax - ymin);
 | 
						|
 | 
						|
    // For every decade...
 | 
						|
    for (let i = ymin; i < ymax; i++) {
 | 
						|
        const yoff = (i - ymin) * yscale + yscale / 2;
 | 
						|
        const y = Math.floor(h - marginBottom - yoff) + 0.5;
 | 
						|
        // Draw Y scale ticks.
 | 
						|
        canvas.beginPath();
 | 
						|
        canvas.moveTo(marginLeft-5, y);
 | 
						|
        canvas.lineTo(marginLeft, y);
 | 
						|
        canvas.strokeStyle = "#000";
 | 
						|
        canvas.stroke();
 | 
						|
 | 
						|
        // Draw Y grid.
 | 
						|
        canvas.beginPath();
 | 
						|
        canvas.moveTo(marginLeft, y);
 | 
						|
        canvas.lineTo(w-marginRight-1, y);
 | 
						|
        canvas.strokeStyle = "#ccc";
 | 
						|
        canvas.stroke();
 | 
						|
 | 
						|
        // Draw Y fine grid.
 | 
						|
        if (i > ymin) {
 | 
						|
            for (let j = 2; j < 10; j++) {
 | 
						|
                let yy = y - Math.log10(j/10) * yscale;
 | 
						|
                canvas.beginPath();
 | 
						|
                canvas.moveTo(marginLeft, yy);
 | 
						|
                canvas.lineTo(w-marginRight-1, yy);
 | 
						|
                canvas.strokeStyle = "#eee";
 | 
						|
                canvas.stroke();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // Draw Y labels.
 | 
						|
        canvas.font = "10px sans-serif";
 | 
						|
        canvas.fillStyle = "#000";
 | 
						|
        canvas.textAlign = "right";
 | 
						|
        const text = `10^${i}`;
 | 
						|
        canvas.fillText(text, marginLeft-10, y+5);
 | 
						|
    }
 | 
						|
 | 
						|
    // How much space to leave in front of the graph.
 | 
						|
    const xhead = 10;
 | 
						|
 | 
						|
    // Draw X labels..
 | 
						|
    canvas.textAlign = "center";
 | 
						|
    canvas.fillText("Now", w - marginRight - xhead, h - marginBottom + 15)
 | 
						|
    canvas.fillText("-10min", marginLeft, h - marginBottom + 15)
 | 
						|
 | 
						|
    const xmax = 60 * 10;
 | 
						|
    const xscale = (w - (marginLeft+marginRight+xhead)) / (xmax);
 | 
						|
    
 | 
						|
    // Clip to main window.
 | 
						|
    canvas.save();
 | 
						|
    canvas.beginPath();
 | 
						|
    canvas.rect(marginLeft, marginTop, w-(marginLeft+marginRight), h-(marginTop+marginBottom+1));
 | 
						|
    canvas.clip();
 | 
						|
 | 
						|
    // Draw actual data line.
 | 
						|
    let first = true;
 | 
						|
    canvas.beginPath();
 | 
						|
    historical.forEach((v) => {
 | 
						|
        const time = v.time;
 | 
						|
        const mbar = v.v;
 | 
						|
        const elapsed = now-time;
 | 
						|
        if (elapsed > xmax) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        const x = (w - marginRight - xhead) - (elapsed * xscale);
 | 
						|
        const yoff = (Math.log10(mbar) - ymin) * yscale + yscale / 2;
 | 
						|
        const y = h - marginBottom - yoff;
 | 
						|
 | 
						|
        if (first) {
 | 
						|
            first = false;
 | 
						|
            canvas.moveTo(x, y);
 | 
						|
        } else {
 | 
						|
            canvas.lineTo(x, y);
 | 
						|
        }
 | 
						|
    });
 | 
						|
    canvas.strokeStyle = "#de1010";
 | 
						|
    canvas.lineWidth = 1;
 | 
						|
    canvas.stroke();
 | 
						|
    canvas.restore();
 | 
						|
 | 
						|
    setTimeout(() => { historicalDraw(w, h); }, 100);
 | 
						|
};
 | 
						|
 | 
						|
window.addEventListener("load", (_) => {
 | 
						|
	console.log("s u c c");
 | 
						|
 | 
						|
	let status = document.querySelector("#status");
 | 
						|
	let volts = document.querySelector("#volts");
 | 
						|
	let mbar = document.querySelector("#mbar");
 | 
						|
	let ping = document.querySelector("#ping");
 | 
						|
    canvas = document.querySelector("#graph").getContext("2d");
 | 
						|
 | 
						|
    // TODO(q3k): unhardcode this.
 | 
						|
    historicalDraw(1024, 512);
 | 
						|
 | 
						|
    // Basic retry loop for connecting to WS.
 | 
						|
	let loc = window.location;
 | 
						|
	let wsloc = "";
 | 
						|
	if (loc.protocol == "https:") {
 | 
						|
		wsloc = "wss:";
 | 
						|
	} else {
 | 
						|
		wsloc = "ws:";
 | 
						|
	}
 | 
						|
	wsloc += "//" + loc.host + "/stream";
 | 
						|
	console.log("Connecting to " + wsloc + "...");
 | 
						|
 | 
						|
	let connected = false;
 | 
						|
	let connect = () => {
 | 
						|
		const socket = new WebSocket(wsloc);
 | 
						|
		socket.addEventListener("open", (event) => {
 | 
						|
			connected = true;
 | 
						|
			console.log("Socket connected!");
 | 
						|
			status.innerHTML = "Online";
 | 
						|
			status.style = "background-color: #60f060;";
 | 
						|
		});
 | 
						|
		socket.addEventListener("message", (event) => {
 | 
						|
			const data = JSON.parse(event.data);
 | 
						|
			volts.innerHTML = data.Volts;
 | 
						|
			mbar.innerHTML = data.Mbar;
 | 
						|
            historicalPush(data.MbarFloat);
 | 
						|
			ping.innerHTML = Date.now();
 | 
						|
		});
 | 
						|
		socket.addEventListener("close", (event) => {
 | 
						|
			status.innerHTML = "Offline";
 | 
						|
			status.style = "background-color: #f06060;";
 | 
						|
			if (connected) {
 | 
						|
				console.log("Socket dead, reconnecting...");
 | 
						|
			}
 | 
						|
			connected = false;
 | 
						|
			setTimeout(connect, 1000);
 | 
						|
		});
 | 
						|
		socket.addEventListener("error", (event) => {
 | 
						|
			socket.close();
 | 
						|
		});
 | 
						|
	};
 | 
						|
	connect();
 | 
						|
});
 | 
						|
</script> |