如何使用 React Faux DOM 在 D3 分组条形图中呈现矩形?

Posted

技术标签:

【中文标题】如何使用 React Faux DOM 在 D3 分组条形图中呈现矩形?【英文标题】:How to render rectangles in a D3 grouped bar chart using React Faux DOM? 【发布时间】:2016-12-03 15:17:20 【问题描述】:

我非常接近使用 react-faux-dom 包在 React 中完成一个组条形图。除了实际的矩形之外,一切都设置好了。已经旋转了几个小时,所以我希望有人能看到我缺少的东西。我在is here 工作的示例。我的目标是有一个带有多条组的时间刻度 x 轴。 X 轴和 Y 轴当前渲染没有问题。

数据结构目前如下所示:

[
  key: "oauths", values: [
     date: Tue Jul 26 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 3060,
     date: Tue Jul 27 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 2060,
     date: Tue Jul 28 2016 00:00:00 GMT-1000 (HST), key: "oauths", value: 3270,
  ...],
  key: "user_stats", values: [
     date: Tue Jul 26 2016 00:00:00 GMT-1000 (HST), key: "user_stats", value: 2976,
    ...
  ]
]

React 组件的渲染方法如下。它在最终的svg.append()... 上出错

render() 
    const data = [ ,  ]; // see above

    // Constants
    const margin = top: 30, right: 20, bottom: 30, left: 50,
          width = 600 - margin.left - margin.right,
          height = 400 - margin.top - margin.bottom,
          n = this.props.dataQueryPeriod.length, // number of samples
          m = 2; // number of series

    // Parse the date / time
    const parseDate = d3.time.format("%Y-%m-%d").parse;

    // Set ranges
    const yScale = d3.scale.linear()
      .range([height, 0]);

    const x0 = d3.scale.ordinal()
      .domain(d3.range(n))
      .rangeBands([0, width], .2);

    const x1 = d3.scale.ordinal()
      .domain(d3.range(m))
      .rangeBands([0, x0.rangeBand()]);

    const xScale = d3.time.scale().range([0, width]);

    // Test colors
    var z = d3.scale.category10();

    // Define axes
    const xAxis = d3.svg.axis()
      .scale(xScale)
      .orient("bottom")
      .ticks(d3.time.days);

    const yAxis = d3.svg.axis()
      .scale(yScale)
      .orient("left")
      .tickFormat(d3.format("s"));

    // Convert structured data to nested data
    const nest = d3.nest()
        .key(function(d)  return d.key; )
        .sortKeys(d3.ascending);

    // Create node
    let node = ReactFauxDOM.createElement('svg');

    let svg = d3.select(node)
        .attr("width", width + margin.left + margin.right)
        .attr("height", height + margin.top + margin.bottom+40)
      .append("g")
        .attr("transform", `translate($margin.left,$margin.top)`);

    data.forEach(function(d) 
      d.date = parseDate(d.date);
      d.value = +d.value;
    );

    const nestedData = nest.entries(data);
    console.log("nested data", nestedData);
    console.log("pre nest data", data);

    // Define axes domains
    xScale.domain(d3.extent(data, function(d)  return d.date; ));
    yScale.domain([0, d3.max(data, function(d)  return d.value; )]);

    svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

    svg.append("g")
      .attr("class", "x axis")
      .attr("transform", `translate(0,$height)`)
      .call(xAxis)
      .selectAll("text")
          .style("text-anchor", "end")
          .attr("dx", "-.8em")
          .attr("dy", ".15em")
          .attr("transform", function(d) 
            return "rotate(-65)";
          );

    svg.append("g").selectAll("g")
        .data(nestedData)
      .enter().append("g")
        .style("fill", function(d, i)  return z(i); )
        .attr("transform", function(d, i)  return `translate($x1(i),0)`; )
      .selectAll("rect")
        .data(function(d)  return d.value; )
      .enter().append("rect")
        .attr("width", x1.rangeBand())
        .attr("height", yScale)
        .attr("x", function(d, i)  return x0(i); )
        .attr("y", function(d)  return height - yScale(d.value); );

    return node.toReact();
  

【问题讨论】:

如果追加不是已经选择了吗? svg.append("g").selectAll("g") 对我来说似乎无关紧要。你得到的确切错误是什么?编辑:哦,我明白了,原来的例子就是这样。不过,这个错误会非常有用。 更好的是,如果你可以在 JSFiddle 中运行它,我可以仔细看看 :) 如果我们都确信这是一个错误,请随时提出问题,也许将其添加为测试用例。 @Kwhitejr 我也碰巧认为工作是一种分心。不知道为什么,但 Bossman 先生强烈反对。 你能解释一下究竟是什么不起作用吗? minimal runnable example 会很棒。 【参考方案1】:

如果您的数据与您提供的示例一样开始,则它已经嵌套和 d3.nest()。假设您示例中的数据是nestedData,那么您的问题是您需要绑定values 而不是value。见下文:

svg.append("g").selectAll("g")
    .data(nestedData)
    .enter()
    .append("g")
    .style("fill", function(d, i)  return z(i); )
    .attr("transform", function(d, i)  return `translate($x1(i),0)`; )
    .selectAll("rect")
    .data(function(d)  return d.values; ) // This needs to be values
    .enter().append("rect")
    .attr("width", x1.rangeBand())
    .attr("height", yScale)
    .attr("x", function(d, i)  return x0(i); )
    .attr("y", function(d)  return height - yScale(d.value); );

【讨论】:

以上是关于如何使用 React Faux DOM 在 D3 分组条形图中呈现矩形?的主要内容,如果未能解决你的问题,请参考以下文章

d3.js Faux-3D Arcs - Uncaught typeerror:无法读取未定义的属性“对象”

在 React 应用程序中使用 D3 渲染元素的价格?

如何访问与 D3 SVG 对象相关的 DOM 元素?

Mojo::DOM - 如何从 dom 对象中解析数据集?

如何将 DOM 附加到 Angular 2 组件并仍然获得封装样式

如何解释 D3 附加到 DOM 元素的 __transition__ 属性作为过渡的一部分?