Imagery fixes (#2668)

* Fix imagery-related styles and markup

- VERY WIP!!!
- Style modernizing;
- Also, padding fixes for pane.scss - unit test for regressions!

* Fix imagery-related styles and markup

- VERY WIP!!!
- Style modernizing WIP;
- Fixes to pane classes for better padding in vertical panes;

* Fix imagery-related styles and markup

- Migrated all imagery CSS into imagery-view-layout.scss from _legacy
.scss;
- CSS cleanups;
- Refactoring/simplification of thumb layout;
- Color fixed for $colorPausedFg in theme constants;

* Scroll to right instead of bottom, on autoscroll.

* Fix imagery-related styles and markup

- Make the most recent thumb visually distinct;
- Clicking a selected thumb now deselects it and unpauses the view;

* Imagery fixes

- Fixed thumb click logic to properly toggle paused when clicking a selected thumb;
- Improved CSS so that `selected` updates more quickly when selecting the latest thumb;
- Clicking the main image pause button now selects the proper thumb;

* Fix linting errors

Co-authored-by: Nikhil <nikhil.k.mandlik@nasa.gov>
This commit is contained in:
Charles Hacskaylo 2020-02-25 11:47:27 -08:00 committed by GitHub
parent 682601477c
commit a0b7999ea2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 226 additions and 331 deletions

View File

@ -1,90 +1,68 @@
<template>
<multipane class="c-imagery-layout"
type="vertical"
>
<pane :style="{'min-height': `300px`}">
<div class="main-image-wrapper c-imagery has-local-controls">
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc">
<span class="holder flex-elem grows c-imagery__lc__sliders">
<input v-model="filters.brightness"
class="icon-brightness"
type="range"
min="0"
max="500"
>
<input v-model="filters.contrast"
class="icon-contrast"
type="range"
min="0"
max="500"
>
</span>
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn">
<a class="s-icon-button icon-reset t-btn-reset"
@click="filters={brightness: 100, contrast: 100}"
></a>
</span>
</div>
<div class="main-image s-image-main"
:class="{'paused unnsynced': paused(),'stale':false }"
:style="{'background-image': `url(${getImageUrl()})`,
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`}"
>
</div>
<div class="l-image-controller flex-elem l-flex-row">
<div class="l-datetime-w flex-elem grows">
<a class="c-button show-thumbs sm hidden icon-thumbs-strip"></a>
<span class="l-time">{{ getTime() }}</span>
</div>
<div class="h-local-controls flex-elem">
<a class="c-button icon-pause pause-play"
:class="{'is-paused': paused()}"
@click="paused(!paused())"
></a>
</div>
</div>
</div>
</pane>
<pane class="c-inspector__elements"
handle="before"
:style="{'min-height': `100px`}"
>
<div class="c-elements-pool">
<div ref="thumbsWrapper"
class="thumbs-layout"
@scroll="handleScroll"
>
<div v-for="(imageData, index) in imageHistory"
:key="index"
class="l-image-thumb-item"
:class="{selected: imageData.selected}"
@click="setSelectedImage(imageData)"
<div class="c-imagery">
<div class="c-imagery__main-image-wrapper has-local-controls">
<div class="h-local-controls h-local-controls--overlay-content c-local-controls--show-on-hover l-flex-row c-imagery__lc">
<span class="holder flex-elem grows c-imagery__lc__sliders">
<input v-model="filters.brightness"
class="icon-brightness"
type="range"
min="0"
max="500"
>
<img class="l-thumb"
:src="getImageUrl(imageData)"
>
<div class="l-time">{{ getTime(imageData) }}</div>
</div>
<input v-model="filters.contrast"
class="icon-contrast"
type="range"
min="0"
max="500"
>
</span>
<span class="holder flex-elem t-reset-btn-holder c-imagery__lc__reset-btn">
<a class="s-icon-button icon-reset t-btn-reset"
@click="filters={brightness: 100, contrast: 100}"
></a>
</span>
</div>
<div class="main-image s-image-main c-imagery__main-image"
:class="{'paused unnsynced': paused(),'stale':false }"
:style="{'background-image': `url(${getImageUrl()})`,
'filter': `brightness(${filters.brightness}%) contrast(${filters.contrast}%)`}"
>
</div>
<div class="c-imagery__control-bar">
<div class="c-imagery__timestamp">{{ getTime() }}</div>
<div class="h-local-controls flex-elem">
<a class="c-button icon-pause pause-play"
:class="{'is-paused': paused()}"
@click="paused(!paused())"
></a>
</div>
</div>
</pane>
</multipane>
</div>
<div ref="thumbsWrapper"
class="c-imagery__thumbs-wrapper"
:class="{'is-paused': paused()}"
@scroll="handleScroll"
>
<div v-for="(imageData, index) in imageHistory"
:key="index"
class="c-imagery__thumb c-thumb"
:class="{selected: imageData.selected}"
@click="setSelectedImage(imageData)"
>
<img class="c-thumb__image"
:src="getImageUrl(imageData)"
>
<div class="c-thumb__timestamp">{{ getTime(imageData) }}</div>
</div>
</div>
</div>
</template>
<script>
import multipane from '@/ui/layout/multipane.vue';
import pane from '@/ui/layout/pane.vue';
import _ from 'lodash';
export default {
inject: ['openmct', 'domainObject'],
components: {
multipane,
pane
},
data() {
return {
autoScroll: true,
@ -109,7 +87,7 @@ export default {
this.subscribe(this.domainObject);
},
updated() {
this.scrollToBottom();
this.scrollToRight();
},
beforeDestroy() {
this.stopListening();
@ -152,6 +130,10 @@ export default {
if (arguments.length > 0 && state !== this.isPaused) {
this.unselectAllImages();
this.isPaused = state;
if (state === true) {
// If we are pausing, select the latest image in imageHistory
this.setSelectedImage(this.imageHistory[this.imageHistory.length - 1]);
}
if (this.nextDatum) {
this.updateValues(this.nextDatum);
@ -180,24 +162,31 @@ export default {
this.updateValues(values[values.length - 1]);
});
},
scrollToBottom() {
scrollToRight() {
if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) {
return;
}
const scrollHeight = this.$refs.thumbsWrapper.scrollHeight || 0;
if (!scrollHeight) {
const scrollWidth = this.$refs.thumbsWrapper.scrollWidth || 0;
if (!scrollWidth) {
return;
}
setTimeout(() => this.$refs.thumbsWrapper.scrollTop = scrollHeight, 0);
setTimeout(() => this.$refs.thumbsWrapper.scrollLeft = scrollWidth, 0);
},
setSelectedImage(image) {
this.imageUrl = this.getImageUrl(image);
this.time = this.getTime(image);
this.paused(true);
this.unselectAllImages();
image.selected = true;
// If we are paused and the current image IS selected, unpause
// Otherwise, set current image and pause
if (this.isPaused && image.selected) {
this.paused(false);
this.unselectAllImages();
} else {
this.imageUrl = this.getImageUrl(image);
this.time = this.getTime(image);
this.paused(true);
this.unselectAllImages();
image.selected = true;
}
},
stopListening() {
if (this.unsubscribe) {

View File

@ -1,16 +1,20 @@
.c-imagery-layout {
.c-imagery {
display: flex;
flex-direction: column;
overflow: auto;
overflow: hidden;
height: 100%;
.main-image-wrapper {
display: flex;
flex-direction: column;
height: 100%;
padding-bottom: 5px;
> * + * {
margin-top: $interiorMargin;
}
.main-image {
&__main-image-wrapper {
display: flex;
flex-direction: column;
flex: 1 1 auto;
}
&__main-image {
background-position: center;
background-repeat: no-repeat;
background-size: contain;
@ -21,12 +25,137 @@
}
}
.l-image-controller {
&__control-bar {
padding: 5px 0 0 0;
display: flex;
align-items: center;
}
.thumbs-layout {
margin-top: 5px;
overflow: auto;
&__timestamp {
flex: 1 1 auto;
}
&__thumbs-wrapper {
flex: 0 0 auto;
display: flex;
flex-direction: row;
height: 135px;
overflow-x: auto;
overflow-y: hidden;
&.is-paused {
background: rgba($colorPausedBg, 0.4);
}
.c-thumb:last-child {
// Hilite the lastest thumb
background: $colorBodyFg;
color: $colorBodyBg;
}
}
}
/*************************************** THUMBS */
.c-thumb {
display: flex;
flex-direction: column;
padding: 4px;
width: $imageThumbsD;
&:hover {
background: $colorThumbHoverBg;
}
&.selected {
background: $colorPausedBg !important;
color: $colorPausedFg !important;
}
&__image {
background-color: rgba($colorBodyFg, 0.2);
width: 100%;
}
&__timestamp {
flex: 0 0 auto;
padding: 2px 3px;
}
}
.l-layout,
.c-fl {
.c-imagery__thumbs-wrapper {
// When Imagery is in a layout, hide the thumbs area
display: none;
}
}
.s-image-main {
background-color: $colorPlotBg;
border: 1px solid transparent;
}
/*************************************** IMAGERY LOCAL CONTROLS*/
.c-imagery {
.h-local-controls--overlay-content {
position: absolute;
right: $interiorMargin; top: $interiorMargin;
z-index: 2;
background: $colorLocalControlOvrBg;
border-radius: $basicCr;
max-width: 200px;
min-width: 100px;
width: 35%;
align-items: center;
padding: $interiorMargin $interiorMarginLg;
input[type="range"] {
display: block;
width: 100%;
&:not(:first-child) {
margin-top: $interiorMarginLg;
}
&:before {
margin-right: $interiorMarginSm;
}
}
}
&__lc {
&__reset-btn {
$bc: $scrollbarTrackColorBg;
&:before,
&:after {
border-right: 1px solid $bc;
content:'';
display: block;
width: 5px;
height: 4px;
}
&:before {
border-top: 1px solid $bc;
margin-bottom: 2px;
}
&:after {
border-bottom: 1px solid $bc;
margin-top: 2px;
}
}
}
}
/*************************************** BUTTONS */
.c-button.pause-play {
// Pause icon set by default in markup
&.is-paused {
background: $colorPausedBg !important;
color: $colorPausedFg;
&:before {
content: $glyph-icon-play;
}
}
}

View File

@ -120,7 +120,7 @@ $colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
// States
$colorPausedBg: #ff9900;
$colorPausedFg: #fff;
$colorPausedFg: #333;
$colorOk: #33cc33;
// Base variations

View File

@ -124,7 +124,7 @@ $colorFilter: $colorFilterFg; // Standalone against $colorBodyBg
// States
$colorPausedBg: #ff9900;
$colorPausedFg: #fff;
$colorPausedFg: #333;
$colorOk: #33cc33;
// Base variations

View File

@ -52,236 +52,6 @@
}
}
/******************************************************************* IMAGERY */
.l-image-main-wrapper,
.l-image-thumbs-wrapper,
.image-main {
@include abs(0);
overflow: hidden;
}
/*************************************** MAIN LAYOUT */
.l-image-main-wrapper {
// Imagery thumbs
bottom: $interiorMargin*2 + $imageThumbsWrapperH;
min-width: 150px;
.l-image-main {
margin-bottom: $interiorMargin;
}
.l-image-main-controlbar {
&.l-flex-row { align-items: center; }
}
}
.l-image-thumbs-wrapper {
top: auto;
min-height: $imageThumbsWrapperH;
max-height: 60%;
box-sizing: border-box;
}
.l-date,
.l-time,
.l-timezone {
display: inline-block;
}
/*************************************** MAIN IMAGE */
.image-main,
.l-image-thumb-item .l-thumb {
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
.l-image-main-controlbar {
line-height: inherit;
.l-datetime-w, .l-controls-w {
direction: rtl;
overflow: hidden;
}
.l-datetime-w {
@include ellipsize();
margin-right: $interiorMarginSm;
text-align: left;
}
.l-controls-w {
z-index: 2;
}
.l-date,
.l-time {
color: pullForward($colorBodyFg, 20%); // TODO: do this as a theme constant
}
.l-mag {
direction: ltr;
display: inline-block;
&:before {
content: "\000049";
}
}
.s-mag {
color: pushBack($colorBodyFg, 20%); // TODO: do this as a theme constant
}
.l-btn.show-thumbs {
display: none;
}
}
.s-image-main {
background-color: $colorPlotBg;
border: 1px solid transparent;
&.paused {
//@include sUnsynced();
}
}
/*************************************** THUMBS */
.l-image-thumbs-wrapper {
overflow-x: hidden;
overflow-y: auto;
padding-bottom: $interiorMargin;
white-space: nowrap;
}
.l-image-thumb-item {
transition: background-color 0.25s;
box-sizing: border-box;
cursor: pointer;
direction: ltr;
display: inline-block;
float: left;
padding: 1px;
margin-left: $interiorMarginSm;
position: relative;
text-align: left;
width: $imageThumbsD + $imageThumbPad*2;
white-space: normal;
.l-thumb,
.l-date,
.l-time {
display: inline-block;
}
.l-date,
.l-time {
padding: 2px 3px;
}
&:hover {
background: $colorThumbHoverBg;
.l-date,
.l-time {
color: #fff;
}
}
&.selected {
background: $colorKeySelectedBg;
.l-date,
.l-time {
color: #fff;
}
}
.l-thumb {
background-color: rgba(#fff, 0.1);
height: $imageThumbsD;
width: $imageThumbsD;
margin-top: 0;
}
}
/*************************************** LOCAL CONTROLS */
.c-imagery {
display: contents;
.h-local-controls--overlay-content {
position: absolute;
right: $interiorMargin; top: $interiorMargin;
z-index: 2;
background: $colorLocalControlOvrBg;
border-radius: $basicCr;
max-width: 200px;
min-width: 100px;
width: 35%;
align-items: center;
padding: $interiorMargin $interiorMarginLg;
input[type="range"] {
display: block;
width: 100%;
&:not(:first-child) {
margin-top: $interiorMarginLg;
}
&:before {
margin-right: $interiorMarginSm;
}
}
}
&__lc {
&__reset-btn {
$bc: $scrollbarTrackColorBg;
&:before,
&:after {
border-right: 1px solid $bc;
content:'';
display: block;
width: 5px;
height: 4px;
}
&:before {
border-top: 1px solid $bc;
margin-bottom: 2px;
}
&:after {
border-bottom: 1px solid $bc;
margin-top: 2px;
}
}
}
}
/*************************************** WHEN IN FRAME */
.c-frame .t-imagery {
.l-image-main-wrapper {
bottom: 0 !important;
height: 100% !important;
.l-image-main-controlbar .c-button {
//font-size: 0.7em;
}
}
.l-image-thumbs-wrapper,
mct-splitter {
display: none;
}
}
/*************************************** MOBILE */
body.mobile.phone {
.t-imagery {
.l-image-main-wrapper,
.l-image-thumbs-wrapper {
min-height: 10px !important;
}
}
}
.c-button.pause-play {
// Pause icon set by default in markup
&.is-paused {
background: $colorPausedBg !important;
color: $colorPausedFg;
&:before {
content: $glyph-icon-play;
}
}
}
/*********************************************************************** CLOCKS AND TIMERS */
.c-clock,
.c-timer {

View File

@ -62,6 +62,8 @@
}
&[class*="--horizontal"] {
padding-left: $interiorMargin;
padding-right: $interiorMargin;
&.l-pane--collapsed {
padding-left: 0 !important;
padding-right: 0 !important;
@ -69,9 +71,11 @@
}
&[class*="--vertical"] {
padding-top: $interiorMargin;
padding-bottom: $interiorMargin;
&.l-pane--collapsed {
padding-top: 0 !important;
padding-top: 0 !important;
padding-bottom: 0 !important;
}
}
@ -277,6 +281,9 @@
/************************** Vertical Splitter Before */
// Pane collapses downward. Used by Elements pool in Inspector
&[class*="-before"] {
$m: $interiorMarginLg;
margin-top: $m;
padding-top: $m;
> .l-pane__handle {
top: 0;
transform: translateY(floor($splitterHandleD / -1));