|
|
<!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> |