Creating a React, Highcharts, htmlwidget in R - using packer and highcharter

Updated Last: 2022-11-25

what-we-dev

Today we are going to build a React.js, Highcharts.js, htmlwidget.R using packer & highcharter.

create-pkg

We start by creating a package.

usethis::create_package("~/r_projects/react.highcharts")

init-widget

Once our package loads, we initialize a widget via packer.

packer::scaffold_widget("reactHC")

npm-install

Install React

  • add react & babel
  • add highcharts react
packer:::apply_react(FALSE)
packer::npm_install("highcharts-react-official",scope = "prod")

react-hc

Our first goal is to get to a reprex (reproducible example) we can always improve it.

We add in the example react-highcharts code into the widget scaffolding.

import "widgets";
import React from "react";
import { render } from "react-dom";
import Highcharts from "highcharts";
import HighchartsReact from "highcharts-react-official";

HTMLWidgets.widget({
  name: "reactHC",
  type: "output",
  factory: function (el, width, height) {

    return {
      renderValue: function (x) {
        const App = () => (
          <div>
            <HighchartsReact highcharts={Highcharts} />
          </div>
        );

        render(<App />, document.getElementById(el.id));
      },

    };
  }
});

bundle-webpack

  • Bundle the Widget

  • document & install the R pkg

packer::bundle()
# ✓ Bundled 
devtools::document()
devtools::install()

Hooray! Our React plot works!

react.highcharts::reactHC()

Highcharts React htmlwidgetimproving-it-a-bit

example-data

For this we will use the ggplot2 data set economics.

head(ggplot2::economics)
## # A tibble: 6 × 6
##   date         pce    pop psavert uempmed unemploy
##   <date>     <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
## 1 1967-07-01  507. 198712    12.6     4.5     2944
## 2 1967-08-01  510. 198911    12.6     4.7     2945
## 3 1967-09-01  516. 199113    11.9     4.6     2958
## 4 1967-10-01  512. 199311    12.9     4.9     3143
## 5 1967-11-01  517. 199498    12.8     4.7     3066
## 6 1967-12-01  525. 199657    11.8     4.8     3018

highcharter

Within the existing R implementation - highcharter, we can create a quick chart with a javascript legend placement, like the below:

library(tidyverse)
library(highcharter)

hc <- economics_long %>%
  mutate(date = datetime_to_timestamp(date)) %>%
  hchart("area", hcaes(date, value01, group = variable)) %>%
  hc_xAxis(type = "datetime") %>%
  hc_plotOptions(area = list(stacking = "normal")) %>%
  hc_legend(layout = "proximate", align = "right", labelFormatter = JS("function () {
           ydat = this.yData;
            return this.name + ' ' + ydat[ydat.length-1].toFixed(2); 
        }"))

hc

opts-export

we can then export the options into JSON directly via the R object, or alternatively export the javascript

listviewer::jsonedit(
  hc$x$hc_opts
)
# export JS options

usethis::use_directory("trash")
## ✓ Setting active project to '/Users/zg/r_projects/react.highcharts'
highcharter::export_hc(hc,filename = "trash/example-export.js")

jsx-mod

We modify our reactHC.jsx file to accept the options

renderValue: function (x) {
  const options = x.options;
  ...
  <HighchartsReact 
  highcharts={Highcharts} 
  options={options}/>
  ...  
  }

R-mod

& modify our R function to pass these options to react & javascript

reactHC <- function(options = NULL, width = NULL, height = NULL, elementId = NULL) {

  # forward options using x
  x = list(
    options = options
  )

  # create widget
  htmlwidgets::createWidget(
    name = 'reactHC',
    x,
    width = width,
    height = height,
    package = 'react.highcharts',
    elementId = elementId
  )
}

webpack-bundle

We then repeat the webpack (& R) bundle, document, install process

packer::bundle()
devtools::document()
devtools::install()

test-voila

Test & … Voila!

We now have a React & Highcharts htmlwidget that we can use in R, Shiny, rmarkdown, quarto docs or anywhere you use R (or generally any of the other 64 languages - I’m certain I’m short on the count) that posit supports :) )

Open Q: I do wonder, is there a way for htmlwidgets to interoperate with JS? Can a npm package use a npmR package? If you know, would you PM me?

react.highcharts::reactHC(
 options = hc$x$hc_opts
)

While I plan to explore this further, that’s all for now!

The source code can be found Here

.jsoneditor.jsoneditor-mode-tree{
  background: #ffffff;
}

$(function(){
  $("#toc-highcharts-react-htmlwidgetimproving-it-a-bit > img").remove();
})