import { hierarchy } from 'd3-hierarchy' function flatten (arr, accumulator = []) { return arr.reduce((acc, child) => { acc.push(child) return child.children ? flatten(child.children, acc) : acc }, accumulator) } function getLinked (text) { const types = ['siblings', 'children', 'parents'] return types.reduce((acc, type) => { // Handle `null` and `undefined` if (text[type]) { text[type].forEach((item, i) => { item.linkType = type }) return [...acc, ...text[type]] } return acc }, []) } export function toSingleManyData (rawData) { rawData.isOrigin = true const h = hierarchy(rawData, d => getLinked(d)) h.each(node => { if (node.parent && node.children) { const id = node.parent.data.id node.children = node.children.filter(child => child.data.id !== id) } }) const nodes = h.descendants() const links = h.links() nodes.forEach(node => { Object.assign(node.data, { type: node.data.type.toLowerCase() }) }) return { nodes, links } } export function toManyManyData (rawData) { rawData.isOrigin = true const h = hierarchy(rawData, d => getLinked(d)) h.each(node => { if (node.parent && node.children) { const id = node.parent.data.id // Remove reference of parent in child's children. node.children = node.children.filter(child => child.data.id !== id) } }) const links = [] const nodes = flatten(h.descendants()).reduce((nodes, node) => { const sameNode = nodes.find(n => node.data.id === n.data.id) if (sameNode) { if (!node.children) return nodes node.children.forEach(child => { if (!sameNode.children.find(c => child.data.id === c.data.id)) { sameNode.children.push(child) } }) } else { if (!node.children) node.children = [] nodes.push(node) } return nodes }, []).map(({ data, children, depth }) => { if (children) { children.forEach(child => { links.push({ source: data.id, target: child.data.id, linkType: child.data.linkType }) }) } return { id: data.id, data: { ...data, type: data.type.toLowerCase() } } }) return { nodes, links } }