OLD | NEW |
1 /* | 1 /* |
2 * Loader: | 2 * Loader: |
3 * Reads GM result reports written out by results.py, and imports | 3 * Reads GM result reports written out by results.py, and imports |
4 * them into $scope.extraColumnHeaders and $scope.imagePairs . | 4 * them into $scope.extraColumnHeaders and $scope.imagePairs . |
5 */ | 5 */ |
6 var Loader = angular.module( | 6 var Loader = angular.module( |
7 'Loader', | 7 'Loader', |
8 ['ConstantsModule'] | 8 ['ConstantsModule'] |
9 ); | 9 ); |
10 | 10 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
49 .indexOf(testSubstring)) && | 49 .indexOf(testSubstring)) && |
50 (viewingTab == imagePair.tab)) { | 50 (viewingTab == imagePair.tab)) { |
51 filteredImagePairs.push(imagePair); | 51 filteredImagePairs.push(imagePair); |
52 } | 52 } |
53 } | 53 } |
54 return filteredImagePairs; | 54 return filteredImagePairs; |
55 }; | 55 }; |
56 } | 56 } |
57 ); | 57 ); |
58 | 58 |
| 59 /** |
| 60 * Limit the input imagePairs to some max number, and merge identical rows |
| 61 * (adjacent rows which have the same (imageA, imageB) pair). |
| 62 * |
| 63 * @param unfilteredImagePairs imagePairs to filter |
| 64 * @param maxPairs maximum number of pairs to output, or <0 for no limit |
| 65 * @param mergeIdenticalRows if true, merge identical rows by setting |
| 66 * ROWSPAN>1 on the first merged row, and ROWSPAN=0 for the rest |
| 67 */ |
| 68 Loader.filter( |
| 69 'mergeAndLimit', |
| 70 function(constants) { |
| 71 return function(unfilteredImagePairs, maxPairs, mergeIdenticalRows) { |
| 72 var numPairs = unfilteredImagePairs.length; |
| 73 if ((maxPairs > 0) && (maxPairs < numPairs)) { |
| 74 numPairs = maxPairs; |
| 75 } |
| 76 var filteredImagePairs = []; |
| 77 if (!mergeIdenticalRows || (numPairs == 1)) { |
| 78 // Take a shortcut if we're not merging identical rows. |
| 79 // We still need to set ROWSPAN to 1 for each row, for the HTML viewer. |
| 80 for (var i = numPairs-1; i >= 0; i--) { |
| 81 var imagePair = unfilteredImagePairs[i]; |
| 82 imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1; |
| 83 filteredImagePairs[i] = imagePair; |
| 84 } |
| 85 } else if (numPairs > 1) { |
| 86 // General case--there are at least 2 rows, so we may need to merge some
. |
| 87 // Work from the bottom up, so we can keep a running total of how many |
| 88 // rows should be merged, and set ROWSPAN of the top row accordingly. |
| 89 var imagePair = unfilteredImagePairs[numPairs-1]; |
| 90 var nextRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]
; |
| 91 var nextRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]
; |
| 92 imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1; |
| 93 filteredImagePairs[numPairs-1] = imagePair; |
| 94 for (var i = numPairs-2; i >= 0; i--) { |
| 95 imagePair = unfilteredImagePairs[i]; |
| 96 var thisRowImageAUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_UR
L]; |
| 97 var thisRowImageBUrl = imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_UR
L]; |
| 98 if ((thisRowImageAUrl == nextRowImageAUrl) && |
| 99 (thisRowImageBUrl == nextRowImageBUrl)) { |
| 100 imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = |
| 101 filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] + 1; |
| 102 filteredImagePairs[i+1][constants.KEY__IMAGEPAIRS__ROWSPAN] = 0; |
| 103 } else { |
| 104 imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] = 1; |
| 105 nextRowImageAUrl = thisRowImageAUrl; |
| 106 nextRowImageBUrl = thisRowImageBUrl; |
| 107 } |
| 108 filteredImagePairs[i] = imagePair; |
| 109 } |
| 110 } else { |
| 111 // No results. |
| 112 } |
| 113 return filteredImagePairs; |
| 114 }; |
| 115 } |
| 116 ); |
| 117 |
59 | 118 |
60 Loader.controller( | 119 Loader.controller( |
61 'Loader.Controller', | 120 'Loader.Controller', |
62 function($scope, $http, $filter, $location, $log, $timeout, constants) { | 121 function($scope, $http, $filter, $location, $log, $timeout, constants) { |
63 $scope.constants = constants; | 122 $scope.constants = constants; |
64 $scope.windowTitle = "Loading GM Results..."; | 123 $scope.windowTitle = "Loading GM Results..."; |
65 $scope.resultsToLoad = $location.search().resultsToLoad; | 124 $scope.resultsToLoad = $location.search().resultsToLoad; |
66 $scope.loadingMessage = "please wait..."; | 125 $scope.loadingMessage = "please wait..."; |
67 | 126 |
68 /** | 127 /** |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 * Toggle selection of all currently showing tests. | 286 * Toggle selection of all currently showing tests. |
228 */ | 287 */ |
229 $scope.toggleAllImagePairs = function() { | 288 $scope.toggleAllImagePairs = function() { |
230 var numImagePairsShowing = $scope.limitedImagePairs.length; | 289 var numImagePairsShowing = $scope.limitedImagePairs.length; |
231 for (var i = 0; i < numImagePairsShowing; i++) { | 290 for (var i = 0; i < numImagePairsShowing; i++) { |
232 var index = $scope.limitedImagePairs[i].index; | 291 var index = $scope.limitedImagePairs[i].index; |
233 $scope.toggleValueInArray(index, $scope.selectedImagePairs); | 292 $scope.toggleValueInArray(index, $scope.selectedImagePairs); |
234 } | 293 } |
235 } | 294 } |
236 | 295 |
| 296 /** |
| 297 * Toggle selection state of a subset of the currently showing tests. |
| 298 * |
| 299 * @param startIndex index within $scope.limitedImagePairs of the first |
| 300 * test to toggle selection state of |
| 301 * @param num number of tests (in a contiguous block) to toggle |
| 302 */ |
| 303 $scope.toggleSomeImagePairs = function(startIndex, num) { |
| 304 var numImagePairsShowing = $scope.limitedImagePairs.length; |
| 305 for (var i = startIndex; i < startIndex + num; i++) { |
| 306 var index = $scope.limitedImagePairs[i].index; |
| 307 $scope.toggleValueInArray(index, $scope.selectedImagePairs); |
| 308 } |
| 309 } |
| 310 |
237 | 311 |
238 // | 312 // |
239 // Tab operations. | 313 // Tab operations. |
240 // | 314 // |
241 | 315 |
242 /** | 316 /** |
243 * Change the selected tab. | 317 * Change the selected tab. |
244 * | 318 * |
245 * @param tab (string): name of the tab to select | 319 * @param tab (string): name of the tab to select |
246 */ | 320 */ |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
328 } | 402 } |
329 }, | 403 }, |
330 | 404 |
331 }; | 405 }; |
332 | 406 |
333 // parameter name -> copier objects to load/save parameter value | 407 // parameter name -> copier objects to load/save parameter value |
334 $scope.queryParameters.map = { | 408 $scope.queryParameters.map = { |
335 'resultsToLoad': $scope.queryParameters.copiers.simple, | 409 'resultsToLoad': $scope.queryParameters.copiers.simple, |
336 'displayLimitPending': $scope.queryParameters.copiers.simple, | 410 'displayLimitPending': $scope.queryParameters.copiers.simple, |
337 'showThumbnailsPending': $scope.queryParameters.copiers.simple, | 411 'showThumbnailsPending': $scope.queryParameters.copiers.simple, |
| 412 'mergeIdenticalRowsPending': $scope.queryParameters.copiers.simple, |
338 'imageSizePending': $scope.queryParameters.copiers.simple, | 413 'imageSizePending': $scope.queryParameters.copiers.simple, |
339 'sortColumnSubdict': $scope.queryParameters.copiers.simple, | 414 'sortColumnSubdict': $scope.queryParameters.copiers.simple, |
340 'sortColumnKey': $scope.queryParameters.copiers.simple, | 415 'sortColumnKey': $scope.queryParameters.copiers.simple, |
341 | 416 |
342 'hiddenResultTypes': $scope.queryParameters.copiers.set, | 417 'hiddenResultTypes': $scope.queryParameters.copiers.set, |
343 'hiddenConfigs': $scope.queryParameters.copiers.set, | 418 'hiddenConfigs': $scope.queryParameters.copiers.set, |
344 }; | 419 }; |
345 $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__BUILDER] = | 420 $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__BUILDER] = |
346 $scope.queryParameters.copiers.categoryValueMatch; | 421 $scope.queryParameters.copiers.categoryValueMatch; |
347 $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__TEST] = | 422 $scope.queryParameters.map[constants.KEY__EXTRACOLUMNS__TEST] = |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
393 | 468 |
394 /** | 469 /** |
395 * Update the displayed results, based on filters/settings, | 470 * Update the displayed results, based on filters/settings, |
396 * and call $scope.queryParameters.save() so that the new filter results | 471 * and call $scope.queryParameters.save() so that the new filter results |
397 * can be bookmarked. | 472 * can be bookmarked. |
398 */ | 473 */ |
399 $scope.updateResults = function() { | 474 $scope.updateResults = function() { |
400 $scope.renderStartTime = window.performance.now(); | 475 $scope.renderStartTime = window.performance.now(); |
401 $log.debug("renderStartTime: " + $scope.renderStartTime); | 476 $log.debug("renderStartTime: " + $scope.renderStartTime); |
402 $scope.displayLimit = $scope.displayLimitPending; | 477 $scope.displayLimit = $scope.displayLimitPending; |
| 478 $scope.mergeIdenticalRows = $scope.mergeIdenticalRowsPending; |
403 // TODO(epoger): Every time we apply a filter, AngularJS creates | 479 // TODO(epoger): Every time we apply a filter, AngularJS creates |
404 // another copy of the array. Is there a way we can filter out | 480 // another copy of the array. Is there a way we can filter out |
405 // the imagePairs as they are displayed, rather than storing multiple | 481 // the imagePairs as they are displayed, rather than storing multiple |
406 // array copies? (For better performance.) | 482 // array copies? (For better performance.) |
407 | 483 |
408 if ($scope.viewingTab == $scope.defaultTab) { | 484 if ($scope.viewingTab == $scope.defaultTab) { |
409 | 485 |
410 // TODO(epoger): Until we allow the user to reverse sort order, | 486 // TODO(epoger): Until we allow the user to reverse sort order, |
411 // there are certain columns we want to sort in a different order. | 487 // there are certain columns we want to sort in a different order. |
412 var doReverse = ( | 488 var doReverse = ( |
413 ($scope.sortColumnKey == | 489 ($scope.sortColumnKey == |
414 constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS) || | 490 constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS) || |
415 ($scope.sortColumnKey == | 491 ($scope.sortColumnKey == |
416 constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)); | 492 constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)); |
417 | 493 |
418 $scope.filteredImagePairs = | 494 $scope.filteredImagePairs = |
419 $filter("orderBy")( | 495 $filter("orderBy")( |
420 $filter("removeHiddenImagePairs")( | 496 $filter("removeHiddenImagePairs")( |
421 $scope.imagePairs, | 497 $scope.imagePairs, |
422 $scope.hiddenResultTypes, | 498 $scope.hiddenResultTypes, |
423 $scope.hiddenConfigs, | 499 $scope.hiddenConfigs, |
424 $scope.categoryValueMatch.builder, | 500 $scope.categoryValueMatch.builder, |
425 $scope.categoryValueMatch.test, | 501 $scope.categoryValueMatch.test, |
426 $scope.viewingTab | 502 $scope.viewingTab |
427 ), | 503 ), |
428 $scope.getSortColumnValue, doReverse); | 504 [$scope.getSortColumnValue, $scope.getSecondOrderSortValue], |
429 $scope.limitedImagePairs = $filter("limitTo")( | 505 doReverse); |
430 $scope.filteredImagePairs, $scope.displayLimit); | 506 $scope.limitedImagePairs = $filter("mergeAndLimit")( |
| 507 $scope.filteredImagePairs, $scope.displayLimit, $scope.mergeIdentica
lRows); |
431 } else { | 508 } else { |
432 $scope.filteredImagePairs = | 509 $scope.filteredImagePairs = |
433 $filter("orderBy")( | 510 $filter("orderBy")( |
434 $filter("filter")( | 511 $filter("filter")( |
435 $scope.imagePairs, | 512 $scope.imagePairs, |
436 {tab: $scope.viewingTab}, | 513 {tab: $scope.viewingTab}, |
437 true | 514 true |
438 ), | 515 ), |
439 $scope.getSortColumnValue); | 516 [$scope.getSortColumnValue, $scope.getSecondOrderSortValue]); |
440 $scope.limitedImagePairs = $scope.filteredImagePairs; | 517 $scope.limitedImagePairs = $filter("mergeAndLimit")( |
| 518 $scope.filteredImagePairs, -1, $scope.mergeIdenticalRows); |
441 } | 519 } |
442 $scope.showThumbnails = $scope.showThumbnailsPending; | 520 $scope.showThumbnails = $scope.showThumbnailsPending; |
443 $scope.imageSize = $scope.imageSizePending; | 521 $scope.imageSize = $scope.imageSizePending; |
444 $scope.setUpdatesPending(false); | 522 $scope.setUpdatesPending(false); |
445 $scope.queryParameters.save(); | 523 $scope.queryParameters.save(); |
446 } | 524 } |
447 | 525 |
448 /** | 526 /** |
449 * This function is called when the results have been completely rendered | 527 * This function is called when the results have been completely rendered |
450 * after updateResults(). | 528 * after updateResults(). |
451 */ | 529 */ |
452 $scope.resultsUpdatedCallback = function() { | 530 $scope.resultsUpdatedCallback = function() { |
453 $scope.renderEndTime = window.performance.now(); | 531 $scope.renderEndTime = window.performance.now(); |
454 $log.debug("renderEndTime: " + $scope.renderEndTime); | 532 $log.debug("renderEndTime: " + $scope.renderEndTime); |
455 } | 533 } |
456 | 534 |
457 /** | 535 /** |
458 * Re-sort the displayed results. | 536 * Re-sort the displayed results. |
459 * | 537 * |
460 * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary | 538 * @param subdict (string): which KEY__IMAGEPAIRS__* subdictionary |
461 * the sort column key is within | 539 * the sort column key is within, or 'none' if the sort column |
| 540 * key is one of KEY__IMAGEPAIRS__* |
462 * @param key (string): sort by value associated with this key in subdict | 541 * @param key (string): sort by value associated with this key in subdict |
463 */ | 542 */ |
464 $scope.sortResultsBy = function(subdict, key) { | 543 $scope.sortResultsBy = function(subdict, key) { |
465 $scope.sortColumnSubdict = subdict; | 544 $scope.sortColumnSubdict = subdict; |
466 $scope.sortColumnKey = key; | 545 $scope.sortColumnKey = key; |
467 $scope.updateResults(); | 546 $scope.updateResults(); |
468 } | 547 } |
469 | 548 |
470 /** | 549 /** |
471 * For a particular ImagePair, return the value of the column we are | 550 * For a particular ImagePair, return the value of the column we are |
472 * sorting on (according to $scope.sortColumnSubdict and | 551 * sorting on (according to $scope.sortColumnSubdict and |
473 * $scope.sortColumnKey). | 552 * $scope.sortColumnKey). |
474 * | 553 * |
475 * @param imagePair: imagePair to get a column value out of. | 554 * @param imagePair: imagePair to get a column value out of. |
476 */ | 555 */ |
477 $scope.getSortColumnValue = function(imagePair) { | 556 $scope.getSortColumnValue = function(imagePair) { |
478 if ($scope.sortColumnSubdict in imagePair) { | 557 if ($scope.sortColumnSubdict in imagePair) { |
479 return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey]; | 558 return imagePair[$scope.sortColumnSubdict][$scope.sortColumnKey]; |
| 559 } else if ($scope.sortColumnKey in imagePair) { |
| 560 return imagePair[$scope.sortColumnKey]; |
480 } else { | 561 } else { |
481 return undefined; | 562 return undefined; |
482 } | 563 } |
483 } | 564 } |
484 | 565 |
485 /** | 566 /** |
| 567 * For a particular ImagePair, return the value we use for the |
| 568 * second-order sort (tiebreaker when multiple rows have |
| 569 * the same getSortColumnValue()). |
| 570 * |
| 571 * We join the imageA and imageB urls for this value, so that we merge |
| 572 * adjacent rows as much as possible. |
| 573 * |
| 574 * @param imagePair: imagePair to get a column value out of. |
| 575 */ |
| 576 $scope.getSecondOrderSortValue = function(imagePair) { |
| 577 return imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + |
| 578 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; |
| 579 } |
| 580 |
| 581 /** |
486 * Set $scope.categoryValueMatch[name] = value, and update results. | 582 * Set $scope.categoryValueMatch[name] = value, and update results. |
487 * | 583 * |
488 * @param name | 584 * @param name |
489 * @param value | 585 * @param value |
490 */ | 586 */ |
491 $scope.setCategoryValueMatch = function(name, value) { | 587 $scope.setCategoryValueMatch = function(name, value) { |
492 $scope.categoryValueMatch[name] = value; | 588 $scope.categoryValueMatch[name] = value; |
493 $scope.updateResults(); | 589 $scope.updateResults(); |
494 } | 590 } |
495 | 591 |
(...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 */ | 923 */ |
828 $scope.getImageDiffRelativeUrl = function(imagePair) { | 924 $scope.getImageDiffRelativeUrl = function(imagePair) { |
829 var before = | 925 var before = |
830 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + | 926 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] + "-vs-" + |
831 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; | 927 imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]; |
832 return before.replace(/[^\w\-]/g, "_") + ".png"; | 928 return before.replace(/[^\w\-]/g, "_") + ".png"; |
833 } | 929 } |
834 | 930 |
835 } | 931 } |
836 ); | 932 ); |
OLD | NEW |