maj Map.js

This commit is contained in:
Gabriel Dehame 2023-02-21 16:05:03 +01:00
parent 8e1101b180
commit 1e0876ae46
2 changed files with 181 additions and 106 deletions

View File

@ -17,7 +17,7 @@ import { ThemeProvider, createTheme } from '@mui/material/styles';
import './App.css'
import Map from './Map2.js';
import Map from './Map.js';
import Rooms from './Rooms.js';
function RoomResearch({callbackRoomSelected}) {

View File

@ -10,10 +10,45 @@ import React from 'react';
import L from 'leaflet';
import stairs from "./stairs.png";
import lift from "./lift.png";
import request2 from "./M-GN1-2.json"
import request3 from "./M-GN1-3.json"
import request4 from "./M-GN1-4.json"
import { useMapEvent, useMap } from 'react-leaflet/hooks'
import toilet from "./toilet.png"
import request from "./test.json"
import { useMapEvent, useMap } from 'react-leaflet/hooks';
function Stairs({position, size, body})
{
// React class (in function form) to represent stairs, takes the position where to put the stairs logo
// and the body of the popup of the stairs (list of floors accessible from that staircase)
const map = useMap();
const [markerIcon, setMarkerIcon] = useState(new L.Icon({ iconUrl: stairs, iconSize: size }));
const mmap = useMapEvent('zoomend', () => {setMarkerIcon(new L.Icon({ iconUrl: stairs, iconSize: [40*Math.pow(2, map.getZoom() - 4), 40*Math.pow(2, map.getZoom() - 4)]}))});
return <Marker position={position} icon={markerIcon}>
{body}
</Marker>
}
function Lift({position, size, body})
{
// React class (in function form) to represent lifts, takes the position where to put the lift logo
// and the body of the popup of the lift (list of floors accessible from that lift)
const map = useMap();
const [markerIcon, setMarkerIcon] = useState(new L.Icon({ iconUrl: lift, iconSize: size }));
const mmap = useMapEvent('zoomend', () => {setMarkerIcon(new L.Icon({ iconUrl: lift, iconSize: [20*Math.pow(2, map.getZoom() - 4), 20*Math.pow(2, map.getZoom() - 4)]}))});
return <Marker position={position} icon={markerIcon}>
{body}
</Marker>
}
function Toilet({position, size, body})
{
// React class (in function form) to represent lifts, takes the position where to put the lift logo
// and the body of the popup of the lift (list of floors accessible from that lift)
const map = useMap();
const [markerIcon, setMarkerIcon] = useState(new L.Icon({ iconUrl: toilet, iconSize: size }));
const mmap = useMapEvent('zoomend', () => {setMarkerIcon(new L.Icon({ iconUrl: toilet, iconSize: [20*Math.pow(2, map.getZoom() - 4), 20*Math.pow(2, map.getZoom() - 4)]}))});
return <Marker position={position} icon={markerIcon}>
{body}
</Marker>
}
function polygonCenter(polygon)
{
@ -39,150 +74,190 @@ function polygonCenter(polygon)
return [(minX + maxX) / 2, (maxY + minY) / 2];
}
function min_max(request) {
function logoSize(polygon)
{
// function to calculate the size of a logo to display
// on a room which edges are in polygon
let minX = -1;
let minY = -1;
let maxX = -1;
let maxY = -1;
// We first calculate the maximal coordinates to then output
// 75% the size of the room
polygon.forEach((pt) => {
if (minX === -1 || minX > pt[0]) {
minX = pt[0];
}
if (minY === -1 || minY > pt[1]) {
minY = pt[1];
}
if (maxY === -1 || maxY < pt[1]) {
maxY = pt[1];
}
if (maxX === -1 || maxX < pt[0]) {
maxX = pt[0];
}
})
// For some unknown reason we have to multiply by 10 otherwise
// it's almost invisible
const x = 30*(maxX - minX)/4;
const y = 30*(maxY - minY)/4;
// We return a square size to make it better looking so we
// take the minimal size of border
if (x < y)
{
return [x,x];
}
return [y,y];
}
function min_max(request)
{
// Function to calculate the minimal and maximal coordinates of all the points in a request
// (it being a list of polygons, a polygon being a list of points, a point being a list of 2 coordinates)
let minX = -1;
let minY = -1;
let maxX = -1;
let maxY = -1;
for (const k in request) {
(request[k]).forEach((po) => {
po.forEach((pt) => {
if (minX === -1 || minX > pt[0]) {
minX = pt[0];
}
if (minY === -1 || minY > pt[1]) {
minY = pt[1];
}
if (maxY === -1 || maxY < pt[1]) {
maxY = pt[1];
}
if (maxX === -1 || maxX < pt[0]) {
maxX = pt[0];
}
})
for (const ind in request)
{
const element = request[ind];
// element can be a room, a lift, a staircase or toilets
(element["surface"]).forEach((pt) => {
if (minX === -1 || minX > pt["x"]) {
minX = pt["x"];
}
if (minY === -1 || minY > pt["y"]) {
minY = pt["y"];
}
if (maxY === -1 || maxY < pt["y"]) {
maxY = pt["y"];
}
if (maxX === -1 || maxX < pt["x"]) {
maxX = pt["x"];
}
})
}
return [minX, maxX, minY, maxY];
}
function Stairs({position, body})
function newPolygon(element, positions, selectedRoom, callback)
{
// React class (in function form) to represent stairs, takes the position where to put the stairs logo
// and the body of the popup of the stairs (list of floors accessible from that staircase)
const map = useMap();
const [markerIcon, setMarkerIcon] = useState(new L.Icon({ iconUrl: stairs, iconSize: [40, 40] }));
const mmap = useMapEvent('zoomend', () => {setMarkerIcon(new L.Icon({ iconUrl: stairs, iconSize: [40*Math.pow(2, map.getZoom() - 4), 40*Math.pow(2, map.getZoom() - 4)]}))});
return <Marker position={position} icon={markerIcon}>
{body}
</Marker>
// Auxiliary function to return the appropriate polygon depending
// on wether it is a room, a lift, a staircase or toilets
const color = selectedRoom === element["id"] ? 'red' : 'grey';
//if (element["type"] === "S")
if (element["id"] === 512 || element["id"] === 517 || element["id"] === 514 || element["id"] === 518)
{
// In this case, the room is a staircase so we add a Stairs component
return <Polygon positions={positions} key={element["id"] + color} color={color} evenHandlers={{click: () => callback(element["id"])}}>
<Tooltip>{element["id"]}</Tooltip>
<Stairs position={polygonCenter(positions)} size={logoSize(positions)} body={<Popup>
<li onClick={() => { console.log("escalier"); }}>
YAY
</li>
<li>
uéuéué
</li>
</Popup>
}
/>
</Polygon>
}
//else if (element["type"] === "L")
else if (element["id"] === 524 || element["id"] === 523)
{
// In this case the room is a lift so we add a Lift component
return <Polygon positions={positions} key={element["id"] + color} color={color} evenHandlers={{click: () => callback(element["id"])}}>
<Tooltip>{element["id"]}</Tooltip>
<Lift position={polygonCenter(positions)} size={logoSize(positions)} body={<Popup>
<li onClick={() => { console.log("ascenseur"); }}>
YAY
</li>
<li>
uéuéué
</li>
</Popup>
}
/>
</Polygon>
}
//else if (element["type"] === "T")
else if (element["id"] === 379)
{
return <Polygon positions={positions} key={element["id"] + color} color={color} evenHandlers={{click: () => callback(element["id"])}}>
<Tooltip>{element["id"]}</Tooltip>
<Toilet position={polygonCenter(positions)} size={logoSize(positions)} body={<Popup>
<li onClick={() => { console.log("toilettes"); }}>
YAY
</li>
<li>
uéuéué
</li>
</Popup>
}
/>
</Polygon>
}
else if (element["type"] === "R")
{
// In this case it is a regular room
return <Polygon positions={positions} key={element["id"] + color} color={color} eventHandlers={{click: () => callback(element["id"])}}>
<Tooltip>{element["id"]}</Tooltip>
</Polygon>
}
}
function Lift({position, body})
function list_polygons(request, center, callback, selectedRoom)
{
// React class (in function form) to represent lifts, takes the position where to put the lift logo
// and the body of the popup of the lift (list of floors accessible from that lift)
const map = useMap();
const [markerIcon, setMarkerIcon] = useState(new L.Icon({ iconUrl: lift, iconSize: [20, 20] }));
const mmap = useMapEvent('zoomend', () => {setMarkerIcon(new L.Icon({ iconUrl: lift, iconSize: [20*Math.pow(2, map.getZoom() - 4), 20*Math.pow(2, map.getZoom() - 4)]}))});
return <Marker position={position} icon={markerIcon}>
{body}
</Marker>
}
function list_polygons(request, center, ratio, cb, selectedRoom)
{
// Function to calculate the list of polygons (React components)
// Main function to calculate the list of polygons (React components)
// Taking the request as parameter, the center of the points of the request
// and the ratio to apply (zoom) as well as a callback (cb) to interact with the
// global web interface when a room is clicked (allowing the display of room informations)
// and a callback (callback) to interact with the global web interface
// when a room is clicked (allowing the display of room informations)
console.log(selectedRoom);
let polygons = [];
for (const k in request)
for (const ind in request)
{
polygons = [...polygons, ((request[k]).map((y) => {
return y.map((z) => {
return [-(z[1] - center[1]) / 25, (z[0] - center[0]) / 25];
})
})).map((x) => {
const color = selectedRoom === k ? 'red' : 'grey';
if (k === "salle-M-GN1-X-aa" || k === "salle-M-GN1-X-ab" || k === "salle-M-GN1-X-ac" || k === "salle-M-GN1-X-ad")
{
// In this case, the room is a staircase so we add a Stairs component
return <Polygon positions={x} key={k + color} color={color} evenHandlers={{click: () => cb(k)}}>
<Tooltip>{k}</Tooltip>
<Stairs position={polygonCenter(x)} body={<Popup>
<li onClick={() => { console.log("escalier"); }}>
YAY
</li>
<li>
uéuéué
</li>
</Popup>
}
/>
</Polygon>
}
else if (k === "salle-M-GN1-X-ag" || k === "salle-M-GN1-X-ah")
{
// In this case the room is a lift so we add a Lift component
return <Polygon positions={x} key={k + color} color={color} evenHandlers={{click: () => cb(k)}}>
<Tooltip>{k}</Tooltip>
<Lift position={polygonCenter(x)} body={<Popup>
<li onClick={() => { console.log("ascenseur"); }}>
YAY
</li>
<li>
uéuéué
</li>
</Popup>
}
/>
</Polygon>
}
else
{
// In this case it is a regular room
return <Polygon positions={x} key={k + color} color={color} eventHandlers={{click: () => cb(k)}}>
<Tooltip>{k}</Tooltip>
</Polygon>
}
})];
const element = request[ind];
// element can be a room, a lift, a staircase or toilets
const positions = (element["surface"]).map((pt) => {
// This function rotates and recenters de the map (should not be necessary once the real data are gathered)
// It also changes the objects into lists of two coordinates to make it accepted by the "positions" attribute of
// the "Polygon" react-leaflet component
return [-(pt["y"] - center[1]) / 25, (pt["x"] - center[0]) / 25];
});
const pol = newPolygon(element, positions, selectedRoom, callback);
polygons = [...polygons, pol];
}
return polygons;
}
function buildPols(request, cb, selectedRoom)
function buildPols(request, callback, selectedRoom)
{
// This function just calls the list_polygons one with appropriate parameters (precalculate ratio and center)
// This function just calls the list_polygons one with appropriate parameters (precalculate center)
const minMaxXY = min_max(request);
const minX = minMaxXY[0];
const maxX = minMaxXY[1];
const minY = minMaxXY[2];
const maxY = minMaxXY[3];
const center = [(maxX + minX) / 2, (maxY + minY) / 2];
const ratio = Math.ceil(Math.max((maxY - minY) / 2284, (maxX - minX) / 135)); //A priori ca devrait être convenable mais là ca ne fonctionne pas, je pense que c'est pck le SVG n'utilise pas des coordonnées et ducoup y'a des trucs bizarre (notamment les étages 3 et 4 n'ont pas du tout la même longueur ni même largeur)
const polygons = list_polygons(request, center, ratio, cb, selectedRoom);
const polygons = list_polygons(request, center, callback, selectedRoom);
return polygons;
}
function Map({ callbackRoomSelected, selectedRoom })
{
const request = new Request('https://encartes.aliens-lyon.fr/api/map/get_floor/47');
fetch(request).then((response) => {console.log(response)});
// When the user selects a room on the map, call callbackRoomSelected.
// The room that is currently selected is selectedRoom. It is null if no room
// is selected
console.log(request);
console.log(selectedRoom);
const createPolygons = React.useCallback((request, callbackRoomSelected, selectedRoom) => {
return buildPols(request, callbackRoomSelected, selectedRoom);
}, [request3, callbackRoomSelected, selectedRoom]);
}, [request, callbackRoomSelected, selectedRoom]);
const polygons = createPolygons(request3, callbackRoomSelected, selectedRoom);
const polygons = createPolygons(request, callbackRoomSelected, selectedRoom);
return <MapContainer center={[0, 0]} zoom={4} scrollWheelZoom={true} style={{ flexGrow: '1' }}>
{polygons}
</MapContainer>