@abi-software/mapintegratedvuer 1.12.0 → 1.12.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/mapintegratedvuer",
3
- "version": "1.12.0",
3
+ "version": "1.12.1",
4
4
  "license": "Apache-2.0",
5
5
  "scripts": {
6
6
  "serve": "vite --host --force",
@@ -52,14 +52,14 @@
52
52
  "*.js"
53
53
  ],
54
54
  "dependencies": {
55
- "@abi-software/flatmapvuer": "1.11.0",
56
- "@abi-software/map-side-bar": "2.10.0",
55
+ "@abi-software/flatmapvuer": "1.11.1",
56
+ "@abi-software/map-side-bar": "2.10.2",
57
57
  "@abi-software/map-utilities": "1.7.0",
58
- "@abi-software/plotvuer": "1.0.4",
59
- "@abi-software/scaffoldvuer": "1.11.0",
60
- "@abi-software/simulationvuer": "2.0.14",
58
+ "@abi-software/plotvuer": "1.0.5",
59
+ "@abi-software/scaffoldvuer": "1.11.2",
60
+ "@abi-software/simulationvuer": "2.0.17",
61
61
  "@abi-software/sparc-annotation": "0.3.2",
62
- "@abi-software/svg-sprite": "^1.0.1",
62
+ "@abi-software/svg-sprite": "1.0.2",
63
63
  "@element-plus/icons-vue": "^2.3.1",
64
64
  "@vitejs/plugin-vue": "^4.6.2",
65
65
  "css-element-queries": "^1.2.3",
@@ -140,8 +140,5 @@
140
140
  "browserslist": [
141
141
  "> 1%",
142
142
  "last 2 versions"
143
- ],
144
- "engines": {
145
- "node": "18.17.1"
146
- }
143
+ ]
147
144
  }
@@ -98,6 +98,7 @@ import {
98
98
  ElRow as Row,
99
99
  ElSelect as Select,
100
100
  } from "element-plus";
101
+ import tagging from '../services/tagging';
101
102
 
102
103
  export default {
103
104
  name: "ContentBar",
@@ -251,6 +252,15 @@ export default {
251
252
  }, 1200);
252
253
  });
253
254
  //this.contextCardVisible = false; // Hide all context cards when switching viewers
255
+
256
+ // GA Tracking
257
+ const viewCategory = this.entries.find(entry => entry.id === value);
258
+ tagging.sendEvent({
259
+ 'event': 'interaction_event',
260
+ 'event_name': `portal_maps_toolbar_viewer_changed`,
261
+ 'category': viewCategory?.title || '',
262
+ 'location': 'map_toolbar'
263
+ });
254
264
  }
255
265
  },
256
266
  // setPopper with is needed as the flatmap context card does not have an image and has smaller with
@@ -63,7 +63,7 @@
63
63
 
64
64
  <!-- Copy to clipboard button container -->
65
65
  <div class="float-button-container">
66
- <CopyToClipboard :content="updatedCopyContent" theme="light" />
66
+ <CopyToClipboard :content="updatedCopyContent" @copied="onCopied" theme="light" />
67
67
  </div>
68
68
  </div>
69
69
  </div>
@@ -73,6 +73,7 @@
73
73
  <script>
74
74
  /* eslint-disable no-alert, no-console */
75
75
  import { CopyToClipboard } from "@abi-software/map-utilities";
76
+ import tagging from '../services/tagging';
76
77
  import '@abi-software/map-utilities/dist/style.css';
77
78
 
78
79
  //provide the s3Bucket related methods and data.
@@ -348,6 +349,17 @@ export default {
348
349
  // note that we assume that the view file is in the same directory as the scaffold (viewUrls take relative paths)
349
350
  const viewUrl = this.getFileFromPath(view.path)
350
351
  this.$emit("scaffold-view-clicked", viewUrl);
352
+ },
353
+ onCopied: function () {
354
+ const { label, type, discoverId } = this.entry;
355
+ const category = type ? `${label} ${type}` : label;
356
+ tagging.sendEvent({
357
+ 'event': 'interaction_event',
358
+ 'event_name': `portal_maps_context_card_copy`,
359
+ 'category': category || '',
360
+ 'location': 'map_toolbar',
361
+ 'dataset_id': discoverId ? discoverId + '' : '',
362
+ });
351
363
  }
352
364
  }
353
365
  };
@@ -87,7 +87,7 @@
87
87
  <template #reference>
88
88
  <el-checkbox
89
89
  v-model="globalSettings.displayMarkers"
90
- @change="updateGlobalSettings"
90
+ @change="updateGlobalSettings('displayMarkers')"
91
91
  size="small"
92
92
  :disabled="globalSettings.viewingMode !== 'Exploration'"
93
93
  >
@@ -101,7 +101,7 @@
101
101
  <div class="setting-popover-block" v-if="'connectionType' in globalSettings">
102
102
  <el-radio-group
103
103
  v-model="globalSettings.connectionType"
104
- @change="updateGlobalSettings"
104
+ @change="updateGlobalSettings('connectionType')"
105
105
  >
106
106
  <el-radio-button value="Origin" size="small">Origin</el-radio-button>
107
107
  <el-radio-button value="Via" size="small">Via</el-radio-button>
@@ -306,7 +306,7 @@
306
306
  <!-- <div class="setting-popover-block" v-if="'displayMarkers' in globalSettings">
307
307
  <el-checkbox
308
308
  v-model="globalSettings.displayMarkers"
309
- @change="updateGlobalSettings"
309
+ @change="updateGlobalSettings('displayMarkers')"
310
310
  >
311
311
  Display Map Markers
312
312
  </el-checkbox>
@@ -316,14 +316,14 @@
316
316
  <el-checkbox
317
317
  v-if="'highlightConnectedPaths' in globalSettings"
318
318
  v-model="globalSettings.highlightConnectedPaths"
319
- @change="updateGlobalSettings"
319
+ @change="updateGlobalSettings('highlightConnectedPaths')"
320
320
  >
321
321
  Highlight Connected Paths
322
322
  </el-checkbox>
323
323
  <el-checkbox
324
324
  v-if="'highlightDOIPaths' in globalSettings"
325
325
  v-model="globalSettings.highlightDOIPaths"
326
- @change="updateGlobalSettings"
326
+ @change="updateGlobalSettings('highlightDOIPaths')"
327
327
  >
328
328
  Highlight DOI Paths
329
329
  </el-checkbox>
@@ -332,7 +332,7 @@
332
332
  <h5>Interactive Mode</h5>
333
333
  <el-radio-group
334
334
  v-model="globalSettings.interactiveMode"
335
- @change="updateGlobalSettings"
335
+ @change="updateGlobalSettings('interactiveMode')"
336
336
  >
337
337
  <el-radio value="dataset">Dataset Exploration</el-radio>
338
338
  <el-radio value="connectivity">Connectivity Exploration</el-radio>
@@ -344,7 +344,7 @@
344
344
  <h5>Flight path</h5>
345
345
  <el-radio-group
346
346
  v-model="globalSettings.flightPathDisplay"
347
- @change="updateGlobalSettings"
347
+ @change="updateGlobalSettings('flightPathDisplay')"
348
348
  >
349
349
  <el-radio :value="false">2D</el-radio>
350
350
  <el-radio :value="true">3D</el-radio>
@@ -354,7 +354,7 @@
354
354
  <h5>Organs</h5>
355
355
  <el-radio-group
356
356
  v-model="globalSettings.organsDisplay"
357
- @change="updateGlobalSettings"
357
+ @change="updateGlobalSettings('organsDisplay')"
358
358
  >
359
359
  <el-radio :value="true">Color</el-radio>
360
360
  <el-radio :value="false">Grayscale</el-radio>
@@ -364,7 +364,7 @@
364
364
  <h5>Apply outlines</h5>
365
365
  <el-radio-group
366
366
  v-model="globalSettings.outlinesDisplay"
367
- @change="updateGlobalSettings"
367
+ @change="updateGlobalSettings('outlinesDisplay')"
368
368
  >
369
369
  <el-radio :value="true">Show</el-radio>
370
370
  <el-radio :value="false">Hide</el-radio>
@@ -375,7 +375,7 @@
375
375
  <el-radio-group
376
376
  class="bg-color-radio-group"
377
377
  v-model="globalSettings.backgroundDisplay"
378
- @change="updateGlobalSettings"
378
+ @change="updateGlobalSettings('backgroundDisplay')"
379
379
  >
380
380
  <el-radio value="white" class="bg-color-radio">
381
381
  <span style="--bg-color: white">white</span>
@@ -443,6 +443,7 @@ import {
443
443
  ElRadioGroup as RadioGroup,
444
444
  ElRow as Row,
445
445
  } from "element-plus";
446
+ import tagging from '../services/tagging';
446
447
 
447
448
  /**
448
449
  * Cmponent for the header of differnt vuers.
@@ -551,10 +552,10 @@ export default {
551
552
  this.globalSettings.interactiveMode = 'connectivity';
552
553
  }
553
554
 
554
- this.updateGlobalSettings();
555
+ this.updateGlobalSettings('viewingMode');
555
556
  }
556
557
  },
557
- updateGlobalSettings: function() {
558
+ updateGlobalSettings: function(changedKey) {
558
559
  const updatedSettings = this.settingsStore.getUpdatedGlobalSettingsKey(this.globalSettings);
559
560
  this.settingsStore.updateGlobalSettings(this.globalSettings);
560
561
 
@@ -574,20 +575,71 @@ export default {
574
575
  updatedSettings.includes('backgroundDisplay')) {
575
576
  EventBus.emit('globalViewerSettingsUpdate');
576
577
  }
578
+
579
+ // GA Tracking
580
+ let category = this.globalSettings[changedKey];
581
+
582
+ // Format category for some items
583
+ if (changedKey === 'flightPathDisplay') {
584
+ category = this.globalSettings.flightPathDisplay ? '3D' : '2D';
585
+ }
586
+ if (changedKey === 'organsDisplay') {
587
+ category = this.globalSettings.organsDisplay ? 'Color': 'Grayscale';
588
+ }
589
+ if (changedKey === 'outlinesDisplay') {
590
+ category = this.globalSettings.outlinesDisplay ? 'Show' : 'Hide';
591
+ }
592
+
593
+ // Prevent viewing mode clicks on active item
594
+ if (updatedSettings.length) {
595
+ tagging.sendEvent({
596
+ 'event': 'interaction_event',
597
+ 'event_name': `portal_maps_settings_${changedKey}`,
598
+ 'category': category,
599
+ 'location': 'map_toolbar'
600
+ });
601
+ }
577
602
  },
578
603
  titleClicked: function(id) {
579
604
  this.$emit("titleClicked", id);
580
605
  },
581
606
  startHelp: function(){
582
607
  EventBus.emit("startHelp");
608
+
609
+ // GA Tracking
610
+ tagging.sendEvent({
611
+ 'event': 'interaction_event',
612
+ 'event_name': `portal_maps_toolbar_help`,
613
+ 'category': 'help_mode_start',
614
+ 'location': 'map_toolbar'
615
+ });
583
616
  },
584
617
  onFullscreen: function() {
585
618
  this.$emit("onFullscreen");
586
619
  this.isFullscreen = !this.isFullscreen;
620
+
621
+ // GA Tracking
622
+ // only for fullscreen enter event to prevent duplicate events
623
+ if (this.isFullscreen) {
624
+ tagging.sendEvent({
625
+ 'event': 'interaction_event',
626
+ 'event_name': `portal_maps_toolbar_fullscreen`,
627
+ 'category': this.isFullscreen ? 'enter' : 'exit',
628
+ 'location': 'map_toolbar'
629
+ });
630
+ }
587
631
  },
588
632
  onFullscreenEsc: function () {
589
633
  if (!document.fullscreenElement) {
590
634
  this.isFullscreen = false;
635
+
636
+ // GA Tracking
637
+ tagging.sendEvent({
638
+ 'event': 'interaction_event',
639
+ 'event_name': `portal_maps_toolbar_fullscreen`,
640
+ 'category': this.isFullscreen ? 'enter' : 'exit',
641
+ 'location': 'map_toolbar'
642
+ });
591
643
  }
592
644
  },
593
645
  close: function() {
@@ -597,6 +649,14 @@ export default {
597
649
  if (document) {
598
650
  this.$refs.linkInput.$el.querySelector("input").select();
599
651
  document.execCommand('copy');
652
+
653
+ // GA Tracking
654
+ tagging.sendEvent({
655
+ 'event': 'interaction_event',
656
+ 'event_name': 'portal_maps_permalink',
657
+ 'category': 'permalink_copy',
658
+ 'location': 'map_toolbar'
659
+ });
600
660
  }
601
661
  },
602
662
  setFailedSearch: function(result) {
@@ -613,13 +673,34 @@ export default {
613
673
  this.displayShareOptions = false;
614
674
  this.loadingLink = true;
615
675
  EventBus.emit("updateShareLinkRequested", withAnnotation);
676
+
677
+ // GA Tracking
678
+ tagging.sendEvent({
679
+ 'event': 'interaction_event',
680
+ 'event_name': 'portal_maps_permalink',
681
+ 'category': 'permalink_generate',
682
+ 'location': 'map_toolbar'
683
+ });
616
684
  },
617
685
  viewClicked: function(view) {
686
+ const prevActiveView = this.activeView;
687
+
618
688
  this.splitFlowStore.updateActiveView({
619
689
  view,
620
690
  entries: this.entriesStore.entries,
621
691
  });
622
692
 
693
+ // GA Tracking
694
+ if (view !== prevActiveView) {
695
+ const viewCategory = this.viewIcons.find((item) => item.icon === view);
696
+ tagging.sendEvent({
697
+ 'event': 'interaction_event',
698
+ 'event_name': `portal_maps_toolbar_split_view`,
699
+ 'category': viewCategory?.name || '',
700
+ 'location': 'map_toolbar'
701
+ });
702
+ }
703
+
623
704
  if (this.$refs.viewPopover) {
624
705
  this.$refs.viewPopover.hide();
625
706
  }
@@ -13,7 +13,7 @@
13
13
 
14
14
  <!-- Copy to clipboard button container -->
15
15
  <div class="float-button-container">
16
- <CopyToClipboard :content="updatedCopyContent" theme="light" />
16
+ <CopyToClipboard :content="updatedCopyContent" @copied="onCopied" theme="light" />
17
17
  </div>
18
18
  </div>
19
19
  </template>
@@ -25,6 +25,7 @@ import {
25
25
  ElLoading as Loading
26
26
  } from "element-plus";
27
27
  import { CopyToClipboard } from "@abi-software/map-utilities";
28
+ import tagging from '../services/tagging';
28
29
  import '@abi-software/map-utilities/dist/style.css';
29
30
 
30
31
  export default {
@@ -126,6 +127,16 @@ export default {
126
127
  return contentArray.join('\n\n<br>');
127
128
  },
128
129
  },
130
+ methods: {
131
+ onCopied: function () {
132
+ tagging.sendEvent({
133
+ 'event': 'interaction_event',
134
+ 'event_name': `portal_maps_context_card_copy`,
135
+ 'category': this.mapImpProv?.id || 'Flatmap Provenance',
136
+ 'location': 'map_toolbar'
137
+ });
138
+ },
139
+ },
129
140
  };
130
141
  </script>
131
142
 
@@ -50,6 +50,7 @@
50
50
  @connectivity-source-change="onConnectivitySourceChange"
51
51
  @filter-visibility="onFilterVisibility"
52
52
  @connectivity-item-close="onConnectivityItemClose"
53
+ @trackEvent="trackEvent"
53
54
  />
54
55
  <SplitDialog
55
56
  :entries="entries"
@@ -126,7 +127,6 @@ export default {
126
127
  search: '',
127
128
  expanded: '',
128
129
  filterTriggered: false,
129
- availableFacets: [],
130
130
  connectivityEntry: [],
131
131
  annotationEntry: [],
132
132
  annotationCallback: undefined,
@@ -279,13 +279,31 @@ export default {
279
279
  Tagging.sendEvent({
280
280
  'event': 'interaction_event',
281
281
  'event_name': 'portal_maps_action_filter',
282
- 'category': facetString || 'filter',
282
+ 'category': facetString || 'filter_reset',
283
283
  'location': 'map_location_pin'
284
284
  });
285
285
  this.filterTriggered = true;
286
286
  }
287
287
  } else if (action.type == "Facets") {
288
288
  const facets = [];
289
+ const facetsArray = action.facets ? action.facets : action.labels;
290
+ const availableFacetsRaw = localStorage.getItem('available-anatomy-facets');
291
+ const availableFacetsAll = availableFacetsRaw ? JSON.parse(availableFacetsRaw) : [];
292
+
293
+ // get label values
294
+ let availableFacets = availableFacetsAll.flatMap(facet => {
295
+ if (facet.children && facet.children.length) {
296
+ return [facet.label, ...facet.children.map(child => child.label)];
297
+ }
298
+ return facet.label;
299
+ }).map(label => label.toLowerCase());
300
+
301
+ // remove duplicate items
302
+ availableFacets = [...new Set(availableFacets)];
303
+
304
+ const filterValuesArray = intersectArrays(availableFacets, facetsArray);
305
+ const filterValues = filterValuesArray.join(', ');
306
+
289
307
  this.settingsStore.facets.species.forEach(e => {
290
308
  facets.push({
291
309
  facet: capitalise(e),
@@ -293,8 +311,9 @@ export default {
293
311
  facetPropPath: "organisms.primary.species.name",
294
312
  });
295
313
  });
314
+
296
315
  facets.push(
297
- ...action.facets.map(val => ({
316
+ ...filterValuesArray.map(val => ({
298
317
  facet: capitalise(val),
299
318
  term: "Anatomical structure",
300
319
  facetPropPath: "anatomy.organ.category.name",
@@ -302,14 +321,12 @@ export default {
302
321
  }))
303
322
  );
304
323
  this.openSearch(facets, "")
305
- const filterValuesArray = intersectArrays(this.availableFacets, action.labels);
306
- const filterValues = filterValuesArray.join(', ');
307
324
  // GA Tagging
308
325
  // Event tracking for map action search/filter data
309
326
  Tagging.sendEvent({
310
327
  'event': 'interaction_event',
311
328
  'event_name': 'portal_maps_action_filter',
312
- 'category': filterValues || 'filter',
329
+ 'category': filterValues || 'filter_reset',
313
330
  'location': 'map_popup_button'
314
331
  });
315
332
  this.filterTriggered = true;
@@ -448,7 +465,9 @@ export default {
448
465
  },
449
466
  openAnnotation: function (payload) {
450
467
  this.annotationEntry = payload.annotationEntry;
451
- this.annotationHighlight = this.annotationEntry.map(entry => entry.models);
468
+ // If drawing, `entry.models` may be undefined; use an empty array instead of [undefined]
469
+ // to prevent errors on highlight
470
+ this.annotationHighlight = this.annotationEntry.map(entry => entry.models).filter(Boolean);
452
471
  if (payload.commitCallback) {
453
472
  this.annotationCallback = markRaw(payload.commitCallback);
454
473
  }
@@ -513,7 +532,7 @@ export default {
513
532
  'event': 'interaction_event',
514
533
  'event_name': 'portal_maps_action_search',
515
534
  'category': this.search,
516
- 'location': 'map_sidebar_search'
535
+ 'location': 'map_sidebar_dataset_search'
517
536
  });
518
537
  }
519
538
  this.filterTriggered = false; // reset for next action
@@ -534,8 +553,8 @@ export default {
534
553
  Tagging.sendEvent({
535
554
  'event': 'interaction_event',
536
555
  'event_name': 'portal_maps_action_filter',
537
- 'category': filterValues || 'filter',
538
- 'location': 'map_sidebar_filter'
556
+ 'category': filterValues || 'filter_reset',
557
+ 'location': 'map_sidebar_dataset_filter'
539
558
  });
540
559
  }
541
560
  this.filterTriggered = false; // reset for next action
@@ -555,6 +574,29 @@ export default {
555
574
  activeFlatmap.updateConnectivityFilters(data.filter);
556
575
  });
557
576
  EventBus.emit("connectivity-query-filter", data);
577
+
578
+ const filterValues = data.filter.filter(f => (f.facet && f.facet.toLowerCase() !== 'show all'))
579
+ .map((f) => f.tagLabel)
580
+ .join(', ');
581
+ const searchValue = data.query;
582
+
583
+ if (filterValues) {
584
+ Tagging.sendEvent({
585
+ 'event': 'interaction_event',
586
+ 'event_name': 'portal_maps_action_filter',
587
+ 'category': filterValues,
588
+ 'location': 'map_sidebar_connectivity_filter'
589
+ });
590
+ }
591
+
592
+ if (searchValue) {
593
+ Tagging.sendEvent({
594
+ 'event': 'interaction_event',
595
+ 'event_name': 'portal_maps_action_search',
596
+ 'category': searchValue,
597
+ 'location': 'map_sidebar_connectivity_search'
598
+ });
599
+ }
558
600
  }
559
601
  }
560
602
  },
@@ -794,6 +836,9 @@ export default {
794
836
  this.settingsStore.updateGlobalSettings(state.globalSettings);
795
837
  }
796
838
  },
839
+ trackEvent: function (data) {
840
+ Tagging.sendEvent(data);
841
+ },
797
842
  },
798
843
  created: function () {
799
844
  this._facets = [];
@@ -164,7 +164,12 @@ const getBodyScaffoldInfo = async (sparcApi, species) => {
164
164
 
165
165
  // Array intersection
166
166
  const intersectArrays = (arr1, arr2) => {
167
- return arr1.filter((x) => arr2.includes(x));
167
+ const lowerArr2 = arr2.map(x => typeof x === 'string' ? x.toLowerCase() : x);
168
+ return arr1.filter(x =>
169
+ typeof x === 'string'
170
+ ? lowerArr2.includes(x.toLowerCase())
171
+ : lowerArr2.includes(x)
172
+ );
168
173
  };
169
174
 
170
175
  // Not using URLSearchParams to avoid encoding spaces
@@ -39,6 +39,7 @@
39
39
  @pathway-selection-changed="onPathwaySelectionChanged"
40
40
  @mapmanager-loaded="onMapmanagerLoaded"
41
41
  :showPathwayFilter="false"
42
+ @trackEvent="trackEvent"
42
43
  />
43
44
 
44
45
  <HelpModeDialog
@@ -40,6 +40,7 @@
40
40
  @open-pubmed-url="onOpenPubmedUrl"
41
41
  @mapmanager-loaded="onMapmanagerLoaded"
42
42
  :showPathwayFilter="false"
43
+ @trackEvent="trackEvent"
43
44
  />
44
45
 
45
46
  <HelpModeDialog
@@ -760,6 +760,9 @@ export default {
760
760
  })
761
761
  EventBus.emit('connectivity-info-open', this.tooltipEntry);
762
762
  },
763
+ trackEvent: function (data) {
764
+ Tagging.sendEvent(data);
765
+ },
763
766
  },
764
767
  data: function () {
765
768
  return {