mirror of
https://git.rezel.net/LudoTech/traque.git
synced 2026-02-09 02:10:18 +01:00
Ajout zones en pavage + fix dockefiles
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import { useAdminContext } from "@/context/adminContext";
|
||||
import { useSocket } from "@/context/socketContext";
|
||||
|
||||
@@ -52,4 +53,4 @@ export default function useAdmin() {
|
||||
}
|
||||
return { ...adminContext, changeGameSettings, changeZoneSettings, changePenaltySettings, pollTeams, getTeam, getTeamName, reorderTeams, addTeam, removeTeam, changeState, updateTeam };
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
"use client";
|
||||
|
||||
import { useSocket } from "@/context/socketContext";
|
||||
import { useTeamConnexion } from "@/context/teamConnexionContext";
|
||||
import { useTeamContext } from "@/context/teamContext";
|
||||
@@ -33,4 +32,4 @@ export default function useGame() {
|
||||
teamId,
|
||||
gameState,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useLocalStorage(key, initialValue) {
|
||||
export default function useLocalStorage(key, initialValue) {
|
||||
const [storedValue, setStoredValue] = useState(initialValue);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
|
||||
@@ -5,11 +5,10 @@ import { useEffect, useState } from "react";
|
||||
* A hook that returns the location of the user and updates it periodically
|
||||
* @returns {Object} The location of the user
|
||||
*/
|
||||
export function useLocation(interval) {
|
||||
export default function useLocation(interval) {
|
||||
const [location, setLocation] = useState();
|
||||
useEffect(() => {
|
||||
function update() {
|
||||
console.log('Updating location');
|
||||
navigator.geolocation.getCurrentPosition((position) => {
|
||||
setLocation([position.coords.latitude, position.coords.longitude]);
|
||||
if(interval != Infinity) {
|
||||
@@ -21,4 +20,4 @@ export function useLocation(interval) {
|
||||
}, []);
|
||||
|
||||
return location;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useMapCircleDraw(area, setArea) {
|
||||
export default function useMapCircleDraw(area, setArea) {
|
||||
const [drawing, setDrawing] = useState(false);
|
||||
const [center, setCenter] = useState(area?.center || null);
|
||||
const [radius, setRadius] = useState(area?.radius || null);
|
||||
@@ -12,7 +13,7 @@ export function useMapCircleDraw(area, setArea) {
|
||||
}, [area])
|
||||
|
||||
function handleClick(e) {
|
||||
if(!drawing) {
|
||||
if (!drawing) {
|
||||
setCenter(e.latlng);
|
||||
setRadius(null);
|
||||
setDrawing(true);
|
||||
@@ -23,14 +24,10 @@ export function useMapCircleDraw(area, setArea) {
|
||||
}
|
||||
|
||||
function handleMouseMove(e) {
|
||||
if(drawing) {
|
||||
if (drawing) {
|
||||
setRadius(e.latlng.distanceTo(center));
|
||||
}
|
||||
}
|
||||
return {
|
||||
handleClick,
|
||||
handleMouseMove,
|
||||
center,
|
||||
radius,
|
||||
}
|
||||
}
|
||||
|
||||
return { handleClick, handleMouseMove, center, radius };
|
||||
}
|
||||
214
traque-front/hook/useMapPolygonDraw.jsx
Normal file
214
traque-front/hook/useMapPolygonDraw.jsx
Normal file
@@ -0,0 +1,214 @@
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import { useMap } from "react-leaflet";
|
||||
|
||||
export default function useMapPolygonDraw(polygons, addPolygon, removePolygon) {
|
||||
const map = useMap();
|
||||
const nodeCatchDistance = 30; // px
|
||||
const nodeHighlightDistance = 30; // px
|
||||
const [currentPolygon, setCurrentPolygon] = useState([]);
|
||||
const [highlightNodes, setHighlightNodes] = useState([]);
|
||||
|
||||
function latlngEqual(latlng1, latlng2, epsilon = 1e-9) {
|
||||
return Math.abs(latlng1.lat - latlng2.lat) < epsilon && Math.abs(latlng1.lng - latlng2.lng) < epsilon;
|
||||
}
|
||||
|
||||
function layerDistance(latlng1, latlng2) {
|
||||
// Return the pixel distance between latlng1 and latlng2 as they appear on the map
|
||||
const {x: x1, y: y1} = map.latLngToLayerPoint(latlng1);
|
||||
const {x: x2, y: y2} = map.latLngToLayerPoint(latlng2);
|
||||
return Math.sqrt((x1 - x2)**2 + (y1 - y2)**2);
|
||||
}
|
||||
|
||||
function isDrawing() {
|
||||
return currentPolygon.length > 0;
|
||||
}
|
||||
|
||||
function areSegmentsIntersecting(p1, p2, p3, p4) {
|
||||
// Return true if the segments (p1, p2) and (p3, p4) are strictly intersecting, else false
|
||||
const direction = (a, b, c) => {
|
||||
return (c.lng - a.lng) * (b.lat - a.lat) - (b.lng - a.lng) * (c.lat - a.lat);
|
||||
};
|
||||
|
||||
const d1 = direction(p3, p4, p1);
|
||||
const d2 = direction(p3, p4, p2);
|
||||
const d3 = direction(p1, p2, p3);
|
||||
const d4 = direction(p1, p2, p4);
|
||||
|
||||
return ((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0));
|
||||
}
|
||||
|
||||
function isIntersecting(segment, pointArray, isPolygon) {
|
||||
// Return true if segment intersects one of the pointArray segments according to areSegmentsIntersecting
|
||||
// Moreover if isPolygon, then it verifies if segment intersects the segment closing pointArray
|
||||
const length = pointArray.length;
|
||||
|
||||
for (let i = 0; i < length-1; i++) {
|
||||
if (areSegmentsIntersecting(segment[0], segment[1], pointArray[i], pointArray[i+1])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isPolygon && length > 2) {
|
||||
return areSegmentsIntersecting(segment[0], segment[1], pointArray[length-1], pointArray[0]);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function isInPolygon(latlng, polygon) {
|
||||
// Return true if latlng is strictly inside polygon
|
||||
// Return false if latlng is outside polygon or on a vertex of the polygon
|
||||
// Return true or false if latlng is on the border
|
||||
if (latlngEqual(latlng, polygon[0])) return false;
|
||||
|
||||
const length = polygon.length;
|
||||
const {lat: x, lng: y} = latlng;
|
||||
let inside = false;
|
||||
|
||||
for (let i = 0, j = length - 1; i < length; j = i++) {
|
||||
if (latlngEqual(latlng, polygon[j])) return false;
|
||||
|
||||
const {lat: xi, lng: yi} = polygon[i];
|
||||
const {lat: xj, lng: yj} = polygon[j];
|
||||
const intersects = ((yi > y) !== (yj > y)) && (x < ((xj - xi) * (y - yi)) / (yj - yi) + xi);
|
||||
|
||||
if (intersects) inside = !inside;
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
function isClockwise(points) {
|
||||
// Return true if the tab describes a clockwise polygon (Shoelace formula)
|
||||
let sum = 0;
|
||||
for (let i = 0; i < points.length; i++) {
|
||||
const curr = points[i];
|
||||
const next = points[(i + 1) % points.length];
|
||||
sum += (next.lng - curr.lng) * (next.lat + curr.lat);
|
||||
}
|
||||
return sum > 0;
|
||||
};
|
||||
|
||||
function getZoneIndex(latlng) {
|
||||
// Return the index of the polygon where latlng is according to isInPolygon
|
||||
for (let iPolygon = 0; iPolygon < polygons.length; iPolygon++) {
|
||||
if (isInPolygon(latlng, polygons[iPolygon])) {
|
||||
return iPolygon;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function getEventLatLng(e) {
|
||||
// Return the closest latlng to e.latlng among the existing nodes including the first node of currentPolygon
|
||||
// If the closest distance is superior to nodeCatchDistance, then e.latlng is returned
|
||||
const closeNodes = [];
|
||||
// Existing nodes
|
||||
for (const polygon of polygons) {
|
||||
for (const node of polygon) {
|
||||
const d = layerDistance(e.latlng, node);
|
||||
if (d < nodeCatchDistance) {
|
||||
closeNodes.push([d, node]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// First node of currentPolygon
|
||||
if (isDrawing()) {
|
||||
const d = layerDistance(e.latlng, currentPolygon[0]);
|
||||
if (d < nodeCatchDistance) {
|
||||
closeNodes.push([d, currentPolygon[0]]);
|
||||
}
|
||||
}
|
||||
// If there is no close node
|
||||
if (closeNodes.length == 0) {
|
||||
return e.latlng;
|
||||
// Else return the closest close node
|
||||
} else {
|
||||
return closeNodes.reduce( (min, current) => { return current[0] < min[0] ? current : min } )[1];
|
||||
}
|
||||
}
|
||||
|
||||
function handleLeftClick(e) {
|
||||
setHighlightNodes([]);
|
||||
const latlng = getEventLatLng(e);
|
||||
const length = currentPolygon.length;
|
||||
|
||||
// If it is the first node
|
||||
if (!isDrawing()) {
|
||||
// If the point is not in an existing polygon
|
||||
if (getZoneIndex(latlng) == -1) {
|
||||
setCurrentPolygon([latlng]);
|
||||
}
|
||||
|
||||
// If it is the last node
|
||||
} else if (latlngEqual(latlng, currentPolygon[0])) {
|
||||
// If the current polygon is a polygon (at least 3 points)
|
||||
if (length >= 3) {
|
||||
// If the current polygon is not circling an existing polygon
|
||||
for (const polygon of polygons) {
|
||||
// meanPoint exists and is strictly inside polygon
|
||||
const meanPoint = {
|
||||
lat: (polygon[0].lat + polygon[1].lat + polygon[2].lat) / 3,
|
||||
lng: (polygon[0].lng + polygon[1].lng + polygon[2].lng) / 3
|
||||
};
|
||||
if (isInPolygon(meanPoint, currentPolygon)) return;
|
||||
}
|
||||
// Making the new polygon clockwise to simplify some algorithms
|
||||
if (!isClockwise(currentPolygon)) currentPolygon.reverse();
|
||||
addPolygon(currentPolygon);
|
||||
setCurrentPolygon([]);
|
||||
}
|
||||
|
||||
// If it is an intermediate node
|
||||
} else {
|
||||
// Is the polygon closing to early ?
|
||||
for (const point of currentPolygon) if (latlngEqual(point, latlng)) return;
|
||||
// Is the new point making the current polygon intersect with itself ?
|
||||
if (isIntersecting([latlng, currentPolygon[length-1]], currentPolygon, false)) return;
|
||||
// Is the new point inside a polygon ?
|
||||
if (getZoneIndex(latlng) != -1) return;
|
||||
// Is the new point making the current polygon intersect with another polygon ?
|
||||
for (const polygon of polygons) {
|
||||
// Strict intersection
|
||||
if (isIntersecting([latlng, currentPolygon[length-1]], polygon, true)) return;
|
||||
// Intersection by joining two non adjacent nodes of polygon
|
||||
let tab = [-1, -1];
|
||||
for (let i = 0; i < polygon.length; i++) {
|
||||
if (latlngEqual(latlng, polygon[i])) tab[0] = i;
|
||||
if (latlngEqual(currentPolygon[length-1], polygon[i])) tab[1] = i;
|
||||
}
|
||||
if (
|
||||
tab[0] != -1 && tab[1] != -1 &&
|
||||
(tab[0] != (tab[1] + 1) % polygon.length) &&
|
||||
(tab[1] != (tab[0] + 1) % polygon.length)
|
||||
) return;
|
||||
}
|
||||
setCurrentPolygon([...currentPolygon, latlng]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleRightClick(e) {
|
||||
setHighlightNodes([]);
|
||||
// If isDrawing, cancel the currentPolygon
|
||||
if (isDrawing()) {
|
||||
setCurrentPolygon([]);
|
||||
// If not isDrawing, remove the clicked polygon
|
||||
} else {
|
||||
const i = getZoneIndex(e.latlng);
|
||||
if (i != -1) removePolygon(i);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMouseMove(e) {
|
||||
const nodes = [];
|
||||
for (const polygon of polygons) {
|
||||
for (const node of polygon) {
|
||||
if (layerDistance(node, e.latlng) < nodeHighlightDistance && node != currentPolygon[0]) nodes.push(node);
|
||||
}
|
||||
}
|
||||
setHighlightNodes(nodes);
|
||||
}
|
||||
|
||||
return { currentPolygon, highlightNodes, handleLeftClick, handleRightClick, handleMouseMove };
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
import { redirect, usePathname } from "next/navigation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function usePasswordProtect(loginPath, redirectPath, loading, loggedIn) {
|
||||
export default function usePasswordProtect(loginPath, redirectPath, loading, loggedIn) {
|
||||
const path = usePathname();
|
||||
useEffect(() => {
|
||||
if (!loggedIn && !loading && path !== loginPath) {
|
||||
@@ -12,4 +12,4 @@ export function usePasswordProtect(loginPath, redirectPath, loading, loggedIn) {
|
||||
redirect(redirectPath)
|
||||
}
|
||||
}, [loggedIn, loading, path]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import {useEffect, useState} from 'react';
|
||||
import { useSocketListener } from './useSocketListener';
|
||||
import { useLocalStorage } from './useLocalStorage';
|
||||
import { usePathname } from 'next/navigation';
|
||||
"use client";
|
||||
import { useEffect, useState } from 'react';
|
||||
import useSocketListener from './useSocketListener';
|
||||
import useLocalStorage from './useLocalStorage';
|
||||
|
||||
const LOGIN_MESSAGE = "login";
|
||||
const LOGOUT_MESSAGE = "logout";
|
||||
const LOGIN_RESPONSE_MESSAGE = "login_response";
|
||||
|
||||
export function useSocketAuth(socket, passwordName) {
|
||||
export default function useSocketAuth(socket, passwordName) {
|
||||
const [loggedIn, setLoggedIn] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [waitingForResponse, setWaitingForResponse] = useState(true);
|
||||
@@ -50,4 +50,4 @@ export function useSocketAuth(socket, passwordName) {
|
||||
|
||||
|
||||
return {login,logout,password: savedPassword, loggedIn, loading};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { useEffect} from "react";
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export function useSocketListener(socket, event, callback) {
|
||||
export default function useSocketListener(socket, event, callback) {
|
||||
useEffect(() => {
|
||||
socket.on(event,callback);
|
||||
return () => {
|
||||
socket.off(event, callback);
|
||||
}
|
||||
}, []);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user