ieeeColors = ({
navy: "#2C3E50",
teal: "#16A085",
orange: "#E67E22",
gray: "#7F8C8D",
lightGray: "#ECF0F1",
darkGray: "#34495E",
red: "#E74C3C",
green: "#27AE60",
blue: "#3498DB",
purple: "#9B59B6",
yellow: "#F1C40F",
white: "#FFFFFF"
})
architectureDiagram = {
const width = Math.min(950, window.innerWidth - 40);
const height = 420;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("width", width)
.attr("height", height)
.style("font-family", "system-ui, -apple-system, sans-serif")
.style("background", ieeeColors.white)
.style("border-radius", "12px")
.style("border", `2px solid ${ieeeColors.navy}`);
// Title
svg.append("text")
.attr("x", width / 2)
.attr("y", 28)
.attr("text-anchor", "middle")
.attr("fill", ieeeColors.navy)
.attr("font-size", "16px")
.attr("font-weight", "bold")
.text("Digital Twin Synchronization Architecture");
// Arrow marker
svg.append("defs")
.append("marker")
.attr("id", "archArrowOrange")
.attr("markerWidth", 10)
.attr("markerHeight", 7)
.attr("refX", 9)
.attr("refY", 3.5)
.attr("orient", "auto")
.append("polygon")
.attr("points", "0 0, 10 3.5, 0 7")
.attr("fill", ieeeColors.orange);
svg.select("defs")
.append("marker")
.attr("id", "archArrowGray")
.attr("markerWidth", 10)
.attr("markerHeight", 7)
.attr("refX", 9)
.attr("refY", 3.5)
.attr("orient", "auto")
.append("polygon")
.attr("points", "0 0, 10 3.5, 0 7")
.attr("fill", ieeeColors.gray);
// Layer definitions
const layers = [
{
name: "Physical Layer",
description: "IoT Devices & Sensors",
color: ieeeColors.blue,
y: 55,
height: 70,
components: ["IoT Device", "Sensors", "Actuators", "Local Controller"]
},
{
name: "Edge Layer",
description: "Gateway & Preprocessing",
color: ieeeColors.teal,
y: 145,
height: 70,
components: ["Edge Gateway", "Protocol Bridge", "Local Cache", "Preprocessing"]
},
{
name: "Cloud Layer",
description: "Platform Services",
color: ieeeColors.purple,
y: 235,
height: 70,
components: ["Message Broker", "Stream Engine", "Time-Series DB", "API Gateway"]
},
{
name: "Digital Twin Layer",
description: "Virtual Representation",
color: ieeeColors.navy,
y: 325,
height: 70,
components: ["Twin Engine", "State Store", "Analytics ML", "Simulation"]
}
];
// Draw layers
layers.forEach((layer, i) => {
// Layer background
svg.append("rect")
.attr("x", 25)
.attr("y", layer.y)
.attr("width", width - 50)
.attr("height", layer.height)
.attr("rx", 10)
.attr("fill", layer.color)
.attr("opacity", 0.08)
.attr("stroke", layer.color)
.attr("stroke-width", 2);
// Layer label
svg.append("text")
.attr("x", 40)
.attr("y", layer.y + 20)
.attr("fill", layer.color)
.attr("font-size", "13px")
.attr("font-weight", "bold")
.text(layer.name);
svg.append("text")
.attr("x", 40)
.attr("y", layer.y + 34)
.attr("fill", ieeeColors.gray)
.attr("font-size", "10px")
.text(layer.description);
// Components
const componentWidth = (width - 120) / layer.components.length;
layer.components.forEach((comp, j) => {
const x = 55 + j * componentWidth;
const y = layer.y + 42;
svg.append("rect")
.attr("x", x)
.attr("y", y)
.attr("width", componentWidth - 12)
.attr("height", 22)
.attr("rx", 5)
.attr("fill", layer.color);
svg.append("text")
.attr("x", x + (componentWidth - 12) / 2)
.attr("y", y + 15)
.attr("text-anchor", "middle")
.attr("fill", ieeeColors.white)
.attr("font-size", "10px")
.attr("font-weight", "500")
.text(comp);
});
});
// Draw data flow arrows between layers
for (let i = 0; i < layers.length - 1; i++) {
const fromY = layers[i].y + layers[i].height;
const toY = layers[i + 1].y;
const midX = width / 2;
// Down arrow (data)
svg.append("line")
.attr("x1", midX - 40)
.attr("y1", fromY + 4)
.attr("x2", midX - 40)
.attr("y2", toY - 4)
.attr("stroke", ieeeColors.orange)
.attr("stroke-width", 3)
.attr("marker-end", "url(#archArrowOrange)");
// Up arrow (commands)
svg.append("line")
.attr("x1", midX + 40)
.attr("y1", toY - 4)
.attr("x2", midX + 40)
.attr("y2", fromY + 4)
.attr("stroke", ieeeColors.gray)
.attr("stroke-width", 2)
.attr("stroke-dasharray", "5,3")
.attr("marker-end", "url(#archArrowGray)");
// Labels
svg.append("text")
.attr("x", midX - 55)
.attr("y", (fromY + toY) / 2 + 4)
.attr("text-anchor", "end")
.attr("fill", ieeeColors.orange)
.attr("font-size", "9px")
.attr("font-weight", "bold")
.text("Data");
svg.append("text")
.attr("x", midX + 55)
.attr("y", (fromY + toY) / 2 + 4)
.attr("fill", ieeeColors.gray)
.attr("font-size", "9px")
.text("Commands");
}
// Sync indicator on right side
svg.append("text")
.attr("x", width - 20)
.attr("y", height / 2)
.attr("text-anchor", "middle")
.attr("fill", ieeeColors.teal)
.attr("font-size", "12px")
.attr("font-weight", "bold")
.attr("transform", `rotate(-90, ${width - 20}, ${height / 2})`)
.text("BIDIRECTIONAL SYNC");
return svg.node();
}