javascript – 遍历生成d3 Sankey Chart数据的对象数组
作者:互联网
必须将此输入(树状结构)格式化为特定格式以绘制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