D3旭日图技术问询:如何实现根节点置于外环(不修改数据顺序)
Absolutely! D3’s flexibility lets you completely customize sunburst chart rendering—so flipping the hierarchy to place your root node on the outer ring is totally achievable, without modifying your original data order. Here’s how to pull it off:
Key Adjustments Needed
By default, D3’s partition layout (used for sunbursts) places the root at the center, with child layers expanding outward. To reverse this, we’ll tweak two core parts: the radius mapping for the partition layout, and how the arc generator calculates inner/outer radii.
1. Reverse the Radius Hierarchy in the Partition Layout
Instead of mapping deeper nodes to larger radii, we’ll map the root node (depth 0) to the largest radius, and each subsequent child layer to a smaller radius. This pushes the root to the outer ring, with children nesting inward.
2. Configure the Arc Generator to Match
The arc generator will use the reversed radius values to draw each segment correctly—outer segments for the root, inner segments for child nodes.
Full Code Example
Let’s walk through a practical implementation:
// Sample data structure (matches your existing JSON/CSV hierarchy order) const sampleData = { name: "Root Node", value: 100, children: [ { name: "Child 1", value: 30, children: [] }, { name: "Child 2", value: 40, children: [] }, // Keep your original child order intact ] }; // Set up dimensions const width = 600; const height = 600; const radiusMax = Math.min(width, height) / 2; // Create SVG container const svg = d3.select("#sunburst") .append("svg") .attr("width", width) .attr("height", height) .append("g") .attr("transform", `translate(${width/2}, ${height/2})`); // Convert data to D3 hierarchy (preserves original child order) const root = d3.hierarchy(sampleData) .sum(d => d.value); // Adjust value calculation to match your needs // Create partition layout with reversed radius logic const totalLayers = root.height + 1; // Total number of layers (root + children) const layerWidth = radiusMax / totalLayers; const partition = d3.partition() .size([2 * Math.PI, radiusMax]) .radius(d => { // Map root (depth 0) to outer radius, each child layer moves inward by layerWidth return radiusMax - (d.depth * layerWidth); }); // Apply layout to get node data const nodes = partition(root).descendants(); // Create arc generator const arc = d3.arc() .startAngle(d => d.x0) .endAngle(d => d.x1) .innerRadius(d => d.y0) // Inner radius = previous layer's outer radius .outerRadius(d => d.y1); // Outer radius = current layer's radius // Draw the sunburst segments svg.selectAll("path") .data(nodes) .enter() .append("path") .attr("d", arc) .style("fill", (d, i) => d3.schemeCategory10[i % 10]) // Customize color logic .style("stroke", "#fff") .style("stroke-width", 2); // Optional: Add interactivity (e.g., tooltips) svg.selectAll("path") .on("mouseover", function(event, d) { // Show tooltip with d.data.name, d.value, etc. });
Critical Notes for Your Use Case
- Preserving Data Order: D3’s
d3.hierarchypreserves the original order of child nodes in your JSON/CSV, so you don’t need to rearrange any data to make this work. - Layer Width Control: Adjust
layerWidthto make rings thicker or thinner—use a fixed pixel value instead of a proportional one if you prefer consistent ring sizes regardless of layer count. - Value Calculation: The
sum(d => d.value)function aggregates values for each segment; replace this withcount()if you want segments sized by node count instead of numeric values.
This approach will replicate your Illustrator-made reverse sunburst, with the added benefit of easy updates via JSON/CSV files—no more manual edits in Illustrator!
内容的提问来源于stack exchange,提问作者jboissy

