-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.js
More file actions
217 lines (185 loc) · 6.73 KB
/
main.js
File metadata and controls
217 lines (185 loc) · 6.73 KB
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
// main.js
// Loads and initializes the AI-Agent Capability Radar chart and its interactive controls
import './stretchScale.js'; // Ensure custom radial-stretch scale is registered before Chart.js usage
(async () => {
'use strict';
// ------------------------------
// 1. Efficacy lookup mapping
// map[causalImpact][environment] -> numeric efficacy score (0–5)
const efficacyMap = {
'Observation only': { Simulated: 0, Mediated: 0, Physical: 0 },
'Minor impact': { Simulated: 1, Mediated: 2, Physical: 3 },
'Intermediate impact': { Simulated: 2, Mediated: 3, Physical: 4 },
'Comprehensive impact':{ Simulated: 3, Mediated: 4, Physical: 5 }
};
// ------------------------------
// 2. Core constants and data
const AXES = ['Autonomy', 'Efficacy', 'Goal-complexity', 'Generality'];
// Fetch default agents…
const defaultAgents = await fetch('agents.json').then(r => r.json());
// …then load saved ones and merge
const saved = JSON.parse(localStorage.getItem('customAgents') || '[]');
const agents = [ ...defaultAgents, ...saved ];
// ------------------------------
// 3. DOM references for interactivity
const sel = document.getElementById('agent-select'); // multi-select list of agents
const slider = document.getElementById('stretch-slider'); // range input for axis stretch
const readout = document.getElementById('stretch-readout');// displays stretch %
const form = document.getElementById('custom-form'); // form for adding custom agent
const resetBtn = document.getElementById('reset-btn');
let rafId = null; // holds current requestAnimationFrame ID
// ------------------------------
// 4. Color palette for chart datasets [borderColor, backgroundColor]
const palette = [
['#0072B2', 'rgba(0,114,178,0.25)'], // blue
['#E69F00', 'rgba(230,159,0,0.25)'], // orange
['#009E73', 'rgba(0,158,115,0.25)'] // green
];
// ------------------------------
// 5. Helper functions
const t = () => +slider.value; // current stretch factor
const setLabel = v => readout.textContent = `${Math.round(v * 100)}% stretched`;
const byName = name => agents.find(a => a.name === name); // find agent by name
const refreshSelect = () => {
sel.innerHTML = agents.map(a => `<option>${a.name}</option>`).join('');
};
refreshSelect(); // populate agent list
// Build up to 3 datasets for Chart.js from selected agent names
const makeDatasets = names => names.slice(0, 3).map((name, i) => ({
label: name,
data: AXES.map(axis => byName(name)[axis]),
borderColor: palette[i][0],
backgroundColor: palette[i][1],
borderWidth: 2,
fill: true
}));
// ------------------------------
// 6. Initialize the radar chart
const chart = new Chart(
document.getElementById('radar'),
{
type: 'radar',
data: {
labels: AXES,
datasets: makeDatasets([agents[0].name]) // default to first agent
},
options: {
responsive: true,
animation: false,
layout: { padding: { top: 0, right: 0, bottom: 0, left: 0 } },
scales: {
r: {
type: 'radialStretch', // custom scale
beginAtZero: true,
max: 5,
stretch: 0,
K: 20, // base of exponential curve
pointLabels: { // label styling
display: true,
color: '#333',
padding: 8,
font: {
family: 'system-ui, sans-serif',
size: 14,
weight: 'normal'
}
}
}
},
plugins: {
legend: {
position: 'bottom',
onClick: (e, item, legend) => {
const idx = item.datasetIndex;
legend.chart.toggleDataVisibility(idx);
legend.chart.update();
}
},
tooltip: {
callbacks: {
label: ctx => {
const AX = ['A','E','GC','G'][ctx.dataIndex];
const raw = ctx.dataset.data[ctx.dataIndex];
return `${ctx.dataset.label} – ${AX}: ${raw}`;
}
}
}
}
}
}
);
// Ensure chart re-measures and redraws on window resize
window.addEventListener('resize', () => {
chart.resize();
chart.update('none');
});
// ------------------------------
// 7. Chart update logic
function updateChart() {
const selected = [...sel.selectedOptions].map(o => o.value);
const names = selected.length ? selected : [agents[0].name];
chart.data.datasets = makeDatasets(names);
chart.update('none');
}
// Download chart as PNG
document.getElementById('dl-btn').addEventListener('click', () => {
const link = document.createElement('a');
link.href = chart.toBase64Image();
link.download = 'AI-agent-radar.png';
link.click();
});
// New code
form.addEventListener('submit', e => {
e.preventDefault();
const data = new FormData(form);
const obj = { name: data.get('name') };
AXES.forEach(axis => {
if (axis === 'Efficacy') {
const causal = data.get('CausalImpact');
const env = data.get('Environment');
obj[axis] = efficacyMap[causal][env];
} else {
obj[axis] = Number(data.get(axis));
}
});
// overwrite or append
const existingIdx = agents.findIndex(a => a.name === obj.name);
if (existingIdx !== -1) {
agents[existingIdx] = obj;
} else {
agents.push(obj);
}
// 2) save to localStorage
let customs = JSON.parse(localStorage.getItem('customAgents') || '[]');
customs = customs.filter(a => a.name !== obj.name);
customs.push(obj);
localStorage.setItem('customAgents', JSON.stringify(customs));
// 3) refresh UI
refreshSelect();
[...sel.options].forEach(o => o.selected = o.value === obj.name);
chart.data.datasets = makeDatasets([obj.name]);
chart.update('none');
form.reset();
});
// 8b. Wire up reset button
resetBtn.addEventListener('click', () => {
localStorage.removeItem('customAgents');
// reload to reset agents[] to defaults
window.location.reload();
});
// End new code
// Handle stretch slider input with animation frame throttling
slider.addEventListener('input', () => {
cancelAnimationFrame(rafId);
rafId = requestAnimationFrame(() => {
chart.options.scales.r.stretch = t();
setLabel(t());
chart.update('none');
});
});
// Update chart when agent selection changes
sel.addEventListener('change', updateChart);
// ------------------------------
// Initialize stretch readout display
setLabel(0);
})();