MaterialsSelector.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. <template>
  2. <div class="col-12 q-pa-md">
  3. <q-table
  4. :rows="rows"
  5. :columns="columns"
  6. :filter="filter"
  7. :loading="loading"
  8. :rows-per-page-options="[3, 12, 24, 0]"
  9. dense
  10. title="Available materials"
  11. title-class="text-h6"
  12. row-key="id"
  13. >
  14. <template #top>
  15. <div class="q-mr-md">
  16. <q-tooltip anchor="top end" self="center middle" >
  17. Using a copy of RefractiveIndex.info website.<br> Analytical models are not implemented.
  18. </q-tooltip>
  19. <q-icon size='sm' name="o_info" />
  20. </div>
  21. <q-input v-model="filter" dense debounce="200" color="primary" >
  22. <q-tooltip v-if="!filter" anchor="top middle" self="center middle">filter by any string</q-tooltip>
  23. <template #append>
  24. <q-icon name="filter_alt" />
  25. </template>
  26. <template v-if="filter" #after>
  27. <q-btn flat round dense icon="cancel" @click="filter=''"/>
  28. </template>
  29. </q-input>
  30. <q-space />
  31. </template>
  32. <template #header="props">
  33. <q-tr :props="props">
  34. <q-th auto-width />
  35. <q-th auto-width />
  36. <q-th auto-width class="text-left"> Label </q-th>
  37. <q-th auto-width class="text-left"> Range </q-th>
  38. <q-th auto-width class="text-left"> Material </q-th>
  39. <q-th class="text-left"> Details </q-th>
  40. </q-tr>
  41. </template>
  42. <template #body="props">
  43. <q-tr :props="props">
  44. <q-td auto-width>
  45. <q-tooltip anchor="top end" self="center middle" >
  46. Add to simulation</q-tooltip>
  47. <q-btn size="sm" color="primary" round dense icon="add" @click="addToSimulation(props.row.id)"/>
  48. </q-td>
  49. <q-td auto-width>
  50. <q-tooltip anchor="top end" self="center middle" >
  51. Download *.yml file</q-tooltip>
  52. <q-btn flat
  53. size="md"
  54. color="primary"
  55. icon="download"
  56. padding="xs 2px"
  57. @click="downloadPageData(props.row.pageData)"
  58. />
  59. </q-td>
  60. <q-td class="">
  61. {{composeLabelFromPageData(props.row.pageData)}}
  62. </q-td>
  63. <q-td auto-width>
  64. <q-tooltip
  65. v-if="props.row.spectrumRangeStart>fromWavelengthStore/1000 ||
  66. props.row.spectrumRangeEnd<toWavelengthStore/1000"
  67. anchor="top middle" self="center middle"
  68. class="bg-red">
  69. Mismatch with spectrum simulation
  70. </q-tooltip>
  71. <span :class="props.row.spectrumRangeStart>fromWavelengthStore/1000?'text-red':'text-black'">
  72. {{ props.row.spectrumRangeStart }}
  73. </span>
  74. <span v-if="props.row.spectrumRangeStart">&ndash;</span>
  75. <span :class="props.row.spectrumRangeEnd<toWavelengthStore/1000?'text-red':'text-black'">
  76. {{ props.row.spectrumRangeEnd }}
  77. </span>
  78. <span v-if="props.row.spectrumRangeStart">&NonBreakingSpace;mkm</span>
  79. </q-td>
  80. <q-td auto-width>
  81. <!-- eslint-disable-next-line vue/no-v-html -->
  82. <div v-html="props.row.bookName"/>
  83. <q-tooltip anchor="top middle" self="center middle" >
  84. {{ props.row.shelfDivider }}</q-tooltip>
  85. </q-td>
  86. <q-td> {{ props.row.bookDivider}}<span v-if="props.row.bookDivider">;&nbsp;</span>{{props.row.pageName }} </q-td>
  87. </q-tr>
  88. </template>
  89. </q-table>
  90. </div>
  91. </template>
  92. <script lang="ts">
  93. import {
  94. computed,
  95. defineComponent,
  96. reactive,
  97. ref
  98. } from 'vue'
  99. import { useStore } from 'src/store'
  100. import { load } from 'js-yaml'
  101. import { composeLabelFromPageData } from 'components/utils'
  102. import { saveAs } from 'file-saver'
  103. export default defineComponent({
  104. name: 'MaterialsSelector',
  105. components: {},
  106. setup: function () {
  107. const $store = useStore()
  108. const loading = ref(true)
  109. const fromWavelengthStore = computed(()=>$store.state.simulationSetup.gui.fromWL)
  110. const toWavelengthStore = computed(()=>$store.state.simulationSetup.gui.toWL)
  111. const columns = [
  112. // do not change the order without updating the template
  113. {name: 'id', label: '', field: 'id'},
  114. {name: 'bookDivider', label: 'State', field: 'bookDivider'},
  115. {name: 'bookName', label: 'Material', field: 'bookName'},
  116. {name: 'spectrumRangeStart', label: 'RangeStart', field: 'spectrumRangeStart'},
  117. {name: 'spectrumRangeEnd', label: 'RangeEnd', field: 'spectrumRangeEnd'},
  118. {name: 'pageName', label: 'Details', field: 'pageName'},
  119. {name: 'shelfDivider', label: 'Group', field: 'shelfDivider'},
  120. {name: 'pageData', label: 'file', field: 'pageData'},
  121. ]
  122. function GetRange(val:string) {
  123. if (val.lastIndexOf('µm') == -1) return [val,'']
  124. const rangeStartPosition = val.slice(0,val.lastIndexOf('µm')-1).lastIndexOf(' ')
  125. const spectrumRange = val.slice(rangeStartPosition+1,val.lastIndexOf('µm')+2)
  126. const newPageName = val.replace(spectrumRange,'')
  127. const spectrumRangeStart = spectrumRange.slice(0, spectrumRange.lastIndexOf('-'))
  128. const spectrumRangeEnd = spectrumRange.slice(spectrumRange.lastIndexOf('-')+1,
  129. spectrumRange.lastIndexOf('µm')-1)
  130. return [newPageName,spectrumRangeStart, spectrumRangeEnd]
  131. }
  132. function splitBookName(val:string) {
  133. if (val.lastIndexOf('(') == -1) return val
  134. const splitPosition = val.lastIndexOf('(')
  135. const mainPart = val.slice(0,splitPosition-1)
  136. const otherPart = val.slice(splitPosition+1, val.length-1)
  137. return mainPart+'<br><span style="font-size: 0.5em;">'+otherPart+'</span>'
  138. }
  139. async function GetPagesFromLib() { /* eslint-disable */
  140. //TODO enable eslint, which is disabled now due to unknown result type of load() from js-yaml
  141. let rows = []
  142. // lib has an irregular structure
  143. const response = await fetch('refractiveindex.info-database/database/library.yml')
  144. const data = await response.text()
  145. const response2 = await fetch('tabulated.txt')
  146. const tabulated = await response2.text()
  147. const lib = await load(data) as any
  148. let i = 1
  149. for (const shelf of lib) {
  150. let shelfDivider = ''
  151. let bookName = ''
  152. for (const bookOrDivider of shelf.content) {
  153. if (bookOrDivider.DIVIDER) {
  154. shelfDivider = bookOrDivider.DIVIDER
  155. continue
  156. } else if (bookOrDivider.name) {
  157. bookName = splitBookName(bookOrDivider.name)
  158. let bookDivider = ''
  159. let pageName = ''
  160. let pageData = ''
  161. for (const pageOrDivider of bookOrDivider.content) {
  162. if (pageOrDivider.DIVIDER) {
  163. bookDivider = pageOrDivider.DIVIDER.replace('Experimental data:','').replace('Experimental data','')
  164. continue
  165. } else if (pageOrDivider.name) {
  166. pageName = pageOrDivider.name
  167. pageData = pageOrDivider.data
  168. if (tabulated.indexOf(pageData) == -1) continue
  169. if (bookDivider.includes('Model') || bookDivider.includes('model')
  170. || pageName.includes('Model') || pageName.includes('model')) continue
  171. const pageNameSplit = GetRange(pageName)
  172. rows.push({ id: i, shelfDivider: shelfDivider, bookName: bookName, bookDivider: bookDivider,
  173. pageName: pageNameSplit[0], spectrumRangeStart: pageNameSplit[1],
  174. spectrumRangeEnd: pageNameSplit[2], pageData: pageData })
  175. i = i + 1
  176. } else {
  177. console.log('###################### Unknown type in pageOrDivider', pageOrDivider)
  178. }
  179. }
  180. } else {
  181. console.log('###################### Unknown type in bookOrDivider', bookOrDivider)
  182. }
  183. }
  184. }
  185. return rows
  186. }
  187. let rowsProto:{
  188. shelfDivider: string, bookName: string,
  189. bookDivider: string, pageName: string, pageData: string
  190. }[] = []
  191. const rows= reactive(rowsProto)
  192. GetPagesFromLib().then(val => {
  193. rows.push(...val);
  194. loading.value = false
  195. })
  196. const activatedMaterials = computed(() => $store.state.guiRuntime.activatedMaterials)
  197. // const columnsQ = computed(()=>{
  198. // return [
  199. // { name: 'name', label: '', align: 'left', field: 'name', headerStyle:''},
  200. // { name: 'Qsca', label: 'Qsca', align: 'left', field: 'Qsca', headerStyle:''},
  201. // { name: 'Qabs', label: 'Qabs', align: 'left', field: 'Qabs', headerStyle:''},
  202. // { name: 'Qext', label: 'Qext', align: 'left', field: 'Qext', headerStyle:''},
  203. // ]
  204. // })
  205. const filter = ref('')
  206. return {columns, rows, loading, filter,
  207. fromWavelengthStore, toWavelengthStore,
  208. composeLabelFromPageData,
  209. addToSimulation(val:number) {
  210. $store.dispatch('guiRuntime/activateMaterial', rows[val-1].pageData)
  211. },
  212. async downloadPageData(filepath:string) {
  213. const response = await fetch('refractiveindex.info-database/database/data/'+filepath)
  214. const data = await response.text()
  215. const scattnlaySpectra = new Blob([data],
  216. {type: 'text/plain;charset=utf-8',
  217. endings: 'native'} //TODO test if newline is correctly written in Windows, MacOS
  218. )
  219. saveAs(scattnlaySpectra, composeLabelFromPageData(filepath));
  220. }
  221. }
  222. },
  223. })
  224. </script>