html svg display + websocket
This commit is contained in:
parent
0e93eafb7e
commit
12c089f7b9
210
data/index.html
210
data/index.html
@ -5,68 +5,166 @@
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<title>Sporttafel</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 8vw;
|
||||
margin: 0;
|
||||
}
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 8vw;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 33vmin;
|
||||
height: 33vmin;
|
||||
font-size: 9vw;
|
||||
}
|
||||
button {
|
||||
width: 33vmin;
|
||||
font-size: 9vw;
|
||||
}
|
||||
|
||||
button.cancel {
|
||||
width: 15vmin;
|
||||
height: 15vmin;
|
||||
}
|
||||
button.cancel {
|
||||
width: 15vmin;
|
||||
height: 15vmin;
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
svg {
|
||||
border: 1px solid black;
|
||||
width: 100%;
|
||||
height: calc(11 / 27 * 100%);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function get(path) {
|
||||
var r = new XMLHttpRequest();
|
||||
r.open("GET", path, true);
|
||||
r.send();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<button onclick="get('/action/cancel')" class="cancel">✗</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/up')">↑</button>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button onclick="get('/action/left')">←</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/confirm')">✓</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/right')">→</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>
|
||||
<button onclick="get('/action/down')">↓</button>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
<svg width="800" height="325" id="display">
|
||||
</svg>
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<button onclick="get('/action/cancel')" class="cancel">✗</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/up')">↑</button>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<button onclick="get('/action/left')">←</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/confirm')">✓</button>
|
||||
</td>
|
||||
<td>
|
||||
<button onclick="get('/action/right')">→</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td>
|
||||
<button onclick="get('/action/down')">↓</button>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
|
||||
<!--suppress PointlessArithmeticExpressionJS -->
|
||||
<script>
|
||||
|
||||
const S = 100 / 27;
|
||||
|
||||
const display = document.getElementById("display");
|
||||
|
||||
const segments = [];
|
||||
|
||||
function get(path) {
|
||||
const request = new XMLHttpRequest();
|
||||
request.open("GET", "http://10.0.0.119" + path, true);
|
||||
request.send();
|
||||
}
|
||||
|
||||
function drawDigit(x, y) {
|
||||
drawPixel(x, y, 0, 3);
|
||||
drawPixel(x, y, 0, 2);
|
||||
drawPixel(x, y, 0, 1);
|
||||
|
||||
drawPixel(x, y, 1, 0);
|
||||
drawPixel(x, y, 2, 0);
|
||||
drawPixel(x, y, 3, 0);
|
||||
|
||||
drawPixel(x, y, 4, 1);
|
||||
drawPixel(x, y, 4, 2);
|
||||
drawPixel(x, y, 4, 3);
|
||||
|
||||
drawPixel(x, y, 4, 5);
|
||||
drawPixel(x, y, 4, 6);
|
||||
drawPixel(x, y, 4, 7);
|
||||
|
||||
drawPixel(x, y, 3, 8);
|
||||
drawPixel(x, y, 2, 8);
|
||||
drawPixel(x, y, 1, 8);
|
||||
|
||||
drawPixel(x, y, 0, 7);
|
||||
drawPixel(x, y, 0, 6);
|
||||
drawPixel(x, y, 0, 5);
|
||||
|
||||
drawPixel(x, y, 1, 4);
|
||||
drawPixel(x, y, 2, 4);
|
||||
drawPixel(x, y, 3, 4);
|
||||
}
|
||||
|
||||
function drawPixel(offsetRasterX, offsetRasterY, innerRasterX, innerRasterY) {
|
||||
const segment = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
const x = (offsetRasterX + innerRasterX) * S;
|
||||
const y = (offsetRasterY + innerRasterY) * S;
|
||||
segment.setAttribute("x", x + "vw");
|
||||
segment.setAttribute("y", y + "vw");
|
||||
segment.setAttribute("width", S + "vw");
|
||||
segment.setAttribute("height", S + "vw");
|
||||
segment.setAttribute("fill", "#555");
|
||||
segment.setAttribute("id", "segment" + segments.length);
|
||||
display.appendChild(segment);
|
||||
segments.push(segment);
|
||||
}
|
||||
|
||||
function drawDisplay(rasterX, rasterY) {
|
||||
drawDigit(rasterX, rasterY);
|
||||
rasterX += 6;
|
||||
drawDigit(rasterX, rasterY);
|
||||
rasterX += 6;
|
||||
drawPixel(rasterX, rasterY, 0, 0);
|
||||
drawPixel(rasterX, rasterY + 2.5, 0, 0);
|
||||
drawPixel(rasterX, rasterY + 5.5, 0, 0);
|
||||
drawPixel(rasterX, rasterY + 8, 0, 0);
|
||||
rasterX += 2;
|
||||
drawDigit(rasterX, rasterY);
|
||||
rasterX += 6;
|
||||
drawDigit(rasterX, rasterY);
|
||||
}
|
||||
|
||||
function connect() {
|
||||
console.log("connecting websocket...");
|
||||
const host = "10.0.0.119";
|
||||
const port = "80";
|
||||
const url = `ws://${host}:${port}/ws`;
|
||||
console.log(url);
|
||||
const socket = new WebSocket(url);
|
||||
socket.timeout = 1;
|
||||
socket.addEventListener('open', _ => console.log('websocket connected'));
|
||||
socket.addEventListener('message', event => {
|
||||
event.data.split(',').filter((color, index) => color !== '').forEach((color, index) => segments[index].setAttribute("fill", "#" + color));
|
||||
});
|
||||
socket.addEventListener('close', _ => {
|
||||
console.log('websocket disconnected');
|
||||
connect();
|
||||
});
|
||||
}
|
||||
|
||||
drawDisplay(1, 1);
|
||||
connect();
|
||||
|
||||
</script>
|
||||
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@ -8,6 +8,8 @@ AsyncWebServer server(80);
|
||||
|
||||
AsyncWebSocket ws("/ws");
|
||||
|
||||
auto websocketStarted = false;
|
||||
|
||||
void httpIndex(AsyncWebServerRequest *request) {
|
||||
info(request->url().c_str());
|
||||
request->send(LittleFS, "/index.html", "text/html");
|
||||
@ -90,8 +92,15 @@ void httpSetup() {
|
||||
server.on("/action/cancel", HTTP_GET, httpActionCancel);
|
||||
server.on("/action/confirm", HTTP_GET, httpActionConfirm);
|
||||
server.begin();
|
||||
websocketStarted = true;
|
||||
}
|
||||
|
||||
void httpLoop() {
|
||||
ws.cleanupClients();
|
||||
}
|
||||
|
||||
void websocketSend(const char *message) {
|
||||
if (websocketStarted) {
|
||||
ws.textAll(message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,4 +5,6 @@ void httpSetup();
|
||||
|
||||
void httpLoop();
|
||||
|
||||
void websocketSend(const char *message);
|
||||
|
||||
#endif
|
||||
|
||||
@ -59,13 +59,14 @@ void logLoop() {
|
||||
const auto c = static_cast<char>(Serial.read());
|
||||
switch (c) {
|
||||
case 13:
|
||||
Serial.print(c);
|
||||
execute(cmd);
|
||||
write = cmd;
|
||||
*write = 0;
|
||||
break;
|
||||
case 8:
|
||||
Serial.print(c);
|
||||
if (write > cmd) {
|
||||
Serial.print(c);
|
||||
*write-- = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include "Color.h"
|
||||
#include "font.h"
|
||||
#include "core/http.h"
|
||||
|
||||
#define PIXELS_PER_SEGMENT 3
|
||||
#define SEGMENTS_PER_DIGIT 7
|
||||
@ -24,7 +25,7 @@ class Display {
|
||||
|
||||
// Adafruit_NeoPixel leds;
|
||||
|
||||
Color buffer[PIXEL_COUNT] = {};
|
||||
Color pixels[PIXEL_COUNT] = {};
|
||||
|
||||
Color color = WHITE;
|
||||
|
||||
@ -46,12 +47,28 @@ public:
|
||||
}
|
||||
|
||||
void clear() {
|
||||
memset(buffer, 0, PIXEL_BYTE_COUNT);
|
||||
memset(pixels, 0, PIXEL_BYTE_COUNT);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
// memcpy(leds.getPixels(), buffer, PIXEL_BYTE_COUNT);
|
||||
// leds.show();
|
||||
|
||||
const auto now = millis();
|
||||
static auto last = now;
|
||||
if (now - last >= 500) {
|
||||
last = now;
|
||||
send();
|
||||
}
|
||||
}
|
||||
|
||||
void send() {
|
||||
char buffer[512];
|
||||
char *b = buffer;
|
||||
for (const auto& pixel: pixels) {
|
||||
b += snprintf(b, sizeof buffer - (b - buffer), "%02X%02X%02X,", pixel.r, pixel.g, pixel.b);
|
||||
}
|
||||
websocketSend(buffer);
|
||||
}
|
||||
|
||||
int printf(const char *format, ...) {
|
||||
@ -78,12 +95,18 @@ public:
|
||||
case '\'':
|
||||
case '"':
|
||||
case '`':
|
||||
case '.': return printDots(pixel, false, false, false, true);
|
||||
case ',': return printDots(pixel, false, false, true, true);
|
||||
case ':': return printDots(pixel, false, true, true, false);
|
||||
case ';': return printDots(pixel, false, true, true, true);
|
||||
case '|': return printDots(pixel, true, true, true, true);
|
||||
default: return printCharacter(pixel, character);
|
||||
case '.':
|
||||
return printDots(pixel, false, false, false, true);
|
||||
case ',':
|
||||
return printDots(pixel, false, false, true, true);
|
||||
case ':':
|
||||
return printDots(pixel, false, true, true, false);
|
||||
case ';':
|
||||
return printDots(pixel, false, true, true, true);
|
||||
case '|':
|
||||
return printDots(pixel, true, true, true, true);
|
||||
default:
|
||||
return printCharacter(pixel, character);
|
||||
}
|
||||
}
|
||||
|
||||
@ -93,19 +116,19 @@ public:
|
||||
return 0;
|
||||
}
|
||||
if (dot0) {
|
||||
buffer[pixel] = color;
|
||||
pixels[pixel] = color;
|
||||
}
|
||||
pixel++;
|
||||
if (dot1) {
|
||||
buffer[pixel] = color;
|
||||
pixels[pixel] = color;
|
||||
}
|
||||
pixel++;
|
||||
if (dot2) {
|
||||
buffer[pixel] = color;
|
||||
pixels[pixel] = color;
|
||||
}
|
||||
pixel++;
|
||||
if (dot3) {
|
||||
buffer[pixel] = color;
|
||||
pixels[pixel] = color;
|
||||
}
|
||||
return pixel;
|
||||
}
|
||||
@ -115,9 +138,9 @@ public:
|
||||
const auto symbol = getSymbol(character);
|
||||
for (auto s = *symbol; s < *symbol + SYMBOL_SIZE; s++) {
|
||||
if (*s) {
|
||||
buffer[pixel++] = color;
|
||||
buffer[pixel++] = color;
|
||||
buffer[pixel++] = color;
|
||||
pixels[pixel++] = color;
|
||||
pixels[pixel++] = color;
|
||||
pixels[pixel++] = color;
|
||||
} else {
|
||||
pixel += 3;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user