Fixed Viewport

This commit is contained in:
lokeshramchand-ctrl 2025-06-25 18:38:22 +05:30
parent fc0c6b1b1f
commit 1c4cf0b8d4
2 changed files with 552 additions and 152 deletions

View file

@ -0,0 +1,27 @@
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#root {
width: 100%;
height: 100%;
}
/* For your map container specifically */
.map-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
/* Ensure OL map gets proper dimensions */
.ol-viewport {
width: 100% !important;
height: 100% !important;
}

View file

@ -7,33 +7,42 @@ import { fromLonLat } from 'ol/proj';
import { Coordinate } from 'ol/coordinate';
import VectorLayer from 'ol/layer/Vector';
import { layerConfigs } from '../../Methods/Layers';
import { loadAndRenderGeoJsonLayer } from '../../Methods/GeoJson_Load'
import { loadAndRenderGeoJsonLayer } from '../../Methods/GeoJson_Load';
import { addMarker } from '../../Methods/Marker';
const OpenLayersMap = () => {
const [term, setTerm] = useState<string>('');
const [address, setAddress] = useState();
const [address, setAddress] = useState<any>();
const [layerVisibility, setLayerVisibility] = useState<Record<string, boolean>>({});
const [searchCompleted, setSearchCompleted] = useState(false);
const [sidebarOpen, setSidebarOpen] = useState(true);
const [isMobile, setIsMobile] = useState(window.innerWidth < 768);
// Check for mobile view
useEffect(() => {
const handleResize = () => {
setIsMobile(window.innerWidth < 768);
if (window.innerWidth >= 768) {
setSidebarOpen(true);
}
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
// Submit Button Logic
const submitForm = async (event: React.FormEvent<HTMLFormElement>) => {
// Preventing the page from reloading
event.preventDefault();
const response = await fetch(`https://nominatim.openstreetmap.org/search?q=${term}&format=json&polygon=1&addressdetails=1`);
const json = await response.json();
console.log(json);
setAddress(json);
console.log(address);
setSearchCompleted(true);
// Initialize all layers as visible
const initialVisibility = Object.fromEntries(
layerConfigs.map(layer => [layer.topic, true])
);
setLayerVisibility(initialVisibility);
alert(term);
}
const mapDivRef = useRef<HTMLDivElement>(null);
@ -102,87 +111,413 @@ const OpenLayersMap = () => {
}
}, [address]);
// UI
return (
<div style={{ display: 'flex', height: '100vh', width: '100vw' }}>
{/* Sidebar */}
<div style={{
width: '320px',
display: 'flex',
flexDirection: 'column',
height: '100vh',
width: '100vw',
fontFamily: "'Poppins', sans-serif",
backgroundColor: '#f8f9fa',
borderRight: '1px solid #dee2e6',
padding: '20px',
overflowY: 'auto',
boxShadow: '2px 0 5px rgba(0,0,0,0.1)'
overflow: 'hidden'
}}>
<h3 style={{
margin: '0 0 20px 0',
color: '#333',
{/* Google Fonts Link */}
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
rel="stylesheet"
/>
<style>
{`
/* Fix for black borders */
body, html, #root {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
}
/* Map container fixes */
.map-container {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-color: #fff;
}
/* Layer list improvements */
.layer-item {
padding: 8px 12px;
margin: 2px 0;
font-size: 13px;
cursor: pointer;
transition: background-color 0.2s;
}
.layer-item:hover {
background-color: #f0f0f0;
}
/* Custom scrollbar */
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #f1f1f1;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #a1a1a1;
}
/* Animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Responsive styles */
@media (max-width: 768px) {
.sidebar {
position: absolute !important;
width: 280px !important;
left: ${sidebarOpen ? '0' : '-280px'};
z-index: 1000;
transition: left 0.3s ease;
height: calc(100vh - 72px) !important;
}
.map-container {
width: 100% !important;
}
.nav-buttons {
display: none !important;
}
.mobile-menu-btn {
display: block !important;
}
.header-content {
padding: 0 16px !important;
}
.search-container {
padding: 16px !important;
}
}
@media (max-width: 480px) {
.header-title {
font-size: 18px !important;
}
.sidebar {
width: 260px !important;
left: ${sidebarOpen ? '0' : '-260px'};
}
.coordinate-display {
bottom: 16px !important;
left: 16px !important;
right: 16px !important;
width: auto !important;
}
}
`}
</style>
{/* Header */}
<header style={{
backgroundColor: '#ffffff',
borderBottom: '1px solid #e9ecef',
boxShadow: '0 2px 12px rgba(0, 0, 0, 0.08)',
padding: '0 32px',
height: '72px',
minHeight: '72px',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
position: 'relative',
zIndex: 1000,
flexShrink: 0
}}>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '12px'
}}>
{/* Mobile menu button - hidden on desktop */}
<button
className="mobile-menu-btn"
onClick={() => setSidebarOpen(!sidebarOpen)}
style={{
display: 'none',
background: 'none',
border: 'none',
fontSize: '20px',
cursor: 'pointer',
padding: '8px',
color: '#2c3e50'
}}
>
☰
</button>
<div style={{
width: '40px',
height: '40px',
background: 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)',
borderRadius: '12px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 4px 12px rgba(44, 62, 80, 0.15)'
}}>
<span style={{
color: 'white',
fontSize: '18px',
fontWeight: '600'
fontWeight: '700'
}}>M</span>
</div>
<span className="header-title" style={{
fontSize: '24px',
fontWeight: '600',
color: '#2c3e50',
letterSpacing: '-0.5px'
}}>
Map Layers
MapExplorer
</span>
</div>
{/* Navigation - hidden on mobile */}
<nav className="nav-buttons" style={{
display: 'flex',
alignItems: 'center',
gap: '8px'
}}>
{['Home', 'Map', 'About', 'Contact'].map((item, index) => (
<button
key={item}
style={{
padding: '12px 20px',
backgroundColor: index === 1 ? '#2c3e50' : 'transparent',
color: index === 1 ? 'white' : '#495057',
border: 'none',
borderRadius: '12px',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
boxShadow: index === 1 ? '0 4px 12px rgba(44, 62, 80, 0.2)' : 'none',
}}
>
{item}
</button>
))}
</nav>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '16px'
}}>
<button style={{
padding: '10px',
backgroundColor: '#f8f9fa',
border: 'none',
borderRadius: '10px',
cursor: 'pointer',
color: '#6c757d',
fontSize: '16px',
transition: 'all 0.3s ease',
}}>
🔔
</button>
<div style={{
width: '36px',
height: '36px',
background: 'linear-gradient(135deg, #6c757d 0%, #8b949e 100%)',
borderRadius: '50%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
color: 'white',
fontSize: '14px',
fontWeight: '600',
cursor: 'pointer',
boxShadow: '0 3px 8px rgba(108, 117, 125, 0.15)',
}}>
U
</div>
</div>
</header>
{/* Main Content */}
<div style={{
display: 'flex',
height: 'calc(100vh - 72px)',
width: '100vw',
overflow: 'hidden',
position: 'relative'
}}>
{/* Sidebar with responsive behavior */}
<div className="sidebar custom-scrollbar" style={{
width: '360px',
backgroundColor: '#ffffff',
borderRight: '1px solid #e9ecef',
padding: '24px',
overflowY: 'auto',
overflowX: 'hidden',
boxShadow: '4px 0 16px rgba(0,0,0,0.06)',
flexShrink: 0
}}>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
marginBottom: '24px'
}}>
<div style={{
width: '8px',
height: '32px',
background: 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)',
borderRadius: '4px'
}} />
<h3 style={{
margin: '0',
color: '#2c3e50',
fontSize: '20px',
fontWeight: '600',
letterSpacing: '-0.3px'
}}>
Map Controls
</h3>
</div>
{/* Search Form */}
<form onSubmit={submitForm} style={{ marginBottom: '20px' }}>
<div className="search-container" style={{
background: 'linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%)',
padding: '20px',
borderRadius: '16px',
marginBottom: '24px',
border: '1px solid #e9ecef',
boxShadow: '0 2px 8px rgba(0,0,0,0.04)'
}}>
<form onSubmit={submitForm}>
<input
value={term}
onChange={(e) => setTerm(e.target.value)}
type="text"
placeholder="Enter address to search"
placeholder="Search for any location..."
style={{
width: '100%',
padding: '10px',
border: '1px solid #ddd',
borderRadius: '4px',
marginBottom: '10px',
fontSize: '14px'
padding: '14px 16px',
border: '1px solid #dee2e6',
borderRadius: '12px',
marginBottom: '12px',
fontSize: '14px',
fontFamily: "'Poppins', sans-serif",
backgroundColor: 'white',
boxShadow: '0 2px 4px rgba(0,0,0,0.04)',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
boxSizing: 'border-box',
outline: 'none'
}}
/>
<button
type="submit"
style={{
width: '100%',
padding: '10px',
backgroundColor: '#007bff',
padding: '14px',
background: 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)',
color: 'white',
border: 'none',
borderRadius: '4px',
borderRadius: '12px',
cursor: 'pointer',
fontSize: '14px',
fontWeight: '500'
fontWeight: '600',
fontFamily: "'Poppins', sans-serif",
boxShadow: '0 4px 12px rgba(44, 62, 80, 0.2)',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
}}
>
Search
🔍 Search Location
</button>
</form>
</div>
{/* Layer Toggle List */}
<div>
<h4 style={{
margin: '0 0 15px 0',
color: '#666',
fontSize: '14px',
fontWeight: '500',
textTransform: 'uppercase',
letterSpacing: '0.5px'
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: '16px'
}}>
Available Layers ({layerConfigs.length})
<h4 style={{
margin: '0',
color: '#495057',
fontSize: '16px',
fontWeight: '600'
}}>
Data Layers
</h4>
<span style={{
background: 'linear-gradient(135deg, #e9ecef 0%, #f8f9fa 100%)',
color: '#6c757d',
padding: '4px 8px',
borderRadius: '12px',
fontSize: '12px',
fontWeight: '500',
boxShadow: '0 1px 3px rgba(0,0,0,0.05)'
}}>
{layerConfigs.length}
</span>
</div>
{layerConfigs.map((layer) => (
{layerConfigs.map((layer, _index) => (
<div key={layer.topic} style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '10px 0',
borderBottom: '1px solid #eee'
padding: '16px',
marginBottom: '8px',
background: layerVisibility[layer.topic]
? 'linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%)'
: 'white',
border: `1px solid ${layerVisibility[layer.topic] ? '#2c3e50' : '#e9ecef'}`,
borderRadius: '12px',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
boxShadow: layerVisibility[layer.topic]
? '0 4px 8px rgba(44, 62, 80, 0.1)'
: '0 1px 3px rgba(0,0,0,0.05)',
cursor: 'pointer'
}}>
<span style={{
fontSize: '13px',
color: '#333',
fontSize: '14px',
color: '#2c3e50',
flex: 1,
marginRight: '10px'
marginRight: '12px',
fontWeight: '500'
}}>
{formatLayerName(layer.topic)}
</span>
@ -191,8 +526,8 @@ const OpenLayersMap = () => {
<label style={{
position: 'relative',
display: 'inline-block',
width: '44px',
height: '24px'
width: '48px',
height: '26px'
}}>
<input
type="checkbox"
@ -207,23 +542,26 @@ const OpenLayersMap = () => {
left: 0,
right: 0,
bottom: 0,
backgroundColor: layerVisibility[layer.topic] ? '#007bff' : '#ccc',
borderRadius: '24px',
transition: '0.3s',
background: layerVisibility[layer.topic]
? 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)'
: '#dee2e6',
borderRadius: '26px',
transition: '0.3s cubic-bezier(0.4, 0, 0.2, 1)',
display: 'flex',
alignItems: 'center'
alignItems: 'center',
boxShadow: 'inset 0 1px 3px rgba(0,0,0,0.1)'
}}>
<span style={{
position: 'absolute',
content: '',
height: '18px',
width: '18px',
left: layerVisibility[layer.topic] ? '23px' : '3px',
height: '20px',
width: '20px',
left: layerVisibility[layer.topic] ? '25px' : '3px',
bottom: '3px',
backgroundColor: 'white',
borderRadius: '50%',
transition: '0.3s',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
transition: '0.3s cubic-bezier(0.4, 0, 0.2, 1)',
boxShadow: '0 2px 6px rgba(0,0,0,0.15)'
}} />
</span>
</label>
@ -231,9 +569,13 @@ const OpenLayersMap = () => {
{!searchCompleted && (
<span style={{
fontSize: '11px',
color: '#999',
fontStyle: 'italic'
fontSize: '12px',
color: '#adb5bd',
fontStyle: 'italic',
backgroundColor: '#f8f9fa',
padding: '4px 8px',
borderRadius: '8px',
boxShadow: '0 1px 2px rgba(0,0,0,0.05)'
}}>
Search first
</span>
@ -241,32 +583,63 @@ const OpenLayersMap = () => {
</div>
))}
</div>
</div>
{/* Map Container */}
<div style={{ flex: 1, position: 'relative' }}>
<div ref={mapDivRef} style={{ width: '100%', height: '100%' }} />
{clickedCoordinate && (
<div style={{
position: 'absolute',
bottom: '20px',
left: '20px',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
color: 'white',
padding: '10px 15px',
borderRadius: '4px',
fontSize: '12px',
fontFamily: 'monospace'
<div className="map-container" style={{
flex: 1,
position: 'relative',
backgroundColor: '#ffffff',
}}>
Coordinates: {clickedCoordinate[0].toFixed(2)} / {clickedCoordinate[1].toFixed(2)}
{/* Overlay for mobile when sidebar is open */}
{isMobile && sidebarOpen && (
<div
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
zIndex: 999,
transition: 'opacity 0.3s ease'
}}
onClick={() => setSidebarOpen(false)}
/>
)}
<div ref={mapDivRef} style={{
width: '100%',
height: '100%',
borderRadius: '0',
overflow: 'hidden'
}} />
{/* Coordinate Display */}
{clickedCoordinate && (
<div className="coordinate-display" style={{
position: 'absolute',
bottom: '24px',
left: '24px',
background: 'rgba(44, 62, 80, 0.9)',
color: 'white',
padding: '12px 16px',
borderRadius: '12px',
fontSize: '13px',
fontFamily: "'Poppins', monospace",
fontWeight: '500',
boxShadow: '0 8px 32px rgba(44, 62, 80, 0.3)',
backdropFilter: 'blur(10px)',
border: '1px solid rgba(255, 255, 255, 0.1)',
animation: 'fadeInUp 0.3s ease-out'
}}>
📍 Coordinates: {clickedCoordinate[0].toFixed(4)}, {clickedCoordinate[1].toFixed(4)}
</div>
)}
</div>
</div>
</div>
);
};
}
export default OpenLayersMap;