ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

javascript – 遍历生成d3 Sankey Chart数据的对象数组

2019-05-22 15:22:41  阅读:240  来源: 互联网

标签:javascript arrays tree d3-js tree-traversal


必须将此输入(树状结构)格式化为特定格式以绘制d3 sankey图表.

let unformattedJson = [
  {
    "key": "a1",
    "value": 30,
    "buckets": [
      {
        "key": "a2",
        "value": 10 
      },
      {
        "key": "b2",
        "value": 20 
      }
    ]
  },
  {
    "key": "b1",
    "value": 70,
    "buckets": [
      {
        "key": "b2",
        "value": 40 
      },
      {
        "key": "c2",
        "value": 30 
      }
    ]
  }
]

我需要生成的预期输出是:

{
  "nodes": [
    {"nodeId":0,"name":"a1"},
    {"nodeId":1,"name":"a2"},
    {"nodeId":2,"name":"b2"},
    {"nodeId":3,"name":"b1"},
    {"nodeId":4,"name":"c2"}
  ],
  "links": [
    {"source":0,"target":1,"value":10},
    {"source":0,"target":2,"value":20},
    {"source":3,"target":2,"value":40},
    {"source":3,"target":4,"value":30}
  ]
}

我的解决方案.我做了两个函数来计算节点和链接.对于节点,我做了一个递归函数来获取所有唯一键并为每个键分配一个id.我创建了另一个函数来获取键之间的所有关系.

let makeNodeObj = function(orObj, index){
    let obj = {};
    obj.nodeId = index;
    obj.name = orObj;
    return obj;
}

var getUniqueKeys = (old, arr)=>{
  let toRet = old;
  arr.forEach((data,index)=>{
    if(toRet.indexOf(data.key)<0){ //remove duplicates
      toRet.push(data.key);
    }
    if(data.buckets !== undefined && data.buckets.length>0){
        getUniqueKeys(toRet, data.buckets);
    }
  });
  return toRet;
}

let uniqueKeys = getUniqueKeys([],unformattedJson);

let nodes = uniqueKeys.map((data,index)=>{
  return makeNodeObj(data,index);
});

let getNodeId = function(nodes, key){
  let node = nodes.find((data)=>{
    return data.name == key
  });
  return node.nodeId;
}

let links = [];
unformattedJson.map((data)=>{
  let sourceId = getNodeId(nodes, data.key);
  if(data.buckets.length>0){
    data.buckets.map((data2)=>{
      let targetId = getNodeId(nodes,data2.key);
      let linkObj = {};
      linkObj.source = sourceId;
      linkObj.target = targetId;
      linkObj.value = data2.value;
      links.push(linkObj);
    })
  }
});

console.log({
  nodes, links
});

我的解决方案只有在只有一个级别深的存储桶时才能工作.如何在子内部实现多个嵌套桶?

解决方法:

我做了一个递归方法来生成预期的输出.密钥与其生成的id之间的关联保持为Map.该方法使用了使用Deep First Search算法遍历树的思想.

let unformattedJson = [
  {
    "key": "a1",
    "value": 30,
    "buckets": [
      {
        "key": "a2",
        "value": 10,
        "buckets": [
          {"key": "a3", "value": 99}
        ]
      },
      {"key": "b2", "value": 20}
    ]
  },
  {
    "key": "b1",
    "value": 70,
    "buckets": [
      {"key": "b2", "value": 40},
      {"key": "c2", "value": 30}
    ]
  }
];

const getData = (input, visited=new Map(), parent, nodes=[], links=[]) =>
{
    input.forEach(x =>
    {
        // Add node into the node list, if not visited previosuly.

        if (!visited.has(x.key))
        {
            let currId = nodes.length;
            nodes.push({nodeId: currId, name: x.key});
            visited.set(x.key, currId);
        }

        // If a parent node exists, add relation into the links list.

        if (parent)
        {
            // Note, we use the "Map" to get the ids.

            links.push({
                source: visited.get(parent.key),
                target: visited.get(x.key),
                value: x.value
            });
        }

        // Traverse (if required) to the next level of deep.

        if (x.buckets)
            getData(x.buckets, visited, x, nodes, links)
    });

    return {nodes: nodes, links: links};
}

console.log(getData(unformattedJson));

标签:javascript,arrays,tree,d3-js,tree-traversal
来源: https://codeday.me/bug/20190522/1152410.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有