|
- ```{r setup, include=FALSE}
- knitr::opts_chunk$set(eval = FALSE)
- ```
-
- ## Setup R Package
-
- Create a package for this HTML widget.
- We're not going to publish this, so you can call it whatever you want
-
- ```{r create-package}
- usethis::create_package("frappeCharts")
- ```
-
- Add a dev script for notes
-
- ```{r dev}
- dir.create("dev")
- file.create("dev/dev.R")
- rstudioapi::navigateToFile("dev/dev.R")
- ```
-
- ## Setup npm package
-
- Same process again, but this time for npm.
-
- ```bash
- npm init
-
- # or
-
- npm init -y
- ```
-
- Open `package.json` and take a look
-
- ```json
- {
- "name": "frappecharts",
- "version": "0.0.1",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "",
- "license": "MIT"
- }
- ```
-
- From Frappe Charts [docs#installation](https://frappe.io/charts/docs#installation):
-
- ```bash
- npm install frappe-charts
- ```
-
- We now have a dependency in `package.json` and there's a `package-lock.json` file.
-
- ```json
- "dependencies": {
- "frappe-charts": "^1.3.0"
- }
- ```
-
- ## Ignore node_modules but add package-lock
-
- There's also a `node_modules/` folder with `frappe-charts/` inside.
- Add `node_modules` to `.Rbuildignore` and `.gitignore`.
- (BTW, you can and are supposed to commit `package-lock.json`.)
-
- ```{r ignore-node-module}
- usethis::use_build_ignore("node_modules")
- usethis::use_build_ignore("package.json")
- usethis::use_build_ignore("package-lock.json")
- usethis::use_git_ignore("node_modules")
- ```
-
- ## Scaffold the HTML widget
-
- ```{r htmlwidgets-scaffold}
- htmlwidgets::scaffoldWidget("frappeChart")
- ```
-
- This adds files in `inst/htmlwidgets`
-
- ```
- inst
- └── htmlwidgets
- ├── frappeChart.js #<< R <-> JS code
- └── frappeChart.yaml #<< list of dependencies
- ```
-
- and creates a file `R/frappeChart.R` with the functions
-
- - `frappeChart()`
- - `frappeChartOutput()` (for shiny)
- - `renderFrappeChart()` (for shiny)
-
- ## Use `npm` to get our dependencies in the right place
-
- `htmlwidgets` load dependencies in a way that's exactly the same as using a
- `<script>` tag in the HTML `<head>`.
- Look at the documentation on Frappe Charts and decide which file we should use.
-
- Here's the block from their docs
-
- ```
- <script src="https://cdn.jsdelivr.net/npm/frappe-charts@1.2.4/dist/frappe-charts.min.iife.js"></script>
- <!-- or -->
- <script src="https://unpkg.com/frappe-charts@1.2.4/dist/frappe-charts.min.iife.js"></script>
- ```
-
- We need to get our dependecy into a subfolder of `inst/htmlwidgets`.
- Convention is `inst/htmlwidgets/lib/<dependency_name>`.
- Rather than creating the directoy and copying over, etc.,
- we can have an `npm` build script do this for us.
-
- To avoid issues with mac/windows,
- we'll add a dev dependency on [`cpy-cli`](https://github.com/sindresorhus/cpy-cli)
-
- ```bash
- npm install cpy-cli --save-dev
- ```
-
- and
-
- ```{r create-lib-dir}
- dir.create("inst/htmlwidets/lib/frappe-charts", recursive = TRUE)
- ```
-
- and then edit `package.json` to add copy tasks
-
- ```
- "scripts": {
- "copy-js": "cpy 'node_modules/frappe-charts/dist/frappe-charts.min.iife*' inst/htmlwidgets/lib/frappe-charts/",
- "build": "npm run copy-js"
- }
- ```
-
- ## Create a demo html_document_plain()
-
- ```{r create-demo-html}
- dir.create("dev/demo")
- js4shiny::js4shiny_rmd(path = "dev/demo/demo.Rmd")
- ```
-
- Use the example in the [Frappe Charts Docs](https://frappe.io/charts/docs).
-
- ```{r}
- tagList(
- div(id = "chart"),
- htmltools::htmlDependency(
- name = "frappe-charts",
- version = "1.3.0",
- package = "frappeCharts",
- src = "htmlwidgets/lib/frappe-charts",
- script = "frappe-charts.min.iife.js",
- all_files = TRUE
- )
- )
- ```
-
- And copy the JS into a javascript chunk.
-
- `r emo::ji("warning")` The dependencies won't be found until you build/install.
-
- ```{r build-install}
- devtools::document()
- devtools::install()
- ```
-
- If you get a path not found error
-
- ```
- Error: path for html_dependency not found: inst/htmlwidgets/lib/frappe-charts
- ```
-
- it's most likely because
-
- ```
- src = "inst/htmlwidgets/lib/frappe-charts"
- ```
-
- ## Replace the example data with another data set and example
-
- The first demo mixes chart types and we don't want to do that.
- Use the example from
- [Basic Chart](https://frappe.io/charts/docs/basic/basic_chart#adding-more-datasets).
-
- ```js
- const data = {
- labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
- datasets: [
- { name: "R", values: [18, 40, 30, 35, 8, 52, 17, -4] },
- { name: "Python", values: [30, 50, -10, 15, 18, 32, 27, 14] }
- ]
- }
- ```
-
- Then re-create this data in an R chunk:
-
- ```{r data-in-r}
- data <- list(
- labels = c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
- datasets = list(
- list(name = "R", values = c(18, 40, 30, 35, 8, 52, 17, -4)),
- list(name = "Python", values = c(30, 50, -10, 15, 18, 32, 27, 14))
- )
- )
- ```
-
- To get the data out of R and make it available in the document,
- `htmlwidgets` embeds the data in a `<script type="application/json">...</script>`
- element in the page.
- Embed the data from the R chunk in a `<script>` tag with an ID
- so that we can find it later.
-
- ```{r embed-r-data-in-script}
- tags$script(
- id = "data",
- type = "application/json",
- htmlwidgets:::toJSON(data)
- )
- ```
-
- Change to `js4shiny::html_document_js()` so that we can see the `console.log()`
- from JavaScript just like R code.
- And then find the `<script>` tag and get it's `.textContent`.
-
- ```{js find-r-data-script}
- let rData = document.getElementById('data')
- rData.textContent
- ```
-
- Use `JSON.parse()` to turn the data into a JS object
- and replace the data used in the chart.
-
- ```{js find-r-data-script}
- let rData = document.getElementById('data')
- rData = JSON.parse(rData.textContent)
- ```
-
- Switch between `data` and `rData` and it should be the same!
-
- Change the values of the data in the R side to be random
- so that each re-run gives a new plot.
-
- Delete the `data` in the JS side.
-
- ## Augment data to set options for the chart
-
- Embed `data` in another list `opts` that will carry additional options,
- such as `title`, `type` and `colors`.
-
- Parse the embedded `<script>` and pass the whole object to `frappe.Chart()`.
-
- Change the colors to
-
- - `#466683` (dark blue)
- - `#44bc96` (green)
- - `#d33f49` (red)
- - `#993d70` (purple)
|