From c9b6b9a5ca082fe7c1b6f58d7713f785a9eb6a5c Mon Sep 17 00:00:00 2001 From: Martial Simon Date: Mon, 15 Sep 2025 01:08:27 +0200 Subject: add: graphs et rushs --- graphs/js/coordinatesDisplay/coordinates.js | 123 ++++++++++++++++++++++++ graphs/js/coordinatesDisplay/index.html | 20 ++++ graphs/js/coordinatesDisplay/resources/logo.svg | 63 ++++++++++++ graphs/js/coordinatesDisplay/server.js | 92 ++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 graphs/js/coordinatesDisplay/coordinates.js create mode 100644 graphs/js/coordinatesDisplay/index.html create mode 100755 graphs/js/coordinatesDisplay/resources/logo.svg create mode 100644 graphs/js/coordinatesDisplay/server.js (limited to 'graphs/js/coordinatesDisplay') diff --git a/graphs/js/coordinatesDisplay/coordinates.js b/graphs/js/coordinatesDisplay/coordinates.js new file mode 100644 index 0000000..845599f --- /dev/null +++ b/graphs/js/coordinatesDisplay/coordinates.js @@ -0,0 +1,123 @@ +/** + * Retrieves the width of the map. + * @returns {Promise} A promise that resolves when the width is retrieved. + */ +const getMapWidth = async () => { + const res = await fetch("http://localhost:2707/mapWidth"); + + return res.json(); +}; + +/** + * Fetches the bit at the specified index from the server. + * @param {number} i - The index of the bit to fetch. + * @returns {Promise} - A promise that resolves with the fetched bit. + */ +const getMapPiece = async (i) => { + const res = await fetch(`http://localhost:2707/piece/${i}`); + + return res.json(); +}; + +/** + * Creates a grid element with the specified map width. + * @param {number} mapWidth - The width of the map. + */ + +function createGrid(mapWidth) { + const div = document.createElement("div"); + + div.id = "asyncGrid"; + div.style.display = "grid"; + div.style.gridTemplateColumns = `repeat(${mapWidth}, 1fr)`; + div.style.gridTemplateRows = `repeat(${mapWidth}, 1fr)`; + div.style.width = "fit-content"; + div.style.height = "fit-content"; + document.body.appendChild(div); +} + +/** + * Displays an SVG element asynchronously at the specified coordinates. + * + * @param {string} svg - The SVG element to be displayed. + * @param {number} x - The x-coordinate of the grid cell where the SVG element will be displayed. + * @param {number} y - The y-coordinate of the grid cell where the SVG element will be displayed. + */ +async function displayPiece(svg, x, y) { + const svgElement = document.createElement("div"); + + svgElement.innerHTML = svg; + + const width = svgElement.lastChild.getAttribute("width"); + const height = svgElement.lastChild.getAttribute("height"); + + svgElement.style.width = `${width}px`; + svgElement.style.height = `${height}px`; + svgElement.style.gridColumn = x + 1; + svgElement.style.gridRow = y + 1; + svgElement.style.padding = 0; + svgElement.style.margin = 0; + document.getElementById("asyncGrid").appendChild(svgElement); +} + +async function displayMap() { + // FIXME ! + + const startTime = Date.now(); + const width = await getMapWidth(); + + createGrid(width); + const promises = new Array(); + + for (let i = 0; i < width * width; i++) { + promises.push( + getMapPiece(i).then(async (piece) => { + await displayPiece(piece.svg, piece.x, piece.y); + }), + ); + } + + await Promise.all(promises); + return Date.now() - startTime; + /*return new Promise((resolve, reject) => { + resolve(getMapWidth); + }) + .then((width) => { + createGrid(width); + let promises = new Array(); + for (let i = 0; i < width * width; i++) { + promises.push( + new Promise((resolve) => { + resolve(getMapPiece(i)); + }).then((piece) => { + displayPiece(piece.svg, piece.x, piece.y); + }), + ); + } + Promise.all(promises); + return Date.now() - startTime; + }) + .catch((error) => error);*/ + // don't forget you can use above functions to help you and also make your own +} + +// Your code goes here, the html page will load your script and launch it +// Catch errors if you push your testing code so the Moulinette doesn't fail +displayMap() + .then((time) => { + console.log("displayed in " + time + " ms."); + }) + .catch((error) => { + console.error(error); + }); + +// As always, we need to export the displayMap function for the tests. +// To avoid errors in browsers (where "module" is not defined), +// we wrap the exports inside a conditional check to ensure they +// are only assigned when the code is running in a Node.js environment. + +if (typeof window === "undefined") { + module.exports = { + displayMap, + }; +} diff --git a/graphs/js/coordinatesDisplay/index.html b/graphs/js/coordinatesDisplay/index.html new file mode 100644 index 0000000..d2bf830 --- /dev/null +++ b/graphs/js/coordinatesDisplay/index.html @@ -0,0 +1,20 @@ + + + + Async Display + + + + + + + diff --git a/graphs/js/coordinatesDisplay/resources/logo.svg b/graphs/js/coordinatesDisplay/resources/logo.svg new file mode 100755 index 0000000..14ac718 --- /dev/null +++ b/graphs/js/coordinatesDisplay/resources/logo.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layer 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + Being a hero means fighting back + even when it seems impossible + + + + + \ No newline at end of file diff --git a/graphs/js/coordinatesDisplay/server.js b/graphs/js/coordinatesDisplay/server.js new file mode 100644 index 0000000..45b7fed --- /dev/null +++ b/graphs/js/coordinatesDisplay/server.js @@ -0,0 +1,92 @@ +// svg image server +const express = require("express"); +const cors = require("cors"); +const DOMParser = require("xmldom").DOMParser; +const XMLSerializer = require("xmldom").XMLSerializer; +const fs = require("fs"); + +const app = express(); + +app.use(cors()); + +app.use(express.static("public")); + +app.listen(2707, () => { + console.log("Server listening on port 2707 👂"); +}); + +const sidePiecesCount = 20; // size has to odd to make the puzzle solvable + +app.get("/mapWidth", (req, res) => { + res.json(sidePiecesCount); +}); + +const parser = new DOMParser(); + +const svgText = fs.readFileSync(__dirname + "/resources/logo.svg", "utf8"); +const svg = parser.parseFromString(svgText, "image/svg+xml"); + +const width = svg.documentElement.getAttribute("width"); +const height = svg.documentElement.getAttribute("height"); + +const gridSideSize = Math.max(width, height); + +const pieceSize = gridSideSize / sidePiecesCount; + +const piecesMap = new Array(sidePiecesCount * sidePiecesCount); + +for (let x = 0; x < sidePiecesCount; x++) { + for (let y = 0; y < sidePiecesCount; y++) { + const piece = svg.cloneNode(true); + + piece.documentElement.setAttribute( + "viewBox", + `${x * pieceSize} ${y * pieceSize} ${pieceSize} ${pieceSize}`, + ); // ATTENTION : this method is really slow, in real life cases you should really cut the image and not send it with information on where to crop it + piece.documentElement.setAttribute("width", `${pieceSize}`); + piece.documentElement.setAttribute("height", `${pieceSize}`); + const svgString = new XMLSerializer().serializeToString(piece); + + piecesMap[x + y * sidePiecesCount] = { + svg: svgString, + x: x, + y: y, + }; + } +} + +const shuffledCoordinates = Array.from( + Array(sidePiecesCount * sidePiecesCount).keys(), +); + +const swap = (a, i, j) => { + const tmp = a[i]; + + a[i] = a[j]; + a[j] = tmp; +}; + +const shuffle = (a) => { + let i = a.length - 1; + + while (i > 0) { + const j = Math.floor(Math.random() * i); + + swap(a, i, j); + i--; + } +}; + +shuffle(shuffledCoordinates); + +console.log("Coordinates shuffled ! 🥳"); +console.log("now serving on port 2707. 🫡"); + +for (let x = 0; x < shuffledCoordinates.length; x++) { + app.get(`/piece/${x}`, (req, res) => { + console.log(`piece ${x} requested 🤖`); + res.send(piecesMap[shuffledCoordinates[x]]); + }); +} + +exports.app = app; -- cgit v1.2.3