0

This is my first post, but long time stack overflow lurker. I have been trying to invoke some Javascript in the Highcharter plot options for a mouseOver or click event when rendering a highchart map in R Shiny. The Javascript works when the app first launches, but when the user switches inputs in the UI to update the map, the Javascript I've written no longer works. The purpose of this JS is to, upon clicking on a state in the map, highlight the state in red. Reproducible example below:

##PACKAGES
library(shiny)
library(shinyWidgets)
library(shinyjs)
library(dplyr)
library(tidyverse)
library(albersusa)
library(highcharter)
library(usdata)

states <- data.frame(
  name  = rep(state.abb,4),
  metric = c(rep("YES",100),rep("NO",100)),
  value  = sample(100:5000,200)
)

ui <- fluidPage(
  
  tags$script(src = "https://code.highcharts.com/mapdata/countries/us/us-all.js"),
  
  fluidRow(
    radioButtons(inputId = "toggle",label="toggle it", 
                 choices = c("YES","NO")),
    column(width=5,highchartOutput("map1"))
    )
  )

server <- function(input, output, session) {
  
  #create rate change
  df1_num<- reactive({
    states %>%
    filter(metric == input$toggle) %>%
    group_by(name) %>%
    mutate(
      first = dplyr::first(value),
      last = dplyr::last(value)
    ) %>%
    distinct(metric,name,first,last) %>%
    mutate(
      #increase/decrease rate change
      rate  = round(((last-first)/first)*100,1),
    )
  })
  
  output$map1 <- renderHighchart({
    #US map of percent change in population trends
    hcmap("countries/us/us-all",
          data   = df1_num(),
          joinBy = c("hc-a2","name"),
          value  = "rate",
          borderColor = "#8d8d8d",
          nullColor = "#D3D3D3",
          download_map_data = FALSE
    ) %>%
      hc_plotOptions(series = list(
        point = list(
          events = list(
            click = JS("function() {
                       let currentY = this.name
                       charts = Highcharts.charts;
                       charts.forEach(function(chart, index) {
                       chart.series.forEach(function(series, seriesIndex) {
                       series.points.forEach(function(point, pointsIndex) {
                       if (point.name == currentY) {
                               point.setState('hover');
                               point.update({color:'red'})
                       }
                       })
                       });
                       });
        }")
          )
        )
      )
      )
  })

}

shinyApp(ui = ui, server = server)

As I stated, it works when the app first launches and a user clicks on any state in the map (or multiple states), but once the UI input changes, the JS no longer appears to work. Not sure if this is a bug in Highcharter, or my poor JS skills, or perhaps there is some kind of workaround in Shiny I'm missing.

Thanks!

jcoder
  • 35
  • 6

1 Answers1

1

Here is an example of how to update the color point on the Highmaps inside point.events.

  plotOptions: {
    series: {
      point: {
        events: {
          click: function() {
            this.update({
              color: 'green'
            })
          }
        }
      }
    }
  },

DEMO: https://jsfiddle.net/BlackLabel/u6baodm7/

Sebastian Hajdus
  • 1,422
  • 1
  • 5
  • 14
  • This is extremely helpful, thank you. Relatedly, @sebastian I am trying to synchronize two Highcharts using click events, which is why I was using the code in my original post question (apologies for not providing this background). Using my JS function I'm able to link the two charts with click events, but it suffers from the Shiny input switch issue. Conversely, if I update my code to reflect your answer, it fixes the Shiny input issue, but then the charts are no longer synchronized. Is there any way around this? I will also start another post/question if helpful. Thanks again – jcoder Oct 11 '22 at 16:14
  • It's a few ways to synchronize charts, for example you can turn [setExtremes](https://api.highcharts.com/class-reference/Highcharts.Axis#setExtremes), [demo](https://jsfiddle.net/BlackLabel/ryk6ubej/) after click, but it's depend what do you want to achieve. It might be a good option to work on a simple demo write in JS and then convert to R. – Sebastian Hajdus Oct 11 '22 at 16:53
  • I made another [question/post](https://stackoverflow.com/questions/74034754/synchronize-two-highcharts-in-shiny-js-not-invoked-on-input-change) with a reproducible example to exemplify what I'm trying to do. I reviewed the demo you shared (thank you!) but I'm having still having difficulty clearly understanding how to link the points between the two charts without losing click event functionality due to Shiny input changes. – jcoder Oct 11 '22 at 22:40