annotate analysis/analysis.js @ 1287:d219aa5329aa

Analysis interface controls all interface objects.
author Nicholas Jillings <n.g.r.jillings@se14.qmul.ac.uk>
date Thu, 31 Mar 2016 15:47:47 +0100
parents ae57d9f618cb
children 760719986df3
rev   line source
n@1223 1 /*
n@1223 2 * Analysis script for WAET
n@1223 3 */
n@1223 4
n@1284 5 // Firefox does not have an XMLDocument.prototype.getElementsByName
n@1284 6 // and there is no searchAll style command, this custom function will
n@1284 7 // search all children recusrively for the name. Used for XSD where all
n@1284 8 // element nodes must have a name and therefore can pull the schema node
n@1284 9 XMLDocument.prototype.getAllElementsByName = function(name)
n@1284 10 {
n@1284 11 name = String(name);
n@1284 12 var selected = this.documentElement.getAllElementsByName(name);
n@1284 13 return selected;
n@1284 14 }
n@1284 15
n@1284 16 Element.prototype.getAllElementsByName = function(name)
n@1284 17 {
n@1284 18 name = String(name);
n@1284 19 var selected = [];
n@1284 20 var node = this.firstElementChild;
n@1284 21 while(node != null)
n@1284 22 {
n@1284 23 if (node.getAttribute('name') == name)
n@1284 24 {
n@1284 25 selected.push(node);
n@1284 26 }
n@1284 27 if (node.childElementCount > 0)
n@1284 28 {
n@1284 29 selected = selected.concat(node.getAllElementsByName(name));
n@1284 30 }
n@1284 31 node = node.nextElementSibling;
n@1284 32 }
n@1284 33 return selected;
n@1284 34 }
n@1284 35
n@1284 36 XMLDocument.prototype.getAllElementsByTagName = function(name)
n@1284 37 {
n@1284 38 name = String(name);
n@1284 39 var selected = this.documentElement.getAllElementsByTagName(name);
n@1284 40 return selected;
n@1284 41 }
n@1284 42
n@1284 43 Element.prototype.getAllElementsByTagName = function(name)
n@1284 44 {
n@1284 45 name = String(name);
n@1284 46 var selected = [];
n@1284 47 var node = this.firstElementChild;
n@1284 48 while(node != null)
n@1284 49 {
n@1284 50 if (node.nodeName == name)
n@1284 51 {
n@1284 52 selected.push(node);
n@1284 53 }
n@1284 54 if (node.childElementCount > 0)
n@1284 55 {
n@1284 56 selected = selected.concat(node.getAllElementsByTagName(name));
n@1284 57 }
n@1284 58 node = node.nextElementSibling;
n@1284 59 }
n@1284 60 return selected;
n@1284 61 }
n@1284 62
n@1284 63 // Firefox does not have an XMLDocument.prototype.getElementsByName
n@1284 64 if (typeof XMLDocument.prototype.getElementsByName != "function") {
n@1284 65 XMLDocument.prototype.getElementsByName = function(name)
n@1284 66 {
n@1284 67 name = String(name);
n@1284 68 var node = this.documentElement.firstElementChild;
n@1284 69 var selected = [];
n@1284 70 while(node != null)
n@1284 71 {
n@1284 72 if (node.getAttribute('name') == name)
n@1284 73 {
n@1284 74 selected.push(node);
n@1284 75 }
n@1284 76 node = node.nextElementSibling;
n@1284 77 }
n@1284 78 return selected;
n@1284 79 }
n@1284 80 }
n@1284 81
n@1284 82 var chartContext, testData;
n@1223 83 window.onload = function() {
n@1223 84 // Load the Visualization API and the corechart package.
n@1284 85 google.charts.load('current', {'packages':['corechart']});
n@1223 86 chartContext = new Chart();
n@1284 87 testData = new Data();
n@1284 88 }
n@1284 89
n@1284 90 function get(url) {
n@1284 91 // Return a new promise.
n@1284 92 return new Promise(function(resolve, reject) {
n@1284 93 // Do the usual XHR stuff
n@1284 94 var req = new XMLHttpRequest();
n@1284 95 req.open('GET', url);
n@1284 96 req.onload = function() {
n@1284 97 // This is called even on 404 etc
n@1284 98 // so check the status
n@1284 99 if (req.status == 200) {
n@1284 100 // Resolve the promise with the response text
n@1284 101 resolve(req.response);
n@1284 102 }
n@1284 103 else {
n@1284 104 // Otherwise reject with the status text
n@1284 105 // which will hopefully be a meaningful error
n@1284 106 reject(Error(req.statusText));
n@1284 107 }
n@1284 108 };
n@1284 109
n@1284 110 // Handle network errors
n@1284 111 req.onerror = function() {
n@1284 112 reject(Error("Network Error"));
n@1284 113 };
n@1284 114
n@1284 115 // Make the request
n@1284 116 req.send();
n@1284 117 });
n@1223 118 }
n@1223 119
n@1227 120 function arrayMean(values) {
n@1227 121 var mean = 0;
n@1227 122 for (var value of values) {
n@1227 123 mean += value;
n@1227 124 }
n@1227 125 mean /= values.length;
n@1227 126 return mean;
n@1227 127 }
n@1227 128
n@1275 129 function percentile(values, p) {
n@1275 130 //http://web.stanford.edu/class/archive/anthsci/anthsci192/anthsci192.1064/handouts/calculating%20percentiles.pdf
n@1227 131 values.sort( function(a,b) {return a - b;} );
n@1227 132 // get ordinal rank
n@1275 133 var index = values.length*p/100;
n@1275 134 var k = Math.floor(index);
n@1275 135 if (k == index) {
n@1275 136 return values[k];
n@1275 137 } else {
n@1275 138 var f = index-k;
n@1275 139 var x_int = (1-f)*values[k]+f*values[k+1];
n@1275 140 return x_int;
n@1275 141 }
n@1227 142 }
n@1227 143
n@1227 144 function arrayMin(array) {
n@1227 145 // Return the minimum value of an array
n@1227 146 var min = array[0];
n@1227 147 for (var value of array) {
n@1227 148 if (value < min) {
n@1227 149 min = value;
n@1227 150 }
n@1227 151 }
n@1227 152 return min;
n@1227 153 }
n@1227 154
n@1227 155 function arrayMax(array) {
n@1227 156 // Return the minimum value of an array
n@1227 157 var max = array[0];
n@1227 158 for (var value of array) {
n@1227 159 if (value > max) {
n@1227 160 max = value;
n@1227 161 }
n@1227 162 }
n@1227 163 return max;
n@1227 164 }
n@1227 165
n@1273 166 function boxplotRow(array) {
n@1273 167 // Take an array of element values and return array of computed intervals
n@1273 168 var result = {
n@1287 169 median : percentile(array,50),
n@1273 170 pct25 : percentile(array,25),
n@1273 171 pct75 : percentile(array,75),
n@1273 172 IQR : null,
n@1273 173 min: null,
n@1273 174 max: null,
n@1273 175 outliers: new Array()
n@1273 176 }
n@1273 177 result.IQR = result.pct75-result.pct25;
n@1273 178 var rest = [];
n@1273 179 var pct75_IQR = result.pct75+1.5*result.IQR;
n@1273 180 var pct25_IQR = result.pct25-1.5*result.IQR;
n@1273 181 for (var i=0; i<array.length; i++) {
n@1273 182 //outliers, ranger above pct75+1.5*IQR or below pct25-1.5*IQR
n@1273 183 var point = array[i];
n@1273 184 if (point > pct75_IQR || point < pct25_IQR) {
n@1273 185 result.outliers.push(point);
n@1273 186 } else {
n@1273 187 rest.push(point);
n@1273 188 }
n@1273 189 }
n@1273 190 result.max = arrayMax(rest);
n@1273 191 result.min = arrayMin(rest);
n@1273 192 return result;
n@1273 193
n@1273 194 }
n@1273 195
n@1227 196 function arrayHistogram(values,steps,min,max) {
n@1227 197 if (steps == undefined) {
n@1227 198 steps = 0.25;
n@1227 199 console.log("Warning: arrayHistogram called without steps size set, default to 0.25");
n@1227 200 }
n@1227 201 if (min == undefined) {min = arrayMin(values);}
n@1227 202 if (max == undefined) {max = arrayMax(values);}
n@1227 203 var histogram = [];
n@1227 204 var index = min;
n@1227 205 while(index < max) {
n@1227 206 histogram.push({
n@1227 207 marker: index,
n@1227 208 lt: index,
n@1227 209 rt: index+steps,
n@1227 210 count: 0
n@1227 211 });
n@1227 212 index += steps;
n@1227 213 }
n@1227 214 for (var value of values) {
n@1227 215 for (var entry of histogram) {
n@1227 216 if (value >= entry.lt && value <= entry.rt) {
n@1227 217 entry.count++;
n@1227 218 break;
n@1227 219 }
n@1227 220 }
n@1227 221 }
n@1227 222 return histogram;
n@1227 223 }
n@1227 224
n@1223 225 function Chart() {
n@1284 226 this.valueData;
n@1227 227 this.charts = [];
n@1223 228
n@1227 229 this.chartObject = function(name) {
n@1227 230 // Create the charting object
n@1227 231 this.name = name;
n@1227 232 this.root = document.createElement("div");
n@1227 233 this.root.className = "chart-holder";
n@1227 234 this.root.setAttribute("name",name);
n@1227 235 this.chartDOM = document.createElement("div");
n@1227 236 this.tableDOM = document.createElement("div");
n@1227 237 this.latexDOM = document.createElement("div");
n@1227 238 this.downloadDOM = document.createElement("div");
n@1227 239 this.chart = undefined;
n@1227 240 this.data = new google.visualization.DataTable();
n@1227 241 this.options = {};
n@1227 242 this.print = document.createElement("button");
n@1228 243 this.sortDataButton = document.createElement("button");
n@1228 244 this.sortDataButton.textContent = "Sort by Data";
n@1228 245 this.sortDataButton.addEventListener("click",this);
n@1228 246 this.sortDataButton.setAttribute("name","sort-data");
n@1228 247 this.sortNameButton = document.createElement("button");
n@1228 248 this.sortNameButton.textContent = "Sort by Name";
n@1228 249 this.sortNameButton.addEventListener("click",this);
n@1228 250 this.sortNameButton.setAttribute("name","sort-name");
n@1228 251 this.draw = function() {
n@1228 252 if (this.chart == undefined) {return;}
n@1228 253 this.tableDOM.innerHTML = null;
n@1228 254 this.latexDOM.innerHTML = null;
n@1228 255 this.buildTable();
n@1228 256 this.writeLatex();
n@1228 257 this.chart.draw(this.data,this.options);
n@1228 258 }
n@1228 259 this.sortData = function() {
n@1265 260 this.data.sort(1);
n@1228 261 }
n@1228 262 this.sortName = function() {
n@1265 263 this.data.sort(0);
n@1228 264 }
n@1227 265 this.handleEvent = function() {
n@1227 266 // Only used to handle the chart.event.addListener(this,'ready') callback
n@1228 267 switch(event.currentTarget.getAttribute("name"))
n@1228 268 {
n@1228 269 case "download":
n@1228 270 window.open(this.chart.getImageURI());
n@1228 271 break;
n@1228 272 case "sort-data":
n@1228 273 this.sortData();
n@1228 274 this.draw();
n@1228 275 break;
n@1228 276 case "sort-name":
n@1228 277 this.sortName();
n@1228 278 this.draw();
n@1228 279 break;
n@1228 280 }
n@1227 281 }
n@1227 282
n@1227 283 this.root.appendChild(this.chartDOM);
n@1227 284 this.root.appendChild(this.tableDOM);
n@1227 285 this.root.appendChild(this.latexDOM);
n@1228 286 this.root.appendChild(this.sortDataButton);
n@1228 287 this.root.appendChild(this.sortNameButton);
n@1227 288 this.root.appendChild(this.print);
n@1227 289 this.print.textContent = "Download";
n@1228 290 this.print.setAttribute("name","download");
n@1227 291 this.print.addEventListener("click",this);
n@1227 292 this.root.appendChild(this.downloadDOM);
n@1227 293 this.buildTable = function() {
n@1227 294 var table = document.createElement("table");
n@1227 295 table.border = "1";
n@1264 296 var numRows = this.data.getNumberOfRows();
n@1264 297 var numColumns = this.data.getNumberOfColumns();
n@1264 298 for (var columnIndex=0; columnIndex<numColumns; columnIndex++)
n@1264 299 {
n@1273 300 var tableTitle = this.data.getColumnLabel(columnIndex);
n@1273 301 if (tableTitle != "") {
n@1273 302 var table_row = document.createElement('tr');
n@1273 303 table.appendChild(table_row);
n@1273 304 var row_title = document.createElement('td');
n@1273 305 table_row.appendChild(row_title);
n@1273 306 row_title.textContent = tableTitle;
n@1273 307 for (var rowIndex=0; rowIndex<numRows; rowIndex++)
n@1264 308 {
n@1273 309 var row_entry = document.createElement('td');
n@1273 310 table_row.appendChild(row_entry);
n@1273 311 var entry = this.data.getValue(rowIndex,columnIndex);
n@1273 312 if (isFinite(Number(entry)))
n@1273 313 {
n@1273 314 entry = String(Number(entry).toFixed(4));
n@1273 315 }
n@1273 316 row_entry.textContent = entry;
n@1264 317 }
n@1227 318 }
n@1227 319 }
n@1227 320 this.tableDOM.appendChild(table);
n@1227 321 };
n@1227 322 this.writeLatex = function() {
n@1264 323 var numRows = this.data.getNumberOfRows();
n@1264 324 var numColumns = this.data.getNumberOfColumns();
n@1227 325 var root = document.createElement("div");
n@1227 326 root.className = "code";
n@1227 327 var holder = document.createElement("pre");
n@1227 328 // Table start
n@1227 329 var start = document.createElement("p");
n@1227 330 start.textContent = "\\" + "begin{tabular}{|l|";
n@1227 331 holder.appendChild(start);
n@1264 332 for (var i=0; i<numRows; i++) {
n@1227 333 start.textContent = start.textContent+"c|";
n@1227 334 }
n@1228 335 start.textContent = start.textContent.concat("}");
n@1227 336 // Now write the rows:
n@1264 337 for (var rIndex=0; rIndex<numColumns; rIndex++) {
n@1273 338 var tableTitle = this.data.getColumnLabel(rIndex);
n@1273 339 if(tableTitle != "")
n@1273 340 {
n@1273 341 var row = document.createElement("p");
n@1273 342 row.textContent = tableTitle.concat(" & ");
n@1273 343 for (var cIndex=0; cIndex<numRows; cIndex++) {
n@1273 344 var entry = this.data.getValue(cIndex,rIndex);
n@1273 345 if (isFinite(Number(entry)))
n@1273 346 {
n@1273 347 entry = String(Number(entry).toFixed(4));
n@1273 348 }
n@1273 349 row.textContent = row.textContent.concat(entry);
n@1273 350 if (cIndex < numRows-1) {
n@1273 351 row.textContent = row.textContent.concat(" & ");
n@1273 352 } else {
n@1273 353 row.textContent = row.textContent.concat(" \\\\ \\hline");
n@1273 354 }
n@1264 355 }
n@1273 356 holder.appendChild(row);
n@1227 357 }
n@1227 358 }
n@1227 359 // Table end
n@1227 360 var end = document.createElement("p");
n@1227 361 end.textContent = "\\" + "end{tabular}";
n@1227 362 holder.appendChild(end);
n@1227 363 root.appendChild(holder);
n@1227 364 this.latexDOM.appendChild(root);
n@1227 365 }
n@1227 366 }
n@1227 367
n@1227 368 this.clear = function() {
n@1227 369 var inject = document.getElementById("test-pages");
n@1227 370 for (var chart of this.charts) {
n@1227 371 inject.removeChild(chart.root);
n@1227 372 }
n@1227 373 this.charts = [];
n@1227 374 }
n@1227 375
n@1227 376 this.drawTestMean = function() {
n@1227 377 // This draws one bargraph per axis with every test element on
n@1227 378 if (this.valueData == null) {
n@1227 379 console.log("Error - Data not loaded");
n@1227 380 return;
n@1227 381 }
n@1227 382 var chartList = [];
n@1227 383
n@1227 384 // Create the data table
n@1227 385 for (var page of this.valueData.pages) {
n@1227 386 for (var element of page.elements) {
n@1227 387 for (var axis of element.axis) {
n@1227 388 // Find the axis
n@1227 389 var axisChart = chartList.find(function(element,index,array){
n@1227 390 if (element.name == this) {return true;} else {return false;}
n@1273 391 },"mean-test-"+axis.name);
n@1227 392 if (axisChart == null) {
n@1273 393 axisChart = new this.chartObject("mean-test-"+axis.name);
n@1227 394 axisChart.options = {
n@1227 395 'title':'Mean of axis: '+axis.name,
n@1227 396 'width':window.innerWidth*0.9,
n@1227 397 'height':(window.innerWidth*0.9)/1.77
n@1227 398 }
n@1227 399 axisChart.data.addColumn('string','id');
n@1227 400 axisChart.data.addColumn('number',axis.name);
n@1227 401 chartList.push(axisChart);
n@1227 402 document.getElementById("test-pages").appendChild(axisChart.root);
n@1227 403 }
n@1227 404 var mean = arrayMean(axis.values);
n@1227 405 axisChart.data.addRow([element.id,mean]);
n@1227 406 }
n@1227 407 }
n@1227 408 }
n@1227 409
n@1227 410 // Build and push charts
n@1227 411 for (var chart of chartList) {
n@1227 412 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
n@1227 413 chart.chart.draw(chart.data,chart.options);
n@1227 414 chart.buildTable();
n@1227 415 chart.writeLatex();
n@1227 416 this.charts.push(chart);
n@1227 417 }
n@1227 418 }
n@1227 419
n@1273 420 this.drawTestBoxplot = function() {
n@1273 421 if (this.valueData == null) {
n@1273 422 console.log("Error - Data not loaded");
n@1273 423 return;
n@1273 424 }
n@1273 425 var chartList = [];
n@1273 426
n@1273 427 // Creates one chart per axis
n@1273 428
n@1273 429 // Create the data table
n@1273 430 for (var page of this.valueData.pages) {
n@1273 431 for (var element of page.elements) {
n@1273 432 for (var axis of element.axis) {
n@1273 433 // Find the axis
n@1273 434 var axisChart = chartList.find(function(element,index,array){
n@1273 435 if (element.name == this) {return true;} else {return false;}
n@1273 436 },"boxplot-test-"+axis.name);
n@1273 437 if (axisChart == null) {
n@1273 438 // Axis chart doesn't exist
n@1273 439 axisChart = new this.chartObject("boxplot-test-"+axis.name);
n@1273 440 axisChart.options = {
n@1273 441 'title':'Boxplot of axis '+axis.name,
n@1273 442 'width':window.innerWidth*0.9,
n@1273 443 'height':(window.innerWidth*0.9)/1.77,
n@1273 444 legend: {position: 'none'},
n@1273 445 lineWidth: 0,
n@1273 446 series: [{'color': '#D3362D'}],
n@1273 447 intervals: {
n@1273 448 barWidth: 1,
n@1273 449 boxWidth: 1,
n@1273 450 lineWidth: 2,
n@1273 451 style: 'boxes'
n@1273 452 },
n@1273 453 interval: {
n@1273 454 max: {
n@1273 455 style: 'bars',
n@1273 456 fillOpacity: 1,
n@1273 457 color: '#777'
n@1273 458 },
n@1273 459 min: {
n@1273 460 style: 'bars',
n@1273 461 fillOpacity: 1,
n@1273 462 color: '#777'
n@1273 463 }
n@1273 464 }
n@1273 465 };
n@1273 466 axisChart.data.addColumn('string','id');
n@1273 467 axisChart.data.addColumn('number','median');
n@1273 468 axisChart.data.addColumn({id:'max',type:'number',role:'interval'});
n@1273 469 axisChart.data.addColumn({id:'min',type:'number',role:'interval'});
n@1273 470 axisChart.data.addColumn({id:'firstQuartile',type:'number',role:'interval'});
n@1273 471 axisChart.data.addColumn({id:'median',type:'number',role:'interval'});
n@1273 472 axisChart.data.addColumn({id:'thirdQuartile',type:'number',role:'interval'});
n@1273 473 chartList.push(axisChart);
n@1273 474 document.getElementById("test-pages").appendChild(axisChart.root);
n@1273 475 }
n@1273 476 var result = boxplotRow(axis.values);
n@1273 477 axisChart.data.addRow([element.id,result.median,result.max,result.min,result.pct25,result.median,result.pct75]);
n@1273 478 }
n@1273 479 }
n@1273 480 }
n@1273 481 // Build and push charts
n@1273 482 for (var chart of chartList) {
n@1273 483 chart.chart = new google.visualization.LineChart(chart.chartDOM);
n@1273 484 chart.chart.draw(chart.data,chart.options);
n@1273 485 chart.buildTable();
n@1273 486 chart.writeLatex();
n@1273 487 this.charts.push(chart);
n@1273 488 }
n@1273 489 }
n@1273 490
n@1227 491 this.drawPageMean = function() {
n@1223 492 // First we must get the value data
n@1226 493 if (this.valueData == null) {
n@1226 494 console.log("Error - Data not loaded");
n@1226 495 return;
n@1226 496 }
n@1226 497 // We create one plot per page
n@1226 498 for (var page of this.valueData.pages) {
n@1227 499
n@1227 500 // Create the chart resulting point
n@1227 501 var chart = new this.chartObject("mean-page-"+page.id);
n@1227 502 document.getElementById("test-pages").appendChild(chart.root);
n@1226 503
n@1226 504 // Create the data table
n@1227 505 chart.data.addColumn('string','id');
n@1226 506 // Get axis labels
n@1226 507 for (var axis of page.elements[0].axis) {
n@1227 508 chart.data.addColumn('number',axis.name);
n@1226 509 }
n@1226 510 var rows = []; // Rows is an array of tuples [col1, col2, col3 ... colN];
n@1226 511 for (var element of page.elements) {
n@1226 512 var entry = [element.id];
n@1226 513 for (var i=0; i<page.elements[0].axis.length; i++) {
n@1226 514 var mean =0;
n@1226 515 if (i < element.axis.length) {
n@1226 516 var axis = element.axis[i];
n@1227 517 mean = arrayMean(axis.values);
n@1226 518 }
n@1226 519 entry.push(mean);
n@1226 520 }
n@1226 521 rows.push(entry);
n@1226 522 }
n@1227 523 chart.data.addRows(rows);
n@1227 524 chart.options = {
n@1227 525 'title':'Mean of page: '+page.id,
n@1227 526 'width':800,
n@1227 527 'height':700
n@1227 528 }
n@1226 529 // Draw the chart
n@1227 530 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
n@1227 531 chart.chart.draw(chart.data,chart.options);
n@1227 532 chart.buildTable();
n@1227 533 chart.writeLatex();
n@1227 534 this.charts.push(chart);
n@1227 535 }
n@1227 536 }
n@1227 537
n@1227 538 this.drawElementHistogram = function() {
n@1227 539 // First we must get the value data
n@1227 540 if (this.valueData == null) {
n@1227 541 console.log("Error - Data not loaded");
n@1227 542 return;
n@1227 543 }
n@1227 544 // We create one plot per element, enjoy...
n@1227 545 for (var page of this.valueData.pages) {
n@1227 546 for (var element of page.elements) {
n@1227 547 // Build the chart object
n@1227 548 var chart = new this.chartObject("histogram-element-"+element.id);
n@1227 549 document.getElementById("test-pages").appendChild(chart.root);
n@1227 550 chart.data.addColumn('string','index');
n@1227 551 var histograms = [];
n@1227 552 for (var axis of element.axis) {
n@1227 553 chart.data.addColumn('number',axis.name);
n@1227 554 histograms.push(arrayHistogram(axis.values,0.125,0.0,1.0));
n@1227 555 }
n@1227 556 for (var axis of element.axis) {
n@1227 557 for (var i=0; i<histograms[0].length; i++)
n@1227 558 {
n@1227 559 var entry = [""+histograms[0][i].lt.toPrecision(2)+"-"+histograms[0][i].rt.toPrecision(3)]
n@1227 560 for (var histogram of histograms) {
n@1227 561 entry.push(histogram[i].count);
n@1227 562 }
n@1227 563 chart.data.addRow(entry);
n@1227 564 }
n@1227 565 }
n@1227 566 chart.options = {
n@1227 567 'title':'Histogram of element: '+element.id,
n@1227 568 'width':800,
n@1227 569 'height':700,
n@1227 570 'bar':{'groupWidth': '100%'}
n@1227 571 }
n@1227 572 // Draw the chart
n@1227 573 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
n@1227 574 chart.chart.draw(chart.data,chart.options);
n@1227 575 chart.buildTable();
n@1227 576 chart.writeLatex();
n@1227 577 this.charts.push(chart);
n@1227 578 }
n@1226 579 }
n@1223 580 }
n@1284 581 }
n@1284 582
n@1284 583 function Data() {
n@1284 584 // This holds the link between the server side calculations and the client side visualisation of the data
n@1284 585
n@1284 586 // Dynamically generate the test filtering / page filterting tools
n@1284 587 var self = this;
n@1284 588 // Collect the test types and counts
n@1284 589 this.testSavedDiv = document.getElementById("test-saved");
n@1284 590 this.testSaves = null;
n@1284 591 this.selectURL = null;
n@1285 592
n@1284 593 this.specification = new Specification();
n@1284 594 get("../test-schema.xsd").then(function(response){
n@1284 595 var parse = new DOMParser();
n@1284 596 self.specification.schema = parse.parseFromString(response,'text/xml');
n@1284 597 },function(error){
n@1284 598 console.log("ERROR: Could not get Test Schema");
n@1284 599 });
n@1284 600 this.update = function(url) {
n@1284 601 var self = this;
n@1284 602 }
n@1285 603
n@1285 604 this.updateData = function(req_str) {
n@1285 605 // Now go get that data
n@1285 606 get(req_str).then(function(response){
n@1285 607 // Returns the data
n@1285 608 chartContext.valueData = JSON.parse(response);
n@1285 609 },function(error){console.error(error);});
n@1285 610 }
n@1284 611 }
n@1284 612
n@1284 613 var interfaceContext = new function() {
n@1284 614 // This creates the interface for the user to connect with the dynamic back-end to retrieve data
n@1284 615 this.rootDOM = document.createElement("div");
n@1285 616 this.getDataButton = {
n@1285 617 button: document.createElement("button"),
n@1285 618 parent: this,
n@1285 619 handleEvent: function(event) {
n@1285 620 // Get the list of files:
n@1285 621 var req_str = "../scripts/get_filtered_score.php"+this.parent.getFilterString();
n@1285 622 testData.updateData(req_str);
n@1285 623 }
n@1285 624 }
n@1285 625 this.getDataButton.button.textContent = "Get Filtered Data";
n@1285 626 this.getDataButton.button.addEventListener("click",this.getDataButton);
n@1285 627
n@1287 628 this.testSaves = {
n@1287 629 json: null,
n@1287 630 selectedURL: null,
n@1287 631 inputs: [],
n@1287 632 parent: this
n@1287 633 };
n@1287 634 this.init = function() {
n@1287 635 var self = this;
n@1287 636 get('../scripts/get_tests.php?format=JSON').then(function(response){
n@1287 637 document.getElementById("test-saved").innerHTML = null;
n@1287 638 var table = document.createElement("table");
n@1287 639 table.innerHTML = "<tr><td>Test Filename</td><td>Count</td><td>Include</td></tr>";
n@1287 640 self.testSaves.json = JSON.parse(response);
n@1287 641 for (var test of self.testSaves.json.tests) {
n@1287 642 var tableRow = document.createElement("tr");
n@1287 643 var tableRowFilename = document.createElement("td");
n@1287 644 tableRowFilename.textContent = test.testName;
n@1287 645 var tableRowCount = document.createElement("td");
n@1287 646 tableRowCount.textContent = test.files.length;
n@1287 647 tableRow.appendChild(tableRowFilename);
n@1287 648 tableRow.appendChild(tableRowCount);
n@1287 649 var tableRowInclude = document.createElement("td");
n@1287 650 var obj = {
n@1287 651 root: document.createElement("input"),
n@1287 652 parent: self.testSaves,
n@1287 653 handleEvent: function(event) {
n@1287 654 this.parent.selectedURL = event.currentTarget.getAttribute("source");
n@1287 655 var self = this;
n@1287 656 get(this.parent.selectedURL).then(function(response){
n@1287 657 var parse = new DOMParser();
n@1287 658 testData.specification.decode(parse.parseFromString(response,'text/xml'));
n@1287 659 self.parent.parent.generateFilters(testData.specification);
n@1287 660 self.parent.parent.getFileCount();
n@1287 661 return true;
n@1287 662 },function(error){
n@1287 663 console.log("ERROR: Could not get"+url);
n@1287 664 return false;
n@1287 665 });
n@1287 666 }
n@1287 667 }
n@1287 668 obj.root.type = "radio";
n@1287 669 obj.root.name = "test-include";
n@1287 670 obj.root.setAttribute("source",test.testName);
n@1287 671 obj.root.addEventListener("change",obj);
n@1287 672 tableRowInclude.appendChild(obj.root);
n@1287 673 tableRow.appendChild(tableRowInclude);
n@1287 674 table.appendChild(tableRow);
n@1287 675 self.testSaves.inputs.push(obj);
n@1287 676 }
n@1287 677 document.getElementById("test-saved").appendChild(table);
n@1287 678 },function(error){console.error(error);});
n@1287 679 }
n@1287 680
n@1284 681 this.filterDOM = document.createElement("div");
n@1284 682 this.filterDOM.innerHTML = "<p>PreTest Filters</p><div id='filter-count'></div>";
n@1284 683 this.filterObjects = [];
n@1284 684 this.generateFilters = function(specification) {
n@1284 685 // Filters are based on the pre and post global surverys
n@1284 686 var FilterObject = function(parent,specification) {
n@1284 687 this.parent = parent;
n@1284 688 this.specification = specification;
n@1284 689 this.rootDOM = document.createElement("div");
n@1284 690 this.rootDOM.innerHTML = "<span>ID: "+specification.id+", Type: "+specification.type+"</span>";
n@1284 691 this.rootDOM.className = "filter-entry";
n@1284 692 this.handleEvent = function(event) {
n@1284 693 switch(this.specification.type) {
n@1284 694 case "number":
n@1284 695 var name = event.currentTarget.name;
n@1284 696 eval("this."+name+" = event.currentTarget.value");
n@1284 697 break;
n@1284 698 case "checkbox":
n@1284 699 break;
n@1284 700 case "radio":
n@1284 701 break;
n@1284 702 }
n@1284 703 this.parent.getFileCount();
n@1284 704 }
n@1284 705 this.getFilterPairs = function() {
n@1284 706 var pairs = [];
n@1284 707 switch(this.specification.type) {
n@1284 708 case "number":
n@1284 709 if (this.min != "") {
n@1284 710 pairs.push([specification.id+"-min",this.min]);
n@1284 711 }
n@1284 712 if (this.max != "") {
n@1284 713 pairs.push([specification.id+"-max",this.max]);
n@1284 714 }
n@1284 715 break;
n@1284 716 case "radio":
n@1284 717 case "checkbox":
n@1284 718 for (var i=0; i<this.options.length; i++) {
n@1284 719 if (!this.options[i].checked) {
n@1284 720 pairs.push([specification.id+"-exclude-"+i,specification.options[i].name]);
n@1284 721 }
n@1284 722 }
n@1284 723 break;
n@1284 724 }
n@1284 725 return pairs;
n@1284 726 }
n@1284 727 switch(specification.type) {
n@1284 728 case "number":
n@1284 729 // Number can be ranged by min/max levels
n@1284 730 this.min = "";
n@1284 731 this.max = "";
n@1284 732 this.minDOM = document.createElement("input");
n@1284 733 this.minDOM.type = "number";
n@1284 734 this.minDOM.name = "min";
n@1284 735 this.minDOM.addEventListener("change",this);
n@1284 736 this.minDOMText = document.createElement("span");
n@1284 737 this.minDOMText.textContent = "Minimum: ";
n@1284 738 var pairHolder = document.createElement("div");
n@1284 739 pairHolder.appendChild(this.minDOMText);
n@1284 740 pairHolder.appendChild(this.minDOM);
n@1284 741 this.rootDOM.appendChild(pairHolder);
n@1284 742
n@1284 743 this.maxDOM = document.createElement("input");
n@1284 744 this.maxDOM.type = "number";
n@1284 745 this.maxDOM.name = "max";
n@1284 746 this.maxDOM.addEventListener("change",this);
n@1284 747 this.maxDOMText = document.createElement("span");
n@1284 748 this.maxDOMText.textContent = "Maximum: ";
n@1284 749 var pairHolder = document.createElement("div");
n@1284 750 pairHolder.appendChild(this.maxDOMText);
n@1284 751 pairHolder.appendChild(this.maxDOM);
n@1284 752 this.rootDOM.appendChild(pairHolder);
n@1284 753 break;
n@1284 754 case "radio":
n@1284 755 case "checkbox":
n@1284 756 this.options = [];
n@1284 757 for (var i=0; i<specification.options.length; i++) {
n@1284 758 var option = specification.options[i];
n@1284 759 var pairHolder = document.createElement("div");
n@1284 760 var text = document.createElement("span");
n@1284 761 text.textContent = option.text;
n@1284 762 var check = document.createElement("input");
n@1284 763 check.type = "checkbox";
n@1284 764 check.setAttribute("option-index",i);
n@1284 765 check.checked = true;
n@1284 766 check.addEventListener("click",this);
n@1284 767 this.options.push(check);
n@1284 768 pairHolder.appendChild(text);
n@1284 769 pairHolder.appendChild(check);
n@1284 770 this.rootDOM.appendChild(pairHolder);
n@1284 771 }
n@1284 772 break;
n@1284 773 default:
n@1284 774 break;
n@1284 775 }
n@1284 776 }
n@1287 777 for (var survey_entry of specification.preTest.options.concat(specification.postTest.options)) {
n@1284 778 switch(survey_entry.type) {
n@1284 779 case "number":
n@1284 780 case "radio":
n@1284 781 case "checkbox":
n@1284 782 var node = new FilterObject(this,survey_entry);
n@1284 783 this.filterObjects.push(node);
n@1284 784 this.filterDOM.appendChild(node.rootDOM);
n@1284 785 break;
n@1284 786 default:
n@1284 787 break;
n@1284 788 }
n@1284 789 }
n@1284 790 document.getElementById("test-saved").appendChild(this.filterDOM);
n@1285 791 document.getElementById("test-saved").appendChild(this.getDataButton.button);
n@1284 792 }
n@1285 793 this.getFilterString = function() {
n@1284 794 var pairs = [];
n@1284 795 for (var obj of this.filterObjects) {
n@1284 796 pairs = pairs.concat(obj.getFilterPairs());
n@1284 797 }
n@1287 798 var req_str = "?url="+this.testSaves.selectedURL;
n@1284 799 var index = 0;
n@1284 800 while(pairs[index] != undefined) {
n@1284 801 req_str += '&';
n@1284 802 req_str += pairs[index][0]+"="+pairs[index][1];
n@1284 803 index++;
n@1284 804 }
n@1285 805 return req_str;
n@1285 806 }
n@1285 807 this.getFilteredUrlArray = function() {
n@1285 808 var req_str = "../scripts/get_filtered_count.php"+this.getFilterString();
n@1285 809 return get(req_str).then(function(response){
n@1284 810 var urls = JSON.parse(response);
n@1285 811 return urls.urls;
n@1285 812 },function(error){
n@1285 813 console.error(error);
n@1285 814 });
n@1285 815 }
n@1285 816 this.getFileCount = function() {
n@1285 817 // First we must get the filter pairs
n@1285 818 this.getFilteredUrlArray().then(function(response){
n@1285 819 var str = "Filtered to "+response.length+" file";
n@1285 820 if (response.length != 1) {
n@1284 821 str += "s.";
n@1284 822 } else {
n@1284 823 str += ".";
n@1284 824 }
n@1284 825 document.getElementById("filter-count").textContent = str;
n@1285 826 },function(error){});
n@1284 827 }
n@1287 828
n@1287 829 this.init();
n@1223 830 }