matterviz 0.3.1 → 0.3.3

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 (358) hide show
  1. package/dist/EmptyState.svelte +10 -2
  2. package/dist/FilePicker.svelte +154 -96
  3. package/dist/Icon.svelte +20 -14
  4. package/dist/MillerIndexInput.svelte +27 -21
  5. package/dist/api/optimade.js +6 -6
  6. package/dist/app.css +216 -178
  7. package/dist/brillouin/BrillouinZone.svelte +299 -198
  8. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  9. package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
  10. package/dist/brillouin/BrillouinZoneExportPane.svelte +74 -55
  11. package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
  12. package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
  13. package/dist/brillouin/BrillouinZoneScene.svelte +277 -165
  14. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  15. package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
  16. package/dist/brillouin/compute.js +11 -6
  17. package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
  18. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  19. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +847 -0
  20. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  21. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3194 -0
  22. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  23. package/dist/chempot-diagram/ChemPotScene3D.svelte +11 -0
  24. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  25. package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
  26. package/dist/chempot-diagram/async-compute.svelte.js +77 -0
  27. package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
  28. package/dist/chempot-diagram/chempot-worker.js +11 -0
  29. package/dist/chempot-diagram/color.d.ts +10 -0
  30. package/dist/chempot-diagram/color.js +32 -0
  31. package/dist/chempot-diagram/compute.d.ts +48 -0
  32. package/dist/chempot-diagram/compute.js +812 -0
  33. package/dist/chempot-diagram/index.d.ts +6 -0
  34. package/dist/chempot-diagram/index.js +6 -0
  35. package/dist/chempot-diagram/pointer.d.ts +16 -0
  36. package/dist/chempot-diagram/pointer.js +40 -0
  37. package/dist/chempot-diagram/temperature.d.ts +15 -0
  38. package/dist/chempot-diagram/temperature.js +36 -0
  39. package/dist/chempot-diagram/types.d.ts +86 -0
  40. package/dist/chempot-diagram/types.js +28 -0
  41. package/dist/colors/index.d.ts +3 -1
  42. package/dist/colors/index.js +9 -3
  43. package/dist/composition/BarChart.svelte +141 -77
  44. package/dist/composition/BubbleChart.svelte +107 -52
  45. package/dist/composition/Composition.svelte +100 -79
  46. package/dist/composition/Formula.svelte +108 -62
  47. package/dist/composition/FormulaFilter.svelte +973 -353
  48. package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
  49. package/dist/composition/PieChart.svelte +199 -99
  50. package/dist/composition/PieChart.svelte.d.ts +1 -1
  51. package/dist/composition/format.d.ts +5 -0
  52. package/dist/composition/format.js +20 -3
  53. package/dist/composition/parse.js +14 -9
  54. package/dist/convex-hull/ConvexHull.svelte +93 -38
  55. package/dist/convex-hull/ConvexHull2D.svelte +551 -393
  56. package/dist/convex-hull/ConvexHull3D.svelte +1303 -825
  57. package/dist/convex-hull/ConvexHull4D.svelte +1012 -686
  58. package/dist/convex-hull/ConvexHullControls.svelte +115 -28
  59. package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
  60. package/dist/convex-hull/ConvexHullStats.svelte +821 -249
  61. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  62. package/dist/convex-hull/ConvexHullTooltip.svelte +41 -16
  63. package/dist/convex-hull/GasPressureControls.svelte +104 -61
  64. package/dist/convex-hull/StructurePopup.svelte +25 -4
  65. package/dist/convex-hull/TemperatureSlider.svelte +45 -25
  66. package/dist/convex-hull/barycentric-coords.js +13 -7
  67. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  68. package/dist/convex-hull/demo-temperature.js +40 -0
  69. package/dist/convex-hull/gas-thermodynamics.js +17 -12
  70. package/dist/convex-hull/helpers.d.ts +10 -1
  71. package/dist/convex-hull/helpers.js +79 -38
  72. package/dist/convex-hull/index.d.ts +1 -0
  73. package/dist/convex-hull/index.js +1 -0
  74. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  75. package/dist/convex-hull/thermodynamics.js +163 -69
  76. package/dist/convex-hull/types.d.ts +12 -12
  77. package/dist/convex-hull/types.js +0 -12
  78. package/dist/coordination/CoordinationBarPlot.svelte +232 -176
  79. package/dist/element/BohrAtom.svelte +56 -13
  80. package/dist/element/ElementHeading.svelte +7 -2
  81. package/dist/element/ElementPhoto.svelte +15 -9
  82. package/dist/element/ElementStats.svelte +10 -4
  83. package/dist/element/ElementTile.svelte +137 -73
  84. package/dist/element/Nucleus.svelte +39 -11
  85. package/dist/element/data.js +2 -14
  86. package/dist/element/data.json.gz +0 -0
  87. package/dist/element/types.d.ts +1 -0
  88. package/dist/feedback/ClickFeedback.svelte +16 -5
  89. package/dist/feedback/DragOverlay.svelte +10 -2
  90. package/dist/feedback/Spinner.svelte +4 -2
  91. package/dist/feedback/StatusMessage.svelte +8 -2
  92. package/dist/fermi-surface/FermiSlice.svelte +118 -88
  93. package/dist/fermi-surface/FermiSurface.svelte +336 -239
  94. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  95. package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
  96. package/dist/fermi-surface/FermiSurfaceScene.svelte +536 -343
  97. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  98. package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
  99. package/dist/fermi-surface/compute.js +16 -20
  100. package/dist/fermi-surface/parse.js +37 -33
  101. package/dist/fermi-surface/symmetry.js +2 -7
  102. package/dist/fermi-surface/types.d.ts +3 -5
  103. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1527 -0
  104. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  105. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
  106. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
  107. package/dist/heatmap-matrix/index.d.ts +53 -0
  108. package/dist/heatmap-matrix/index.js +100 -0
  109. package/dist/heatmap-matrix/shared.d.ts +2 -0
  110. package/dist/heatmap-matrix/shared.js +4 -0
  111. package/dist/icons.d.ts +111 -0
  112. package/dist/icons.js +158 -0
  113. package/dist/index.d.ts +5 -2
  114. package/dist/index.js +5 -2
  115. package/dist/io/decompress.js +1 -1
  116. package/dist/io/export.d.ts +3 -0
  117. package/dist/io/export.js +138 -140
  118. package/dist/io/file-drop.d.ts +7 -0
  119. package/dist/io/file-drop.js +43 -0
  120. package/dist/io/index.d.ts +2 -2
  121. package/dist/io/index.js +2 -112
  122. package/dist/io/is-binary.js +2 -3
  123. package/dist/io/types.d.ts +1 -0
  124. package/dist/io/url-drop.d.ts +2 -0
  125. package/dist/io/url-drop.js +117 -0
  126. package/dist/isosurface/Isosurface.svelte +220 -110
  127. package/dist/isosurface/IsosurfaceControls.svelte +65 -28
  128. package/dist/isosurface/parse.js +104 -56
  129. package/dist/isosurface/slice.d.ts +2 -1
  130. package/dist/isosurface/slice.js +8 -13
  131. package/dist/isosurface/types.d.ts +14 -1
  132. package/dist/isosurface/types.js +152 -5
  133. package/dist/labels.d.ts +2 -1
  134. package/dist/labels.js +12 -8
  135. package/dist/layout/FullscreenToggle.svelte +11 -2
  136. package/dist/layout/InfoCard.svelte +38 -6
  137. package/dist/layout/InfoTag.svelte +125 -94
  138. package/dist/layout/PropertyFilter.svelte +82 -37
  139. package/dist/layout/SettingsSection.svelte +85 -55
  140. package/dist/layout/SubpageGrid.svelte +82 -0
  141. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  142. package/dist/layout/index.d.ts +1 -0
  143. package/dist/layout/index.js +1 -0
  144. package/dist/layout/json-tree/JsonNode.svelte +266 -223
  145. package/dist/layout/json-tree/JsonTree.svelte +516 -429
  146. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  147. package/dist/layout/json-tree/JsonValue.svelte +281 -173
  148. package/dist/layout/json-tree/types.d.ts +10 -2
  149. package/dist/layout/json-tree/utils.d.ts +2 -0
  150. package/dist/layout/json-tree/utils.js +37 -2
  151. package/dist/marching-cubes.js +25 -2
  152. package/dist/math.d.ts +20 -17
  153. package/dist/math.js +474 -57
  154. package/dist/overlays/ContextMenu.svelte +66 -40
  155. package/dist/overlays/DraggablePane.svelte +331 -154
  156. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  157. package/dist/periodic-table/PeriodicTable.svelte +278 -145
  158. package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
  159. package/dist/periodic-table/PropertySelect.svelte +25 -7
  160. package/dist/periodic-table/TableInset.svelte +8 -3
  161. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +559 -267
  162. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  163. package/dist/phase-diagram/PhaseDiagramControls.svelte +131 -51
  164. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  165. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
  166. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  167. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +160 -110
  168. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +8 -1
  169. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +217 -86
  170. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  171. package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
  172. package/dist/phase-diagram/build-diagram.js +9 -9
  173. package/dist/phase-diagram/colors.js +1 -3
  174. package/dist/phase-diagram/index.d.ts +2 -0
  175. package/dist/phase-diagram/index.js +2 -0
  176. package/dist/phase-diagram/parse.js +10 -9
  177. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  178. package/dist/phase-diagram/svg-to-diagram.js +869 -0
  179. package/dist/phase-diagram/types.d.ts +10 -0
  180. package/dist/phase-diagram/utils.d.ts +8 -4
  181. package/dist/phase-diagram/utils.js +219 -74
  182. package/dist/plot/AxisLabel.svelte +51 -0
  183. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  184. package/dist/plot/BarPlot.svelte +1461 -768
  185. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  186. package/dist/plot/BarPlotControls.svelte +33 -6
  187. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  188. package/dist/plot/ColorBar.svelte +533 -383
  189. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  190. package/dist/plot/ColorScaleSelect.svelte +28 -7
  191. package/dist/plot/ElementScatter.svelte +38 -16
  192. package/dist/plot/FillArea.svelte +152 -92
  193. package/dist/plot/Histogram.svelte +1162 -709
  194. package/dist/plot/Histogram.svelte.d.ts +1 -1
  195. package/dist/plot/HistogramControls.svelte +81 -18
  196. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  197. package/dist/plot/InteractiveAxisLabel.svelte +34 -11
  198. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  199. package/dist/plot/Line.svelte +63 -28
  200. package/dist/plot/PlotControls.svelte +221 -96
  201. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  202. package/dist/plot/PlotLegend.svelte +174 -91
  203. package/dist/plot/PlotTooltip.svelte +45 -6
  204. package/dist/plot/PortalSelect.svelte +175 -146
  205. package/dist/plot/ReferenceLine.svelte +77 -22
  206. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  207. package/dist/plot/ReferenceLine3D.svelte +132 -107
  208. package/dist/plot/ReferencePlane.svelte +146 -123
  209. package/dist/plot/ScatterPlot.svelte +1880 -1156
  210. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  211. package/dist/plot/ScatterPlot3D.svelte +256 -131
  212. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  213. package/dist/plot/ScatterPlot3DControls.svelte +300 -297
  214. package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
  215. package/dist/plot/ScatterPlot3DScene.svelte +608 -406
  216. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  217. package/dist/plot/ScatterPlotControls.svelte +150 -70
  218. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  219. package/dist/plot/ScatterPoint.svelte +98 -26
  220. package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
  221. package/dist/plot/SpacegroupBarPlot.svelte +142 -85
  222. package/dist/plot/Surface3D.svelte +159 -108
  223. package/dist/plot/ZeroLines.svelte +96 -0
  224. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  225. package/dist/plot/ZoomRect.svelte +23 -0
  226. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  227. package/dist/plot/axis-utils.d.ts +1 -1
  228. package/dist/plot/axis-utils.js +1 -3
  229. package/dist/plot/data-cleaning.js +12 -28
  230. package/dist/plot/data-transform.js +2 -1
  231. package/dist/plot/fill-utils.js +2 -0
  232. package/dist/plot/index.d.ts +6 -2
  233. package/dist/plot/index.js +6 -2
  234. package/dist/plot/interactions.d.ts +8 -10
  235. package/dist/plot/interactions.js +2 -3
  236. package/dist/plot/layout.d.ts +11 -2
  237. package/dist/plot/layout.js +44 -17
  238. package/dist/plot/reference-line.d.ts +5 -22
  239. package/dist/plot/reference-line.js +12 -84
  240. package/dist/plot/scales.js +24 -36
  241. package/dist/plot/types.d.ts +53 -40
  242. package/dist/plot/types.js +12 -7
  243. package/dist/plot/utils/label-placement.d.ts +32 -15
  244. package/dist/plot/utils/label-placement.js +227 -63
  245. package/dist/plot/utils/series-visibility.js +2 -3
  246. package/dist/plot/utils.d.ts +1 -0
  247. package/dist/plot/utils.js +14 -0
  248. package/dist/rdf/RdfPlot.svelte +173 -132
  249. package/dist/rdf/calc-rdf.js +4 -5
  250. package/dist/sanitize.d.ts +4 -0
  251. package/dist/sanitize.js +107 -0
  252. package/dist/settings.d.ts +21 -6
  253. package/dist/settings.js +63 -19
  254. package/dist/spectral/Bands.svelte +963 -412
  255. package/dist/spectral/Bands.svelte.d.ts +22 -2
  256. package/dist/spectral/BandsAndDos.svelte +90 -49
  257. package/dist/spectral/BrillouinBandsDos.svelte +151 -93
  258. package/dist/spectral/Dos.svelte +389 -258
  259. package/dist/spectral/helpers.d.ts +23 -1
  260. package/dist/spectral/helpers.js +119 -51
  261. package/dist/spectral/types.d.ts +2 -0
  262. package/dist/state.svelte.d.ts +1 -1
  263. package/dist/state.svelte.js +3 -2
  264. package/dist/structure/Arrow.svelte +59 -20
  265. package/dist/structure/AtomLegend.svelte +231 -129
  266. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  267. package/dist/structure/Bond.svelte +73 -47
  268. package/dist/structure/CanvasTooltip.svelte +10 -2
  269. package/dist/structure/CellSelect.svelte +148 -51
  270. package/dist/structure/Cylinder.svelte +33 -17
  271. package/dist/structure/Lattice.svelte +88 -33
  272. package/dist/structure/Structure.svelte +1077 -821
  273. package/dist/structure/Structure.svelte.d.ts +1 -1
  274. package/dist/structure/StructureControls.svelte +373 -139
  275. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  276. package/dist/structure/StructureExportPane.svelte +124 -89
  277. package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
  278. package/dist/structure/StructureInfoPane.svelte +304 -231
  279. package/dist/structure/StructureScene.svelte +919 -445
  280. package/dist/structure/StructureScene.svelte.d.ts +16 -7
  281. package/dist/structure/atom-properties.d.ts +6 -2
  282. package/dist/structure/atom-properties.js +42 -29
  283. package/dist/structure/bonding.js +6 -7
  284. package/dist/structure/export.js +22 -34
  285. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  286. package/dist/structure/ferrox-wasm-types.js +0 -3
  287. package/dist/structure/ferrox-wasm.d.ts +3 -2
  288. package/dist/structure/ferrox-wasm.js +2 -3
  289. package/dist/structure/index.d.ts +16 -0
  290. package/dist/structure/index.js +88 -6
  291. package/dist/structure/measure.d.ts +2 -2
  292. package/dist/structure/measure.js +4 -44
  293. package/dist/structure/parse.js +130 -155
  294. package/dist/structure/partial-occupancy.d.ts +25 -0
  295. package/dist/structure/partial-occupancy.js +99 -0
  296. package/dist/structure/pbc.d.ts +1 -0
  297. package/dist/structure/pbc.js +16 -6
  298. package/dist/structure/supercell.d.ts +2 -2
  299. package/dist/structure/supercell.js +12 -22
  300. package/dist/structure/validation.js +5 -3
  301. package/dist/symmetry/SymmetryStats.svelte +94 -37
  302. package/dist/symmetry/WyckoffTable.svelte +42 -14
  303. package/dist/symmetry/cell-transform.js +5 -3
  304. package/dist/symmetry/index.d.ts +7 -4
  305. package/dist/symmetry/index.js +87 -21
  306. package/dist/symmetry/spacegroups.js +148 -148
  307. package/dist/table/HeatmapTable.svelte +1112 -516
  308. package/dist/table/HeatmapTable.svelte.d.ts +12 -1
  309. package/dist/table/ToggleMenu.svelte +125 -90
  310. package/dist/table/index.d.ts +2 -0
  311. package/dist/table/index.js +2 -4
  312. package/dist/theme/ThemeControl.svelte +21 -12
  313. package/dist/time.js +4 -1
  314. package/dist/tooltip/TooltipContent.svelte +33 -8
  315. package/dist/trajectory/Trajectory.svelte +889 -687
  316. package/dist/trajectory/TrajectoryError.svelte +14 -3
  317. package/dist/trajectory/TrajectoryExportPane.svelte +148 -90
  318. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  319. package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
  320. package/dist/trajectory/constants.d.ts +6 -0
  321. package/dist/trajectory/constants.js +7 -0
  322. package/dist/trajectory/extract.js +13 -31
  323. package/dist/trajectory/format-detect.d.ts +9 -0
  324. package/dist/trajectory/format-detect.js +76 -0
  325. package/dist/trajectory/frame-reader.d.ts +17 -0
  326. package/dist/trajectory/frame-reader.js +332 -0
  327. package/dist/trajectory/helpers.d.ts +14 -0
  328. package/dist/trajectory/helpers.js +172 -0
  329. package/dist/trajectory/index.d.ts +1 -0
  330. package/dist/trajectory/index.js +23 -14
  331. package/dist/trajectory/parse/ase.d.ts +2 -0
  332. package/dist/trajectory/parse/ase.js +77 -0
  333. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  334. package/dist/trajectory/parse/hdf5.js +129 -0
  335. package/dist/trajectory/parse/index.d.ts +12 -0
  336. package/dist/trajectory/parse/index.js +299 -0
  337. package/dist/trajectory/parse/lammps.d.ts +5 -0
  338. package/dist/trajectory/parse/lammps.js +179 -0
  339. package/dist/trajectory/parse/vasp.d.ts +2 -0
  340. package/dist/trajectory/parse/vasp.js +68 -0
  341. package/dist/trajectory/parse/xyz.d.ts +2 -0
  342. package/dist/trajectory/parse/xyz.js +110 -0
  343. package/dist/trajectory/plotting.js +13 -8
  344. package/dist/trajectory/types.d.ts +11 -0
  345. package/dist/trajectory/types.js +1 -0
  346. package/dist/utils.d.ts +3 -0
  347. package/dist/utils.js +17 -0
  348. package/dist/xrd/XrdPlot.svelte +337 -245
  349. package/dist/xrd/broadening.js +14 -9
  350. package/dist/xrd/calc-xrd.js +12 -19
  351. package/dist/xrd/parse.d.ts +1 -1
  352. package/dist/xrd/parse.js +17 -17
  353. package/package.json +103 -101
  354. package/readme.md +4 -4
  355. package/dist/trajectory/parse.d.ts +0 -42
  356. package/dist/trajectory/parse.js +0 -1267
  357. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
  358. /package/dist/theme/{themes.js → themes.mjs} +0 -0
@@ -1,183 +1,265 @@
1
- <script lang="ts">import { add_alpha, PLOT_COLORS } from '../colors';
2
- import EmptyState from '../EmptyState.svelte';
3
- import StatusMessage from '../feedback/StatusMessage.svelte';
4
- import { decompress_data_binary, decompress_file, detect_compression_format, handle_url_drop, } from '../io';
5
- import { format_value } from '../labels';
6
- import SettingsSection from '../layout/SettingsSection.svelte';
7
- import { BarPlot, ScatterPlot } from '../plot';
8
- import { add_xrd_pattern } from './calc-xrd';
9
- import { compute_broadened_pattern, DEFAULT_BROADENING } from './broadening';
10
- function is_xrd_pattern(obj) {
11
- if (!obj || typeof obj !== `object`)
12
- return false;
13
- const record = obj;
14
- return (Array.isArray(record.x) &&
15
- Array.isArray(record.y) &&
16
- record.x.length === record.y.length);
17
- }
18
- function format_hkl(hkl, format) {
1
+ <script lang="ts">
2
+ import { add_alpha, PLOT_COLORS } from '../colors'
3
+ import EmptyState from '../EmptyState.svelte'
4
+ import StatusMessage from '../feedback/StatusMessage.svelte'
5
+ import {
6
+ decompress_data_binary,
7
+ decompress_file,
8
+ detect_compression_format,
9
+ handle_url_drop,
10
+ } from '../io'
11
+ import { format_value } from '../labels'
12
+ import { sanitize_html } from '../sanitize'
13
+ import SettingsSection from '../layout/SettingsSection.svelte'
14
+ import type { Vec2 } from '../math'
15
+ import type {
16
+ AxisConfig,
17
+ BarHandlerProps,
18
+ BarSeries,
19
+ ControlsConfig,
20
+ DataSeries,
21
+ ScatterHandlerProps,
22
+ } from '../plot'
23
+ import { BarPlot, ScatterPlot } from '../plot'
24
+ import { add_xrd_pattern } from './calc-xrd'
25
+ import type { ComponentProps } from 'svelte'
26
+ import type { BroadeningParams } from './broadening'
27
+ import { compute_broadened_pattern, DEFAULT_BROADENING } from './broadening'
28
+ import type { Hkl, HklFormat, PatternEntry, XrdPattern } from './index'
29
+
30
+ function is_xrd_pattern(obj: unknown): obj is XrdPattern {
31
+ if (!obj || typeof obj !== `object`) return false
32
+ const pattern_obj = obj as { x?: unknown; y?: unknown }
33
+ const x = pattern_obj.x
34
+ const y = pattern_obj.y
35
+ return (
36
+ Array.isArray(x) &&
37
+ Array.isArray(y) &&
38
+ x.length === y.length
39
+ )
40
+ }
41
+
42
+ function format_hkl(hkl: Hkl, format: HklFormat): string {
19
43
  if (format === `compact`) {
20
- // Use crystallographic overbar notation for negative indices (e.g. 1̄ instead of -1)
21
- // Note: Requires font support for Unicode combining characters (U+0305)
22
- return hkl
23
- .map((val) => {
24
- // Use combining overline character (U+0305) for negative values
25
- // Apply overbar to each digit for multi-digit numbers
26
- if (val < 0) {
27
- const digits = String(Math.abs(val));
28
- return digits
29
- .split(``)
30
- .map((digit) => `${digit}\u0305`)
31
- .join(``);
32
- }
33
- return `${val}`;
44
+ // Use crystallographic overbar notation for negative indices (e.g. 1̄ instead of -1)
45
+ // Note: Requires font support for Unicode combining characters (U+0305)
46
+ return hkl
47
+ .map((val) => {
48
+ // Use combining overline character (U+0305) for negative values
49
+ // Apply overbar to each digit for multi-digit numbers
50
+ if (val < 0) {
51
+ const digits = String(Math.abs(val))
52
+ return digits
53
+ .split(``)
54
+ .map((digit) => `${digit}\u0305`)
55
+ .join(``)
56
+ }
57
+ return `${val}`
34
58
  })
35
- .join(``);
59
+ .join(``)
36
60
  }
37
- if (format === `full`)
38
- return `(${hkl.join(`, `)})`;
39
- return ``;
40
- }
41
- let { patterns, peak_width = 0.5, annotate_peaks = 5, hkl_format = `compact`, show_angles = null, orientation = `vertical`, wavelength = null, x_axis = {}, y_axis = {}, allow_file_drop = true, on_file_drop, loading = $bindable(false), error_msg = $bindable(), broadening_enabled = $bindable(false), broadening_params = $bindable({ ...DEFAULT_BROADENING }), controls = {}, ...rest } = $props();
42
- let dragover = $state(false);
43
- let dropped_entries = $state([]);
44
- // Normalize various input shapes to a consistent array of { label, pattern, color }
45
- const pattern_entries = $derived.by(() => {
46
- if (!patterns)
47
- return [];
61
+ if (format === `full`) return `(${hkl.join(`, `)})`
62
+ return ``
63
+ }
64
+
65
+ let {
66
+ patterns,
67
+ peak_width = 0.5,
68
+ annotate_peaks = 5,
69
+ hkl_format = `compact`,
70
+ show_angles = null,
71
+ orientation = `vertical`,
72
+ wavelength = null,
73
+ x_axis = {},
74
+ y_axis = {},
75
+ allow_file_drop = true,
76
+ on_file_drop,
77
+ loading = $bindable(false),
78
+ error_msg = $bindable(),
79
+ broadening_enabled = $bindable(false),
80
+ broadening_params = $bindable({ ...DEFAULT_BROADENING }),
81
+ controls = {},
82
+ ...rest
83
+ }:
84
+ & ComponentProps<typeof BarPlot>
85
+ & ComponentProps<typeof ScatterPlot>
86
+ & {
87
+ patterns:
88
+ | XrdPattern
89
+ | Record<string, XrdPattern | { pattern: XrdPattern; color?: string }>
90
+ | PatternEntry[]
91
+ peak_width?: number
92
+ annotate_peaks?: number // int => top-k, float in (0,1) => threshold of max
93
+ hkl_format?: HklFormat
94
+ show_angles?: boolean | null
95
+ wavelength?: number | null
96
+ x_axis?: AxisConfig
97
+ y_axis?: AxisConfig
98
+ allow_file_drop?: boolean
99
+ on_file_drop?: (content: string | ArrayBuffer, filename: string) => void
100
+ loading?: boolean
101
+ error_msg?: string
102
+ broadening_enabled?: boolean
103
+ broadening_params?: BroadeningParams
104
+ controls?: ControlsConfig
105
+ } = $props()
106
+
107
+ let dragover = $state(false)
108
+ let dropped_entries = $state<PatternEntry[]>([])
109
+
110
+ // Normalize various input shapes to a consistent array of { label, pattern, color }
111
+ const pattern_entries = $derived.by<PatternEntry[]>(() => {
112
+ if (!patterns) return []
48
113
  const base_entries = Array.isArray(patterns)
49
- ? patterns
50
- : is_xrd_pattern(patterns)
51
- ? [{ label: `XRD Pattern`, pattern: patterns }]
52
- : Object.entries(patterns).map(([label, value]) => `pattern` in value
53
- ? { label, ...value }
54
- : { label, pattern: value });
114
+ ? (patterns as PatternEntry[])
115
+ : is_xrd_pattern(patterns)
116
+ ? [{ label: `XRD Pattern`, pattern: patterns as XrdPattern }]
117
+ : Object.entries(
118
+ patterns as Record<
119
+ string,
120
+ XrdPattern | { pattern: XrdPattern; color?: string }
121
+ >,
122
+ ).map(([label, value]) =>
123
+ `pattern` in value
124
+ ? { label, ...value }
125
+ : { label, pattern: value as XrdPattern }
126
+ )
55
127
  // Merge user-provided patterns with any dropped-on-the-fly entries
56
- return [...base_entries, ...dropped_entries];
57
- });
58
- // Decide default show_angles
59
- const actual_show_angles = $derived(show_angles ?? pattern_entries.length <= 2);
60
- // Compute global max intensity for normalization (as in pymatviz xrd_pattern)
61
- const global_max_intensity = $derived.by(() => {
62
- let max_val = 0;
128
+ return [...base_entries, ...dropped_entries]
129
+ })
130
+
131
+ // Decide default show_angles
132
+ const actual_show_angles = $derived(
133
+ show_angles ?? pattern_entries.length <= 2,
134
+ )
135
+
136
+ // Compute global max intensity for normalization (as in pymatviz xrd_pattern)
137
+ const global_max_intensity = $derived.by(() => {
138
+ let max_val = 0
63
139
  for (const entry of pattern_entries) {
64
- for (const y of entry.pattern.y)
65
- if (y > max_val)
66
- max_val = y;
140
+ for (const y of entry.pattern.y) if (y > max_val) max_val = y
67
141
  }
68
- return max_val || 1;
69
- });
70
- // Compute overall 2θ domain (degrees)
71
- const angle_range = $derived.by(() => {
72
- if (pattern_entries.length === 0)
73
- return [0, 90]; // Default range
74
- let min_x = Infinity;
75
- let max_x = 0;
76
- for (const entry of pattern_entries) {
77
- const entry_min = Math.min(...entry.pattern.x);
78
- const entry_max = Math.max(...entry.pattern.x);
79
- if (entry_min < min_x)
80
- min_x = entry_min;
81
- if (entry_max > max_x)
82
- max_x = entry_max;
142
+ return max_val || 1
143
+ })
144
+
145
+ // Compute overall 2θ domain (degrees)
146
+ const angle_range = $derived.by((): Vec2 => {
147
+ const valid = pattern_entries.filter((entry) => entry.pattern.x.length > 0)
148
+ if (valid.length === 0) return [0, 90]
149
+ let [min_x, max_x] = [Infinity, 0]
150
+ for (const entry of valid) {
151
+ const entry_min = Math.min(...entry.pattern.x)
152
+ const entry_max = Math.max(...entry.pattern.x)
153
+ if (entry_min < min_x) min_x = entry_min
154
+ if (entry_max > max_x) max_x = entry_max
83
155
  }
84
- // Use data min if it's significantly above 0, otherwise start at 0
85
- const x_min = min_x > 10 ? Math.floor(min_x) : 0;
86
- return [x_min, Math.ceil(max_x)];
87
- });
88
- // Scaled intensities are normalized to 0..100, add 10% top padding for peak labels
89
- const intensity_range = [0, 110];
90
- // Build BarPlot series from entries (for Discrete/Stick view)
91
- const bar_series = $derived.by(() => {
92
- if (broadening_enabled)
93
- return []; // Optimization: skip if not used
94
- const include_name = pattern_entries.length > 1;
156
+ const x_min = min_x > 10 ? Math.floor(min_x) : 0
157
+ return [x_min, Math.ceil(max_x)]
158
+ })
159
+
160
+ // Scaled intensities are normalized to 0..100, add 10% top padding for peak labels
161
+ const intensity_range: [number, number] = [0, 110]
162
+
163
+ // Build BarPlot series from entries (for Discrete/Stick view)
164
+ const bar_series = $derived.by<BarSeries[]>(() => {
165
+ if (broadening_enabled) return [] // Optimization: skip if not used
166
+
167
+ const include_name = pattern_entries.length > 1
95
168
  // Add transparency when multiple series overlap
96
- const alpha = pattern_entries.length > 1 ? 0.6 : 1;
97
- const scale = (y) => (y / global_max_intensity) * 100;
169
+ const alpha = pattern_entries.length > 1 ? 0.6 : 1
170
+ const scale = (y: number) => (y / global_max_intensity) * 100
98
171
  return pattern_entries.map((entry, entry_idx) => {
99
- const xs = entry.pattern.x;
100
- const ys = entry.pattern.y.map((val) => scale(val || 0));
101
- const metadata = [];
102
- const labels = [];
103
- // Determine which peaks to annotate
104
- const intens = ys;
105
- let selected_indices = [];
106
- if (annotate_peaks && annotate_peaks > 0) {
107
- let candidates = [];
108
- if (annotate_peaks > 0 && annotate_peaks < 1) {
109
- const thresh = annotate_peaks * 100;
110
- candidates = intens
111
- .map((y_val, idx) => ({ y_val, idx }))
112
- .filter(({ y_val }) => y_val > thresh);
113
- }
114
- else {
115
- const k = Math.min(intens.length, Math.floor(annotate_peaks));
116
- candidates = intens
117
- .map((y_val, idx) => ({ y_val, idx }))
118
- .sort((a, b) => b.y_val - a.y_val)
119
- .slice(0, k);
120
- }
121
- // Filter out overlapping labels: keep higher intensity peaks when x values are close
122
- // Min spacing as fraction of x-range to avoid overlaps (roughly 3% of range)
123
- const x_range = Math.max(...xs) - Math.min(...xs);
124
- const min_spacing = x_range * 0.03;
125
- // Sort by intensity descending so we keep highest peaks first
126
- candidates.sort((a, b) => b.y_val - a.y_val);
127
- const kept = [];
128
- for (const cand of candidates) {
129
- const cand_x = xs[cand.idx];
130
- // Check if any already-kept peak is too close
131
- const too_close = kept.some((kept_peak) => Math.abs(xs[kept_peak.idx] - cand_x) < min_spacing);
132
- if (!too_close)
133
- kept.push(cand);
134
- }
135
- selected_indices = kept.map((kept_peak) => kept_peak.idx);
172
+ const xs = entry.pattern.x
173
+ const ys = entry.pattern.y.map((val) => scale(val || 0))
174
+ const metadata: Record<string, unknown>[] = []
175
+ const labels: (string | null)[] = []
176
+
177
+ // Determine which peaks to annotate
178
+ const intens = ys
179
+ let selected_indices: number[] = []
180
+ if (annotate_peaks && annotate_peaks > 0) {
181
+ let candidates: { idx: number; y_val: number }[] = []
182
+ if (annotate_peaks > 0 && annotate_peaks < 1) {
183
+ const thresh = annotate_peaks * 100
184
+ candidates = intens
185
+ .map((y_val, idx) => ({ y_val, idx }))
186
+ .filter(({ y_val }) => y_val > thresh)
187
+ } else {
188
+ const max_peaks = Math.min(intens.length, Math.floor(annotate_peaks))
189
+ candidates = intens
190
+ .map((y_val, idx) => ({ y_val, idx }))
191
+ .sort((a, b) => b.y_val - a.y_val)
192
+ .slice(0, max_peaks)
136
193
  }
137
- for (let idx = 0; idx < xs.length; idx++) {
138
- const hkls_objs = entry.pattern.hkls?.[idx] ?? [];
139
- const hkls = hkls_objs
140
- .map((h) => (Array.isArray(h?.hkl) ? h.hkl : null))
141
- .filter((h) => Array.isArray(h) && h.length === 3);
142
- const d_hkl = entry.pattern.d_hkls?.[idx];
143
- metadata.push({ hkls, d: d_hkl, label: entry.label });
144
- if (selected_indices.includes(idx)) {
145
- const angle_text = actual_show_angles
146
- ? `${format_value(xs[idx], `.2f`)}°`
147
- : ``;
148
- const hkl_text = hkls && hkl_format
149
- ? hkls.map((h) => format_hkl(h, hkl_format)).join(`, `)
150
- : ``;
151
- // Use @ separator between hkl and angle for better clarity
152
- const separator = hkl_text && angle_text ? ` @ ` : ``;
153
- const text = [hkl_text, angle_text].filter(Boolean).join(separator);
154
- labels.push(text);
155
- }
156
- else
157
- labels.push(null);
194
+
195
+ // Filter out overlapping labels: keep higher intensity peaks when x values are close
196
+ // Min spacing as fraction of x-range to avoid overlaps (roughly 3% of range)
197
+ const x_range = Math.max(...xs) - Math.min(...xs)
198
+ const min_spacing = x_range * 0.03
199
+ // Sort by intensity descending so we keep highest peaks first
200
+ candidates.sort((a, b) => b.y_val - a.y_val)
201
+ const kept: { idx: number; y_val: number }[] = []
202
+ for (const cand of candidates) {
203
+ const cand_x = xs[cand.idx]
204
+ // Check if any already-kept peak is too close
205
+ const too_close = kept.some(
206
+ (kept_peak) => Math.abs(xs[kept_peak.idx] - cand_x) < min_spacing,
207
+ )
208
+ if (!too_close) kept.push(cand)
158
209
  }
159
- const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length];
160
- return {
161
- x: xs,
162
- y: ys,
163
- label: include_name ? entry.label : ``,
164
- color: add_alpha(base_color, alpha),
165
- bar_width: Math.max(peak_width, 0.8),
166
- visible: true,
167
- metadata,
168
- labels,
169
- };
170
- });
171
- });
172
- // Build ScatterPlot series (for Broadened Profile view)
173
- const scatter_series = $derived.by(() => {
174
- if (!broadening_enabled)
175
- return [];
176
- const include_name = pattern_entries.length > 1;
210
+ selected_indices = kept.map((kept_peak) => kept_peak.idx)
211
+ }
212
+
213
+ for (let idx = 0; idx < xs.length; idx++) {
214
+ const hkls_objs = entry.pattern.hkls?.[idx] ?? []
215
+ const hkls: Hkl[] = hkls_objs
216
+ .map((hkl_obj) => (Array.isArray(hkl_obj?.hkl) ? hkl_obj.hkl : null))
217
+ .filter((hkl_val): hkl_val is Hkl => Array.isArray(hkl_val) && hkl_val.length === 3)
218
+ const d_hkl = entry.pattern.d_hkls?.[idx]
219
+ metadata.push({ hkls, d: d_hkl, label: entry.label })
220
+
221
+ if (selected_indices.includes(idx)) {
222
+ const angle_text = actual_show_angles
223
+ ? `${format_value(xs[idx], `.2f`)}°`
224
+ : ``
225
+ const hkl_text = hkls && hkl_format
226
+ ? hkls.map((hkl_val) => format_hkl(hkl_val, hkl_format)).join(`, `)
227
+ : ``
228
+ // Use @ separator between hkl and angle for better clarity
229
+ const separator = hkl_text && angle_text ? ` @ ` : ``
230
+ const text = [hkl_text, angle_text].filter(Boolean).join(separator)
231
+ labels.push(text)
232
+ } else labels.push(null)
233
+ }
234
+
235
+ const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length]
236
+ return {
237
+ x: xs,
238
+ y: ys,
239
+ label: include_name ? entry.label : ``,
240
+ color: add_alpha(base_color, alpha),
241
+ bar_width: Math.max(peak_width, 0.8),
242
+ visible: true,
243
+ metadata,
244
+ labels,
245
+ }
246
+ })
247
+ })
248
+
249
+ // Build ScatterPlot series (for Broadened Profile view)
250
+ const scatter_series = $derived.by<DataSeries[]>(() => {
251
+ if (!broadening_enabled) return []
252
+
253
+ const include_name = pattern_entries.length > 1
177
254
  // We rescale after broadening so that max peak is 100, matching stick view scale
178
255
  return pattern_entries
179
- .map((entry, entry_idx) => {
180
- const broadened = compute_broadened_pattern(entry.pattern, broadening_params, angle_range);
256
+ .map((entry, entry_idx) => {
257
+ const broadened = compute_broadened_pattern(
258
+ entry.pattern,
259
+ broadening_params,
260
+ angle_range,
261
+ )
262
+
181
263
  // Normalize broadened profile relative to GLOBAL max intensity of stick patterns?
182
264
  // Or normalize to 100 for *this* profile?
183
265
  // Usually we want relative intensities between patterns to be preserved if possible.
@@ -185,91 +267,101 @@ const scatter_series = $derived.by(() => {
185
267
  // If we normalize each profile to 100 independently, we lose relative scaling between patterns.
186
268
  // If we normalize by global_max_intensity (from sticks), broadened peaks will be tiny.
187
269
  // Let's normalize such that the highest peak across ALL broadened patterns is 100.
270
+
188
271
  return {
189
- broadened,
190
- entry,
191
- entry_idx,
192
- };
193
- })
194
- .map(({ broadened, entry, entry_idx }, _, all_processed) => {
272
+ broadened,
273
+ entry,
274
+ entry_idx,
275
+ }
276
+ })
277
+ .map(({ broadened, entry, entry_idx }, _, all_processed) => {
195
278
  // Find global max of all broadened patterns to normalize
196
- const all_ys = all_processed.flatMap((p) => p.broadened.y);
197
- const max_y = Math.max(...all_ys, 1); // Avoid div by zero
198
- const scale = (y) => (y / max_y) * 100;
199
- const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length];
279
+ const all_ys = all_processed.flatMap((processed) => processed.broadened.y)
280
+ const max_y = Math.max(...all_ys, 1) // Avoid div by zero
281
+
282
+ const scale = (y: number) => (y / max_y) * 100
283
+ const base_color = entry.color ?? PLOT_COLORS[entry_idx % PLOT_COLORS.length]
200
284
  // Add transparency when multiple series overlap
201
- const alpha = all_processed.length > 1 ? 0.6 : 1;
285
+ const alpha = all_processed.length > 1 ? 0.6 : 1
286
+
202
287
  return {
203
- x: broadened.x,
204
- y: broadened.y.map(scale),
205
- label: include_name ? entry.label : ``,
206
- color: add_alpha(base_color, alpha),
207
- markers: `line`, // Only line for profile
208
- line_style: { stroke_width: 2 },
209
- visible: true,
210
- };
211
- });
212
- });
213
- async function handle_file_drop(event) {
214
- event.preventDefault();
215
- dragover = false;
216
- if (!allow_file_drop)
217
- return;
218
- loading = true;
219
- error_msg = undefined;
220
- const compute_and_add = async (content, filename) => {
221
- const result = await add_xrd_pattern(content, filename, wavelength);
222
- if (result.error) {
223
- error_msg = result.error;
224
- }
225
- else if (result.pattern) {
226
- dropped_entries = [result.pattern, ...dropped_entries];
227
- }
228
- };
288
+ x: broadened.x,
289
+ y: broadened.y.map(scale),
290
+ label: include_name ? entry.label : ``,
291
+ color: add_alpha(base_color, alpha),
292
+ markers: `line`, // Only line for profile
293
+ line_style: { stroke_width: 2 },
294
+ visible: true,
295
+ } as DataSeries
296
+ })
297
+ })
298
+
299
+ async function handle_file_drop(event: DragEvent) {
300
+ event.preventDefault()
301
+ dragover = false
302
+ if (!allow_file_drop) return
303
+ loading = true
304
+ error_msg = undefined
305
+
306
+ const compute_and_add = async (
307
+ content: string | ArrayBuffer,
308
+ filename: string,
309
+ ) => {
310
+ const result = await add_xrd_pattern(content, filename, wavelength)
311
+ if (result.error) {
312
+ error_msg = result.error
313
+ } else if (result.pattern) {
314
+ dropped_entries = [result.pattern, ...dropped_entries]
315
+ }
316
+ }
317
+
229
318
  try {
230
- // Handle URL-based drops
231
- const handled = await handle_url_drop(event, on_file_drop || compute_and_add).catch(() => false);
232
- if (handled)
233
- return;
234
- const file = event.dataTransfer?.files?.[0];
235
- if (file) {
236
- try {
237
- const lower_name = file.name.toLowerCase();
238
- const compression_format = detect_compression_format(lower_name);
239
- // Get base filename without compression extension
240
- const base_name = compression_format
241
- ? lower_name.replace(/\.(gz|gzip)$/i, ``)
242
- : lower_name;
243
- const base_ext = base_name.split(`.`).pop();
244
- // Handle .brml files (ZIP archives) - both plain and gzipped
245
- if (base_ext === `brml`) {
246
- let buffer = await file.arrayBuffer();
247
- // Decompress if gzipped
248
- if (compression_format === `gzip`) {
249
- buffer = await decompress_data_binary(buffer, `gzip`);
250
- }
251
- const output_name = base_name.endsWith(`.brml`)
252
- ? base_name
253
- : file.name.replace(/\.gz$/i, ``);
254
- await (on_file_drop || compute_and_add)(buffer, output_name);
255
- }
256
- else {
257
- // Text-based formats (.xy, .xye, .xrdml) - decompress_file handles .gz
258
- const { content, filename } = await decompress_file(file);
259
- if (content)
260
- await (on_file_drop || compute_and_add)(content, filename);
261
- }
262
- }
263
- catch (exc) {
264
- error_msg = `Failed to load file ${file.name}: ${exc instanceof Error ? exc.message : String(exc)}`;
319
+ // Handle URL-based drops
320
+ const handled = await handle_url_drop(
321
+ event,
322
+ on_file_drop || compute_and_add,
323
+ ).catch(() => false)
324
+ if (handled) return
325
+
326
+ const file = event.dataTransfer?.files?.[0]
327
+ if (file) {
328
+ try {
329
+ const lower_name = file.name.toLowerCase()
330
+ const compression_format = detect_compression_format(lower_name)
331
+ // Get base filename without compression extension
332
+ const base_name = compression_format
333
+ ? lower_name.replace(/\.(gz|gzip)$/i, ``)
334
+ : lower_name
335
+ const base_ext = base_name.split(`.`).pop()
336
+
337
+ // Handle .brml files (ZIP archives) - both plain and gzipped
338
+ if (base_ext === `brml`) {
339
+ let buffer = await file.arrayBuffer()
340
+ // Decompress if gzipped
341
+ if (compression_format === `gzip`) {
342
+ buffer = await decompress_data_binary(buffer, `gzip`)
265
343
  }
344
+ const output_name = base_name.endsWith(`.brml`)
345
+ ? base_name
346
+ : file.name.replace(/\.gz$/i, ``)
347
+ await (on_file_drop || compute_and_add)(buffer, output_name)
348
+ } else {
349
+ // Text-based formats (.xy, .xye, .xrdml) - decompress_file handles .gz
350
+ const { content, filename } = await decompress_file(file)
351
+ if (content) await (on_file_drop || compute_and_add)(content, filename)
352
+ }
353
+ } catch (exc) {
354
+ error_msg = `Failed to load file ${file.name}: ${
355
+ exc instanceof Error ? exc.message : String(exc)
356
+ }`
266
357
  }
358
+ }
359
+ } finally {
360
+ loading = false
267
361
  }
268
- finally {
269
- loading = false;
270
- }
271
- }
272
- const [angle_label, intensity_label] = [`2θ (degrees)`, `Intensity (a.u.)`];
362
+ }
363
+
364
+ const [angle_label, intensity_label] = [`2θ (degrees)`, `Intensity (a.u.)`]
273
365
  </script>
274
366
 
275
367
  {#snippet broadening_controls_snippet()}
@@ -361,7 +453,7 @@ const [angle_label, intensity_label] = [`2θ (degrees)`, `Intensity (a.u.)`];
361
453
  {#snippet tooltip(info: ScatterHandlerProps)}
362
454
  {@const angle_text = `${format_value(info.x, `.2f`)}°`}
363
455
  {@const intensity_text = `${format_value(info.y, `.1f`)}`}
364
- {@html info.label ?? ``}<br />
456
+ {@html sanitize_html(info.label ?? ``)}<br />
365
457
  2θ: {angle_text}<br />
366
458
  Intensity: {intensity_text}
367
459
  {/snippet}
@@ -408,7 +500,7 @@ const [angle_label, intensity_label] = [`2θ (degrees)`, `Intensity (a.u.)`];
408
500
  ? hkls.map((hkl: Hkl) => format_hkl(hkl, hkl_format)).join(`, `)
409
501
  : ``}
410
502
  {@const d_text = d != null ? `${format_value(d, `.3f`)} Å` : ``}
411
- {@html info.metadata?.label ?? ``}<br />
503
+ {@html sanitize_html(info.metadata?.label ?? ``)}<br />
412
504
  2θ: {angle_text}<br />
413
505
  Intensity: {intensity_text}
414
506
  {#if hkl_text}<br />hkl: {hkl_text}{/if}