R Shiny - 在外部单击时隐藏工具提示(工具提示在服务器端创建)

问题描述 投票:0回答:0

上下文

我正在尝试弹出一个工具提示点击信息图标显示,点击图标本身或应用程序的任何其他地方隐藏。与 SO 左侧面板中的工具提示的行为方式非常相似。

到目前为止尝试过:

  • 我从this SO accepted answer借用了工具提示来显示和隐藏点击带有
    data-trigger="click"
    的信息图标。但是,我也无法在应用程序的任何其他位置单击时隐藏它。
  • 基于this other SO accepted answer,我能够在点击信息图标时显示工具提示,并在除图标之外的任何其他地方点击时隐藏。但是,我无法在第二次单击图标本身时将其隐藏,这是所需的行为。答案中提供的代码完全满足该 MRE 的需求,但在实际应用程序中却没有,这表明该 MRE 和应用程序之间的差异将决定该解决方案是否适用于实际环境。此处发布的 MRE 包括之前 MRE 中缺失的方面。

背景

这个问题与this other(也是我几天前发布的)相关,已经成功回答。但是,当尝试在我正在处理的实际应用程序中实施该解决方案时,它并没有完全按预期工作。在评论中进一步讨论并与在那里给出答案的人聊天,让我意识到我的应用程序的以下特定方面,在我以前的 MRE 中没有出现,为了得到好的答案是相关的。

本题新增的方面:

  • 工具提示是在服务器端创建的
  • 帮助文本来自反应对象
  • 一些帮助文本包含html元素

我在这里明确说明这一点,希望防止答案被标记为重复和关闭


到目前为止我的代码的 MRE

CSS文件:

style.css

.tooltip > .tooltip-inner {
  pointer-events: none;
  background-color: #2355b4;
  color: #FFFFFF;
  border: 1px solid #000000;
  padding: 10px;
  font-size: 25px;
  font-style: italic;
  text-align: justify;
  margin-left: 0;
  max-width: 1000px;
}
.tooltip.bottom > .tooltip-arrow {
  border-bottom-color: #2355b4;
}

img {
  border: 0;
  display:inline;
  margin: 0 1px;
  padding: 1px;
  box-shadow: none;
  width:auto;
  height:18px;
}

R闪亮文件:

myApp.R

library(shiny)


# ==============================================================================
js <- "
$(function () {
  // initialize tooltips
  $('[data-toggle=tooltip]').tooltip({
    html: true
  });
  
  // create listener on html (`everywhere`) which will hide (all) tooltips on click
  $('html').on('click', function(el) {
     $('[data-toggle=tooltip]').tooltip('hide');
  });
  
  // create listener on tooltip elements to toggle the tooltip
  $('[data-toggle=tooltip]').on('click', function(evt) {
     // make sure the click is not bubbling up to <html> to avoid closing it right away
     evt.stopPropagation();
     // hide all other tooltips to ensure there is at most one tooltip open at a time
     $('[data-toggle=tooltip]').not($(this)).tooltip('hide');
     $(this).tooltip('show'); 
  });
})
"
# ==============================================================================


# ==============================================================================
ui <- function() {
  fluidPage(
    includeCSS("style.css"),
    br(),br(),
    
    fluidRow(
      # Step 1
      uiOutput('head_step1'),
      # here goes some more ui for step 1
      br(),br(),
      
      # Step 2
      uiOutput('head_step2'),
      # here goes some more ui for step 2
      br(),br(),
      
      # Step 3
      uiOutput('head_step3')
      # here goes some more ui for step 3
    )
  )
}
# ==============================================================================


# ==============================================================================
# this function just returns the label matching the specified id
getLabel <- function(dbData, id) {
  dbData$labelsEnlish[dbData$ids == id]
}
# ==============================================================================


# ==============================================================================
server <- function(input, server, output, session) {
  # reactive object containing labels for different languages
  #   - in the actual app this object is much more complex
  #     with multiple languages, many other features inside,
  #     and dependencies on SQL-pulled data.
  #   - here kept reduced to the relevant things for the MRE.
  dbData <- reactiveValues(
    labelsEnlish = c("Step 1: Drop a Pin",
                     "Step 2: Find Public Data",
                     "Step 3: Load Public Data",
                     # help texts for step 1
                     "Click the pin icon",
                     "and then click on a location on the map.",
                     # help texts for step 2
                     "Define the distance and period to query.",
                     "A query for public sites will be available",
                     # help text for step 3
                     "Select the data type(s) to retrieve."
    ),
    ids = c(1, 2, 3, # the three headers
            4, 5, # the help texts for step 1
            6, 7, # the help texts for step 2
            8 # the help text for step 3
    )
  )
  
  # Step 1 - Header
  output$head_step1 <- renderUI({
    span(tags$script(HTML(js)),
      style = "display:inline-block;",
      h4(getLabel(dbData, 1), # 'Step 1: Drop a Pin'
         style = "vertical-align: middle; display: inline;"),
      span(
        `data-toggle` = "tooltip",
        `data-placement` = "bottom",
        `data-trigger` = "manual",
        title = HTML('<p>',
                     getLabel(dbData, 4), # 'Click the pin icon'
                     paste0(' <img src="marker_2.png"> '),
                     getLabel(dbData, 5), # 'and then click on a location on the map.'
                     '</p>'),
        icon("info-circle")
      )
    )
  })
  
  # Step 2 - Header
  output$head_step2 <- renderUI({
    span(
      style = "display:inline-block;",
      h4(getLabel(dbData, 2), # 'Step 2: Find Public Data'
         style = "vertical-align: middle; display: inline;"),
      span(tags$script(HTML(js)),
        `data-toggle` = "tooltip",
        `data-placement` = "bottom",
        `data-trigger` = "manual",
        title = HTML(
          '<div><p>',
          getLabel(dbData, 6), # 'Define the distance and period to query.'
          '</p><p>',
          getLabel(dbData, 7), # 'A query for public sites will be available'
          '</p></div>'),
        icon("info-circle")
      )
    )
  })
  
  # Step 3 - Header
  output$head_step3 <- renderUI({
    span(
      style = "display:inline-block;",
      h4(getLabel(dbData, 3), # 'Step 3: Load Public Data'
      style = "vertical-align: middle; display: inline;"),
      span(tags$script(HTML(js)),
        `data-toggle` = "tooltip",
        `data-placement` = "bottom",
        `data-trigger` = "manual",
        title = getLabel(dbData, 8), # 'Select the data type(s) to retrieve.'
        icon("info-circle")
      )
    )
  })
}
# ==============================================================================


# ==============================================================================
shinyApp(ui = ui, server = server,
         options = list(display.mode = "normal"),
         enableBookmarking = "server")
# ==============================================================================

步骤 1 标题中使用的图像:

marker_2.png

可在此处下载。必须放置在

www
旁边的
myApp.R
命名文件夹中。

| myApp.R
| style.css
| www/
   | marker_2.png

另外两个相关的注释:

  • this answer中,JS代码读取
    $(this).tooltip('toggle');
    而不是
    $(this).tooltip('show');
    。但是,对于
    toggle
    ,工具提示在显示后立即隐藏,并且表现不稳定。使用
    show
    ,这些问题是不可见的。
  • 同一个答案中的人告诉我只调用一次 JS 代码,而不是在每个工具提示范围内,但是,我只知道如何在 UI 中执行此操作,而不是在服务器中执行此操作。因此,我在这里发布了带有多个 JS 调用的代码,希望答案也能在这方面对我有所帮助。

期望的行为

  • 第一次点击图标时显示
  • 第二次点击图标或点击任何其他地方隐藏


当前行为

  • 第一次点击图标时显示
  • 在任何其他地方点击隐藏
  • 第二次点击图标时不隐藏
javascript r shiny popup tooltip
© www.soinside.com 2019 - 2024. All rights reserved.