rstudio / flexdashboard

Easy interactive dashboards for R
https://pkgs.rstudio.com/flexdashboard/
Other
812 stars 301 forks source link

Problems with tables from `gt` package #267

Closed awgymer closed 1 year ago

awgymer commented 4 years ago

It seems that flexdashboard doesn't recognise tables generated with the gt package as tables, I believe because they are wrapped in div and the table element isn't at the top level of the content. This leads to them being put inside chart-shim wrappers which cause long tables to be cut off.

I think this is a more general problem with the way flexdashboard decides what sort of container to put content in, because I've noticed the same thing happen when I generate custom HTML content for a section with htmltools.

An example is when I tried to put an image and a guage in the same section:

div(
div(class = "rage-guage-wrapper",
   div(class = "rage-guage-logo-wrap", img(class = "rage-guage-logo",  src=get_team_logo(TEAM_0, logos_pth))),
   div(class = "rage-guage-guage",
     gauge(
       ref_rating[allegiance==TEAM_0, rating], min = -1, max = 1, 
       gaugeSectors(success = c(0.25, 1), warning = c(-0.25, 0.25), danger = c(-0.25, -1))
   )
)
))

It would be useful if there was some way to force a row/column section to behave in a fixed manner rather than relying on its guesswork. Perhaps something like being able to do:

### Custom Table Section {tabular}

or

### Custom HTML section {noshim}

jthomasmock commented 3 years ago

Just a heads up, you can get scrolling for gt or other arbitrary output by wrapping gt in a div():

div(style='height:100%; overflow-y:scroll', gt(mtcars))
Full Example of an R Markdown doc ```` --- title: "Untitled" output: flexdashboard::flex_dashboard: orientation: columns vertical_layout: scroll --- ```{r setup, include=FALSE} library(flexdashboard) library(tidyverse) library(gt) library(kableExtra) library(htmltools) ``` Column {data-width=650;} ----------------------------------------------------------------------- ### Chart A ```{r} div(style = 'height:100%; overflow-y: scroll', gt(mtcars)) ``` Column {data-width=350;} ----------------------------------------------------------------------- ### Chart B ```{r} div(style='height:100%; overflow-y: scroll', gt(mtcars)) ``` ### Chart C ```{r} div(style='height:100%; overflow-y: scroll', gt(mtcars)) ``` ````
awgymer commented 3 years ago

This was a while back now, but the issue was I think I explicitly didn't want scrolling. Like with a kable table it just expands the divs to the size of the largest table. I ended up adding some custom JS to create an extra component finder:

// gt tables
window.FlexDashboardComponents.push({
  find: function(container) {
    return container.find('.gt-no-scroll');
  },
  flex: function(fillPage) {
    return fillPage;
  }
});

Then wrapping my gt tables in a div with that class (I think that maybe now gt supports adding classes to top-level divs itself?).

You can see an example of it in practice here

Nilafhiosagam commented 3 years ago

I'm facing the same issue

Using jthomasmock's approach with div() inserts a scroll bar but it doesn't scroll. My html knowledge is zero

I have the output as: orientation: rows vertical_layout: scroll

image

Edit: Actually thanks @awgymer I was able to use your custom JS to blindly achieve my aim

lstarkey commented 2 years ago

This was a while back now, but the issue was I think I explicitly didn't want scrolling. Like with a kable table it just expands the divs to the size of the largest table. I ended up adding some custom JS to create an extra component finder:

// gt tables
window.FlexDashboardComponents.push({
  find: function(container) {
    return container.find('.gt-no-scroll');
  },
  flex: function(fillPage) {
    return fillPage;
  }
});

Then wrapping my gt tables in a div with that class (I think that maybe now gt supports adding classes to top-level divs itself?).

You can see an example of it in practice here

This is so so close to helping me address my problem, except the "fillpage" fix doesn't allow the content to scroll. By which I mean, it prevents it from being placed in the chart-shim div and instead places it in the main div, but I cannot see all of the content.

I am trying to embed responsive HTML into a flexdashboard storyboard.

Rmd:

---
title: "Title"
output: 
  flexdashboard::flex_dashboard:
    theme:
      version: 5
      bootswatch: litera

runtime: shiny
---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)

load("my_work_space.RData")

library(tidyverse)
library(dplyr)
library(htmltools)
library(shiny)

Body {.storyboard}

Slide1


htmltools::includeHTML('www/timeline.html') %>% HTML()

Slide2

timeline.html:

<!DOCTYPE html>

Mustafa Kemal Atatürk

FATHER OF THE TURKS

1881

He was born in 1881 (probably in the spring) in Salonica, then an Ottoman city, now inGreece. His father Ali Riza, a customs official turned lumber merchant, died when Mustafawas still a boy. His mother Zubeyde, adevout and strong-willed woman, raised him and his sister.

1893

First enrolled in a traditionalreligious school, he soon switched to a modern school. In 1893, he entered a military highschool where his mathematics teacher gave him the second name Kemal (meaning perfection)in recognition of young Mustafa's superior achievement.

1905

In 1905, Mustafa Kemal graduated from the War Academy in Istanbul with the rank of Staff Captain. Posted in Damascus, he started with several colleagues, a clandestinesociety called "Homeland and Freedom" to fight against the Sultan'sdespotism.

1908

In 1908 he helped the group of officers who toppled the Sultan. Mustafa Kemal'scareer flourished as he won his heroism in the far corners of the Ottoman Empire,including Albania and Tripoli. He also briefly served as a staff officer in Salonica andIstanbul and as a military attache in Sofia.

1915

In 1915, when Dardanelles campaign was launched, Colonel Mustafa Kemal became anational hero by winning successive victories and finally repelling the invaders.

1916

Promotedto general in 1916, at age 35, he liberated two major provinces in eastern Turkey thatyear. In the next two years, he served as commander of several Ottoman armies inPalestine, Aleppo, and elsewhere, achieving another major victory by stopping the enemyadvance at Aleppo.

1919

On May 19, 1919, Mustafa Kemal Pasha landed in the Black Sea port of Samsun to startthe War of Independence. In defiance of the Sultan's government, he rallied a liberationarmy in Anatolia and convened the Congress of Erzurum and Sivas which established thebasis for the new national effort under his leadership.

1920

On April 23, 1920, the GrandNational Assembly was inaugurated. Mustafa Kemal Pasha was elected to its Presidency. Fighting on many fronts, he led his forces to victory against rebels and invadingarmies. Following the Turkish triumph at the two major battles at Inonu in Western Turkey,the Grand National Assembly conferred on Mustafa Kemal Pasha the title ofCommander-in-Chief with the rank of Marshal.

1922

At the end of August 1922, the Turkish armieswon their ultimate victory. Within a few weeks, the Turkish mainland was completelyliberated, the armistice signed, and the rule of the Ottoman dynasty abolished

1923

In July 1923, the national government signed the Lausanne Treaty with Great Britain,France, Greece, Italy, and others. In mid-October, Ankara became the capital of the new Turkish State. On October 29, the Republic was proclaimed and Mustafa Kemal Pasha wasunanimously elected President of the Republic.

1934

The account of Atatürk's fifteen year Presidency is a saga of dramatic modernization.With indefatigable determination, he created a new political and legal system, abolished the Caliphate and made both government and education secular, gave equal rights to women,changed the alphabet and the attire, and advanced the arts and the sciences, agricultureand industry. In 1934, when the surname law was adopted, the national parliament gave him the name"Atatürk" (Father of the Turks)

1938

On November 10, 1938, following an illness of a few months, the national liberator and the Father of modern Turkey died. But his legacy to his people and to the world endures.

``` Javascript: ``` (function ($) { $.fn.timeline = function () { var selectors = { id: $(this), item: $(this).find(".timeline-item"), activeClass: "timeline-item--active", img: ".timeline__img" }; selectors.item.eq(0).addClass(selectors.activeClass); selectors.id.css( "background-image", "url(" + selectors.item.first().find(selectors.img).attr("src") + ")" ); var itemLength = selectors.item.length; $(window).scroll(function () { var max, min; var pos = $(this).scrollTop(); selectors.item.each(function (i) { min = $(this).offset().top; max = $(this).height() + $(this).offset().top; var that = $(this); if (i == itemLength - 2 && pos > min + $(this).height() / 2) { selectors.item.removeClass(selectors.activeClass); selectors.id.css( "background-image", "url(" + selectors.item.last().find(selectors.img).attr("src") + ")" ); selectors.item.last().addClass(selectors.activeClass); } else if (pos <= max - 40 && pos >= min) { selectors.id.css( "background-image", "url(" + $(this).find(selectors.img).attr("src") + ")" ); selectors.item.removeClass(selectors.activeClass); $(this).addClass(selectors.activeClass); } }); }); }; })(jQuery); $("#timeline-1").timeline(); window.FlexDashboardComponents.push({ find: function(container) { return container.find('.timeline-container'); }, flex: function(fillpage) { return fillpage; } }); ``` CSS: ``` @import url("https://fonts.googleapis.com/css?family=Cardo|Pathway+Gothic+One"); .timeline { display: flex; margin: 0 auto; flex-wrap: wrap; flex-direction: column; max-width: 700px; position: relative; } .timeline__content-title { font-weight: normal; font-size: 66px; margin: -10px 0 0 0; transition: 0.4s; padding: 0 10px; box-sizing: border-box; font-family: "Pathway Gothic One", sans-serif; color: #fff; } .timeline__content-desc { margin: 0; font-size: 15px; box-sizing: border-box; color: rgba(255, 255, 255, 0.7); font-family: Cardo; font-weight: normal; line-height: 25px; } .timeline:before { position: absolute; left: 50%; width: 2px; height: 100%; margin-left: -1px; content: ""; background: rgba(255, 255, 255, 0.07); } @media only screen and (max-width: 767px) { .timeline:before { left: 40px; } } .timeline-item { padding: 40px 0; opacity: 0.3; filter: blur(2px); transition: 0.5s; box-sizing: border-box; width: calc(50% - 40px); display: flex; position: relative; transform: translateY(-80px); } .timeline-item:before { content: attr(data-text); letter-spacing: 3px; width: 100%; position: absolute; color: rgba(255, 255, 255, 0.5); font-size: 13px; font-family: "Pathway Gothic One", sans-serif; border-left: 2px solid rgba(255, 255, 255, 0.5); top: 70%; margin-top: -5px; padding-left: 15px; opacity: 0; right: calc(-100% - 56px); } .timeline-item:nth-child(even) { align-self: flex-end; } .timeline-item:nth-child(even):before { right: auto; text-align: right; left: calc(-100% - 56px); padding-left: 0; border-left: none; border-right: 2px solid rgba(255, 255, 255, 0.5); padding-right: 15px; } .timeline-item--active { opacity: 1; transform: translateY(0); filter: blur(0px); } .timeline-item--active:before { top: 50%; transition: 0.3s all 0.2s; opacity: 1; } .timeline-item--active .timeline__content-title { margin: -50px 0 20px 0; } @media only screen and (max-width: 767px) { .timeline-item { align-self: baseline !important; width: 100%; padding: 0 30px 150px 80px; } .timeline-item:before { left: 10px !important; padding: 0 !important; top: 50px; text-align: center !important; width: 60px; border: none !important; } .timeline-item:last-child { padding-bottom: 40px; } } .timeline__img { max-width: 100%; box-shadow: 0 10px 15px rgba(0, 0, 0, 0.4); } .timeline-container { width: 100%; position: relative; padding: 80px 0; transition: 0.3s ease 0s; background-attachment: fixed; background-size: cover; } .timeline-container:before { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: rgba(99, 99, 99, 0.8); content: ""; } .timeline-header { width: 100%; text-align: center; margin-bottom: 80px; position: relative; } .timeline-header__title { color: #fff; font-size: 46px; font-family: Cardo; font-weight: normal; margin: 0; } .timeline-header__subtitle { color: rgba(255, 255, 255, 0.5); font-family: "Pathway Gothic One", sans-serif; font-size: 16px; letter-spacing: 5px; margin: 10px 0 0 0; font-weight: normal; } .demo-footer { padding: 60px 0; text-align: center; } .demo-footer a { color: #999; display: inline-block; font-family: Cardo; } ```
awgymer commented 2 years ago

@lstarkey yes, per above I didn't want it to scroll so that doesn't surprise me.

Not sure exactly what you are trying to achieve but I have a scrollable table on the page I linked at the end of my previous comment (Where in the world? Section) that might be what you are after so you could look at what I did there (this was ages ago so off the top of my head I can't tell you)

I actually can't even remember what fillpage does but perhaps that is a setting you can change to get what you need?

lstarkey commented 2 years ago

Sigh, not quite. My issue is that the responsive JS doesn't work when the HTML is placed in the chart-shim div, because it responds to the div's scroll and not the larger page scroll (if that makes sense?). I need some way to override placement in the chart-shim div so that window scroll is the only one available. Thank you anyhow!

awgymer commented 2 years ago

Hmm I seem to remember when I was trying to make this work I spent a lot of time working in chrome devtools to adjust the css until I had the layout I wanted and then worked out how to make flexdashboard generate that.

Do you know what actual settings you need the table/div to have yet?

lstarkey commented 2 years ago

nope, not sure. Thanks anyway!

gadenbuie commented 1 year ago

It seems this has been resolved for everyone! If you're facing a similar challenge, definitely check out Tom's comment here. If you happen to have a similar problem, please open a new issue with a reprex and we'll be happy to look into it.