Stage move API now works
The test plugin seems to have problems calling setPosition more than once. We don't understand this... Co-authored-by: Kaspar Emanuel <kaspar@monostable.co.uk>
This commit is contained in:
parent
757ee216cf
commit
297908fbc8
4 changed files with 298 additions and 39 deletions
|
|
@ -0,0 +1,131 @@
|
|||
<config lang="json">
|
||||
{
|
||||
"name": "Script Editor",
|
||||
"type": "web-worker",
|
||||
"tags": [],
|
||||
"ui": "",
|
||||
"version": "0.1.0",
|
||||
"cover": "",
|
||||
"description": "A Script Editor for Controlling OpenFlexure Microscope with ImJoy",
|
||||
"icon": "extension",
|
||||
"inputs": null,
|
||||
"outputs": null,
|
||||
"api_version": "0.1.8",
|
||||
"env": "",
|
||||
"permissions": [],
|
||||
"requirements": [],
|
||||
"dependencies": []
|
||||
}
|
||||
</config>
|
||||
|
||||
<script lang="javascript">
|
||||
class ImJoyPlugin {
|
||||
async setup() {
|
||||
api.log('initialized')
|
||||
}
|
||||
|
||||
async run(ctx) {
|
||||
let pluginInEditor, stopped, editorWindow;
|
||||
const config = {lang: 'javascript'}
|
||||
config.templates = [
|
||||
{
|
||||
name: "New",
|
||||
url: null,
|
||||
lang: 'javascript',
|
||||
},
|
||||
{
|
||||
name: "Snap Image Template",
|
||||
url: "./OpenFlexureSnapImageTemplate.imjoy.html",
|
||||
lang: "html",
|
||||
}
|
||||
]
|
||||
config.ui_elements = {
|
||||
save: {
|
||||
_rintf: true,
|
||||
type: 'button',
|
||||
label: "Save",
|
||||
visible: false,
|
||||
icon: "content-save",
|
||||
callback(content) {
|
||||
console.log(content)
|
||||
}
|
||||
},
|
||||
run: {
|
||||
_rintf: true,
|
||||
type: 'button',
|
||||
label: "Run",
|
||||
icon: "play",
|
||||
visible: true,
|
||||
shortcut: 'Shift-Enter',
|
||||
async callback(content) {
|
||||
try {
|
||||
editorWindow.setLoader(true);
|
||||
editorWindow.updateUIElement('stop', {
|
||||
visible: true
|
||||
})
|
||||
api.showProgress(0);
|
||||
pluginInEditor = await api.getPlugin({src: content, hot_reloading: true})
|
||||
|
||||
if (stopped) {
|
||||
pluginInEditor = null;
|
||||
return;
|
||||
}
|
||||
if (pluginInEditor && pluginInEditor.run) {
|
||||
return await pluginInEditor.run({
|
||||
config: {},
|
||||
data: {}
|
||||
});
|
||||
}
|
||||
if (stopped) {
|
||||
pluginInEditor = null;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
api.showMessage("Failed to load plugin, error: " + e.toString());
|
||||
} finally {
|
||||
editorWindow.updateUIElement('stop', {
|
||||
visible: false
|
||||
})
|
||||
editorWindow.setLoader(false);
|
||||
api.showProgress(100);
|
||||
}
|
||||
}
|
||||
},
|
||||
stop: {
|
||||
_rintf: true,
|
||||
type: 'button',
|
||||
label: "Stop",
|
||||
style: "color: #ff0080cf;",
|
||||
icon: "stop",
|
||||
visible: false,
|
||||
async callback() {
|
||||
stopped = true;
|
||||
await editorWindow.setLoader(false);
|
||||
await editorWindow.updateUIElement('stop', {
|
||||
visible: false
|
||||
})
|
||||
}
|
||||
},
|
||||
export: {
|
||||
_rintf: true,
|
||||
type: 'button',
|
||||
label: "Export",
|
||||
icon: "file-download-outline",
|
||||
visible: true,
|
||||
async callback(content) {
|
||||
const fileName = (pluginInEditor && pluginInEditor.config.name && pluginInEditor.config.name + '.imjoy.html') || config.name + '.imjoy.html' || "myPlugin.imjoy.html";
|
||||
await api.exportFile(content, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
editorWindow = await api.createWindow({
|
||||
src: 'https://if.imjoy.io',
|
||||
name: (ctx && ctx.data && ctx.data.name) ||'OpenFlexure Script Editor',
|
||||
config,
|
||||
data: {code: ctx && ctx.data && ctx.data.code}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
api.export(new ImJoyPlugin())
|
||||
</script>
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<docs>
|
||||
[TODO: write documentation for this plugin.]
|
||||
</docs>
|
||||
|
||||
<config lang="json">
|
||||
{
|
||||
"name": "OpenFlexureSnapImageTemplate",
|
||||
"type": "web-worker",
|
||||
"tags": [],
|
||||
"ui": "",
|
||||
"version": "0.1.0",
|
||||
"cover": "",
|
||||
"description": "[TODO: describe this plugin with one sentence.]",
|
||||
"icon": "extension",
|
||||
"inputs": null,
|
||||
"outputs": null,
|
||||
"api_version": "0.1.8",
|
||||
"env": "",
|
||||
"permissions": [],
|
||||
"requirements": [],
|
||||
"dependencies": []
|
||||
}
|
||||
</config>
|
||||
|
||||
<script lang="javascript">
|
||||
class ImJoyPlugin {
|
||||
async setup() {
|
||||
api.log('initialized')
|
||||
}
|
||||
|
||||
async run(ctx) {
|
||||
// get a list of service
|
||||
const services = await api.getServices({name: "OpenFlexure"});
|
||||
// get the first service
|
||||
const ofm = services[0];
|
||||
// snap an image
|
||||
await ofm.snapImage();
|
||||
console.log("snapped an image");
|
||||
}
|
||||
}
|
||||
|
||||
api.export(new ImJoyPlugin())
|
||||
</script>
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<docs>
|
||||
[TODO: write documentation for this plugin.]
|
||||
</docs>
|
||||
|
||||
<config lang="json">
|
||||
{
|
||||
"name": "Test OFM Stage",
|
||||
"type": "web-worker",
|
||||
"tags": [],
|
||||
"ui": "",
|
||||
"version": "0.1.0",
|
||||
"cover": "",
|
||||
"description": "Move the OFM stage to test the API works",
|
||||
"icon": "extension",
|
||||
"inputs": null,
|
||||
"outputs": null,
|
||||
"api_version": "0.1.8",
|
||||
"env": "",
|
||||
"permissions": [],
|
||||
"requirements": [],
|
||||
"dependencies": []
|
||||
}
|
||||
</config>
|
||||
|
||||
<script lang="javascript">
|
||||
class ImJoyPlugin {
|
||||
async setup() {
|
||||
api.log('initialized')
|
||||
}
|
||||
|
||||
async run(ctx) {
|
||||
// get a list of service
|
||||
const services = await api.getServices({name: "OpenFlexure"});
|
||||
// get the first service
|
||||
const ofm = services[0];
|
||||
// snap an image
|
||||
const start = await ofm.getXYZPosition();
|
||||
console.log(`Starting position: ${start}`);
|
||||
// move the Z axis up and down
|
||||
await ofm.setPosition(start[2] + 100);
|
||||
console.log(`Moved Z to ${await ofm.getPosition()}`);
|
||||
await ofm.setPosition(start[2]);
|
||||
console.log(`Moved Z to ${await ofm.getPosition()}`);
|
||||
}
|
||||
}
|
||||
|
||||
api.export(new ImJoyPlugin())
|
||||
</script>
|
||||
|
|
@ -98,6 +98,21 @@ import * as imjoyCore from "imjoy-core";
|
|||
import axios from "axios";
|
||||
import UIkit from "uikit";
|
||||
|
||||
// TODO: move this to a module or something...
|
||||
async function pollAction(response) {
|
||||
// Poll an action until its status is completed
|
||||
// TODO: raise an error if it fails or is cancelled
|
||||
// For ease, this accepts and returns a response object from
|
||||
// axios.get
|
||||
// FIXME: this could be an infinite loop if the task is cancelled/errored
|
||||
let r = response;
|
||||
while ((r.data.status == "running") | (r.data.status == "pending")) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
r = await axios.get(r.data.href);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
export default {
|
||||
name: "ImJoyContent",
|
||||
|
||||
|
|
@ -123,6 +138,9 @@ export default {
|
|||
},
|
||||
moveActionUri: function() {
|
||||
return `${this.$store.getters.baseUri}/api/v2/actions/stage/move`;
|
||||
},
|
||||
baseUri: function() {
|
||||
return this.$store.getters.baseUri;
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -168,7 +186,7 @@ export default {
|
|||
}
|
||||
});
|
||||
|
||||
imjoy.start({ workspace: "default" }).then(() => {
|
||||
imjoy.start({ workspace: "default" }).then(async () => {
|
||||
console.log("ImJoy started");
|
||||
imjoy.event_bus.on("add_window", w => {
|
||||
this.addWindow(w);
|
||||
|
|
@ -176,8 +194,16 @@ export default {
|
|||
this.setupMicroscopeAPI();
|
||||
this.setupViewers();
|
||||
// load the script editor for openflexure
|
||||
this.loadPlugin(
|
||||
"https://gist.githubusercontent.com/oeway/7a9dcb49c51b1f99b2c3619f470fe35c/raw/OpenFlexureScriptEditor.imjoy.html"
|
||||
await this.loadPlugin(
|
||||
`${window.location.origin}/OpenFlexureScriptEditor.imjoy.html`
|
||||
);
|
||||
// Load the snap image template
|
||||
await this.loadPlugin(
|
||||
`${window.location.origin}/OpenFlexureSnapImageTemplate.imjoy.html`
|
||||
);
|
||||
// Load the snap image template
|
||||
await this.loadPlugin(
|
||||
`${window.location.origin}/OpenFlexureTestMoveStage.imjoy.html`
|
||||
);
|
||||
this.setupPluginEngine();
|
||||
});
|
||||
|
|
@ -232,22 +258,10 @@ export default {
|
|||
// See here: https://valelab4.ucsf.edu/~MM/doc/MMCore/html/class_c_m_m_core.html
|
||||
const snapshotUri = this.snapshotStreamUri;
|
||||
const captureActionUri = this.captureActionUri;
|
||||
const getPositionUri = this.getPositionUri;
|
||||
const moveActionUri = this.moveActionUri;
|
||||
const modalError = this.modalError;
|
||||
async function pollUntilComplete(response) {
|
||||
// Poll an action until its status is completed
|
||||
// TODO: raise an error if it fails or is cancelled
|
||||
// For ease, this accepts and returns a response object from
|
||||
// axios.get
|
||||
// FIXME: this could be an infinite loop if the task is cancelled/errored
|
||||
let r = response;
|
||||
while (r.data.status == "running" | r.data.status == "pending") {
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
r = await axios.get(r.data.href);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
const getPositionAsObject = this.getStagePosition;
|
||||
const setPositionAsObject = this.setStagePosition;
|
||||
|
||||
const service = {
|
||||
type: "_microscope-control",
|
||||
name: "OpenFlexure",
|
||||
|
|
@ -276,9 +290,7 @@ export default {
|
|||
async getImage() {
|
||||
// FIXME: handle nicely getImage() being called before snapImage()
|
||||
// Wait until the capture has completed and we can retrieve it
|
||||
service.lastSnapResponse = await pollUntilComplete(
|
||||
service.lastSnapResponse
|
||||
);
|
||||
service.lastSnapResponse = await pollAction(service.lastSnapResponse);
|
||||
let capture = service.lastSnapResponse.data.output;
|
||||
// TODO: check links.download.href exists and is JPEG
|
||||
let jpeg = await axios
|
||||
|
|
@ -299,35 +311,37 @@ export default {
|
|||
setPosition(z) {
|
||||
// The C api suggests this defaults to just Z, and can accept a "label" to
|
||||
// select the stage.
|
||||
return service.setXYZPosition({
|
||||
"z": z,
|
||||
"absolute": true,
|
||||
return setPositionAsObject({
|
||||
z: z,
|
||||
absolute: true
|
||||
});
|
||||
},
|
||||
async getPosition() {
|
||||
const pos = await service.getXYZPosition();
|
||||
return pos.z;
|
||||
const {z} = await getPositionAsObject();
|
||||
return z;
|
||||
},
|
||||
async setXYPosition(x, y) {
|
||||
return service.setXYZPosition({
|
||||
"x": x,
|
||||
"y": y,
|
||||
"absolute": true,
|
||||
return setPositionAsObject({
|
||||
x: x,
|
||||
y: y,
|
||||
absolute: true
|
||||
});
|
||||
},
|
||||
async getXYPosition() {
|
||||
const pos = await service.getXYZPosition();
|
||||
return [pos.x, pos.y];
|
||||
const {x, y} = await getPositionAsObject();
|
||||
return [x, y];
|
||||
},
|
||||
async getXYZPosition() {
|
||||
return axios
|
||||
.get(getPositionUri)
|
||||
.then(r => r.data)
|
||||
const {x, y, z} = await getPositionAsObject();
|
||||
return [x, y, z];
|
||||
},
|
||||
async setXYZPosition(payload) {
|
||||
return axios
|
||||
.post(moveActionUri, payload)
|
||||
.then(pollUntilComplete)
|
||||
async setXYZPosition(x, y, z) {
|
||||
return setPositionAsObject({
|
||||
x: x,
|
||||
y: y,
|
||||
z: z,
|
||||
absolute: true
|
||||
});
|
||||
}
|
||||
};
|
||||
this.imjoy.pm.registerService({ name: "openflexure" }, service);
|
||||
|
|
@ -463,6 +477,29 @@ export default {
|
|||
if (uri) {
|
||||
this.loadPlugin(uri);
|
||||
}
|
||||
} /*
|
||||
async getPosition() {
|
||||
const pos = await service.getXYZPosition();
|
||||
return pos.z;
|
||||
},
|
||||
async setXYPosition(x, y) {
|
||||
return service.setXYZPosition({
|
||||
"x": x,
|
||||
"y": y,
|
||||
"absolute": true,
|
||||
});
|
||||
},
|
||||
async getXYPosition() {
|
||||
const pos = await service.getXYZPosition();
|
||||
return [pos.x, pos.y];
|
||||
},*/,
|
||||
async getStagePosition() {
|
||||
return axios.get(this.getPositionUri).then(r => r.data);
|
||||
},
|
||||
async setStagePosition(payload) {
|
||||
return axios
|
||||
.post(this.moveActionUri, payload)
|
||||
.then(pollAction)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue