shinyJsTutorials icon indicating copy to clipboard operation
shinyJsTutorials copied to clipboard

Creating my own widget

Open Tixierae opened this issue 6 years ago • 0 comments

I followed the exact template of your Gauge widget to try to create a histogram widget (.js and .R files below).

The core of the .js file works. If you just paste the whole var chart = c3.generate({...}) statement into http://c3js.org/samples/chart_bar.html, adding the lines

var x = {
"x1":[0, 50, 100, 150, 200, 250],
"prob":[0.3, 0.2, 0.1, 0.05, 0.04, 0.01],
"my_th":2
};

at the top, the histogram shows as expected. However, when executing

C3Hist(x1=c(0, 50, 100, 150, 200, 250),prob=c(0.3, 0.2, 0.1, 0.05, 0.04, 0.01),my_th=2)

in RStudio, nothing shows. So, I believe that my bindings are at fault, but I couldn't find what's wrong. Could you please have a quick look? Your help would be much appreciated.

If you need to reproduce the error, you can install my fork of C3 with devtools::install_github("tixierae/shinyJsTutorials/tutorials/materials2/C3"). Note that I created a C3Hist.yaml file, and added export(C3Hist);export(C3HistOutput) to the NAMESPACE file.

C3Hist.R

C3Hist <- function(prob,x1,my_th,width=NULL,height=NULL) {
  # forward options using x
  x = list(
    prob = prob,
    x1 = x1,
    my_th = my_th
  )
  # create widget
  htmlwidgets::createWidget(
    name = 'C3Hist',
    x,
    width = width,
    height = height,
    package = 'C3'
  )
}
C3HistOutput <- function(outputId, width = '100%', height = '400px'){
  htmlwidgets::shinyWidgetOutput(outputId, 'C3Hist', width, height, package = 'C3')
}
renderC3Hist <- function(expr, env = parent.frame(), quoted = FALSE) {
  if (!quoted) { expr <- substitute(expr) } # force quoted
  htmlwidgets::shinyRenderWidget(expr, C3HistOutput, env, quoted = TRUE)
}

C3Hist.js

HTMLWidgets.widget({
    name: 'C3Hist',
    type: 'output',
    factory: function(el, width, height) {
        // create an empty chart
        var chart = null;
        return {
            renderValue: function(x) {
                // check if the chart exists
                if(chart === null){
                    // the chart did not exist and we want to create a new chart via c3.generate
                    var chart = c3.generate({  
                        bindto : el,
                        data: {
                            columns: [
                                ['x1'].concat(x.x1),
                                ['prob'].concat(x.prob)
                            ],
                            type: 'bar',
                            xs: {
                                'prob': 'x1', 
                            },
                            colors: {
                                prob: function(d) {
                                    return (x.prob.indexOf(d.value) >= x.my_th) ? '#aec7e8':'#1f77b4';
                                }
                            },
                            onclick:  function (d, element) {Shiny.onInputChange(el.id,d)}
                        },
                        bar: {
                            width: {
                                ratio: 1 // this makes bar width 100% of length between ticks
                            }
                        },
                        legend: {
                            show: false
                        },
                        // take care of color in tooltip
                        tooltip: {
                            contents: function (d, defaultTitleFormat, defaultValueFormat, color) {
                                color = function() {
                                    return (x.prob.indexOf(d[0].value) >= x.my_th) ? '#aec7e8':'#1f77b4';
                                };
                                return chart.internal.getTooltipContent.call(this, d, defaultTitleFormat, defaultValueFormat, color)
                            }
                        }
                    });
                    // store the chart on el so we can get it latter
                    el.chart = chart;
                }
                // at this stage the chart always exists
                // load the new data
                chart.load({
                    columns: [
                        ['x1'].concat(x.x1),
                        ['prob'].concat(x.prob)
                    ]
                });
            },
            resize: function(width, height) {
                // this will vary based on the JavaScript library
                // in the case of C3 we are fortunate that there is a resize method
                //  http://c3js.org/samples/api_resize.html
                chart.resize({height:height, width:width})
            }
        };
    }
});

Tixierae avatar Mar 30 '18 09:03 Tixierae