Merge branch 'goal_1' into v3
This commit is contained in:
commit
f4a10ec897
53 changed files with 2534 additions and 10836 deletions
|
|
@ -1,4 +1,4 @@
|
|||
<template>
|
||||
<template :key="shortcut.shortcut">
|
||||
<div id="app" class="uk-height-1-1 uk-margin-remove uk-padding-remove" :class="handleTheme">
|
||||
<!-- this stops the app loading until setConnected is committed in the store, this means
|
||||
other components will not load until we have Thing Descriptions. -->
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
<button class="uk-modal-close-default" type="button" uk-close></button>
|
||||
<div
|
||||
v-for="shortcut in keyboardManual"
|
||||
:key="shortcut.shortcut"
|
||||
class="uk-margin-small"
|
||||
uk-grid
|
||||
>
|
||||
|
|
@ -26,10 +25,12 @@
|
|||
// Import components
|
||||
import appContent from "./components/appContent.vue";
|
||||
import loadingContent from "./components/loadingContent.vue";
|
||||
import MouseTrap from "mousetrap";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
import { eventBus } from "./eventBus.js";
|
||||
|
||||
var Mousetrap = require("mousetrap");
|
||||
|
||||
Mousetrap.prototype.stopCallback = function (e, element) {
|
||||
MouseTrap.prototype.stopCallback = function (e, element) {
|
||||
// if the element has the class "mousetrap" then no need to stop
|
||||
if ((" " + element.className + " ").indexOf(" mousetrap ") > -1) {
|
||||
return false;
|
||||
|
|
@ -55,7 +56,7 @@ export default {
|
|||
|
||||
components: {
|
||||
appContent,
|
||||
loadingContent,
|
||||
loadingContent
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -153,10 +154,10 @@ export default {
|
|||
|
||||
// Focus keys
|
||||
Mousetrap.bind("pageup", () => {
|
||||
this.$root.$emit("globalMoveStepEvent", 0, 0, 1);
|
||||
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: 1});
|
||||
});
|
||||
Mousetrap.bind("pagedown", () => {
|
||||
this.$root.$emit("globalMoveStepEvent", 0, 0, -1);
|
||||
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: -1});
|
||||
});
|
||||
this.keyboardManual.push({
|
||||
shortcut: "pgup / pgdn",
|
||||
|
|
@ -165,7 +166,7 @@ export default {
|
|||
|
||||
// Capture
|
||||
Mousetrap.bind("c", () => {
|
||||
this.$root.$emit("globalCaptureEvent");
|
||||
eventBus.emit("globalCaptureEvent", {});
|
||||
});
|
||||
this.keyboardManual.push({
|
||||
shortcut: "c",
|
||||
|
|
@ -174,7 +175,7 @@ export default {
|
|||
|
||||
// Autofocus
|
||||
Mousetrap.bind("a", () => {
|
||||
this.$root.$emit("globalFastAutofocusEvent");
|
||||
eventBus.emit("globalFastAutofocusEvent", {});
|
||||
});
|
||||
this.keyboardManual.push({
|
||||
shortcut: "a",
|
||||
|
|
@ -183,10 +184,10 @@ export default {
|
|||
|
||||
// Increment/decrement tab
|
||||
Mousetrap.bind("shift+down", () => {
|
||||
this.$root.$emit("globalIncrementTab");
|
||||
eventBus.emit("globalIncrementTab", {});
|
||||
});
|
||||
Mousetrap.bind("shift+up", () => {
|
||||
this.$root.$emit("globalDecrementTab");
|
||||
eventBus.emit("globalDecrementTab", {});
|
||||
});
|
||||
this.keyboardManual.push({
|
||||
shortcut: "shift+↑ / shift+↓",
|
||||
|
|
@ -194,7 +195,7 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
beforeDestroy: function () {
|
||||
beforeUnmount: function () {
|
||||
// Disconnect the theme observer
|
||||
if (this.themeObserver) {
|
||||
this.themeObserver.disconnect();
|
||||
|
|
@ -237,7 +238,7 @@ export default {
|
|||
}
|
||||
},
|
||||
handleExit: function () {
|
||||
this.$root.$emit("globalTogglePreview", false);
|
||||
eventBus.emit("globalTogglePreview", false);
|
||||
},
|
||||
|
||||
// Handle global mouse wheel events to be associated with navigation
|
||||
|
|
@ -249,7 +250,7 @@ export default {
|
|||
) {
|
||||
var z_rel = event.deltaY / 100;
|
||||
// Emit a signal to move, acted on by panelControl.vue
|
||||
this.$root.$emit("globalMoveStepEvent", 0, 0, z_rel, false);
|
||||
eventBus.emit("globalMoveStepEvent", {x: 0, y: 0, z: z_rel, absolute: false});
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -276,7 +277,7 @@ export default {
|
|||
}
|
||||
// Make a position request
|
||||
// Emit a signal to move, acted on by panelControl.vue
|
||||
this.$root.$emit("globalMoveStepEvent", x_rel, y_rel, z_rel);
|
||||
eventBus.emit("globalMoveStepEvent", {x: x_rel, y: y_rel, z: 0});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
class="uk-flex uk-flex-column uk-padding-remove uk-width-auto uk-height-1-1 uk-text-center"
|
||||
>
|
||||
<!-- For each top tab -->
|
||||
<template v-for="(item, index) in topTabs">
|
||||
<template v-for="(item, index) in topTabs" :key="item.id + '-tab-icon'">
|
||||
<!-- Render the tab icon -->
|
||||
<tabIcon
|
||||
:id="item.id + '-tab-icon'"
|
||||
:key="item.id + '-tab-icon'"
|
||||
:tab-i-d="item.id"
|
||||
:title="item.title"
|
||||
:require-connection="true"
|
||||
|
|
@ -37,11 +36,10 @@
|
|||
<hr id="extension-tab-divider" />
|
||||
|
||||
<!-- For each bottom tab -->
|
||||
<template v-for="(item, index) in bottomTabs">
|
||||
<template v-for="(item, index) in bottomTabs" :key="item.id + '-tab-icon'">
|
||||
<!-- Render the tab icon -->
|
||||
<tabIcon
|
||||
:id="item.id + '-tab-icon'"
|
||||
:key="item.id + '-tab-icon'"
|
||||
:tab-i-d="item.id"
|
||||
:title="item.title"
|
||||
:require-connection="true"
|
||||
|
|
@ -79,8 +77,8 @@
|
|||
|
||||
<script>
|
||||
// Import generic components
|
||||
import tabIcon from "./genericComponents/tabIcon";
|
||||
import tabContent from "./genericComponents/tabContent";
|
||||
import tabIcon from "./genericComponents/tabIcon.vue";
|
||||
import tabContent from "./genericComponents/tabContent.vue";
|
||||
|
||||
// Import new content components
|
||||
import aboutContent from "./tabContentComponents/aboutContent.vue";
|
||||
|
|
@ -92,6 +90,9 @@ import scanListContent from "./tabContentComponents/scanListContent.vue";
|
|||
import settingsContent from "./tabContentComponents/settingsContent.vue";
|
||||
import slideScanContent from "./tabContentComponents/slideScanContent.vue";
|
||||
import viewContent from "./tabContentComponents/viewContent.vue";
|
||||
// vue3 migration
|
||||
import { shallowRef, markRaw, ref } from 'vue'
|
||||
import { eventBus } from "../eventBus.js";
|
||||
|
||||
// Import modal components for device initialisation
|
||||
import calibrationWizard from "./modalComponents/calibrationWizard.vue";
|
||||
|
|
@ -103,7 +104,7 @@ export default {
|
|||
components: {
|
||||
tabIcon,
|
||||
tabContent,
|
||||
calibrationWizard,
|
||||
calibrationWizard
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
|
|
@ -113,26 +114,26 @@ export default {
|
|||
id: "settings",
|
||||
title: "Settings",
|
||||
icon: "settings",
|
||||
component: settingsContent,
|
||||
component: markRaw(settingsContent),
|
||||
class: "uk-margin-auto-top",
|
||||
},
|
||||
{
|
||||
id: "logging",
|
||||
title: "Logging",
|
||||
icon: "assignment_late",
|
||||
component: loggingContent,
|
||||
component: markRaw(loggingContent),
|
||||
},
|
||||
{
|
||||
id: "about",
|
||||
title: "About",
|
||||
icon: "info",
|
||||
component: aboutContent,
|
||||
component: markRaw(aboutContent),
|
||||
},
|
||||
{
|
||||
id: "power",
|
||||
title: "Power",
|
||||
icon: "power_settings_new",
|
||||
component: powerContent,
|
||||
component: markRaw(powerContent),
|
||||
},
|
||||
],
|
||||
coreTopTabs: [
|
||||
|
|
@ -140,21 +141,21 @@ export default {
|
|||
id: "view",
|
||||
title: "View",
|
||||
icon: "visibility",
|
||||
component: viewContent,
|
||||
component: markRaw(viewContent),
|
||||
requiredThings: [],
|
||||
},
|
||||
{
|
||||
id: "control",
|
||||
title: "Control",
|
||||
icon: "gamepad",
|
||||
component: controlContent,
|
||||
component: markRaw(controlContent),
|
||||
requiredThings: [],
|
||||
},
|
||||
{
|
||||
id: "background-detect",
|
||||
title: "Background Detect",
|
||||
icon: "background_replace",
|
||||
component: backgroundDetectContent,
|
||||
component: markRaw(backgroundDetectContent),
|
||||
// While stage isn't needed; automatic background detect has little function
|
||||
// for a manual microscope.
|
||||
requiredThings: ["stage"],
|
||||
|
|
@ -163,14 +164,14 @@ export default {
|
|||
id: "slide-scan",
|
||||
title: "Slide Scan",
|
||||
icon: "settings_overscan",
|
||||
component: slideScanContent,
|
||||
component: markRaw(slideScanContent),
|
||||
requiredThings: ["smart_scan"],
|
||||
},
|
||||
{
|
||||
id: "scan-list",
|
||||
title: "Scan List",
|
||||
icon: "photo_library",
|
||||
component: scanListContent,
|
||||
component: markRaw(scanListContent),
|
||||
requiredThings: ["smart_scan"],
|
||||
},
|
||||
],
|
||||
|
|
@ -207,15 +208,15 @@ export default {
|
|||
|
||||
mounted() {
|
||||
// A global signal listener to switch tab
|
||||
this.$root.$on("globalSwitchTab", (tabID) => {
|
||||
eventBus.on("globalSwitchTab", (tabID) => {
|
||||
this.currentTab = tabID;
|
||||
});
|
||||
// A global signal listener to increment tab
|
||||
this.$root.$on("globalIncrementTab", () => {
|
||||
eventBus.on("globalIncrementTab", () => {
|
||||
this.incrementTabBy(1);
|
||||
});
|
||||
// A global signal listener to decrement tab
|
||||
this.$root.$on("globalDecrementTab", () => {
|
||||
eventBus.on("globalDecrementTab", () => {
|
||||
this.incrementTabBy(-1);
|
||||
});
|
||||
if (this.$store.getters.ready) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
<div
|
||||
id="stream-display"
|
||||
ref="streamDisplay"
|
||||
v-observe-visibility="visibilityChanged"
|
||||
class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget"
|
||||
>
|
||||
<img
|
||||
|
|
@ -16,6 +15,9 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
//vue3 migration
|
||||
import { useIntersectionObserver } from '@vueuse/core';
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "MiniStreamDisplay",
|
||||
|
|
@ -31,10 +33,17 @@ export default {
|
|||
return `${this.$store.getters.baseUri}/camera/mjpeg_stream`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
this.isVisible = isVisible;
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.streamDisplay,
|
||||
([{ isIntersecting }]) => {
|
||||
this.isVisible = isIntersecting;
|
||||
},
|
||||
{
|
||||
threshold: 0.0,
|
||||
}
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,11 @@
|
|||
<template>
|
||||
<a href="#" class="uk-link" :class="classObject" :uk-tooltip="tooltipOptions" @click="setThisTab">
|
||||
<a
|
||||
href="#"
|
||||
class="uk-link"
|
||||
:class="classObject"
|
||||
:uk-tooltip="tooltipOptions ? tooltipOptions : null"
|
||||
@click="setThisTab"
|
||||
>
|
||||
<slot></slot>
|
||||
<div v-if="showTitle" class="tabtitle">
|
||||
{{ computedTitle }}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<div v-observe-visibility="visibilityChanged" class="uk-margin-remove uk-padding-remove">
|
||||
<div class="uk-margin-remove uk-padding-remove">
|
||||
<button
|
||||
ref="actionButton"
|
||||
type="button"
|
||||
:disabled="buttonDisabled"
|
||||
class="uk-button uk-width-1-1 uk-position-relative"
|
||||
|
|
@ -28,10 +29,34 @@
|
|||
<script>
|
||||
import ActionProgressBar from "./actionProgressBar.vue";
|
||||
import ActionStatusModal from "./actionStatusModal.vue";
|
||||
//vue3 migration
|
||||
import { eventBus } from "../../eventBus.js";
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
|
||||
export default {
|
||||
name: "ActionButton",
|
||||
components: { ActionProgressBar, ActionStatusModal },
|
||||
|
||||
emits: [
|
||||
'update:progress',
|
||||
'update:taskStarted',
|
||||
'update:taskRunning',
|
||||
'update:log',
|
||||
'update:taskStatus',
|
||||
'submit',
|
||||
'taskStarted',
|
||||
'taskRunning',
|
||||
'response',
|
||||
'completed',
|
||||
'cancelled',
|
||||
'finished',
|
||||
'error'
|
||||
],
|
||||
|
||||
components: {
|
||||
ActionProgressBar,
|
||||
ActionStatusModal
|
||||
},
|
||||
|
||||
props: {
|
||||
action: {
|
||||
|
|
@ -129,31 +154,52 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
progress(newval) {
|
||||
this.$emit("update:progress", newval);
|
||||
progress: {
|
||||
handler(newval) {
|
||||
this.$emit("update:progress", newval);
|
||||
},
|
||||
},
|
||||
taskStarted(newval) {
|
||||
this.$emit("update:taskStarted", newval);
|
||||
taskStarted: {
|
||||
handler(newval) {
|
||||
this.$emit("update:taskStarted", newval);
|
||||
},
|
||||
},
|
||||
taskRunning(newval) {
|
||||
this.$emit("update:taskRunning", newval);
|
||||
taskRunning: {
|
||||
handler(newval) {
|
||||
this.$emit("update:taskRunning", newval);
|
||||
},
|
||||
},
|
||||
log(newval) {
|
||||
this.$emit("update:log", newval);
|
||||
log: {
|
||||
handler(newval) {
|
||||
this.$emit("update:log", newval);
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
taskStatus(newval) {
|
||||
this.$emit("update:taskStatus", newval);
|
||||
},
|
||||
},
|
||||
taskStatus: {
|
||||
handler(newval) {
|
||||
this.$emit("update:taskStatus", newval);
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.actionButton,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{
|
||||
threshold: 0.0, // Adjust as needed
|
||||
},
|
||||
);
|
||||
|
||||
// Check for already running tasks
|
||||
if (this.taskStarted != true) {
|
||||
this.checkExistingTasks();
|
||||
}
|
||||
// A global signal listener to perform the action
|
||||
if (this.submitOnEvent) {
|
||||
this.$root.$on(this.submitOnEvent, () => {
|
||||
eventBus.on(this.submitOnEvent, () => {
|
||||
if (this.isDisabled) return;
|
||||
// Bootstrap task if button is not disabled.
|
||||
this.bootstrapTask();
|
||||
|
|
@ -161,9 +207,9 @@ export default {
|
|||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
if (this.submitOnEvent) {
|
||||
this.$root.$off(this.submitOnEvent);
|
||||
eventBus.off(this.submitOnEvent);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -222,6 +268,7 @@ export default {
|
|||
|
||||
async startTask() {
|
||||
// Starts a new Action task
|
||||
console.log("Starting task with data:", this.submitData);
|
||||
this.$emit("submit", this.submitData);
|
||||
// Send a request to start a task
|
||||
this.taskStarted = true;
|
||||
|
|
|
|||
|
|
@ -60,11 +60,16 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
log: function () {
|
||||
this.scrollToBottom();
|
||||
log: {
|
||||
handler() {
|
||||
this.scrollToBottom();
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
taskStatus: function () {
|
||||
this.scrollToBottom();
|
||||
taskStatus: {
|
||||
handler() {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -28,11 +28,15 @@
|
|||
import UIkit from "uikit";
|
||||
import ActionProgressBar from "./actionProgressBar.vue";
|
||||
import ActionLogDisplay from "./actionLogDisplay.vue";
|
||||
// vue3 migration
|
||||
import { eventBus } from "../../eventBus.js";
|
||||
|
||||
export default {
|
||||
name: "ActionStatusModal",
|
||||
components: { ActionProgressBar, ActionLogDisplay },
|
||||
|
||||
components: {
|
||||
ActionProgressBar,
|
||||
ActionLogDisplay
|
||||
},
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
|
|
@ -71,7 +75,7 @@ export default {
|
|||
},
|
||||
hide() {
|
||||
UIkit.modal(this.$refs.modal).hide();
|
||||
this.$root.$emit("modalClosed");
|
||||
eventBus.emit("modalClosed");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -100,12 +100,13 @@
|
|||
|
||||
<script>
|
||||
import syncPropertyButton from "./syncPropertyButton.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "InputFromSchema",
|
||||
|
||||
components: {
|
||||
syncPropertyButton,
|
||||
syncPropertyButton
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -113,9 +114,10 @@ export default {
|
|||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
modelValue: {
|
||||
type: null,
|
||||
required: true,
|
||||
required: false,
|
||||
default: undefined,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
|
|
@ -133,11 +135,11 @@ export default {
|
|||
// the value is an array or object. For future updates we stringify and parse
|
||||
// (see resetInternalValue). If we do this here there is a chance we get errors
|
||||
// as internalValue is still null when rendering starts.
|
||||
internalValue: Array.isArray(this.value)
|
||||
? [...this.value]
|
||||
: typeof this.value === "object"
|
||||
? { ...this.value }
|
||||
: this.value,
|
||||
internalValue: Array.isArray(this.modelValue)
|
||||
? [...this.modelValue]
|
||||
: typeof this.modelValue === "object"
|
||||
? { ...this.modelValue }
|
||||
: this.modelValue,
|
||||
// Is edited can't be computed as we mutate internalValue
|
||||
isEdited: false,
|
||||
animateUpdate: false,
|
||||
|
|
@ -206,14 +208,18 @@ export default {
|
|||
},
|
||||
|
||||
watch: {
|
||||
value() {
|
||||
// Fire updateIsEdited on both value and internal value change,
|
||||
// as change in value may not causse internalValue to change.
|
||||
this.updateIsEdited();
|
||||
this.resetInternalValue();
|
||||
modelValue: {
|
||||
handler() {
|
||||
// Fire updateIsEdited on both value and internal value change,
|
||||
// as change in value may not causse internalValue to change.
|
||||
this.updateIsEdited();
|
||||
this.resetInternalValue();
|
||||
},
|
||||
},
|
||||
internalValue() {
|
||||
this.updateIsEdited();
|
||||
internalValue: {
|
||||
handler() {
|
||||
this.updateIsEdited();
|
||||
},
|
||||
},
|
||||
animate(updated) {
|
||||
if (updated) {
|
||||
|
|
@ -223,7 +229,7 @@ export default {
|
|||
},
|
||||
|
||||
mounted() {
|
||||
if (this.value !== undefined) {
|
||||
if (this.modelValue !== undefined) {
|
||||
this.resetInternalValue();
|
||||
}
|
||||
},
|
||||
|
|
@ -233,7 +239,7 @@ export default {
|
|||
// Whenever updatirng th internal value stringify and parse as a form of deepcopy.
|
||||
// This ensure that the this.value prop is not mutated for when elements of arrays
|
||||
// or objects are updated.
|
||||
this.internalValue = JSON.parse(JSON.stringify(this.value));
|
||||
this.internalValue = JSON.parse(JSON.stringify(this.modelValue));
|
||||
},
|
||||
requestUpdate: async function () {
|
||||
this.$emit("requestUpdate");
|
||||
|
|
@ -262,7 +268,7 @@ export default {
|
|||
}
|
||||
},
|
||||
updateIsEdited: function () {
|
||||
this.isEdited = this.deepStringify(this.internalValue) !== this.deepStringify(this.value);
|
||||
this.isEdited = this.deepStringify(this.internalValue) !== this.deepStringify(this.modelValue);
|
||||
},
|
||||
animationEnd: function () {
|
||||
this.animateUpdate = false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<input-from-schema
|
||||
v-model="value"
|
||||
v-model="modelValue"
|
||||
:data-schema="propertyDescription"
|
||||
:label="label"
|
||||
:animate="animate"
|
||||
|
|
@ -13,12 +13,14 @@
|
|||
<script>
|
||||
import { formatValue } from "@/js_utils/formatter.mjs";
|
||||
import InputFromSchema from "./inputFromSchema.vue";
|
||||
// vue3 migration
|
||||
|
||||
|
||||
export default {
|
||||
name: "PropertyControl",
|
||||
|
||||
components: {
|
||||
InputFromSchema,
|
||||
InputFromSchema
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -48,7 +50,7 @@ export default {
|
|||
|
||||
data() {
|
||||
return {
|
||||
value: undefined,
|
||||
modelValue: undefined,
|
||||
animate: false,
|
||||
};
|
||||
},
|
||||
|
|
@ -74,7 +76,7 @@ export default {
|
|||
// Read the property when we're mounted - usually this won't
|
||||
// work because the URL isn't set yet. However, it's helpful if
|
||||
// the app is reloaded (e.g. from a dev server).
|
||||
if (this.value == undefined) {
|
||||
if (this.modelValue == undefined) {
|
||||
this.readProperty();
|
||||
}
|
||||
},
|
||||
|
|
@ -82,12 +84,12 @@ export default {
|
|||
methods: {
|
||||
readProperty: async function () {
|
||||
let data = await this.readThingProperty(this.thingName, this.propertyName);
|
||||
this.value = data;
|
||||
this.modelValue = data;
|
||||
return data;
|
||||
},
|
||||
writeProperty: async function (requestedValue) {
|
||||
try {
|
||||
this.value = requestedValue;
|
||||
this.modelValue = requestedValue;
|
||||
await this.writeThingProperty(this.thingName, this.propertyName, requestedValue);
|
||||
if (this.readBack) {
|
||||
await new Promise((r) => setTimeout(r, this.readBackDelay));
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@
|
|||
|
||||
<script>
|
||||
import ActionButton from "./actionButton.vue";
|
||||
// vue3 migration
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "ServerSpecifiedActionButton",
|
||||
|
||||
components: {
|
||||
ActionButton,
|
||||
ActionButton
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -11,13 +11,14 @@
|
|||
|
||||
<script>
|
||||
import PropertyControl from "./propertyControl.vue";
|
||||
// vue3 migration
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "ServerSpecifiedPropertyControl",
|
||||
|
||||
components: {
|
||||
PropertyControl,
|
||||
PropertyControl
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -14,12 +14,16 @@
|
|||
|
||||
<script>
|
||||
import devTools from "./tabContentComponents/aboutComponents/devTools.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "LoadingContent",
|
||||
|
||||
components: { devTools },
|
||||
components: {
|
||||
devTools
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {};
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
<h2 class="uk-modal-title">Microscope Calibration</h2>
|
||||
|
||||
<component
|
||||
v-bind="currentTask.props"
|
||||
:is="currentTask.component"
|
||||
v-if="currentTask"
|
||||
:key="taskIndex"
|
||||
v-bind="currentTask.props"
|
||||
:first="isFirstTask"
|
||||
:final="isFinalTask"
|
||||
:start-on-last="movingBackward"
|
||||
|
|
@ -28,7 +28,13 @@ import finalStep from "./calibrationWizardComponents/finalStep.vue";
|
|||
export default {
|
||||
name: "CalibrationWizard",
|
||||
|
||||
components: {},
|
||||
components: {
|
||||
singleStepTask,
|
||||
welcomeStep,
|
||||
cameraCalibrationTask,
|
||||
cameraStageMappingTask,
|
||||
finalStep
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ gets very confusing.
|
|||
<div>
|
||||
<h3 v-if="title">{{ title }}</h3>
|
||||
<component
|
||||
v-bind="currentStep.props"
|
||||
:is="currentStep.component"
|
||||
v-if="currentStep"
|
||||
:key="stepIndex"
|
||||
v-bind="currentStep.props"
|
||||
@awaiting-user="handleAwaitingUser"
|
||||
/>
|
||||
<p class="uk-text-right">
|
||||
|
|
|
|||
|
|
@ -19,13 +19,14 @@
|
|||
<script>
|
||||
import stepTemplateWithStream from "../stepTemplateWithStream.vue";
|
||||
import cameraCalibrationSettings from "../../../tabContentComponents/settingsComponents/cameraSettingsComponents/cameraCalibrationSettings.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "CameraMainCalibrationStep",
|
||||
|
||||
components: {
|
||||
stepTemplateWithStream,
|
||||
cameraCalibrationSettings,
|
||||
cameraCalibrationSettings
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -14,10 +14,13 @@
|
|||
import calibrationWizardTask from "./calibrationWizardTask.vue";
|
||||
import camCalibrationExplanation from "./cameraCalibrationSteps/camCalibrationExplanation.vue";
|
||||
import cameraMainCalibrationStep from "./cameraCalibrationSteps/cameraMainCalibrationStep.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
export default {
|
||||
name: "CameraCalibrationTask",
|
||||
components: { calibrationWizardTask },
|
||||
components: {
|
||||
calibrationWizardTask},
|
||||
props: {
|
||||
// Standard calibrationWizardTask props below:
|
||||
first: Boolean,
|
||||
|
|
@ -30,7 +33,7 @@ export default {
|
|||
|
||||
data: function () {
|
||||
return {
|
||||
steps: [{ component: camCalibrationExplanation }, { component: cameraMainCalibrationStep }],
|
||||
steps: [{ component: markRaw(camCalibrationExplanation) }, { component: markRaw(cameraMainCalibrationStep)}],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,10 +15,14 @@ import calibrationWizardTask from "./calibrationWizardTask.vue";
|
|||
import csmExplanation from "./csmSteps/csmExplanation.vue";
|
||||
import focusStep from "./csmSteps/focusStep.vue";
|
||||
import runCsmStep from "./csmSteps/runCsmStep.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
export default {
|
||||
name: "CameraCalibrationTask",
|
||||
components: { calibrationWizardTask },
|
||||
components: {
|
||||
calibrationWizardTask
|
||||
},
|
||||
props: {
|
||||
// Standard calibrationWizardTask props below:
|
||||
first: Boolean,
|
||||
|
|
@ -31,7 +35,7 @@ export default {
|
|||
|
||||
data: function () {
|
||||
return {
|
||||
steps: [{ component: csmExplanation }, { component: focusStep }, { component: runCsmStep }],
|
||||
steps: [{ component: markRaw(csmExplanation) }, { component: markRaw(focusStep) }, { component: markRaw(runCsmStep) }],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@
|
|||
<script>
|
||||
import stepTemplateWithStream from "../stepTemplateWithStream.vue";
|
||||
import ActionButton from "../../../labThingsComponents/actionButton.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "CameraMainCalibrationStep",
|
||||
|
||||
components: {
|
||||
stepTemplateWithStream,
|
||||
ActionButton,
|
||||
ActionButton
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -47,7 +49,7 @@ export default {
|
|||
gap: 8px; /* Small space between buttons */
|
||||
margin-top: 4px; /* Gap from image */
|
||||
}
|
||||
.moveZ >>> .uk-button.uk-width-1-1 {
|
||||
.moveZ :deep(.uk-button.uk-width-1-1) {
|
||||
line-height: 50px;
|
||||
font-size: 50px !important;
|
||||
height: 60px;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
<script>
|
||||
import stepTemplateWithStream from "../stepTemplateWithStream.vue";
|
||||
import CSMCalibrationSettings from "../../../tabContentComponents/settingsComponents/CSMSettingsComponents/CSMCalibrationSettings.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "CameraMainCalibrationStep",
|
||||
|
|
|
|||
|
|
@ -24,10 +24,14 @@ supplied by the wizard.
|
|||
|
||||
<script>
|
||||
import calibrationWizardTask from "./calibrationWizardTask.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
export default {
|
||||
name: "SingleStepTask",
|
||||
components: { calibrationWizardTask },
|
||||
components: {
|
||||
calibrationWizardTask
|
||||
},
|
||||
props: {
|
||||
// This must be sent
|
||||
stepComponent: {
|
||||
|
|
@ -54,7 +58,7 @@ export default {
|
|||
|
||||
data: function () {
|
||||
return {
|
||||
steps: [{ component: this.stepComponent, props: this.stepProps }],
|
||||
steps: [{ component: markRaw(this.stepComponent), props: this.stepProps }],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
<script>
|
||||
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "StepTemplateWithStream",
|
||||
|
||||
components: {
|
||||
miniStreamDisplay,
|
||||
miniStreamDisplay
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -64,10 +64,13 @@
|
|||
|
||||
<script>
|
||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "StatusPane",
|
||||
components: { ActionButton },
|
||||
components: {
|
||||
ActionButton
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -24,13 +24,14 @@
|
|||
<script>
|
||||
import devTools from "./aboutComponents/devTools.vue";
|
||||
import statusPane from "./aboutComponents/statusPane.vue";
|
||||
//vue3 migration
|
||||
|
||||
export default {
|
||||
name: "AboutContent",
|
||||
|
||||
components: {
|
||||
devTools,
|
||||
statusPane,
|
||||
statusPane
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div v-observe-visibility="visibilityChanged" class="uk-padding-small">
|
||||
<div ref="backgroundDetectContent" class="uk-padding-small">
|
||||
<div>
|
||||
<ul uk-accordion="multiple: true">
|
||||
<li>
|
||||
|
|
@ -47,11 +47,13 @@
|
|||
<script>
|
||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
import ServerSpecifiedPropertyControl from "../../labThingsComponents/serverSpecifiedPropertyControl.vue";
|
||||
// vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActionButton,
|
||||
ServerSpecifiedPropertyControl,
|
||||
ServerSpecifiedPropertyControl
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -64,14 +66,20 @@ export default {
|
|||
};
|
||||
},
|
||||
|
||||
async created() {
|
||||
this.readSettings();
|
||||
},
|
||||
|
||||
methods: {
|
||||
async safeReadSettings() {
|
||||
if (!this.$store.state.connected) return;
|
||||
|
||||
try {
|
||||
await this.readSettings();
|
||||
} catch (error) {
|
||||
console.error("Error reading background detector settings:", error);
|
||||
}
|
||||
},
|
||||
|
||||
visibilityChanged(isVisible) {
|
||||
if (isVisible) {
|
||||
this.readSettings();
|
||||
this.safeReadSettings();
|
||||
}
|
||||
},
|
||||
alertBackgroundSet() {
|
||||
|
|
@ -99,6 +107,18 @@ export default {
|
|||
}
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.backgroundDetectContent,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{
|
||||
threshold: 0.0,
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="less">
|
||||
|
|
|
|||
|
|
@ -13,13 +13,14 @@
|
|||
<script>
|
||||
import paneBackgroundDetect from "./backgroundDetectComponents/paneBackgroundDetect";
|
||||
import streamDisplay from "./streamContent.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "BackgroundDetectContent",
|
||||
|
||||
components: {
|
||||
paneBackgroundDetect,
|
||||
streamDisplay,
|
||||
streamDisplay
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@
|
|||
</template>
|
||||
<script>
|
||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
// vue3 migration
|
||||
import { eventBus } from "../../../eventBus.js";
|
||||
|
||||
export default {
|
||||
name: "AutofocusControl",
|
||||
|
||||
components: {
|
||||
ActionButton,
|
||||
ActionButton
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -38,7 +40,7 @@ export default {
|
|||
},
|
||||
afterAutofocus() {
|
||||
this.isAutofocusing = false;
|
||||
this.$root.$emit("globalUpdatePositionEvent");
|
||||
eventBus.emit("globalUpdatePositionEvent");
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import axios from "axios";
|
|||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
import positionControl from "./positionControl.vue";
|
||||
import autofocusControl from "./autofocusControl.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "PaneControl",
|
||||
|
|
@ -41,7 +42,7 @@ export default {
|
|||
components: {
|
||||
ActionButton,
|
||||
positionControl,
|
||||
autofocusControl,
|
||||
autofocusControl
|
||||
},
|
||||
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ and zero position buttons. It also includes the d-pad.
|
|||
<!-- Text boxes to set and view position -->
|
||||
<div class="input-and-buttons-container">
|
||||
<input
|
||||
v-for="(_v, key) in setPosition"
|
||||
:key="`setPosition_${key}`"
|
||||
v-for="(_v, key) in setPosition"
|
||||
v-model="setPosition[key]"
|
||||
class="uk-form-small numeric-setting-line-input"
|
||||
type="number"
|
||||
|
|
@ -61,13 +61,16 @@ and zero position buttons. It also includes the d-pad.
|
|||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
import syncPropertyButton from "../../labThingsComponents/syncPropertyButton.vue";
|
||||
import stageControlButtons from "./stageControlButtons.vue";
|
||||
// vue3 migration
|
||||
import { eventBus } from "../../../eventBus.js";
|
||||
|
||||
export default {
|
||||
name: "PaneControl",
|
||||
|
||||
components: {
|
||||
ActionButton,
|
||||
syncPropertyButton,
|
||||
stageControlButtons,
|
||||
stageControlButtons
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -79,45 +82,57 @@ export default {
|
|||
|
||||
computed: {
|
||||
positionStatusUri: function () {
|
||||
console.log("Computing position status URI", this.thingActionUrl("stage", "position"));
|
||||
return this.thingActionUrl("stage", "position");
|
||||
},
|
||||
},
|
||||
|
||||
async mounted() {
|
||||
let self = this;
|
||||
// A global signal listener to perform a move action
|
||||
this.$root.$on("globalMoveEvent", self.move);
|
||||
this.$root.$on("globalUpdatePositionEvent", self.updatePosition);
|
||||
eventBus.on("globalMoveEvent", this.move);
|
||||
// A global signal listener to update position text boxes
|
||||
eventBus.on("globalUpdatePositionEvent", this.updatePosition);
|
||||
// A global signal listener to perform a move action in pixels
|
||||
this.$root.$on("globalMoveInImageCoordinatesEvent", (x, y, absolute) => {
|
||||
this.moveInImageCoordinatesRequest(x, y, absolute);
|
||||
});
|
||||
eventBus.on("globalMoveInImageCoordinatesEvent", this.onMoveImage);
|
||||
// A global signal listener to perform a move in multiples of a step size
|
||||
this.$root.$on("globalMoveStepEvent", (x_steps, y_steps, z_steps) => {
|
||||
const navigationStepSize = this.$store.state.navigationStepSize;
|
||||
const navigationInvert = this.$store.state.navigationInvert;
|
||||
const x = x_steps * navigationStepSize.x * (navigationInvert.x ? -1 : 1);
|
||||
const y = y_steps * navigationStepSize.y * (navigationInvert.y ? -1 : 1);
|
||||
const z = z_steps * navigationStepSize.z * (navigationInvert.z ? -1 : 1);
|
||||
this.$root.$emit("globalMoveEvent", x, y, z, false);
|
||||
});
|
||||
eventBus.on("globalMoveStepEvent", this.onMoveStep);
|
||||
// Update the current position in text boxes
|
||||
await this.updatePosition();
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
// Remove global signal listener to perform a move action
|
||||
this.$root.$off("globalMoveEvent");
|
||||
this.$root.$off("globalMoveInImageCoordinatesEvent");
|
||||
this.$root.$off("globalMoveStepEvent");
|
||||
this.$root.$off("globalUpdatePositionEvent");
|
||||
eventBus.off("globalMoveEvent", this.move);
|
||||
eventBus.off("globalUpdatePositionEvent", this.updatePosition);
|
||||
eventBus.off("globalMoveInImageCoordinatesEvent", this.onMoveImage);
|
||||
eventBus.off("globalMoveStepEvent", this.onMoveStep);
|
||||
},
|
||||
|
||||
methods: {
|
||||
timeout(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
},
|
||||
async move(x, y, z, absolute) {
|
||||
|
||||
onMoveImage(payload) {
|
||||
console.log("Received move in image coordinates:", payload);
|
||||
this.moveInImageCoordinatesRequest(payload.x, payload.y, payload.absolute);
|
||||
},
|
||||
|
||||
onMoveStep(payload) {
|
||||
console.log("Received key move step event:", payload);
|
||||
const { x: x_steps, y: y_steps, z: z_steps } = payload;
|
||||
const navigationStepSize = this.$store.state.navigationStepSize;
|
||||
const navigationInvert = this.$store.state.navigationInvert;
|
||||
const x = x_steps * navigationStepSize.x * (navigationInvert.x ? -1 : 1);
|
||||
const y = y_steps * navigationStepSize.y * (navigationInvert.y ? -1 : 1);
|
||||
const z = z_steps * navigationStepSize.z * (navigationInvert.z ? -1 : 1);
|
||||
const movePayload = { x, y, z, absolute: false };
|
||||
eventBus.emit("globalMoveEvent", movePayload);
|
||||
console.log("Emitted global move event with:", movePayload);
|
||||
},
|
||||
|
||||
async move(payload) {
|
||||
const { x, y, z, absolute } = payload;
|
||||
// Move the stage, by updating the controls and starting a move task
|
||||
// This is equivalent to clicking the "move" button.
|
||||
if (this.moveLock) return; // Discard move requests if we're already moving
|
||||
|
|
@ -133,15 +148,17 @@ export default {
|
|||
y: this.setPosition.y + y,
|
||||
z: this.setPosition.z + z,
|
||||
};
|
||||
console.log("Updated setPosition for relative move:", this.setPosition);
|
||||
}
|
||||
await this.timeout(1); // Wait for Vue to update the position
|
||||
await this.$nextTick(); // Wait for Vue to update the position
|
||||
await this.startMoveTask();
|
||||
},
|
||||
async startMoveTask() {
|
||||
this.moveLock = true;
|
||||
//this.moveLock = true;
|
||||
await this.$refs.moveButton.startTask();
|
||||
},
|
||||
moveComplete() {
|
||||
console.log("Move completed.");
|
||||
this.updatePosition();
|
||||
this.moveLock = false;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -37,11 +37,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { eventBus } from "../../../eventBus.js";
|
||||
|
||||
export default {
|
||||
name: "StageControlButtons",
|
||||
methods: {
|
||||
move(x, y, z) {
|
||||
this.$root.$emit("globalMoveStepEvent", x, y, z);
|
||||
eventBus.emit("globalMoveStepEvent", {x, y, z, absolute: false});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,15 +11,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import paneControl from "./controlComponents/paneControl";
|
||||
import paneControl from "./controlComponents/paneControl.vue";
|
||||
import streamDisplay from "./streamContent.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "ControlContent",
|
||||
|
||||
components: {
|
||||
paneControl,
|
||||
streamDisplay,
|
||||
streamDisplay
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div v-observe-visibility="visibilityChanged" class="uk-padding uk-padding-remove-top">
|
||||
<div ref="loggingDisplay" class="uk-padding uk-padding-remove-top">
|
||||
<!-- Logging nav bar -->
|
||||
<nav class="logging-navbar uk-navbar-container uk-navbar-transparent" uk-navbar="mode: click">
|
||||
<!-- Left side controls -->
|
||||
|
|
@ -83,13 +83,15 @@
|
|||
import axios from "axios";
|
||||
import Paginate from "vuejs-paginate";
|
||||
import EndpointButton from "../labThingsComponents/endpointButton.vue";
|
||||
//vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
name: "LoggingContent",
|
||||
|
||||
components: {
|
||||
Paginate,
|
||||
EndpointButton,
|
||||
EndpointButton
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -133,6 +135,18 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.loggingDisplay,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{
|
||||
threshold: 0.0,
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
methods: {
|
||||
scrollToTop() {
|
||||
this.$emit("scrollTop");
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<template>
|
||||
<div v-observe-visibility="visibilityChanged">
|
||||
<div ref="osdViewerContainer" class="osd-viewer-container uk-height-1-1">
|
||||
<div id="openseadragon" ref="osdContainer"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import OpenSeaDragon from "openseadragon";
|
||||
// vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
name: "OpenSeadragonViewer",
|
||||
|
|
@ -54,24 +56,43 @@ export default {
|
|||
},
|
||||
|
||||
async mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.osdViewerContainer,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{ threshold: 0.0 }
|
||||
);
|
||||
|
||||
if (this.src) {
|
||||
this.loadOpenSeaDragon(this.src);
|
||||
}
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
// Remove global signal listener to perform a gallery refresh
|
||||
this.osdViewer.destroy();
|
||||
if (this.osdViewer) {
|
||||
this.osdViewer.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
// adding this check to avoid error when the viewer is not yet initialized.
|
||||
if (isVisible) {
|
||||
this.loadOpenSeaDragon();
|
||||
|
||||
if (!this.osdViewer && this.src) {
|
||||
this.loadOpenSeaDragon(this.src);
|
||||
}
|
||||
} else {
|
||||
this.osdViewer.destroy();
|
||||
|
||||
if (this.osdViewer) {
|
||||
this.osdViewer.destroy();
|
||||
this.osdViewer = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async loadOpenSeaDragon() {
|
||||
if (this.osdViewer) {
|
||||
this.osdViewer.destroy();
|
||||
|
|
|
|||
|
|
@ -82,11 +82,15 @@
|
|||
import axios from "axios";
|
||||
import actionButton from "../../labThingsComponents/actionButton.vue";
|
||||
import EndpointButton from "../../labThingsComponents/endpointButton.vue";
|
||||
// vue3 migration
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "ScanCard",
|
||||
components: { actionButton, EndpointButton },
|
||||
components: {
|
||||
actionButton,
|
||||
EndpointButton
|
||||
},
|
||||
|
||||
props: {
|
||||
scanData: {
|
||||
|
|
|
|||
|
|
@ -55,10 +55,13 @@
|
|||
<script>
|
||||
import UIkit from "uikit";
|
||||
import OpenSeadragonViewer from "./openSeadragonViewer.vue";
|
||||
// vue3 migration
|
||||
|
||||
export default {
|
||||
name: "ScanViewerModal",
|
||||
components: { OpenSeadragonViewer },
|
||||
components: {
|
||||
OpenSeadragonViewer
|
||||
},
|
||||
props: {
|
||||
selectedScan: {
|
||||
type: Object,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div
|
||||
v-observe-visibility="visibilityChanged"
|
||||
ref="galleryDisplay"
|
||||
class="galleryDisplay uk-padding uk-padding-remove-top"
|
||||
>
|
||||
<!-- Gallery nav bar -->
|
||||
|
|
@ -100,11 +100,18 @@ import axios from "axios";
|
|||
import actionButton from "../labThingsComponents/actionButton.vue";
|
||||
import scanCard from "./scanListComponents/scanCard.vue";
|
||||
import ScanViewerModal from "./scanListComponents/scanViewer.vue";
|
||||
// vue3 migration
|
||||
import { eventBus } from "../../eventBus.js";
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "ScanListContent",
|
||||
components: { actionButton, scanCard, ScanViewerModal },
|
||||
components: {
|
||||
actionButton,
|
||||
scanCard,
|
||||
ScanViewerModal
|
||||
},
|
||||
|
||||
data: function () {
|
||||
return {
|
||||
|
|
@ -141,13 +148,22 @@ export default {
|
|||
},
|
||||
|
||||
async mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.galleryDisplay,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{
|
||||
threshold: 0.0, // Adjust as needed
|
||||
},
|
||||
);
|
||||
// Update on mount (does nothing if not connected)
|
||||
await this.updateScans();
|
||||
// A global signal listener to perform a gallery refresh
|
||||
this.$root.$on("globalUpdateScans", () => {
|
||||
eventBus.on("globalUpdateScans", () => {
|
||||
this.updateScans();
|
||||
});
|
||||
this.$root.$on("modalClosed", () => {
|
||||
eventBus.on("modalClosed", () => {
|
||||
// Handle the modal closed event here
|
||||
this.updateScans();
|
||||
});
|
||||
|
|
@ -171,15 +187,15 @@ export default {
|
|||
);
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
// Remove global signal listener to perform a gallery refresh
|
||||
this.$root.$off("globalUpdateScans");
|
||||
eventBus.off("globalUpdateScans", this.updateScans);
|
||||
// Then we call that function here to unwatch
|
||||
if (this.unwatchStoreFunction) {
|
||||
this.unwatchStoreFunction();
|
||||
this.unwatchStoreFunction = null;
|
||||
}
|
||||
this.$root.$off("modalClosed"); // Clean up event listener
|
||||
eventBus.off("modalClosed", this.updateScans); // Clean up event listener
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
<script>
|
||||
import CSMCalibrationSettings from "./CSMSettingsComponents/CSMCalibrationSettings.vue";
|
||||
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
|
||||
// vue3 migration
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
|
|
@ -24,7 +25,7 @@ export default {
|
|||
|
||||
components: {
|
||||
CSMCalibrationSettings,
|
||||
miniStreamDisplay,
|
||||
miniStreamDisplay
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div id="CSMCalibrationSettings" v-observe-visibility="visibilityChanged">
|
||||
<div id="CSMCalibrationSettings" ref="CSMCalibrationSettingsContainer" class="uk-width-large">
|
||||
<!--Show auto calibrate if default plugin is enabled-->
|
||||
<div v-if="'calibrate_xy' in actions" class="uk-margin-small">
|
||||
<action-button
|
||||
|
|
@ -57,6 +57,8 @@
|
|||
<script>
|
||||
import ActionButton from "@/components/labThingsComponents/actionButton.vue";
|
||||
import matrixDisplay from "@/components/ui/matrixDisplay.vue";
|
||||
// vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
|
|
@ -64,7 +66,7 @@ export default {
|
|||
|
||||
components: {
|
||||
ActionButton,
|
||||
matrixDisplay,
|
||||
matrixDisplay
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
@ -93,6 +95,16 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.CSMCalibrationSettingsContainer,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{ threshold: 0.0 }
|
||||
);
|
||||
},
|
||||
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
if (isVisible) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
import cameraCalibrationSettings from "./cameraSettingsComponents/cameraCalibrationSettings.vue";
|
||||
import miniStreamDisplay from "../../genericComponents/miniStreamDisplay.vue";
|
||||
import ServerSpecifiedPropertyControl from "../../labThingsComponents/serverSpecifiedPropertyControl.vue";
|
||||
// vue3 migration
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
|
|
@ -33,7 +34,7 @@ export default {
|
|||
components: {
|
||||
cameraCalibrationSettings,
|
||||
miniStreamDisplay,
|
||||
ServerSpecifiedPropertyControl,
|
||||
ServerSpecifiedPropertyControl
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
|
|||
|
|
@ -22,13 +22,15 @@
|
|||
|
||||
<script>
|
||||
import ServerSpecifiedActionButton from "../../../labThingsComponents/serverSpecifiedActionButton.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "CameraCalibrationSettings",
|
||||
|
||||
components: {
|
||||
ServerSpecifiedActionButton,
|
||||
ServerSpecifiedActionButton
|
||||
},
|
||||
|
||||
props: {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export default {
|
|||
|
||||
components: {
|
||||
streamSettings,
|
||||
appSettings,
|
||||
appSettings
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div id="stageSettings" v-observe-visibility="visibilityChanged" class="uk-width-large">
|
||||
<div id="stageSettings" ref="stageSettingsContainer" class="uk-width-large">
|
||||
The microscope stage is a <b>{{ stageType }}</b>
|
||||
<div>
|
||||
<div class="uk-margin">
|
||||
|
|
@ -29,12 +29,14 @@
|
|||
|
||||
<script>
|
||||
import ActionButton from "../../labThingsComponents/actionButton.vue";
|
||||
// vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
name: "StageSettings",
|
||||
|
||||
components: {
|
||||
ActionButton,
|
||||
ActionButton
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -49,6 +51,16 @@ export default {
|
|||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.stageSettingsContainer,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{ threshold: 0.0 }
|
||||
);
|
||||
},
|
||||
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
if (isVisible) {
|
||||
|
|
|
|||
|
|
@ -65,8 +65,11 @@ import cameraSettings from "./settingsComponents/cameraSettings.vue";
|
|||
import CSMSettings from "./settingsComponents/CSMSettings.vue";
|
||||
import stageSettings from "./settingsComponents/stageSettings.vue";
|
||||
// Import generic components
|
||||
import tabIcon from "../genericComponents/tabIcon";
|
||||
import tabContent from "../genericComponents/tabContent";
|
||||
import tabIcon from "../genericComponents/tabIcon.vue";
|
||||
import tabContent from "../genericComponents/tabContent.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
|
|
@ -75,7 +78,7 @@ export default {
|
|||
components: {
|
||||
tabIcon,
|
||||
tabContent,
|
||||
calibrationWizard,
|
||||
calibrationWizard
|
||||
},
|
||||
|
||||
data: function () {
|
||||
|
|
@ -87,14 +90,14 @@ export default {
|
|||
id: "display",
|
||||
title: "Display",
|
||||
requireConnection: false,
|
||||
component: displaySettings,
|
||||
component: markRaw(displaySettings),
|
||||
requiredThings: [],
|
||||
},
|
||||
{
|
||||
id: "stage-control",
|
||||
title: "Stage Control Preferences",
|
||||
requireConnection: false,
|
||||
component: stageControlSettings,
|
||||
component: markRaw(stageControlSettings),
|
||||
requiredThings: ["stage"],
|
||||
},
|
||||
],
|
||||
|
|
@ -103,21 +106,21 @@ export default {
|
|||
id: "camera",
|
||||
title: "Camera",
|
||||
requireConnection: true,
|
||||
component: cameraSettings,
|
||||
component: markRaw(cameraSettings),
|
||||
requiredThings: [],
|
||||
},
|
||||
{
|
||||
id: "stage",
|
||||
title: "Stage",
|
||||
requireConnection: true,
|
||||
component: stageSettings,
|
||||
component: markRaw(stageSettings),
|
||||
requiredThings: ["stage"],
|
||||
},
|
||||
{
|
||||
id: "mapping",
|
||||
title: "Camera to Stage Mapping",
|
||||
requireConnection: true,
|
||||
component: CSMSettings,
|
||||
component: markRaw(CSMSettings),
|
||||
requiredThings: ["camera_stage_mapping"],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@
|
|||
submit-label="Start Smart Scan"
|
||||
:can-terminate="true"
|
||||
@taskStarted="startScanning"
|
||||
@update:taskStatus="taskStatus = $event"
|
||||
@update:progress="progress = $event"
|
||||
@update:log="log = $event"
|
||||
@beforeUpdate:taskStatus="taskStatus = $event"
|
||||
@beforeUpdate:progress="progress = $event"
|
||||
@beforeUpdate:log="log = $event"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -130,6 +130,8 @@ import actionLogDisplay from "../labThingsComponents/actionLogDisplay.vue";
|
|||
import actionProgressBar from "../labThingsComponents/actionProgressBar.vue";
|
||||
import MiniStreamDisplay from "../genericComponents/miniStreamDisplay.vue";
|
||||
import ActionButton from "../labThingsComponents/actionButton.vue";
|
||||
// vue3 migration
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
export default {
|
||||
name: "SlideScanContent",
|
||||
|
|
@ -137,11 +139,11 @@ export default {
|
|||
components: {
|
||||
streamDisplay,
|
||||
propertyControl,
|
||||
ServerSpecifiedPropertyControl,
|
||||
actionLogDisplay,
|
||||
actionProgressBar,
|
||||
MiniStreamDisplay,
|
||||
ActionButton,
|
||||
ServerSpecifiedPropertyControl
|
||||
},
|
||||
|
||||
data() {
|
||||
|
|
@ -177,6 +179,18 @@ export default {
|
|||
this.workflowOptions = await this.readThingProperty("smart_scan", "workflow_display_names");
|
||||
},
|
||||
|
||||
mounted() {
|
||||
useIntersectionObserver(
|
||||
this.$refs.slideScanContent,
|
||||
([{ isIntersecting }]) => {
|
||||
this.visibilityChanged(isIntersecting);
|
||||
},
|
||||
{
|
||||
threshold: 0.0, // Adjust as needed
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
if (isVisible) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
<div
|
||||
id="stream-display"
|
||||
ref="streamDisplay"
|
||||
v-observe-visibility="visibilityChanged"
|
||||
class="stream-display uk-width-1-1 uk-height-1-1 scrollTarget"
|
||||
>
|
||||
<img
|
||||
|
|
@ -35,6 +34,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
// vue3 migration
|
||||
import { eventBus } from "../../eventBus.js";
|
||||
import { useIntersectionObserver } from "@vueuse/core";
|
||||
|
||||
// Export main app
|
||||
export default {
|
||||
name: "StreamDisplay",
|
||||
|
|
@ -47,7 +50,7 @@ export default {
|
|||
resizeTimeoutId: setTimeout(this.doneResizing, 500),
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
computed: {
|
||||
streamEnabled: function () {
|
||||
return this.$store.getters.ready && !this.$store.state.disableStream;
|
||||
|
|
@ -62,30 +65,44 @@ export default {
|
|||
},
|
||||
|
||||
mounted() {
|
||||
//set up an intersection observer
|
||||
useIntersectionObserver(
|
||||
this.$refs.streamDisplay,
|
||||
([{ isIntersecting }]) => {
|
||||
this.isVisible = isIntersecting;
|
||||
},
|
||||
{
|
||||
threshold: 0.0,
|
||||
}
|
||||
);
|
||||
// A global signal listener to flash the stream element
|
||||
this.$root.$on("globalFlashStream", () => {
|
||||
this.onFlashStream = () => {
|
||||
this.flashStream();
|
||||
});
|
||||
};
|
||||
|
||||
eventBus.on("globalFlashStream", this.onFlashStream);
|
||||
|
||||
// Mutation observer
|
||||
this.sizeObserver = new ResizeObserver(() => {
|
||||
this.handleResize(); // For any element attached to the observer, run handleResize() on change
|
||||
});
|
||||
// Fetch streamDisplay component by ref
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
if (this.$refs.streamDisplay && this.$refs.streamDisplay.parentNode) {
|
||||
const streamDisplayElement = this.$refs.streamDisplay.parentNode;
|
||||
// Attach streamDisplay to the size observer
|
||||
this.sizeObserver.observe(streamDisplayElement);
|
||||
}
|
||||
},
|
||||
|
||||
created: function () {
|
||||
// Do nothing: preview stream now runs all the time
|
||||
},
|
||||
|
||||
beforeDestroy: function () {
|
||||
beforeUnmount: function () {
|
||||
// Remove global signal listener to change the GPU preview state
|
||||
this.$root.$off("globalTogglePreview");
|
||||
//eventBus.off("globalTogglePreview", true);
|
||||
// Remove global signal listener to flash the stream element
|
||||
this.$root.$off("globalFlashStream");
|
||||
eventBus.off("globalFlashStream", this.onFlashStream);
|
||||
// Disconnect the size observer
|
||||
this.sizeObserver.disconnect();
|
||||
// Remove from the array of active streams
|
||||
|
|
@ -93,9 +110,6 @@ export default {
|
|||
},
|
||||
|
||||
methods: {
|
||||
visibilityChanged(isVisible) {
|
||||
this.isVisible = isVisible;
|
||||
},
|
||||
flashStream: function () {
|
||||
// Run an animation that flashes the stream (for capture feedback)
|
||||
let element = this.$refs.streamDisplay;
|
||||
|
|
@ -126,7 +140,10 @@ export default {
|
|||
let yRelative = (0.5 * event.target.offsetHeight - yCoordinate) * scale;
|
||||
|
||||
// Emit a signal to move, acted on by paneControl.vue
|
||||
this.$root.$emit("globalMoveInImageCoordinatesEvent", -xRelative, -yRelative);
|
||||
eventBus.emit("globalMoveInImageCoordinatesEvent", {
|
||||
x:-xRelative,
|
||||
y:-yRelative
|
||||
});
|
||||
},
|
||||
|
||||
handleResize: function () {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@
|
|||
|
||||
<script>
|
||||
import streamDisplay from "./streamContent.vue";
|
||||
// vue3 migration
|
||||
import { markRaw } from "vue";
|
||||
|
||||
export default {
|
||||
name: "ViewContent",
|
||||
|
|
|
|||
3
webapp/src/eventBus.js
Normal file
3
webapp/src/eventBus.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import mitt from "mitt";
|
||||
|
||||
export const eventBus = mitt();
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import Vue from "vue";
|
||||
import { createApp } from 'vue';
|
||||
import App from "./App.vue";
|
||||
import store from "./store";
|
||||
import UIkit from "uikit";
|
||||
|
|
@ -21,15 +21,16 @@ UIkit.mixin(
|
|||
"accordion",
|
||||
);
|
||||
|
||||
// Create Vue app
|
||||
const app = createApp(App);
|
||||
|
||||
// Use visibility observer
|
||||
Vue.use(VueObserveVisibility);
|
||||
app.use(VueObserveVisibility);
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
// Use global mixins
|
||||
app.mixin(queryMixin);
|
||||
app.mixin(modalMixin);
|
||||
|
||||
Vue.mixin(queryMixin);
|
||||
Vue.mixin(modalMixin);
|
||||
|
||||
new Vue({
|
||||
store,
|
||||
render: (h) => h(App),
|
||||
}).$mount("#app");
|
||||
// Use Vuex store
|
||||
app.use(store);
|
||||
app.mount("#app");
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import UIkit from "uikit";
|
||||
import { eventBus } from "@/eventBus";
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
|
|
@ -14,7 +15,7 @@ export default {
|
|||
var context = this;
|
||||
|
||||
// Stop GPU preview to show modal
|
||||
context.$root.$emit("globalTogglePreview", false);
|
||||
eventBus.emit("globalTogglePreview", false);
|
||||
|
||||
// force OK to be capitalised
|
||||
UIkit.modal.i18n = { ok: "OK", cancel: "Cancel" };
|
||||
|
|
@ -33,9 +34,9 @@ export default {
|
|||
.finally(function () {
|
||||
// Re-enable the GPU preview, if it was active before the modal
|
||||
if (context.$store.state.autoGpuPreview) {
|
||||
context.$root.$emit("globalTogglePreview", true);
|
||||
eventBus.emit("globalTogglePreview", true);
|
||||
}
|
||||
context.$root.$emit("modalClosed");
|
||||
eventBus.emit("modalClosed");
|
||||
});
|
||||
};
|
||||
return new Promise(showModal);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue