showcases/graph/graph-layer/adaptor/graph-flare.js (67 lines of code) (raw):

import {scalePow} from 'd3-scale'; import {extent} from 'd3-array'; export default class GraphAdaptor { constructor(data) { this._processData(data); } update(data) { this._processData(data); } getTopology() { const {nodes, links} = this; return { nodes, links }; } getNode(id) { return this.nodeMap[id]; } // process hierarchical nested data structure _processData(data) { this.nodes = []; this.links = []; this.nodeMap = {}; this.nodeNameMap = {}; this._processNode(null, data); // scale size for display const scale = scalePow() .domain(extent(this.nodes, n => n.size)) .range([6, 20]) .exponent(0.5); this.nodes.forEach(n => { n.size = scale(n.size); }); // count links per node for force-directed graph layout this.links.forEach(l => { l.sourceCount = this.links.reduce( (count, ll) => (ll.source === l.source || ll.target === l.source ? count + 1 : count), 0 ); l.targetCount = this.links.reduce( (count, ll) => (ll.source === l.target || ll.target === l.target ? count + 1 : count), 0 ); }); } _processNode(parent, node) { const {name, children, size} = node; let newNode = this.nodeNameMap[name]; if (!newNode) { newNode = { id: this.nodes.length, name, size: size || 0 }; this.nodeMap[newNode.id] = newNode; this.nodeNameMap[name] = newNode; this.nodes.push(newNode); newNode.children = children ? children.map(child => this._processNode(newNode, child)) : []; } if (parent) { this.links.push({ id: this.links.length, source: parent.id, target: newNode.id }); } return newNode; } }