Merge pull request #1699 from nasa/imagery-issue-1676

Imagery issue #1676
This commit is contained in:
Pete Richards 2017-09-12 11:28:40 -07:00 committed by GitHub
commit 54b975f242
8 changed files with 107 additions and 63 deletions

View File

@ -21,7 +21,7 @@
*****************************************************************************/ *****************************************************************************/
/************************** FEATURES */ /************************** FEATURES */
$enableImageryThumbs: false; // Set to true if historical imagery thumbnails are supported $enableImageryThumbs: true; // Set to true if historical imagery thumbnails are supported
/************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */ /************************** VERY INFLUENTIAL GLOBAL DIMENSIONS */
$bodyMargin: 10px; $bodyMargin: 10px;
@ -82,7 +82,7 @@ $tabularTdPadTB: 2px;
/*************** Imagery */ /*************** Imagery */
$imageMainControlBarH: 25px; $imageMainControlBarH: 25px;
$imageThumbsD: 120px; $imageThumbsD: 120px;
$imageThumbsWrapperH: $imageThumbsD * 1.4; $imageThumbsWrapperH: 155px;
$imageThumbPad: 1px; $imageThumbPad: 1px;
/*************** Ticks */ /*************** Ticks */
$ticksH: 25px; $ticksH: 25px;

View File

@ -9,7 +9,6 @@
@if $enableImageryThumbs == true { @if $enableImageryThumbs == true {
bottom: $interiorMargin*2 + $imageThumbsWrapperH; bottom: $interiorMargin*2 + $imageThumbsWrapperH;
} }
min-height: 100px;
min-width: 150px; min-width: 150px;
.l-image-main { .l-image-main {
background-color: $colorPlotBg; background-color: $colorPlotBg;
@ -22,7 +21,9 @@
.l-image-thumbs-wrapper { .l-image-thumbs-wrapper {
top: auto; top: auto;
height: $imageThumbsWrapperH; min-height: $imageThumbsWrapperH;
max-height: 60%;
box-sizing: border-box;
} }
.l-date, .l-date,
@ -82,9 +83,8 @@
/*************************************** THUMBS */ /*************************************** THUMBS */
.l-image-thumbs-wrapper { .l-image-thumbs-wrapper {
//@include test(green); overflow-x: hidden;
overflow-x: auto; overflow-y: auto;
overflow-y: hidden;
padding-bottom: $interiorMargin; padding-bottom: $interiorMargin;
white-space: nowrap; white-space: nowrap;
} }
@ -92,8 +92,17 @@
.l-image-thumb-item { .l-image-thumb-item {
@include transition(background-color, 0.25s); @include transition(background-color, 0.25s);
box-sizing: border-box; box-sizing: border-box;
cursor: pointer;
direction: ltr;
display: inline-block;
float: left;
font-size: 0.8em;
padding: 1px; padding: 1px;
position: relative; margin-left: $interiorMarginSm;
position: relative;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
.l-thumb, .l-thumb,
.l-date, .l-date,
.l-time { .l-time {
@ -103,14 +112,7 @@
.l-time { .l-time {
padding: 2px 3px; padding: 2px 3px;
} }
cursor: pointer;
direction: ltr;
display: inline-block;
font-size: 0.8em;
margin-left: $interiorMarginSm;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
&:hover { &:hover {
background: $colorThumbHoverBg; background: $colorThumbHoverBg;
.l-date, .l-date,
@ -184,7 +186,8 @@
/*************************************** WHEN IN FRAME */ /*************************************** WHEN IN FRAME */
.frame .t-imagery { .frame .t-imagery {
.l-image-main-wrapper { .l-image-main-wrapper {
bottom: 0; bottom: 0 !important;
height: 100% !important;
.l-image-main-controlbar { .l-image-main-controlbar {
font-size: 0.7em; font-size: 0.7em;
} }
@ -194,7 +197,8 @@
} }
} }
} }
.l-image-thumbs-wrapper { .l-image-thumbs-wrapper,
mct-splitter {
display: none; display: none;
} }
} }

View File

@ -117,9 +117,7 @@ define(
// Apply styles to child elements // Apply styles to child elements
function updateChildren(children) { function updateChildren(children) {
if (alias) { position = userWidthPreference || position;
position = userWidthPreference || position;
}
// Pick out correct elements to update, flowing from // Pick out correct elements to update, flowing from
// selected anchor edge. // selected anchor edge.
@ -182,7 +180,9 @@ define(
} }
function setUserWidthPreference(value) { function setUserWidthPreference(value) {
userWidthPreference = value; if (alias) {
userWidthPreference = value;
}
} }
function persistToLocalStorage(value) { function persistToLocalStorage(value) {

View File

@ -25,14 +25,12 @@ define([
"./src/controllers/ImageryController", "./src/controllers/ImageryController",
"./src/directives/MCTBackgroundImage", "./src/directives/MCTBackgroundImage",
"text!./res/templates/imagery.html", "text!./res/templates/imagery.html",
"text!./res/templates/imageryTimeline.html",
'legacyRegistry' 'legacyRegistry'
], function ( ], function (
ImageryViewPolicy, ImageryViewPolicy,
ImageryController, ImageryController,
MCTBackgroundImage, MCTBackgroundImage,
imageryTemplate, imageryTemplate,
imageryTimelineTemplate,
legacyRegistry legacyRegistry
) { ) {
@ -50,17 +48,6 @@ define([
"telemetry" "telemetry"
], ],
"editable": false "editable": false
},
{
"name": "Historical Imagery",
"key": "historical-imagery",
"cssClass": "icon-image",
"template": imageryTimelineTemplate,
"priority": "preferred",
"needs": [
"telemetry"
],
"editable": false
} }
], ],
"policies": [ "policies": [

View File

@ -1,5 +1,6 @@
<div class="t-imagery" ng-controller="ImageryController as imagery"> <div class="t-imagery" ng-controller="ImageryController as imagery">
<div class="l-image-main-wrapper l-flex-col" <mct-split-pane class='abs' anchor="bottom" alias="imagery">
<div class="split-pane-component l-image-main-wrapper l-flex-col"
ng-mouseenter="showLocalControls = true;" ng-mouseenter="showLocalControls = true;"
ng-mouseleave="showLocalControls = false;"> ng-mouseleave="showLocalControls = false;">
<div class="l-local-controls s-local-controls s-wrapper-transluc l-flex-row" <div class="l-local-controls s-local-controls s-wrapper-transluc l-flex-row"
@ -55,4 +56,14 @@
</div> </div>
</div> </div>
</div> </div>
<mct-splitter></mct-splitter>
<div class="split-pane-component l-image-thumbs-wrapper">
<div class="l-image-thumb-item" ng-class="{selected: image.selected}" ng-repeat="image in imageHistory track by $index"
ng-click="imagery.setSelectedImage(image)" ng-init="imagery.scrollToBottom()">
<img class="l-thumb"
ng-src={{imagery.getImageUrl(image)}}>
<div class="l-time">{{imagery.getTime(image)}}</div>
</div>
</div>
</mct-split-pane>
</div> </div>

View File

@ -1,8 +0,0 @@
<div class="l-image-thumbs-wrapper" ng-controller="ImageryController as imagery">
<div class="l-image-thumb-item" ng-repeat="image in imageHistory track by $index">
<img class="l-thumb" ng-init="imagery.scrollToRight()"
ng-src={{imagery.getImageUrl(image)}} >
<div class="l-time">{{imagery.getTime(image)}}</div>
</div>
</div>

View File

@ -48,9 +48,8 @@ define(
this.zone = ""; this.zone = "";
this.imageUrl = ""; this.imageUrl = "";
this.requestCount = 0; this.requestCount = 0;
this.scrollable = $(element[0]); this.scrollable = $(".l-image-thumbs-wrapper");
this.autoScroll = openmct.time.clock() ? true : false; this.autoScroll = openmct.time.clock() ? true : false;
this.$scope.imageHistory = []; this.$scope.imageHistory = [];
this.$scope.filters = { this.$scope.filters = {
brightness: 100, brightness: 100,
@ -63,6 +62,7 @@ define(
this.updateHistory = this.updateHistory.bind(this); this.updateHistory = this.updateHistory.bind(this);
this.onBoundsChange = this.onBoundsChange.bind(this); this.onBoundsChange = this.onBoundsChange.bind(this);
this.onScroll = this.onScroll.bind(this); this.onScroll = this.onScroll.bind(this);
this.setSelectedImage = this.setSelectedImage.bind(this);
this.subscribe(this.$scope.domainObject); this.subscribe(this.$scope.domainObject);
@ -80,10 +80,10 @@ define(
var metadata = this.openmct var metadata = this.openmct
.telemetry .telemetry
.getMetadata(this.domainObject); .getMetadata(this.domainObject);
var timeKey = this.openmct.time.timeSystem().key; this.timeKey = this.openmct.time.timeSystem().key;
this.timeFormat = this.openmct this.timeFormat = this.openmct
.telemetry .telemetry
.getValueFormatter(metadata.value(timeKey)); .getValueFormatter(metadata.value(this.timeKey));
this.imageFormat = this.openmct this.imageFormat = this.openmct
.telemetry .telemetry
.getValueFormatter(metadata.valuesForHints(['image'])[0]); .getValueFormatter(metadata.valuesForHints(['image'])[0]);
@ -161,7 +161,7 @@ define(
/** /**
* Updates displayable values to match those of the most * Updates displayable values to match those of the most
* recently recieved datum. * recently received datum.
* @param {object} [datum] the datum * @param {object} [datum] the datum
* @private * @private
*/ */
@ -170,7 +170,6 @@ define(
this.nextDatum = datum; this.nextDatum = datum;
return; return;
} }
this.time = this.timeFormat.format(datum); this.time = this.timeFormat.format(datum);
this.imageUrl = this.imageFormat.format(datum); this.imageUrl = this.imageFormat.format(datum);
@ -185,8 +184,7 @@ define(
ImageryController.prototype.updateHistory = function (datum) { ImageryController.prototype.updateHistory = function (datum) {
if (this.$scope.imageHistory.length === 0 || if (this.$scope.imageHistory.length === 0 ||
!_.isEqual(this.$scope.imageHistory.slice(-1)[0], datum)) { !_.isEqual(this.$scope.imageHistory.slice(-1)[0], datum)) {
var index = _.sortedIndex(this.$scope.imageHistory, datum, this.timeFormat.format.bind(this.timeFormat));
var index = _.sortedIndex(this.$scope.imageHistory, datum, 'utc');
this.$scope.imageHistory.splice(index, 0, datum); this.$scope.imageHistory.splice(index, 0, datum);
return true; return true;
} }
@ -196,8 +194,12 @@ define(
ImageryController.prototype.onScroll = function (event) { ImageryController.prototype.onScroll = function (event) {
this.$window.requestAnimationFrame(function () { this.$window.requestAnimationFrame(function () {
var thumbnailWrapperHeight = this.scrollable[0].offsetHeight;
var thumbnailWrapperWidth = this.scrollable[0].offsetWidth;
if (this.scrollable[0].scrollLeft < if (this.scrollable[0].scrollLeft <
(this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - 20) { (this.scrollable[0].scrollWidth - this.scrollable[0].clientWidth) - (thumbnailWrapperWidth) ||
this.scrollable[0].scrollTop <
(this.scrollable[0].scrollHeight - this.scrollable[0].clientHeight) - (thumbnailWrapperHeight)) {
this.autoScroll = false; this.autoScroll = false;
} else { } else {
this.autoScroll = true; this.autoScroll = true;
@ -205,12 +207,16 @@ define(
}.bind(this)); }.bind(this));
}; };
ImageryController.prototype.scrollToRight = function () { /**
* Force history imagery div to scroll to bottom.
*/
ImageryController.prototype.scrollToBottom = function () {
if (this.autoScroll) { if (this.autoScroll) {
this.scrollable[0].scrollLeft = this.scrollable[0].scrollWidth; this.scrollable[0].scrollTop = this.scrollable[0].scrollHeight;
} }
}; };
/** /**
* Get the time portion (hours, minutes, seconds) of the * Get the time portion (hours, minutes, seconds) of the
* timestamp associated with the incoming image telemetry * timestamp associated with the incoming image telemetry
@ -243,16 +249,38 @@ define(
* @returns {boolean} the current state * @returns {boolean} the current state
*/ */
ImageryController.prototype.paused = function (state) { ImageryController.prototype.paused = function (state) {
if (arguments.length > 0 && state !== this.isPaused) { if (arguments.length > 0 && state !== this.isPaused) {
this.isPaused = state; this.unselectAllImages();
if (this.nextDatum) { this.isPaused = state;
this.updateValues(this.nextDatum); if (this.nextDatum) {
delete this.nextDatum; this.updateValues(this.nextDatum);
} delete this.nextDatum;
} }
return this.isPaused; this.autoScroll = true;
}; }
return this.isPaused;
};
/**
* Set the selected image on the state for the large imagery div to use.
* @param {object} [image] the image object to get url from.
*/
ImageryController.prototype.setSelectedImage = function (image) {
this.imageUrl = this.getImageUrl(image);
this.time = this.getTime(image);
this.paused(true);
this.unselectAllImages();
image.selected = true;
};
/**
* Loop through the history imagery data to set all images to unselected.
*/
ImageryController.prototype.unselectAllImages = function () {
for (var i = 0; i < this.$scope.imageHistory.length; i++) {
this.$scope.imageHistory[i].selected = false;
}
};
return ImageryController; return ImageryController;
} }
); );

View File

@ -226,6 +226,28 @@ define(
expect(controller.updateHistory(mockDatum)).toBe(false); expect(controller.updateHistory(mockDatum)).toBe(false);
expect(controller.updateHistory(mockDatum)).toBe(false); expect(controller.updateHistory(mockDatum)).toBe(false);
}); });
describe("user clicks on imagery thumbnail", function () {
var mockDatum = { utc: 1434600258123, url: 'some/url', selected: false};
it("pauses and adds selected class to imagery thumbnail", function () {
controller.setSelectedImage(mockDatum);
expect(controller.paused()).toBeTruthy();
expect(mockDatum.selected).toBeTruthy();
});
it("unselects previously selected image", function () {
$scope.imageHistory = [{ utc: 1434600258123, url: 'some/url', selected: true}];
controller.unselectAllImages();
expect($scope.imageHistory[0].selected).toBeFalsy();
});
it("updates larger image url and time", function () {
controller.setSelectedImage(mockDatum);
expect(controller.getImageUrl()).toEqual(controller.getImageUrl(mockDatum));
expect(controller.getTime()).toEqual(controller.timeFormat.format(mockDatum.utc));
});
});
}); });
it("initially shows an empty string for date/time", function () { it("initially shows an empty string for date/time", function () {