| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Intro Chart</title> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script> |
| <style> |
| body { |
| margin: 0; |
| padding: 20px; |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Arial, sans-serif; |
| background-color: #fafafa; |
| display: flex; |
| justify-content: center; |
| align-items: center; |
| min-height: 100vh; |
| } |
| #chart { |
| background: white; |
| border-radius: 8px; |
| padding: 40px; |
| box-shadow: 0 2px 8px rgba(0,0,0,0.1); |
| } |
| </style> |
| </head> |
| <body> |
| <div id="chart"></div> |
| |
| <script> |
| const data = [ |
| { |
| title: "Model builders", |
| items: ["best training method", "non-regression", "risks/costs"], |
| color: "#FFA500" |
| }, |
| { |
| title: "Users", |
| items: ["best model for X", "hype vs trust"], |
| color: "#FFD700" |
| }, |
| { |
| title: "Field", |
| items: ["capabilities", "direction"], |
| color: "#FFA500", |
| hasIcon: true |
| } |
| ]; |
| |
| const width = 800; |
| const height = 300; |
| const boxWidth = 200; |
| const boxHeight = 180; |
| const boxSpacing = 50; |
| |
| const svg = d3.select("#chart") |
| .append("svg") |
| .attr("width", width) |
| .attr("height", height); |
| |
| const boxes = svg.selectAll("g.box") |
| .data(data) |
| .enter() |
| .append("g") |
| .attr("class", "box") |
| .attr("transform", (d, i) => `translate(${i * (boxWidth + boxSpacing) + 50}, 50)`); |
| |
| |
| boxes.append("rect") |
| .attr("width", boxWidth) |
| .attr("height", boxHeight) |
| .attr("rx", 20) |
| .attr("ry", 20) |
| .attr("fill", "white") |
| .attr("stroke", d => d.color) |
| .attr("stroke-width", 3); |
| |
| |
| boxes.append("text") |
| .attr("x", boxWidth / 2) |
| .attr("y", 35) |
| .attr("text-anchor", "middle") |
| .attr("font-size", "16px") |
| .attr("font-weight", "600") |
| .text(d => d.title); |
| |
| |
| boxes.each(function(d) { |
| const box = d3.select(this); |
| |
| d.items.forEach((item, i) => { |
| box.append("text") |
| .attr("x", 20) |
| .attr("y", 70 + i * 25) |
| .attr("font-size", "13px") |
| .attr("fill", "#333") |
| .text(`- ${item}`); |
| }); |
| |
| |
| if (d.hasIcon) { |
| box.append("text") |
| .attr("x", boxWidth - 40) |
| .attr("y", boxHeight - 25) |
| .attr("font-size", "32px") |
| .text("🔄"); |
| } |
| }); |
| </script> |
| </body> |
| </html> |