ramnathv / rCharts

Interactive JS Charts from R
http://rcharts.io
Other
1.19k stars 654 forks source link

dependency management with html_dependency from htmltools #453

Open timelyportfolio opened 10 years ago

timelyportfolio commented 10 years ago

explore the use of https://github.com/rstudio/htmltools/blob/master/R/html_dependency.R to handle js/css dependencies. might help solve issue #200 and #233 and #444

ramnathv commented 10 years ago

I was thinking exactly of this and in fact playing with it! It seems like a neat way to handle dependencies and offers more flexibility with respect to rendering. It would also solve the issue of layouts.

ramnathv commented 10 years ago

We should be able to modify config.yml and write a wrapper function that would call htmlDependency to setup the page.

ramnathv commented 10 years ago

Here is a simple proof-of-concept of how to get rCharts working with the dependency management in htmltools.

## create two charts
r1 <- rPlot(mpg ~ wt, data = mtcars, type = 'point')
r2 <- rPlot(mpg ~ wt, data = mtcars, type = 'point', color = 'gear')

library(htmltools)

## define polychart depenencies
importPolychart <- function(){
  htmlDependency("polychart", "1.0.1",   
    src = system.file('libraries', 'polycharts', package = 'rCharts'),
    script = "js/polychart2.standalone.js"
  )
}

## wrapper function to render chart javascript with dependency
drawPolychart <- function(chart){
  chart_ = paste(capture.output(chart$show('inline')), collapse = '\n')
  attachDependencies(HTML(chart_), importPolychart())
}

## build page using shiny's bootstrap page functions
page = bootstrapPage(fluidRow(
    column(6,  drawPolychart(r1)),
    column(6,  drawPolychart(r2))
))

html_print(page)

To automate this, we might need to overhaul config.yml by adding name and version strings. Then we can write a generic importChart function which will simply accept a library and a package name and automatically read config.yml and do the needful.

This looks promising and might be a simpler way to allow for custom chart layouts instead of messing with afterScript and other hacky methods. @timelyportfolio any comments on this are welcome.

ramnathv commented 10 years ago

I have a more generic approach to this issue, but ran into some bugs as seen here

ramnathv commented 10 years ago

There are two ways to drive a more generic approach. If we were to follow convention over configuration, then it would be good to name all js/css files using the convention name-version.extension. For example jquery-1.8.2.min.js, or polychart-2.1.1.min.js.

Alternately, we could expand config.yml and specify everything explicitly. For example

polychart:
  jshead: 
    - {name: polychart, version: "2.1.1", script = "js/polychart-2.1.1.min.js"}

The first approach means just renaming files and following the convention consistently. The second approach requires more work as we need to update all config.yml files and also the code that parses the config files.

What do you think @timelyportfolio ?

timelyportfolio commented 10 years ago

My first set of thoughts are

Would like to sleep on it and hope for inspiration :)

ramnathv commented 10 years ago

Thanks for your preliminary thoughts @timelyportfolio. Here are my responses to your questions.

Ease

I think both approaches are fairly easy to implement for both rCharts supported libraries as well as plugins. I would lean towards the name-version approach, since it is clean and requires little to no code (am a big fan of convention over configuration for depenencies).

Multiple Versions

I think it would be best if each rCharts library specified the exact version of dependencies, since we are anyway packaging the related file. I would let htmltools handle dependency conflicts, which I believe it resolves by using the latest version. So, I don't think we need to support the minimum/maximum stuff.

Shiny compatibility will happen automatically, since it has been refactored to make use of htmltools. So dependencies will be managed by htmltools even when building a Shiny application.

Looking forward to more thoughts and comments you have.

timelyportfolio commented 10 years ago

Ok, I'm convinced. Let's do it. How can I help?

ramnathv commented 10 years ago

Let me put together my ideas on this and a plan to make this happen. Meanwhile, here is a slightly different approach to packaging HTML widgets.

  1. http://github.com/ramnathv/htmlwidgets
  2. http://github.com/ramnathv/knob
  3. https://github.com/ramnathv/morris

This approach is most suitable for js libraries that pass a purely json payload.

ramnathv commented 10 years ago

The easiest way to handle this without breaking anything is to define an alternate configuration file that has the same format as required by htmltools.

polychart:
  jshead: 
    - {name: polychart, version: "2.1.1", script = "js/polychart-2.1.1.min.js"}

This would allow us to quickly test everything. Subsequently, we can replace config.yml with this, and rewrite the get_config function so that it recognizes the new config file format.