-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisualizer.js
92 lines (78 loc) · 3.12 KB
/
visualizer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
class Visualizer{
static drawNetwork(ctx,network){
const margin = 50;
const left = margin
const top = margin
const width = ctx.canvas.width-margin*2;
const height = ctx.canvas.height - margin*2;
//Visualizer.drawLevel(ctx,network.levels[0],left,top,width,height);
const levelHeight = height/network.levels.length;
for(let i=network.levels.length-1;i>=0;i--){
const levelTop = top+lerp(height-levelHeight,0,network.levels.length==1?0.5:i/(network.levels.length-1))
ctx.setLineDash([7,3])
Visualizer.drawLevel(ctx,network.levels[i],left,levelTop,width,levelHeight,i==network.levels.length-1?['🠉','🠈','🠊','🠋']:[])
}
}
static drawLevel(ctx,level,left,top,width,height,outputLabels){
const right = left + width
const bottom = top + height
const {inputs,outputs,weights,biases} = level;
const nodeRadius = 18;
//weights
for(let i=0;i<inputs.length;i++){
for(let j=0;j<outputs.length;j++){
ctx.beginPath();
ctx.moveTo(Visualizer.#getNodeX(inputs,i,left,right),bottom)
ctx.lineTo(Visualizer.#getNodeX(outputs,j,left,right),top)
ctx.lineWidth=2;
ctx.strokeStyle = getRGBA(weights[i][j]);
ctx.stroke();
}
}
//inputlevel + biases as outercircle
for(let i=0;i<inputs.length;i++){
const x = Visualizer.#getNodeX(inputs,i,left,right)
ctx.beginPath();
ctx.arc(x,bottom,nodeRadius,0,Math.PI*2);
ctx.fillStyle="black";
ctx.fill()
ctx.beginPath();
ctx.arc(x,bottom,nodeRadius*0.6,0,Math.PI*2);
ctx.fillStyle=getRGBA(inputs[i])
ctx.fill()
}
//outputlevel +biases as outercircle
for(let i=0;i<outputs.length;i++){
const x = Visualizer.#getNodeX(outputs,i,left,right)
ctx.beginPath();
ctx.arc(x,top,nodeRadius,0,Math.PI*2);
ctx.fillStyle="black";
ctx.fill()
ctx.beginPath();
ctx.arc(x,top,nodeRadius*0.6,0,Math.PI*2);
ctx.fillStyle=getRGBA(outputs[i])
ctx.fill()
ctx.beginPath();
ctx.lineWidth=2;
ctx.arc(x,top,nodeRadius,0,Math.PI*2);
ctx.strokeStyle=getRGBA(biases[i]);
ctx.setLineDash([6,5])
ctx.stroke();
ctx.setLineDash([])
if(outputLabels[i]){
ctx.beginPath();
ctx.textAlign="center";
ctx.textBaseline="middle";
ctx.fillStyle="black";
ctx.strokeStyle="white";
ctx.font=(nodeRadius*1.5)+"px Arial";
ctx.fillText(outputLabels[i],x,top+nodeRadius*0.1);
ctx.lineWidth=0.5;
ctx.strokeText(outputLabels[i],x,top+nodeRadius*0.1);
}
}
}
static #getNodeX(nodes,index,left,right){
return lerp(left,right,nodes.length==1?0.5:index/(nodes.length-1));
}
}