zoukankan      html  css  js  c++  java
  • d3 bubble源码分析

    技术

    d3、d3.pack、d3.hierarchy

    展示

    https://bl.ocks.org/xunhanliu/e0688dc2ae9167c4c7fc264c0aedcdd1

    关于怎么使用,代码中有关键注释。

     

    d3.pack

    // https://d3js.org Version 4.8.0. Copyright 2017 Mike Bostock.

    层级数据的结构

     这是一种典型的树形结构,每个节点包含树的深度和高度,还有“父亲指针”,“儿子指针”。

    部分源码

     1 var index$2 = function() {
     2   var radius = null,
     3       dx = 1,
     4       dy = 1,
     5       padding = constantZero;
     6 
     7   function pack(root) {
     8     root.x = dx / 2, root.y = dy / 2;
     9     if (radius) {
    10       root.eachBefore(radiusLeaf(radius)) //前序遍历,对每个节点的半径进行设置。
    11           .eachAfter(packChildren(padding, 0.5)) //后序遍历
    12           .eachBefore(translateChild(1));
    13     } else {
    14       root.eachBefore(radiusLeaf(defaultRadius$1))
    15           .eachAfter(packChildren(constantZero, 1))
    16           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))//确定每个节点的半径
    17           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));//处理每个节点的偏移
    18     }
    19     return root;
    20   }
    21 
    22   pack.radius = function(x) {
    23     return arguments.length ? (radius = optional(x), pack) : radius;
    24   };
    25 
    26   pack.size = function(x) {
    27     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
    28   };
    29 
    30   pack.padding = function(x) {
    31     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
    32   };
    33 
    34   return pack;
    35 };
    36 
    37 function radiusLeaf(radius) {
    38   return function(node) {
    39     if (!node.children) {
    40       node.r = Math.max(0, +radius(node) || 0);
    41     }
    42   };
    43 }
    44 
    45 function packChildren(padding, k) {
    46   return function(node) {
    47     if (children = node.children) {
    48       var children,
    49           i,
    50           n = children.length,
    51           r = padding(node) * k || 0,
    52           e;
    53 
    54       if (r) for (i = 0; i < n; ++i) children[i].r += r;
    55       e = packEnclose(children);
    56       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
    57       node.r = e + r;
    58     }
    59   };
    60 }
    61 
    62 function translateChild(k) {
    63   return function(node) {
    64     var parent = node.parent;
    65     node.r *= k;
    66     if (parent) {
    67       node.x = parent.x + k * node.x;
    68       node.y = parent.y + k * node.y;
    69     }
    70   };
    71 }

    主要逻辑在L10-L12.

    1. root.eachBefore(radiusLeaf(radius))函数 比较简单,前序遍历,对每个节点的半径进行设置。其中radius是回调函数,参数是node.
    2. root.eachAfter(packChildren(padding, 0.5)) //后序遍历,在packEnclose函数中设置每个children相对于此节点的位置,并返回此节点的半径大小。这句话完成了半径的设置和节点相对于父节点的相对位置。
    3. root.eachBefore(translateChild(1)); //由于第二步的位置偏移只是相对于父节点的,这里,递归的把children的偏移加上其父亲节点的偏移。

    注意L15行功能是否多余:

      本来packEnclose生成的布局是圆形相切布局(圆紧挨着圆,可能不太好看),如何在圆之间加一些空隙,这里作者用了一个小技巧:把计算之前的圆增大一点,经过packEnclose布局后,再把圆的半径给恢复。注:原数据中除叶子节点外都没有半径信息的,如果没有L15的代码的话,冒然增加一个padding,是无效果的,最后的结果是相切布局。L15的结果是把所有节点的半径都设置一下(相切布局)。

    其中packChildren中的packEnclose函数是布局的核心代码。此部分代码未使用碰撞的思想(需要迭代,速度就更慢了),直接进行几何的相切布局。

    使用方式:

    返回结果: 外圆的半径。注意原数据a中每个元素多了一些坐标信息。意思就是,给一组点的大小,经过这个函数后,会得出一些布局信息。

  • 相关阅读:
    美团面试准备
    SSM实战项目——Java高并发秒杀API
    接口和抽象类有什么区别
    Java中static、final、static final的区别
    多线程面试题
    idea新建maven项目没有src目录
    聊聊MyBatis缓存机制
    Java 8系列之重新认识HashMap
    数据库SQL实战练习
    牛客网刷题(一)
  • 原文地址:https://www.cnblogs.com/xunhanliu/p/10478562.html
Copyright © 2011-2022 走看看