Difficulty in developing javascript graph using htmlwidgets

Hi all,

I am currently developing a package for AWS Stepfunctions: (GitHub - DyfanJones/aws-step-functions-data-science-sdk-r: Step Functions Data Science SDK for building machine learning (ML) workflows and pipelines on AWS). The package has been developed from the Python version (GitHub - aws/aws-step-functions-data-science-sdk-python: Step Functions Data Science SDK for building machine learning (ML) workflows and pipelines on AWS).

I wish to render the JavaScript graphs within RStudio. I am coming across the following javascript error: sfn.min.js:60 Uncaught TypeError: Cannot read property 'getBBox' of null. However the jupyter notebook version renders successfully. (I believe it due to my lack of understanding of how the htmlwidget package works).

Jupyter Notebook rendering code example:

IRdisplay::display_html('<link rel="stylesheet" type="text/css" href="https://do0of8uwbahzz.cloudfront.net/graph.css">
  <div id="graph-966" class="workflowgraph">
    
    <svg></svg>
    
    </div>
    <script type="text/javascript">
      
      require.config({
        paths: {
          sfn: "https://do0of8uwbahzz.cloudfront.net/sfn",
        }
      });
    require([\'sfn\'], function(sfn) {
      var element = document.getElementById(\'graph-966\')
      var options = {
        width: parseFloat(getComputedStyle(element, null).width.replace("px", "")),
        height: 600,
        layout: \'LR\',
        resizeHeight: true
      };
      var definition = {"StartAt":"MyPassState","States":{"MyPassState":{"Type":"Pass","Next":"Wait for 3 seconds"},"Wait for 3 seconds":{"Seconds":3,"Type":"Wait","Next":"Convert HelloWorld to Base64"},"Convert HelloWorld to Base64":{"Parameters":{"FunctionName":"MyLambda","Payload":{"input":"HelloWorld"}},"Resource":"arn:aws:states:::lambda:invoke","Type":"Task","End":true,"Retry":[{"Error_equals":["States.TaskFailed"],"Interval_seconds":15,"Max_attempts":2,"Backoff_rate":4}],"Catch":[{"Error_equals":"States.TaskFailed","Next":"LambdaTaskFailed"}]},"LambdaTaskFailed":{"Type":"Fail"}}};
      var elementId = \'#graph-966\';
      var graph = new sfn.StateMachineGraph(definition, elementId, options);
      graph.render();
    });
    
    </script>')

Htmlwidget version

R binding:

sfn_flow_graph <- function(definition, portrait = FALSE,  width = NULL, height = 600) {

  if (isFALSE(portrait))
    layout = 'LR'
  else
    layout = 'TB'

  # forward options using params
  params = list(
    definition = definition,
    layout = layout
  )
  # create widget
  htmlwidgets::createWidget(
    name = 'sfn_flow_graph',
    params,
    width = width,
    height = height,
    package = 'stepfunctions',
    elementId = sprintf('graph-%d', as.integer(stats::runif(1, 0, 999)))
  )
}

JavaScript binding:

HTMLWidgets.widget({

  name: "sfn_flow_graph",

  type: "output",

  factory: function(el, width, height) {

    return {

      renderValue: function(x) {
          // Commmented out code from jupyter notebook rendering: workflow_widgets_graph.R
          // var element = document.getElementById(el.id);
          // parseFloat(getComputedStyle(element, null).width.replace("px", ""))
          var options = {
              width: width,
              height: height,
              layout: x.layout,
              resizeHeight: true
          };
          var definition = x.definition;

          var graph = new sfn.StateMachineGraph(definition, '#'+el.id, options);
          graph.render();

      },

      resize: function(width, height) {
      }
    };
  }
});

yaml Dependencies:

dependencies:
 - name: d3
   version: 4.13.0
   src: "htmlwidgets/lib/d3"
   script: "d3.min.js"
 - name: dagre
   version: 0.6.3
   src: "htmlwidgets/lib/dagre-d3"
   script: "dagre-d3.min.js"
 - name: sfn
   version: 0.1.5
   src: "htmlwidgets/lib/sfn_graph"
   script: "sfn.min.js"
   stylesheet: "sfn.css"

Example of running code:

state_def <- "{\"StartAt\":\"MyPassState\",\"States\":{\"MyPassState\":{\"Type\":\"Pass\",\"Next\":\"Wait for 3 seconds\"},\"Wait for 3 seconds\":{\"Seconds\":3,\"Type\":\"Wait\",\"Next\":\"Convert HelloWorld to Base64\"},\"Convert HelloWorld to Base64\":{\"Parameters\":{\"FunctionName\":\"MyLambda\",\"Payload\":{\"input\":\"HelloWorld\"}},\"Resource\":\"arn:aws:states:::lambda:invoke\",\"Type\":\"Task\",\"End\":true,\"Retry\":[{\"Error_equals\":[\"States.TaskFailed\"],\"Interval_seconds\":15,\"Max_attempts\":2,\"Backoff_rate\":4}],\"Catch\":[{\"Error_equals\":\"States.TaskFailed\",\"Next\":\"LambdaTaskFailed\"}]},\"LambdaTaskFailed\":{\"Type\":\"Fail\"}}}"
state_list = jsonlite::fromJSON(state_def)

sfn_flow_graph(
  definition = jsonlite::toJSON(state_list, auto_unbox= T)
)

This returns an error:

sfn.min.js:60 Uncaught TypeError: Cannot read property 'getBBox' of null
    at width (sfn.min.js:60)
    at t.value (sfn.min.js:60)
    at Object.renderValue (sfn_flow_graph.js:24)
    at Object.renderValue (htmlwidgets.js:886)
    at htmlwidgets.js:653
    at Array.forEach (<anonymous>)
    at forEach (htmlwidgets.js:55)
    at htmlwidgets.js:576
    at Array.forEach (<anonymous>)
    at forEach (htmlwidgets.js:55)

The error seems to be coming from aws javascript dependency "sfn.min.js" however I think it is because the dependencies of "sfn.min.js" (d3, dagre-d3) not being picked up.

My code is currently on the branch "htmlwidget" of repo: aws-step-functions-data-science-sdk-r

Any help with this would be greatly appreciated.

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.