@abi-software/flatmapvuer 1.5.6 → 1.6.0-beta.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.
@@ -257,7 +257,7 @@ Please use `const` to assign meaningful names to them...
257
257
  <div
258
258
  class="pathway-location"
259
259
  :class="{ open: drawerOpen, close: !drawerOpen }"
260
- v-show="!(disableUI || isCentreLine)"
260
+ v-show="!disableUI"
261
261
  >
262
262
  <div
263
263
  class="pathway-container"
@@ -388,17 +388,6 @@ Please use `const` to assign meaningful names to them...
388
388
  ref="taxonSelection"
389
389
  key="taxonSelection"
390
390
  />
391
- <selections-group
392
- v-if="!(isCentreLine || isFC) && centreLines && centreLines.length > 0"
393
- title="Nerves"
394
- labelKey="label"
395
- identifierKey="key"
396
- :selections="centreLines"
397
- @changed="centreLinesSelected"
398
- @selections-data-changed="onSelectionsDataChanged"
399
- ref="centrelinesSelection"
400
- key="centrelinesSelection"
401
- />
402
391
  </div>
403
392
  <div
404
393
  @click="toggleDrawer"
@@ -519,8 +508,8 @@ Please use `const` to assign meaningful names to them...
519
508
  class="flatmap-radio"
520
509
  @change="setFlightPath3D"
521
510
  >
522
- <el-radio :label="false">2D</el-radio>
523
- <el-radio :label="true">3D</el-radio>
511
+ <el-radio :value="false">2D</el-radio>
512
+ <el-radio :value="true">3D</el-radio>
524
513
  </el-radio-group>
525
514
  </el-row>
526
515
  <el-row class="backgroundSpacer"></el-row>
@@ -531,8 +520,8 @@ Please use `const` to assign meaningful names to them...
531
520
  class="flatmap-radio"
532
521
  @change="setColour"
533
522
  >
534
- <el-radio :label="true">Colour</el-radio>
535
- <el-radio :label="false">Greyscale</el-radio>
523
+ <el-radio :value="true">Colour</el-radio>
524
+ <el-radio :value="false">Greyscale</el-radio>
536
525
  </el-radio-group>
537
526
  </el-row>
538
527
  <el-row class="backgroundSpacer"></el-row>
@@ -543,8 +532,8 @@ Please use `const` to assign meaningful names to them...
543
532
  class="flatmap-radio"
544
533
  @change="setOutlines"
545
534
  >
546
- <el-radio :label="true">Show</el-radio>
547
- <el-radio :label="false">Hide</el-radio>
535
+ <el-radio :value="true">Show</el-radio>
536
+ <el-radio :value="false">Hide</el-radio>
548
537
  </el-radio-group>
549
538
  </el-row>
550
539
  <el-row class="backgroundSpacer"></el-row>
@@ -634,7 +623,7 @@ Please use `const` to assign meaningful names to them...
634
623
 
635
624
  <script>
636
625
  /* eslint-disable no-alert, no-console */
637
- import { shallowRef, markRaw } from 'vue'
626
+ import { inject, provide, shallowRef, markRaw } from 'vue'
638
627
  import {
639
628
  WarningFilled as ElIconWarningFilled,
640
629
  ArrowDown as ElIconArrowDown,
@@ -658,8 +647,9 @@ import {
658
647
  import flatmapMarker from '../icons/flatmap-marker'
659
648
  import {
660
649
  FlatmapQueries,
661
- findTaxonomyLabel,
650
+ findTaxonomyLabels,
662
651
  } from '../services/flatmapQueries.js'
652
+ import { capitalise } from './utilities.js'
663
653
  import yellowstar from '../icons/yellowstar'
664
654
  import ResizeSensor from 'css-element-queries/src/ResizeSensor'
665
655
  import * as flatmap from '@abi-software/flatmap-viewer'
@@ -717,28 +707,6 @@ const processFTUs = (parent, key) => {
717
707
  return ftus
718
708
  }
719
709
 
720
- const processSystems = (systems) => {
721
- const allSystems = []
722
- if (systems && systems.length > 0) {
723
- const data = { label: 'All', key: 'All', children: [] }
724
- systems.forEach((system) => {
725
- const child = {
726
- colour: system.colour,
727
- enabled: system.enabled,
728
- label: system.id,
729
- key: system.id,
730
- }
731
- const children = processFTUs(system, child.key)
732
- if (children.length > 0) child.children = children
733
- data.children.push(child)
734
- })
735
-
736
- allSystems.push(data)
737
- }
738
-
739
- return allSystems
740
- }
741
-
742
710
  const createUnfilledTooltipData = function () {
743
711
  return {
744
712
  destinations: [],
@@ -784,10 +752,23 @@ export default {
784
752
  this.setStateRequired = false
785
753
  },
786
754
  setup(props) {
787
- const annotator = markRaw(new AnnotationService(`${props.flatmapAPI}annotator`));
755
+ let annotator = inject('$annotator')
756
+ if (!annotator) {
757
+ annotator = markRaw(new AnnotationService(`${props.flatmapAPI}annotator`));
758
+ provide('$annotator', annotator)
759
+ }
788
760
  return { annotator }
789
761
  },
790
762
  methods: {
763
+ /**
764
+ * @public
765
+ * Function to manually send aborted signal when annotation tooltip popup or sidebar tab closed.
766
+ */
767
+ manualAbortedOnClose: function () {
768
+ if (this.annotationSidebar) this.$emit("annotation-close")
769
+ this.closeTooltip()
770
+ this.annotationEventCallback({}, { type: 'aborted' })
771
+ },
791
772
  /**
792
773
  * @public
793
774
  * Function to initialise drawing.
@@ -804,6 +785,7 @@ export default {
804
785
  */
805
786
  cancelDrawnFeature: function () {
806
787
  if (this.isValidDrawnCreated) {
788
+ if (this.annotationSidebar) this.$emit("annotation-close")
807
789
  this.closeTooltip()
808
790
  this.annotationEntry = {
809
791
  ...this.drawnCreatedEvent.feature,
@@ -861,17 +843,13 @@ export default {
861
843
  * @arg {String} `name`
862
844
  */
863
845
  toolbarEvent: function (type, name) {
864
- this.closeTooltip()
846
+ this.manualAbortedOnClose()
865
847
  this.doubleClickedFeature = false
866
848
  this.connectionEntry = {}
867
849
  if (type === 'mode') {
868
850
  // Deselect any feature when draw mode is changed
869
851
  this.changeAnnotationDrawMode({ mode: 'simple_select' })
870
852
  this.activeDrawMode = name
871
- // rollback modified feature when exit edit/delete mode
872
- if (Object.keys(this.annotationEntry).length > 0 && !this.featureAnnotationSubmitted) {
873
- this.rollbackAnnotationEvent()
874
- }
875
853
  } else if (type === 'tool') {
876
854
  if (name) {
877
855
  const tool = name.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`)
@@ -990,12 +968,11 @@ export default {
990
968
  this.featureAnnotationSubmitted = true
991
969
  this.mapImp.commitAnnotationEvent(this.annotationEntry)
992
970
  if (this.annotationEntry.type === 'deleted') {
971
+ if (this.annotationSidebar) this.$emit("annotation-close")
993
972
  this.closeTooltip()
994
973
  this.annotationEntry = {}
995
- } else {
996
- // Update 'existDrawnFeatures' when created or updated event
997
- this.addAnnotationFeature()
998
974
  }
975
+ this.addAnnotationFeature()
999
976
  }
1000
977
  },
1001
978
  /**
@@ -1088,6 +1065,7 @@ export default {
1088
1065
  setDrawnType: function (flag) {
1089
1066
  this.drawnType = flag
1090
1067
  if (this.mapImp) {
1068
+ this.manualAbortedOnClose()
1091
1069
  this.addAnnotationFeature()
1092
1070
  this.initialiseDrawing()
1093
1071
  }
@@ -1100,6 +1078,7 @@ export default {
1100
1078
  setAnnotatedType: function (flag) {
1101
1079
  this.annotatedType = flag
1102
1080
  if (this.mapImp) {
1081
+ this.manualAbortedOnClose()
1103
1082
  this.addAnnotationFeature()
1104
1083
  }
1105
1084
  },
@@ -1166,7 +1145,6 @@ export default {
1166
1145
  if (children.length > 0) child.children = children
1167
1146
  data.children.push(child)
1168
1147
  })
1169
-
1170
1148
  this.systems.push(data)
1171
1149
  }
1172
1150
  },
@@ -1177,14 +1155,22 @@ export default {
1177
1155
  * @arg {String} `flatmapAPI`,
1178
1156
  * @arg {Array} `taxonIdentifiers`
1179
1157
  */
1180
- processTaxon: function (flatmapAPI, taxonIdentifiers) {
1158
+ processTaxon: function (taxonIdentifiers, state) {
1181
1159
  this.taxonConnectivity.length = 0
1182
- taxonIdentifiers.forEach((taxon) => {
1183
- findTaxonomyLabel(flatmapAPI, taxon).then((value) => {
1184
- const item = { taxon, label: value }
1185
- this.taxonConnectivity.push(item)
1186
- })
1187
- })
1160
+ findTaxonomyLabels(this.mapImp, taxonIdentifiers).then((entityLabels) => {
1161
+ if (entityLabels.length) {
1162
+ entityLabels.forEach((entityLabel) => {
1163
+ let enabled = true
1164
+ if (state) {
1165
+ enabled = state.checkAll ? true : state.checked.includes(entityLabel.taxon)
1166
+ }
1167
+ this.taxonConnectivity.push({...entityLabel, enabled});
1168
+ if (this.mapImp) {
1169
+ this.mapImp.enableConnectivityByTaxonIds(entityLabel.taxon, enabled)
1170
+ }
1171
+ });
1172
+ }
1173
+ });
1188
1174
  },
1189
1175
  /**
1190
1176
  * @public
@@ -1202,7 +1188,7 @@ export default {
1202
1188
  setColour: function (flag) {
1203
1189
  this.colourRadio = flag
1204
1190
  if (this.mapImp) {
1205
- this.mapImp.setColour({ colour: flag, outline: this.outlinesRadio })
1191
+ this.mapImp.setPaint({ colour: flag, outline: this.outlinesRadio })
1206
1192
  }
1207
1193
  },
1208
1194
  /**
@@ -1212,9 +1198,25 @@ export default {
1212
1198
  * @arg {Boolean} `flag`
1213
1199
  */
1214
1200
  setOutlines: function (flag) {
1215
- this.outlineRadio = flag
1201
+ this.outlinesRadio = flag
1202
+ if (this.mapImp) {
1203
+ this.mapImp.setPaint({ colour: this.colourRadio, outline: flag })
1204
+ }
1205
+ },
1206
+ setInitMapState: function () {
1216
1207
  if (this.mapImp) {
1217
- this.mapImp.setColour({ colour: this.colourRadio, outline: flag })
1208
+ const map = this.mapImp._map;
1209
+ const bounds = this.mapImp.options.bounds;
1210
+ const initBounds = [
1211
+ [bounds[0], bounds[1]],
1212
+ [bounds[2], bounds[3]]
1213
+ ];
1214
+
1215
+ map.setMaxBounds(null); // override default
1216
+
1217
+ this.initMapState = {
1218
+ initBounds,
1219
+ };
1218
1220
  }
1219
1221
  },
1220
1222
  /**
@@ -1224,9 +1226,18 @@ export default {
1224
1226
  */
1225
1227
  resetView: function () {
1226
1228
  if (this.mapImp) {
1227
- this.mapImp.resetMap()
1228
- if (this.$refs.centrelinesSelection) {
1229
- this.$refs.centrelinesSelection.reset()
1229
+ // fit to window
1230
+ const map = this.mapImp._map;
1231
+ const { initBounds } = this.initMapState;
1232
+ // reset rotation
1233
+ map.resetNorthPitch({
1234
+ animate: false,
1235
+ });
1236
+ if (initBounds) {
1237
+ // reset zoom and position
1238
+ map.fitBounds(initBounds, {
1239
+ animate: false
1240
+ });
1230
1241
  }
1231
1242
  if (this.$refs.skcanSelection) {
1232
1243
  this.$refs.skcanSelection.reset()
@@ -1262,18 +1273,6 @@ export default {
1262
1273
  this.mapImp.zoomOut()
1263
1274
  }
1264
1275
  },
1265
- /**
1266
- * @public
1267
- * Function to show or hide centrelines and nodes.
1268
- * The parameter ``payload`` is an object with a boolean property, ``value``,
1269
- * ``payload.value = true/false``.
1270
- * @arg {Object} `payload`
1271
- */
1272
- centreLinesSelected: function (payload) {
1273
- if (this.mapImp) {
1274
- this.mapImp.enableCentrelines(payload.value)
1275
- }
1276
- },
1277
1276
  onSelectionsDataChanged: function (data) {
1278
1277
  this.$emit('pathway-selection-changed', data);
1279
1278
  },
@@ -1314,7 +1313,7 @@ export default {
1314
1313
  let pathFeatures = paths.map((p) => this.mapImp.featureProperties(p))
1315
1314
 
1316
1315
  // Query the flatmap knowledge graph for connectivity, we use this to grab the origins
1317
- let connectivity = await this.flatmapQueries.queryForConnectivity(payload)
1316
+ let connectivity = await this.flatmapQueries.queryForConnectivityNew(this.mapImp, payload)
1318
1317
 
1319
1318
  // Check and flatten the origins node graph
1320
1319
  let originsFlat = connectivity?.ids?.dendrites?.flat().flat()
@@ -1582,8 +1581,12 @@ export default {
1582
1581
  // Rollback drawing when no new annotation submitted
1583
1582
  if (!this.featureAnnotationSubmitted) this.rollbackAnnotationEvent()
1584
1583
  else this.featureAnnotationSubmitted = false
1584
+ this.annotationEntry = {}
1585
1585
  } else if (data.type === 'modeChanged') {
1586
1586
  if (data.feature.mode === 'direct_select') this.doubleClickedFeature = true
1587
+ if (this.annotationSidebar && data.feature.mode === 'simple_select') {
1588
+ this.annotationEventCallback({}, { type: 'aborted' })
1589
+ }
1587
1590
  } else if (data.type === 'selectionChanged') {
1588
1591
  this.selectedDrawnFeature = data.feature.features.length === 0 ?
1589
1592
  undefined : data.feature.features[0]
@@ -1616,6 +1619,8 @@ export default {
1616
1619
  if (data.type === 'created') this.drawnCreatedEvent = payload
1617
1620
  else this.checkAndCreatePopups(payload)
1618
1621
  }
1622
+ if (data.type === 'deleted') this.previousDeletedEvent = data
1623
+ else this.previousDeletedEvent = {}
1619
1624
  },
1620
1625
  /**
1621
1626
  * @public
@@ -1660,6 +1665,9 @@ export default {
1660
1665
  }
1661
1666
  if (eventType === 'click') {
1662
1667
  this.featuresAlert = data.alert
1668
+ //The following will be used to track either a feature is selected
1669
+ this.statesTracking.activeClick = true
1670
+ this.statesTracking.activeTerm = data?.models
1663
1671
  if (this.viewingMode === 'Neuron Connection') {
1664
1672
  this.highlightConnectedPaths([data.models])
1665
1673
  } else {
@@ -1717,7 +1725,123 @@ export default {
1717
1725
  if (modeName) {
1718
1726
  this.viewingMode = modeName
1719
1727
  }
1720
- this.closeTooltip()
1728
+ this.manualAbortedOnClose()
1729
+ },
1730
+ /**
1731
+ * @public
1732
+ * Function to remove active tooltips on map.
1733
+ */
1734
+ removeActiveTooltips: function () {
1735
+ const tooltips = this.$el.querySelectorAll('.flatmap-tooltip-popup');
1736
+ tooltips.forEach((tooltip) => tooltip.remove());
1737
+ },
1738
+ /**
1739
+ * Function to create tooltip for the provided connectivity data.
1740
+ * @arg {Array} `connectivityData`
1741
+ */
1742
+ createTooltipForConnectivity: function (connectivityData) {
1743
+ // combine all labels to show together
1744
+ // content type must be DOM object to use HTML
1745
+ const labelsContainer = document.createElement('div');
1746
+ labelsContainer.classList.add('flatmap-feature-label');
1747
+
1748
+ connectivityData.forEach((connectivity, i) => {
1749
+ const { label } = connectivity;
1750
+ labelsContainer.append(capitalise(label));
1751
+
1752
+ if ((i + 1) < connectivityData.length) {
1753
+ const hr = document.createElement('hr');
1754
+ labelsContainer.appendChild(hr);
1755
+ }
1756
+ });
1757
+
1758
+ this.mapImp.showPopup(
1759
+ connectivityData[0].featureId,
1760
+ labelsContainer,
1761
+ {
1762
+ className: 'custom-popup flatmap-tooltip-popup',
1763
+ positionAtLastClick: false,
1764
+ preserveSelection: true,
1765
+ }
1766
+ );
1767
+ },
1768
+ /**
1769
+ * Function to show connectivity tooltips on the map
1770
+ * and highlight the nerve.
1771
+ * @arg {Object} `payload`
1772
+ */
1773
+ showConnectivityTooltips: function (payload) {
1774
+ const { connectivityInfo, data } = payload;
1775
+ const featuresToHighlight = [];
1776
+ const connectivityData = [];
1777
+ const filteredConnectivityData = [];
1778
+ const errorData = [];
1779
+
1780
+ if (!data.length) {
1781
+ // Close all tooltips on the current flatmap element
1782
+ this.removeActiveTooltips();
1783
+ } else {
1784
+ data.forEach((item) => {
1785
+ connectivityData.push({
1786
+ id: item.id,
1787
+ label: item.label,
1788
+ });
1789
+ });
1790
+ }
1791
+
1792
+ // to keep the highlighted path on map
1793
+ if (connectivityInfo && connectivityInfo.featureId) {
1794
+ featuresToHighlight.push(...connectivityInfo.featureId);
1795
+ }
1796
+
1797
+ // search the features on the map first
1798
+ if (this.mapImp) {
1799
+ connectivityData.forEach((connectivity, i) => {
1800
+ const {id, label} = connectivity;
1801
+ const response = this.mapImp.search(id);
1802
+
1803
+ if (response?.results.length) {
1804
+ const featureId = response?.results[0].featureId;
1805
+
1806
+ filteredConnectivityData.push({
1807
+ featureId,
1808
+ id,
1809
+ label,
1810
+ });
1811
+ featuresToHighlight.push(id);
1812
+ } else {
1813
+ errorData.push(connectivity);
1814
+ }
1815
+ });
1816
+
1817
+ if (filteredConnectivityData.length) {
1818
+ // show tooltip of the first item
1819
+ // with all labels
1820
+ this.createTooltipForConnectivity(filteredConnectivityData);
1821
+ } else {
1822
+ errorData.push(...connectivityData);
1823
+ // Close all tooltips on the current flatmap element
1824
+ this.removeActiveTooltips();
1825
+ }
1826
+
1827
+ // Emit error message for connectivity graph
1828
+ if (errorData.length) {
1829
+ this.emitConnectivityGraphError(errorData);
1830
+ }
1831
+
1832
+ // highlight all available features
1833
+ this.mapImp.zoomToFeatures(featuresToHighlight, { noZoomIn: true });
1834
+ }
1835
+ },
1836
+ emitConnectivityGraphError: function (errorData) {
1837
+ const errorMessage = 'cannot be found on the map!';
1838
+
1839
+ this.$emit('connectivity-graph-error', {
1840
+ data: {
1841
+ errorData: errorData,
1842
+ errorMessage: errorMessage,
1843
+ }
1844
+ });
1721
1845
  },
1722
1846
  /**
1723
1847
  * @public
@@ -1729,6 +1853,13 @@ export default {
1729
1853
  // Call flatmap database to get the connection data
1730
1854
  if (this.viewingMode === 'Annotation') {
1731
1855
  if (data.feature) {
1856
+ if (this.annotationSidebar && this.previousDeletedEvent.type === 'deleted') {
1857
+ this.annotationEntry = {
1858
+ ...this.previousDeletedEvent,
1859
+ resourceId: this.serverURL
1860
+ }
1861
+ this.annotationEventCallback({}, { type: 'aborted' })
1862
+ }
1732
1863
  this.annotationEntry = {
1733
1864
  ...data.feature,
1734
1865
  resourceId: this.serverURL,
@@ -1744,7 +1875,9 @@ export default {
1744
1875
  ) {
1745
1876
  this.featureAnnotationSubmitted = false
1746
1877
  this.annotationEntry.featureId = data.feature.feature.id
1747
- if (this.activeDrawTool) this.createConnectivityBody()
1878
+ if (this.activeDrawTool) {
1879
+ this.createConnectivityBody()
1880
+ }
1748
1881
  this.displayTooltip(
1749
1882
  data.feature.feature.id,
1750
1883
  centroid(data.feature.feature.geometry)
@@ -1757,13 +1890,13 @@ export default {
1757
1890
  this.annotation = {}
1758
1891
  }
1759
1892
  } else {
1893
+ //require data.resource && data.feature.source
1760
1894
  let results =
1761
- await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(data)
1895
+ await this.flatmapQueries.retrieveFlatmapKnowledgeForEvent(this.mapImp, data)
1762
1896
  // The line below only creates the tooltip if some data was found on the path
1763
- // result 0 is the connection, result 1 is the pubmed results from flatmap
1897
+ // the pubmed URLs are in knowledge response.references
1764
1898
  if (
1765
- results[0] ||
1766
- results[1] ||
1899
+ (results && results[0]) ||
1767
1900
  (data.feature.hyperlinks && data.feature.hyperlinks.length > 0)
1768
1901
  ) {
1769
1902
  this.resourceForTooltip = data.resource[0]
@@ -1807,7 +1940,7 @@ export default {
1807
1940
  * @arg {Object} `data`
1808
1941
  */
1809
1942
  createTooltipFromNeuronCuration: async function (data) {
1810
- this.tooltipEntry = await this.flatmapQueries.createTooltipData(data)
1943
+ this.tooltipEntry = await this.flatmapQueries.createTooltipData(this.mapImp, data)
1811
1944
  this.displayTooltip(data.resource[0])
1812
1945
  },
1813
1946
  /**
@@ -2027,6 +2160,9 @@ export default {
2027
2160
  }
2028
2161
  this.$emit('connectivity-info-open', this.tooltipEntry);
2029
2162
  }
2163
+ if (this.annotationSidebar && this.viewingMode === 'Annotation') {
2164
+ this.$emit('annotation-open', {annotationEntry: this.annotationEntry, commitCallback: this.commitAnnotationEvent});
2165
+ }
2030
2166
  // If UI is not disabled,
2031
2167
  // And connectivityInfoSidebar is not set (default) or set to `false`
2032
2168
  // Provenance popup will be shown on map
@@ -2035,6 +2171,7 @@ export default {
2035
2171
  !this.disableUI && (
2036
2172
  (
2037
2173
  this.viewingMode === 'Annotation' &&
2174
+ !this.annotationSidebar &&
2038
2175
  this.userInformation
2039
2176
  ) ||
2040
2177
  (
@@ -2146,6 +2283,48 @@ export default {
2146
2283
  return Array.from(new Set(labels))
2147
2284
  }
2148
2285
  },
2286
+ /**
2287
+ * Function to get and store the state (object) of the map in
2288
+ * the provided argument
2289
+ */
2290
+ getVisibilityState: function (state) {
2291
+ const refs = ['alertSelection', 'pathwaysSelection', 'taxonSelection']
2292
+ refs.forEach(ref => {
2293
+ let comp = this.$refs[ref]
2294
+ if (comp) {
2295
+ state[ref] = comp.getState()
2296
+ }
2297
+ })
2298
+ if (this.$refs.treeControls) {
2299
+ const checkedKeys = this.$refs.treeControls.$refs.regionTree.getCheckedKeys();
2300
+ //Only store first level systems (terms without .)
2301
+ state['systemsSelection'] = checkedKeys.filter(term => !term.includes('.'))
2302
+ }
2303
+ },
2304
+ /**
2305
+ * Function to set and restore the visibility state (object) of
2306
+ * the map with the provided argument
2307
+ */
2308
+ setVisibilityState: function (state) {
2309
+ const refs = ['alertSelection', 'pathwaysSelection', 'taxonSelection']
2310
+ refs.forEach(ref => {
2311
+ const settings = state[ref]
2312
+ if (settings) {
2313
+ const comp = this.$refs[ref]
2314
+ if (comp) {
2315
+ comp.setState(settings)
2316
+ }
2317
+ }
2318
+ })
2319
+ if ('systemsSelection' in state) {
2320
+ if (this.$refs.treeControls) {
2321
+ this.$refs.treeControls.$refs.regionTree.setCheckedKeys(state['systemsSelection']);
2322
+ this.systems[0].children.forEach((item) => {
2323
+ this.mapImp.enableSystem(item.key, state['systemsSelection'].includes(item.key))
2324
+ })
2325
+ }
2326
+ }
2327
+ },
2149
2328
  /**
2150
2329
  * @public
2151
2330
  * Function to get the state (object) of the map.
@@ -2161,6 +2340,13 @@ export default {
2161
2340
  else if (identifier && identifier.biologicalSex)
2162
2341
  state['biologicalSex'] = identifier.biologicalSex
2163
2342
  if (identifier && identifier.uuid) state['uuid'] = identifier.uuid
2343
+ state['viewingMode'] = this.viewingMode
2344
+ state['searchTerm'] = this.statesTracking.activeTerm
2345
+ state['flightPath3D'] = this.flightPath3DRadio
2346
+ state['colour'] = this.colourRadio
2347
+ state['outlinesRadio'] = this.outlinesRadio
2348
+ state['background'] = this.currentBackground
2349
+ this.getVisibilityState(state)
2164
2350
  return state
2165
2351
  }
2166
2352
  return undefined
@@ -2178,9 +2364,7 @@ export default {
2178
2364
  this.entry == state.entry &&
2179
2365
  (!state.biologicalSex || state.biologicalSex === this.biologicalSex)
2180
2366
  ) {
2181
- if (state.viewport) {
2182
- this.mapImp.setState(state.viewport)
2183
- }
2367
+ this.restoreMapState(state)
2184
2368
  } else {
2185
2369
  this.createFlatmap(state)
2186
2370
  }
@@ -2196,7 +2380,33 @@ export default {
2196
2380
  restoreMapState: function (state) {
2197
2381
  if (state) {
2198
2382
  if (state.viewport) this.mapImp.setState(state.viewport)
2199
- if (state.searchTerm) this.searchAndShowResult(state.searchTerm, true)
2383
+ if (state.viewingMode) this.changeViewingMode(state.viewingMode)
2384
+ //The following three are boolean
2385
+ if ('flightPath3D' in state) this.setFlightPath3D(state.flightPath3D)
2386
+ if ('colour' in state) this.setColour(state.colour)
2387
+ if ('outlines' in state) this.setOutlines(state.outlines)
2388
+ if (state.background) this.backgroundChangeCallback(state.background)
2389
+ if (state.searchTerm) {
2390
+ const searchTerm = state.searchTerm
2391
+ this.searchAndShowResult(searchTerm, true)
2392
+ if (state.viewingMode === "Neuron Connection") {
2393
+ this.highlightConnectedPaths([searchTerm])
2394
+ } else {
2395
+ const geoID = this.mapImp.modelFeatureIds(searchTerm)
2396
+ if (geoID.length > 0) {
2397
+ const feature = this.mapImp.featureProperties(geoID[0])
2398
+ this.searchAndShowResult(searchTerm, true)
2399
+ const data = {
2400
+ resource: [feature.source],
2401
+ feature,
2402
+ label: feature.label,
2403
+ provenanceTaxonomy: feature.taxons
2404
+ }
2405
+ this.checkAndCreatePopups(data)
2406
+ }
2407
+ }
2408
+ }
2409
+ this.setVisibilityState(state)
2200
2410
  }
2201
2411
  },
2202
2412
  /**
@@ -2289,16 +2499,13 @@ export default {
2289
2499
  this.serverURL = this.mapImp.makeServerUrl('').slice(0, -1)
2290
2500
  let mapVersion = this.mapImp.details.version
2291
2501
  this.setFlightPathInfo(mapVersion)
2292
- this.onFlatmapReady()
2293
- if (this._stateToBeSet) this.restoreMapState(this._stateToBeSet)
2294
- else {
2295
- this.restoreMapState(state)
2296
- }
2502
+ const stateToSet = this._stateToBeSet ? this._stateToBeSet : state
2503
+ this.onFlatmapReady(stateToSet)
2504
+ this.$nextTick(() => this.restoreMapState(stateToSet))
2297
2505
  })
2298
2506
  } else if (state) {
2299
2507
  this._stateToBeSet = {
2300
- viewport: state.viewport,
2301
- searchTerm: state.searchTerm,
2508
+ ...state
2302
2509
  }
2303
2510
  if (this.mapImp && !this.loading)
2304
2511
  this.restoreMapState(this._stateToBeSet)
@@ -2340,32 +2547,28 @@ export default {
2340
2547
  * @public
2341
2548
  * This function is used for functions that need to run immediately after the flatmap is loaded.
2342
2549
  */
2343
- onFlatmapReady: function () {
2550
+ onFlatmapReady: function (state) {
2344
2551
  // onFlatmapReady is used for functions that need to run immediately after the flatmap is loaded
2345
2552
  this.sensor = markRaw(new ResizeSensor(this.$refs.display, this.mapResize))
2346
- console.log(this.mapImp.options)
2347
2553
  if (this.mapImp.options?.style === 'functional') {
2348
2554
  this.isFC = true
2349
- } else if (this.mapImp.options?.style === 'centreline') {
2350
- this.isCentreLine = true
2351
2555
  }
2352
2556
  this.mapImp.setBackgroundOpacity(1)
2353
2557
  this.backgroundChangeCallback(this.currentBackground)
2354
2558
  this.pathways = this.mapImp.pathTypes()
2355
- if (!this.isCentreLine) {
2356
- this.mapImp.enableCentrelines(false)
2357
- }
2358
2559
  //Disable layers for now
2359
2560
  //this.layers = this.mapImp.getLayers();
2360
2561
  this.processSystems(this.mapImp.getSystems())
2361
- this.processTaxon(this.flatmapAPI, this.mapImp.taxonIdentifiers)
2562
+ //Async, pass the state for checking
2563
+ this.processTaxon(this.mapImp.taxonIdentifiers, state ? state['taxonSelection'] : undefined)
2362
2564
  this.containsAlert = "alert" in this.mapImp.featureFilterRanges()
2363
2565
  this.addResizeButtonToMinimap()
2364
2566
  this.loading = false
2365
2567
  this.computePathControlsMaximumHeight()
2366
- this.drawerOpen = !this.isCentreLine
2568
+ this.drawerOpen = true;
2367
2569
  this.mapResize()
2368
2570
  this.handleMapClick();
2571
+ this.setInitMapState();
2369
2572
  /**
2370
2573
  * This is ``onFlatmapReady`` event.
2371
2574
  * @arg ``this`` (Component Vue Instance)
@@ -2379,9 +2582,15 @@ export default {
2379
2582
  */
2380
2583
  handleMapClick: function () {
2381
2584
  const _map = this.mapImp._map;
2382
-
2383
2585
  if (_map) {
2384
2586
  _map.on('click', (e) => {
2587
+ //A little logic to make sure we are keeping track
2588
+ //of selected term
2589
+ if (this.statesTracking.activeClick) {
2590
+ this.statesTracking.activeClick = false
2591
+ } else {
2592
+ this.statesTracking.activeTerm = ""
2593
+ }
2385
2594
  if (this.tooltipEntry.featureId) {
2386
2595
  this.$emit('connectivity-info-close');
2387
2596
  }
@@ -2417,6 +2626,7 @@ export default {
2417
2626
  if (this.mapImp) {
2418
2627
  if (term === undefined || term === '') {
2419
2628
  this.mapImp.clearSearchResults()
2629
+ this.statesTracking.activeTerm = ""
2420
2630
  return true
2421
2631
  } else {
2422
2632
  const searchResults = this.mapImp.search(term)
@@ -2425,6 +2635,7 @@ export default {
2425
2635
  searchResults.results &&
2426
2636
  searchResults.results.length > 0
2427
2637
  ) {
2638
+ this.statesTracking.activeTerm = term
2428
2639
  this.mapImp.showSearchResults(searchResults)
2429
2640
  if (
2430
2641
  displayLabel &&
@@ -2488,7 +2699,7 @@ export default {
2488
2699
  */
2489
2700
  minZoom: {
2490
2701
  type: Number,
2491
- default: 4,
2702
+ default: 1,
2492
2703
  },
2493
2704
  /**
2494
2705
  * The option to add another feature label _(`FeatureSmallSymbolLayer`)_
@@ -2645,12 +2856,18 @@ export default {
2645
2856
  type: Boolean,
2646
2857
  default: false,
2647
2858
  },
2859
+ /**
2860
+ * The option to show annotation in sidebar
2861
+ */
2862
+ annotationSidebar: {
2863
+ type: Boolean,
2864
+ default: false,
2865
+ },
2648
2866
  },
2649
2867
  provide() {
2650
2868
  return {
2651
2869
  flatmapAPI: this.flatmapAPI,
2652
2870
  sparcAPI: this.sparcAPI,
2653
- $annotator: this.annotator,
2654
2871
  getFeaturesAlert: () => this.featuresAlert,
2655
2872
  userApiKey: this.userToken,
2656
2873
  }
@@ -2668,19 +2885,13 @@ export default {
2668
2885
  serverURL: undefined,
2669
2886
  layers: [],
2670
2887
  pathways: [],
2888
+ initMapState: {},
2671
2889
  sckanDisplay: [
2672
2890
  {
2673
2891
  label: 'Display Path with SCKAN',
2674
2892
  key: 'VALID',
2675
2893
  },
2676
2894
  ],
2677
- centreLines: [
2678
- {
2679
- label: 'Display Nerves',
2680
- key: 'centrelines',
2681
- enabled: false,
2682
- },
2683
- ],
2684
2895
  systems: [],
2685
2896
  taxonConnectivity: [],
2686
2897
  pathwaysMaxHeight: 1000,
@@ -2706,7 +2917,6 @@ export default {
2706
2917
  helpModeActiveIndex: this.helpModeInitialIndex,
2707
2918
  yellowstar: yellowstar,
2708
2919
  isFC: false,
2709
- isCentreLine: false,
2710
2920
  inHelp: false,
2711
2921
  currentBackground: 'white',
2712
2922
  availableBackground: ['white', 'lightskyblue', 'black'],
@@ -2751,6 +2961,7 @@ export default {
2751
2961
  activeDrawTool: undefined,
2752
2962
  featureAnnotationSubmitted: false,
2753
2963
  drawnCreatedEvent: {},
2964
+ previousDeletedEvent: {},
2754
2965
  connectionEntry: {},
2755
2966
  existDrawnFeatures: [], // Store all exist drawn features
2756
2967
  doubleClickedFeature: false,
@@ -2772,7 +2983,11 @@ export default {
2772
2983
  with: true,
2773
2984
  without: true,
2774
2985
  }
2775
- })
2986
+ }),
2987
+ statesTracking: markRaw({
2988
+ activeClick: false,
2989
+ activeTerm: "",
2990
+ }),
2776
2991
  }
2777
2992
  },
2778
2993
  computed: {
@@ -2820,9 +3035,7 @@ export default {
2820
3035
  this.showAnnotator(true)
2821
3036
  this.userInformation = userData
2822
3037
  this.setFeatureAnnotated()
2823
- if (this.existDrawnFeatures.length === 0) {
2824
- this.addAnnotationFeature()
2825
- }
3038
+ this.addAnnotationFeature()
2826
3039
  }
2827
3040
  this.loading = false
2828
3041
  })
@@ -2920,6 +3133,11 @@ export default {
2920
3133
  left: 0px;
2921
3134
  transform: translateX(0);
2922
3135
  transition: all var(--el-transition-duration);
3136
+ z-index: 99;
3137
+ display: flex;
3138
+ flex-direction: row;
3139
+ align-items: center;
3140
+
2923
3141
  &.open {
2924
3142
  transform: translateX(0);
2925
3143
  }
@@ -3465,7 +3683,6 @@ export default {
3465
3683
  }
3466
3684
  }
3467
3685
 
3468
- .open-drawer,
3469
3686
  .drawer-button {
3470
3687
  z-index: 8;
3471
3688
  width: 20px;
@@ -3475,18 +3692,6 @@ export default {
3475
3692
  vertical-align: middle;
3476
3693
  cursor: pointer;
3477
3694
  pointer-events: auto;
3478
- }
3479
-
3480
- .open-drawer {
3481
- position: absolute;
3482
- left: 0px;
3483
- background-color: #f7faff;
3484
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06);
3485
- }
3486
-
3487
- .drawer-button {
3488
- float: left;
3489
- margin-top: calc(50% - 36px);
3490
3695
  background-color: #f9f2fc;
3491
3696
 
3492
3697
  i {