mirror of
https://github.com/nasa/openmct.git
synced 2025-01-18 02:39:56 +00:00
[Tables] limit digests to increase performance
This commit is contained in:
parent
2a4944d6ee
commit
50f303bbdc
@ -5,7 +5,7 @@
|
|||||||
Export
|
Export
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="l-view-section scrolling" style="overflow: auto;">
|
<div class="l-view-section scrolling" style="overflow: auto;" mct-resize="resize()">
|
||||||
<table class="sizing-table">
|
<table class="sizing-table">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@ -32,7 +32,8 @@
|
|||||||
enableSort ? 'sortable' : '',
|
enableSort ? 'sortable' : '',
|
||||||
sortColumn === header ? 'sort' : '',
|
sortColumn === header ? 'sort' : '',
|
||||||
sortDirection || ''
|
sortDirection || ''
|
||||||
].join(' ')">
|
].join(' ')"
|
||||||
|
ng-click="toggleSort(header)">
|
||||||
{{ header }}
|
{{ header }}
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -58,7 +59,8 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr ng-repeat-end
|
<tr ng-repeat-end
|
||||||
ng-style="{ top: visibleRow.offsetY + 'px' }">
|
ng-style="{ top: visibleRow.offsetY + 'px' }"
|
||||||
|
ng-click="table.onRowClick($event, visibleRow.rowIndex) ">
|
||||||
<td ng-repeat="header in displayHeaders"
|
<td ng-repeat="header in displayHeaders"
|
||||||
ng-style=" {
|
ng-style=" {
|
||||||
width: columnWidths[$index] + 'px',
|
width: columnWidths[$index] + 'px',
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
<div ng-controller="TelemetryTableController as tableController"
|
<div ng-controller="TelemetryTableController as tableController"
|
||||||
ng-class="{'loading': loading}">
|
ng-class="{'loading': loading}">
|
||||||
|
Request time: {{tableController.lastRequestTime | date : 'HH:mm:ss:sss'}}
|
||||||
<mct-table
|
<mct-table
|
||||||
headers="headers"
|
headers="headers"
|
||||||
time-columns="tableController.timeColumns"
|
|
||||||
rows="rows"
|
rows="rows"
|
||||||
|
time-columns="tableController.timeColumns"
|
||||||
|
on-show-cell=""
|
||||||
enableFilter="true"
|
enableFilter="true"
|
||||||
enableSort="true"
|
enableSort="true"
|
||||||
|
auto-scroll="autoScroll"
|
||||||
default-sort="defaultSort"
|
default-sort="defaultSort"
|
||||||
class="tabular-holder has-control-bar">
|
class="tabular-holder has-control-bar">
|
||||||
</mct-table>
|
</mct-table>
|
||||||
|
@ -163,8 +163,6 @@ define(
|
|||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
console.log('constructed');
|
|
||||||
|
|
||||||
$scope.$on('$destroy', function() {
|
$scope.$on('$destroy', function() {
|
||||||
this.scrollable.off('scroll', this.onScroll);
|
this.scrollable.off('scroll', this.onScroll);
|
||||||
this.destroyConductorListeners();
|
this.destroyConductorListeners();
|
||||||
@ -193,15 +191,7 @@ define(
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
MCTTableController.prototype.scrollToBottom = function () {
|
MCTTableController.prototype.scrollToBottom = function () {
|
||||||
var self = this;
|
this.scrollable[0].scrollTop = this.scrollable[0].scrollHeight;
|
||||||
|
|
||||||
//Use timeout to defer execution until next digest when any
|
|
||||||
// pending UI changes have completed, eg. a new row in the table.
|
|
||||||
if (this.$scope.autoScroll) {
|
|
||||||
this.digest(function () {
|
|
||||||
self.scrollable[0].scrollTop = self.scrollable[0].scrollHeight;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,8 +209,12 @@ define(
|
|||||||
|
|
||||||
//Resize the columns , then update the rows visible in the table
|
//Resize the columns , then update the rows visible in the table
|
||||||
this.resize([this.$scope.sizingRow, row])
|
this.resize([this.$scope.sizingRow, row])
|
||||||
.then(this.setVisibleRows.bind(this))
|
.then(this.setVisibleRows)
|
||||||
.then(this.scrollToBottom.bind(this));
|
.then(function () {
|
||||||
|
if (this.$scope.autoScroll) {
|
||||||
|
this.scrollToBottom();
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
var toi = this.conductor.timeOfInterest();
|
var toi = this.conductor.timeOfInterest();
|
||||||
if (toi !== -1) {
|
if (toi !== -1) {
|
||||||
@ -250,16 +244,24 @@ define(
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
MCTTableController.prototype.onScroll = function (event) {
|
MCTTableController.prototype.onScroll = function (event) {
|
||||||
|
if (!this.scrolling) {
|
||||||
|
this.scrolling = true;
|
||||||
|
|
||||||
|
requestAnimationFrame(function () {
|
||||||
|
this.setVisibleRows();
|
||||||
|
this.digest();
|
||||||
|
|
||||||
// If user scrolls away from bottom, disable auto-scroll.
|
// If user scrolls away from bottom, disable auto-scroll.
|
||||||
// Auto-scroll will be re-enabled if user scrolls to bottom again.
|
// Auto-scroll will be re-enabled if user scrolls to bottom again.
|
||||||
if (this.scrollable[0].scrollTop <
|
if (this.scrollable[0].scrollTop <
|
||||||
(this.scrollable[0].scrollHeight - this.scrollable[0].offsetHeight)) {
|
(this.scrollable[0].scrollHeight - this.scrollable[0].offsetHeight) - 20) {
|
||||||
this.$scope.autoScroll = false;
|
this.$scope.autoScroll = false;
|
||||||
} else {
|
} else {
|
||||||
this.$scope.autoScroll = true;
|
this.$scope.autoScroll = true;
|
||||||
}
|
}
|
||||||
this.setVisibleRows();
|
this.scrolling = false;
|
||||||
this.$scope.$digest();
|
}.bind(this));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -338,7 +340,7 @@ define(
|
|||||||
this.$scope.visibleRows[this.$scope.visibleRows.length - 1]
|
this.$scope.visibleRows[this.$scope.visibleRows.length - 1]
|
||||||
.rowIndex === end) {
|
.rowIndex === end) {
|
||||||
|
|
||||||
return; // don't update if no changes are required.
|
return Promise.resolve(); // don't update if no changes are required.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Set visible rows from display rows, based on calculated offset.
|
//Set visible rows from display rows, based on calculated offset.
|
||||||
@ -351,6 +353,7 @@ define(
|
|||||||
contents: row
|
contents: row
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
return this.digest();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -566,25 +569,25 @@ define(
|
|||||||
return largestRow;
|
return largestRow;
|
||||||
};
|
};
|
||||||
|
|
||||||
MCTTableController.prototype.digest = function (callback) {
|
// Will effectively cap digests at 60Hz
|
||||||
|
// Also turns digest into a promise allowing code to force digest, then
|
||||||
|
// schedule something to happen afterwards
|
||||||
|
MCTTableController.prototype.digest = function () {
|
||||||
var scope = this.$scope;
|
var scope = this.$scope;
|
||||||
var callbacks = this.callbacks;
|
var self = this;
|
||||||
var requestAnimationFrame = this.$window.requestAnimationFrame;
|
var requestAnimationFrame = this.$window.requestAnimationFrame;
|
||||||
|
|
||||||
var promise = callbacks[callback];
|
if (!this.digestPromise) {
|
||||||
|
this.digestPromise = new Promise(function (resolve) {
|
||||||
if (!promise){
|
|
||||||
promise = new Promise(function (resolve) {
|
|
||||||
requestAnimationFrame(function() {
|
requestAnimationFrame(function() {
|
||||||
scope.$digest();
|
scope.$digest();
|
||||||
delete callbacks[callback];
|
delete self.digestPromise;
|
||||||
resolve(callback && callback());
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
callbacks[callback] = promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return promise;
|
return this.digestPromise;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -598,7 +601,7 @@ define(
|
|||||||
*/
|
*/
|
||||||
MCTTableController.prototype.resize = function (rows) {
|
MCTTableController.prototype.resize = function (rows) {
|
||||||
this.$scope.sizingRow = this.buildLargestRow(rows);
|
this.$scope.sizingRow = this.buildLargestRow(rows);
|
||||||
return this.digest(this.setElementSizes);
|
return this.digest().then(this.setElementSizes);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -631,7 +634,6 @@ define(
|
|||||||
.then(this.setVisibleRows)
|
.then(this.setVisibleRows)
|
||||||
//Timeout following setVisibleRows to allow digest to
|
//Timeout following setVisibleRows to allow digest to
|
||||||
// perform DOM changes, otherwise scrollTo won't work.
|
// perform DOM changes, otherwise scrollTo won't work.
|
||||||
.then(this.digest)
|
|
||||||
.then(function () {
|
.then(function () {
|
||||||
//If TOI specified, scroll to it
|
//If TOI specified, scroll to it
|
||||||
var timeOfInterest = this.conductor.timeOfInterest();
|
var timeOfInterest = this.conductor.timeOfInterest();
|
||||||
@ -732,7 +734,9 @@ define(
|
|||||||
*/
|
*/
|
||||||
MCTTableController.prototype.changeBounds = function (bounds) {
|
MCTTableController.prototype.changeBounds = function (bounds) {
|
||||||
this.setTimeOfInterestRow(this.conductor.timeOfInterest());
|
this.setTimeOfInterestRow(this.conductor.timeOfInterest());
|
||||||
|
if (this.$scope.toiRowIndex !== -1) {
|
||||||
this.scrollToRow(this.$scope.toiRowIndex);
|
this.scrollToRow(this.$scope.toiRowIndex);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,15 +76,23 @@ define(
|
|||||||
'loadColumns',
|
'loadColumns',
|
||||||
'getHistoricalData',
|
'getHistoricalData',
|
||||||
'subscribeToNewData',
|
'subscribeToNewData',
|
||||||
'changeBounds'
|
'changeBounds',
|
||||||
|
'setScroll'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.getData();
|
this.getData();
|
||||||
this.registerChangeListeners();
|
this.registerChangeListeners();
|
||||||
|
|
||||||
|
this.openmct.conductor.on('follow', this.setScroll);
|
||||||
|
this.setScroll(this.openmct.conductor.follow());
|
||||||
|
|
||||||
this.$scope.$on("$destroy", this.destroy);
|
this.$scope.$on("$destroy", this.destroy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TelemetryTableController.prototype.setScroll = function (scroll){
|
||||||
|
this.$scope.autoScroll = scroll;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the selected time system, find a matching domain column
|
* Based on the selected time system, find a matching domain column
|
||||||
* to sort by. By default will just match on key.
|
* to sort by. By default will just match on key.
|
||||||
@ -171,6 +179,7 @@ define(
|
|||||||
|
|
||||||
this.openmct.conductor.off('timeSystem', this.sortByTimeSystem);
|
this.openmct.conductor.off('timeSystem', this.sortByTimeSystem);
|
||||||
this.openmct.conductor.off('bounds', this.changeBounds);
|
this.openmct.conductor.off('bounds', this.changeBounds);
|
||||||
|
this.openmct.conductor.off('follow', this.setScroll);
|
||||||
|
|
||||||
this.subscriptions.forEach(function (subscription) {
|
this.subscriptions.forEach(function (subscription) {
|
||||||
subscription();
|
subscription();
|
||||||
@ -229,20 +238,18 @@ define(
|
|||||||
var openmct = this.openmct;
|
var openmct = this.openmct;
|
||||||
var bounds = openmct.conductor.bounds();
|
var bounds = openmct.conductor.bounds();
|
||||||
var scope = this.$scope;
|
var scope = this.$scope;
|
||||||
|
var rowData = [];
|
||||||
var processedObjects = 0;
|
var processedObjects = 0;
|
||||||
var requestTime = this.lastRequestTime = Date.now();
|
var requestTime = this.lastRequestTime = Date.now();
|
||||||
|
|
||||||
return new Promise(function (resolve, reject){
|
return new Promise(function (resolve, reject){
|
||||||
console.log('Created promise');
|
|
||||||
function finishProcessing(tableRows){
|
function finishProcessing(tableRows){
|
||||||
scope.rows = tableRows;
|
scope.rows = tableRows.concat(scope.rows);
|
||||||
scope.loading = false;
|
scope.loading = false;
|
||||||
console.log('Resolved promise');
|
|
||||||
resolve(tableRows);
|
resolve(tableRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
function processData(historicalData, index, rowData, limitEvaluator){
|
function processData(historicalData, index, limitEvaluator){
|
||||||
console.log("Processing batch");
|
|
||||||
if (index >= historicalData.length) {
|
if (index >= historicalData.length) {
|
||||||
processedObjects++;
|
processedObjects++;
|
||||||
|
|
||||||
@ -250,13 +257,14 @@ define(
|
|||||||
finishProcessing(rowData);
|
finishProcessing(rowData);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rowData = rowData.concat(historicalData.slice(index, index + this.batchSize)
|
rowData = rowData.concat(
|
||||||
.map(this.table.getRowValues.bind(this.table, limitEvaluator)));
|
historicalData.slice(index, index + this.batchSize).map(
|
||||||
|
this.table.getRowValues.bind(this.table, limitEvaluator))
|
||||||
|
);
|
||||||
this.timeoutHandle = this.$timeout(processData.bind(
|
this.timeoutHandle = this.$timeout(processData.bind(
|
||||||
this,
|
this,
|
||||||
historicalData,
|
historicalData,
|
||||||
index + this.batchSize,
|
index + this.batchSize,
|
||||||
rowData,
|
|
||||||
limitEvaluator
|
limitEvaluator
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -265,12 +273,10 @@ define(
|
|||||||
function makeTableRows(object, historicalData) {
|
function makeTableRows(object, historicalData) {
|
||||||
// Only process one request at a time
|
// Only process one request at a time
|
||||||
if (requestTime === this.lastRequestTime) {
|
if (requestTime === this.lastRequestTime) {
|
||||||
console.log('Processing request');
|
|
||||||
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
|
var limitEvaluator = openmct.telemetry.limitEvaluator(object);
|
||||||
processData.call(this, historicalData, 0, [], limitEvaluator);
|
processData.call(this, historicalData, 0, limitEvaluator);
|
||||||
} else {
|
} else {
|
||||||
console.log('Ignoring returned data because of staleness');
|
resolve(rowData);
|
||||||
resolve([]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +293,6 @@ define(
|
|||||||
objects.forEach(requestData.bind(this));
|
objects.forEach(requestData.bind(this));
|
||||||
} else {
|
} else {
|
||||||
scope.loading = false;
|
scope.loading = false;
|
||||||
console.log('Resolved promise');
|
|
||||||
resolve([]);
|
resolve([]);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
@ -317,16 +322,15 @@ define(
|
|||||||
this.$scope.$broadcast('remove:row', 0);
|
this.$scope.$broadcast('remove:row', 0);
|
||||||
this.$scope.rows.shift();
|
this.$scope.rows.shift();
|
||||||
}
|
}
|
||||||
|
if (!this.$scope.loading) {
|
||||||
this.$scope.$broadcast('add:row',
|
this.$scope.$broadcast('add:row',
|
||||||
this.$scope.rows.length - 1);
|
this.$scope.rows.length - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
objects.forEach(function (object){
|
objects.forEach(function (object){
|
||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
telemetryApi.subscribe(object, newData.bind(this, object), {}));
|
||||||
console.log('subscribed');
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
return objects;
|
return objects;
|
||||||
@ -374,7 +378,7 @@ define(
|
|||||||
getDomainObjects()
|
getDomainObjects()
|
||||||
.then(filterForTelemetry)
|
.then(filterForTelemetry)
|
||||||
.then(this.loadColumns)
|
.then(this.loadColumns)
|
||||||
//.then(this.subscribeToNewData)
|
.then(this.subscribeToNewData)
|
||||||
.then(this.getHistoricalData)
|
.then(this.getHistoricalData)
|
||||||
.catch(error)
|
.catch(error)
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user