252 lines
7.1 KiB
HTML
252 lines
7.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>US Critical Minerals Security Flowchart</title>
|
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
|
<style>
|
|
body { background: #f8f8f8; }
|
|
.node rect {
|
|
rx: 8px;
|
|
ry: 8px;
|
|
stroke: #333;
|
|
stroke-width: 1.5px;
|
|
}
|
|
.node text {
|
|
font-family: 'Segoe UI', Arial, sans-serif;
|
|
font-size: 15px;
|
|
fill: #222;
|
|
pointer-events: none;
|
|
}
|
|
.group-title {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
fill: #fff;
|
|
}
|
|
.group-bg {
|
|
fill: #111;
|
|
rx: 8px;
|
|
ry: 8px;
|
|
}
|
|
.group-kpi {
|
|
font-size: 12px;
|
|
fill: #bdbdbd;
|
|
}
|
|
.arrow {
|
|
fill: none;
|
|
stroke: #888;
|
|
stroke-width: 2px;
|
|
marker-end: url(#arrowhead);
|
|
}
|
|
.main-goal {
|
|
fill: #4caf50;
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
}
|
|
.main-goal-bg {
|
|
fill: #d0e8d0;
|
|
rx: 8px;
|
|
ry: 8px;
|
|
stroke: #4caf50;
|
|
stroke-width: 2px;
|
|
}
|
|
.subnode {
|
|
fill: #fff;
|
|
stroke: #bbb;
|
|
stroke-width: 1.2px;
|
|
}
|
|
.highlight {
|
|
fill: #e0e0e0;
|
|
}
|
|
.gray {
|
|
fill: #f5f5f5;
|
|
}
|
|
.light {
|
|
fill: #e8f5e9;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<svg id="flowchart" width="1100" height="700"></svg>
|
|
<script>
|
|
const svg = d3.select("#flowchart");
|
|
const width = +svg.attr("width");
|
|
const height = +svg.attr("height");
|
|
|
|
// 箭头定义
|
|
svg.append("defs").append("marker")
|
|
.attr("id", "arrowhead")
|
|
.attr("viewBox", "0 -5 10 10")
|
|
.attr("refX", 18)
|
|
.attr("refY", 0)
|
|
.attr("markerWidth", 7)
|
|
.attr("markerHeight", 7)
|
|
.attr("orient", "auto")
|
|
.append("path")
|
|
.attr("d", "M0,-5L10,0L0,5")
|
|
.attr("fill", "#888");
|
|
|
|
// 主目标
|
|
svg.append("rect")
|
|
.attr("class", "main-goal-bg")
|
|
.attr("x", 370)
|
|
.attr("y", 30)
|
|
.attr("width", 360)
|
|
.attr("height", 60);
|
|
|
|
svg.append("text")
|
|
.attr("class", "main-goal")
|
|
.attr("x", 550)
|
|
.attr("y", 60)
|
|
.attr("text-anchor", "middle")
|
|
.text("US critical minerals security");
|
|
|
|
svg.append("text")
|
|
.attr("x", 390)
|
|
.attr("y", 50)
|
|
.attr("font-size", 13)
|
|
.attr("fill", "#333")
|
|
.text("OVERALL GOAL:");
|
|
|
|
// 分组数据
|
|
const groups = [
|
|
{
|
|
title: "1",
|
|
subtitle: "Rebuild US critical minerals industry competitiveness",
|
|
kpi: "KPIs: Average time from discovery to construction; no. of workers in CM industry; no. of projects in pipeline",
|
|
x: 60, y: 120, w: 320, h: 80,
|
|
color: "#111",
|
|
nodes: [
|
|
{ id: "1e", text: "Develop critical minerals workforce", x: 80, y: 230, w: 180, h: 40 },
|
|
{ id: "1f", text: "Increase investment in R&D for new tech and AI usage", x: 80, y: 280, w: 220, h: 40 },
|
|
{ id: "1c", text: "Improve permitting and regulations", x: 80, y: 330, w: 180, h: 40 },
|
|
{ id: "1d", text: "Support domestic exploration with funding, data, and AI tools", x: 80, y: 380, w: 240, h: 40 },
|
|
{ id: "1b2d", text: "Support secondary processing expansion", x: 250, y: 230, w: 200, h: 40 },
|
|
{ id: "1a", text: "Increase domestic financing and incentives", x: 250, y: 280, w: 200, h: 40 },
|
|
{ id: "expand", text: "Expand US critical minerals project pipeline", x: 250, y: 330, w: 220, h: 40, highlight: true },
|
|
{ id: "incprod", text: "Increase domestic production", x: 250, y: 380, w: 180, h: 40, highlight: true }
|
|
]
|
|
},
|
|
{
|
|
title: "2",
|
|
subtitle: "Reduce import reliance from non-allied countries",
|
|
kpi: "KPIs: Percentage of US critical minerals imported from or processed by non-allied countries",
|
|
x: 410, y: 120, w: 320, h: 80,
|
|
color: "#222",
|
|
nodes: [
|
|
{ id: "2a", text: "Expand the role and use of existing multilateral arrangements", x: 430, y: 230, w: 250, h: 40 },
|
|
{ id: "2b", text: "Expand US government financing tools", x: 430, y: 280, w: 220, h: 40 },
|
|
{ id: "2c", text: "Support exploration and processing data initiatives", x: 430, y: 330, w: 250, h: 40 },
|
|
{ id: "alliedprod", text: "Increase allied production", x: 700, y: 230, w: 180, h: 40, highlight: true },
|
|
{ id: "alliedpipe", text: "Expand allied critical minerals project pipeline", x: 700, y: 280, w: 220, h: 40, highlight: true }
|
|
]
|
|
},
|
|
{
|
|
title: "3",
|
|
subtitle: "Reduce the risk of critical minerals market disruptions",
|
|
kpi: "KPIs: No. of months of critical mineral reserves; percentage of value chain data collected",
|
|
x: 760, y: 120, w: 320, h: 80,
|
|
color: "#111",
|
|
nodes: [
|
|
{ id: "mon", text: "Monitor critical minerals value chain vulnerabilities", x: 780, y: 230, w: 260, h: 40 },
|
|
{ id: "3a", text: "Develop a real-time value chain mapping and monitoring system", x: 780, y: 280, w: 300, h: 40 },
|
|
{ id: "supply", text: "Reduce supply disruption risks", x: 780, y: 330, w: 200, h: 40 },
|
|
{ id: "3b", text: "Expand purpose and use of National Defense Stockpile", x: 780, y: 380, w: 300, h: 40 },
|
|
{ id: "price", text: "Reduce price disruption risks", x: 780, y: 430, w: 200, h: 40 },
|
|
{ id: "3c", text: "Identify and deploy targeted market incentives", x: 780, y: 480, w: 300, h: 40 }
|
|
]
|
|
}
|
|
];
|
|
|
|
// 画分组背景和标题
|
|
groups.forEach(g => {
|
|
svg.append("rect")
|
|
.attr("class", "group-bg")
|
|
.attr("x", g.x)
|
|
.attr("y", g.y)
|
|
.attr("width", g.w)
|
|
.attr("height", g.h)
|
|
.attr("fill", g.color);
|
|
|
|
svg.append("text")
|
|
.attr("class", "group-title")
|
|
.attr("x", g.x + 18)
|
|
.attr("y", g.y + 28)
|
|
.text(g.title);
|
|
|
|
svg.append("text")
|
|
.attr("x", g.x + 45)
|
|
.attr("y", g.y + 28)
|
|
.attr("font-size", 16)
|
|
.attr("fill", "#fff")
|
|
.text(g.subtitle);
|
|
|
|
svg.append("text")
|
|
.attr("class", "group-kpi")
|
|
.attr("x", g.x + 10)
|
|
.attr("y", g.y + 55)
|
|
.text(g.kpi);
|
|
});
|
|
|
|
// 画节点
|
|
groups.forEach(g => {
|
|
g.nodes.forEach(n => {
|
|
svg.append("rect")
|
|
.attr("class", n.highlight ? "subnode highlight" : "subnode")
|
|
.attr("x", n.x)
|
|
.attr("y", n.y)
|
|
.attr("width", n.w)
|
|
.attr("height", n.h);
|
|
|
|
svg.append("text")
|
|
.attr("x", n.x + n.w / 2)
|
|
.attr("y", n.y + n.h / 2 + 5)
|
|
.attr("text-anchor", "middle")
|
|
.attr("font-size", 14)
|
|
.attr("fill", "#222")
|
|
.text(n.text);
|
|
});
|
|
});
|
|
|
|
// 连线数据(部分示例,实际可根据需要补充)
|
|
const links = [
|
|
// group 1
|
|
{ from: "1f", to: "1e" },
|
|
{ from: "1c", to: "expand" },
|
|
{ from: "1d", to: "expand" },
|
|
{ from: "1b2d", to: "incprod" },
|
|
{ from: "1a", to: "incprod" },
|
|
{ from: "expand", to: "incprod" },
|
|
// group 2
|
|
{ from: "2a", to: "alliedprod" },
|
|
{ from: "2b", to: "alliedpipe" },
|
|
{ from: "2c", to: "alliedpipe" },
|
|
{ from: "alliedpipe", to: "alliedprod" },
|
|
// group 3
|
|
{ from: "mon", to: "3a" },
|
|
{ from: "supply", to: "3b" },
|
|
{ from: "price", to: "3c" }
|
|
];
|
|
|
|
// 节点id到中心点映射
|
|
const nodeCenters = {};
|
|
groups.forEach(g => {
|
|
g.nodes.forEach(n => {
|
|
nodeCenters[n.id] = {
|
|
x: n.x + n.w / 2,
|
|
y: n.y + n.h / 2
|
|
};
|
|
});
|
|
});
|
|
|
|
// 画连线
|
|
links.forEach(l => {
|
|
const from = nodeCenters[l.from];
|
|
const to = nodeCenters[l.to];
|
|
if (from && to) {
|
|
svg.append("path")
|
|
.attr("class", "arrow")
|
|
.attr("d", `M${from.x},${from.y+20} C${from.x},${from.y+40} ${to.x},${to.y-40} ${to.x},${to.y-20}`);
|
|
}
|
|
});
|
|
</script> |