从 r2d3 迁移到 htmlwidget

问题描述 投票:0回答:1

我正在尝试使用正确的工作流程将我使用 {r2d3} 创建的内容移动到 {htmlwidgets}。例如,以下代码在 r2d3 中运行并创建一个非常简单的 x 轴:

// set up constants used throughout script
const margin = { top: 80, right: 100, bottom: 80, left: 100 };
const plotWidth = 800 - margin.left - margin.right;
const plotHeight = 400 - margin.top - margin.bottom;

// set width and height of svg element (plot + margin)
svg.attr("width", plotWidth + margin.left + margin.right)
   .attr("height", plotHeight + margin.top + margin.bottom);  // Set plot background opacity

// create plot group and move it
let plotGroup = svg.append("g")
                   .attr("transform",
                         "translate(" + margin.left + "," + margin.top + ")");

// x-axis
let xAxis = d3.scaleLinear()
    .domain([0, 1])
    .range([0, plotWidth]);

// add x-axis to plot
plotGroup.append("g")
   .attr("transform", "translate(0," + plotHeight + ")")
   .call(d3.axisBottom(xAxis).tickFormat(d3.format(".0%")));

但是,当我尝试使用 {htmlwidgets} 创建 R 包时,没有绘制任何内容。这是我的 htmlwidget 工厂:

function factory(el, width, height) {

  return {
    setupSvg: () => {
      d3.select(el).selectAll('*').remove();
      svg = d3.select(el).append('svg'); // Assign to the higher-scoped svg variable
      return svg;
    },

    draw: function() {
      // set up constants used throughout script
      const margin = { top: 80, right: 100, bottom: 80, left: 100 };
      const plotWidth = 800 - margin.left - margin.right;
      const plotHeight = 400 - margin.top - margin.bottom;

      // set width and height of svg element (plot + margin)
      svg.attr("width", plotWidth + margin.left + margin.right)
         .attr("height", plotHeight + margin.top + margin.bottom);  // Set plot background opacity

      // create plot group and move it
      let plotGroup = svg.append("g")
                         .attr("transform",
                               "translate(" + margin.left + "," + margin.top + ")");

      // x-axis
      let xAxis = d3.scaleLinear()
          .domain([0, 1])
          .range([0, plotWidth]);

      // add x-axis to plot
      plotGroup.append("g")
         .attr("transform", "translate(0," + plotHeight + ")")
         .call(d3.axisBottom(xAxis).tickFormat(d3.format(".0%")));

    },

    renderValue: function() {
      svg = this.setupSvg();
    },

    resize: function(newWidth, newHeight) {
      console.log('resize w, h', newWidth, newHeight);
      width = newWidth;
      height = newHeight;
      // Update the dimensions of the SVG element
      svg.attr('width', newWidth);
      svg.attr('height', newHeight);
      // Re-render the plot
      this.renderValue();
    }
  };
}

但是什么也没有被策划。当我检查 html 代码时,我可以确认:

最后,这是我调用小部件的 R 代码:

#' Visualize Probabilities
#'
#' A function to visualize probabilities using a lollipop chart
#'
#' @title lollipops
#'
#' @return A HTML widget object.
#' @export
#'
lollipops <-
  function(data,
           width = NULL,
           height = NULL,
           elementId = NULL) {
    # forward options using x
    opts = list(data = dataframeToD3(data.frame(data)))

    # Define sizing policy
    sizingPolicy = htmlwidgets::sizingPolicy(
      defaultWidth = 400,
      defaultHeight = 400,
      browser.fill = TRUE
    )
    # create widget
    htmlwidgets::createWidget(
      name = 'lollipops',
      opts,
      width = width,
      height = height,
      package = 'vizdraws',
      elementId = elementId,
      sizingPolicy = sizingPolicy
    )
  }

我错过了什么?

r d3.js htmlwidgets r2d3
1个回答
0
投票

如果我没看错的话,你真的很接近。这是一个利用 https://github.com/ramnathv/htmlwidgets/issues/305.

的最小示例

我认为您的代码无法正常工作的主要原因是

this.draw()
中缺少
renderValue()
。我做了一些非常小的调整,我认为这会改善成品。如果您遇到任何麻烦,请告诉我,我很乐意提供帮助。

library(htmlwidgets)
library(htmltools)

widget_js <- tags$script(HTML("
HTMLWidgets.widget({

  name: 'lollipops',

  type: 'output',
  
  factory: function(el, width, height) {
  
    return {
      svg: null,
      
      setupSvg: function() {
        d3.select(el).selectAll('*').remove();
        // not necessary but more convenient to access later with this.svg
        this.svg = d3.select(el).append('svg'); // Assign to the higher-scoped svg variable
      },
  
      draw: function() {
        // set up constants used throughout script
        const margin = { top: 80, right: 100, bottom: 80, left: 100 };
        const plotWidth = 800 - margin.left - margin.right;
        const plotHeight = 400 - margin.top - margin.bottom;
        const svg = this.svg;
  
        // set width and height of svg element (plot + margin)
        svg.attr('width', plotWidth + margin.left + margin.right)
           .attr('height', plotHeight + margin.top + margin.bottom);  // Set plot background opacity
  
        // create plot group and move it
        let plotGroup = svg.append('g')
                           .attr('transform',
                                 'translate(' + margin.left + ',' + margin.top + ')');
  
        // x-axis
        let xAxis = d3.scaleLinear()
            .domain([0, 1])
            .range([0, plotWidth]);
  
        // add x-axis to plot
        plotGroup.append('g')
           .attr('transform', 'translate(0,' + plotHeight + ')')
           .call(d3.axisBottom(xAxis).tickFormat(d3.format('.0%')));
  
      },
  
      renderValue: function() {
        this.setupSvg();
        this.draw();
      },
  
      resize: function(newWidth, newHeight) {
        console.log('resize w, h', newWidth, newHeight);
        const width = newWidth;
        const height = newHeight;
        // Update the dimensions of the SVG element
        this.svg.attr('width', newWidth);
        this.svg.attr('height', newHeight);
        // Re-render the plot
        this.renderValue();
      }
    };
  }
})
"))

browsable(tagList(
  d3r::d3_dep_v7(),
  widget_js,
  htmlwidgets::createWidget('lollipops', x = list(), width = "100%")
))

© www.soinside.com 2019 - 2024. All rights reserved.