【D3】cluster layout

一、

和其他D3类一样,layout 可以链式传递,使用简明的申明添加多种自定义设置。

二、API

# d3.layout.cluster()

Creates a new cluster layout with the default settings: the default sort order is null; the default children accessor assumes each input data is an object with a children array; the default separation function uses one node width for siblings, and two node widths for non-siblings; the default size is 1×1.

使用默认配置创建新集群.

默认排序为null,

默认子节点是一个数组对象,

默认子节点之间宽度间隔为节点宽度,没有子节点为两个节点宽度,默认大小为1x1

# cluster(root
# cluster.nodes(root)

Runs the cluster layout, returning the array of nodes associated with the specified rootnode. The cluster layout is part of D3's family of hierarchical layouts. These layouts follow the same basic structure: the input argument to the layout is the root node of the hierarchy, and the output return value is an array representing the computed positions of all nodes. Several attributes are populated on each node:

运行集群布局,返回值为根节点下所有子节点列表,集群布局是D3 分层布局的一部分。这些布局都有共同的基础结构:1)输入参数根节点  2)返回值为所有计算好位置的节点列表。

每个节点有如下属性:

1)parent  - 父节点,值可能为 父节点、null 、 根节点

2)children - 子节点,值可能为 子节点列表、null、叶结点

3)depth - 深度, 值可能为 0 ~ 最底层叶结点层级

4)x - 计算好的x 坐标

5)y - 计算好的y 坐标

尽管 x y 可以有具体值,但可以为任意单位,比如x 为 半径, y 为角度 ,生成一个雷达图 而不是 笛卡尔图

# cluster.links(nodes)

Given the specified array of nodes, such as those returned by nodes, returns an array of objects representing the links from parent to child for each node. Leaf nodes will not have any links. Each link is an object with two attributes:

指定节点列表后,比如cluster.links(nodes) 返回 的是节点列表中所有节点之间的链接。叶结点没有链接。

每个关联有两个属性:

1)source - 开始节点,父节点

2)target - 结束节点,子节点

在获取对象线(diagonal)图是,这个方法非常有用,可以获取需展示的链接描述列表。

svg.selectAll("path")
    .data(cluster.links(nodes))
  .enter().append("path")
    .attr("d", d3.svg.diagonal());

# cluster.children([children])

If children is specified, sets the specified children accessor function. If children is not specified, returns the current children accessor function, which by default assumes that the input data is an object with a children array:

如果指定了孩子节点,设定孩子节点存储函数。如果子节点没制定,返回当前子节点存储函数, 默认存储函数是children为key 的 数组,如下

function children(d) {
  return d.children;
}

一般子节点文件结构如下:

{
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731}
     ]
    }
   ]
  }
 ]
}
View Code

The children accessor is first invoked for root node in the hierarchy. If the accessor returns null, then the node is assumed to be a leaf node at the layout traversal terminates. Otherwise, the accessor should return an array of data elements representing the child nodes.

子节点首先是由root 节点为根节点。如果该节点没有子节点,那么就是叶节点,处于吐得最底端。另外,这个方法会返回子节点数据列表。

# cluster.sort([comparator])

If comparator is specified, sets the sort order of sibling nodes for the layout using the specified comparator function. If comparator is not specified, returns the current group sort order, which defaults to null for no sorting. The comparator function is invoked for pairs of nodes, being passed the input data for each node. The default comparator is null, which disables sorting and uses tree traversal order. For example, to sort sibling nodes in descending order by the associated input data's string name attribute, say:

如果指定比较函数,就会使用用户自定义比较函数布局。如果比较函数没有指定,默认是null 不排序。比较函数是节点两两比较,传递每个节点的数据。默认比较函数为null,关闭比较使用树的递归排序。比如,对子节点对名字字段进行降序排列,代码如下:

function comparator(a, b) {
  return d3.ascending(a.name, b.name);
}

# cluster.separation([separation])

If separation is specified, uses the specified function to compute separation between neighboring nodes. If separation is not specified, returns the current separation function, which defaults to:

如果间隔函数指定,将使用间隔函数分割相邻节点。如果间隔函数不指定,返回当前间隔函数,默认如下:

function separation(a, b) {
  return a.parent == b.parent ? 1 : 2;
}

A variation that is more appropriate for radial layouts reduces the separation gap proportionally to the radius:

对于雷达图,如下变化会更合适,根据节点层级减少节点间隔

function separation(a, b) {
  return (a.parent == b.parent ? 1 : 2) / a.depth;
}

The separation function is passed two neighboring nodes a and b, and must return the desired separation between nodes. The nodes are typically siblings, though the nodes may also be cousins (or even more distant relations) if the layout decides to place such nodes adjacent.

间隔函数传入参数为两个节点,返回值为两个节点之间的间隔。如果图一定决定节点如何相邻,两个节点必须相邻,可能节点是表节点(甚至更远点),

# cluster.size([size])

If size is specified, sets the available layout size to the specified two-element array of numbers representing x and y. If size is not specified, returns the current size, which defaults to 1×1, or null if a nodeSize is in use. Although the layout has a size in x and y, this represents an arbitrary coordinate system. For example, to produce a radial layout where the tree breadth (x) in measured in degrees, and the tree depth (y) is a radius r in pixels, say [360, r].

如果大小指定,设置图大小的参数为x,y。如下:

d3.layout.cluster()
    .size([height, width - 160])

如果大小没制定,将返回当前大小,默认为1x1 , 或 null (如果使用节点大小)。尽管布局有x,y 指定大小,这可以指定任意坐标系。比如,雷达图, x 的坐标为角度, y 为树的深度 单位为像素, 如 [360,r]

# cluster.nodeSize([nodeSize])

If nodeSize is specified, sets a fixed size for each node as a two-element array of numbers representing x and y. If nodeSize is not specified, returns the current node size, which defaults to null, meaning that the layout has an overall fixed size, which can be retrieved using size.

如果指定节点大小,格式为[width,height] 。 如果没指定节点大小,返回当前节点大小,默认为null,表示布局有一个整体确定的大小,可用cluster.size([size])恢复。

# cluster.value([value])

If value is specified, sets the value accessor to the specified function. If value is not specified, returns the current value accessor which defaults to null, meaning that the value attribute is not computed. If specified, the value accessor is invoked for each input data element, and must return a number representing the numeric value of the node. This value has no effect on the cluster layout, but is generic functionality provided by hierarchy layouts.

如果指定值,设置值函数。如果没指定,返回当前值函数,默认为null,表示值没有计算。如果指定,值函数将会对每个节点进行计算,返回一个数值。这个值对接点布局没有任何影响,是通用功能层次结构布局的方法。

例子:

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node circle {
    fill: #fff;
    stroke: steelblue;
    stroke- 1.5px;
}

.node {
    font: 10px sans-serif;
}

.link {
    fill: none;
    stroke: #ccc;
    stroke- 1.5px;
}

</style>
<body>
<div>
    请选择渲染的层级
    <select id="selectDepth">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
    </select>
</div>

<div id="result"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="data.js"></script>
<script>
function renderTree (data) {
    document.getElementById('result').innerHTML = '';

    var width = 960,
        height = 2200;

    var cluster = d3.layout.cluster()
        .size([height, width - 160]);

    var diagonal = d3.svg.diagonal()
        .projection(function(d) { return [d.y, d.x]; });

    var svg = d3.select("#result").append("svg")
        .attr("width", width)
        .attr("height", height)
        .append("g")
        .attr("transform", "translate(40,0)");
  var nodes = cluster.nodes(data),
      links = cluster.links(nodes);

  var link = svg.selectAll(".link")
      .data(links)
      .enter().append("path")
      .attr("class", "link")
      .attr("d", diagonal);

  var node = svg.selectAll(".node")
      .data(nodes)
      .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
      .on('click', function (d) {
          console.log(d);
      })

  node.append("circle")
      .attr("r", 4.5);

  node.append("text")
      .attr("dx", function(d) { return d.children ? -8 : 8; })
      .attr("dy", 3)
      .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
      .text(function(d) { return d.name; });
};


renderTree (getTreeDataByDepth(data, 1));

function getTreeDataByDepth (data, depth) {
    // console.log(data,depth);
    if ((depth === 0) ||
        (data === null) ||
        (data === undefined)) {
        return null;
    }

    var result = {}
    result['name'] = data['name'];
    if (data.children !== undefined) {
        for (var i = 0 ; i < data.children.length ; i++) {
            var child = getTreeDataByDepth(data.children[i], depth - 1);
            if (child !== null) {
                if (result['children'] === undefined) {
                    result['children']  = [];
                }
                result['children'].push(child);
            }
        }
    }
    return result;
}

var select = document.getElementById('selectDepth');
select.addEventListener('change', function (e) {
    var depth = e.target.value;
    console.log();
    renderTree (getTreeDataByDepth(data, depth));
});
</script>
</body>
</html>
View Code
var data = {
 "name": "flare",
 "children": [
  {
   "name": "analytics",
   "children": [
    {
     "name": "cluster",
     "children": [
      {"name": "AgglomerativeCluster", "size": 3938},
      {"name": "CommunityStructure", "size": 3812},
      {"name": "HierarchicalCluster", "size": 6714},
      {"name": "MergeEdge", "size": 743}
     ]
    },
    {
     "name": "graph",
     "children": [
      {"name": "BetweennessCentrality", "size": 3534},
      {"name": "LinkDistance", "size": 5731},
      {"name": "MaxFlowMinCut", "size": 7840},
      {"name": "ShortestPaths", "size": 5914},
      {"name": "SpanningTree", "size": 3416}
     ]
    },
    {
     "name": "optimization",
     "children": [
      {"name": "AspectRatioBanker", "size": 7074}
     ]
    }
   ]
  },
  {
   "name": "animate",
   "children": [
    {
     "name": "interpolate",
     "children": [
      {"name": "ArrayInterpolator", "size": 1983},
      {"name": "ColorInterpolator", "size": 2047},
      {"name": "DateInterpolator", "size": 1375},
      {"name": "Interpolator", "size": 8746},
      {"name": "MatrixInterpolator", "size": 2202},
      {"name": "NumberInterpolator", "size": 1382},
      {"name": "ObjectInterpolator", "size": 1629},
      {"name": "PointInterpolator", "size": 1675},
      {"name": "RectangleInterpolator", "size": 2042}
     ]
    },
    {"name": "ISchedulable", "size": 1041},
    {"name": "Parallel", "size": 5176},
    {"name": "Pause", "size": 449},
    {"name": "Scheduler", "size": 5593},
    {"name": "Sequence", "size": 5534},
    {"name": "Transition", "size": 9201},
    {"name": "Transitioner", "size": 19975},
    {"name": "TransitionEvent", "size": 1116},
    {"name": "Tween", "size": 6006},
    {"name": "Easing", "size": 17010},
    {"name": "FunctionSequence", "size": 5842},
   ]
  },
  {
   "name": "display",
   "children": [
    {"name": "DirtySprite", "size": 8833},
    {"name": "LineSprite", "size": 1732},
    {"name": "RectSprite", "size": 3623},
    {"name": "TextSprite", "size": 10066}
   ]
  },
  {
   "name": "flex",
   "children": [
    {"name": "FlareVis", "size": 4116}
   ]
  }]
}
View Code
计划、执行、每天高效的活着学着
原文地址:https://www.cnblogs.com/huxiaoyun90/p/4545449.html