Support ImageJ.JS
This commit is contained in:
parent
cfa5297a23
commit
61c49e520f
3 changed files with 158 additions and 64 deletions
|
|
@ -55,7 +55,10 @@
|
|||
:current-tab="currentTab"
|
||||
@set-tab="setTab"
|
||||
>
|
||||
<img src="https://cloud.monostable.co.uk/imjoy-icon-material.svg" />
|
||||
<img
|
||||
style="filter: grayscale(100%);width: 22px;margin-top: 5px;margin-bottom: 8px;"
|
||||
src="https://imjoy.io/static/img/imjoy-icon.svg"
|
||||
/>
|
||||
</tabIcon>
|
||||
<hr id="extension-tab-divider" />
|
||||
|
||||
|
|
@ -153,7 +156,7 @@ import galleryContent from "./tabContentComponents/galleryContent.vue";
|
|||
import extensionContent from "./tabContentComponents/extensionContent.vue";
|
||||
import aboutContent from "./tabContentComponents/aboutContent.vue";
|
||||
import loggingContent from "./tabContentComponents/loggingContent.vue";
|
||||
import ImJoyContent from "./tabContentComponents/imjoyContent.vue"
|
||||
import ImJoyContent from "./tabContentComponents/imjoyContent.vue";
|
||||
|
||||
// Import modal components for device initialisation
|
||||
import calibrationModal from "./modalComponents/calibrationModal.vue";
|
||||
|
|
@ -177,7 +180,7 @@ export default {
|
|||
aboutContent,
|
||||
loggingContent,
|
||||
TabIcon,
|
||||
ImJoyContent,
|
||||
ImJoyContent
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -41,16 +41,25 @@
|
|||
>
|
||||
<a :href="metadataModalTarget" uk-toggle>More...</a>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-for="item in openInImjoyMenuItems" :key="item">
|
||||
<a href="#" @click="item.callback(name, imgURL)"
|
||||
><i class="material-icons">launch</i>{{ item.title }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="uk-card-footer uk-padding-small">
|
||||
<button class="uk-icon" type="button">
|
||||
<img
|
||||
style="width:25px;"
|
||||
src="https://imjoy.io/static/img/imjoy-icon.svg"
|
||||
/>
|
||||
</button>
|
||||
<div uk-dropdown="pos: top-center">
|
||||
<ul class="uk-nav uk-dropdown-nav">
|
||||
<li v-for="item in openInImjoyMenuItems" :key="item.name">
|
||||
<a href="#" @click="item.callback(name, imgURL)"
|
||||
><i class="material-icons">launch</i>{{ item.title }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div v-for="tag in tags" :key="tag" class="uk-display-inline">
|
||||
<span
|
||||
v-if="tag === 'temporary'"
|
||||
|
|
@ -215,7 +224,7 @@ export default {
|
|||
|
||||
computed: {
|
||||
openInImjoyMenuItems: function() {
|
||||
return this.$store.state.openInImjoyMenuItems
|
||||
return this.$store.state.openInImjoyMenuItems;
|
||||
},
|
||||
tagModalID: function() {
|
||||
return this.makeModalName("tag-modal-");
|
||||
|
|
|
|||
|
|
@ -1,11 +1,31 @@
|
|||
<template>
|
||||
<!-- Grid managing tab content -->
|
||||
<div class="uk-height-1-1 view-component">
|
||||
<button class="uk-button uk-button-default" type="button">Plugins</button>
|
||||
<button
|
||||
v-if="activeWindow"
|
||||
class="uk-button uk-button-default close-button"
|
||||
type="button"
|
||||
@click="closeActiveWindow()"
|
||||
>
|
||||
<i class="material-icons">close</i>
|
||||
</button>
|
||||
<button class="uk-button uk-button-default plugins-button" type="button">
|
||||
<img
|
||||
style="width:18px;"
|
||||
src="https://imjoy.io/static/img/imjoy-icon.svg"
|
||||
/> Plugins
|
||||
</button>
|
||||
<div uk-dropdown>
|
||||
<ul class="uk-nav uk-dropdown-nav">
|
||||
<li><a href="#" @click="loadPluginDialog()">Load Plugin</a></li>
|
||||
<li class="uk-nav-divider"></li>
|
||||
<li>
|
||||
<a href="#" @click="loadPluginDialog()">
|
||||
<i class="material-icons">add</i> Load Plugin</a
|
||||
>
|
||||
</li>
|
||||
<li
|
||||
v-if="Object.keys(loadedPlugins).length > 0"
|
||||
class="uk-nav-divider"
|
||||
></li>
|
||||
<li>
|
||||
<a
|
||||
v-for="(p, name) in loadedPlugins"
|
||||
|
|
@ -18,7 +38,7 @@
|
|||
<li class="uk-nav-divider"></li>
|
||||
<li>
|
||||
<a v-for="w in windows" :key="w.id" href="#" @click="activeWindow = w"
|
||||
><i class="material-icons">launch</i>{{ w.name }}</a
|
||||
><i class="material-icons">filter_none</i> {{ w.name }}</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -28,9 +48,9 @@
|
|||
v-for="w in windows"
|
||||
v-show="w === activeWindow"
|
||||
:key="w.id"
|
||||
class="uk-card uk-card-body imjoy-container-card"
|
||||
style="height: 100%;"
|
||||
>
|
||||
<h3 class="uk-card-title">{{ w.name }}</h3>
|
||||
<h4 class="window-title">{{ w.name }}</h4>
|
||||
<div :id="w.window_id" class="window-container"></div>
|
||||
</div>
|
||||
|
||||
|
|
@ -52,7 +72,8 @@ export default {
|
|||
windows: {},
|
||||
loading: false,
|
||||
loadedPlugins: {},
|
||||
activeWindow: null
|
||||
activeWindow: null,
|
||||
viewers: {}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
|
@ -61,16 +82,76 @@ export default {
|
|||
//imjoy config
|
||||
});
|
||||
|
||||
imjoy.start({ workspace: "default" }).then(async () => {
|
||||
imjoy.start({ workspace: "default" }).then(() => {
|
||||
console.log("ImJoy started");
|
||||
imjoy.event_bus.on("add_window", async w => {
|
||||
imjoy.event_bus.on("add_window", w => {
|
||||
this.addWindow(w);
|
||||
});
|
||||
await this.loadPlugin("https://kaibu.org/#/app");
|
||||
this.setupViewers();
|
||||
});
|
||||
this.imjoy = imjoy;
|
||||
},
|
||||
methods: {
|
||||
closeActiveWindow() {
|
||||
if (this.activeWindow) {
|
||||
this.activeWindow.api.close();
|
||||
this.activeWindow = null;
|
||||
}
|
||||
},
|
||||
selectWindow(name) {
|
||||
for (let w of Object.values(this.windows)) {
|
||||
if (w.name === name) {
|
||||
this.activeWindow = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
async setupViewers() {
|
||||
this.loading = true;
|
||||
// TODO: improve this using the ImJoy `api.getServices`
|
||||
// See here: https://imjoy.io/docs/#/api?id=apigetservices
|
||||
// The idea is that plugins can register custom services via `api.registerService`
|
||||
// For example, we can have a image visualization service
|
||||
// Then other plugins can use `api.getServices` to get a list of services
|
||||
// And this can be used for render our "Open In ImJoy" menu
|
||||
try {
|
||||
const self = this;
|
||||
this.viewers.kaibu = await this.imjoy.pm.createWindow(null, {
|
||||
name: "Kaibu",
|
||||
src: "https://kaibu.org/#/app"
|
||||
});
|
||||
this.$store.commit("addOpenInImjoyMenuItem", {
|
||||
title: "Kaibu",
|
||||
async callback(name, imageUrl) {
|
||||
self.selectWindow("Kaibu");
|
||||
const viewer = self.viewers.kaibu;
|
||||
viewer.set_mode("full");
|
||||
await viewer.view_image(imageUrl, { type: "2d-image", name });
|
||||
await viewer.add_shapes([]);
|
||||
}
|
||||
});
|
||||
this.viewers.imagej = await this.imjoy.pm.createWindow(null, {
|
||||
name: "ImageJ.JS",
|
||||
src: "https://ij.imjoy.io"
|
||||
});
|
||||
this.$store.commit("addOpenInImjoyMenuItem", {
|
||||
title: "ImageJ.JS",
|
||||
async callback(name, imageUrl) {
|
||||
self.selectWindow("ImageJ.JS");
|
||||
const viewer = self.viewers.imagej;
|
||||
const response = await fetch(imageUrl);
|
||||
const buffer = await response.arrayBuffer();
|
||||
await viewer.viewImage(buffer, {
|
||||
name: name.replace(".jpeg", ".jpg")
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
alert(`Failed to setup viewers, error: ${e}`);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
addWindow(w) {
|
||||
this.windows = this.windows || {};
|
||||
this.windows[w.window_id] = w;
|
||||
|
|
@ -78,54 +159,33 @@ export default {
|
|||
this.$forceUpdate();
|
||||
},
|
||||
loadPlugin(uri) {
|
||||
this.loading = true;
|
||||
this.imjoy.pm
|
||||
.reloadPluginRecursively({
|
||||
uri
|
||||
})
|
||||
.then(async plugin => {
|
||||
this.loadedPlugins[plugin.name] = plugin;
|
||||
this.registerOpenInImJoy(plugin);
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
alert(`failed to load the plugin, error: ${e}`);
|
||||
});
|
||||
},
|
||||
registerOpenInImJoy(plugin) {
|
||||
let item;
|
||||
// TODO: improve this using the ImJoy `api.getServices`
|
||||
// See here: https://imjoy.io/docs/#/api?id=apigetservices
|
||||
// The idea is that plugins can register custom services via `api.registerService`
|
||||
// For example, we can have a image visualization service
|
||||
// Then other plugins can use `api.getServices` to get a list of services
|
||||
// And this can be used for render our "Open In ImJoy" menu
|
||||
if (plugin.name === "Kaibu") {
|
||||
item = {
|
||||
title: "Kaibu",
|
||||
async callback(name, imageUrl) {
|
||||
const viewer = await plugin.api.run();
|
||||
viewer.set_mode('full');
|
||||
await viewer.view_image(imageUrl, {type: '2d-image', name});
|
||||
}
|
||||
};
|
||||
} else if (plugin.name === "ImageJ.JS") {
|
||||
item = {
|
||||
title: "ImageJ.JS",
|
||||
async callback(name, imageUrl) { // eslint-disable-line
|
||||
alert("not implemented");
|
||||
}
|
||||
};
|
||||
}
|
||||
if (item) this.$store.commit("addOpenInImjoyMenuItem", item);
|
||||
return new Promise((resolve, reject) => {
|
||||
this.loading = true;
|
||||
this.imjoy.pm
|
||||
.reloadPluginRecursively({
|
||||
uri
|
||||
})
|
||||
.then(async plugin => {
|
||||
this.loadedPlugins[plugin.name] = plugin;
|
||||
this.loading = false;
|
||||
resolve(plugin);
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
this.loading = false;
|
||||
reject(e);
|
||||
alert(`failed to load the plugin, error: ${e}`);
|
||||
});
|
||||
});
|
||||
},
|
||||
async runPlugin(plugin) {
|
||||
await plugin.api.run();
|
||||
},
|
||||
loadPluginDialog() {
|
||||
const uri = prompt("Paste the ImJoy plugin url here");
|
||||
const uri = prompt(
|
||||
"Paste the ImJoy plugin url here",
|
||||
"imjoy-team/imjoy-plugins:Welcome"
|
||||
);
|
||||
if (uri) {
|
||||
this.loadPlugin(uri);
|
||||
}
|
||||
|
|
@ -143,4 +203,26 @@ export default {
|
|||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.window-title {
|
||||
height: 26px;
|
||||
text-align: center;
|
||||
font-size: 1.2rem;
|
||||
background-color: #efefef;
|
||||
color: #482727;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.plugins-button {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
height: 26px;
|
||||
line-height: 11px;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
position: absolute;
|
||||
right: 100px;
|
||||
height: 26px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue