Build Your Own React-based htmlwidget!!!

Build Your Own React-based htmlwidget!!!

reactR 是一种新的建造 html 控件的工作流程。本文基于对 Build Your Own React-based htmlwidget 的学习,自己构建了一个绘制华夫图的 html 控件。

安装 reactR

1
devtools::install_github("react-R/reactR")

Build Your Own React-based htmlwidget 一文中介绍了如何构建日历图小部件的流程,可以先安装试用一下:nivocal

1
devtools::install_github('react-R/nivocal')
1
2
3
4
5
6
7
8
9
10
11
12
library(nivocal)

df <- data.frame(
day = seq.Date(
from = as.Date("2017-03-15"),
length.out = 500,
by = "days"
),
value = round(runif(500)*1000, 0)
)

nivocal(df)

1
2
3
4
5
6
7
8
9
10
11
nivocal(
df,
emptyColor = "#eeeeee",
colors = c(
"#61cdbb",
"#97e3d5",
"#e8c1a0",
"#f47560"),
monthBorderColor = "#ffffff",
dayBorderColor = "#ffffff"
)

开始制作华夫图的控件

华夫图的示例在这里:waffle

创建 nivowaffle 包

1
usethis::create_package('nivowaffle')

创建名为 nivowaffle 的草稿

1
2
3
reactR::scaffoldReactWidget(
'nivowaffle',
npmPkgs = c("@nivo/waffle" = "0.52.1"))

你可以在这个网站上找到你想制作的控件的版本:https://unpkg.com/@nivo/[email protected]/

完成下面的两步之后,你的包的结构应该是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ tree
.
├── DESCRIPTION
├── NAMESPACE
├── R
│ └── nivowaffle.R
├── app.R
├── inst
│ └── htmlwidgets
│ └── nivowaffle.yaml
├── man
├── nivowaffle.Rproj
├── package.json
├── srcjs
│ └── nivowaffle.js
└── webpack.config.js

5 directories, 9 files

首先编辑 nivowaffle.js

1
2
3
4
5
6
7
8
9
import { reactWidget } from 'reactR';
import { ResponsiveWaffle } from '@nivo/waffle';

reactWidget(
'nivowaffle',
'output',
{ResponsiveWaffle: ResponsiveWaffle},
{}
);

然后我们需要使用 yarn 进行打包,在终端运行(可以直接在 RStudio 中开启):

1
2
3
4
5
# 如果你没有安装yarn,你可以使用brew进行安装:
brew install yarn
# 然后运行,注意是先要把目录切换到包目录里面
cd nivowaffle
yarn install

在进行下一步之前,你需要先把 webpack.config.js 文件打开根据你的需要输入下面的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var path = require('path');

module.exports = {
entry: path.join(__dirname, 'srcjs', 'nivowaffle.js'),
output: {
path: path.join(__dirname, 'inst', 'htmlwidgets'),
filename: 'nivowaffle.js'
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
]
},
externals: {
'react': 'window.React',
'react-dom': 'window.ReactDOM',
'reactR': 'window.reactR'
},
stats: {
colors: true
},
devtool: 'source-map'
};

显然,这样设置的目的是将 nivowaffle.js 编译后移动到 /inst/htmlwidgets文件夹里。

完成这一步之后再回到终端:

1
yarn run webpack

打包完成!!!

R 函数绑定

R 函数绑定的目的是将 R 的数据传递给 JS,我们注意到 JS 接收的数据应该是这样的:

我们可以按照下面的方式修改 nivowaffle.R 中的 nivowaffle() 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#' 绘制华夫图
#'
#' @import htmlwidgets
#'
#' @export
nivowaffle <- function(
data = NULL,
total = 100,
rows = 18,
columns = 14,
colorBy = "id",
width = NULL,
height = NULL,
elementId = NULL) {

data <- mapply(
function(id, label, value, color){
list(
id = id,
label = label,
value = value,
color = color
)
},
data$id,
data$label,
data$value,
data$color,
SIMPLIFY = FALSE
)

component <- reactR::reactMarkup(htmltools::tag(
"ResponsiveWaffle",
list(
data = data,
total = total,
rows = rows,
columns = columns,
colorBy = colorBy
)
)
)

编译和安装

下面再编译和安装包:

1
2
devtools::document()
devtools::install(quick = TRUE)

测试

1
2
3
4
5
6
7
8
library(nivowaffle)
df <- data.frame(
id = c("men", "women", "children"),
label = c("men", "women", "children"),
value = c(20, 13, 16),
color = c("#468df3", "#ba72ff", "#a1cfff")
)
nivowaffle(df)

为了更自由地添加自定义化,我们可以按照下面的方式修改 nivowaffle.R 中的 nivowaffle() 函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#' 绘制华夫图
#'
#' @import htmlwidgets
#'
#' @export
nivowaffle <- function(
data = NULL,
total = 100,
rows = 18,
columns = 14,
colorBy = "id",
...,
width = NULL,
height = NULL,
elementId = NULL) {

data <- mapply(
function(id, label, value, color){
list(
id = id,
label = label,
value = value,
color = color
)
},
data$id,
data$label,
data$value,
data$color,
SIMPLIFY = FALSE
)

component <- reactR::reactMarkup(htmltools::tag(
"ResponsiveWaffle",
list(
data = data,
total = total,
rows = rows,
columns = columns,
colorBy = colorBy,
...
)
)
)

也就是说,我加了两个省略号。重新安装之后再运行:

1
2
3
4
5
6
7
nivowaffle(df,
total = 100,
rows = 14,
columns = 18,
colors="accent",
borderColor="inherit:darker(0.3)",
fillDirection = "left")

其中 colors 参数可以使用 http://colorbrewer2.org 的调色板名称,再例如:

1
2
3
4
5
6
7
nivowaffle(df,
total = 100,
rows = 10,
columns = 18,
colors="set2",
borderColor="inherit:darker(0.3)",
fillDirection = "left")

运行示例 shiny APP

你需要把包文件夹里面的 app.R 中的 server 里面的函数改一下,例如上面那个。

1
shiny::runApp()

GitHub

最后我把这个包稍微整理了一下放在我的 GitHub 上:nivowaffle,欢迎测试。

# R

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×