console
const width = 600,height=400;
const r = 10;
const gap = 15;
const size = 20;
const halfSize = Math.floor(size/2);
const hubSize = 3;
const hubs = new Array(hubSize).fill("").map((d,i)=>{
if(hubSize%2 !== 0){
return {
x:width/2,
y:height/2 - (2*r + gap)*(Math.floor(hubSize/2) - i)
}
}else{
return {
x:width/2,
y:height/2 + ((i-(hubSize-i-1))*(r+gap/2))
}
}
})
const isOdd = size%2 === 0;
const leftSpokenY = i=> halfSize === 1 ? height/2 : (height-40)/(halfSize-1)*(i%(halfSize))+20;
const rightSpokeY =i=> halfSize === 0? height/2 :(height-40)/(halfSize)*(i%(halfSize+1))+20
const spokeY = i=> isOdd ? leftSpokenY(i) : rightSpokeY(i);
const spokes = new Array(size).fill("").map((d,i)=>({
x:i<halfSize ? 20:width-20,
y:i<halfSize ? leftSpokenY(i) : spokeY(i),
name:`device${i+1}`
}));
const leftDevice = spokes.slice(0,halfSize);
const rightDevice = spokes.slice(halfSize);
const links = hubs.map(hub=>{
return spokes.map(d=>{
return {
source:{
x:hub.x,
y:hub.y
},
target:{
x:d.x,y:d.y
}
}
})
})
const g = d3.select(svg).attr("width",width).attr("height",height).append("g");
const diagonal = d3.linkHorizontal().x(d => d.x).y(d => d.y);
const link = g.selectAll("path")
.data(links.flat());
link.enter().append("path")
.attr("d", d => {
return diagonal({source: d.source, target: d.target});
})
.attr("fill","none")
.attr("stroke","red");
g.selectAll(".hub").data(hubs).join("circle")
.attr("cx",d=>d.x).attr("cy",d=>d.y).attr("r",10);
g.selectAll(".leftSpoke")
.data(leftDevice).join("circle").attr("cx",d=>d.x)
.attr("cy",d=>d.y).classed("leftSpoke",true).attr("r",10);;
g.selectAll(".rightSpoke")
.data(rightDevice).join("circle").attr("cx",d=>d.x)
.attr("cy",d=>d.y).classed("rightSpoke",true).attr("r",10);
var svgElement = document.getElementsByTagName('svg')[0];
var svgContent = new XMLSerializer().serializeToString(svgElement);
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = new Image();
img.onload = function() {
const scale = Math.min(canvas.width / img.width, canvas.height / img.height);
const w = img.width * scale;
const h = img.height * scale;
const x = (canvas.width - w) / 2;
const y = (canvas.height - h) / 2;
ctx.drawImage(img, x, y, w, h);
};
img.src = 'data:image/svg+xml;base64,' + btoa(svgContent);
<svg id="svg" ></svg>
<canvas id="c" width="100" height="100"></canvas>
svg{
background-color: rgba(0,0,0,0.2);
}
#c{
background-color: #ccc;
width: 100px;
height: 100px;
}