ui_migration bugfix(component) Added setStreamId prop, img v-show and one pixel fallback to drop jpeg stream connection

This commit is contained in:
Antonio Anaya 2026-06-02 06:38:11 -06:00
parent 702d18552d
commit 60f79a41d8
4 changed files with 61 additions and 14 deletions

View file

@ -5,7 +5,7 @@
<paneControl />
</div>
<div class="view-component uk-width-expand">
<streamDisplay />
<streamDisplay :stream-id="setStreamId" />
</div>
</div>
</template>
@ -21,6 +21,12 @@ export default {
paneControl,
streamDisplay,
},
data() {
return {
setStreamId: "control",
};
},
};
</script>

View file

@ -17,7 +17,7 @@
class="image-fit"
:src="lastStitchedImage"
/>
<streamDisplay v-else />
<streamDisplay v-else :stream-id="setStreamId" />
<template #controls>
<slideScanControls />
<label class="uk-form-label" for="form-stacked-text">Sample ID</label>
@ -81,6 +81,7 @@ export default {
lastStitchedImage: null,
scanComplete: false,
scan_name: "",
setStreamId: "slideScan",
};
},

View file

@ -5,10 +5,9 @@
class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget"
>
<img
v-if="isVisible"
v-show="isVisible && streamEnabled"
ref="click-frame"
class="uk-align-center uk-margin-remove-bottom"
:hidden="!streamEnabled"
:src="streamImgUri"
alt="Stream"
@dblclick="clickMonitor"
@ -36,10 +35,19 @@ import { useIntersectionObserver } from "@vueuse/core";
import { useSettingsStore } from "@/stores/settings.js";
import { mapState } from "pinia";
const ONE_PIXEL_FALLBACK = "data:image/PNG;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";
// Export main app
export default {
name: "StreamDisplay",
props: {
streamId: {
type: [String],
required: true,
},
},
setup() {
const store = useSettingsStore();
return {
@ -66,7 +74,13 @@ export default {
return !(this.displaySize[0] == 0) && !(this.displaySize[1] == 0);
},
streamImgUri: function () {
return `${this.baseUri}/camera/mjpeg_stream`;
// Only request the real stream if it's enabled AND currently visible on screen
if (this.isVisible && this.streamEnabled) {
return `${this.baseUri}/camera/mjpeg_stream`;
}
// Force the browser to kill the connection by loading a 1 pixel image
return ONE_PIXEL_FALLBACK;
},
},
@ -106,9 +120,14 @@ export default {
},
beforeUnmount() {
// Kill the timeout
// Kill the resize timeout
clearTimeout(this.resizeTimeoutId);
// Kill the flash animation timeout (Fixes Beth's MR comment)
if (this.flashTimeoutId) {
clearTimeout(this.flashTimeoutId);
}
// Kill the Intersection Observer
if (this.stopIntersectionObserver) {
this.stopIntersectionObserver();
@ -120,7 +139,7 @@ export default {
// Disconnect the size Observer
if (this.sizeObserver) {
this.sizeObserver.disconnect();
this.store.removeStream(this.$.uid);
this.store.removeStream(this.streamId);
}
},
@ -128,11 +147,26 @@ export default {
flashStream: function () {
// Run an animation that flashes the stream (for capture feedback)
let element = this.$refs.streamDisplay;
// Defensive check in case the ref isn't available
if (!element) return;
element.classList.remove("uk-animation-fade");
element.offsetHeight; /* trigger reflow */
/* trigger reflow */
element.offsetHeight;
element.classList.add("uk-animation-fade");
setTimeout(function () {
element.classList.remove("uk-animation-fade");
// Clear the timer if flashStream is called again before the 800ms is up
if (this.flashTimeoutId) {
clearTimeout(this.flashTimeoutId);
}
// Track the timeout ID
this.flashTimeoutId = setTimeout(() => {
// Extra defensive check just in case
if (element && element.classList) {
element.classList.remove("uk-animation-fade");
}
}, 800);
},
@ -174,12 +208,12 @@ export default {
// Handle closed stream
if (this.displaySize[0] == 0 && this.displaySize[1] == 0) {
// If this stream was previously active
if (this.store.activeStreams[this.$.uid] == true) {
this.store.removeStream(this.$.uid);
if (this.store.activeStreams[this.streamId] == true) {
this.store.removeStream(this.streamId);
}
// If resized to anything other than zero
} else {
this.store.addStream(this.$.uid);
this.store.addStream(this.streamId);
}
},

View file

@ -2,7 +2,7 @@
<!-- Grid managing tab content -->
<div uk-grid class="uk-height-1-1 uk-margin-remove uk-padding-remove">
<div class="view-component uk-width-expand">
<streamDisplay />
<streamDisplay :stream-id="setStreamId" />
</div>
</div>
</template>
@ -16,5 +16,11 @@ export default {
components: {
streamDisplay,
},
data() {
return {
setStreamId: "view",
};
},
};
</script>