Index: gm/rebaseline_server/static/live-view.html |
diff --git a/gm/rebaseline_server/static/live-view.html b/gm/rebaseline_server/static/live-view.html |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1662adf89cb9e1fb01657abdf3790f3c1a3a970c |
--- /dev/null |
+++ b/gm/rebaseline_server/static/live-view.html |
@@ -0,0 +1,446 @@ |
+<!DOCTYPE html> |
+ |
+<html ng-app="Loader" ng-controller="Loader.Controller"> |
+ |
+<head> |
+ <title ng-bind="windowTitle"></title> |
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> |
+ <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.20/angular.js"></script> |
+ <script src="constants.js"></script> |
+ <script src="live-loader.js"></script> |
+ <script src="utils.js"></script> |
+ |
+ <link rel="stylesheet" href="view.css"> |
+</head> |
+ |
+<body> |
+ <h2> |
+ Instructions, roadmap, etc. are at |
+ <a href="http://tinyurl.com/SkiaRebaselineServer"> |
+ http://tinyurl.com/SkiaRebaselineServer |
+ </a> |
+ </h2> |
+ |
+ <em ng-show="!readyToDisplay"> |
+ Loading results of query: |
+ <ul> |
+ <li>setA: "{{setASection}}" within {{setADir}}</li> |
+ <li>setB: "{{setBSection}}" within {{setBDir}}</li> |
+ </ul> |
+ <br> |
+ {{loadingMessage}} |
+ </em> |
+ |
+ <div ng-show="readyToDisplay"> |
+ |
+ <div class="warning-div" |
+ ng-show="urlSchemaVersionLoaded != constants.URL_VALUE__SCHEMA_VERSION__CURRENT"> |
+ WARNING! The URL you loaded used schema version {{urlSchemaVersionLoaded}}, rather than |
+ the most recent version {{constants.URL_VALUE__SCHEMA_VERSION__CURRENT}}. It has been |
+ converted to the most recent version on a best-effort basis; you may wish to double-check |
+ which records are displayed. |
+ </div> |
+ |
+ <div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]"> |
+ setA: "{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}" |
+ within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}} |
+ <span ng-show="header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span> |
+ <br> |
+ setB: "{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}" |
+ within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}} |
+ <span ng-show="header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]">at <a href="https://skia.googlesource.com/skia/+/{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}">rev {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__REPO_REVISION]}}</a></span> |
+ <br> |
+ <a href="{{liveQueryUrl}}">latest raw JSON diffs between these two sets</a><br> |
+ These results current as of |
+ {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}} |
+ </div> |
+ |
+ <div class="tab-wrapper"><!-- tabs --> |
+ <div class="tab-spacer" ng-repeat="tab in tabs"> |
+ <div class="tab tab-{{tab == viewingTab}}" |
+ ng-click="setViewingTab(tab)"> |
+ {{tab}} ({{numResultsPerTab[tab]}}) |
+ </div> |
+ <div class="tab-spacer"> |
+ |
+ </div> |
+ </div> |
+ </div><!-- tabs --> |
+ |
+ <div class="tab-main"><!-- main display area of selected tab --> |
+ |
+ <br> |
+ <!-- We only show the filters/settings table on the Unfiled tab. --> |
+ <table ng-show="viewingTab == defaultTab" border="1"> |
+ <tr> |
+ <th colspan="4"> |
+ Filters |
+ </th> |
+ <th> |
+ Settings |
+ </th> |
+ </tr> |
+ <tr valign="top"> |
+ |
+ <!-- filters --> |
+ <td ng-repeat="columnName in orderedColumnNames"> |
+ |
+ <!-- Only display filterable columns here... --> |
+ <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE]"> |
+ {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}<br> |
+ |
+ <!-- If we filter this column using free-form text match... --> |
+ <div ng-if="extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]"> |
+ <input type="text" |
+ ng-model="columnStringMatch[columnName]" |
+ ng-change="setUpdatesPending(true)"/> |
+ <br> |
+ <button ng-click="setColumnStringMatch(columnName, '')" |
+ ng-disabled="('' == columnStringMatch[columnName])"> |
+ clear (show all) |
+ </button> |
+ </div> |
+ |
+ <!-- If we filter this column using checkboxes... --> |
+ <div ng-if="!extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER]"> |
+ <label ng-repeat="valueAndCount in extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS]"> |
+ <input type="checkbox" |
+ name="resultTypes" |
+ value="{{valueAndCount[0]}}" |
+ ng-checked="isValueInSet(valueAndCount[0], showingColumnValues[columnName])" |
+ ng-click="toggleValueInSet(valueAndCount[0], showingColumnValues[columnName]); setUpdatesPending(true)"> |
+ {{valueAndCount[0]}} ({{valueAndCount[1]}})<br> |
+ </label> |
+ <button ng-click="showingColumnValues[columnName] = {}; toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()" |
+ ng-disabled="!readyToDisplay || allColumnValues[columnName].length == setSize(showingColumnValues[columnName])"> |
+ all |
+ </button> |
+ <button ng-click="showingColumnValues[columnName] = {}; updateResults()" |
+ ng-disabled="!readyToDisplay || 0 == setSize(showingColumnValues[columnName])"> |
+ none |
+ </button> |
+ <button ng-click="toggleValuesInSet(allColumnValues[columnName], showingColumnValues[columnName]); updateResults()"> |
+ toggle |
+ </button> |
+ </div> |
+ |
+ </div> |
+ </td> |
+ |
+ <!-- settings --> |
+ <td><table> |
+ <tr><td> |
+ <input type="checkbox" ng-model="showThumbnailsPending" |
+ ng-init="showThumbnailsPending = true" |
+ ng-change="areUpdatesPending = true"/> |
+ Show thumbnails |
+ </td></tr> |
+ <tr><td> |
+ <input type="checkbox" ng-model="mergeIdenticalRowsPending" |
+ ng-init="mergeIdenticalRowsPending = true" |
+ ng-change="areUpdatesPending = true"/> |
+ Merge identical rows |
+ </td></tr> |
+ <tr><td> |
+ Image width |
+ <input type="text" ng-model="imageSizePending" |
+ ng-init="imageSizePending=100" |
+ ng-change="areUpdatesPending = true" |
+ maxlength="4"/> |
+ </td></tr> |
+ <tr><td> |
+ Max records to display |
+ <input type="text" ng-model="displayLimitPending" |
+ ng-init="displayLimitPending=50" |
+ ng-change="areUpdatesPending = true" |
+ maxlength="4"/> |
+ </td></tr> |
+ <tr><td> |
+ <button class="update-results-button" |
+ ng-click="updateResults()" |
+ ng-disabled="!areUpdatesPending"> |
+ Update Results |
+ </button> |
+ </td></tr> |
+ </tr></table></td> |
+ </tr> |
+ </table> |
+ |
+ <p> |
+ |
+ <!-- Submission UI that we only show in the Pending Approval tab. --> |
+ <div ng-show="'Pending Approval' == viewingTab"> |
+ <div style="display:inline-block"> |
+ <button style="font-size:20px" |
+ ng-click="submitApprovals(filteredImagePairs)" |
+ ng-disabled="submitPending || (filteredImagePairs.length == 0)"> |
+ Get a patchfile to update these {{filteredImagePairs.length}} expectations |
+ </button> |
+ </div> |
+ <div style="display:inline-block"> |
+ <div style="font-size:20px" |
+ ng-show="submitPending"> |
+ Submitting, please wait... |
+ </div> |
+ </div> |
+ <div> |
+ Advanced settings... |
+ <input type="checkbox" ng-model="showSubmitAdvancedSettings"> |
+ show |
+ <ul ng-show="showSubmitAdvancedSettings"> |
+ <li ng-repeat="setting in [constants.KEY__EXPECTATIONS__REVIEWED, constants.KEY__EXPECTATIONS__IGNOREFAILURE]"> |
+ {{setting}} |
+ <input type="checkbox" ng-model="submitAdvancedSettings[setting]"> |
+ </li> |
+ <li ng-repeat="setting in ['bug']"> |
+ {{setting}} |
+ <input type="text" ng-model="submitAdvancedSettings[setting]"> |
+ </li> |
+ </ul> |
+ </div> |
+ <div ng-show="diffResults"> |
+ <p> |
+ Here is the patch to apply to your local checkout: |
+ <br> |
+ <textarea rows="8" cols="50">{{diffResults}}</textarea> |
+ <br> |
+ <a download="patch.txt" ng-href="{{diffResultsBlobUrl}}"> |
+ Click here to download that patch as a text file. |
+ </a> |
+ </div> |
+ </div> |
+ |
+ <p> |
+ |
+ <table border="0"><tr><td> <!-- table holding results header + results table --> |
+ <table border="0" width="100%"> <!-- results header --> |
+ <tr> |
+ <td> |
+ Found {{filteredImagePairs.length}} matches; |
+ <span ng-show="filteredImagePairs.length > limitedImagePairs.length"> |
+ displaying the first {{limitedImagePairs.length}}. |
+ </span> |
+ <span ng-show="filteredImagePairs.length <= limitedImagePairs.length"> |
+ displaying them all. |
+ </span> |
+ <span ng-show="renderEndTime > renderStartTime"> |
+ Rendered in {{(renderEndTime - renderStartTime).toFixed(0)}} ms. |
+ </span> |
+ <br> |
+ (click on the column header radio buttons to re-sort by that column) |
+ </td> |
+ <td align="right"> |
+ <div> |
+ all tests shown: |
+ <button ng-click="selectAllImagePairs()"> |
+ select |
+ </button> |
+ <button ng-click="clearAllImagePairs()"> |
+ clear |
+ </button> |
+ <button ng-click="toggleAllImagePairs()"> |
+ toggle |
+ </button> |
+ </div> |
+ <div ng-repeat="otherTab in tabs"> |
+ <button ng-click="moveSelectedImagePairsToTab(otherTab)" |
+ ng-disabled="selectedImagePairs.length == 0" |
+ ng-show="otherTab != viewingTab"> |
+ move {{selectedImagePairs.length}} selected tests to {{otherTab}} tab |
+ </button> |
+ </div> |
+ </td> |
+ </tr> |
+ </table> <!-- results header --> |
+ </td></tr><tr><td> |
+ <table border="1" ng-app="diff_viewer"> <!-- results --> |
+ <tr> |
+ <!-- Most column headers are displayed in a common fashion... --> |
+ <th ng-repeat="columnName in orderedColumnNames"> |
+ <a ng-class="'sort-' + sortedByColumnsCls(columnName)" |
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXTRACOLUMNS, columnName)" |
+ href="" |
+ class="sortable-header"> |
+ {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}} |
+ </a> |
+ </th> |
+ <!-- ... but there are a few columns where we display things differently. --> |
+ <th> |
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__EXPECTATIONS__BUGS)" |
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__EXPECTATIONS, constants.KEY__EXPECTATIONS__BUGS)" |
+ href="" |
+ class="sortable-header"> |
+ bugs |
+ </a> |
+ </th> |
+ <th width="{{imageSize}}"> |
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_A_URL)" |
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_A_URL)" |
+ href="" |
+ title="setA: '{{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_A_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}" |
+ class="sortable-header"> |
+ <span ng-show="'Pending Approval' != viewingTab"> |
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}} |
+ </span> |
+ <span ng-show="'Pending Approval' == viewingTab"> |
+ old expectations |
+ </span> |
+ </a> |
+ </th> |
+ <th width="{{imageSize}}"> |
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__IMAGEPAIRS__IMAGE_B_URL)" |
+ ng-click="sortResultsBy('none', constants.KEY__IMAGEPAIRS__IMAGE_B_URL)" |
+ href="" |
+ title="setB: '{{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__SECTION]}}' within {{header[constants.KEY__HEADER__SET_B_DESCRIPTIONS][constants.KEY__SET_DESCRIPTIONS__DIR]}}" |
+ class="sortable-header"> |
+ <span ng-show="'Pending Approval' != viewingTab"> |
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}} |
+ </span> |
+ <span ng-show="'Pending Approval' == viewingTab"> |
+ new expectations |
+ </span> |
+ </a> |
+ </th> |
+ <th width="{{imageSize}}"> |
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)" |
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS)" |
+ href="" |
+ class="sortable-header"> |
+ differing pixels in white |
+ </a> |
+ </th> |
+ <th width="{{imageSize}}"> |
+ <a ng-class="'sort-' + sortedByColumnsCls(constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)" |
+ ng-click="sortResultsBy(constants.KEY__IMAGEPAIRS__DIFFERENCES, constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF)" |
+ href="" |
+ class="sortable-header"> |
+ perceptual difference |
+ </a> |
+ <br> |
+ <input type="range" ng-model="pixelDiffBgColorBrightness" |
+ ng-init="pixelDiffBgColorBrightness=64; pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)" |
+ ng-change="pixelDiffBgColor=brightnessStringToHexColor(pixelDiffBgColorBrightness)" |
+ title="image background brightness" |
+ min="0" max="255"/> |
+ </th> |
+ <th> |
+ <!-- imagepair-selection checkbox column --> |
+ </th> |
+ </tr> |
+ |
+ <tr ng-repeat="imagePair in limitedImagePairs" valign="top" |
+ ng-class-odd="'results-odd'" ng-class-even="'results-even'" |
+ results-updated-callback-directive> |
+ |
+ <td ng-repeat="columnName in orderedColumnNames"> |
+ {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}} |
+ <br> |
+ <button class="show-only-button" |
+ ng-show="viewingTab == defaultTab" |
+ ng-disabled="1 == setSize(showingColumnValues[columnName])" |
+ ng-click="showOnlyColumnValue(columnName, imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName])" |
+ title="show only results of {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}} {{imagePair[constants.KEY__IMAGEPAIRS__EXTRACOLUMNS][columnName]}}"> |
+ show only |
+ </button> |
+ <br> |
+ <button class="show-all-button" |
+ ng-show="viewingTab == defaultTab" |
+ ng-disabled="allColumnValues[columnName].length == setSize(showingColumnValues[columnName])" |
+ ng-click="showAllColumnValues(columnName)" |
+ title="show results of all {{extraColumnHeaders[columnName][constants.KEY__EXTRACOLUMNHEADERS__HEADER_TEXT]}}s"> |
+ show all |
+ </button> |
+ </td> |
+ |
+ <!-- bugs --> |
+ <td> |
+ <a ng-repeat="bug in imagePair[constants.KEY__IMAGEPAIRS__EXPECTATIONS][constants.KEY__EXPECTATIONS__BUGS]" |
+ href="https://code.google.com/p/skia/issues/detail?id={{bug}}" |
+ target="_blank"> |
+ {{bug}} |
+ </a> |
+ </td> |
+ |
+ <!-- image A --> |
+ <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}"> |
+ <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] != null"> |
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" target="_blank">View Image</a><br/> |
+ <img ng-if="showThumbnails" |
+ width="{{imageSize}}" |
+ ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL]}}" /> |
+ </div> |
+ <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_A_URL] == null" |
+ style="text-align:center"> |
+ –none– |
+ </div> |
+ </td> |
+ |
+ <!-- image B --> |
+ <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}"> |
+ <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] != null"> |
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" target="_blank">View Image</a><br/> |
+ <img ng-if="showThumbnails" |
+ width="{{imageSize}}" |
+ ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL]}}" /> |
+ </div> |
+ <div ng-show="imagePair[constants.KEY__IMAGEPAIRS__IMAGE_B_URL] == null" |
+ style="text-align:center"> |
+ –none– |
+ </div> |
+ </td> |
+ |
+ <!-- whitediffs: every differing pixel shown in white --> |
+ <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}"> |
+ <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]" |
+ title="{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] | number:0}} of {{(100 * imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS] / imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS]) | number:0}} pixels ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}%) differ from expectation."> |
+ |
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" target="_blank">View Image</a><br/> |
+ <img ng-if="showThumbnails" |
+ width="{{imageSize}}" |
+ ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__WHITE_DIFF_URL]}}" /> |
+ <br/> |
+ {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCENT_DIFF_PIXELS].toFixed(4)}}% |
+ ({{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__NUM_DIFF_PIXELS]}}) |
+ </div> |
+ <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]" |
+ style="text-align:center"> |
+ –none– |
+ </div> |
+ </td> |
+ |
+ <!-- diffs: per-channel RGB deltas --> |
+ <td width="{{imageSize}}" ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}"> |
+ <div ng-if="imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]" |
+ title="Perceptual difference measure is {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}%. Maximum difference per channel: R={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][0]}}, G={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][1]}}, B={{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL][2]}}"> |
+ |
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" target="_blank">View Image</a><br/> |
+ <img ng-if="showThumbnails" |
+ ng-style="{backgroundColor: pixelDiffBgColor}" |
+ width="{{imageSize}}" |
+ ng-src="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__DIFF_URL]}}" /> |
+ <br/> |
+ {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__PERCEPTUAL_DIFF].toFixed(4)}}% |
+ {{imagePair[constants.KEY__IMAGEPAIRS__DIFFERENCES][constants.KEY__DIFFERENCES__MAX_DIFF_PER_CHANNEL]}} |
+ </div> |
+ <div ng-show="!imagePair[constants.KEY__IMAGEPAIRS__IS_DIFFERENT]" |
+ style="text-align:center"> |
+ –none– |
+ </div> |
+ </td> |
+ |
+ <td ng-if="imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN] > 0" rowspan="{{imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN]}}"> |
+ <br/> |
+ <input type="checkbox" |
+ name="rowSelect" |
+ value="{{imagePair.index}}" |
+ ng-checked="isValueInArray(imagePair.index, selectedImagePairs)" |
+ ng-click="toggleSomeImagePairs($index, imagePair[constants.KEY__IMAGEPAIRS__ROWSPAN])"> |
+ </tr> |
+ </table> <!-- imagePairs --> |
+ </td></tr></table> <!-- table holding results header + imagePairs table --> |
+ |
+ </div><!-- main display area of selected tab --> |
+ </div><!-- everything: hide until readyToDisplay --> |
+ |
+</body> |
+</html> |