D3吸引父母的孩子们走路

时间:2017-05-17 23:41:47

标签: d3.js svg

var data = [{
parent: {path: "M80 0 L500 0 L500 40 L80 40 Z", color: "red"},
children: {
   a: {path: "M80 0 L220 0 L220 40 L80 40 Z"},
   b: {path: "M220 0 L360 0 L360 40 L220 40 Z"},
   c: {path: "M360 0 L500 0 L500 40 L360 40 Z"}
    }
},
{
parent: {path: "M80 40 L500 40 L500 80 L80 80 Z", color: "green"},
children: {
  a: {path: "M80 40 L220 40 L220 80 L80 80 Z"},
  b: {path: "M220 40 L360 40 L360 80 L220 80 Z"},
  c: {path: "M360 40 L500 40 L500 80 L360 80 Z"}
  }
},
]

var parents = d3.select("svg")
     .selectAll("g")
     .data(data)
     .enter().append("g");

parents.append("path")
  .attr("d", function (d) { return d.parent.path; })
  .style("fill", function(d) {return d.parent.color} );

在父路径下绘制子路径的最佳方法是什么?我想知道是否有任何d3惯用的方法来做到这一点。

<svg>
   <g><path d="M80 0 L500 0 L500 40 L80 40 Z" style="fill: red;"></path>
        <g>
             child a
             child b
             child c
        </g>
   </g>
   <g><path d="M80 40 L500 40 L500 80 L80 80 Z" style="fill: green;"></path>
        <g>
             child a
             child b
             child c
        </g>
   </g>
</svg>

我创建了一个jsfiddle示例以获得帮助。 https://jsfiddle.net/kvslee/vkmpyjub/

1 个答案:

答案 0 :(得分:0)

你要问的是复杂的,因为在D3中,data函数接受三件事:一个数组,一个函数或什么都没有。更简单的解决方案是更改数据结构......但是,我将提出一个完全使用您的数据结构的解决方案。

为了实现这一点,在孩子们的路径中,我不得不使用这种丑陋的数据连接在数组中转换该对象:

var children = childrenGroup.selectAll("foo")
    .data(function(d) {
        var childrenData = [];
        for (var key in d.children) {
            childrenData.push({
                path: d.children[key].path
            })
        };
        return childrenData
    })
    .enter()
    .append("path");

以下是整个代码,检查控制台是否有SVG:

&#13;
&#13;
var data = [{
    parent: {
      path: "M80 0 L500 0 L500 40 L80 40 Z",
      color: "red"
    },
    children: {
      a: {
        path: "M80 0 L220 0 L220 40 L80 40 Z"
      },
      b: {
        path: "M220 0 L360 0 L360 40 L220 40 Z"
      },
      c: {
        path: "M360 0 L500 0 L500 40 L360 40 Z"
      }
    }
  },

  {
    parent: {
      path: "M80 40 L500 40 L500 80 L80 80 Z",
      color: "green"
    },
    children: {
      a: {
        path: "M80 40 L220 40 L220 80 L80 80 Z"
      },
      b: {
        path: "M220 40 L360 40 L360 80 L220 80 Z"
      },
      c: {
        path: "M360 40 L500 40 L500 80 L360 80 Z"
      }
    }
  },
];

var svg = d3.select("svg");

var parents = svg.selectAll("foo")
  .data(data)
  .enter()
  .append("g")
  .style("fill", function(d) {
    return d.parent.color
  });

parents.append("path")
  .attr("d", function(d) {
    return d.parent.path;
  });

var childrenGroup = parents.selectAll("foo")
  .data(function(d) {
    return [d]
  })
  .enter()
  .append("g");

var children = childrenGroup.selectAll("foo")
  .data(function(d) {
    var childrenData = [];
    for (var key in d.children) {
      childrenData.push({
        path: d.children[key].path
      })
    };
    return childrenData
  })
  .enter()
  .append("path");

children.attr("d", function(d) {
  return d.path;
})

var mySVG = (new XMLSerializer()).serializeToString(svg.node());
console.log(mySVG)
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg></svg>
&#13;
&#13;
&#13;

这是console.log具有适当缩进的结果:

<svg xmlns="http://www.w3.org/2000/svg">
    <g style="fill: red;">
        <path d="M80 0 L500 0 L500 40 L80 40 Z" />
        <g>
            <path d="M80 0 L220 0 L220 40 L80 40 Z" />
            <path d="M220 0 L360 0 L360 40 L220 40 Z" />
            <path d="M360 0 L500 0 L500 40 L360 40 Z" />
        </g>
    </g>
    <g style="fill: green;">
        <path d="M80 40 L500 40 L500 80 L80 80 Z" />
        <g>
            <path d="M80 40 L220 40 L220 80 L80 80 Z" />
            <path d="M220 40 L360 40 L360 80 L220 80 Z" />
            <path d="M360 40 L500 40 L500 80 L360 80 Z" />
        </g>
    </g>
</svg>

PS:我将样式移到了父组。