技术咨询:将D3可缩放树形图的JSON数据获取改为硬编码变量
Got it, let's walk through how to swap out the external JSON fetch for a hardcoded data variable in your D3 zoomable treemap. It's actually pretty straightforward once you know which parts to tweak—here's what you need to do:
Step 1: Define Your Hardcoded Data
First, create a JavaScript variable that matches the exact structure of your original JSON file. D3's treemap relies on a hierarchical structure with name, value, and children (for nested categories) fields, so make sure your hardcoded data mirrors that.
Example of a valid hardcoded dataset:
const treeData = { name: "Root Category", children: [ { name: "Electronics", children: [ { name: "Phones", value: 450 }, { name: "Laptops", value: 600 }, { name: "Tablets", value: 300 } ] }, { name: "Clothing", children: [ { name: "Shirts", value: 200 }, { name: "Pants", value: 250 } ] }, { name: "Home Goods", value: 500 } ] };
Step 2: Remove the JSON Fetch Logic
Original code probably uses d3.json() to load external data, which looks like this:
// Old code with JSON fetch d3.json("your-data-file.json").then(function(data) { // Treemap processing and rendering here });
You can delete this entire fetch block—since we're using hardcoded data, we don't need asynchronous loading anymore.
Step 3: Initialize the Treemap with Your Hardcoded Data
Replace the fetch callback logic with direct use of your treeData variable. The core treemap setup (using d3.hierarchy and d3.treemap) stays almost identical—you just pass your hardcoded variable instead of the fetched data parameter.
Here's how that looks:
// Create hierarchy from hardcoded data const root = d3.hierarchy(treeData) .sum(d => d.value) // Calculate size based on 'value' field .sort((a, b) => b.value - a.value); // Sort nodes by size (descending) // Initialize treemap layout const treemap = d3.treemap() .size([width, height]) // Set your SVG dimensions .paddingInner(2) // Space between inner nodes .paddingOuter(3); // Space around the treemap // Generate the treemap layout treemap(root);
Step 4: Keep Rendering Code the Same
All the code for drawing rectangles, adding labels, and handling zoom (if your template includes it) can stay exactly as it was. The root object generated from your hardcoded data will have the same structure as the one from the JSON fetch, so D3 will render it the same way.
Full Working Example
Here's a complete, simplified version of a zoomable treemap with hardcoded data (includes basic zoom functionality):
<!DOCTYPE html> <html> <head> <script src="https://d3js.org/d3.v7.min.js"></script> </head> <body> <svg width="800" height="600"></svg> <script> // Hardcoded hierarchical data const treeData = { name: "Retail Store", children: [ { name: "Electronics", children: [ { name: "Smartphones", value: 500 }, { name: "Laptops", value: 700 }, { name: "Headphones", value: 300 } ] }, { name: "Apparel", children: [ { name: "Men's", value: 400 }, { name: "Women's", value: 450 }, { name: "Kids'", value: 250 } ] }, { name: "Home Decor", value: 600 } ] }; const svg = d3.select("svg"); const width = +svg.attr("width"); const height = +svg.attr("height"); // Create zoom behavior const zoom = d3.zoom() .scaleExtent([1, 4]) .on("zoom", (event) => { g.attr("transform", event.transform); }); svg.call(zoom); const g = svg.append("g"); // Process data const root = d3.hierarchy(treeData) .sum(d => d.value) .sort((a, b) => b.value - a.value); const treemap = d3.treemap() .size([width, height]) .paddingInner(2) .paddingOuter(3); treemap(root); // Draw rectangles const nodes = g.selectAll("rect") .data(root.leaves()) .enter() .append("rect") .attr("x", d => d.x0) .attr("y", d => d.y0) .attr("width", d => d.x1 - d.x0) .attr("height", d => d.y1 - d.y0) .style("fill", (d, i) => d3.schemeCategory10[i % 10]) .style("stroke", "#fff") .on("click", (event, d) => zoomToNode(d, root)); // Add labels g.selectAll("text") .data(root.leaves()) .enter() .append("text") .attr("x", d => d.x0 + 5) .attr("y", d => d.y0 + 20) .text(d => d.data.name) .style("font-size", "12px") .style("fill", "#fff"); // Zoom functionality function zoomToNode(node, root) { const x0 = node.x0; const x1 = node.x1; const y0 = node.y0; const y1 = node.y1; svg.transition().duration(750).call( zoom.transform, d3.zoomIdentity .translate(width / 2, height / 2) .scale(Math.min(width / (x1 - x0), height / (y1 - y0))) .translate(-(x0 + x1) / 2, -(y0 + y1) / 2) ); } </script> </body> </html>
Key Notes
- Match Structure Exactly: Make sure your hardcoded data uses the same field names (
name,value,children) as your original JSON. If your JSON used different keys (likelabelinstead ofname), adjust thed3.hierarchyandsumfunctions accordingly. - No Asynchronous Code: Since we're using synchronous data, you don't need
.then()callbacks or async/await—your code runs in a straight line. - Zoom Compatibility: If your treemap includes zoom, the logic will work the same because the
rootnode structure is identical to the fetched version.
内容的提问来源于stack exchange,提问作者Poul

