Spaces:
Sleeping
Implement comprehensive mobile responsiveness for wind visualization
Browse filesMobile map improvements:
- Changed map height from 600px to 80vh for better mobile scaling
- Added responsive CSS for forecast timeline controls
- Mobile forecast bar: larger buttons, better touch targets
- Enhanced timeline visibility with bigger text and buttons
Mobile forecast controls:
- Tablets (768px): 40px nav buttons, 35px hour buttons, improved spacing
- Phones (480px): 35px nav buttons, 30px hour buttons, compact layout
- Full-width forecast bar on mobile with proper padding
- Better touch targets for hour selection buttons
Mobile interface optimization:
- Map takes 85-95vh on mobile (vs 600px fixed height)
- Responsive Gradio container with minimal padding
- Portrait mode: hides controls on very small screens for max map space
- Wind control buttons properly sized for mobile interaction
Result: Forecast timeline fully visible and usable on all mobile devices
with significantly larger map area for better wind visualization.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
@@ -481,7 +481,7 @@ def create_wind_map(region="global", forecast_mode=False):
|
|
481 |
zoom_start=zoom,
|
482 |
control_scale=True,
|
483 |
width='100%',
|
484 |
-
height='
|
485 |
)
|
486 |
|
487 |
# Add light theme option (but don't make it active by default)
|
@@ -505,9 +505,108 @@ def create_wind_map(region="global", forecast_mode=False):
|
|
505 |
forecast_data = None
|
506 |
log_step(6, f"Current data ready: 10m={len(wind_data_10m)} components, 100m={len(wind_data_100m)} components")
|
507 |
|
508 |
-
# Add Leaflet-Velocity from CDN
|
509 |
velocity_css = """
|
510 |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
511 |
"""
|
512 |
m.get_root().html.add_child(Element(velocity_css))
|
513 |
|
@@ -1282,7 +1381,27 @@ def update_visualization(region, forecast_mode=False):
|
|
1282 |
_processing_state["is_processing"] = False
|
1283 |
|
1284 |
# Create Gradio interface
|
1285 |
-
with gr.Blocks(title="Wind Particle Visualization"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1286 |
|
1287 |
gr.Markdown("""
|
1288 |
# 🌪️ ECMWF Wind Visualization with Forecast - v4.0 LIVE
|
|
|
481 |
zoom_start=zoom,
|
482 |
control_scale=True,
|
483 |
width='100%',
|
484 |
+
height='80vh' # Use viewport height for better mobile scaling
|
485 |
)
|
486 |
|
487 |
# Add light theme option (but don't make it active by default)
|
|
|
505 |
forecast_data = None
|
506 |
log_step(6, f"Current data ready: 10m={len(wind_data_10m)} components, 100m={len(wind_data_100m)} components")
|
507 |
|
508 |
+
# Add Leaflet-Velocity from CDN with mobile-responsive CSS
|
509 |
velocity_css = """
|
510 |
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
511 |
+
<style>
|
512 |
+
/* Mobile responsiveness for forecast controls */
|
513 |
+
@media (max-width: 768px) {
|
514 |
+
.forecast-controls {
|
515 |
+
bottom: 5px !important;
|
516 |
+
left: 5px !important;
|
517 |
+
right: 5px !important;
|
518 |
+
transform: none !important;
|
519 |
+
width: auto !important;
|
520 |
+
padding: 15px !important;
|
521 |
+
font-size: 14px !important;
|
522 |
+
}
|
523 |
+
.forecast-timeline {
|
524 |
+
flex-wrap: wrap !important;
|
525 |
+
justify-content: center !important;
|
526 |
+
gap: 8px !important;
|
527 |
+
}
|
528 |
+
.forecast-hour-btn {
|
529 |
+
min-width: 35px !important;
|
530 |
+
padding: 8px 10px !important;
|
531 |
+
font-size: 12px !important;
|
532 |
+
margin: 2px !important;
|
533 |
+
}
|
534 |
+
.forecast-prev, .forecast-next {
|
535 |
+
width: 40px !important;
|
536 |
+
height: 40px !important;
|
537 |
+
font-size: 18px !important;
|
538 |
+
}
|
539 |
+
.forecast-hour-display {
|
540 |
+
font-size: 16px !important;
|
541 |
+
min-width: 35px !important;
|
542 |
+
}
|
543 |
+
.wind-controls {
|
544 |
+
top: 5px !important;
|
545 |
+
right: 5px !important;
|
546 |
+
padding: 8px !important;
|
547 |
+
}
|
548 |
+
.wind-controls button {
|
549 |
+
width: 140px !important;
|
550 |
+
padding: 8px !important;
|
551 |
+
font-size: 12px !important;
|
552 |
+
}
|
553 |
+
/* Make map container fill screen on mobile */
|
554 |
+
.leaflet-container {
|
555 |
+
height: 85vh !important;
|
556 |
+
}
|
557 |
+
}
|
558 |
+
|
559 |
+
/* Small mobile phones */
|
560 |
+
@media (max-width: 480px) {
|
561 |
+
.forecast-controls {
|
562 |
+
padding: 10px 8px !important;
|
563 |
+
font-size: 12px !important;
|
564 |
+
}
|
565 |
+
.forecast-hour-btn {
|
566 |
+
min-width: 30px !important;
|
567 |
+
padding: 6px 8px !important;
|
568 |
+
font-size: 11px !important;
|
569 |
+
}
|
570 |
+
.forecast-prev, .forecast-next {
|
571 |
+
width: 35px !important;
|
572 |
+
height: 35px !important;
|
573 |
+
font-size: 16px !important;
|
574 |
+
}
|
575 |
+
.wind-controls {
|
576 |
+
padding: 6px !important;
|
577 |
+
}
|
578 |
+
.wind-controls button {
|
579 |
+
width: 120px !important;
|
580 |
+
padding: 6px !important;
|
581 |
+
font-size: 11px !important;
|
582 |
+
}
|
583 |
+
.leaflet-container {
|
584 |
+
height: 90vh !important;
|
585 |
+
}
|
586 |
+
/* Mobile Gradio interface improvements */
|
587 |
+
.gradio-container {
|
588 |
+
max-width: 100% !important;
|
589 |
+
padding: 0 !important;
|
590 |
+
}
|
591 |
+
.gr-row {
|
592 |
+
flex-direction: column !important;
|
593 |
+
}
|
594 |
+
.gr-column {
|
595 |
+
width: 100% !important;
|
596 |
+
max-width: 100% !important;
|
597 |
+
}
|
598 |
+
}
|
599 |
+
|
600 |
+
/* Hide Gradio controls on very small screens to maximize map space */
|
601 |
+
@media (max-width: 480px) and (orientation: portrait) {
|
602 |
+
.gradio-container .gr-row:first-child {
|
603 |
+
display: none !important;
|
604 |
+
}
|
605 |
+
.leaflet-container {
|
606 |
+
height: 95vh !important;
|
607 |
+
}
|
608 |
+
}
|
609 |
+
</style>
|
610 |
"""
|
611 |
m.get_root().html.add_child(Element(velocity_css))
|
612 |
|
|
|
1381 |
_processing_state["is_processing"] = False
|
1382 |
|
1383 |
# Create Gradio interface
|
1384 |
+
with gr.Blocks(title="Wind Particle Visualization", css="""
|
1385 |
+
@media (max-width: 768px) {
|
1386 |
+
.gradio-container {
|
1387 |
+
padding: 8px !important;
|
1388 |
+
}
|
1389 |
+
.gr-column {
|
1390 |
+
min-height: auto !important;
|
1391 |
+
}
|
1392 |
+
.gradio-html {
|
1393 |
+
min-height: 85vh !important;
|
1394 |
+
}
|
1395 |
+
}
|
1396 |
+
@media (max-width: 480px) {
|
1397 |
+
.gradio-container {
|
1398 |
+
padding: 4px !important;
|
1399 |
+
}
|
1400 |
+
.gradio-html {
|
1401 |
+
min-height: 90vh !important;
|
1402 |
+
}
|
1403 |
+
}
|
1404 |
+
""") as app:
|
1405 |
|
1406 |
gr.Markdown("""
|
1407 |
# 🌪️ ECMWF Wind Visualization with Forecast - v4.0 LIVE
|