Files
fairhopper/frontend/index.html
2023-03-31 10:19:21 +02:00

240 lines
7.4 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css"
integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
<link rel="stylesheet" href="styles.css">
<title>FairHopper Visualisation Client</title>
</head>
<body>
<main class="container-fluid container">
<h1 class="mt-1 mb-2">
FairHopper Visualisation Client
</h1>
<div id="purchase-container" class="purchase-container d-none">
<h3>Product selection</h3>
<div id="products-content" class="products-content"></div>
</div>
<div class="row">
<div class="col-10">
<div class="board-container">
<div id="board-content"></div>
</div>
</div>
<div class="col-2">
<h3 class="pb-2 border-bottom">
Players
</h3>
<ul class="players" id="players-content"></ul>
</div>
</div>
</main>
</body>
<script>
const BOARD_ICONS = {
PLAYER: "😀",
PLAYER_ON_DESTINATION: "😎",
OBSTACLE: "🔥",
DESTINATION: "🏠",
};
function createBoard(board) {
let html = "";
for (let y = 0; y < board.height; y++) {
let colHtml = "";
for (let x = 0; x < board.width; x++) {
colHtml += `<div class="cell" id="cell-${x}-${y}">&nbsp;</div>`;
}
html += `
<div class="flex-grid">
${colHtml}
</div>
`;
}
document.getElementById("board-content").innerHTML = html;
}
function findCell(position) {
return document.getElementById(`cell-${position.x}-${position.y}`);
}
function renderCellContent(position, content) {
const cell = findCell(position);
if (cell) {
cell.innerText = content;
}
}
function renderPlayerList(players) {
const html = players.filter(player => player.active).map((player) => {
const onDestination = player.state == "ON_DESTINATION";
return `
<li class="${onDestination ? "text-success" : ""}">
${player.name} (${player.move_count})
${onDestination ? "✅" : ""}
</li>
`;
}).join("");
document.getElementById("players-content").innerHTML = html;
}
function renderPlayers(players) {
players.filter(player => player.active).forEach(player => {
const cell = findCell(player.position);
const onDestination = player.state == "ON_DESTINATION";
const playerIcon = onDestination ? BOARD_ICONS.PLAYER_ON_DESTINATION : BOARD_ICONS.PLAYER;
if (cell) {
const html = `
<div class="player-tooltip">${player.name}</div>
${playerIcon}
`;
cell.innerHTML = html;
}
});
}
function getLayerObjectsOfType(layers, type) {
let objects = [];
layers.forEach(layer => {
objects = objects.concat(layer.objects.filter(obj => obj.type === type))
});
return objects;
}
function renderObstacles(layers) {
const objects = getLayerObjectsOfType(layers, "OBSTACLE");
objects.forEach(obj => {
renderCellContent(obj.position, BOARD_ICONS.OBSTACLE);
});
}
function renderDestination(position) {
renderCellContent(position, BOARD_ICONS.DESTINATION);
}
function renderGameDump(data) {
createBoard(data.board);
renderObstacles(data.layers)
renderDestination(data.destination.position);
renderPlayerList(data.players);
renderPlayers(data.players);
}
function productPurchaseStart(products) {
console.log("productPurchaseStart:", products);
const containerElement = document.getElementById("purchase-container");
const contentElement = document.getElementById("products-content");
const html = products.map(product => {
return `
<div class="card product">
<img src="img/products/${product.name}.jpeg" class="card-img-topx" alt="${product.name}">
<div class="card-body">
<h5 class="card-title">${product.name}</h5>
</div>
</div>
`;
}).join("");
contentElement.innerHTML = html;
containerElement.classList.remove("d-none")
}
function productPurchased(product) {
console.log("productPurchased:", product)
}
function productPurchaseDone() {
console.log("productPurchaseDone")
const container = document.getElementById("purchase-container");
container.classList.add("d-none")
}
function wsConnect() {
let ws = new WebSocket('ws://localhost:8011');
ws.onopen = () => {
console.log("WS connected")
};
ws.onmessage = (e) => {
const wsMessage = JSON.parse(e.data);
console.log("WS message received:", wsMessage)
switch (wsMessage.message) {
case "game_dump":
renderGameDump(wsMessage.data);
break;
case "product_purchase_start":
productPurchaseStart(wsMessage.data.products)
break;
case "product_purchased":
productPurchased(wsMessage.data)
break;
case "product_purchase_done":
productPurchaseDone()
break;
default:
console.error("Unknown message:", wsMessage)
}
};
ws.onclose = (e) => {
setTimeout(function () {
wsConnect();
}, 1000);
};
ws.onerror = (err) => {
console.error("Socket encountered error:", err.message, "Closing socket");
ws.close();
};
}
window.onload = () => {
wsConnect();
productPurchaseStart([
{
"name": "CocaCola",
"uuid": "4af72121-c4c5-4a28-b514-2ba577a7f6c5",
"description": null
},
{
"name": "Pepsi",
"uuid": "a14ad558-6ab2-4aa7-9456-f525430c38f8",
"description": null
},
{
"name": "Fanta",
"uuid": "7ea2fe22-c938-4217-91ec-e96c040b077f",
"description": null
},
{
"name": "Snickers",
"uuid": "04d8ad0c-fa80-4342-9449-390b162995fd",
"description": null
},
{
"name": "Mars",
"uuid": "f8674776-dc57-418f-b4ea-29f4ec4fdf35",
"description": null
},
{
"name": "Burek",
"uuid": "329942c8-9a6d-42e5-b859-3df577c5bce7",
"description": null
}
])
}
</script>
</html>