@abi-software/mapintegratedvuer 1.17.2 → 1.17.3-simulation.1
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/{ConnectivityGraph-BL4B9GZX.js → ConnectivityGraph-9pXPgFJR.js} +2 -2
- package/dist/{ContentMixin-Djmb_gqk.js → ContentMixin-DIqgKIz6.js} +279 -536
- package/dist/Flatmap-D7GVPV7o.js +103422 -0
- package/dist/{Iframe-ByYxT4Yq.js → Iframe-CCEA3d9c.js} +2 -2
- package/dist/{MultiFlatmap-DSkdlRiS.js → MultiFlatmap-Cuke1uNp.js} +3 -3
- package/dist/{Plot-ymkHVq_A.js → Plot-B4oTBVAT.js} +2 -2
- package/dist/{Scaffold-bw7posKm.js → Scaffold-Czz8X5kL.js} +79 -53
- package/dist/Simulation-BKmz8zwm.js +107 -0
- package/dist/{index-CwfUgFL1.js → index-_b4VBGHk.js} +30002 -25408
- package/dist/mapintegratedvuer.js +1 -1
- package/dist/mapintegratedvuer.umd.cjs +4291 -229
- package/dist/style-CM86xE3J.js +119 -0
- package/dist/style.css +1 -1
- package/package.json +10 -5
- package/src/App.vue +285 -258
- package/src/assets/styles.scss +1 -1
- package/src/components/ContextCard.vue +0 -1
- package/src/components/DummyRouteComponent.vue +1 -0
- package/src/components/EventBus.ts +13 -0
- package/src/components/FloatingWindow.vue +142 -0
- package/src/components/MapContent.vue +9 -4
- package/src/components/PlotComponent.vue +56 -0
- package/src/components/SplitDialog.vue +1 -6
- package/src/components/SplitFlow.vue +504 -444
- package/src/components/scripts/utilities.js +1 -1
- package/src/components/viewers/Flatmap.vue +166 -83
- package/src/components/viewers/Simulation.vue +118 -11
- package/src/components.d.ts +3 -0
- package/src/main.js +9 -3
- package/src/mixins/ContentMixin.js +467 -406
- package/src/mixins/DynamicMarkerMixin.js +50 -17
- package/src/services/mapping.js +69 -0
- package/src/services/testData.js +71 -0
- package/src/stores/entries.js +1 -1
- package/src/stores/mapping.js +29 -0
- package/src/stores/settings.js +4 -0
- package/src/stores/simulationPlotStore.js +124 -0
- package/src/stores/splitFlow.js +425 -352
- package/src/types/simulation.js +18 -0
- package/dist/Flatmap-uPEQNDkK.js +0 -202
- package/dist/Simulation-C_gdqDes.js +0 -28
- package/dist/style-Czqe2bTf.js +0 -57
- package/src/components/EventBus.js +0 -3
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
import { mapStores } from 'pinia';
|
|
3
3
|
import { useSettingsStore } from '../stores/settings';
|
|
4
|
+
import { retrieveProtocolData } from '../services/testData.js';
|
|
5
|
+
import { markRaw } from 'vue'
|
|
4
6
|
|
|
5
7
|
// remove duplicates by stringifying the objects
|
|
6
8
|
const removeDuplicates = function (arrayOfAnything) {
|
|
@@ -9,12 +11,18 @@ const removeDuplicates = function (arrayOfAnything) {
|
|
|
9
11
|
JSON.parse(e)
|
|
10
12
|
)
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
|
|
13
15
|
/* eslint-disable no-alert, no-console */
|
|
14
16
|
export default {
|
|
15
17
|
computed: {
|
|
16
18
|
...mapStores(useSettingsStore),
|
|
17
19
|
},
|
|
20
|
+
data: function () {
|
|
21
|
+
return {
|
|
22
|
+
protocolData: undefined,
|
|
23
|
+
markerToUberonID: {},
|
|
24
|
+
}
|
|
25
|
+
},
|
|
18
26
|
methods: {
|
|
19
27
|
flatmapPanZoomCallback: function (payload) {
|
|
20
28
|
if (this.mouseHovered) {
|
|
@@ -33,22 +41,23 @@ export default {
|
|
|
33
41
|
*/
|
|
34
42
|
flatmapMarkerUpdate(flatmap) {
|
|
35
43
|
if (!this.flatmapReady) return;
|
|
44
|
+
if (!this.protocolData) {
|
|
45
|
+
let flatmapImp = flatmap;
|
|
46
|
+
if (!flatmapImp)
|
|
47
|
+
flatmapImp = this.getFlatmapImp();
|
|
36
48
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
49
|
+
if (flatmapImp) {
|
|
50
|
+
// Set the dataset markers
|
|
51
|
+
let markers = this.settingsStore.globalSettings.displayMarkers ? this.settingsStore.markers : [];
|
|
52
|
+
markers = removeDuplicates(markers);
|
|
53
|
+
flatmapImp.clearMarkers();
|
|
54
|
+
flatmapImp.clearDatasetMarkers();
|
|
55
|
+
flatmapImp.addDatasetMarkers(markers);
|
|
40
56
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
flatmapImp.clearMarkers();
|
|
46
|
-
flatmapImp.clearDatasetMarkers();
|
|
47
|
-
flatmapImp.addDatasetMarkers(markers);
|
|
48
|
-
|
|
49
|
-
// Set the featured markers
|
|
50
|
-
if (this.entry.type === "MultiFlatmap") {
|
|
51
|
-
this.restoreFeaturedMarkers(flatmapImp);
|
|
57
|
+
// Set the featured markers
|
|
58
|
+
if (this.entry.type === "MultiFlatmap") {
|
|
59
|
+
this.restoreFeaturedMarkers(flatmapImp);
|
|
60
|
+
}
|
|
52
61
|
}
|
|
53
62
|
}
|
|
54
63
|
},
|
|
@@ -72,12 +81,36 @@ export default {
|
|
|
72
81
|
}
|
|
73
82
|
return markersOnFlatmap;
|
|
74
83
|
},
|
|
75
|
-
|
|
84
|
+
updateProtocolMarkers: function (flatmapImp, ids) {
|
|
85
|
+
flatmapImp.clearMarkers()
|
|
86
|
+
if (ids.length > 0) {
|
|
87
|
+
ids.forEach((id) => {
|
|
88
|
+
const terms = flatmapImp.sparqlQuery(`
|
|
89
|
+
prefix bgf: <https://bg-rdf.org/ontologies/bondgraph-framework#>
|
|
90
|
+
prefix UBERON: <http://purl.obolibrary.org/obo/UBERON_>
|
|
91
|
+
select ?featureUri where {
|
|
92
|
+
?featureUri bgf:hasLocation ?region
|
|
93
|
+
filter (?region in (${id}))
|
|
94
|
+
}`)
|
|
95
|
+
const result = terms[0]
|
|
96
|
+
const featureUri = result.get('featureUri').value
|
|
97
|
+
const fID = flatmapImp.addMarkerByFeatureUri(featureUri)
|
|
98
|
+
this.markerToUberonID[fID] = id
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
flatmapReadyForMarkerUpdates: async function (flatmap) {
|
|
76
103
|
if (flatmap) {
|
|
77
104
|
flatmap.enablePanZoomEvents(true); // Use zoom events for dynamic markers
|
|
78
105
|
this.flatmapReady = true;
|
|
79
106
|
const flatmapImp = flatmap.mapImp;
|
|
80
|
-
|
|
107
|
+
if (flatmapImp) {
|
|
108
|
+
const flatmapUUID = flatmapImp.mapMetadata.uuid;
|
|
109
|
+
this.protocolData = markRaw(await retrieveProtocolData(this.settingsStore.testDataLocation, flatmapUUID));
|
|
110
|
+
if (!this.protocolData) {
|
|
111
|
+
this.flatmapMarkerUpdate(flatmapImp);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
81
114
|
}
|
|
82
115
|
},
|
|
83
116
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import readXlsxFile from 'read-excel-file'
|
|
2
|
+
|
|
3
|
+
const BASE_URL =
|
|
4
|
+
'https://raw.githubusercontent.com/hsorby/fc-feature-mapping/main/'
|
|
5
|
+
const INDEX_FILE = 'mapping_index.json'
|
|
6
|
+
|
|
7
|
+
export class MappingService {
|
|
8
|
+
// Find the correct Excel file for the current Flatmap
|
|
9
|
+
static async getMappingIndex() {
|
|
10
|
+
try {
|
|
11
|
+
// Fetch the master index
|
|
12
|
+
const response = await fetch(`${BASE_URL}${INDEX_FILE}`)
|
|
13
|
+
if (!response.ok) throw new Error('Failed to fetch index')
|
|
14
|
+
|
|
15
|
+
const index = await response.json()
|
|
16
|
+
|
|
17
|
+
return index || null
|
|
18
|
+
} catch (e) {
|
|
19
|
+
console.error('Error finding map mapping:', e)
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Fetch and Parse the Excel file
|
|
25
|
+
static async loadMapping(index) {
|
|
26
|
+
const flatmapMap = new Map()
|
|
27
|
+
|
|
28
|
+
for (const entry in index) {
|
|
29
|
+
try {
|
|
30
|
+
const filename = index[entry]
|
|
31
|
+
|
|
32
|
+
const response = await fetch(`${BASE_URL}${filename}`)
|
|
33
|
+
if (!response.ok) throw new Error(`Failed to fetch ${filename}`)
|
|
34
|
+
|
|
35
|
+
// Get the binary data
|
|
36
|
+
const blob = await response.blob()
|
|
37
|
+
|
|
38
|
+
// Parse with read-excel-file
|
|
39
|
+
// rows is an array of arrays: [ ["Header1", "Header2"], ["Row1Col1", "Row1Col2"] ]
|
|
40
|
+
const rows = await readXlsxFile(blob)
|
|
41
|
+
|
|
42
|
+
// Remove header row
|
|
43
|
+
const headers = rows.shift()
|
|
44
|
+
const nameIndex = headers.indexOf('Name')
|
|
45
|
+
const componentIndex = headers.indexOf('Component')
|
|
46
|
+
const flatmapIdIndex = headers.indexOf('Flatmap ID')
|
|
47
|
+
|
|
48
|
+
// Convert to a Lookup Map for fast access
|
|
49
|
+
// Assuming Column 0 = FlatmapID, Column 1 = Component, Column 2 = Variable
|
|
50
|
+
const lookup = new Map()
|
|
51
|
+
|
|
52
|
+
rows.forEach((row) => {
|
|
53
|
+
const flatmapId = row[flatmapIdIndex]
|
|
54
|
+
const component = row[componentIndex]
|
|
55
|
+
const variable = row[nameIndex]
|
|
56
|
+
|
|
57
|
+
if (flatmapId && component && variable) {
|
|
58
|
+
lookup.set(flatmapId, { component, variable })
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
flatmapMap.set(entry, lookup)
|
|
62
|
+
} catch (e) {
|
|
63
|
+
console.error('Error parsing mapping file:', e)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return flatmapMap
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const resolveURL = (relative, base) => {
|
|
2
|
+
const resolved = new URL(relative, base);
|
|
3
|
+
return resolved.href;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const readProtocolData = async (item, baseUrl) => {
|
|
7
|
+
if (item && item.resource?.url) {
|
|
8
|
+
const resolvedUrl = resolveURL(item.resource.url, baseUrl);
|
|
9
|
+
const response = await fetch(resolvedUrl)
|
|
10
|
+
const data = await response.json()
|
|
11
|
+
//convert url
|
|
12
|
+
const fields = ["csv_file", "protocol", "thumbnail"]
|
|
13
|
+
data.forEach((protocol) => {
|
|
14
|
+
fields.forEach((field) => {
|
|
15
|
+
if (field in protocol) {
|
|
16
|
+
protocol[field] = resolveURL(protocol[field], resolvedUrl)
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
})
|
|
20
|
+
return data
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const updateProtocolData = async (entry, baseUrl) => {
|
|
27
|
+
if (entry["simulation-protocols"]) {
|
|
28
|
+
const processedData = [];
|
|
29
|
+
for (const item of entry["simulation-protocols"]) {
|
|
30
|
+
const data = await readProtocolData(item, baseUrl);
|
|
31
|
+
if (data) {
|
|
32
|
+
processedData.push(...data);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return processedData;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const getProtocolData = async (uuid, data, baseUrl) => {
|
|
40
|
+
const processedResults = [];
|
|
41
|
+
for (const entry of data) {
|
|
42
|
+
let found = false;
|
|
43
|
+
if (entry.flatmaps) {
|
|
44
|
+
for (const flatmap of entry.flatmaps) {
|
|
45
|
+
if (flatmap.associated_flatmap?.identifier === uuid) {
|
|
46
|
+
found = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (found) {
|
|
51
|
+
const results = await updateProtocolData(entry, baseUrl);
|
|
52
|
+
if (results) {
|
|
53
|
+
processedResults.push(...results);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return processedResults;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const retrieveProtocolData = async (url, uuid) => {
|
|
61
|
+
if (url) {
|
|
62
|
+
const response = await fetch(url);
|
|
63
|
+
const data = await response.json();
|
|
64
|
+
return await getProtocolData(uuid, data, url);
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export {
|
|
70
|
+
retrieveProtocolData
|
|
71
|
+
};
|
package/src/stores/entries.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineStore } from 'pinia';
|
|
2
2
|
import { initialDefaultState } from "../components/scripts/utilities";
|
|
3
|
-
import { getKnowledgeSourceFromProvenance } from '@abi-software/flatmapvuer
|
|
3
|
+
import { getKnowledgeSourceFromProvenance } from '@abi-software/flatmapvuer';
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-alert, no-console */
|
|
6
6
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { MappingService } from '../services/mapping'
|
|
3
|
+
|
|
4
|
+
export const useMappingStore = defineStore('mapping', {
|
|
5
|
+
state: () => ({
|
|
6
|
+
elementMap: new Map(),
|
|
7
|
+
}),
|
|
8
|
+
|
|
9
|
+
actions: {
|
|
10
|
+
async initializeMapping() {
|
|
11
|
+
this.elementMap.clear()
|
|
12
|
+
|
|
13
|
+
// Find which file to load
|
|
14
|
+
const index = await MappingService.getMappingIndex()
|
|
15
|
+
|
|
16
|
+
if (index) {
|
|
17
|
+
// Parse and store
|
|
18
|
+
this.elementMap = await MappingService.loadMapping(index)
|
|
19
|
+
} else {
|
|
20
|
+
console.warn('No index found.')
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
// Helper to get data for a specific element ID
|
|
25
|
+
mapToCellMLIdentifiers(flatmapUuid, flatmapElementId) {
|
|
26
|
+
return this.elementMap.get(flatmapUuid)?.get(flatmapElementId) || { component: undefined, variable: undefined }
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
})
|
package/src/stores/settings.js
CHANGED
|
@@ -14,6 +14,7 @@ export const useSettingsStore = defineStore('settings', {
|
|
|
14
14
|
flatmapAPI: undefined,
|
|
15
15
|
mapManager: undefined,
|
|
16
16
|
rootUrl: undefined,
|
|
17
|
+
testDataLocation: undefined,
|
|
17
18
|
facets: { species: [], gender: [], organ: [] },
|
|
18
19
|
appliedFacets: [],
|
|
19
20
|
numberOfDatasetsForFacets: [],
|
|
@@ -116,6 +117,9 @@ export const useSettingsStore = defineStore('settings', {
|
|
|
116
117
|
updateRootUrl(rootUrl) {
|
|
117
118
|
this.rootUrl = rootUrl;
|
|
118
119
|
},
|
|
120
|
+
updateTestDataLocation(testDataLocation) {
|
|
121
|
+
this.testDataLocation = testDataLocation;
|
|
122
|
+
},
|
|
119
123
|
updateMarkers(markers) {
|
|
120
124
|
this.markers = markers;
|
|
121
125
|
},
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import EventBus from '../components/EventBus'
|
|
4
|
+
|
|
5
|
+
const BASE_Z_INDEX = 100
|
|
6
|
+
|
|
7
|
+
export const useSimulationPlotStore = defineStore('simulationPlot', () => {
|
|
8
|
+
const windows = ref([])
|
|
9
|
+
const zStack = ref([])
|
|
10
|
+
const simulationEntries = ref({})
|
|
11
|
+
|
|
12
|
+
function initListeners() {
|
|
13
|
+
EventBus.on('simulation-response', handleSimulationResponse)
|
|
14
|
+
EventBus.on('simulation-ready', handleSimulationReady)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function cleanupListeners() {
|
|
18
|
+
EventBus.off('simulation-response', handleSimulationResponse)
|
|
19
|
+
EventBus.off('simulation-ready', handleSimulationReady)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function removeWindow(windowId) {
|
|
23
|
+
const targetWindow = windows.value.find(win => win.id === windowId)
|
|
24
|
+
if (!targetWindow) return
|
|
25
|
+
windows.value = windows.value.filter((win) => win.id !== windowId)
|
|
26
|
+
zStack.value = zStack.value.filter((stackId) => stackId !== windowId)
|
|
27
|
+
EventBus.emit('plot-window-closed', { id: targetWindow.id})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function refreshZIndices() {
|
|
31
|
+
windows.value.forEach((win) => {
|
|
32
|
+
// Find where this window sits in the stack
|
|
33
|
+
const stackIndex = zStack.value.indexOf(win.id)
|
|
34
|
+
|
|
35
|
+
// If found, assign zIndex. If not (error case), keep it low.
|
|
36
|
+
if (stackIndex !== -1) {
|
|
37
|
+
win.zIndex = BASE_Z_INDEX + stackIndex
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function bringToFront(windowId) {
|
|
43
|
+
const stackIndex = zStack.value.indexOf(windowId)
|
|
44
|
+
if (stackIndex === -1) return // Should not happen
|
|
45
|
+
|
|
46
|
+
zStack.value.splice(stackIndex, 1)
|
|
47
|
+
|
|
48
|
+
zStack.value.push(windowId)
|
|
49
|
+
|
|
50
|
+
refreshZIndices()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function handleSimulationReady(data) {
|
|
54
|
+
simulationEntries.value[data.resourceId] = { ready: data.ready, entryId: data.entryId }
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getEntryIdWithResource(data) {
|
|
58
|
+
if (!data.resource || !simulationEntries.value[data.resource]?.ready) return 0
|
|
59
|
+
return simulationEntries.value[data.resource].entryId
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function runExperimentalData(data) {
|
|
63
|
+
const entryId = getEntryIdWithResource(data)
|
|
64
|
+
if (entryId) {
|
|
65
|
+
console.log("Fire", simulationEntries.value[data.resource].entryId, data)
|
|
66
|
+
EventBus.emit('simulation-external-data', {
|
|
67
|
+
targetEntryId: simulationEntries.value[data.resource].entryId,
|
|
68
|
+
action: data,
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
return entryId
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function requestSimulation(data) {
|
|
75
|
+
if (data.protocol === null || !simulationEntries.value[data.protocol?.resource]?.ready) return
|
|
76
|
+
|
|
77
|
+
let targetWindow = windows.value.find(win => win.id === data.windowId)
|
|
78
|
+
if (!targetWindow) {
|
|
79
|
+
targetWindow = {
|
|
80
|
+
label: data.label,
|
|
81
|
+
id: data.windowId,
|
|
82
|
+
ownerId: data.ownerId,
|
|
83
|
+
data: null,
|
|
84
|
+
zIndex: BASE_Z_INDEX,
|
|
85
|
+
x: data.position.x + data.offset.left,
|
|
86
|
+
y: data.position.y + data.offset.top,
|
|
87
|
+
}
|
|
88
|
+
windows.value.push(targetWindow)
|
|
89
|
+
zStack.value.push(targetWindow.id)
|
|
90
|
+
refreshZIndices()
|
|
91
|
+
} else {
|
|
92
|
+
bringToFront(targetWindow.id)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
EventBus.emit('simulation-data-request', {
|
|
96
|
+
id: 'nz.ac.auckland.simulation-data-request',
|
|
97
|
+
version: '0.1.0',
|
|
98
|
+
payload: data,
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function handleSimulationResponse(response) {
|
|
103
|
+
if (response.id !== 'nz.ac.auckland.simulation-data-response') return
|
|
104
|
+
const targetWindow = windows.value.find(win => win.id === response.payload.windowId)
|
|
105
|
+
|
|
106
|
+
if (targetWindow) {
|
|
107
|
+
targetWindow.data = response.payload.data
|
|
108
|
+
} else {
|
|
109
|
+
console.warn('Received simulation response for unknown window ID:', response.payload.windowId)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
windows,
|
|
115
|
+
bringToFront,
|
|
116
|
+
cleanupListeners,
|
|
117
|
+
getEntryIdWithResource,
|
|
118
|
+
handleSimulationResponse,
|
|
119
|
+
requestSimulation,
|
|
120
|
+
runExperimentalData,
|
|
121
|
+
initListeners,
|
|
122
|
+
removeWindow,
|
|
123
|
+
}
|
|
124
|
+
})
|