Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

293 lines
6.8KB

  1. ```{r setup, include=FALSE}
  2. knitr::opts_chunk$set(eval = FALSE)
  3. ```
  4. ## Setup R Package
  5. Create a package for this HTML widget.
  6. We're not going to publish this, so you can call it whatever you want
  7. ```{r create-package}
  8. usethis::create_package("frappeCharts")
  9. ```
  10. Add a dev script for notes
  11. ```{r dev}
  12. dir.create("dev")
  13. file.create("dev/dev.R")
  14. rstudioapi::navigateToFile("dev/dev.R")
  15. ```
  16. ## Setup npm package
  17. Same process again, but this time for npm.
  18. ```bash
  19. npm init
  20. # or
  21. npm init -y
  22. ```
  23. Open `package.json` and take a look
  24. ```json
  25. {
  26. "name": "frappecharts",
  27. "version": "0.0.1",
  28. "description": "",
  29. "main": "index.js",
  30. "scripts": {
  31. "test": "echo \"Error: no test specified\" && exit 1"
  32. },
  33. "author": "",
  34. "license": "MIT"
  35. }
  36. ```
  37. From Frappe Charts [docs#installation](https://frappe.io/charts/docs#installation):
  38. ```bash
  39. npm install frappe-charts
  40. ```
  41. We now have a dependency in `package.json` and there's a `package-lock.json` file.
  42. ```json
  43. "dependencies": {
  44. "frappe-charts": "^1.3.0"
  45. }
  46. ```
  47. ## Ignore node_modules but add package-lock
  48. There's also a `node_modules/` folder with `frappe-charts/` inside.
  49. Add `node_modules` to `.Rbuildignore` and `.gitignore`.
  50. (BTW, you can and are supposed to commit `package-lock.json`.)
  51. ```{r ignore-node-module}
  52. usethis::use_build_ignore("node_modules")
  53. usethis::use_build_ignore("package.json")
  54. usethis::use_build_ignore("package-lock.json")
  55. usethis::use_git_ignore("node_modules")
  56. ```
  57. ## Scaffold the HTML widget
  58. ```{r htmlwidgets-scaffold}
  59. htmlwidgets::scaffoldWidget("frappeChart")
  60. ```
  61. This adds files in `inst/htmlwidgets`
  62. ```
  63. inst
  64. └── htmlwidgets
  65. ├── frappeChart.js #<< R <-> JS code
  66. └── frappeChart.yaml #<< list of dependencies
  67. ```
  68. and creates a file `R/frappeChart.R` with the functions
  69. - `frappeChart()`
  70. - `frappeChartOutput()` (for shiny)
  71. - `renderFrappeChart()` (for shiny)
  72. ## Use `npm` to get our dependencies in the right place
  73. `htmlwidgets` load dependencies in a way that's exactly the same as using a
  74. `<script>` tag in the HTML `<head>`.
  75. Look at the documentation on Frappe Charts and decide which file we should use.
  76. Here's the block from their docs
  77. ```
  78. <script src="https://cdn.jsdelivr.net/npm/frappe-charts@1.2.4/dist/frappe-charts.min.iife.js"></script>
  79. <!-- or -->
  80. <script src="https://unpkg.com/frappe-charts@1.2.4/dist/frappe-charts.min.iife.js"></script>
  81. ```
  82. We need to get our dependecy into a subfolder of `inst/htmlwidgets`.
  83. Convention is `inst/htmlwidgets/lib/<dependency_name>`.
  84. Rather than creating the directoy and copying over, etc.,
  85. we can have an `npm` build script do this for us.
  86. To avoid issues with mac/windows,
  87. we'll add a dev dependency on [`cpy-cli`](https://github.com/sindresorhus/cpy-cli)
  88. ```bash
  89. npm install cpy-cli --save-dev
  90. ```
  91. and
  92. ```{r create-lib-dir}
  93. dir.create("inst/htmlwidets/lib/frappe-charts", recursive = TRUE)
  94. ```
  95. and then edit `package.json` to add copy tasks
  96. ```
  97. "scripts": {
  98. "copy-js": "cpy 'node_modules/frappe-charts/dist/frappe-charts.min.iife*' inst/htmlwidgets/lib/frappe-charts/",
  99. "build": "npm run copy-js"
  100. }
  101. ```
  102. ## Create a demo html_document_plain()
  103. ```{r create-demo-html}
  104. dir.create("dev/demo")
  105. js4shiny::js4shiny_rmd(path = "dev/demo/demo.Rmd")
  106. ```
  107. Use the example in the [Frappe Charts Docs](https://frappe.io/charts/docs).
  108. ```{r}
  109. tagList(
  110. div(id = "chart"),
  111. htmltools::htmlDependency(
  112. name = "frappe-charts",
  113. version = "1.3.0",
  114. package = "frappeCharts",
  115. src = "htmlwidgets/lib/frappe-charts",
  116. script = "frappe-charts.min.iife.js",
  117. all_files = TRUE
  118. )
  119. )
  120. ```
  121. And copy the JS into a javascript chunk.
  122. `r emo::ji("warning")` The dependencies won't be found until you build/install.
  123. ```{r build-install}
  124. devtools::document()
  125. devtools::install()
  126. ```
  127. If you get a path not found error
  128. ```
  129. Error: path for html_dependency not found: inst/htmlwidgets/lib/frappe-charts
  130. ```
  131. it's most likely because
  132. ```
  133. src = "inst/htmlwidgets/lib/frappe-charts"
  134. ```
  135. ## Replace the example data with another data set and example
  136. The first demo mixes chart types and we don't want to do that.
  137. Use the example from
  138. [Basic Chart](https://frappe.io/charts/docs/basic/basic_chart#adding-more-datasets).
  139. ```js
  140. const data = {
  141. labels: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
  142. datasets: [
  143. { name: "R", values: [18, 40, 30, 35, 8, 52, 17, -4] },
  144. { name: "Python", values: [30, 50, -10, 15, 18, 32, 27, 14] }
  145. ]
  146. }
  147. ```
  148. Then re-create this data in an R chunk:
  149. ```{r data-in-r}
  150. data <- list(
  151. labels = c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"),
  152. datasets = list(
  153. list(name = "R", values = c(18, 40, 30, 35, 8, 52, 17, -4)),
  154. list(name = "Python", values = c(30, 50, -10, 15, 18, 32, 27, 14))
  155. )
  156. )
  157. ```
  158. To get the data out of R and make it available in the document,
  159. `htmlwidgets` embeds the data in a `<script type="application/json">...</script>`
  160. element in the page.
  161. Embed the data from the R chunk in a `<script>` tag with an ID
  162. so that we can find it later.
  163. ```{r embed-r-data-in-script}
  164. tags$script(
  165. id = "data",
  166. type = "application/json",
  167. htmlwidgets:::toJSON(data)
  168. )
  169. ```
  170. Change to `js4shiny::html_document_js()` so that we can see the `console.log()`
  171. from JavaScript just like R code.
  172. And then find the `<script>` tag and get it's `.textContent`.
  173. ```{js find-r-data-script}
  174. let rData = document.getElementById('data')
  175. rData.textContent
  176. ```
  177. Use `JSON.parse()` to turn the data into a JS object
  178. and replace the data used in the chart.
  179. ```{js find-r-data-script}
  180. let rData = document.getElementById('data')
  181. rData = JSON.parse(rData.textContent)
  182. ```
  183. Switch between `data` and `rData` and it should be the same!
  184. Change the values of the data in the R side to be random
  185. so that each re-run gives a new plot.
  186. ~~Delete the `data` in the JS side.~~
  187. Comment out the `data` on the JS side (but we'll want to see the structure later).
  188. ## Augment data to set options for the chart
  189. Embed `data` in another list `opts` that will carry additional options,
  190. such as `title`, `type` and `colors`.
  191. Parse the embedded `<script>` and pass the whole object to `frappe.Chart()`.
  192. Change the colors to
  193. - `#466683` (dark blue)
  194. - `#44bc96` (green)
  195. - `#d33f49` (red)
  196. - `#993d70` (purple)
  197. ## Learn about other options for line charts
  198. Read <https://frappe.io/charts/docs/basic/trends_regions>
  199. and add and test additional line options.
  200. Goal: shaded area chart with lines only.
  201. Make the `labels` one week and repeat 4 times.
  202. Generate `runif(7 * 4)` random numbers.
  203. ```r
  204. rep(c("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"), 4)
  205. ```
  206. Find and implement an option to reduce the number of labels on the x-axis.
  207. ## Turn on dots again and make navigable
  208. ```{r}
  209. opts <- list(
  210. title = "My AwesomeR Chart",
  211. type = "bar",
  212. height = 250,
  213. colors = c("#466683", "#44bc96"),
  214. data = data,
  215. axisOptions = list(xIsSeries = TRUE),
  216. isNavigable = TRUE
  217. )
  218. ```