DreamContent.jsx
1 chart = { 2 3 // Specify the chart’s dimensions. 4 const width = 928; 5 const height = width; 6 7 // Create the color scale. 8 const color = d3.scaleLinear() 9 .domain([0, 5]) 10 .range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"]) 11 .interpolate(d3.interpolateHcl); 12 13 // Compute the layout. 14 const pack = data => d3.pack() 15 .size([width, height]) 16 .padding(3) 17 (d3.hierarchy(data) 18 .sum(d => d.value) 19 .sort((a, b) => b.value - a.value)); 20 const root = pack(data); 21 22 // Create the SVG container. 23 const svg = d3.create("svg") 24 .attr("viewBox", `-${width / 2} -${height / 2} ${width} ${height}`) 25 .attr("width", width) 26 .attr("height", height) 27 .attr("style", `max-width: 100%; height: auto; display: block; margin: 0 -14px; background: ${color(0)}; cursor: pointer;`); 28 29 // Append the nodes. 30 const node = svg.append("g") 31 .selectAll("circle") 32 .data(root.descendants().slice(1)) 33 .join("circle") 34 .attr("fill", d => d.children ? color(d.depth) : "white") 35 .attr("pointer-events", d => !d.children ? "none" : null) 36 .on("mouseover", function() { d3.select(this).attr("stroke", "#000"); }) 37 .on("mouseout", function() { d3.select(this).attr("stroke", null); }) 38 .on("click", (event, d) => focus !== d && (zoom(event, d), event.stopPropagation())); 39 40 // Append the text labels. 41 const label = svg.append("g") 42 .style("font", "10px sans-serif") 43 .attr("pointer-events", "none") 44 .attr("text-anchor", "middle") 45 .selectAll("text") 46 .data(root.descendants()) 47 .join("text") 48 .style("fill-opacity", d => d.parent === root ? 1 : 0) 49 .style("display", d => d.parent === root ? "inline" : "none") 50 .text(d => d.data.name); 51 52 // Create the zoom behavior and zoom immediately in to the initial focus node. 53 svg.on("click", (event) => zoom(event, root)); 54 let focus = root; 55 let view; 56 zoomTo([focus.x, focus.y, focus.r * 2]); 57 58 function zoomTo(v) { 59 const k = width / v[2]; 60 61 view = v; 62 63 label.attr("transform", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`); 64 node.attr("transform", d => `translate(${(d.x - v[0]) * k},${(d.y - v[1]) * k})`); 65 node.attr("r", d => d.r * k); 66 } 67 68 function zoom(event, d) { 69 const focus0 = focus; 70 71 focus = d; 72 73 const transition = svg.transition() 74 .duration(event.altKey ? 7500 : 750) 75 .tween("zoom", d => { 76 const i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2]); 77 return t => zoomTo(i(t)); 78 }); 79 80 label 81 .filter(function(d) { return d.parent === focus || this.style.display === "inline"; }) 82 .transition(transition) 83 .style("fill-opacity", d => d.parent === focus ? 1 : 0) 84 .on("start", function(d) { if (d.parent === focus) this.style.display = "inline"; }) 85 .on("end", function(d) { if (d.parent !== focus) this.style.display = "none"; }); 86 } 87 88 return svg.node(); 89 }