feat: simplify date range selection by removing modal inputs and enhance station metadata display with value boxes.
Browse files
server.R
CHANGED
|
@@ -83,12 +83,8 @@ server <- function(input, output, session) {
|
|
| 83 |
inputs_to_toggle <- c(
|
| 84 |
"station_selector",
|
| 85 |
"date_range",
|
| 86 |
-
"modal_date_start",
|
| 87 |
-
"modal_date_end",
|
| 88 |
"zoom_home",
|
| 89 |
-
"close_panel",
|
| 90 |
"main_nav",
|
| 91 |
-
"download_data",
|
| 92 |
"download_hourly"
|
| 93 |
)
|
| 94 |
|
|
@@ -332,74 +328,12 @@ server <- function(input, output, session) {
|
|
| 332 |
# Sync dropdown
|
| 333 |
updateSelectizeInput(session, "station_selector", selected = id_val)
|
| 334 |
|
| 335 |
-
# Trigger Panel
|
| 336 |
-
output$show_details_panel <- reactive(TRUE)
|
| 337 |
-
outputOptions(output, "show_details_panel", suspendWhenHidden = FALSE)
|
| 338 |
-
|
| 339 |
# NOTE: Date reset removed to preserve user context
|
| 340 |
})
|
| 341 |
|
| 342 |
# --- Date Synchronization (Sliding Window & Bi-Directional) ---
|
| 343 |
|
| 344 |
-
#
|
| 345 |
-
observeEvent(input$modal_date_start, {
|
| 346 |
-
req(input$modal_date_start, input$modal_date_end)
|
| 347 |
-
|
| 348 |
-
# Calculate current diff
|
| 349 |
-
diff <- as.numeric(difftime(input$modal_date_end, input$modal_date_start, units = "days"))
|
| 350 |
-
|
| 351 |
-
# Validation Logic
|
| 352 |
-
if (diff > 366) {
|
| 353 |
-
freezeReactiveValue(input, "modal_date_end")
|
| 354 |
-
new_end <- as.Date(input$modal_date_start) + 366
|
| 355 |
-
updateDateInput(session, "modal_date_end", value = new_end)
|
| 356 |
-
# Update tracked state to prevent sidebar from incorrectly detecting changes
|
| 357 |
-
previous_date_range(c(input$modal_date_start, new_end))
|
| 358 |
-
} else if (diff < 28) {
|
| 359 |
-
freezeReactiveValue(input, "modal_date_end")
|
| 360 |
-
new_end <- as.Date(input$modal_date_start) + 28
|
| 361 |
-
updateDateInput(session, "modal_date_end", value = new_end)
|
| 362 |
-
# Update tracked state
|
| 363 |
-
previous_date_range(c(input$modal_date_start, new_end))
|
| 364 |
-
} else {
|
| 365 |
-
# Valid range (28-366 checks pass)
|
| 366 |
-
# Update tracked state before syncing to sidebar
|
| 367 |
-
previous_date_range(c(input$modal_date_start, input$modal_date_end))
|
| 368 |
-
# Sync to Sidebar
|
| 369 |
-
updateDateRangeInput(session, "date_range", start = input$modal_date_start, end = input$modal_date_end)
|
| 370 |
-
}
|
| 371 |
-
})
|
| 372 |
-
|
| 373 |
-
observeEvent(input$modal_date_end, {
|
| 374 |
-
req(input$modal_date_start, input$modal_date_end)
|
| 375 |
-
|
| 376 |
-
# Calculate current diff
|
| 377 |
-
diff <- as.numeric(difftime(input$modal_date_end, input$modal_date_start, units = "days"))
|
| 378 |
-
|
| 379 |
-
# Validation Logic (Adjust Start Date)
|
| 380 |
-
if (diff > 366) {
|
| 381 |
-
freezeReactiveValue(input, "modal_date_start")
|
| 382 |
-
new_start <- as.Date(input$modal_date_end) - 366
|
| 383 |
-
updateDateInput(session, "modal_date_start", value = new_start)
|
| 384 |
-
# Update tracked state
|
| 385 |
-
previous_date_range(c(new_start, input$modal_date_end))
|
| 386 |
-
} else if (diff < 28) {
|
| 387 |
-
freezeReactiveValue(input, "modal_date_start")
|
| 388 |
-
# If diff < 28, we need to push start back to ensure at least 28 days
|
| 389 |
-
new_start <- as.Date(input$modal_date_end) - 28
|
| 390 |
-
updateDateInput(session, "modal_date_start", value = new_start)
|
| 391 |
-
# Update tracked state
|
| 392 |
-
previous_date_range(c(new_start, input$modal_date_end))
|
| 393 |
-
} else {
|
| 394 |
-
# Valid range
|
| 395 |
-
# Update tracked state before syncing to sidebar
|
| 396 |
-
previous_date_range(c(input$modal_date_start, input$modal_date_end))
|
| 397 |
-
# Sync to Sidebar
|
| 398 |
-
updateDateRangeInput(session, "date_range", start = input$modal_date_start, end = input$modal_date_end)
|
| 399 |
-
}
|
| 400 |
-
})
|
| 401 |
-
|
| 402 |
-
# 2. Sync Sidebar -> Panel (and enforce 366 days on sidebar with bi-directional detection)
|
| 403 |
observeEvent(input$date_range, {
|
| 404 |
req(input$date_range)
|
| 405 |
d_start <- input$date_range[1]
|
|
@@ -427,7 +361,6 @@ server <- function(input, output, session) {
|
|
| 427 |
|
| 428 |
if (end_changed && !start_changed) {
|
| 429 |
# User changed end date -> adjust start date
|
| 430 |
-
# Logic: If diff > 366, pull start to (end - 366). If diff < 28, push start to (end - 28)
|
| 431 |
target_diff <- if (diff > 366) 366 else 28
|
| 432 |
new_start <- d_end - target_diff
|
| 433 |
|
|
@@ -436,9 +369,6 @@ server <- function(input, output, session) {
|
|
| 436 |
|
| 437 |
# Update tracked state
|
| 438 |
previous_date_range(c(new_start, d_end))
|
| 439 |
-
# Sync to Panel
|
| 440 |
-
updateDateInput(session, "modal_date_start", value = new_start)
|
| 441 |
-
updateDateInput(session, "modal_date_end", value = d_end)
|
| 442 |
} else {
|
| 443 |
# User changed start date (or both) -> adjust end date
|
| 444 |
target_diff <- if (diff > 366) 366 else 28
|
|
@@ -449,19 +379,10 @@ server <- function(input, output, session) {
|
|
| 449 |
|
| 450 |
# Update tracked state
|
| 451 |
previous_date_range(c(d_start, new_end))
|
| 452 |
-
# Sync to Panel
|
| 453 |
-
updateDateInput(session, "modal_date_start", value = d_start)
|
| 454 |
-
updateDateInput(session, "modal_date_end", value = new_end)
|
| 455 |
}
|
| 456 |
} else {
|
| 457 |
# Update tracked state
|
| 458 |
previous_date_range(c(d_start, d_end))
|
| 459 |
-
# Distinct check to break loops
|
| 460 |
-
# Only update panel if it's different to avoid circularity
|
| 461 |
-
if (!isTRUE(all.equal(input$modal_date_start, d_start)) || !isTRUE(all.equal(input$modal_date_end, d_end))) {
|
| 462 |
-
updateDateInput(session, "modal_date_start", value = d_start)
|
| 463 |
-
updateDateInput(session, "modal_date_end", value = d_end)
|
| 464 |
-
}
|
| 465 |
}
|
| 466 |
})
|
| 467 |
|
|
@@ -482,7 +403,8 @@ server <- function(input, output, session) {
|
|
| 482 |
|
| 483 |
# Initial Trigger (Debounced Window)
|
| 484 |
window_reactive <- reactive({
|
| 485 |
-
|
|
|
|
| 486 |
})
|
| 487 |
window_debounced <- window_reactive %>% debounce(500)
|
| 488 |
|
|
@@ -865,6 +787,10 @@ server <- function(input, output, session) {
|
|
| 865 |
loading_diagnostics(paste0("Success: ", nrow(clean_df), " rows loaded."))
|
| 866 |
loading_status(FALSE)
|
| 867 |
fetch_stage(0)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 868 |
# Show rendering message and then unfreeze after delay
|
| 869 |
session$sendCustomMessage("freezeUI", list(text = "Rendering plots..."))
|
| 870 |
later::later(function() {
|
|
@@ -896,38 +822,11 @@ server <- function(input, output, session) {
|
|
| 896 |
})
|
| 897 |
outputOptions(output, "has_diag", suspendWhenHidden = FALSE)
|
| 898 |
|
| 899 |
-
# Station Meta
|
| 900 |
-
output$panel_station_name <- renderText({
|
| 901 |
-
req(current_station_id())
|
| 902 |
-
s <- all_stations() %>% filter(id == current_station_id())
|
| 903 |
-
if (nrow(s) > 0) paste0(s$name[1], " (", s$id[1], ")") else current_station_id()
|
| 904 |
-
})
|
| 905 |
-
|
| 906 |
-
output$panel_station_meta <- renderText({
|
| 907 |
-
req(current_station_id())
|
| 908 |
-
s <- all_stations() %>% filter(id == current_station_id())
|
| 909 |
-
if (nrow(s) > 0) {
|
| 910 |
-
paste0(
|
| 911 |
-
s$state[1], " | ",
|
| 912 |
-
"Lat: ", s$latitude[1], " | Lon: ", s$longitude[1], " | Elev: ", s$elevation[1], "m"
|
| 913 |
-
)
|
| 914 |
-
} else {
|
| 915 |
-
""
|
| 916 |
-
}
|
| 917 |
-
})
|
| 918 |
# Plots
|
| 919 |
observe({
|
| 920 |
df <- station_data()
|
| 921 |
req(df)
|
| 922 |
|
| 923 |
-
# Filter by Date Range from Modal (local processing)
|
| 924 |
-
if (!is.null(input$modal_date_start) && !is.null(input$modal_date_end)) {
|
| 925 |
-
df <- df %>% filter(
|
| 926 |
-
datetime >= as.POSIXct(input$modal_date_start),
|
| 927 |
-
datetime <= as.POSIXct(input$modal_date_end) + days(1)
|
| 928 |
-
)
|
| 929 |
-
}
|
| 930 |
-
|
| 931 |
output$temp_plot <- renderPlotly({
|
| 932 |
create_weather_trends_plot(df)
|
| 933 |
})
|
|
@@ -986,32 +885,53 @@ server <- function(input, output, session) {
|
|
| 986 |
|
| 987 |
s_name <- meta$name[1]
|
| 988 |
s_state <- meta$state[1]
|
|
|
|
| 989 |
|
| 990 |
# Data Range
|
| 991 |
df <- station_data()
|
| 992 |
if (is.null(df) || nrow(df) == 0) {
|
| 993 |
-
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
)
|
| 997 |
}
|
| 998 |
|
| 999 |
-
|
| 1000 |
-
|
| 1001 |
-
|
| 1002 |
-
|
| 1003 |
-
|
| 1004 |
-
|
| 1005 |
-
|
| 1006 |
-
|
| 1007 |
-
|
| 1008 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1009 |
),
|
| 1010 |
-
|
| 1011 |
-
|
| 1012 |
-
|
| 1013 |
-
|
| 1014 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1015 |
)
|
| 1016 |
)
|
| 1017 |
})
|
|
@@ -1045,18 +965,9 @@ server <- function(input, output, session) {
|
|
| 1045 |
radius = 8, color = "red", fill = FALSE, opacity = 1, weight = 3
|
| 1046 |
)
|
| 1047 |
|
| 1048 |
-
# Show Panel
|
| 1049 |
-
output$show_details_panel <- reactive(TRUE)
|
| 1050 |
-
outputOptions(output, "show_details_panel", suspendWhenHidden = FALSE)
|
| 1051 |
-
|
| 1052 |
# NOTE: Date reset removed to preserve user context (same as map marker click)
|
| 1053 |
})
|
| 1054 |
|
| 1055 |
-
# Close Panel
|
| 1056 |
-
observeEvent(input$close_panel, {
|
| 1057 |
-
output$show_details_panel <- reactive(FALSE)
|
| 1058 |
-
})
|
| 1059 |
-
|
| 1060 |
# Dynamic Details Tabs (Hide Wind Rose for Daily)
|
| 1061 |
output$details_tabs <- renderUI({
|
| 1062 |
req(input$data_resolution)
|
|
@@ -1102,16 +1013,6 @@ server <- function(input, output, session) {
|
|
| 1102 |
))
|
| 1103 |
}
|
| 1104 |
|
| 1105 |
-
do.call(bslib::
|
| 1106 |
})
|
| 1107 |
-
|
| 1108 |
-
# Downloads
|
| 1109 |
-
output$download_data <- downloadHandler(
|
| 1110 |
-
filename = function() {
|
| 1111 |
-
paste0("dwd_station_", current_station_id(), ".csv")
|
| 1112 |
-
},
|
| 1113 |
-
content = function(file) {
|
| 1114 |
-
write_csv(station_data(), file)
|
| 1115 |
-
}
|
| 1116 |
-
)
|
| 1117 |
}
|
|
|
|
| 83 |
inputs_to_toggle <- c(
|
| 84 |
"station_selector",
|
| 85 |
"date_range",
|
|
|
|
|
|
|
| 86 |
"zoom_home",
|
|
|
|
| 87 |
"main_nav",
|
|
|
|
| 88 |
"download_hourly"
|
| 89 |
)
|
| 90 |
|
|
|
|
| 328 |
# Sync dropdown
|
| 329 |
updateSelectizeInput(session, "station_selector", selected = id_val)
|
| 330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
# NOTE: Date reset removed to preserve user context
|
| 332 |
})
|
| 333 |
|
| 334 |
# --- Date Synchronization (Sliding Window & Bi-Directional) ---
|
| 335 |
|
| 336 |
+
# 2. Sidebar constraints: 28 <= days <= 366
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
observeEvent(input$date_range, {
|
| 338 |
req(input$date_range)
|
| 339 |
d_start <- input$date_range[1]
|
|
|
|
| 361 |
|
| 362 |
if (end_changed && !start_changed) {
|
| 363 |
# User changed end date -> adjust start date
|
|
|
|
| 364 |
target_diff <- if (diff > 366) 366 else 28
|
| 365 |
new_start <- d_end - target_diff
|
| 366 |
|
|
|
|
| 369 |
|
| 370 |
# Update tracked state
|
| 371 |
previous_date_range(c(new_start, d_end))
|
|
|
|
|
|
|
|
|
|
| 372 |
} else {
|
| 373 |
# User changed start date (or both) -> adjust end date
|
| 374 |
target_diff <- if (diff > 366) 366 else 28
|
|
|
|
| 379 |
|
| 380 |
# Update tracked state
|
| 381 |
previous_date_range(c(d_start, new_end))
|
|
|
|
|
|
|
|
|
|
| 382 |
}
|
| 383 |
} else {
|
| 384 |
# Update tracked state
|
| 385 |
previous_date_range(c(d_start, d_end))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 386 |
}
|
| 387 |
})
|
| 388 |
|
|
|
|
| 403 |
|
| 404 |
# Initial Trigger (Debounced Window)
|
| 405 |
window_reactive <- reactive({
|
| 406 |
+
req(input$date_range)
|
| 407 |
+
list(id = current_station_id(), start = input$date_range[1], end = input$date_range[2])
|
| 408 |
})
|
| 409 |
window_debounced <- window_reactive %>% debounce(500)
|
| 410 |
|
|
|
|
| 787 |
loading_diagnostics(paste0("Success: ", nrow(clean_df), " rows loaded."))
|
| 788 |
loading_status(FALSE)
|
| 789 |
fetch_stage(0)
|
| 790 |
+
|
| 791 |
+
# Navigate to Dashboard tab
|
| 792 |
+
updateNavbarPage(session, "main_nav", selected = "Dashboard")
|
| 793 |
+
|
| 794 |
# Show rendering message and then unfreeze after delay
|
| 795 |
session$sendCustomMessage("freezeUI", list(text = "Rendering plots..."))
|
| 796 |
later::later(function() {
|
|
|
|
| 822 |
})
|
| 823 |
outputOptions(output, "has_diag", suspendWhenHidden = FALSE)
|
| 824 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 825 |
# Plots
|
| 826 |
observe({
|
| 827 |
df <- station_data()
|
| 828 |
req(df)
|
| 829 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 830 |
output$temp_plot <- renderPlotly({
|
| 831 |
create_weather_trends_plot(df)
|
| 832 |
})
|
|
|
|
| 885 |
|
| 886 |
s_name <- meta$name[1]
|
| 887 |
s_state <- meta$state[1]
|
| 888 |
+
s_elev <- meta$elevation[1]
|
| 889 |
|
| 890 |
# Data Range
|
| 891 |
df <- station_data()
|
| 892 |
if (is.null(df) || nrow(df) == 0) {
|
| 893 |
+
dates_text <- "No data loaded"
|
| 894 |
+
} else {
|
| 895 |
+
date_range <- range(as.Date(df$datetime), na.rm = TRUE)
|
| 896 |
+
dates_text <- paste(date_range[1], "to", date_range[2])
|
| 897 |
}
|
| 898 |
|
| 899 |
+
layout_columns(
|
| 900 |
+
fill = FALSE,
|
| 901 |
+
value_box(
|
| 902 |
+
title = "Station",
|
| 903 |
+
value = s_name,
|
| 904 |
+
showcase = bsicons::bs_icon("geo-alt-fill"),
|
| 905 |
+
p(paste("ID:", id)),
|
| 906 |
+
theme = "primary"
|
| 907 |
+
),
|
| 908 |
+
value_box(
|
| 909 |
+
title = "State / Location",
|
| 910 |
+
value = s_state,
|
| 911 |
+
showcase = bsicons::bs_icon("map-fill"),
|
| 912 |
+
p(paste0("Lat: ", meta$latitude[1], " | Lon: ", meta$longitude[1])),
|
| 913 |
+
theme = "secondary"
|
| 914 |
+
),
|
| 915 |
+
value_box(
|
| 916 |
+
title = "Elevation",
|
| 917 |
+
value = paste0(s_elev, " m"),
|
| 918 |
+
showcase = bsicons::bs_icon("align-bottom"),
|
| 919 |
+
p("Above mean sea level"),
|
| 920 |
+
theme = "info"
|
| 921 |
),
|
| 922 |
+
value_box(
|
| 923 |
+
title = "Data Period",
|
| 924 |
+
value = dates_text,
|
| 925 |
+
showcase = bsicons::bs_icon("calendar3"),
|
| 926 |
+
p(paste("Resolution:", input$data_resolution)),
|
| 927 |
+
theme = "success"
|
| 928 |
+
),
|
| 929 |
+
value_box(
|
| 930 |
+
title = "Actions",
|
| 931 |
+
value = "Download",
|
| 932 |
+
showcase = bsicons::bs_icon("download"),
|
| 933 |
+
downloadButton("download_hourly", "Export CSV", class = "btn-sm btn-light", style = "width: 100%;"),
|
| 934 |
+
theme = "warning"
|
| 935 |
)
|
| 936 |
)
|
| 937 |
})
|
|
|
|
| 965 |
radius = 8, color = "red", fill = FALSE, opacity = 1, weight = 3
|
| 966 |
)
|
| 967 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 968 |
# NOTE: Date reset removed to preserve user context (same as map marker click)
|
| 969 |
})
|
| 970 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 971 |
# Dynamic Details Tabs (Hide Wind Rose for Daily)
|
| 972 |
output$details_tabs <- renderUI({
|
| 973 |
req(input$data_resolution)
|
|
|
|
| 1013 |
))
|
| 1014 |
}
|
| 1015 |
|
| 1016 |
+
do.call(bslib::navset_pill, tabs)
|
| 1017 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1018 |
}
|
ui.R
CHANGED
|
@@ -228,41 +228,6 @@ ui <- page_navbar(
|
|
| 228 |
id = "zoom_home_panel",
|
| 229 |
top = 80, left = 10,
|
| 230 |
actionButton("zoom_home", bsicons::bs_icon("house-fill"), class = "btn-home", title = "Zoom to all stations")
|
| 231 |
-
),
|
| 232 |
-
|
| 233 |
-
# Floating Panel
|
| 234 |
-
conditionalPanel(
|
| 235 |
-
condition = "output.show_details_panel",
|
| 236 |
-
absolutePanel(
|
| 237 |
-
id = "station_detail_panel",
|
| 238 |
-
class = "panel panel-default",
|
| 239 |
-
top = 20, right = 20, width = 550,
|
| 240 |
-
draggable = TRUE,
|
| 241 |
-
|
| 242 |
-
# Header
|
| 243 |
-
div(
|
| 244 |
-
style = "padding-bottom: 10px; border-bottom: 1px solid #eee; margin-bottom: 10px; padding-right: 30px;",
|
| 245 |
-
h4(textOutput("panel_station_name"), style = "margin: 0; font-size: 1.1rem; font-weight: bold;"),
|
| 246 |
-
div(style = "font-size: 0.85rem; color: #666;", textOutput("panel_station_meta")),
|
| 247 |
-
actionButton("close_panel", icon("times"), class = "close-btn-custom", label = NULL)
|
| 248 |
-
),
|
| 249 |
-
|
| 250 |
-
# Controls
|
| 251 |
-
div(
|
| 252 |
-
style = "margin-bottom: 10px;",
|
| 253 |
-
fluidRow(
|
| 254 |
-
column(6, dateInput("modal_date_start", "Start Date", value = NULL)),
|
| 255 |
-
column(6, dateInput("modal_date_end", "End Date", value = NULL))
|
| 256 |
-
),
|
| 257 |
-
div(
|
| 258 |
-
style = "text-align: right;",
|
| 259 |
-
conditionalPanel(condition = "output.station_ready", downloadButton("download_data", "Export CSV", class = "btn-sm btn-outline-success"))
|
| 260 |
-
)
|
| 261 |
-
),
|
| 262 |
-
|
| 263 |
-
# Content Tabs
|
| 264 |
-
uiOutput("details_tabs")
|
| 265 |
-
)
|
| 266 |
)
|
| 267 |
)
|
| 268 |
),
|
|
@@ -271,20 +236,32 @@ ui <- page_navbar(
|
|
| 271 |
DT::dataTableOutput("table")
|
| 272 |
),
|
| 273 |
nav_panel(
|
| 274 |
-
title = "
|
|
|
|
| 275 |
conditionalPanel(
|
| 276 |
condition = "!output.station_ready",
|
| 277 |
div(
|
| 278 |
style = "height: 600px; display: flex; align-items: center; justify-content: center;",
|
| 279 |
-
p("Select a station from the map or the Stations Info table to view the
|
| 280 |
)
|
| 281 |
),
|
| 282 |
conditionalPanel(
|
| 283 |
condition = "output.station_ready",
|
| 284 |
-
|
| 285 |
-
|
| 286 |
-
|
| 287 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 288 |
)
|
| 289 |
),
|
| 290 |
nav_spacer(),
|
|
|
|
| 228 |
id = "zoom_home_panel",
|
| 229 |
top = 80, left = 10,
|
| 230 |
actionButton("zoom_home", bsicons::bs_icon("house-fill"), class = "btn-home", title = "Zoom to all stations")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
)
|
| 232 |
)
|
| 233 |
),
|
|
|
|
| 236 |
DT::dataTableOutput("table")
|
| 237 |
),
|
| 238 |
nav_panel(
|
| 239 |
+
title = "Dashboard",
|
| 240 |
+
value = "Dashboard",
|
| 241 |
conditionalPanel(
|
| 242 |
condition = "!output.station_ready",
|
| 243 |
div(
|
| 244 |
style = "height: 600px; display: flex; align-items: center; justify-content: center;",
|
| 245 |
+
p("Select a station from the map or the Stations Info table to view the dashboard.", style = "color: #999;")
|
| 246 |
)
|
| 247 |
),
|
| 248 |
conditionalPanel(
|
| 249 |
condition = "output.station_ready",
|
| 250 |
+
uiOutput("station_info_header"),
|
| 251 |
+
navset_card_pill(
|
| 252 |
+
id = "dashboard_subtabs",
|
| 253 |
+
nav_panel(
|
| 254 |
+
title = "Plots",
|
| 255 |
+
uiOutput("details_tabs")
|
| 256 |
+
),
|
| 257 |
+
nav_panel(
|
| 258 |
+
title = "Data",
|
| 259 |
+
div(
|
| 260 |
+
style = "margin-top: 10px;",
|
| 261 |
+
DT::dataTableOutput("hourly_data_table")
|
| 262 |
+
)
|
| 263 |
+
)
|
| 264 |
+
)
|
| 265 |
)
|
| 266 |
),
|
| 267 |
nav_spacer(),
|