将父和嵌套数据与d3.js组合 [英] Combining Parent and Nested Data with d3.js

查看:98
本文介绍了将父和嵌套数据与d3.js组合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的数据结构(假设数据结构不可协商):

I have a data structure like this (assume that the data structure is non-negotiable):

data = {
    segments : [
        {x : 20, size : 10, colors : ['#ff0000','#00ff00']},
        {x : 40, size : 20, colors : ['#0000ff','#000000']}
    ]};

使用 d3.js javascript库,我想绘制四个矩形,每个颜色一个颜色数组。来自数组中每个条目的信息用于绘制与其颜色数组中的每个颜色对应的矩形。例如,红色和绿色矩形的宽度和高度为10.生成的html应该如下所示:

Using the d3.js javascript library, I'd like to draw four rectangles, one for each color in both colors arrays. Information from each entry in the segments array is used to draw the rectangles corresponding to each color in its color array. E.g., The red and green rectangles will have a width and height of 10. The resulting html should look like this:

<div id="container">
    <svg width="200" height="200">
        <g>
            <rect x="20" y="20" width="10" height="10" fill="#ff0000"></rect>
            <rect x="30" y="30" width="10" height="10" fill="#00ff00"></rect>
        </g>
        <g>
            <rect x="40" y="40" width="20" height="20" fill="#0000ff"></rect>
            <rect x="60" y="60" width="20" height="20" fill="#000000"></rect>
        </g>
    </svg>
</div>

我想出了一些代码来实现这一点,但我发现了关于使用数据的部分在数据中的两个不同级别的嵌套是混乱的,我觉得可能有一个更成熟的方法来完成同样的d3.js。以下是代码(完整示例: http://jsbin.com/welcome/39650/edit ) :

I've come up with some code that accomplishes this, but I found the part about using data from two different levels of nesting in data to be confusing, and I feel that there might be a more idiomatic way to accomplish the same with d3.js. Here's the code (full example at http://jsbin.com/welcome/39650/edit):

function pos(d,i) { return d.x + (i * d.size); } // rect position
function size(d,i) { return d.size; }            // rect size
function f(d,i) { return d.color; }              // rect color

// add the top-level svg element and size it
vis = d3
    .select('#container')
    .append('svg')
    .attr('width',200)
    .attr('height',200);

// add the nested svg elements
var nested = vis
    .selectAll('g')
    .data(data.segments)
    .enter()
    .append('g');

// Add a rectangle for each color
nested
    .selectAll('rect')
    .data(function(d) {
        // **** ATTENTION ****
        // Is there a more idiomatic, d3-ish way to approach this?
        var expanded = [];
        for(var i = 0; i < d.colors.length; i++) {
            expanded.push({
                color : d.colors[i],
                x     : d.x
                size  : d.size });
        }
        return expanded;
    })
    .enter()
    .append('rect')
    .attr('x',pos)
    .attr('y',pos)
    .attr('width',size)
    .attr('height',size)
    .attr('fill',f);

是否有更好和/或更习惯的方式来访问来自两个不同级别的数据使用d3.js嵌套数据结构?

感谢 meetamit的回答关闭主意,并使用更常用的d3.js缩进感谢 nautat的回答

Here's the solution I came up with, thanks to meetamit's answer for the closure idea, and using more idiomatic d3.js indentation thanks to nautat's answer:

$(function() {
  var
    vis = null,
    width = 200,
    height = 200,
    data = {
        segments : [
           {x : 20, y : 0, size : 10, colors : ['#ff0000','#00ff00']},
           {x : 40, y : 0, size : 20, colors : ['#0000ff','#000000']}
        ]
    };

    // set the color
    function f(d,i) {return d;}

    // set the position
    function pos(segment) {
      return function(d,i) {
        return segment.x + (i * segment.size);
      };
    }

    // set the size
    function size(segment) {
      return function() {
        return segment.size;
      };
    }

    // add the top-level svg element and size it
    vis = d3.select('#container').append('svg')
        .attr('width',width)
        .attr('height',height);

    // add the nested svg elements
    var nested = vis
        .selectAll('g')
          .data(data.segments)
        .enter().append('g');

    // Add a rectangle for each color.  Size of rectangles is determined
    // by the "parent" data object.
    nested
    .each(function(segment, i) {
      var 
          ps = pos(segment),
          sz = size(segment);

      var colors = d3.select(this)
        .selectAll('rect')
          .data(segment.colors)
        .enter().append('rect')
          .attr('x', ps)
          .attr('y',ps)
          .attr('width', sz)
          .attr('height',sz)
          .attr('fill', f);
  });

});

以下是完整的工作示例: http://jsbin.com/welcome/42885/edit

Here's the full working example: http://jsbin.com/welcome/42885/edit

推荐答案

您可以使用closures

You can use closures

var nested = vis
  .selectAll('g')
  .data(data.segments);


nested.enter()
  .append('g')
  .each(function(segment, i) {
    var colors = d3.select(this)
      .selectAll('rect')
      .data(segment.colors);

    colors.enter()
      .append('rect')
      .attr('x', function(color, j) { return pos(segment, j); })
      // OR: .attr('x', function(color, j) { return segment.x + (j * segment.size); })
      .attr('width', function(color, j) { return size(segment); })
      .attr('fill', String);
  });

这篇关于将父和嵌套数据与d3.js组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆