diff --git a/platform/commonUI/general/res/sass/_constants.scss b/platform/commonUI/general/res/sass/_constants.scss index 1d62164284..c2a61f1048 100644 --- a/platform/commonUI/general/res/sass/_constants.scss +++ b/platform/commonUI/general/res/sass/_constants.scss @@ -75,7 +75,7 @@ $treeContextTriggerW: 20px; /*************** Tabular */ $tabularHeaderH: 22px; $tabularTdPadLR: $itemPadLR; -$tabularTdPadTB: 3px; +$tabularTdPadTB: 2px; /*************** Imagery */ $imageMainControlBarH: 25px; $imageThumbsD: 120px; diff --git a/platform/commonUI/general/res/sass/controls/_time-of-interest.scss b/platform/commonUI/general/res/sass/controls/_time-of-interest.scss index f341788eda..9cf36e8332 100644 --- a/platform/commonUI/general/res/sass/controls/_time-of-interest.scss +++ b/platform/commonUI/general/res/sass/controls/_time-of-interest.scss @@ -20,21 +20,6 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ - -/* -Plots --toi-holder:before vertical line --toi: glyphs - -Tables -tr: border color -td:before: glyphs - -TC --toi-holder:before, after: vertical lines --toi: glyphs - -*/ .l-toi-holder, .l-toi-holder:after, .l-toi-holder:before, @@ -44,7 +29,6 @@ TC position: absolute; } - .l-toi-holder { $p: 3px; @include transform(translateX(-50%)); @@ -52,14 +36,16 @@ TC position: absolute; top: 0; bottom: 0; - width: $toiW; // Needs to be an even number to avoid sub-pixel antialiasing of the vertical line + width: $toiW; &:not(.pinned) { opacity: 0; pointer-events: none; } + &.pinned { opacity: 1; } + &:before, &:after { // Vertical lines. TC uses both; plot only uses :before @@ -73,8 +59,9 @@ TC bottom: 0; width: 2px; } + .l-toi { - // Holds clock icon an unpin button + // Holds clock icon and unpin button font-size: $toiW; height: $toiW; width: $toiW; @@ -83,6 +70,7 @@ TC @extend .icon-clock; &:hover { &:before { + color: $toiColorBgAlert; content: $glyph-icon-x-in-circle; } } @@ -90,26 +78,33 @@ TC } .l-toi-val { - $tbP: 1px; - background-color: $toiColorBg; //rgba($toiColorBg, 0.8); - border-radius: $controlCr; - box-sizing: content-box; - display: inline-block; - color: $toiColorFg; - font-size: 0.7rem; - height: $toiW; - right: $toiW + $interiorMarginSm; - top: 50%; - @include transform(translateY(-50%)); - line-height: $toiW; - padding: $tbP $p; - white-space: nowrap; + display: none; // Hide by default; see .show-val below } - &.val-to-right { + &.show-val { .l-toi-val { - right: auto; - left: $toiW + $interiorMarginSm; + $tbP: 1px; + background-color: $toiColorBg; + border-radius: $controlCr; + box-sizing: content-box; + color: $toiColorFg; + display: inline-block; + font-size: 0.7rem; + font-weight: 400; + height: $toiW; + right: $toiW + $interiorMarginSm; + top: 50%; + @include transform(translateY(-50%)); + line-height: $toiW; + padding: $tbP $p; + white-space: nowrap; + } + + &.val-to-right { + .l-toi-val { + right: auto; + left: $toiW + $interiorMarginSm; + } } } } @@ -120,38 +115,42 @@ table { tbody, .tbody { tr, .tr { &.l-toi.pinned { - td { - border-top: 1px dashed $toiColorBg; - &:first-child:before { - @extend .ui-symbol; - @include transform(translate(-50%, -50%)); - content: $glyph-icon-clock; - display: block; - position: absolute; - text-shadow: 0 1px 15px black; - left: 50%; - top: 0; - z-index: 2; - color: $toiColorBg; - } - } + border-top: 1px dashed $toiColorBg; + td, .td { + &:first-child { + &:before, + &:after { + @include transform(translate(-50%, -50%)); + display: block; + position: absolute; + left: 50%; + bottom: auto; + top: 0; - &.highlight-bottom-edge { - td { - border-bottom: 1px dashed $toiColorBg; - //border-top: 1px solid transparent; - &:first-child:before { - @include transform(translate(-50%, 50%)); - top: auto; - bottom: 0; + } + &:before { + @extend .icon-clock; + color: $toiColorBg; + cursor: pointer; + z-index: 3; + } + &:after { + border-radius: 100%; + content: ''; + background: $toiColorBlocker; + height: $toiW + $interiorMargin; + width: $toiW + $interiorMargin; + z-index: 2; } } } &:hover { - td:first-child:before { - content: $glyph-icon-x-in-circle; - cursor: pointer; + td, .td { + &:first-child:before { + color: $toiColorBgAlert; + content: $glyph-icon-x-in-circle !important; + } } } } @@ -164,6 +163,7 @@ table { .gl-plot-wrapper-display-area-and-x-axis { .l-toi-holder { bottom: nth($plotDisplayArea, 3) - $interiorMargin; + z-index: 3; &:after { display: none; } @@ -172,8 +172,6 @@ table { @include transform(translateY(100%)); bottom: 0; } - - z-index: 3; } } } \ No newline at end of file diff --git a/platform/commonUI/general/res/sass/lists/_tabular.scss b/platform/commonUI/general/res/sass/lists/_tabular.scss index 1377744fbf..91be1c8d75 100644 --- a/platform/commonUI/general/res/sass/lists/_tabular.scss +++ b/platform/commonUI/general/res/sass/lists/_tabular.scss @@ -51,13 +51,9 @@ table { tbody, .tbody { display: table-row-group; -/* tr, .tr { - &:hover { - background: rgba($colorTabBodyFg, 0.1); - } - }*/ } tr, .tr { + border-top: 1px solid $colorTabBorder; display: table-row; &:first-child .td { border-top: none; @@ -71,11 +67,12 @@ table { } th, .th, td, .td { display: table-cell; + font-size: 0.7rem; } th, .th { border-left: 1px solid $colorTabHeaderBorder; color: $colorTabHeaderFg; - padding: $tabularTdPadLR $tabularTdPadLR; + padding: $tabularTdPadTB $tabularTdPadLR; white-space: nowrap; vertical-align: middle; // This is crucial to hiding f**king 4px height injected by browser by default &:first-child { @@ -99,7 +96,6 @@ table { } } td, .td { - border-top: 1px solid $colorTabBorder; min-width: 20px; color: $colorTelemFresh; padding: $tabularTdPadTB $tabularTdPadLR; diff --git a/platform/commonUI/themes/espresso/res/sass/_constants.scss b/platform/commonUI/themes/espresso/res/sass/_constants.scss index 2319a96a2c..da9829756e 100644 --- a/platform/commonUI/themes/espresso/res/sass/_constants.scss +++ b/platform/commonUI/themes/espresso/res/sass/_constants.scss @@ -104,9 +104,11 @@ $colorInspectorSectionHeaderBg: $colorFormSectionHeader; $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%); // Time of Interest -$toiColorBg: #6b93c6; //$colorBtnMajorBg; +$toiColorBg: #6b93c6; +$toiColorBlocker: $colorBodyBg; // Color of blocker element beneath the TOI icon $toiColorFg: #000; -$toiW: 12px; +$toiColorBgAlert: #cf644a; // $colorFormInvalid; +$toiW: 12px; // Needs to be an even number to avoid sub-pixel antialiasing of the vertical line // Status colors, mainly used for messaging and item ancillary symbols $colorStatusFg: #ccc; diff --git a/platform/commonUI/themes/snow/res/sass/_constants.scss b/platform/commonUI/themes/snow/res/sass/_constants.scss index 1ba115b563..71c72967bc 100644 --- a/platform/commonUI/themes/snow/res/sass/_constants.scss +++ b/platform/commonUI/themes/snow/res/sass/_constants.scss @@ -105,8 +105,10 @@ $colorInspectorSectionHeaderFg: pullForward($colorInspectorBg, 40%); // Time of Interest $toiColorBg: #6b93c6; +$toiColorBlocker: $colorBodyBg; // Color of blocker element beneath the TOI icon $toiColorFg: #fff; -$toiW: 12px; +$toiColorBgAlert: #a7292a; // $colorFormInvalid; +$toiW: 12px; // Needs to be an even number to avoid sub-pixel antialiasing of the vertical line // Status colors, mainly used for messaging and item ancillary symbols $colorStatusFg: #fff; diff --git a/platform/features/conductor-v2/conductor/bundle.js b/platform/features/conductor-v2/conductor/bundle.js index 2c692f2a4b..a5170cc131 100644 --- a/platform/features/conductor-v2/conductor/bundle.js +++ b/platform/features/conductor-v2/conductor/bundle.js @@ -91,7 +91,7 @@ define([ "$scope", "timeConductor", "timeConductorViewService", - "$timeout" + "formatService" ] } ], diff --git a/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss b/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss index 8c728b8ea7..ec54e6a61e 100644 --- a/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss +++ b/platform/features/conductor-v2/conductor/res/sass/_time-conductor-base.scss @@ -244,11 +244,6 @@ left: nth($timeCondAxisLROffset, 1); right: nth($timeCondAxisLROffset, 2); &:hover { - // Hide the cursor, because the TOI element essentially "becomes" the cursor - // when the user is hovering over the visualization area. - - // AH - not any more it doesn't? - //cursor: none; .l-toi-holder.hover { opacity: 1; } diff --git a/platform/features/conductor-v2/conductor/res/templates/time-conductor.html b/platform/features/conductor-v2/conductor/res/templates/time-conductor.html index d7e42b34c7..849b72d21d 100644 --- a/platform/features/conductor-v2/conductor/res/templates/time-conductor.html +++ b/platform/features/conductor-v2/conductor/res/templates/time-conductor.html @@ -100,15 +100,13 @@ ng-click="toi.click($event)">
- -
+
-
2016-09-15 21:31:30.000Z
+ {{toi.toiText}}
diff --git a/platform/features/conductor-v2/conductor/src/TimeConductor.js b/platform/features/conductor-v2/conductor/src/TimeConductor.js index 2c2194b5a0..f594083100 100644 --- a/platform/features/conductor-v2/conductor/src/TimeConductor.js +++ b/platform/features/conductor-v2/conductor/src/TimeConductor.js @@ -123,6 +123,12 @@ define(['EventEmitter'], function (EventEmitter) { * @property {TimeConductorBounds} bounds */ this.emit('bounds', this.boundsVal); + + // If a bounds change results in a TOI outside of the current + // bounds, unset it + if (this.toi < newBounds.start || this.toi > newBounds.end) { + this.timeOfInterest(undefined); + } } //Return a copy to prevent direct mutation of time conductor bounds. return JSON.parse(JSON.stringify(this.boundsVal)); @@ -158,17 +164,21 @@ define(['EventEmitter'], function (EventEmitter) { /** * Get or set the Time of Interest. The Time of Interest is the temporal * focus of the current view. It can be manipulated by the user from the - * time conductor or from other views. + * time conductor or from other views. The time of interest can + * effectively be unset by assigning a value of 'undefined'. * @fires TimeConductor#timeOfInterest - * @param newTOI - * @returns {number} the current time of interest + * @param {number | undefined} newTOI A new time of interest, represented + * as a + * number that is valid in the current time system. + * @returns {number | undefined} the current time of interest */ TimeConductor.prototype.timeOfInterest = function (newTOI) { if (arguments.length > 0) { this.toi = newTOI; /** - * @event TimeConductor#timeOfInterest The Time of Interest has moved. - * @property {number} Current time of interest + * @event TimeConductor#timeOfInterest The Time of Interest has + * changed. + * @property {number | undefined} Current time of interest */ this.emit('timeOfInterest', this.toi); } diff --git a/platform/features/conductor-v2/conductor/src/ui/ConductorTOIController.js b/platform/features/conductor-v2/conductor/src/ui/ConductorTOIController.js index c168acadf6..61ba17cd10 100644 --- a/platform/features/conductor-v2/conductor/src/ui/ConductorTOIController.js +++ b/platform/features/conductor-v2/conductor/src/ui/ConductorTOIController.js @@ -29,9 +29,11 @@ define( * labelled 'ticks'. It requires 'start' and 'end' integer values to * be specified as attributes. */ - function ConductorTOIController($scope, conductor, conductorViewService, $timeout) { + function ConductorTOIController($scope, conductor, conductorViewService, formatService) { this.conductor = conductor; this.conductorViewService = conductorViewService; + this.formatService = formatService; + this.toiText = undefined; //Bind all class functions to 'this' Object.keys(ConductorTOIController.prototype).filter(function (key) { @@ -43,19 +45,10 @@ define( this.conductor.on('timeOfInterest', this.changeTimeOfInterest); this.conductorViewService.on('zoom', this.setOffsetFromBounds); this.conductorViewService.on('pan', this.setOffsetFromBounds); - - this.$timeout = $timeout; - - var generateRandomTOI = function () { - var bounds = conductor.bounds(); - var range = bounds.end - bounds.start; - var toi = Math.random() * range + bounds.start; - console.log('calculated random TOI of ' + toi); - conductor.timeOfInterest(toi); - //this.timeoutHandle = $timeout(generateRandomTOI, 1000); - }.bind(this); - - //this.timeoutHandle = $timeout(generateRandomTOI, 2000); + this.conductor.on('timeSystem', this.changeTimeSystem); + if (conductor.timeSystem()) { + this.changeTimeSystem(conductor.timeSystem()); + } $scope.$on('$destroy', this.destroy); @@ -63,23 +56,28 @@ define( ConductorTOIController.prototype.destroy = function () { this.conductor.off('timeOfInterest', this.setOffsetFromBounds); + this.conductor.off('timeSystem', this.changeTimeSystem); this.conductorViewService.off('zoom', this.setOffsetFromBounds); this.conductorViewService.off('pan', this.setOffsetFromBounds); - - this.$timeout.cancel(this.timeoutHandle); }; ConductorTOIController.prototype.setOffsetFromBounds = function (bounds) { var toi = this.conductor.timeOfInterest(); var offset = toi - bounds.start; - this.left = offset / (bounds.end - bounds.start) * 100; + var duration = bounds.end - bounds.start; + this.left = offset / duration * 100; + this.toiText = this.format.format(toi); + }; + + ConductorTOIController.prototype.changeTimeSystem = function (timeSystem) { + this.format = this.formatService.getFormat(timeSystem.formats()[0]); }; ConductorTOIController.prototype.changeTimeOfInterest = function () { var bounds = this.conductor.bounds(); if (bounds) { this.setOffsetFromBounds(bounds); - this.pinned = true; + this.pinned = this.conductor.timeOfInterest() !== undefined; } }; @@ -96,17 +94,8 @@ define( } }; - /* - ConductorTOIController.prototype.zoom = function (bounds) { - this.changeTOI(bounds) - }; - - ConductorTOIController.prototype.pan = function (bounds) { - this.changeTOI(bounds) - };*/ - ConductorTOIController.prototype.resize = function () { - //Do something + //Do something? }; return ConductorTOIController; diff --git a/platform/features/plot/res/templates/plot.html b/platform/features/plot/res/templates/plot.html index d6d9a2d50a..e0dd954d18 100644 --- a/platform/features/plot/res/templates/plot.html +++ b/platform/features/plot/res/templates/plot.html @@ -75,15 +75,15 @@
-
- +
- - + 21:31:30
diff --git a/platform/features/table/bundle.js b/platform/features/table/bundle.js index 4c7b77b47e..def5e4da62 100644 --- a/platform/features/table/bundle.js +++ b/platform/features/table/bundle.js @@ -109,7 +109,7 @@ define([ { "key": "HistoricalTableController", "implementation": HistoricalTableController, - "depends": ["$scope", "telemetryHandler", "telemetryFormatter", "$timeout"] + "depends": ["$scope", "telemetryHandler", "telemetryFormatter", "$timeout", "timeConductor"] }, { "key": "RealtimeTableController", diff --git a/platform/features/table/res/templates/historical-table.html b/platform/features/table/res/templates/historical-table.html index d306601daf..168886e59d 100644 --- a/platform/features/table/res/templates/historical-table.html +++ b/platform/features/table/res/templates/historical-table.html @@ -1,9 +1,11 @@ -
+
\ No newline at end of file diff --git a/platform/features/table/res/templates/mct-table.html b/platform/features/table/res/templates/mct-table.html index e3f3b1c009..054ec54e94 100644 --- a/platform/features/table/res/templates/mct-table.html +++ b/platform/features/table/res/templates/mct-table.html @@ -49,20 +49,23 @@ + + - - {{ visibleRow.contents[header].text }} - - - - + class="{{visibleRow.contents.cssClass}}" + ng-click="table.onRowClick($event, visibleRow.contents)" + ng-style="{ + top: visibleRow.offsetY + 'px', + }"> + + {{ visibleRow.contents[header].text }} + + + +
diff --git a/platform/features/table/src/controllers/HistoricalTableController.js b/platform/features/table/src/controllers/HistoricalTableController.js index d8af8060de..90e13db704 100644 --- a/platform/features/table/src/controllers/HistoricalTableController.js +++ b/platform/features/table/src/controllers/HistoricalTableController.js @@ -36,7 +36,7 @@ define( * @param telemetryFormatter * @constructor */ - function HistoricalTableController($scope, telemetryHandler, telemetryFormatter, $timeout) { + function HistoricalTableController($scope, telemetryHandler, telemetryFormatter, $timeout, conductor) { var self = this; this.$timeout = $timeout; @@ -49,7 +49,7 @@ define( } }); - TableController.call(this, $scope, telemetryHandler, telemetryFormatter); + TableController.call(this, $scope, telemetryHandler, telemetryFormatter, conductor); } HistoricalTableController.prototype = Object.create(TableController.prototype); @@ -59,6 +59,7 @@ define( * @private */ HistoricalTableController.prototype.doneProcessing = function (rowData) { + //Set table rows to formatted data; this.$scope.rows = rowData; this.$scope.loading = false; }; @@ -109,8 +110,9 @@ define( //Process rows in a batch with size not exceeding a maximum length for (; i < end; i++) { - rowData.push(this.table.getRowValues(telemetryObject, - this.handle.makeDatum(telemetryObject, series, i))); + var datum = this.handle.makeDatum(telemetryObject, series, i); + this.data.push(datum); + rowData.push(this.table.getRowValues(telemetryObject, datum)); } //Done processing all rows for this object. @@ -123,7 +125,7 @@ define( // before continuing processing this.timeoutHandle = this.$timeout(this.processTelemetryObjects.bind(this, objects, offset, end, rowData)); }; - + /** * Populates historical data on scope when it becomes available from * the telemetry API @@ -132,7 +134,7 @@ define( if (this.timeoutHandle) { this.$timeout.cancel(this.timeoutHandle); } - + this.data = []; this.timeoutHandle = this.$timeout(this.processTelemetryObjects.bind(this, this.handle.getTelemetryObjects(), 0, 0, [])); }; diff --git a/platform/features/table/src/controllers/MCTTableController.js b/platform/features/table/src/controllers/MCTTableController.js index bf5ea9218c..3db5d8267a 100644 --- a/platform/features/table/src/controllers/MCTTableController.js +++ b/platform/features/table/src/controllers/MCTTableController.js @@ -25,6 +25,13 @@ define( this.tbody = element.find('tbody'); this.$scope.sizingRow = {}; + //Bind all class functions to 'this' + Object.keys(MCTTableController.prototype).filter(function (key) { + return typeof MCTTableController.prototype[key] === 'function'; + }).forEach(function (key) { + this[key] = MCTTableController.prototype[key].bind(this); + }.bind(this)); + this.scrollable.on('scroll', this.onScroll.bind(this)); $scope.visibleRows = []; @@ -294,37 +301,38 @@ define( /** * @private */ - MCTTableController.prototype.insertSorted = function (array, element) { - var index = -1, - self = this, - sortKey = this.$scope.sortColumn; + MCTTableController.prototype.binarySearch = function (searchArray, searchElement, min, max) { + var sampleAt = Math.floor((max - min) / 2) + min; - function binarySearch(searchArray, searchElement, min, max) { - var sampleAt = Math.floor((max - min) / 2) + min; - - if (max < min) { - return min; // Element is not in array, min gives direction - } - - switch (self.sortComparator(searchElement[sortKey].text, - searchArray[sampleAt][sortKey].text)) { - case -1: - return binarySearch(searchArray, searchElement, min, - sampleAt - 1); - case 0 : - return sampleAt; - case 1 : - return binarySearch(searchArray, searchElement, - sampleAt + 1, max); - } + if (max < min) { + return min; // Element is not in array, min gives direction } + switch (this.sortComparator(searchElement[this.$scope.sortColumn].text, + searchArray[sampleAt][this.$scope.sortColumn].text)) { + case -1: + return this.binarySearch(searchArray, searchElement, min, + sampleAt - 1); + case 0 : + return sampleAt; + case 1 : + return this.binarySearch(searchArray, searchElement, + sampleAt + 1, max); + } + }; + + /** + * @private + */ + MCTTableController.prototype.insertSorted = function (array, element) { + var index = -1; + if (!this.$scope.sortColumn || !this.$scope.sortDirection) { //No sorting applied, push it on the end. index = array.length; } else { //Sort is enabled, perform binary search to find insertion point - index = binarySearch(array, element, 0, array.length - 1); + index = this.binarySearch(array, element, 0, array.length - 1); } if (index === -1) { array.unshift(element); @@ -488,6 +496,11 @@ define( this.resize(newRows).then(this.setVisibleRows.bind(this)); }; + MCTTableController.prototype.onRowClick = function (event, row) { + var index = this.$scope.rows.indexOf(row); + this.$scope.onRowClick({event: event, rowIndex:index, sortColumn: this.$scope.sortColumn, sortDirection: this.$scope.sortDirection}); + }; + /** * Applies user defined filters to rows. These filters are based on * the text entered in the search areas in each column. diff --git a/platform/features/table/src/controllers/TelemetryTableController.js b/platform/features/table/src/controllers/TelemetryTableController.js index 1e77e16278..3845026f8e 100644 --- a/platform/features/table/src/controllers/TelemetryTableController.js +++ b/platform/features/table/src/controllers/TelemetryTableController.js @@ -26,9 +26,10 @@ */ define( [ - '../TableConfiguration' + '../TableConfiguration', + '../DomainColumn' ], - function (TableConfiguration) { + function (TableConfiguration, DomainColumn) { /** * The TableController is responsible for getting data onto the page @@ -43,7 +44,8 @@ define( function TelemetryTableController( $scope, telemetryHandler, - telemetryFormatter + telemetryFormatter, + conductor ) { var self = this; @@ -54,6 +56,8 @@ define( this.table = new TableConfiguration($scope.domainObject, telemetryFormatter); this.changeListeners = []; + this.conductor = conductor; + this.data = []; $scope.rows = []; @@ -64,9 +68,27 @@ define( }); // Unsubscribe when the plot is destroyed - this.$scope.$on("$destroy", this.destroy.bind(this)); + this.$scope.$on("$destroy", this.destroy); } + TelemetryTableController.prototype.onRowClick = function (event, rowIndex, sortBy, sortOrder) { + var datum = this.data[rowIndex]; + + if (event.altKey) { + console.log("selected: " + this.$scope.rows[rowIndex]); + //Is column one that we can use to set time of interest? + var domainColumn = this.table.columns.filter(function (column) { + return column instanceof DomainColumn && + column.getTitle() === sortBy; + })[0]; + if (domainColumn) { + var timeOfInterest = datum[domainColumn.domainMetadata.key]; + this.conductor.timeOfInterest(timeOfInterest); + } + } + + }; + /** * @private */ @@ -188,6 +210,10 @@ define( }); }; + TelemetryTableController.prototype.changeTimeOfInterest = function (toi) { + + } + return TelemetryTableController; } ); diff --git a/platform/features/table/src/directives/MCTTable.js b/platform/features/table/src/directives/MCTTable.js index 12407e7598..d138c8ac97 100644 --- a/platform/features/table/src/directives/MCTTable.js +++ b/platform/features/table/src/directives/MCTTable.js @@ -88,12 +88,14 @@ define( 'exportService', MCTTableController ], + controllerAs: "table", scope: { headers: "=", rows: "=", enableFilter: "=?", enableSort: "=?", - autoScroll: "=?" + autoScroll: "=?", + onRowClick: "&" } }; }