diff --git a/src/plugins/imagery/ImageryViewProvider.js b/src/plugins/imagery/ImageryViewProvider.js
index 1419990027..2fbc57f365 100644
--- a/src/plugins/imagery/ImageryViewProvider.js
+++ b/src/plugins/imagery/ImageryViewProvider.js
@@ -62,6 +62,9 @@ export default function ImageryViewProvider(openmct) {
destroy: function () {
component.$destroy();
component = undefined;
+ },
+ _getInstance: function () {
+ return component;
}
};
}
diff --git a/src/plugins/imagery/components/ImageryViewLayout.vue b/src/plugins/imagery/components/ImageryViewLayout.vue
index e480824c14..b39f3dbd2a 100644
--- a/src/plugins/imagery/components/ImageryViewLayout.vue
+++ b/src/plugins/imagery/components/ImageryViewLayout.vue
@@ -124,27 +124,40 @@
-
-
-
-
-
{{ image.formattedTime }}
+
+
+
{{ image.formattedTime }}
+
+
+
@@ -171,6 +184,8 @@ const TWENTYFOUR_HOURS = EIGHT_HOURS * 3;
const ARROW_RIGHT = 39;
const ARROW_LEFT = 37;
+const SCROLL_LATENCY = 250;
+
export default {
components: {
Compass
@@ -204,7 +219,8 @@ export default {
focusedImageNaturalAspectRatio: undefined,
imageContainerWidth: undefined,
imageContainerHeight: undefined,
- lockCompass: true
+ lockCompass: true,
+ resizingWindow: false
};
},
computed: {
@@ -380,9 +396,13 @@ export default {
this.imageContainerResizeObserver = new ResizeObserver(this.resizeImageContainer);
this.imageContainerResizeObserver.observe(this.$refs.focusedImage);
- },
- updated() {
- this.scrollToRight();
+
+ // For adjusting scroll bar size and position when resizing thumbs wrapper
+ this.handleScroll = _.debounce(this.handleScroll, SCROLL_LATENCY);
+ this.handleThumbWindowResizeEnded = _.debounce(this.handleThumbWindowResizeEnded, SCROLL_LATENCY);
+
+ this.thumbWrapperResizeObserver = new ResizeObserver(this.handleThumbWindowResizeStart);
+ this.thumbWrapperResizeObserver.observe(this.$refs.thumbsWrapper);
},
beforeDestroy() {
if (this.unsubscribe) {
@@ -394,6 +414,10 @@ export default {
this.imageContainerResizeObserver.disconnect();
}
+ if (this.thumbWrapperResizeObserver) {
+ this.thumbWrapperResizeObserver.disconnect();
+ }
+
if (this.relatedTelemetry.hasRelatedTelemetry) {
this.relatedTelemetry.destroy();
}
@@ -561,17 +585,15 @@ export default {
},
handleScroll() {
const thumbsWrapper = this.$refs.thumbsWrapper;
- if (!thumbsWrapper) {
+ if (!thumbsWrapper || this.resizingWindow) {
return;
}
- const { scrollLeft, scrollWidth, clientWidth, scrollTop, scrollHeight, clientHeight } = thumbsWrapper;
- const disableScroll = (scrollWidth - scrollLeft) > 2 * clientWidth
- || (scrollHeight - scrollTop) > 2 * clientHeight;
+ const { scrollLeft, scrollWidth, clientWidth } = thumbsWrapper;
+ const disableScroll = scrollWidth > Math.ceil(scrollLeft + clientWidth);
this.autoScroll = !disableScroll;
},
paused(state, type) {
-
this.isPaused = state;
if (type === 'button') {
@@ -584,6 +606,7 @@ export default {
}
this.autoScroll = true;
+ this.scrollToRight();
},
scrollToFocused() {
const thumbsWrapper = this.$refs.thumbsWrapper;
@@ -600,8 +623,8 @@ export default {
});
}
},
- scrollToRight() {
- if (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll) {
+ scrollToRight(type) {
+ if (type !== 'reset' && (this.isPaused || !this.$refs.thumbsWrapper || !this.autoScroll)) {
return;
}
@@ -610,7 +633,9 @@ export default {
return;
}
- setTimeout(() => this.$refs.thumbsWrapper.scrollLeft = scrollWidth, 0);
+ this.$nextTick(() => {
+ this.$refs.thumbsWrapper.scrollLeft = scrollWidth;
+ });
},
setFocusedImage(index, thumbnailClick = false) {
if (this.isPaused && !thumbnailClick) {
@@ -678,9 +703,9 @@ export default {
image.imageDownloadName = this.getImageDownloadName(datum);
this.imageHistory.push(image);
-
if (setFocused) {
this.setFocusedImage(this.imageHistory.length - 1);
+ this.scrollToRight();
}
},
getFormatter(key) {
@@ -816,6 +841,24 @@ export default {
this.imageContainerHeight = this.$refs.focusedImage.clientHeight;
}
},
+ handleThumbWindowResizeStart() {
+ if (!this.autoScroll) {
+ return;
+ }
+
+ // To hide resume button while scrolling
+ this.resizingWindow = true;
+ this.handleThumbWindowResizeEnded();
+ },
+ handleThumbWindowResizeEnded() {
+ if (!this.isPaused) {
+ this.scrollToRight('reset');
+ }
+
+ this.$nextTick(() => {
+ this.resizingWindow = false;
+ });
+ },
toggleLockCompass() {
this.lockCompass = !this.lockCompass;
}
diff --git a/src/plugins/imagery/components/imagery-view-layout.scss b/src/plugins/imagery/components/imagery-view-layout.scss
index 8f6fec9dc1..7e45f2bd6d 100644
--- a/src/plugins/imagery/components/imagery-view-layout.scss
+++ b/src/plugins/imagery/components/imagery-view-layout.scss
@@ -93,24 +93,43 @@
}
&__thumbs-wrapper {
- flex: 0 0 auto;
+ display: flex; // Uses row layout
+
+ &.is-autoscroll-off {
+ background: $colorInteriorBorder;
+ [class*='__auto-scroll-resume-button'] {
+ display: block;
+ }
+ }
+
+ &.is-paused {
+ background: rgba($colorPausedBg, 0.4);
+ }
+ }
+
+ &__thumbs-scroll-area {
+ flex: 0 1 auto;
display: flex;
flex-direction: row;
height: 135px;
overflow-x: auto;
overflow-y: hidden;
+ margin-bottom: 1px;
padding-bottom: $interiorMarginSm;
- &.is-paused {
- background: rgba($colorPausedBg, 0.4);
- }
-
.c-thumb:last-child {
// Hilite the lastest thumb
background: $colorBodyFg;
color: $colorBodyBg;
}
}
+
+ &__auto-scroll-resume-button {
+ display: none; // Set to block when __thumbs-wrapper has .is-autoscroll-off
+ flex: 0 0 auto;
+ font-size: 0.8em;
+ margin: $interiorMarginSm;
+ }
}
/*************************************** THUMBS */
@@ -142,7 +161,7 @@
.l-layout,
.c-fl {
- .c-imagery__thumbs-wrapper {
+ .c-imagery__thumbs-scroll-area {
// When Imagery is in a layout, hide the thumbs area
display: none;
}
diff --git a/src/plugins/imagery/pluginSpec.js b/src/plugins/imagery/pluginSpec.js
index 9179692d81..9a73c9ebdb 100644
--- a/src/plugins/imagery/pluginSpec.js
+++ b/src/plugins/imagery/pluginSpec.js
@@ -92,6 +92,7 @@ describe("The Imagery View Layout", () => {
let resolveFunction;
let openmct;
+ let appHolder;
let parent;
let child;
let imageTelemetry = generateTelemetry(START - TEN_MINUTES, COUNT);
@@ -195,7 +196,7 @@ describe("The Imagery View Layout", () => {
// this setups up the app
beforeEach((done) => {
- const appHolder = document.createElement('div');
+ appHolder = document.createElement('div');
appHolder.style.width = '640px';
appHolder.style.height = '480px';
@@ -209,6 +210,8 @@ describe("The Imagery View Layout", () => {
child = document.createElement('div');
parent.appendChild(child);
+ // document.querySelector('body').append(parent);
+
spyOn(window, 'ResizeObserver').and.returnValue({
observe() {},
disconnect() {}
@@ -362,5 +365,21 @@ describe("The Imagery View Layout", () => {
done();
});
});
+ it ('shows an auto scroll button when scroll to left', async () => {
+ // to mock what a scroll would do
+ imageryView._getInstance().$refs.ImageryLayout.autoScroll = false;
+ await Vue.nextTick();
+ let autoScrollButton = parent.querySelector('.c-imagery__auto-scroll-resume-button');
+ expect(autoScrollButton).toBeTruthy();
+ });
+ it ('scrollToRight is called when clicking on auto scroll button', async () => {
+ // use spyon to spy the scroll function
+ spyOn(imageryView._getInstance().$refs.ImageryLayout, 'scrollToRight');
+ imageryView._getInstance().$refs.ImageryLayout.autoScroll = false;
+ await Vue.nextTick();
+ parent.querySelector('.c-imagery__auto-scroll-resume-button').click();
+ expect(imageryView._getInstance().$refs.ImageryLayout.scrollToRight).toHaveBeenCalledWith('reset');
+
+ });
});
});