|
|
|
const canvas = document.querySelector("#canvas") |
|
const ctx = canvas.getContext("2d") |
|
|
|
const layerSizes = [30, 16, 16, 10] |
|
const nlayers = layerSizes.length |
|
const maxSize = Math.max(...layerSizes) |
|
|
|
const nodeR = 5 |
|
const scalarR = 3 |
|
const pad = 50 |
|
const colPad = 180 |
|
const rowPad = 16 |
|
const di = 0.2 |
|
const ei = (1-di)/2 |
|
const coord = (col,row) => [ |
|
pad + col * colPad, |
|
pad + (row + maxSize/2 - layerSizes[Math.round(col)]/2) * rowPad |
|
] |
|
|
|
const w = pad*2 + (nlayers-1)*colPad |
|
const h = pad*2 + (maxSize-1)*rowPad |
|
const H = h*2 - pad |
|
canvas.width = w*2 |
|
canvas.height = H*2 |
|
canvas.style.width = w |
|
canvas.style.height = H |
|
ctx.scale(2,2) |
|
|
|
const nodeStroke = "#000" |
|
const nodeFill = "#000" |
|
const scalarFill = "#000" |
|
let synStroke = "rgba(0,0,0,0.2)" |
|
const edgeStroke = "rgba(0,0,0,0.5)" |
|
|
|
const dot = (x,y,r,f) => { |
|
ctx.beginPath() |
|
ctx.arc(x,y,r,0,2*Math.PI) |
|
if (f) ctx.fillStyle = f |
|
ctx.fill() |
|
} |
|
const circ = (x,y,r,s,f) => { |
|
ctx.beginPath() |
|
ctx.arc(x,y,r,0,2*Math.PI) |
|
if (f) { ctx.fillStyle = f; ctx.fill() } |
|
if (s) ctx.strokeStyle = s |
|
ctx.stroke() |
|
} |
|
const line = (x0,y0,x1,y1,s) => { |
|
ctx.beginPath() |
|
ctx.moveTo(x0,y0) |
|
ctx.lineTo(x1,y1) |
|
if (s) ctx.strokeStyle = s |
|
ctx.stroke() |
|
} |
|
|
|
function drawA() { |
|
for (let i=0; i<nlayers; i++) { |
|
for (let j=0; j<layerSizes[i]; j++) { |
|
const [x,y] = coord(i, j) |
|
fanA(x,y,i+1) |
|
dot(x,y,scalarR,scalarFill) |
|
} |
|
} |
|
} |
|
|
|
function fanA(x0,y0,i) { |
|
if (i >= nlayers) return |
|
for (j=0; j<layerSizes[i]; j++) { |
|
const [x,y] = coord(i,j) |
|
line(x0,y0,x,y,synStroke) |
|
} |
|
} |
|
|
|
function drawB() { |
|
for (let i=0; i<nlayers; i++) { |
|
for (let j=0; j<layerSizes[i]; j++) { |
|
const [x,y] = coord(i, j) |
|
dot(x,y,scalarR,scalarFill) |
|
if (i>0) { |
|
const [x0] = coord(i-di, j) |
|
line(x,y,x0,y,edgeStroke) |
|
circ(x0,y,nodeR,nodeStroke,nodeFill) |
|
} |
|
} |
|
fanB(i) |
|
} |
|
} |
|
|
|
function fanB(i) { |
|
if (i>=nlayers-1) return |
|
const [x,y] = coord(i+ei, layerSizes[i]/2) |
|
for (let j=0; j<layerSizes[i]; j++) { |
|
const [x0,y0] = coord(i,j) |
|
line(x,y,x0,y0,synStroke) |
|
} |
|
const i1 = i+1 |
|
for (let j=0; j<layerSizes[i1]; j++) { |
|
const [x0,y0] = coord(i1-di,j) |
|
line(x,y,x0,y0,synStroke) |
|
} |
|
circ(x,y,nodeR,nodeStroke,nodeFill) |
|
} |
|
|
|
|
|
drawA(); |
|
ctx.translate(0,h-pad) |
|
synStroke = "rgba(0,0,0,0.3)" |
|
drawB(); |