Task: using R
and shinydashboard
, embed a custom Javascript-generated plot in the dashboard body. Specify width of the plot as percentage, so that the plot occupies its column (or box) regardless of viewer's screen setup.
Setup: R
(3.5.2), shiny
(1.2.0) and shinydashboard
(0.7.1). The dashboard code (simplified reproducible example) is as follows:
library(shiny)
library(shinydashboard)
ui <- fluidPage(
dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Main", tabName = "tab1", icon = icon("dashboard")
)
)
),
dashboardBody(
tabItems(
tabItem("tab1",
column(width = 12,
tags$div(id = "main", style = "width: 100%; height: 400px"),
tags$script(src = "http://cdnjs.cloudflare.com/ajax/libs/echarts/4.1.0/echarts.min.js"),
tags$script(src = "myscript.js")
)
)
)
)
)
)
server <- function(input, output) {
}
# Run the application
shinyApp(ui = ui, server = server)
The respective Javascript file myscript.js
, which is to be placed in the www
subfolder relative to the app file itself, is as follows:
// JS Plot with Echarts 4
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
};
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
Problem: for some reason, the 100%
specification gets converted to 100px
in the final result, producing this output:
Inspecting the plot I see that div#main
has indeed the width of 100%, but then it contains another, smaller div
, which is already 100px
wide:
To me, it would seem that either tabItem
or tabItems
are at fault, because without using them the outcome is correct, and that smaller intermediary div
takes its width from its parent correctly:
For completeness, the code for the working version (without tabItem(s)
) is this:
library(shiny)
library(shinydashboard)
ui <- fluidPage(
dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
column(width = 12,
tags$div(id = "main", style = "width: 100%; height: 400px"),
tags$script(src = "http://cdnjs.cloudflare.com/ajax/libs/echarts/4.1.0/echarts.min.js"),
tags$script(src = "myscript.js")
)
)
)
)
server <- function(input, output) {
}
# Run the application
shinyApp(ui = ui, server = server)
As you can see, the code is almost identical, aside from the offending functions. I don't see however how a shinydashboard could possibly work without these functions, as they structure the whole application. Is there any workaround you can think of? Thanks.
Very interesting, but yes it seems like a bug/feature in tabItems
.
By setting the width via css, it just stretches the plot, so that doesnt really work. I found those little workarounds, that resize the plot on a window resize.
Option 1:
To initially resize the window I use shinyjs
to collapse the sidebar at startup, so the plot gets resized too. This will start the app with a collapsed sidebar.
If you want the sidebar to not be collapsed at startup, you would have to add collapsed = TRUE
to dashboardSidebar
and change addClass
in the server to removeClass
.
Option 2:
If you don't want to use shinyjs
you could add a little JS-snippet like:
jss <- HTML("
$(document).on('shiny:connected', function() {
$('.sidebar-toggle').click();
});
")
with
tags$head(tags$script(jss))
in the dashboardBody
and collapsed = TRUE
in the dashboardSidebar
.
app.R
ui <- fluidPage(
dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Main", tabName = "tab1", icon = icon("dashboard")
)
)
),
dashboardBody(
useShinyjs(),
tabItems(
tabItem("tab1",
column(width = 12,
tags$div(id = "main", style = "width: 100%; height: 400px"),
tags$script(src = "http://cdnjs.cloudflare.com/ajax/libs/echarts/4.1.0/echarts.min.js"),
tags$script(src = "myscript.js")
)
)
)
)
)
)
server <- function(input, output) {
addClass(selector = "body", class = "sidebar-collapse")
}
# Run the application
shinyApp(ui = ui, server = server)
myscript.js
option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
};
var myChart = echarts.init(document.getElementById('main'), width='100%');
myChart.setOption(option);
$(window).on('resize', function(){
if(myChart != null && myChart != undefined){
myChart.resize();
}
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With