@abi-software/mapintegratedvuer 1.22.0 → 1.24.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.
Files changed (39) hide show
  1. package/dist/{ConnectivityGraph-BBZ3Dgat.js → ConnectivityGraph-CCxk8vcE.js} +6 -6
  2. package/dist/{ContentMixin-B-O_IwPg.js → ContentMixin-Db8nqZax.js} +303 -247
  3. package/dist/{DynamicMarkerMixin-B9iqtP_f.js → DynamicMarkerMixin-LB2RYdSY.js} +1 -1
  4. package/dist/{Flatmap-BoEFI50b.js → Flatmap-CqUzOkdl.js} +5 -5
  5. package/dist/{Iframe-Slj-LQTF.js → Iframe-I-xdZ2FP.js} +2 -2
  6. package/dist/{MultiFlatmap-l6aBn6x3.js → MultiFlatmap-11L97ycJ.js} +6 -6
  7. package/dist/{Plot-CIhEip5b.js → Plot-Bd9RqyVD.js} +2 -2
  8. package/dist/{Scaffold-D5ZGCDvt.js → Scaffold-CySWXQxI.js} +46 -36
  9. package/dist/Simulation-ChUbGudZ.js +32 -0
  10. package/dist/{connectivities-Br3MpoAv.js → connectivities-LtlFwLOp.js} +6399 -5790
  11. package/dist/es-D-YkSGXX.js +436 -0
  12. package/dist/mapintegratedvuer.js +13061 -11664
  13. package/dist/mapintegratedvuer.umd.cjs +191 -190
  14. package/dist/style.css +1 -1
  15. package/package.json +7 -7
  16. package/src/assets/header-icon.scss +9 -3
  17. package/src/components/ContentBar.vue +172 -92
  18. package/src/components/ContentVuer.vue +41 -1
  19. package/src/components/ContextCard.vue +15 -3
  20. package/src/components/DatasetHeader.vue +4 -1
  21. package/src/components/DialogToolbarContent.vue +45 -4
  22. package/src/components/EventBus.js +8 -0
  23. package/src/components/MapContent.vue +85 -31
  24. package/src/components/ResizeSensor.vue +7 -9
  25. package/src/components/ScreenshotPopover.vue +526 -0
  26. package/src/components/SplitDialog.vue +94 -93
  27. package/src/components/SplitFlow.vue +158 -96
  28. package/src/components/scripts/utilities.js +56 -1
  29. package/src/components/viewers/Flatmap.vue +1 -0
  30. package/src/components/viewers/MultiFlatmap.vue +3 -0
  31. package/src/components/viewers/Scaffold.vue +25 -13
  32. package/src/components/viewers/Simulation.vue +23 -1
  33. package/src/components.d.ts +2 -0
  34. package/src/mixins/ContentMixin.js +23 -10
  35. package/src/services/screenshot.js +1186 -0
  36. package/src/stores/connectivities.js +38 -5
  37. package/src/stores/settings.js +18 -0
  38. package/vite.config.js +27 -4
  39. package/dist/Simulation-C5o5DXRb.js +0 -25
@@ -57,6 +57,7 @@
57
57
  import { markRaw } from 'vue';
58
58
  import EventBus from '../EventBus';
59
59
  import ContentMixin from '../../mixins/ContentMixin';
60
+ import { snapshotThreeRenderer } from '../../services/screenshot.js';
60
61
 
61
62
  import { ScaffoldVuer } from '@abi-software/scaffoldvuer';
62
63
  import '@abi-software/scaffoldvuer/dist/style.css';
@@ -150,7 +151,10 @@ export default {
150
151
  // Both EventBus.emit and getKnowledgeTooltip will trigger sidebar content update
151
152
  // Then setVisibilityFilter will be called to zoom to the clicked nerve.
152
153
  if (resource.length === 1) {
153
- this.clickedObject = resource[0].data;
154
+ // Keep only the fields needed here; resource data carries the live
155
+ // zincObject, which should not be made reactive or retained.
156
+ const { id, isNerves, anatomicalId } = resource[0].data;
157
+ this.clickedObject = { id, isNerves, anatomicalId };
154
158
  if (this.clickedObject.isNerves || this.clickedObject.anatomicalId) {
155
159
  const label = this.clickedObject.id.toLowerCase();
156
160
  if (this.$refs.scaffold.viewingMode === 'Neuron Connection') {
@@ -245,6 +249,11 @@ export default {
245
249
  this.scaffoldCamera.onResize();
246
250
  }
247
251
  },
252
+ getScreenshotSources: async function (pixelRatio) {
253
+ const zincRenderer = this.$refs.scaffold?.$module?.zincRenderer;
254
+ if (!zincRenderer) return [];
255
+ return [snapshotThreeRenderer(zincRenderer, pixelRatio)];
256
+ },
248
257
  getState: function () {
249
258
  if (this.$refs.scaffold) {
250
259
  return this.$refs.scaffold.getState();
@@ -297,6 +306,7 @@ export default {
297
306
  },
298
307
  scaffoldIsReady: function () {
299
308
  this.scaffoldLoaded = true;
309
+ this.$emit('viewer-ready', true);
300
310
  this.$refs.scaffold.$module.graphicsHighlight.highlightColour = [1, 0, 1];
301
311
  if (!this.scaffoldRef) {
302
312
  this.scaffoldRef = markRaw(this.$refs.scaffold);
@@ -309,7 +319,7 @@ export default {
309
319
  }
310
320
  this.updateViewerSettings();
311
321
  EventBus.emit('mapLoaded', this.$refs.scaffold);
312
- setTimeout(() => {
322
+ this._greyScaleTimer = setTimeout(() => {
313
323
  this.setNerveGreyScale();
314
324
  }, 500);
315
325
  },
@@ -383,6 +393,9 @@ export default {
383
393
  ? this.settingsStore.numberOfDatasetsForFacets
384
394
  : {};
385
395
  },
396
+ scaffoldKnowledge: function () {
397
+ return this.connectivityKnowledge?.[this.entry.resource];
398
+ },
386
399
  },
387
400
  watch: {
388
401
  visible: {
@@ -403,23 +416,19 @@ export default {
403
416
  });
404
417
  }
405
418
  },
406
- deep: true,
407
419
  immediate: true,
408
420
  },
409
- connectivityKnowledge: {
410
- handler(newVal, _oldVal) {
421
+ // Knowledge entries are replaced so a shallow watch on this scaffold's entry is sufficient
422
+ scaffoldKnowledge: {
423
+ handler(scaffoldKnowledge) {
411
424
  // Store scaffold knowledge locally
412
- if (this.entry.resource in newVal) {
413
- const scaffoldKnowledge = newVal[this.entry.resource];
414
- if (scaffoldKnowledge.length !== this.nervesKnowledge.length) {
415
- this.nervesKnowledge = scaffoldKnowledge;
416
- if (this.scaffoldLoaded) {
417
- this.setNerveGreyScale();
418
- }
425
+ if (scaffoldKnowledge && scaffoldKnowledge.length !== this.nervesKnowledge.length) {
426
+ this.nervesKnowledge = scaffoldKnowledge;
427
+ if (this.scaffoldLoaded) {
428
+ this.setNerveGreyScale();
419
429
  }
420
430
  }
421
431
  },
422
- deep: true,
423
432
  immediate: true,
424
433
  },
425
434
  },
@@ -435,6 +444,9 @@ export default {
435
444
  query: '',
436
445
  };
437
446
  },
447
+ beforeUnmount: function () {
448
+ clearTimeout(this._greyScaleTimer);
449
+ },
438
450
  };
439
451
  </script>
440
452
 
@@ -1,5 +1,14 @@
1
1
  <template>
2
- <SimulationVuer :apiLocation="apiLocation" :id="id" ref="simulation" />
2
+ <SimulationVuer
3
+ v-if="isCrossOriginIsolated"
4
+ :apiLocation="apiLocation"
5
+ :id="id"
6
+ ref="simulation"
7
+ />
8
+ <div v-else class="simulation-unsupported">
9
+ Simulations require a cross-origin isolated page (for SharedArrayBuffer support). This browser
10
+ or host is not configured for it.
11
+ </div>
3
12
  </template>
4
13
 
5
14
  <script>
@@ -13,6 +22,13 @@ export default {
13
22
  components: {
14
23
  SimulationVuer,
15
24
  },
25
+ data: function () {
26
+ return {
27
+ // libOpenCOR (wasm) uses threads, which need SharedArrayBuffer and therefore COOP/COEP headers.
28
+ // Without them it aborts on Safari.
29
+ isCrossOriginIsolated: window.crossOriginIsolated === true,
30
+ };
31
+ },
16
32
  computed: {
17
33
  id: function () {
18
34
  //resource field is only available for simulation omex file and it will run locally.
@@ -22,3 +38,9 @@ export default {
22
38
  },
23
39
  };
24
40
  </script>
41
+
42
+ <style scoped lang="scss">
43
+ .simulation-unsupported {
44
+ padding: 1rem;
45
+ }
46
+ </style>
@@ -34,6 +34,7 @@ declare module 'vue' {
34
34
  ElIcon: typeof import('element-plus/es')['ElIcon']
35
35
  ElIconArrowDown: typeof import('@element-plus/icons-vue')['ArrowDown']
36
36
  ElIconArrowUp: typeof import('@element-plus/icons-vue')['ArrowUp']
37
+ ElIconCamera: typeof import('@element-plus/icons-vue')['Camera']
37
38
  ElIconCompass: typeof import('@element-plus/icons-vue')['Compass']
38
39
  ElIconEditPen: typeof import('@element-plus/icons-vue')['EditPen']
39
40
  ElIconMoreFilled: typeof import('@element-plus/icons-vue')['MoreFilled']
@@ -57,6 +58,7 @@ declare module 'vue' {
57
58
  RouterLink: typeof import('vue-router')['RouterLink']
58
59
  RouterView: typeof import('vue-router')['RouterView']
59
60
  Scaffold: typeof import('./components/viewers/Scaffold.vue')['default']
61
+ ScreenshotPopover: typeof import('./components/ScreenshotPopover.vue')['default']
60
62
  SearchControls: typeof import('./components/SearchControls.vue')['default']
61
63
  Simulation: typeof import('./components/viewers/Simulation.vue')['default']
62
64
  SplitDialog: typeof import('./components/SplitDialog.vue')['default']
@@ -6,6 +6,7 @@ import { useSettingsStore } from '../stores/settings';
6
6
  import { useSplitFlowStore } from '../stores/splitFlow';
7
7
  import { useConnectivitiesStore } from '../stores/connectivities';
8
8
  import Tagging from '../services/tagging.js';
9
+ import { snapshotMaplibre } from '../services/screenshot.js';
9
10
 
10
11
  import { getFlatmapFilterOptions } from '@abi-software/map-utilities';
11
12
  import { FlatmapQueries } from '@abi-software/flatmapvuer/src/services/flatmapQueries.js';
@@ -17,14 +18,18 @@ import {
17
18
  getTermNerveMaps,
18
19
  getFilterOptions as getScaffoldFilterOptions,
19
20
  } from '@abi-software/scaffoldvuer/src/scripts/MappedNerves.js';
20
- import { defaultSpecies } from '../components/scripts/utilities.js';
21
+ import {
22
+ defaultSpecies,
23
+ getLatestFlatmap,
24
+ getFlatmapPathways,
25
+ } from '../components/scripts/utilities.js';
21
26
 
22
27
  function capitalise(text) {
23
28
  return text[0].toUpperCase() + text.substring(1);
24
29
  }
25
30
 
26
31
  export default {
27
- emits: ['flatmap-provenance-ready', 'resource-selected', 'species-changed'],
32
+ emits: ['flatmap-provenance-ready', 'resource-selected', 'species-changed', 'viewer-ready'],
28
33
  props: {
29
34
  /**
30
35
  * Object containing information for
@@ -78,6 +83,8 @@ export default {
78
83
  },
79
84
  beforeUnmount: function () {
80
85
  this.alive = false;
86
+ window.removeEventListener('mousedown', this.checkEndHelpMouseDown);
87
+ clearTimeout(this.highlightDelay);
81
88
  },
82
89
  mounted: function () {
83
90
  if (this.$refs.multiflatmap) {
@@ -139,6 +146,17 @@ export default {
139
146
  getState: function () {
140
147
  return undefined;
141
148
  },
149
+ /**
150
+ * Return snapshots of WebGL canvases rendered at `pixelRatio`,
151
+ * used by the screenshot service. Defaults to the flatmap canvas.
152
+ */
153
+ getScreenshotSources: async function (pixelRatio) {
154
+ const map = this.getFlatmapImp?.()?.map;
155
+ if (map) {
156
+ return [await snapshotMaplibre(map, pixelRatio)];
157
+ }
158
+ return [];
159
+ },
142
160
  openMap: function (type) {
143
161
  EventBus.emit('OpenNewMap', type);
144
162
  this.trackOpenMap(`open_new_${type}_map`);
@@ -612,19 +630,14 @@ export default {
612
630
  return;
613
631
  },
614
632
  loadExplorerConfig: async function () {
615
- this.flatmapService = await this.mockUpFlatmapService();
633
+ this.flatmapService = markRaw(await this.mockUpFlatmapService());
616
634
  this.loadConnectivityExplorerConfig(this.flatmapService);
617
635
  },
618
636
  mockUpFlatmapService: async function () {
619
- const flatmapResponse = await fetch(this.flatmapAPI);
620
- const flatmapJson = await flatmapResponse.json();
621
- const latestFlatmap = flatmapJson
622
- .filter((f) => f.id === 'human-flatmap_male')
623
- .sort((a, b) => b.created.localeCompare(a.created))[0];
637
+ const latestFlatmap = await getLatestFlatmap(this.flatmapAPI, 'human-flatmap_male');
624
638
  const flatmapUuid = latestFlatmap.uuid;
625
639
  const flatmapSource = latestFlatmap.sckan['knowledge-source'];
626
- const pathwaysResponse = await fetch(`${this.flatmapAPI}/flatmap/${flatmapUuid}/pathways`);
627
- const pathwaysJson = await pathwaysResponse.json();
640
+ const pathwaysJson = await getFlatmapPathways(this.flatmapAPI, flatmapUuid);
628
641
 
629
642
  this.flatmapQueries = markRaw(new FlatmapQueries());
630
643
  this.flatmapQueries.initialise(this.flatmapAPI);