WIP: update webapp to use new backend
This is still very much WIP, but I now have fast autofocus, stage moves, image streaming, and click-to-move.
This commit is contained in:
parent
e82acf2941
commit
799dc7f522
12 changed files with 9371 additions and 8401 deletions
|
|
@ -344,13 +344,16 @@ export default {
|
|||
|
||||
methods: {
|
||||
updatePlugins: function() {
|
||||
return axios
|
||||
/*return axios
|
||||
.get(this.pluginsUri)
|
||||
.then(response => {
|
||||
this.plugins = response.data;
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});*/
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve({});
|
||||
});
|
||||
},
|
||||
setTab: function(event, tab) {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default {
|
|||
|
||||
computed: {
|
||||
streamImgUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/streams/mjpeg`;
|
||||
return `${this.$store.getters.baseUri}/camera/mjpeg_stream`;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export default {
|
|||
if (task.status == "pending" || task.status == "running") {
|
||||
this.taskStarted = true;
|
||||
this.$emit("taskStarted", this.taskId);
|
||||
this.startPolling(task.id, task.links.self.href);
|
||||
this.startPolling(task.id, task.links.find(t => t.rel==self).href);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -219,7 +219,10 @@ export default {
|
|||
|
||||
var checkCondition = (resolve, reject) => {
|
||||
// If the condition is met, we're done!
|
||||
axios.get(this.taskUrl).then(response => {
|
||||
axios.get(
|
||||
this.taskUrl,
|
||||
{baseURL: this.$store.getters.baseUri}
|
||||
).then(response => {
|
||||
var result = response.data.status;
|
||||
// If the task ends with success
|
||||
if (result == "completed") {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,6 @@
|
|||
<b>API origin:</b>
|
||||
<br />
|
||||
{{ $store.state.origin }}
|
||||
<br />
|
||||
<b>API URL:</b>
|
||||
<br />
|
||||
{{ $store.getters.uriV2 }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -228,14 +228,17 @@ export default {
|
|||
},
|
||||
|
||||
computed: {
|
||||
baseUri: function() {
|
||||
return this.$store.getters.baseUri;
|
||||
},
|
||||
moveActionUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/actions/stage/move`;
|
||||
return `${this.$store.getters.baseUri}/stage/move_relative`;
|
||||
},
|
||||
zeroActionUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/actions/stage/zero`;
|
||||
},
|
||||
positionStatusUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/instrument/state/stage/position`;
|
||||
return `${this.baseUri}/stage/position`;
|
||||
},
|
||||
pluginsUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/extensions`;
|
||||
|
|
@ -308,14 +311,13 @@ export default {
|
|||
if (!this.moveLock) {
|
||||
// Lock move requests
|
||||
this.moveLock = true;
|
||||
|
||||
let move_type = absolute ? "absolute" : "relative";
|
||||
// Send move request
|
||||
axios
|
||||
.post(this.moveActionUri, {
|
||||
.post(`${this.baseUri}/stage/move_${move_type}`, {
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
absolute: absolute
|
||||
z: z
|
||||
})
|
||||
.then(() => {
|
||||
this.updatePosition(); // Update the position in text boxes
|
||||
|
|
@ -344,8 +346,8 @@ export default {
|
|||
// Send move request
|
||||
axios
|
||||
.post(this.moveInImageCoordinatesUri, {
|
||||
x: y, // NB the coordinates are numpy/PIL style, meaning X and Y are swapped.
|
||||
y: x
|
||||
x: x, // NB the coordinates are numpy/PIL style, meaning X and Y are swapped.
|
||||
y: y
|
||||
})
|
||||
.then(() => {
|
||||
this.updatePosition(); // Update the position in text boxes
|
||||
|
|
@ -383,42 +385,11 @@ export default {
|
|||
},
|
||||
|
||||
updateAutofocusUri: function() {
|
||||
axios
|
||||
.get(this.pluginsUri) // Get a list of plugins
|
||||
.then(response => {
|
||||
var plugins = response.data;
|
||||
var foundExtension = plugins.find(
|
||||
e => e.title === "org.openflexure.autofocus"
|
||||
);
|
||||
// if ScanPlugin is enabled
|
||||
if (foundExtension) {
|
||||
// Get plugin action link
|
||||
this.fastAutofocusUri = foundExtension.links.fast_autofocus.href;
|
||||
this.normalAutofocusUri = foundExtension.links.autofocus.href;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
this.fastAutofocusUri = `${this.baseUri}/autofocus/fast_autofocus`;
|
||||
},
|
||||
|
||||
updateMoveInImageCoordinatesUri: function() {
|
||||
axios
|
||||
.get(this.pluginsUri) // Get a list of plugins
|
||||
.then(response => {
|
||||
var plugins = response.data;
|
||||
var foundExtension = plugins.find(
|
||||
e => e.title === "org.openflexure.camera_stage_mapping"
|
||||
);
|
||||
if (foundExtension) {
|
||||
// Get plugin action link
|
||||
this.moveInImageCoordinatesUri =
|
||||
foundExtension.links.move_in_image_coordinates.href;
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
this.moveInImageCoordinatesUri = `${this.baseUri}/camera_stage_mapping/move_in_image_coordinates`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,42 +10,6 @@
|
|||
This will disable the embedded web stream of the camera.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div>
|
||||
<h3>Microscope display output</h3>
|
||||
<div uk-grid>
|
||||
<div>
|
||||
<label :class="[{ 'uk-disabled': !this.$store.getters.ready }]"
|
||||
><input
|
||||
v-model="autoGpuPreview"
|
||||
class="uk-checkbox"
|
||||
type="checkbox"
|
||||
/>
|
||||
Enable GPU preview</label
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label :class="[{ 'uk-disabled': !this.$store.getters.ready }]"
|
||||
><input v-model="trackWindow" class="uk-checkbox" type="checkbox" />
|
||||
Track window</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<p>
|
||||
Enable GPU preview turns on a low-latency camera preview drawn directly
|
||||
to the Raspberry Pi display output.
|
||||
</p>
|
||||
<p class="uk-margin-small">
|
||||
<b
|
||||
>Content, such as your mouse, won't be visible behind this preview.</b
|
||||
>
|
||||
Track Window will attempt to resize the GPU preview based on the current
|
||||
window size, however this is often imperfect and cannot track window
|
||||
movement.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -66,28 +30,6 @@ export default {
|
|||
set(value) {
|
||||
this.$store.commit("changeDisableStream", value);
|
||||
}
|
||||
},
|
||||
|
||||
autoGpuPreview: {
|
||||
get() {
|
||||
return this.$store.state.autoGpuPreview;
|
||||
},
|
||||
set(value) {
|
||||
// NB the stream viewer watches the store, and is
|
||||
// responsible for making the request that switches
|
||||
// GPU preview on/off
|
||||
// see streamContent.vue
|
||||
this.$store.commit("changeAutoGpuPreview", value);
|
||||
}
|
||||
},
|
||||
|
||||
trackWindow: {
|
||||
get() {
|
||||
return this.$store.state.trackWindow;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeTrackWindow", value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -96,34 +38,6 @@ export default {
|
|||
// (the next 3 functions all relate to this)
|
||||
disableStream: function(newValue) {
|
||||
this.setLocalStorageObj("disableStream", newValue);
|
||||
},
|
||||
autoGpuPreview: function(newValue) {
|
||||
this.setLocalStorageObj("autoGpuPreview", newValue);
|
||||
},
|
||||
trackWindow: function(newValue) {
|
||||
this.setLocalStorageObj("trackWindow", newValue);
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
// Apply sensible defaults for stream settings, depending on
|
||||
// whether we're connecting locally or remotely, respecting
|
||||
// the settings that were cached previously.
|
||||
const localMode = ["localhost", "0.0.0.0", "127.0.0.1", "[::1]"].includes(
|
||||
window.location.hostname
|
||||
);
|
||||
const localDefaults = {
|
||||
disableStream: true,
|
||||
autoGpuPreview: true,
|
||||
trackWindow: true
|
||||
};
|
||||
for (let k in localDefaults) {
|
||||
if (localStorage.getItem(k) !== null) {
|
||||
this[k] = this.getLocalStorageObj(k);
|
||||
} else if (localMode) {
|
||||
console.log(`${k} set to default value for a local connection`);
|
||||
this[k] = localDefaults[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -59,34 +59,14 @@ export default {
|
|||
return !(this.displaySize[0] == 0) && !(this.displaySize[1] == 0);
|
||||
},
|
||||
streamImgUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/streams/mjpeg`;
|
||||
},
|
||||
startPreviewUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/actions/camera/preview/start`;
|
||||
},
|
||||
stopPreviewUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/actions/camera/preview/stop`;
|
||||
return `${this.$store.getters.baseUri}/camera/mjpeg_stream`;
|
||||
},
|
||||
settingsUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/instrument/settings`;
|
||||
},
|
||||
autoGpuPreview: function() {
|
||||
return this.$store.state.autoGpuPreview;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
autoGpuPreview: function(newValue) {
|
||||
// When the GPU preview setting in the store changes, update the server
|
||||
this.safePreviewRequest(newValue);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
// A global signal listener to change the GPU preview state
|
||||
this.$root.$on("globalTogglePreview", state => {
|
||||
this.previewRequest(state);
|
||||
});
|
||||
// A global signal listener to flash the stream element
|
||||
this.$root.$on("globalFlashStream", () => {
|
||||
this.flashStream();
|
||||
|
|
@ -103,8 +83,7 @@ export default {
|
|||
},
|
||||
|
||||
created: function() {
|
||||
// Send a request to start/stop GPU preview based on global setting
|
||||
this.safePreviewRequest(this.autoGpuPreview);
|
||||
// Do nothing: preview stream now runs all the time
|
||||
},
|
||||
|
||||
beforeDestroy: function() {
|
||||
|
|
@ -174,40 +153,10 @@ export default {
|
|||
// If this stream was previously active
|
||||
if (this.$store.state.activeStreams[this._uid] == true) {
|
||||
this.$store.commit("removeStream", this._uid);
|
||||
// If all streams are closed, request the GPU preview close
|
||||
var a = Object.values(this.$store.state.activeStreams);
|
||||
let allClosed = a.every(v => v === false);
|
||||
if (allClosed) {
|
||||
this.safePreviewRequest(false);
|
||||
}
|
||||
}
|
||||
// If resized to anything other than zero
|
||||
} else {
|
||||
this.$store.commit("addStream", this._uid);
|
||||
if (this.$store.state.autoGpuPreview == true) {
|
||||
// Start the preview immediately
|
||||
this.safePreviewRequest(true);
|
||||
// Send another start preview request after a timeout
|
||||
/*
|
||||
The internal logic of this component means that a stop GPU preview
|
||||
request will only ever be sent if ALL stream components are invisible.
|
||||
However, when switching tabs, sometimes the previous component will
|
||||
react to becoming invisible before the new tab has become visible.
|
||||
This results in a stop-preview request being sent JUST before the new
|
||||
start preview request is sent. In an ideal network, this is fine, however
|
||||
due to network jitter, these requests will occasionally be recieved out
|
||||
of order, causing the preview to start in the new location, and then
|
||||
quickly stop again.
|
||||
Preventing this properly will involve some clever server-side logic
|
||||
probably, however as a pit-stop solution, we always send another
|
||||
start-preview request after 1 second. This means that either:
|
||||
1. The initial requests happened in order, in which case this follow-up
|
||||
request does nothing, or
|
||||
2. The requests leapfrog eachother, stopping the preview, in which case
|
||||
the follow-up request restarts the preview in the correct location.
|
||||
*/
|
||||
setTimeout(() => this.safePreviewRequest(true), 250);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -233,63 +182,6 @@ export default {
|
|||
|
||||
this.displaySize = elementSize;
|
||||
this.displayPosition = elementPositionOnDisplay;
|
||||
},
|
||||
|
||||
safePreviewRequest: function(state) {
|
||||
// previewRequest, but only stopping preview if all streams are invisible
|
||||
// and only starting preview if any stream is visible
|
||||
var a = Object.values(this.$store.state.activeStreams);
|
||||
let allClosed = a.every(v => v === false);
|
||||
// If all streams are closed, don't start GPU preview
|
||||
if (state === true && allClosed) {
|
||||
return false;
|
||||
}
|
||||
// If not all streams are closed, don't stop GPU preview
|
||||
if (state === false && !allClosed) {
|
||||
return false;
|
||||
}
|
||||
return this.previewRequest(state);
|
||||
},
|
||||
|
||||
previewRequest: function(state) {
|
||||
// If requesting starting the stream, but this component is inactive, skip
|
||||
if (
|
||||
this.$store.getters.ready == true &&
|
||||
this.$store.state.autoGpuPreview == true
|
||||
) {
|
||||
var requestUri = null;
|
||||
// Create URI
|
||||
if (state == true) {
|
||||
requestUri = this.startPreviewUri;
|
||||
} else {
|
||||
requestUri = this.stopPreviewUri;
|
||||
}
|
||||
|
||||
// Generate payload if tracking window position
|
||||
var payload = {};
|
||||
if (this.$store.state.trackWindow == true && state == true) {
|
||||
// Recalculate frame dimensions and position
|
||||
this.recalculateSize();
|
||||
// Copy data into payload array
|
||||
payload = {
|
||||
window: [
|
||||
this.displayPosition[0],
|
||||
this.displayPosition[1],
|
||||
this.displaySize[0],
|
||||
this.displaySize[1]
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
// Send preview request
|
||||
|
||||
axios
|
||||
.post(requestUri, payload)
|
||||
.then(() => {})
|
||||
.catch(error => {
|
||||
this.modalError(error); // Let mixin handle error
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue