@abi-software/flatmapvuer 1.4.2 → 1.4.3-image.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/flatmapvuer.js +21922 -21447
- package/dist/flatmapvuer.umd.cjs +108 -102
- package/dist/style.css +1 -1
- package/package.json +8 -5
- package/src/App.vue +13 -1
- package/src/components/FlatmapVuer.vue +191 -36
- package/src/components/MultiFlatmapVuer.vue +17 -1
- package/src/main.js +1 -1
- package/src/mixins/imageMixin.js +116 -0
- package/src/services/scicrunchQueries.js +280 -0
- package/src/stores/settings.js +46 -0
- /package/src/{store → stores}/index.js +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
methods: {
|
|
3
|
+
populateMapWithImages: function (mapImp, images, type) {
|
|
4
|
+
this.downloadImageKeys = []; // to count downloaded images
|
|
5
|
+
for (const [key, list] of Object.entries(images)) {
|
|
6
|
+
// Exclude empty list
|
|
7
|
+
if (list.length) {
|
|
8
|
+
this.downloadImageThumbnail(mapImp, key, list, type);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
downloadImageThumbnail: function (mapImp, key, list, type) {
|
|
13
|
+
// This inner list count will be updated by failed download
|
|
14
|
+
const count = list.length;
|
|
15
|
+
|
|
16
|
+
if (!this.downloadImageKeys.includes(key)) {
|
|
17
|
+
this.downloadImageKeys.push(key);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (count > 0) {
|
|
21
|
+
//Pick a random image
|
|
22
|
+
const index = Math.floor(Math.random() * count);
|
|
23
|
+
const thumbnail = list[index].thumbnail;
|
|
24
|
+
this.getThumbnail(thumbnail, type)
|
|
25
|
+
.then((wrapperElement) => {
|
|
26
|
+
this.downloadImageKeys = this.downloadImageKeys.filter((item) => item !== key);
|
|
27
|
+
this.addImageThumbnailMarker(mapImp, key, wrapperElement);
|
|
28
|
+
|
|
29
|
+
// All images are downloaded
|
|
30
|
+
if (!this.downloadImageKeys.length) {
|
|
31
|
+
this.imagesDownloading = false;
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
.catch(() => {
|
|
35
|
+
//Failed to download, pick another one
|
|
36
|
+
list.splice(index);
|
|
37
|
+
this.downloadImageThumbnail(mapImp, key, list, type);
|
|
38
|
+
});
|
|
39
|
+
} else {
|
|
40
|
+
if (this.downloadImageKeys.includes(key)) {
|
|
41
|
+
this.downloadImageKeys = this.downloadImageKeys.filter((item) => item !== key);
|
|
42
|
+
|
|
43
|
+
// Failed to download, the last item
|
|
44
|
+
if (!this.downloadImageKeys.length) {
|
|
45
|
+
this.imagesDownloading = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
getThumbnail: async function (url, type) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
if (type === "Image" || type === "Segmentation") {
|
|
53
|
+
this.getBinaryThumbnail(url)
|
|
54
|
+
.then((response) => resolve(response))
|
|
55
|
+
.catch((response) => reject(response));
|
|
56
|
+
} else {
|
|
57
|
+
this.getGenericThumbnail(url)
|
|
58
|
+
.then((response) => resolve(response))
|
|
59
|
+
.catch((response) => reject(response));
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
getBinaryThumbnail: async function (url) {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
fetch(url)
|
|
66
|
+
.then((response) => {
|
|
67
|
+
if (response.status >= 200 && response.status < 300) {
|
|
68
|
+
return response.text();
|
|
69
|
+
} else {
|
|
70
|
+
reject();
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
.then((data) => {
|
|
74
|
+
if (data) {
|
|
75
|
+
let img = new Image();
|
|
76
|
+
let wrapperElement = document.createElement("div");
|
|
77
|
+
img.style = "height: auto;width: 50px;margin-right: 80px;";
|
|
78
|
+
img.onload = function () {
|
|
79
|
+
wrapperElement.appendChild(img);
|
|
80
|
+
resolve(wrapperElement);
|
|
81
|
+
};
|
|
82
|
+
img.onerror = function () {
|
|
83
|
+
reject(new Error("Failed to load image at " + url));
|
|
84
|
+
};
|
|
85
|
+
img.src = `data:'image/png';base64,${data}`;
|
|
86
|
+
} else {
|
|
87
|
+
reject(new Error("Failed to load image at " + url));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
getGenericThumbnail: async function (url) {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
let img = new Image();
|
|
95
|
+
let wrapperElement = document.createElement("div");
|
|
96
|
+
img.style = "height: auto;width: 50px;margin-right: 80px;";
|
|
97
|
+
img.onload = function () {
|
|
98
|
+
wrapperElement.appendChild(img);
|
|
99
|
+
resolve(wrapperElement);
|
|
100
|
+
};
|
|
101
|
+
img.onerror = function () {
|
|
102
|
+
reject(new Error("Failed to load image at " + url));
|
|
103
|
+
};
|
|
104
|
+
img.src = url;
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
addImageThumbnailMarker: function (mapImp, id, wrapperElement) {
|
|
108
|
+
const markerIdentifier = mapImp.addMarker(id, {
|
|
109
|
+
element: wrapperElement,
|
|
110
|
+
className: "highlight-marker",
|
|
111
|
+
cluster: false,
|
|
112
|
+
type: "image",
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
};
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
const getOrganCuries = async (sparcApi, filetypes = [], species = []) => {
|
|
2
|
+
let params = new URLSearchParams();
|
|
3
|
+
filetypes.forEach((type) => {
|
|
4
|
+
params.append("filetypes", type);
|
|
5
|
+
});
|
|
6
|
+
species.forEach((name) => {
|
|
7
|
+
params.append("species", name);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const response = await fetch(`${sparcApi}/get-organ-curies/?${params}`);
|
|
11
|
+
const data = await response.json();
|
|
12
|
+
|
|
13
|
+
let organCuries = [];
|
|
14
|
+
data.uberon.array.forEach((pair) => {
|
|
15
|
+
const organCurie = {
|
|
16
|
+
id: pair.id.toUpperCase(),
|
|
17
|
+
name: pair.name,
|
|
18
|
+
};
|
|
19
|
+
organCuries.push(organCurie);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return organCuries;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const getFilesInfoForCuries = async (sparcApi, organCuries, filetypes) => {
|
|
26
|
+
const response = await fetch(`${sparcApi}/get-files-info-for-curies`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
body: JSON.stringify({
|
|
29
|
+
curies: organCuries.map((item) => item.id),
|
|
30
|
+
filetypes: filetypes,
|
|
31
|
+
}),
|
|
32
|
+
headers: {
|
|
33
|
+
"Content-Type": "application/json",
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
|
|
38
|
+
return data;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getFileNameFromPath = (filePath) => {
|
|
42
|
+
return filePath.substring(filePath.lastIndexOf("/") + 1);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const getBiolucidaThumbnailURL = (sparcApi, biolucidaId) => {
|
|
46
|
+
return `${sparcApi}/thumbnail/${biolucidaId}`;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const getBiolucidaThumbnails = async (sparcApi, organCuries, type) => {
|
|
50
|
+
try {
|
|
51
|
+
const data = await getFilesInfoForCuries(sparcApi, organCuries, [
|
|
52
|
+
"biolucida-2d",
|
|
53
|
+
"biolucida-3d",
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
if (data["files_info"]) {
|
|
57
|
+
let images = {};
|
|
58
|
+
for (const [key, value] of Object.entries(data["files_info"])) {
|
|
59
|
+
if (value.length > 0) {
|
|
60
|
+
let list = [];
|
|
61
|
+
value.forEach((entry) => {
|
|
62
|
+
const thumbnailURL = getBiolucidaThumbnailURL(
|
|
63
|
+
sparcApi,
|
|
64
|
+
entry.biolucida_id
|
|
65
|
+
);
|
|
66
|
+
if (entry.biolucida_id) {
|
|
67
|
+
let image = {
|
|
68
|
+
thumbnail: thumbnailURL,
|
|
69
|
+
resource: entry.file_path,
|
|
70
|
+
id: entry.id,
|
|
71
|
+
title: getFileNameFromPath(entry.file_path),
|
|
72
|
+
type: type,
|
|
73
|
+
link: thumbnailURL,
|
|
74
|
+
mimetype: entry.mimetype,
|
|
75
|
+
species: entry.species,
|
|
76
|
+
version: entry.version,
|
|
77
|
+
};
|
|
78
|
+
list.push(image);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
images[key] = list;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return images;
|
|
85
|
+
}
|
|
86
|
+
} catch (error) {
|
|
87
|
+
console.error("Error:", error);
|
|
88
|
+
}
|
|
89
|
+
return {};
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const getSegmentationThumbnailURL = (
|
|
93
|
+
sparcApi,
|
|
94
|
+
datasetId,
|
|
95
|
+
datasetVersion,
|
|
96
|
+
filePath
|
|
97
|
+
) => {
|
|
98
|
+
return `${sparcApi}/thumbnail/neurolucida?datasetId=${datasetId}&version=${datasetVersion}&path=files/${filePath}`;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const getSegmentationThumbnails = async (sparcApi, organCuries, type) => {
|
|
102
|
+
try {
|
|
103
|
+
const data = await getFilesInfoForCuries(sparcApi, organCuries, [
|
|
104
|
+
"mbf-segmentation",
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
if (data["files_info"]) {
|
|
108
|
+
let images = {};
|
|
109
|
+
for (const [key, value] of Object.entries(data["files_info"])) {
|
|
110
|
+
if (value.length > 0) {
|
|
111
|
+
let list = [];
|
|
112
|
+
value.forEach((entry) => {
|
|
113
|
+
const thumbnailURL = getSegmentationThumbnailURL(
|
|
114
|
+
sparcApi,
|
|
115
|
+
entry.id,
|
|
116
|
+
entry.version,
|
|
117
|
+
entry.file_path
|
|
118
|
+
);
|
|
119
|
+
let image = {
|
|
120
|
+
thumbnail: thumbnailURL,
|
|
121
|
+
resource: entry.file_path,
|
|
122
|
+
id: entry.id,
|
|
123
|
+
title: getFileNameFromPath(entry.file_path),
|
|
124
|
+
type: type,
|
|
125
|
+
link: thumbnailURL,
|
|
126
|
+
mimetype: entry.mimetype,
|
|
127
|
+
species: entry.species,
|
|
128
|
+
version: entry.version,
|
|
129
|
+
};
|
|
130
|
+
list.push(image);
|
|
131
|
+
});
|
|
132
|
+
images[key] = list;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return images;
|
|
136
|
+
}
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error("Error:", error);
|
|
139
|
+
}
|
|
140
|
+
return {};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const findEntryWithPathInArray = (entry, list, type) => {
|
|
144
|
+
if (entry && list) {
|
|
145
|
+
for (let i = 0; i < entry.isSourceOf.length; i++) {
|
|
146
|
+
for (let l = 0; l < list.length; l++) {
|
|
147
|
+
const item = list[l];
|
|
148
|
+
if (
|
|
149
|
+
entry.id === item.id &&
|
|
150
|
+
(!type || item.type === type) &&
|
|
151
|
+
entry.isSourceOf[i] === item.file_path
|
|
152
|
+
) {
|
|
153
|
+
return item;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const getScaffoldThumbnailURL = (sparcApi, entry, list) => {
|
|
162
|
+
const viewEntry = findEntryWithPathInArray(
|
|
163
|
+
entry,
|
|
164
|
+
list,
|
|
165
|
+
"abi-scaffold-view-file"
|
|
166
|
+
);
|
|
167
|
+
const thumbnailEntry = findEntryWithPathInArray(
|
|
168
|
+
viewEntry,
|
|
169
|
+
list,
|
|
170
|
+
"abi-thumbnail"
|
|
171
|
+
);
|
|
172
|
+
if (thumbnailEntry) {
|
|
173
|
+
return `${sparcApi}/s3-resource/${thumbnailEntry.id}/files/${thumbnailEntry.file_path}`;
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
const getScaffoldThumbnails = async (sparcApi, organCuries, type) => {
|
|
179
|
+
try {
|
|
180
|
+
const data = await getFilesInfoForCuries(sparcApi, organCuries, [
|
|
181
|
+
"abi-thumbnail",
|
|
182
|
+
"abi-scaffold-metadata-file",
|
|
183
|
+
"abi-scaffold-view-file",
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
if (data["files_info"]) {
|
|
187
|
+
let images = {};
|
|
188
|
+
for (const [key, value] of Object.entries(data["files_info"])) {
|
|
189
|
+
if (value.length > 0) {
|
|
190
|
+
let list = [];
|
|
191
|
+
value.forEach((entry) => {
|
|
192
|
+
if (entry.type === "abi-scaffold-metadata-file") {
|
|
193
|
+
const thumbnailURL = getScaffoldThumbnailURL(
|
|
194
|
+
sparcApi,
|
|
195
|
+
entry,
|
|
196
|
+
value
|
|
197
|
+
);
|
|
198
|
+
if (thumbnailURL) {
|
|
199
|
+
let image = {
|
|
200
|
+
thumbnail: thumbnailURL,
|
|
201
|
+
resource: entry.file_path,
|
|
202
|
+
id: entry.id,
|
|
203
|
+
title: getFileNameFromPath(entry.file_path),
|
|
204
|
+
type: type,
|
|
205
|
+
link: thumbnailURL,
|
|
206
|
+
species: entry.species,
|
|
207
|
+
version: entry.version,
|
|
208
|
+
};
|
|
209
|
+
list.push(image);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
images[key] = list;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return images;
|
|
217
|
+
}
|
|
218
|
+
} catch (error) {
|
|
219
|
+
console.error("Error:", error);
|
|
220
|
+
}
|
|
221
|
+
return {};
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const getPlotThumbnailURL = (sparcApi, entry) => {
|
|
225
|
+
//None of the thumbnail for plot is properly annotated.
|
|
226
|
+
//We will use the first in is source of for testing.
|
|
227
|
+
if (entry.isSourceOf.length > 0) {
|
|
228
|
+
return `${sparcApi}/s3-resource/${entry.id}/files/${entry.isSourceOf[0]}`;
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const getPlotThumbnails = async (sparcApi, organCuries, type) => {
|
|
234
|
+
try {
|
|
235
|
+
const data = await getFilesInfoForCuries(sparcApi, organCuries, [
|
|
236
|
+
"abi-plot",
|
|
237
|
+
"abi-thumbnail",
|
|
238
|
+
]);
|
|
239
|
+
|
|
240
|
+
if (data["files_info"]) {
|
|
241
|
+
let images = {};
|
|
242
|
+
for (const [key, value] of Object.entries(data["files_info"])) {
|
|
243
|
+
if (value.length > 0) {
|
|
244
|
+
let list = [];
|
|
245
|
+
value.forEach((entry) => {
|
|
246
|
+
if (entry.type === "abi-plot") {
|
|
247
|
+
const thumbnailURL = getPlotThumbnailURL(sparcApi, entry);
|
|
248
|
+
if (thumbnailURL) {
|
|
249
|
+
let image = {
|
|
250
|
+
thumbnail: thumbnailURL,
|
|
251
|
+
resource: entry.file_path,
|
|
252
|
+
id: entry.id,
|
|
253
|
+
title: getFileNameFromPath(entry.file_path),
|
|
254
|
+
type: type,
|
|
255
|
+
link: thumbnailURL,
|
|
256
|
+
species: entry.species,
|
|
257
|
+
version: entry.version,
|
|
258
|
+
};
|
|
259
|
+
list.push(image);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
images[key] = list;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return images;
|
|
267
|
+
}
|
|
268
|
+
} catch (error) {
|
|
269
|
+
console.error("Error:", error);
|
|
270
|
+
}
|
|
271
|
+
return {};
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
export {
|
|
275
|
+
getOrganCuries,
|
|
276
|
+
getBiolucidaThumbnails,
|
|
277
|
+
getSegmentationThumbnails,
|
|
278
|
+
getScaffoldThumbnails,
|
|
279
|
+
getPlotThumbnails,
|
|
280
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineStore } from "pinia";
|
|
2
|
+
|
|
3
|
+
/* eslint-disable no-alert, no-console */
|
|
4
|
+
|
|
5
|
+
export const useSettingsStore = defineStore("settings", {
|
|
6
|
+
state: () => {
|
|
7
|
+
return {
|
|
8
|
+
organCuries: [],
|
|
9
|
+
imageTypes: [],
|
|
10
|
+
imageThumbnails: {},
|
|
11
|
+
};
|
|
12
|
+
},
|
|
13
|
+
getters: {
|
|
14
|
+
imageTypeCached: (state) => (imageType) => {
|
|
15
|
+
return state.imageTypes.includes(imageType);
|
|
16
|
+
},
|
|
17
|
+
getImageThumbnails:
|
|
18
|
+
(state) =>
|
|
19
|
+
(imageType, uberonIds = undefined) => {
|
|
20
|
+
if (uberonIds) {
|
|
21
|
+
let thumbnails = {};
|
|
22
|
+
Object.entries(state.imageThumbnails).forEach(([key, value]) => {
|
|
23
|
+
if (uberonIds.includes(key)) {
|
|
24
|
+
thumbnails[key] = value.filter((item) => item.type === imageType);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
return thumbnails;
|
|
28
|
+
}
|
|
29
|
+
return state.imageThumbnails;
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
actions: {
|
|
33
|
+
updateOrganCuries(organCuries) {
|
|
34
|
+
this.organCuries = organCuries;
|
|
35
|
+
},
|
|
36
|
+
updateImageThumbnails(imageType, imageThumbnails) {
|
|
37
|
+
this.imageTypes.push(imageType);
|
|
38
|
+
Object.keys(imageThumbnails).forEach((key) => {
|
|
39
|
+
if (!(key in this.imageThumbnails)) {
|
|
40
|
+
this.imageThumbnails[key] = [];
|
|
41
|
+
}
|
|
42
|
+
this.imageThumbnails[key].push(...imageThumbnails[key]);
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
File without changes
|