source: src/main/webapp/plotlog.xhtml@ 15

Last change on this file since 15 was 14, checked in by bart, 4 years ago

Update to version 1.41

File size: 11.1 KB
RevLine 
[1]1<?xml version="1.0" encoding="UTF-8"?>
2<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
3<head>
4<title>Plot log results</title>
5<script src="Chart.min_2.8.0.js"></script>
6</head>
7<style>
8canvas {
9 -moz-user-select: none;
10 -webkit-user-select: none;
11 -ms-user-select: none;
12}
13</style>
14<body>
15 <div class="noscript">
16 <h2 style="color: #ff0000">Seems your browser doesn't support
17 Javascript! Websockets rely on Javascript being enabled. Please
18 enable Javascript and reload this page!</h2>
19 </div>
20 <h1 id="header">Graph of log results</h1>
21
22 Progress:
23 <div id="progress">Waiting for log file name</div>
24 <br />
[4]25 <div style="width: 100%;">
[1]26 <canvas id="canvas"></canvas>
27 </div>
[14]28
29 Agreement: <div id="agreement" style="display:inline;">?</div>
[1]30</body>
31
32<!-- Script to get/update the SESSIONS list and put it into the table. -->
33<script type="application/javascript">
34
35
36
37
38
[9]39
[1]40
41
42
43 <![CDATA[
44 "use strict";
45
46
47
48 var ws = null;
49
50 <!-- Most functions are reactive programming written out-->
51
52 function connect() {
53
54 var id=document.location.search;
55 id = location.search.split('id=')[1]
56 if (id==undefined) return;
57
58 // load the log file with given id
59 document.getElementById('header').innerHTML="Graph of log "+id;
60
61 var url = "log/"+id+".json";
62 setStatus("Downloading file "+url);
63 var request=new XMLHttpRequest();
64 request.responseType = 'text';
65 request.open('Get', url)
66 request.onload=function() {
67 if (request.status!=200) {
68 setStatus("Failed to fetch "+url+":" +request.status+" "+request.statusText)
69 return;
70 }
71 processLogFile(JSON.parse(request.response));
72 }
73 request.send();
74 }
75
76
77 /**
78 Figure out the protocol contents and parse accordingly.
79 */
80 function processLogFile(json) {
[9]81 if (json['SAOPState']!=undefined) {
82 processSAOP(json['SAOPState']);
83 } else if (json['SHAOPState']!=undefined) {
84 processSHAOP(json['SHAOPState']);
85 } else {
[1]86 setStatus("Unknown log file contents "+Object.keys(json));
[9]87 }
[1]88 }
89
90 /**
91 Handle SAOP protocol result.
92 */
93 function processSAOP(json) {
94 var partyprofiles={}
95 var profs=json['partyprofiles'];
96 for (var party in profs) {
[10]97 partyprofiles[party]=profs[party]['profile'].split('?',1)[0]; // hacky, remove complete query.
[1]98 }
99
100 getProfiles(json, partyprofiles);
101 }
102
103 /**
[9]104 Handle SHAOP protocol result. Get only SHAOP profiles. Remove all 'partial=XX' from relevant profiles.
105 */
106 function processSHAOP(json) {
107 var partyprofiles={}
108 var teams=json['settings']['SHAOPSettings']['participants'];
109 for (var partyid in json['partyNumbers']) {
110 var nr= json['partyNumbers'][partyid];
111 if ( (nr & 1 != 0)) continue; // skip COB parties
112 var shaop=teams[nr/2]['shaop'];
113 var profile = shaop['profile'].split('?',1)[0]; // hacky, remove complete query.
114 partyprofiles[partyid]=profile;
115 }
116
117
118 getProfiles(json, partyprofiles);
119 }
120
121
122 /**
[1]123 Get the partyprofiles.
124 @json the json protocol result
125 @partyprofileURIs dict with the websocket addresses for each party'as profile
126 @partyprofiles dict with each party's profile. Initially should be {}
127 */
128 function getProfiles(json, partyprofileURIs, partyprofiles={}) {
129 var keys = Object.keys(partyprofileURIs);
130 if (keys.length==0) {
[14]131 plotResults(computeUtils(json, partyprofiles), isAgreement(json));
[1]132 return;
133 }
134 var party = keys[0];
135 var uri=partyprofileURIs[party];
136 delete partyprofileURIs[party];
137
138 setStatus("fetching profile "+uri);
139 if ('WebSocket' in window) {
140 ws = new WebSocket(uri);
141 } else if ('MozWebSocket' in window) {
142 ws = new MozWebSocket(uri);
143 } else {
144 setStatus('Fatal: WebSocket is not supported by this browser. Please use a newer browser');
145 return;
146 }
147 ws.onmessage = function (event) {
148 var profile = JSON.parse(event.data);
149 if (profile['LinearAdditiveUtilitySpace']==undefined) {
150 setStatus('Fatal: profile '+uri+" does not contain a LinearAdditiveUtilitySpace.");
151 return;
152 }
153 partyprofiles[party]=profile['LinearAdditiveUtilitySpace'];
154 getProfiles(json, partyprofileURIs, partyprofiles);
155 };
156 ws.onerror=function(event) {
157 setStatus('Error fetching profile '+uri+':'+event);
158 }
159 }
160
161 /**
[14]162 @return true if there is agreement
163 */
164 function isAgreement(logfile) {
165 var actions=logfile['actions'];
166 var lastact = actions[actions.length -1];
167 return 'accept' in lastact;
168 }
169 /**
[1]170 @json the log file contents
171 @param partyprofiles a dict with key=party id and value a the (linear additive) profile
172 */
173 function computeUtils(json, partyprofiles) {
174
175 setStatus("Computing utilities.")
176 var utilities={};
177 for (var party in partyprofiles) {
178 utilities[party]=[];
179 }
180 var actions = json['actions'];
181 for (var action in actions) {
182 var offer = actions[action];
183 if (offer['offer']==undefined)
184 continue;
185 var issueutilities = offer['offer']['bid']['issuevalues']
186 for (var party in partyprofiles) {
187 utilities[party].push(utility(partyprofiles[party],issueutilities));
188 }
189 }
190 return utilities;
191
192
193 }
194
195 var chartColors = [
196 'rgb(255, 99, 132)',
197 'rgb(3, 192, 12)',
198 'rgb(54, 162, 235)',
199 'rgb(153, 102, 255)',
200 'rgb(201, 203, 207)',
201 'rgb(255, 159, 64)',
202 'rgb(255, 205, 86)'
203 ];
204
205 function color(i) {
206 return chartColors[i % chartColors.length];
207 }
208
209 /**
210 @param utilities the dict with key=party id of the utilities of all steps for each party )
[14]211 @param isAgreement true iff there is agreement reached
[1]212 */
213
[14]214 function plotResults( utilities, isAgreement) {
[1]215 setStatus("Plotting" )
[14]216
217 document.getElementById('agreement').innerHTML=isAgreement?"Yes":"No";
[1]218
219 var parties=Object.keys(utilities);
220 var thelabels=[];
221 for (var i=1; i<=utilities[parties[0]].length; i++) { thelabels.push(i); }
222
223 var thedatasets=[];
224 var partynr=0;
225 for (var party in utilities) {
226 var dataset={
227 label: party,
228 lineTension:0, // straight lines between the points
229 backgroundColor: color(partynr),
230 borderColor: color(partynr),
231 data: utilities[party],
232 fill: false
233 };
234 thedatasets.push(dataset);
235 partynr++;
236 }
237
238 var config = {
239 type: 'line',
240 data: {
241 labels: thelabels,
242 datasets: thedatasets
243 },
244 options: {
245 responsive: true,
246 title: {
247 display: true,
248 text: 'Per-turn utility plot'
249 },
250 tooltips: {
251 mode: 'index',
252 intersect: false,
253 },
254 hover: {
255 mode: 'nearest',
256 intersect: true
257 },
258 scales: {
259 xAxes: [{
260 display: true,
261 scaleLabel: {
262 display: true,
263 labelString: 'Turn'
264 }
265 }],
266 yAxes: [{
267 display: true,
268 scaleLabel: {
269 display: true,
270 labelString: 'Utility'
271 }
272 }]
273 }
274 }
275 };
276
277 var ctx = document.getElementById('canvas').getContext('2d');
278 window.myLine = new Chart(ctx, config);
279
280 setStatus("Plot ready." )
281
282 }
283
284 /**
285 keys are STRING objects 0,1,2... values are utility values (double)
286 */
287 function makeJxPolyline(pointslist) {
288 var jxpoints = []
289 for (var i in pointslist) {
290 jxpoints.push(new jxPoint(20*Number(i), 100*pointslist[i]));
291 }
292 return jxpoints;
293 }
294
295 /******************* Private support funcs****************/
296
297 /**
298 Set the progress/status text
299 */
300 function setStatus(text) {
301 document.getElementById('progress').innerHTML=text;
302 }
303
304 /*
305 @param sessions a list of IDs (Strings).
306 */
307 function update(sessions) {
308 var table = document.getElementById("sessionsTable");
309 table.innerHTML="";
310 for(var session of sessions) {
311 var row = table.insertRow(-1); //-1 = end
312 row.insertCell(0).innerHTML = session;
313 }
314
315 }
316
317
318
319
320 /**
321 Compute utilityes
322 @param linadditive the linear additive utility space
323 @param issueValues the bid containing dict with values for the issues
324 @return utility of issueValues
325 */
326 function utility(profile, issueValues) {
327 var util=0;
328 var weights = profile['issueWeights'];
329
330 for (var issue in issueValues) {
331 util = util + weights[issue] * evaluate(profile['issueUtilities'][issue], issueValues[issue] );
332 }
333 return util;
334 }
335
336 /**
337 Bit hacky, javascript version of evaluator of utility space.
338 Would be much nicer if we could use java here
339 */
340 function evaluate (utilfunc, value) {
341 if (utilfunc == undefined) {
342 return 0;
343 }
344 if (utilfunc['numberutils']!=undefined) {
345 // it's numeric issue. Compute
346 var minval = utilfunc['numberutils']['lowValue'];
347 var minutil = utilfunc['numberutils']['lowUtility'];
348 var maxval = utilfunc['numberutils']['highValue'];
349 var maxutil = utilfunc['numberutils']['highUtility'];
350
351 var alfa = (value-minval) / (maxval - minval) ;
352 alfa = Math.max(Math.min(alfa, 1),0);
353 return alfa * maxutil + (1-alfa) * minutil;
354 }
355 if (utilfunc['discreteutils']!=undefined) {
356 // it's discrete issue. Compute
357 return utilfunc['discreteutils']['valueUtilities'][value];
358 }
359 setStatus("Unknown utility function type "+Object.keys(utilfunc));
360
361 }
362
363
364 ]]>
365
366
367
368
369
370
[9]371
[1]372</script>
373
374
375
376<script type="application/javascript">
377
378
379
380
381
382
[9]383
[1]384 <![CDATA[
385 "use strict";
386 /*
387 This is called when the window DOM is loaded. window.onload runs BEFORE the window is loaded
388 and therefore is too early to remove the noscript message.
389 */
390 document.addEventListener("DOMContentLoaded", function() {
391 // Remove elements with "noscript" class - <noscript> is not allowed in XHTML
392 var noscripts = document.getElementsByClassName("noscript");
393 for (var i = 0; i < noscripts.length; i++) {
394 noscripts[i].parentNode.removeChild(noscripts[i]);
395 }
396 connect();
397
398 }, false);
399 ]]>
400
401
402
403
404
405
406
[9]407
[1]408</script>
409
410
411</html>
Note: See TracBrowser for help on using the repository browser.