Search code examples
rshinyplotly

Can I change the cursor in plotly only when hovering over points?


I want to change the default plotly cursor only when hovering over points

Example app

library(shiny)
library(plotly)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(
      sliderInput("num_points", "Number of Points:", min = 2, max = 20, value = 10)
    ),
    mainPanel(
      plotlyOutput("line_plot")
    )
  )
)

server <- function(input, output, session) {
  output$line_plot <- renderPlotly({

    num_points <- input$num_points
    x <- 1:num_points
    y <- rnorm(num_points, mean = 5, sd = 2) 

    plot_ly(x = ~x, y = ~y, type = 'scatter', mode = 'lines+markers',
            line = list(color = 'blue'), marker = list(color = 'red', size = 10),
            hoverinfo = 'text', text = ~paste("X: ", x, "<br>Y: ", round(y, 2))) |>
      layout(
        title = "Line Plot with Points",
        xaxis = list(title = "X Axis"),
        yaxis = list(title = "Y Axis")
      )
  })
}

shinyApp(ui, server)

Solution

  • You can use htmlwidgets::onRender and implement JS to change the cursor style on plotly_hover event of your line_plot.

    library(shiny)
    library(plotly)
    
    ui <- fluidPage(
     
      sidebarLayout(
        sidebarPanel(
          sliderInput("num_points", "Number of Points:", min = 2, max = 20, value = 10)
        ),
        mainPanel(
          plotlyOutput("line_plot")
        )
      )
    )
    
    server <- function(input, output, session) {
      output$line_plot <- renderPlotly({
        
        num_points <- input$num_points
        x <- 1:num_points
        y <- rnorm(num_points, mean = 5, sd = 2) 
        
        plot_ly(x = ~x, y = ~y, type = 'scatter', mode = 'lines+markers',
                line = list(color = 'blue'), marker = list(color = 'red', size = 10),
                hoverinfo = 'text', text = ~paste("X: ", x, "<br>Y: ", round(y, 2))) |>
          layout(
            title = "Line Plot with Points",
            xaxis = list(title = "X Axis"),
            yaxis = list(title = "Y Axis")
          ) %>%
          htmlwidgets::onRender(
              paste0(
                "function(el, x) {",
                "  function setCursor() {",
                "    var dragLayer = el.getElementsByClassName('nsewdrag')[0];",
                "    if (dragLayer) {",
                "      dragLayer.style.cursor = 'default';",
                "      el.on('plotly_hover', function(data) {",
                "        dragLayer.style.cursor = 'pointer';",
                "      });",
                "      el.on('plotly_unhover', function(data) {",
                "        dragLayer.style.cursor = 'default';",
                "      });",
                "      return true;",
                "    }",
                "    return false;",
                "  }",
                "  if (!setCursor()) {",
                "    var observer = new MutationObserver(function(mutations) {",
                "      if (setCursor()) { observer.disconnect(); }",
                "    });",
                "    observer.observe(el, { childList: true, subtree: true });",
                "  }",
                "}"
              )
          )
      })
    }
    
    shinyApp(ui, server)