Improvements on maps

This commit is contained in:
Sebastien Riviere
2025-08-31 17:33:18 +02:00
parent e5d90d824e
commit d088253758
13 changed files with 264 additions and 184 deletions

View File

@@ -1,14 +1,67 @@
import { useEffect, useState } from 'react';
import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
export function List({array, children}) {
// The elements of array have to be identified by a field id
// TODO : change key
return (
<div className='w-full h-full bg-gray-300 overflow-y-auto'>
<ul className="w-full p-1 divide-y-4 divide-gray-300">
<div className='w-full h-full bg-gray-300 overflow-y-scroll'>
<ul className="w-full p-1 pb-0">
{array.map((elem, i) => (
<li className="w-full" key={elem.id}>
<li className="w-full" key={elem.id ?? i}>
{children(elem, i)}
<div className="w-full h-1"/>
</li>
))}
</ul>
</div>
);
}
export function ReorderList({droppableId, array, setArray, children}) {
const [arrayLocal, setArrayLocal] = useState(array);
useEffect(() => {
setArrayLocal(array);
}, [array])
function reorder(list, startIndex, endIndex) {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
function onDragEnd(result) {
if (!result.destination) return;
if (result.destination.index === result.source.index) return;
const newArray = reorder(array, result.source.index, result.destination.index);
setArrayLocal(newArray);
setArray(newArray);
}
return (
<DragDropContext onDragEnd={onDragEnd} >
<Droppable droppableId={droppableId}>
{provided => (
<div className='w-full h-full bg-gray-300 overflow-y-scroll' ref={provided.innerRef} {...provided.droppableProps}>
<ul className="w-full p-1 pb-0">
{arrayLocal.map((elem, i) => (
<li className='w-full' key={elem.id}>
<Draggable draggableId={elem.id.toString()} index={i}>
{provided => (
<div className='w-full' {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef}>
{children(elem, i)}
<div className="w-full h-1"/>
</div>
)}
</Draggable>
</li>
))}
</ul>
{provided.placeholder}
</div>
)}
</Droppable>
</DragDropContext>
);
}

View File

@@ -1,17 +1,28 @@
import { useEffect, useState } from "react";
import { useMap } from "react-leaflet";
import { MapContainer, TileLayer, useMap } from "react-leaflet";
import "leaflet/dist/leaflet.css";
export function MapPan(props) {
const DEFAULT_ZOOM = 14;
const mapStyles = {
default: {
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
},
satellite: {
url: "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
attribution: 'Tiles &copy; Esri'
},
}
export function MapPan({center, zoom}) {
const map = useMap();
const [initialized, setInitialized] = useState(false);
useEffect(() => {
if (!initialized && props.center) {
map.flyTo(props.center, props.zoom, { animate: false });
setInitialized(true)
if (center, zoom) {
map.flyTo(center, zoom, { animate: false });
}
}, [props.center]);
}, [center, zoom]);
return null;
}
@@ -21,6 +32,8 @@ export function MapEventListener({ onLeftClick, onRightClick, onMouseMove }) {
// Handle the mouse click left
useEffect(() => {
if (!onLeftClick) return;
let moved = false;
let downButton = null;
@@ -55,6 +68,7 @@ export function MapEventListener({ onLeftClick, onRightClick, onMouseMove }) {
// Handle the right click
useEffect(() => {
if (!onRightClick) return;
const handleMouseDown = (e) => {
if (e.originalEvent.button == 2) {
@@ -71,6 +85,8 @@ export function MapEventListener({ onLeftClick, onRightClick, onMouseMove }) {
// Handle the mouse move
useEffect(() => {
if (!onMouseMove) return;
map.on('mousemove', onMouseMove);
return () => {
@@ -85,4 +101,42 @@ export function MapEventListener({ onLeftClick, onRightClick, onMouseMove }) {
container.addEventListener('contextmenu', preventContextMenu);
return () => container.removeEventListener('contextmenu', preventContextMenu);
}, []);
return null;
}
export function CustomMapContainer({mapStyle, children}) {
const [location, setLocation] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
if (!navigator.geolocation) {
console.log('Geolocation not supported');
return;
}
navigator.geolocation.getCurrentPosition(
(pos) => {
setLocation([pos.coords.latitude, pos.coords.longitude]);
setLoading(false);
},
(err) => console.log("Error :", err),
{
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
}
);
}, []);
if (loading) {
return <div className="w-full h-full"/>
}
return (
<MapContainer className='w-full h-full' center={location} zoom={DEFAULT_ZOOM} scrollWheelZoom={true}>
<TileLayer url={(mapStyle || mapStyles.default).url} attribution={(mapStyle || mapStyles.default).attribution}/>
{children}
</MapContainer>
)
}