Nouveau Document Texte
Nouveau Document Texte
const MAPBOX_TOKEN =
'pk.eyJ1IjoiaHlkcm9tb2JpbGUiLCJhIjoiY2x0YWt4MzRhMGtuejJrbWxwM3ZyZm02aiJ9.DIvAxkGuhR
EiJe_OgThF2g';
const DRAW_MODES = {
polygon: 'draw_polygon',
polyline: 'draw_line_string',
marker: 'draw_point',
label: 'draw_label' // mode fictif pour le label
};
const layerIds = [
'gl-draw-polygon-fill-inactive',
'gl-draw-polygon-fill-active',
'gl-draw-polygon-stroke-inactive',
'gl-draw-polygon-stroke-active',
'gl-draw-line-inactive',
'gl-draw-line-active',
'gl-draw-point-inactive',
'gl-draw-point-active'
];
React.useEffect(() => {
const map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/satellite-streets-v12',
accessToken: MAPBOX_TOKEN,
center: [0, 20],
zoom: 1.5,
projection: 'globe'
});
mapRef.current = map;
map.addControl(new mapboxgl.NavigationControl(), 'top-left');
map.on('load', () => {
layerIds.forEach(id => {
if (map.getLayer(id)) {
const prop = id.includes('fill') ? 'fill-color' : id.includes('line') ?
'line-color' : 'circle-color';
map.setPaintProperty(
id,
prop,
['case', ['has', 'color'], ['get', 'color'], POLYGON_COLOR]
);
}
});
});
}, []);
React.useEffect(() => {
if (mode === 'marker') {
setIsMarkerMode(true);
setIsLabelMode(false);
} else if (mode === 'label') {
setIsLabelMode(true);
setIsMarkerMode(false);
} else {
setIsMarkerMode(false);
setIsLabelMode(false);
}
if (!drawRef.current) return;
drawRef.current.changeMode(mode && mode !== 'marker' && mode !== 'label' ?
DRAW_MODES[mode] : 'simple_select');
}, [mode]);
React.useEffect(() => {
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
}
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging]);
return (
<div ref={mapContainerRef} style={{ position: 'relative', width: '100vw',
height: '100vh' }}>
<div
style={{
position: 'absolute',
left: position.x,
top: position.y,
zIndex: 10,
background: 'rgba(255, 255, 255, 0.95)',
padding: '12px 8px',
borderRadius: 16,
display: 'flex',
flexDirection: 'column',
gap: 8,
boxShadow: '0 4px 12px rgba(0,0,0,0.1)',
backdropFilter: 'blur(8px)',
cursor: isDragging ? 'grabbing' : 'default',
userSelect: 'none'
}}
onMouseDown={handleMouseDown}
>
<div
className="toolbar-handle"
style={{
padding: '4px',
marginBottom: '4px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
cursor: 'grab'
}}
>
<span className="material-icons" style={{ color: '#666', fontSize: '20px'
}}>drag_indicator</span>
</div>
{Object.keys(DRAW_MODES).map(key => (
<button
key={key}
onClick={() => setMode(key as keyof typeof DRAW_MODES)}
style={{
padding: '8px',
borderRadius: 12,
border: (mode === key || (key === 'marker' && isMarkerMode) || (key
=== 'label' && isLabelMode)) ? `2px solid ${POLYGON_COLOR}` : '1px solid
rgba(0,0,0,0.1)',
background: (mode === key || (key === 'marker' && isMarkerMode) ||
(key === 'label' && isLabelMode)) ? POLYGON_COLOR : 'rgba(255,255,255,0.9)',
color: (mode === key || (key === 'marker' && isMarkerMode) || (key
=== 'label' && isLabelMode)) ? '#fff' : '#424242',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '44px',
height: '44px',
}}
title={key === 'marker' ? 'Marker' : key === 'label' ? 'Label' :
key.charAt(0).toUpperCase() + key.slice(1)}
>
{key === 'polygon' && <span className="material-icons">draw</span>}
{key === 'polyline' && <span
className="material-icons">timeline</span>}
{key === 'marker' && <span className="material-icons">flag</span>}
{key === 'label' && <span
style={{fontWeight:'bold',fontSize:18}}>ABC</span>}
</button>
))}
<div style={{ height: '1px', background: 'rgba(0,0,0,0.1)', margin: '4px 0'
}} />
<button
onClick={() => setMode(null)}
style={{
padding: '8px',
borderRadius: 12,
border: !mode ? `2px solid ${POLYGON_COLOR}` : '1px solid
rgba(0,0,0,0.1)',
background: !mode ? POLYGON_COLOR : 'rgba(255,255,255,0.9)',
color: !mode ? '#fff' : '#424242',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '44px',
height: '44px',
}}
title="Sélection"
>
<span className="material-icons">select_all</span>
</button>
<button
onClick={clearAllMarkers}
style={{
padding: '8px',
borderRadius: 12,
border: '1px solid #1976d2',
background: '#1976d2',
color: '#fff',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '44px',
height: '44px',
}}
title="Effacer tous les markers"
>
<span className="material-icons">location_off</span>
</button>
<button
onClick={clearAllLabels}
style={{
padding: '8px',
borderRadius: 12,
border: '1px solid #4CAF50',
background: '#4CAF50',
color: '#fff',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '44px',
height: '44px',
}}
title="Effacer tous les labels"
>
<span className="material-icons">text_fields</span>
</button>
</div>
{labelInput && (
<input
autoFocus
style={{
position: 'absolute',
left: labelInput.x,
top: labelInput.y,
transform: 'translate(-50%, -100%)',
zIndex: 1000,
fontSize: 15,
fontWeight: 'bold',
borderRadius: 6,
border: '1px solid #2196F3',
padding: '2px 8px',
background: '#fff',
color: '#222',
boxShadow: '0 2px 6px rgba(0,0,0,0.15)'
}}
value={labelInputValue}
onChange={e => setLabelInputValue(e.target.value)}
onBlur={handleLabelInputSubmit}
onKeyDown={e => {
if (e.key === 'Enter') handleLabelInputSubmit();
if (e.key === 'Escape') { setLabelInput(null);
setLabelInputValue(''); }
}}
placeholder="Entrer le texte du label..."
/>
)}
<div id="map" style={{ width: '100%', height: '100%' }} />
</div>
);
}