I would like this app to immediately copy to clipboard the coordinates upon click.
In other words, I want to get rid of the copy button.
If this is not possible, I would like to have the copy button appear in the leaflet popup.
library(shiny)
library(bslib)
library(rclipboard)
library(leaflet)
base_map <- leaflet() |>
addTiles()
# The UI
ui <- bslib::page_fluid(
rclipboardSetup(),
# Add a text input
textInput("copytext", "Copy this:", "Co-Ordinates!"),
# UI ouputs for the copy-to-clipboard buttons
uiOutput("clip"),
# A text input for testing the clipboard content.
textInput("paste", "Paste here:"),
leafletOutput("map")
)
# The server
server <- function(input, output, session) {
# Add clipboard buttons
output$clip <- renderUI({
rclipButton(
inputId = "clipbtn",
label = "rclipButton Copy",
clipText = input$copytext,
icon = icon("clipboard"),
)
})
output$map <- renderLeaflet(base_map)
observe({
click <- input$map_click
text <- paste0(click$lat, ", ", click$lng)
leafletProxy("map") |>
addPopups(
lat = click$lat,
lng = click$lng,
popup = text
)
updateTextInput(session, "copytext", value = text)
}) |>
bindEvent(input$map_click)
}
shinyApp(ui, server)
rclipboard
is an R wrapper for clipboard.js
, which describes itself as a library for:
Modern copy to clipboard. No Flash.
This is a useful library for writing arbitrary data (e.g. images) to the clipboard. However, we can write text without dependencies using the JavaScript navigator.clipboard
API and the Shiny to JavaScript API.
In your ui
add a Shiny custom message handler. In this case, a function which takes some text and copies it to the clipboard:
ui <- bslib::page_fluid(
tags$script("
Shiny.addCustomMessageHandler('txt', function (txt) {
navigator.clipboard.writeText(txt);
});
"), # <- This is the only new UI element
textInput("copytext", "Copy this:", "Co-Ordinates!"),
textInput("paste", "Paste here:"),
leafletOutput("map")
)
In your server logic, add session$sendCustomMessage("txt", text)
to the observe event:
server <- function(input, output, session) {
output$map <- renderLeaflet(base_map)
observe({
click <- input$map_click
text <- paste0(click$lat, ", ", click$lng)
# Only this line is new
session$sendCustomMessage("txt", text)
leafletProxy("map") |>
addPopups(
lat = click$lat,
lng = click$lng,
popup = text
)
updateTextInput(session, "copytext", value = text)
}) |>
bindEvent(input$map_click)
}
Depending on your IDE this might not work in the preview pane, as the navigator.clipboard
API may not be supported. It should work in any modern browser. navigator.clipboard.writeText()
has been supported in Chrome, Firefox and Opera since 2018, and in Safari and Edge since 2020. See here for more browser compatibility details.