0

The authoring page https://rstudio.github.io/crosstalk/authoring.html says to create sel_handle at factory scope, before returning renderValue and resize. Is this necessary (e.g. because it needs to be created before renderValue is called), or could it be created in renderValue(), and attached to scatter? I'm referring to the sample code from that page, i.e.

HTMLWidgets.widget({

  name: 'd3scatter',

  type: 'output',

  factory: function(el, width, height) {

    var firstRun = true;
    var scatter = d3scatter(el).width(width).height(height);

    var sel_handle = new crosstalk.SelectionHandle();

    scatter.on("brush", function(keys) {
      sel_handle.set(keys);
    });

    sel_handle.on("change", function(e) {
      if (e.sender !== sel_handle) {
        scatter.clearBrush();
      }
      scatter.selection(e.value);
    });

    return {
      renderValue: function(x) {
        var value = x.data;
        scatter
          .x_var(value.x_var)
          .y_var(value.y_var)
          .color_var(value.color_var)
          .color_spec(value.color_spec)
          .x_label(value.x_label)
          .y_label(value.y_label)
          .x_lim(value.x_lim)
          .y_lim(value.y_lim)
          .key(x.settings.crosstalk_key);

        sel_handle.setGroup(x.settings.crosstalk_group);

        scatter(!firstRun);
        firstRun = false;
      },
      resize: function(width, height) {
        scatter.width(width).height(height)(false);
      }
    };
  }
});

I'm considering putting the creating into renderValue() because in many cases my widget won't use sharedData, so I don't want to unnecessarily link in the crosstalkLibs. But I won't know this until I see x for the first time in renderValue.

The sample code might end up something like this:

HTMLWidgets.widget({

  name: 'd3scatter',

  type: 'output',

  factory: function(el, width, height) {

    var firstRun = true;
    var scatter = d3scatter(el).width(width).height(height);

    return {
      renderValue: function(x) {
        var value = x.data;
        scatter
          .x_var(value.x_var)
          .y_var(value.y_var)
          .color_var(value.color_var)
          .color_spec(value.color_spec)
          .x_label(value.x_label)
          .y_label(value.y_label)
          .x_lim(value.x_lim)
          .y_lim(value.y_lim)
          .key(x.settings.crosstalk_key);

        if (firstRun && typeof x.settings !== "undefined") {
          scatter.sel_handle = new crosstalk.SelectionHandle();

          scatter.on("brush", function(keys) {
            scatter.sel_handle.set(keys);
          });

          scatter.sel_handle.on("change", function(e) {
            if (e.sender !== sel_handle) {
              scatter.clearBrush();
            }
            scatter.selection(e.value);
          });

          scatter.sel_handle.setGroup(x.settings.crosstalk_group);
        }
        scatter(!firstRun);
        firstRun = false;
      },
      resize: function(width, height) {
        scatter.width(width).height(height)(false);
      }
    };
  }
});

This is untested code so it may contain typos, but will this general approach cause problems?

CJ Yetman
  • 8,373
  • 2
  • 24
  • 56
user2554330
  • 37,248
  • 4
  • 43
  • 90

1 Answers1

0

After a couple of days of experimentation: the answer to my question is that the sample approach works, but is not necessary. There is at least one error in the proposed modification to the code: the test for whether the change message came from the same component should be

if (e.sender !== this) {
  scatter.clearBrush();
}

but in general the approach is fine.

user2554330
  • 37,248
  • 4
  • 43
  • 90