| OLD | NEW |
| 1 <!DOCTYPE html> | 1 <!DOCTYPE html> |
| 2 <!-- | 2 <!-- |
| 3 Copyright 2016 The Chromium Authors. All rights reserved. | 3 Copyright 2016 The Chromium Authors. All rights reserved. |
| 4 Use of this source code is governed by a BSD-style license that can be | 4 Use of this source code is governed by a BSD-style license that can be |
| 5 found in the LICENSE file. | 5 found in the LICENSE file. |
| 6 --> | 6 --> |
| 7 | 7 |
| 8 <link rel="import" href="/tracing/value/ui/histogram_set_table_cell.html"> | 8 <link rel="import" href="/tracing/value/ui/histogram_set_table_cell.html"> |
| 9 <link rel="import" href="/tracing/value/ui/histogram_set_table_name_cell.html"> | 9 <link rel="import" href="/tracing/value/ui/histogram_set_table_name_cell.html"> |
| 10 | 10 |
| 11 <script> | 11 <script> |
| 12 'use strict'; | 12 'use strict'; |
| 13 tr.exportTo('tr.v.ui', function() { | 13 tr.exportTo('tr.v.ui', function() { |
| 14 class HistogramSetTableRow { | 14 class HistogramSetTableRow { |
| 15 constructor(name) { | 15 /** |
| 16 this.name = name; | 16 * @param {!tr.v.HistogramSetHierarchy} hierarchy |
| 17 this.description = ''; | 17 * @param {!Element} baseTable tr-ui-b-table |
| 18 this.depth = 0; | 18 * @param {!tr.v.ui.HistogramSetViewState} rootViewState |
| 19 this.subRows = []; | 19 */ |
| 20 this.columns = new Map(); | 20 constructor(hierarchy, baseTable, rootViewState) { |
| 21 this.hierarchy_ = hierarchy; |
| 22 this.baseTable_ = baseTable; |
| 23 this.rootViewState_ = rootViewState; |
| 24 this.viewState_ = new tr.v.ui.HistogramSetTableRowState(); |
| 25 this.viewState_.addUpdateListener(this.onViewStateUpdate_.bind(this)); |
| 26 |
| 21 this.nameCell_ = undefined; | 27 this.nameCell_ = undefined; |
| 22 this.cells = new Map(); | 28 this.cells_ = new Map(); |
| 23 this.constrainNameColumnWidth_ = false; | 29 this.subRows_ = []; |
| 24 this.overviewDataRange_ = undefined; | 30 for (const subHierarchy of hierarchy.subRows) { |
| 25 this.displayStatistic_ = 'avg'; | 31 const subRow = new HistogramSetTableRow( |
| 26 this.doMergeRelationshipsForColumn_ = new Map(); | 32 subHierarchy, baseTable, rootViewState); |
| 33 this.subRows_.push(subRow); |
| 34 this.viewState.subRows.set(subRow.name, subRow.viewState); |
| 35 } |
| 36 // Don't assign this.viewState.subRows. There can't be anything listening |
| 37 // to it, so avoid the overhead of dispatching an event. |
| 27 } | 38 } |
| 28 | 39 |
| 29 /** | 40 /** |
| 30 * Clones and filters |rows| to contain only |histograms|. | 41 * @return {string} |
| 31 * | |
| 32 * @param {!Array.<HistogramSetTableRow>} rows | |
| 33 * @param {!tr.v.HistogramSet} histograms | |
| 34 * @returns {!Array.<HistogramSetTableRow>} | |
| 35 */ | 42 */ |
| 36 static filter(rows, histograms) { | 43 get name() { |
| 37 let results = []; | 44 return this.hierarchy_.name; |
| 38 for (let row of rows) { | |
| 39 let filteredSubRows = []; | |
| 40 if (row.subRows.length > 0) { | |
| 41 // This is a branch row. Drop it if all of its subrows were dropped. | |
| 42 filteredSubRows = HistogramSetTableRow.filter( | |
| 43 row.subRows, histograms); | |
| 44 if (filteredSubRows.length === 0) continue; | |
| 45 } else { | |
| 46 // This is a leaf row. Drop it if none of the Histograms in | |
| 47 // |row.columns| were merged from any in |histograms|. | |
| 48 let found = false; | |
| 49 for (let testHist of row.columns.values()) { | |
| 50 if (!(testHist instanceof tr.v.Histogram)) continue; | |
| 51 if (histograms.lookupHistogram(testHist.guid) !== undefined) { | |
| 52 found = true; | |
| 53 break; | |
| 54 } | |
| 55 let mergedFrom = testHist.diagnostics.get( | |
| 56 tr.v.d.MERGED_FROM_DIAGNOSTIC_KEY); | |
| 57 if (mergedFrom !== undefined) { | |
| 58 for (let origHist of mergedFrom) { | |
| 59 if (histograms.lookupHistogram(origHist.guid) !== undefined) { | |
| 60 found = true; | |
| 61 break; | |
| 62 } | |
| 63 } | |
| 64 } | |
| 65 if (found) break; | |
| 66 } | |
| 67 // If none of the Histograms in |row| were merged from any of | |
| 68 // |histograms|, then drop this row. | |
| 69 if (!found) continue; | |
| 70 } | |
| 71 | |
| 72 let clone = new HistogramSetTableRow(row.name); | |
| 73 clone.description = row.description; | |
| 74 clone.depth = row.depth; | |
| 75 clone.subRows = filteredSubRows; | |
| 76 // Don't need to clone Histograms. | |
| 77 clone.columns = row.columns; | |
| 78 // Don't need to rebuild nameCell or cells. | |
| 79 clone.nameCell_ = row.nameCell_; | |
| 80 clone.cells = row.cells; | |
| 81 clone.constrainNameColumnWidth_ = row.constrainNameColumnWidth_; | |
| 82 clone.overviewDataRange_ = row.overviewDataRange_; | |
| 83 clone.displayStatistic_ = row.displayStatistic_; | |
| 84 results.push(clone); | |
| 85 } | |
| 86 return results; | |
| 87 } | 45 } |
| 88 | 46 |
| 89 /** | 47 /** |
| 90 * Build table rows recursively from grouped Histograms. | 48 * @return {number} |
| 91 * | |
| 92 * @param {!(HistogramArray|HistogramArrayMap)} | |
| 93 * @returns {!Array.<!HistogramSetTableRow>} | |
| 94 */ | 49 */ |
| 95 static build(histogramArrayMap) { | 50 get depth() { |
| 96 const rootRows = []; | 51 return this.hierarchy_.depth; |
| 97 HistogramSetTableRow.buildInternal_(histogramArrayMap, [], rootRows); | 52 } |
| 98 | 53 |
| 99 const histograms = new tr.v.HistogramSet(); | 54 /** |
| 55 * @return {string} |
| 56 */ |
| 57 get description() { |
| 58 return this.hierarchy_.description; |
| 59 } |
| 100 | 60 |
| 101 for (const row of HistogramSetTableRow.walkAll(rootRows)) { | 61 /** |
| 102 for (const hist of row.columns.values()) { | 62 * @return {!Map.<string, !(undefined|tr.v.Histogram|tr.v.HistogramSet)>} |
| 103 if (!(hist instanceof tr.v.Histogram)) continue; | 63 */ |
| 104 histograms.addHistogram(hist); | 64 get columns() { |
| 105 } | 65 return this.hierarchy_.columns; |
| 106 } | 66 } |
| 107 | 67 |
| 108 histograms.deduplicateDiagnostics(); | 68 /** |
| 69 * @return {!tr.b.Range} |
| 70 */ |
| 71 get overviewDataRange() { |
| 72 return this.hierarchy_.overviewDataRange; |
| 73 } |
| 109 | 74 |
| 110 for (const row of HistogramSetTableRow.walkAll(rootRows)) { | 75 /** |
| 111 for (const [name, hist] of row.columns) { | 76 * @return {!tr.v.ui.HistogramSetViewState} |
| 112 if (!(hist instanceof tr.v.Histogram)) continue; | 77 */ |
| 113 if (!row.doMergeRelationshipsForColumn_.get(name)) continue; | 78 get rootViewState() { |
| 114 hist.diagnostics.mergeRelationships(hist); | 79 return this.rootViewState_; |
| 115 } | 80 } |
| 116 } | |
| 117 | 81 |
| 118 // Delete "merged to" diagnostics from the original Histograms, or else | 82 /** |
| 119 // they'll accumulate as the user re-groups them, and slow down future | 83 * @return {!Map.<string, !Element>} tr-v-ui-histogram-set-table-cell |
| 120 // mergeRelationships operations. | 84 */ |
| 121 for (const row of HistogramSetTableRow.walkAll(rootRows)) { | 85 get cells() { |
| 122 // Walk directly down to the leaves in order to avoid touching | 86 return this.cells_; |
| 123 // original Histograms more than once. | 87 } |
| 124 if (row.subRows.length) continue; | |
| 125 | 88 |
| 126 for (const hist of row.columns.values()) { | 89 /** |
| 127 if (!(hist instanceof tr.v.Histogram)) continue; | 90 * @return {!Array.<tr.v.ui.HistogramSetTableRow>} |
| 91 */ |
| 92 get subRows() { |
| 93 return this.subRows_; |
| 94 } |
| 128 | 95 |
| 129 const mergedFrom = hist.diagnostics.get( | 96 /** |
| 130 tr.v.MERGED_FROM_DIAGNOSTIC_KEY); | 97 * @return {!Array.<tr.v.ui.HistogramSetTableRowState>} |
| 131 if (mergedFrom !== undefined) { | 98 */ |
| 132 for (const other of mergedFrom) { | 99 get viewState() { |
| 133 other.diagnostics.delete(tr.v.MERGED_TO_DIAGNOSTIC_KEY); | 100 return this.viewState_; |
| 134 } | |
| 135 } | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 for (const row of HistogramSetTableRow.walkAll(rootRows)) { | |
| 140 row.maybeRebin_(); | |
| 141 } | |
| 142 | |
| 143 return rootRows; | |
| 144 } | 101 } |
| 145 | 102 |
| 146 * walk() { | 103 * walk() { |
| 147 yield this; | 104 yield this; |
| 148 for (const row of this.subRows) yield* row.walk(); | 105 for (const row of this.subRows) yield* row.walk(); |
| 149 } | 106 } |
| 150 | 107 |
| 151 static* walkAll(rootRows) { | 108 static* walkAll(rootRows) { |
| 152 for (const rootRow of rootRows) yield* rootRow.walk(); | 109 for (const rootRow of rootRows) yield* rootRow.walk(); |
| 153 } | 110 } |
| 154 | 111 |
| 155 maybeRebin_() { | |
| 156 // if all of |this| row's columns are single-bin, then re-bin all of them. | |
| 157 const dataRange = new tr.b.math.Range(); | |
| 158 for (const hist of this.columns.values()) { | |
| 159 if (!(hist instanceof tr.v.Histogram)) continue; | |
| 160 if (hist.allBins.length > 1) return; // don't re-bin | |
| 161 if (hist.numValues === 0) continue; // ignore hist | |
| 162 dataRange.addValue(hist.min); | |
| 163 dataRange.addValue(hist.max); | |
| 164 } | |
| 165 | |
| 166 dataRange.addValue(tr.b.math.lesserWholeNumber(dataRange.min)); | |
| 167 dataRange.addValue(tr.b.math.greaterWholeNumber(dataRange.max)); | |
| 168 | |
| 169 if (dataRange.min === dataRange.max) return; // don't rebin | |
| 170 | |
| 171 const boundaries = tr.v.HistogramBinBoundaries.createLinear( | |
| 172 dataRange.min, dataRange.max, tr.v.DEFAULT_REBINNED_COUNT); | |
| 173 | |
| 174 for (const [name, hist] of this.columns) { | |
| 175 if (!(hist instanceof tr.v.Histogram)) continue; | |
| 176 this.columns.set(name, hist.rebin(boundaries)); | |
| 177 } | |
| 178 } | |
| 179 | |
| 180 static mergeHistogramDownHierarchy_(histogram, hierarchy, columnName) { | |
| 181 // Track the path down the grouping tree to each Histogram, | |
| 182 // but only start tracking the path at the grouping level that | |
| 183 // corresponds to the Histogram NAME Grouping. This groupingPath will be | |
| 184 // attached to Histograms in order to help mergeRelationships() figure out | |
| 185 // which merged Histograms should be related to which other merged | |
| 186 // Histograms. | |
| 187 let groupingPath = undefined; | |
| 188 | |
| 189 for (let row of hierarchy) { | |
| 190 if (groupingPath !== undefined) { | |
| 191 groupingPath.push(row.name); | |
| 192 } else if (row.name === histogram.name) { | |
| 193 // Start tracking the path, but don't add histogram.name to the path, | |
| 194 // since related histograms won't have the same name. | |
| 195 groupingPath = []; | |
| 196 } | |
| 197 | |
| 198 if (!row.description) { | |
| 199 row.description = histogram.description; | |
| 200 } | |
| 201 | |
| 202 if (row.columns.get(columnName) === undefined) { | |
| 203 let clone = histogram.clone(); | |
| 204 if (groupingPath !== undefined) { | |
| 205 new tr.v.d.GroupingPath(groupingPath).addToHistogram(clone); | |
| 206 } | |
| 207 row.columns.set(columnName, clone); | |
| 208 row.doMergeRelationshipsForColumn_.set(columnName, true); | |
| 209 continue; | |
| 210 } | |
| 211 | |
| 212 if (!(row.columns.get(columnName) instanceof tr.v.Histogram)) continue; | |
| 213 | |
| 214 if (!row.columns.get(columnName).canAddHistogram(histogram)) { | |
| 215 row.columns.set(columnName, tr.v.ui.UNMERGEABLE); | |
| 216 continue; | |
| 217 } | |
| 218 | |
| 219 let merged = row.columns.get(columnName); | |
| 220 | |
| 221 // If row.columns.get(columnName).name != histogram.name, then it won't | |
| 222 // make sense to merge relationships for this histogram. | |
| 223 if (merged.name !== histogram.name) { | |
| 224 row.doMergeRelationshipsForColumn_.set(name, false); | |
| 225 } | |
| 226 | |
| 227 merged.addHistogram(histogram); | |
| 228 } | |
| 229 } | |
| 230 | |
| 231 static buildInternal_(histogramArrayMap, hierarchy, rootRows) { | |
| 232 for (let [name, histograms] of histogramArrayMap) { | |
| 233 if (histograms instanceof Array) { | |
| 234 // This recursion base case corresponds to the recursion base case of | |
| 235 // groupHistogramsRecursively(). The last groupingCallback is always | |
| 236 // getDisplayLabel, which defines the columns of the table and is | |
| 237 // unskippable. | |
| 238 for (let histogram of histograms) { | |
| 239 HistogramSetTableRow.mergeHistogramDownHierarchy_( | |
| 240 histogram, hierarchy, name); | |
| 241 } | |
| 242 } else if (histograms instanceof Map) { | |
| 243 // |histograms| is actually a nested histogramArrayMap. | |
| 244 let row = new HistogramSetTableRow(name); | |
| 245 row.depth = hierarchy.length; | |
| 246 hierarchy.push(row); | |
| 247 HistogramSetTableRow.buildInternal_(histograms, hierarchy, rootRows); | |
| 248 hierarchy.pop(); | |
| 249 | |
| 250 if (hierarchy.length === 0) { | |
| 251 rootRows.push(row); | |
| 252 } else { | |
| 253 hierarchy[hierarchy.length - 1].subRows.push(row); | |
| 254 } | |
| 255 } | |
| 256 } | |
| 257 } | |
| 258 | |
| 259 get nameCell() { | 112 get nameCell() { |
| 260 if (this.nameCell_ === undefined) { | 113 if (this.nameCell_ === undefined) { |
| 261 this.nameCell_ = document.createElement( | 114 this.nameCell_ = document.createElement( |
| 262 'tr-v-ui-histogram-set-table-name-cell'); | 115 'tr-v-ui-histogram-set-table-name-cell'); |
| 263 this.nameCell_.row = this; | 116 this.nameCell_.build(this); |
| 264 this.nameCell_.constrainWidth = this.constrainNameColumnWidth_; | |
| 265 } | 117 } |
| 266 return this.nameCell_; | 118 return this.nameCell_; |
| 267 } | 119 } |
| 268 | 120 |
| 269 set constrainNameColumnWidth(constrain) { | 121 getCell(displayLabel) { |
| 270 for (const row of this.walk()) { | 122 // Build all of the cells at once so that we only need to set |
| 271 row.constrainNameColumnWidth_ = constrain; | 123 // this.viewState.cells once, which dispatches an event to the nameCell. |
| 272 if (row.nameCell_ !== undefined) { | 124 if (!this.cells.has(displayLabel)) this.buildCells(); |
| 273 row.nameCell_.constrainWidth = constrain; | 125 return this.cells.get(displayLabel); |
| 274 } | |
| 275 } | |
| 276 } | 126 } |
| 277 | 127 |
| 278 get isNameCellOverflowing() { | 128 buildCells() { |
| 279 for (const row of this.walk()) { | 129 const cellStates = new Map(); |
| 280 if (row.nameCell.isOverflowing) return true; | 130 for (const displayLabel of this.columns.keys()) { |
| 131 const cell = document.createElement('tr-v-ui-histogram-set-table-cell'); |
| 132 cell.build(this, displayLabel); |
| 133 this.cells.set(displayLabel, cell); |
| 134 |
| 135 const previousState = this.viewState.cells.get(displayLabel); |
| 136 if (previousState !== undefined) { |
| 137 cell.viewState.updateFromViewState(previousState); |
| 138 } |
| 139 cellStates.set(displayLabel, cell.viewState); |
| 281 } | 140 } |
| 282 return false; | 141 this.viewState.cells = cellStates; |
| 283 } | |
| 284 | |
| 285 get displayStatistic() { | |
| 286 return this.displayStatistic_; | |
| 287 } | |
| 288 | |
| 289 set displayStatistic(statName) { | |
| 290 for (const row of this.walk()) { | |
| 291 row.displayStatistic_ = statName; | |
| 292 for (let [displayLabel, cell] of row.cells) { | |
| 293 cell.displayStatistic = statName; | |
| 294 } | |
| 295 } | |
| 296 } | |
| 297 | |
| 298 buildCell(displayLabel, referenceDisplayLabel) { | |
| 299 let cell = document.createElement('tr-v-ui-histogram-set-table-cell'); | |
| 300 cell.row = this; | |
| 301 cell.histogram = this.columns.get(displayLabel); | |
| 302 cell.displayStatistic = this.displayStatistic; | |
| 303 if (referenceDisplayLabel && | |
| 304 referenceDisplayLabel !== displayLabel) { | |
| 305 cell.referenceHistogram = this.columns.get( | |
| 306 referenceDisplayLabel); | |
| 307 } | |
| 308 this.cells.set(displayLabel, cell); | |
| 309 return cell; | |
| 310 } | |
| 311 | |
| 312 get overviewDataRange() { | |
| 313 if (this.overviewDataRange_ === undefined) { | |
| 314 this.overviewDataRange_ = new tr.b.math.Range(); | |
| 315 for (let [displayLabel, hist] of this.columns) { | |
| 316 if (hist.average !== undefined) { | |
| 317 this.overviewDataRange_.addValue(hist.average); | |
| 318 } | |
| 319 | |
| 320 for (let subRow of this.subRows) { | |
| 321 let subHist = subRow.columns.get(displayLabel); | |
| 322 if (!(subHist instanceof tr.v.Histogram)) continue; | |
| 323 if (subHist.average === undefined) continue; | |
| 324 this.overviewDataRange_.addValue(subHist.average); | |
| 325 } | |
| 326 } | |
| 327 } | |
| 328 return this.overviewDataRange_; | |
| 329 } | |
| 330 | |
| 331 getLeafHistograms(histograms) { | |
| 332 for (const row of this.walk()) { | |
| 333 if (row.subRows.length) return; | |
| 334 | |
| 335 for (const hist of this.columns.values()) { | |
| 336 histograms.addHistogram(hist); | |
| 337 } | |
| 338 } | |
| 339 } | 142 } |
| 340 | 143 |
| 341 compareNames(other) { | 144 compareNames(other) { |
| 342 return this.name.localeCompare(other.name); | 145 return this.name.localeCompare(other.name); |
| 343 } | 146 } |
| 344 | 147 |
| 345 compareCells(other, displayLabel, referenceDisplayLabel) { | 148 compareCells(other, displayLabel, referenceDisplayLabel) { |
| 346 let cellA = this.columns.get(displayLabel); | 149 const cellA = this.columns.get(displayLabel); |
| 347 let cellB = other.columns.get(displayLabel); | 150 const cellB = other.columns.get(displayLabel); |
| 348 if (!(cellA instanceof tr.v.Histogram) || | 151 if (!(cellA instanceof tr.v.Histogram) || |
| 349 !(cellB instanceof tr.v.Histogram)) { | 152 !(cellB instanceof tr.v.Histogram)) { |
| 350 return undefined; | 153 return undefined; |
| 351 } | 154 } |
| 352 | 155 |
| 353 let referenceCellA; | 156 let referenceCellA; |
| 354 let referenceCellB; | 157 let referenceCellB; |
| 355 | 158 |
| 356 // If a reference column is selected, compare the absolute deltas | 159 // If a reference column is selected, compare the absolute deltas |
| 357 // between the two cells and their references. | 160 // between the two cells and their references. |
| 358 if (referenceDisplayLabel && | 161 if (referenceDisplayLabel && |
| 359 referenceDisplayLabel !== displayLabel) { | 162 referenceDisplayLabel !== displayLabel) { |
| 360 referenceCellA = this.columns.get(referenceDisplayLabel); | 163 referenceCellA = this.columns.get(referenceDisplayLabel); |
| 361 referenceCellB = other.columns.get(referenceDisplayLabel); | 164 referenceCellB = other.columns.get(referenceDisplayLabel); |
| 362 } | 165 } |
| 363 | 166 |
| 364 const statisticA = cellA.getAvailableStatisticName( | 167 const statisticA = cellA.getAvailableStatisticName( |
| 365 this.displayStatistic, referenceCellA); | 168 this.rootViewState.displayStatisticName, referenceCellA); |
| 366 const statisticB = cellB.getAvailableStatisticName( | 169 const statisticB = cellB.getAvailableStatisticName( |
| 367 this.displayStatistic, referenceCellB); | 170 this.rootViewState.displayStatisticName, referenceCellB); |
| 368 const valueA = cellA.getStatisticScalar(statisticA, referenceCellA).value; | 171 const valueA = cellA.getStatisticScalar(statisticA, referenceCellA).value; |
| 369 const valueB = cellB.getStatisticScalar(statisticB, referenceCellB).value; | 172 const valueB = cellB.getStatisticScalar(statisticB, referenceCellB).value; |
| 370 | 173 |
| 371 return valueA - valueB; | 174 return valueA - valueB; |
| 372 } | 175 } |
| 373 | 176 |
| 374 getExpansionStates(table) { | 177 onViewStateUpdate_(event) { |
| 375 let states = { | 178 if (event.delta.isExpanded) { |
| 376 expanded: table.getExpandedForTableRow(this), | 179 this.baseTable_.setExpandedForTableRow(this, this.viewState.isExpanded); |
| 377 cells: new Map(), | |
| 378 subRows: new Map(), | |
| 379 }; | |
| 380 | |
| 381 for (let [displayLabel, cell] of this.cells) { | |
| 382 if (cell.isHistogramOpen) { | |
| 383 states.cells.set(displayLabel, true); | |
| 384 } | |
| 385 } | 180 } |
| 386 | 181 |
| 387 if (states.expanded) { | 182 if (event.delta.subRows) { |
| 388 for (let i = 0; i < this.subRows.length; ++i) { | 183 throw new Error('HistogramSetTableRow.subRows must not be reassigned.'); |
| 389 states.subRows.set(i, this.subRows[i].getExpansionStates(table)); | |
| 390 } | |
| 391 } | 184 } |
| 392 return states; | |
| 393 } | |
| 394 | 185 |
| 395 setExpansionStates(states, table) { | 186 if (event.delta.cells) { |
| 396 if (states.expanded) { | 187 // Only validate the cells that have already been built. |
| 397 if (this.subRows.length) { | 188 // Cells may not have been built yet, so only validate the cells that |
| 398 table.setExpandedForTableRow(this, true); | 189 // have been built. |
| 399 for (let [index, subStates] of states.subRows) { | 190 for (const [displayLabel, cell] of this.cells) { |
| 400 this.subRows[index].setExpansionStates(subStates, table); | 191 if (cell.viewState !== this.viewState.cells.get(displayLabel)) { |
| 192 throw new Error('Only HistogramSetTableRow may update cells'); |
| 401 } | 193 } |
| 402 } | 194 } |
| 403 } | 195 } |
| 196 } |
| 404 | 197 |
| 405 for (let [displayLabel, isHistogramOpen] of states.cells) { | 198 async restoreState(vs) { |
| 406 let cell = this.cells.get(displayLabel); | 199 // Don't use updateFromViewState() because it would overwrite cells and |
| 407 if (cell) { | 200 // subRows, but we just want to restore them. |
| 408 cell.isHistogramOpen = isHistogramOpen; | 201 await this.viewState.update({ |
| 409 } | 202 isExpanded: vs.isExpanded, |
| 203 isOverviewed: vs.isOverviewed, |
| 204 }); |
| 205 |
| 206 // If cells haven't been built yet, then their state will be restored when |
| 207 // they are built. |
| 208 for (const [displayLabel, cell] of this.cells) { |
| 209 const previousState = vs.cells.get(displayLabel); |
| 210 if (!previousState) continue; |
| 211 await cell.viewState.updateFromViewState(previousState); |
| 212 } |
| 213 for (const row of this.subRows) { |
| 214 const previousState = vs.subRows.get(row.name); |
| 215 if (!previousState) continue; |
| 216 await row.restoreState(previousState); |
| 410 } | 217 } |
| 411 } | 218 } |
| 412 } | 219 } |
| 413 | 220 |
| 414 return { | 221 return { |
| 415 HistogramSetTableRow, | 222 HistogramSetTableRow, |
| 416 }; | 223 }; |
| 417 }); | 224 }); |
| 418 </script> | 225 </script> |
| OLD | NEW |