@abi-software/map-side-bar 2.19.0 → 2.20.0-acuppoints.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abi-software/map-side-bar",
3
- "version": "2.19.0",
3
+ "version": "2.20.0-acuppoints.0",
4
4
  "license": "Apache-2.0",
5
5
  "engines": {
6
6
  "node": "^24.20.0"
@@ -49,8 +49,8 @@
49
49
  "./src/*": "./src/*"
50
50
  },
51
51
  "dependencies": {
52
- "@abi-software/gallery": "1.6.0",
53
- "@abi-software/map-utilities": "1.12.0",
52
+ "@abi-software/gallery": "1.7.0",
53
+ "@abi-software/map-utilities": "1.13.0",
54
54
  "@abi-software/svg-sprite": "1.4.0",
55
55
  "@element-plus/icons-vue": "^2.3.2",
56
56
  "algoliasearch": "^4.27.0",
package/src/App.vue CHANGED
@@ -14,6 +14,7 @@
14
14
  <el-button @click="keywordSearch">keyword search</el-button>
15
15
  <el-button @click="getFacets">Get facets</el-button>
16
16
  <el-button @click="toggleCreateData">Create Data/Annotation</el-button>
17
+ <el-button @click="searchAcupoints">Search Acupoints</el-button>
17
18
  <el-button @click="openConnectivitySearch()">Connectivity Search</el-button>
18
19
  </div>
19
20
  <SideBar
@@ -22,14 +23,19 @@
22
23
  ref="sideBar"
23
24
  :visible="sideBarVisibility"
24
25
  :annotationEntry="annotationEntry"
26
+ :acupointsInfoList="acupoints"
25
27
  :createData="createData"
26
28
  :connectivityEntry="connectivityEntry"
27
29
  :connectivityKnowledge="connectivityKnowledge"
28
30
  :showVisibilityFilter="true"
31
+ :tabs="tabArray"
29
32
  @search-changed="searchChanged($event)"
30
33
  @hover-changed="hoverChanged($event)"
31
34
  @connectivity-hovered="onConnectivityHovered"
32
35
  @actionClick="action"
36
+ @acupoints-clicked="onAcupointsClicked"
37
+ @acupoints-hovered="onAcupointsHovered"
38
+ @acupoints-result="onAcupointsResult"
33
39
  @connectivity-collapse-change="onConnectivityCollapseChange"
34
40
  />
35
41
  </div>
@@ -37,9 +43,11 @@
37
43
 
38
44
  <script>
39
45
  // optionally import default styles
40
- import SideBar from './components/SideBar.vue';
41
- import EventBus from './components/EventBus.js';
42
- import exampleConnectivityInput from './exampleConnectivityInput.js';
46
+ import { acupointEntries } from './acupoints.js'
47
+ import SideBar from './components/SideBar.vue'
48
+ import EventBus from './components/EventBus.js'
49
+ import exampleConnectivityInput from './exampleConnectivityInput.js'
50
+
43
51
 
44
52
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
45
53
 
@@ -115,6 +123,13 @@ export default {
115
123
  },
116
124
  data: function () {
117
125
  return {
126
+ acupoints: acupointEntries,
127
+ tabArray: [
128
+ { title: 'Dataset Explorer', id: 1, type: 'datasetExplorer', closable: false },
129
+ { title: 'Connectivity Explorer', id: 2, type: 'connectivityExplorer', closable: false },
130
+ { title: 'Annotation', id: 3, type: 'annotation', closable: true },
131
+ {title: 'Acupoints', id: 4, type: 'acupoints' },
132
+ ],
118
133
  annotationEntry: [
119
134
  {
120
135
  featureId: 'epicardium',
@@ -153,6 +168,15 @@ export default {
153
168
  };
154
169
  },
155
170
  methods: {
171
+ onAcupointsClicked: function (data) {
172
+ console.log("acupoints-clicked", data)
173
+ },
174
+ onAcupointsHovered: function (data) {
175
+ console.log("acupoints-hovered", data)
176
+ },
177
+ onAcupointsResult: function (data) {
178
+ console.log("acupoints-result", data)
179
+ },
156
180
  loadConnectivityKnowledge: async function () {
157
181
  const sql = `select knowledge from knowledge
158
182
  where source="${this.sckanVersion}"
@@ -228,6 +252,9 @@ export default {
228
252
  openSearch: function () {
229
253
  this.$refs.sideBar.openSearch([], 'http://purl.obolibrary.org/obo/UBERON_0001103');
230
254
  },
255
+ searchAcupoints: function() {
256
+ this.$refs.sideBar.openAcupointsSearch("LU 1")
257
+ },
231
258
  singleFacets: function () {
232
259
  this.$refs.sideBar.addFilter({
233
260
  facet: 'Cardiovascular system',
@@ -0,0 +1,78 @@
1
+ export const acupointEntries = {
2
+ "LU 1": {
3
+ "Acupoint": "LU 1",
4
+ "Label": "LU 1",
5
+ "Synonym": "Test data",
6
+ "UMLS CUI": "",
7
+ "Meridian": "LTest data",
8
+ "Chinese Name": "Zhongfu",
9
+ "English Name": "Central Treasury",
10
+ "Location": " z zxczc.",
11
+ "Reference": "Test data",
12
+ "Indications": "Test data",
13
+ "Acupuncture Method": "Test data",
14
+ "Vasculature": "Test data",
15
+ "Innervation": "Test data",
16
+ "Curated": false,
17
+ "onMRI": true,
18
+ "Meridian Point": true,
19
+ "Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
20
+ },
21
+ "LU 2": {
22
+ "Acupoint": "LU 2",
23
+ "Label": "LU 2",
24
+ "Synonym": "Test data",
25
+ "UMLS CUI": "",
26
+ "Meridian": "LTest data",
27
+ "Chinese Name": "Yunmen",
28
+ "English Name": "Cloud Gate",
29
+ "Location": " z zxczc.",
30
+ "Reference": "Test data",
31
+ "Indications": "Test data",
32
+ "Acupuncture Method": "Test data",
33
+ "Vasculature": "Test data",
34
+ "Innervation": "Test data",
35
+ "Curated": true,
36
+ "onMRI": true,
37
+ "Meridian Point": false,
38
+ "Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
39
+ },
40
+ "ST 3": {
41
+ "Acupoint": "ST 3",
42
+ "Label": "ST 3",
43
+ "Synonym": "Test data",
44
+ "UMLS CUI": "",
45
+ "Meridian": "STest data",
46
+ "Chinese Name": "Cheng Qi",
47
+ "English Name": "Not Available",
48
+ "Location": " z zxcxadadadzc.",
49
+ "Reference": "Test data",
50
+ "Indications": "Test data",
51
+ "Acupuncture Method": "Test data",
52
+ "Vasculature": "Test data",
53
+ "Innervation": "Test data",
54
+ "Curated": true,
55
+ "onMRI": false,
56
+ "Meridian Point": false,
57
+ "Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
58
+ },
59
+ "LR 4": {
60
+ "Acupoint": "LR 4",
61
+ "Label": "LR 4",
62
+ "Synonym": "Test data",
63
+ "UMLS CUI": "",
64
+ "Meridian": "STest data",
65
+ "Chinese Name": "Zhongfeng",
66
+ "English Name": "Not Available",
67
+ "Location": " z zxcxadadadzc.",
68
+ "Reference": "Test data",
69
+ "Indications": "Test data",
70
+ "Acupuncture Method": "Test data",
71
+ "Vasculature": "Test data",
72
+ "Innervation": "Test data",
73
+ "Curated": false,
74
+ "onMRI": false,
75
+ "Meridian Point": true,
76
+ "Link": "https://tara-repository.mgb.org/term_resolution/tara.html"
77
+ }
78
+ }
@@ -0,0 +1,316 @@
1
+ <template>
2
+ <div class="dataset-card-container" ref="container">
3
+ <div class="dataset-card" ref="card">
4
+ <div class="seperator-path"></div>
5
+ <div class="card"
6
+ @click="cardClicked(entry)"
7
+ @mouseover="cardHovered(entry)"
8
+ @mouseleave="cardHovered(undefined)"
9
+ >
10
+ <div class="card-right">
11
+ <el-collapse class="collapse-card" v-model="expanded" @change="expandedChanged">
12
+ <el-collapse-item :title="entry.Acupoint" name="1" class="collapse-card">
13
+ <template #title>
14
+ <div>
15
+ <span class="title">{{ entry.Acupoint }}</span>
16
+ <el-tag
17
+ v-for="tag in tags"
18
+ :key="tag.name"
19
+ :type="tag.type"
20
+ effect="plain"
21
+ class="acupointTags"
22
+ size="small"
23
+ >
24
+ {{ tag.name }}
25
+ </el-tag>
26
+ </div>
27
+ </template>
28
+ <template v-for="field in displayFields" :key="field['name']">
29
+ <div class="details">
30
+ <strong>{{ field['name'] }}: </strong>
31
+ <template v-if="field['name'] === 'Acupoint Curie'">
32
+ <a :href="entry['Acupoint IRI']" target="_blank">
33
+ <span>
34
+ {{ entry['Acupoint Curie'] }}
35
+ </span>
36
+ </a>
37
+ </template>
38
+ <template v-else-if="field['name'] === 'Reference'">
39
+ <div v-html="formatReference(entry[field['name']])"></div>
40
+ </template>
41
+ <template v-else>
42
+ <span
43
+ v-if="!field['isEditing']"
44
+ @click="setFieldToEditing(field)"
45
+ >
46
+ {{ entry[field['name']] || 'Not Available' }}
47
+ </span>
48
+ <el-input
49
+ v-else
50
+ v-model="entry[field['name']]"
51
+ @blur="field['isEditing'] = false"
52
+ @keyup.enter="field['isEditing'] = false"
53
+ @vue:mounted="inputMounted"
54
+ type="textarea"
55
+ />
56
+ </template>
57
+ </div>
58
+ </template>
59
+ </el-collapse-item>
60
+ </el-collapse>
61
+ </div>
62
+ </div>
63
+ </div>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+ import EventBus from './EventBus.js'
69
+ import {
70
+ ElCollapse as Collapse,
71
+ ElCollapseItem as CollapseItem,
72
+ ElTag as Tag
73
+ } from 'element-plus'
74
+ /* eslint-disable no-alert, no-console */
75
+
76
+ export default {
77
+ components: {
78
+ Collapse,
79
+ CollapseItem,
80
+ Tag
81
+ },
82
+ data() {
83
+ return {
84
+ expanded: [],
85
+ tags: [],
86
+ displayFields: [
87
+ {name: "Acupoint Curie", isEditing: false},
88
+ {name: "Acupoint", isEditing: false},
89
+ {name: "Acupoint Category", isEditing: false},
90
+ {name: "Synonym", isEditing: false},
91
+ {name: "Pinyin Name", isEditing: false},
92
+ {name: "Chinese Name", isEditing: false},
93
+ {name: "Meridian", isEditing: false},
94
+ {name: "Special Point Role", isEditing: false},
95
+ {name: "Location", isEditing: false},
96
+ {name: "Location Anatomy", isEditing: false},
97
+ {name: "Acupuncture Method", isEditing: false},
98
+ {name: "Indications", isEditing: false},
99
+ {name: "Innervation", isEditing: false},
100
+ {name: "Nearby Nerve", isEditing: false},
101
+ {name: "Vasculature", isEditing: false},
102
+ {name: "Nearby Artery", isEditing: false},
103
+ {name: "Nearby Vein", isEditing: false},
104
+ {name: "Reference", isEditing: false},
105
+ //{name: "Notes", isEditing: false},
106
+ ]
107
+ }
108
+ },
109
+ name: 'AcupointsCard',
110
+ props: {
111
+ /**
112
+ * Object containing information for
113
+ * the required viewing.
114
+ */
115
+ entry: {
116
+ type: Object,
117
+ default: () => {},
118
+ },
119
+ allowEditing: {
120
+ type: Boolean,
121
+ default: false,
122
+ },
123
+ },
124
+ created: function () {
125
+ if (this.entry["Meridian Point"]) {
126
+ this.tags.push({ name: 'WHO', type: 'info' })
127
+ }
128
+ if (this.entry.Meridian) {
129
+ this.tags.push({ name: this.entry.Meridian, type: 'info' })
130
+ }
131
+ if (this.entry.onMRI) {
132
+ this.tags.push({ name: 'Spotted', type: 'success' })
133
+ }
134
+ if (this.entry.userDefined) {
135
+ this.tags.push({ name: 'User Defined', type: 'warning' })
136
+ }
137
+ },
138
+ methods: {
139
+ expandedChanged: function() {
140
+ if (this.expanded.length > 0) {
141
+ EventBus.emit('acupoints-clicked', this.entry);
142
+ }
143
+ },
144
+ cardClicked: function (data) {
145
+ EventBus.emit('acupoints-clicked', data);
146
+ },
147
+ cardHovered: function (data) {
148
+ EventBus.emit('acupoints-hovered', data);
149
+ },
150
+ inputMounted: function(event) {
151
+ event.el?.querySelector('textarea')?.focus();
152
+ },
153
+ formatReference: function(text) {
154
+ if (!text) {
155
+ return 'Not Available';
156
+ }
157
+ // Escape HTML first so only the markup added below is rendered
158
+ const escaped = String(text)
159
+ .replace(/&/g, '&amp;')
160
+ .replace(/</g, '&lt;')
161
+ .replace(/>/g, '&gt;')
162
+ .replace(/"/g, '&quot;')
163
+ .replace(/'/g, '&#39;');
164
+ return escaped
165
+ // Bold and italicise square-bracketed labels, e.g. [Acupoint Location, Pinyin Label]
166
+ .replace(/\[([^\]\n]+)\]/g, '<strong><em>[$1]</em></strong>')
167
+ // Turn http(s) URLs into links, leaving trailing punctuation outside
168
+ .replace(/https?:\/\/[^\s<]+?(?=[.,;:!?)]*(?:\s|<|$))/g,
169
+ (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`)
170
+ .replace(/\n/g, '<br>');
171
+ },
172
+ setFieldToEditing: function(field) {
173
+ if (this.allowEditing) {
174
+ field['isEditing'] = true;
175
+ }
176
+ }
177
+ },
178
+ }
179
+ </script>
180
+
181
+ <style lang="scss" scoped>
182
+
183
+ :deep(.el-collapse-item__header) {
184
+ font-weight: bold;
185
+ }
186
+
187
+ :deep(.el-collapse-item__content) {
188
+ padding-bottom: 4px;
189
+ }
190
+
191
+ :deep(.el-collapse-item__wrap) {
192
+ border: none;
193
+ }
194
+
195
+ .collapse-card {
196
+ border-top: none;
197
+ :deep(.el-collapse-item__header) {
198
+ border-bottom: none;
199
+ }
200
+ }
201
+
202
+ .dataset-card {
203
+ padding-left: 5px;
204
+ padding-right: 5px;
205
+ position: relative;
206
+ }
207
+
208
+ .title {
209
+ padding-bottom: 0.75rem;
210
+ font-family: Asap;
211
+ font-size: 14px;
212
+ font-weight: bold;
213
+ font-stretch: normal;
214
+ font-style: normal;
215
+ line-height: 1.5;
216
+ letter-spacing: 1.05px;
217
+ color: #484848;
218
+ cursor: pointer;
219
+ }
220
+ .card {
221
+ padding-top: 12px;
222
+ position: relative;
223
+ display: flex;
224
+ }
225
+
226
+ .card-left {
227
+ flex: 1;
228
+ }
229
+
230
+ .card-right {
231
+ flex: 1.3;
232
+ padding-left: 6px;
233
+ }
234
+
235
+ .button {
236
+ z-index: 10;
237
+ font-family: Asap;
238
+ font-size: 14px;
239
+ font-weight: normal;
240
+ font-stretch: normal;
241
+ font-style: normal;
242
+ line-height: normal;
243
+ letter-spacing: normal;
244
+ background-color: $app-primary-color;
245
+ border: $app-primary-color;
246
+ color: white;
247
+ cursor: pointer;
248
+ margin-top: 8px;
249
+ }
250
+
251
+ .button:hover {
252
+ background-color: $app-primary-color;
253
+ color: white;
254
+ }
255
+
256
+ .banner-img {
257
+ width: 128px;
258
+ height: 128px;
259
+ box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.25);
260
+ background-color: #ffffff;
261
+ cursor: pointer;
262
+ }
263
+ .details {
264
+ font-family: Asap;
265
+ font-size: 14px;
266
+ font-weight: normal;
267
+ font-stretch: normal;
268
+ font-style: normal;
269
+ line-height: 1.5;
270
+ letter-spacing: 1.05px;
271
+ color: #484848;
272
+ }
273
+
274
+ .badges-container {
275
+ margin-top: 0.75rem;
276
+ }
277
+
278
+ .loading-icon {
279
+ z-index: 20;
280
+ width: 40px;
281
+ height: 40px;
282
+ left: 80px;
283
+ }
284
+
285
+ .loading-icon :deep(.el-loading-mask) {
286
+ background-color: rgba(117, 190, 218, 0) !important;
287
+ }
288
+
289
+ .loading-icon :deep(.el-loading-spinner .path) {
290
+ stroke: $app-primary-color;
291
+ }
292
+
293
+ .title {
294
+ font: inherit;
295
+ margin-top:4px;
296
+ padding-right:30px;
297
+ vertical-align:middle;
298
+ }
299
+
300
+ .acupointTags {
301
+ margin-right:4px;
302
+ }
303
+
304
+ .float-button-container {
305
+ position: absolute;
306
+ bottom: 8px;
307
+ right: 16px;
308
+ opacity: 0;
309
+ visibility: hidden;
310
+
311
+ .card:hover & {
312
+ opacity: 1;
313
+ visibility: visible;
314
+ }
315
+ }
316
+ </style>