Связать код JavaScript с виджетом R Shiny

#javascript #html #r #shiny

#javascript #HTML #r #блестящий

Вопрос:

Резюме: я хотел бы адаптировать библиотеку JavaScript (а именно OwlCarousel2) в R, а точнее в R Shiny. Я уже сделал несколько шагов, но не могу найти способ добавить JS-скрипт, необходимый в конце структуры HTML (непосредственно перед концом тела).


OwlCarousel2 это библиотека, которая позволяет создавать карточки и заставлять их скользить. Смотрите здесь для получения более подробной информации.

Что я сделал до сих пор:

  • Прежде всего, я проверил, что могу воспроизвести ожидаемое поведение этой библиотеки только с помощью HTML, CSS и JS, следуя этому руководству.

  • Затем я попытался адаптировать это в R Shiny. По сути, я создал функции, встраивающие необработанный HTML, вставил JS и CSS www и запустил приложение, чтобы убедиться, что оно работает. Это произошло: карты были отображены, и было поведение слайда. Но это было немного запутанно, поэтому я решил превратить его в пакет, чтобы мне (и другим) было проще использовать его повторно.

  • Чтобы преобразовать это в пакет, я использовал два источника:

    1. учебное пособие, сопровождающее пакет {applause}
    2. эта новая книга о R и Javascript

Я создал три функции: owl_carousel_item() для создания карточек, owl_carousel() для встраивания карточек в a div с классом slider owl-carousel и html_dependency_owlcarousel() для включения зависимостей.

 html_dependency_owlcarousel <- function() {
  htmltools::htmlDependency(
    name = "owl.carousel",
    version = "2.3.4",
    package = "shinymisc",
    src = "htmlwidgets/owl_carousel",
    script = c("owl.carousel.min.js", "owl.carousel.js"),
    stylesheet = c("owl.carousel.min.css", "style.css"),
    all_files = FALSE
  )
}

owl_carousel <- function(id, ...) {

  tag <- htmltools::tags$div(
    id = id,
    class = "slider owl-carousel",
    ...
  )

  htmltools::tagList(
    tag,
    html_dependency_owlcarousel()
  )
}

owl_carousel_item <- function(title, subtitle, content = NULL, button_text = NULL, width = "300px") {

  if (!is.null(button_text))
    button <- shiny::tags$div(class = "btn", value = button_text)
  else
    button <- NULL

  shiny::tags$div(
    class = "card",
    style = paste0("width: ", width),
    shiny::tags$div(class = "img"),
    shiny::tags$div(
      class = "content",
      shiny::tags$div(class = "title", title),
      shiny::tags$div(class = "sub-title", subtitle),
      shiny::tags$p(content),
      button
    )
  )

}
  

С помощью этого кода (и зависимостей) я создаю приложение, которое имеет структуру HTML, почти эквивалентную той, которую я мог бы создать вне среды пакета: оно отображает карточки, но они не скользят. Чего не хватает <script> , так это того, что должно быть внизу этой структуры, непосредственно перед концом <body> . Вот почему карточки не скользят.

Я попытался применить метод, описанный в этой главе упомянутой ранее книги, но безуспешно, потому что я не мог заставить htmlwidgets::createWidget() работать с моим tag .

Поэтому мой вопрос: как я могу разместить следующий скрипт в конце структуры HTML?

 $(".slider").owlCarousel({
    loop: true,
    autoplay: true,
    autoplayTimeout: 2000, //2000ms = 2s;
    autoplayHoverPause: true,
  });
  

Имейте в виду, что эти параметры должны быть доступны для редактирования с помощью функции owl_carousel() (поэтому просто вставить это в конце tag in owl_carousel() недостаточно).

Я знаю, что это должно быть не очень понятно, поэтому вот ссылка на репозиторий, содержащий то, что я сделал до сих пор.

Примечание: это должно быть менее сложным, чем для других виджетов. Здесь нет *Output render* функций or, нет данных, просто функция для встраивания блоков и заставления их скользить.

Редактировать: некоторый код для проверки того, что он работает (он должен отображать две карточки и анимацию):

 library(shiny)
library(fullPage)

ui <- fullPage(
  menu = c("Section 1" = "section1"),
  pageSection(
    menu = "section1",
    owl_carousel(
      id = "test",
      owl_carousel_item(
        title = "test1",
        subtitle = "subtitle1",
        content = "this is a test"
      ),
      owl_carousel_item(
        title = "test2", 
        subtitle = "subtitle2", 
        content = "this is a test", 
        button_text = "button to click"
      )
    )
  )
)

server <- function(input, output, session) {
  
}

shinyApp(ui, server)
  

Комментарии:

1. возможно, добавление a htmltools::tags$script('ur jquery code here') в список тегов

2. Спасибо, это работает shiny::fluidPage , но не для других макетов, например, fullPage::fullPage потому, что скрипт кажется «слишком высоким» в структуре HTML. Более того, это не похоже на простой способ связать javascript с функцией в пакете.

3. можете ли вы предоставить MWE, чтобы я мог его протестировать. также спасибо за то, что сделали shiny лучше

4. также, возможно, если вы дождетесь загрузки содержимого, это сработает

5. Я уже знаю, как заставить это работать в «классической» настройке. Здесь моя проблема связана с тем фактом, что это пакет R, и что структура сильно отличается. Поэтому я не могу создать MWE. Тем не менее, вы можете загрузить репозиторий, на который я ссылался в своем посте, чтобы иметь точную ситуацию, в которой я нахожусь.

Ответ №1:

Решение заключалось в перемещении owl_carousel.js в inst/htmlwidgets и изменении renderValue функции для включения предоставленного jQuery кода.

 renderValue: function(x) {

  // TODO: code to render the widget, e.g.
  el.innerHTML = x.message;

  $(".slider").owlCarousel({
    loop: true,
    autoplay: true,
    autoplayTimeout: 2000, //2000ms = 2s;
    autoplayHoverPause: true,
  })

}
  

И изменение возвращаемого значения owl_carousel функции на :

 owl_carousel <- function(id, ..., width = "100%", height = "400px") {

  tag <- htmltools::tags$div(
    id = id,
    class = "slider owl-carousel",
    ...
  )
  
  x <- list(message=as.character(htmltools::tagList(
    tag,
    html_dependency_owlcarousel()
  )))
  htmlwidgets::createWidget(
     name = 'owl_carousel',
     x,
     package = 'shinymisc'
   )
}
  

Редактировать
Для проблемы с css, которую вы не включили style.css в yaml:

 dependencies:
 - name: jQuery
   version: 3.5.1
   src: htmlwidgets/jquery
   script: jquery.min.js
 - name: OwlCarousel2
   version: 2.3.4
   src: htmlwidgets/owl_carousel
   script: owl.carousel.min.js
   stylesheet:
    - owl.carousel.min.css
    - style.css
  

Результат

Комментарии:

1. Это не работает. Я добавил пример в свой пост, чтобы легко проверить, работает код или нет. В этом примере после применения ваших изменений ошибок нет, но ничего не отображается

2. @bretauv ошибка возникает из-за того, что jquery не находит owlCarousel функцию, возможно, существует конфликт между версией jQuery, используемой fullPage и используемой owlCarousel

3. fullPage использует jQuery 3.2, а OwlCarousel использует 3.5

4. это работает при печати виджета и с shiny::fluidPage

5. Действительно, мне пришлось открыть его в браузере. Однако стиль css не применяется (хотя это было раньше). Не могли бы вы сделать форк репозитория, чтобы у меня было именно то, что у вас есть?