--- title: "Custom Click Behaviors" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Custom Click Behaviors} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` ```{r setup} library(linkeR) library(shiny) library(leaflet) library(DT) ``` # Customizing Click Behaviors While `linkeR` provides sensible defaults, you often want custom behaviors when users click on linked components. This vignette shows how to create rich, interactive experiences. ## Custom Leaflet Click Handler You can define exactly what happens when a leaflet marker is clicked (either directly or via linking): ```{r custom-leaflet} server <- function(input, output, session) { business_data <- reactive({ # Your business data here }) output$business_map <- renderLeaflet({ # Render your map (no popup needed - custom handler will create it) leaflet(business_data()) %>% addTiles() %>% addCircleMarkers( lng = ~longitude, lat = ~latitude, layerId = ~business_id, radius = ~sqrt(revenue/1000) + 3 ) }) output$business_table <- renderDT({ # Your table rendering code }) # Link with custom leaflet behavior link_plots( session, business_map = business_data, business_table = business_data, shared_id_column = "business_id", # Custom handler for leaflet clicks leaflet_click_handler = function(map_proxy, selected_data, session) { if (!is.null(selected_data)) { # Create rich popup popup_content <- paste0( "
", "

", selected_data$name, "

", "

Revenue: $", format(selected_data$revenue, big.mark = ","), "

", "

Category: ", selected_data$category, "

", "

Rating: ", selected_data$rating, "/5.0 ⭐

", "
" ) # Custom zoom and popup map_proxy %>% leaflet::setView( lng = selected_data$longitude, lat = selected_data$latitude, zoom = 15 # Custom zoom level ) %>% leaflet::clearPopups() %>% leaflet::addPopups( lng = selected_data$longitude, lat = selected_data$latitude, popup = popup_content ) } else { # Handle deselection map_proxy %>% leaflet::clearPopups() } } ) } ``` ## Custom DT Click Handler Similarly, you can customize table selection behavior: ```{r custom-dt} link_plots( session, business_map = business_data, business_table = business_data, shared_id_column = "business_id", # Custom handler for table clicks dt_click_handler = function(dt_proxy, selected_data, session) { if (!is.null(selected_data)) { # Find the row and select it current_data <- business_data() row_idx <- which(current_data$business_id == selected_data$business_id) if (length(row_idx) > 0) { # Select and scroll to row DT::selectRows(dt_proxy, selected = row_idx[1]) # Optional: scroll to the row page_size <- 10 # Your page size target_page <- ceiling(row_idx[1] / page_size) DT::selectPage(dt_proxy, target_page) # Show additional info showNotification( paste("Selected:", selected_data$name, "- Revenue: $", format(selected_data$revenue, big.mark = ",")), type = "message", duration = 3 ) } } else { # Handle deselection DT::selectRows(dt_proxy, selected = integer(0)) } } ) ``` ## Global Selection Callback You can also add a callback that fires whenever any selection changes: ```{r global-callback} link_plots( session, business_map = business_data, business_table = business_data, shared_id_column = "business_id", # Global callback for all selection changes on_selection_change = function(selected_id, selected_data, source_id, session) { if (!is.null(selected_data)) { # Update other UI elements output$selected_business_info <- renderText({ paste0( "Selected: ", selected_data$name, "\n", "Source: ", source_id, "\n", "Revenue: $", format(selected_data$revenue, big.mark = ",") ) }) # Log for analytics cat("Selection event:", selected_id, "from", source_id, "\n") # Update other reactive values current_selection(selected_data) } else { # Handle deselection output$selected_business_info <- renderText("No selection") current_selection(NULL) } } ) ``` ## Best Practices 1. **Consistent Experience**: Custom handlers should provide the same experience whether triggered by direct clicks or linking 2. **Error Handling**: Wrap custom logic in `tryCatch()` for robustness 3. **Performance**: Keep custom handlers lightweight to avoid UI lag 4. **Visual Feedback**: Provide clear visual feedback for user actions 5. **Deselection**: Always handle the case where `selected_data` is `NULL` ## Advanced Example: Conditional Behavior ```{r conditional} leaflet_click_handler = function(map_proxy, selected_data, session) { if (!is.null(selected_data)) { # Different behavior based on data properties if (selected_data$risk_level == "High") { # Show warning for high-risk items showModal(modalDialog( title = "High Risk Alert", paste("This location has high risk level:", selected_data$name), easyClose = TRUE )) } # Color popup based on risk popup_color <- switch(selected_data$risk_level, "Low" = "#d4edda", "Medium" = "#fff3cd", "High" = "#f8d7da" ) popup_content <- paste0( "
", "

", selected_data$name, "

", "

Risk Level: ", selected_data$risk_level, "

", "
" ) map_proxy %>% leaflet::setView(lng = selected_data$longitude, lat = selected_data$latitude, zoom = 13) %>% leaflet::clearPopups() %>% leaflet::addPopups( lng = selected_data$longitude, lat = selected_data$latitude, popup = popup_content ) } } ``` This approach lets you create rich, context-aware interactions that respond intelligently to your data.