matterviz 0.4.2 → 0.4.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.
- package/dist/FilePicker.svelte +40 -50
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +15 -0
- package/dist/brillouin/BrillouinZone.svelte +18 -9
- package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
- package/dist/chempot-diagram/async-compute.svelte.js +12 -13
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/composition/BarChart.svelte +7 -9
- package/dist/composition/Composition.svelte +3 -8
- package/dist/composition/Formula.svelte +2 -2
- package/dist/composition/FormulaFilter.svelte +27 -93
- package/dist/composition/format.js +6 -8
- package/dist/composition/parse.js +50 -105
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +6 -17
- package/dist/convex-hull/ConvexHull2D.svelte +0 -2
- package/dist/convex-hull/ConvexHull3D.svelte +19 -47
- package/dist/convex-hull/ConvexHull4D.svelte +65 -95
- package/dist/convex-hull/StructurePopup.svelte +1 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.js +1 -7
- package/dist/convex-hull/thermodynamics.js +19 -27
- package/dist/coordination/CoordinationBarPlot.svelte +12 -21
- package/dist/element/BohrAtom.svelte +0 -1
- package/dist/element/ElementTile.svelte +26 -44
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +5 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -1
- package/dist/fermi-surface/FermiSurface.svelte +22 -23
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
- package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
- package/dist/fermi-surface/compute.js +22 -55
- package/dist/fermi-surface/parse.js +38 -70
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +57 -84
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +1 -1
- package/dist/io/decompress.d.ts +2 -0
- package/dist/io/decompress.js +3 -2
- package/dist/io/export.d.ts +7 -4
- package/dist/io/export.js +70 -18
- package/dist/io/file-drop.js +60 -35
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +28 -16
- package/dist/isosurface/Isosurface.svelte +687 -196
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +564 -85
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.js +1 -1
- package/dist/layout/InfoCard.svelte +1 -3
- package/dist/layout/SettingsSection.svelte +52 -61
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/ViewerChrome.svelte +7 -1
- package/dist/layout/json-tree/JsonNode.svelte +14 -48
- package/dist/layout/json-tree/JsonTree.svelte +48 -95
- package/dist/layout/json-tree/JsonValue.svelte +3 -18
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -179
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +3 -2
- package/dist/math.js +29 -38
- package/dist/overlays/ContextMenu.svelte +15 -32
- package/dist/overlays/DraggablePane.svelte +39 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
- package/dist/overlays/GlassChip.svelte +3 -1
- package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
- package/dist/phase-diagram/build-diagram.js +1 -6
- package/dist/phase-diagram/svg-to-diagram.js +9 -14
- package/dist/plot/bar/BarPlot.svelte +38 -42
- package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
- package/dist/plot/box/BoxPlot.svelte +27 -23
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +1 -1
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +0 -10
- package/dist/plot/core/layout.d.ts +12 -5
- package/dist/plot/core/layout.js +37 -27
- package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/svg.js +0 -1
- package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
- package/dist/plot/core/utils/hierarchy-chart.js +12 -0
- package/dist/plot/core/utils/hierarchy-labels.js +3 -2
- package/dist/plot/histogram/Histogram.svelte +21 -26
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
- package/dist/plot/scatter/ScatterPlot.svelte +67 -52
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/sunburst/Sunburst.svelte +20 -20
- package/dist/plot/treemap/Treemap.svelte +175 -60
- package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
- package/dist/plot/treemap/index.d.ts +1 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +4 -2
- package/dist/plot/treemap/treemap.js +5 -2
- package/dist/rdf/RdfPlot.svelte +17 -35
- package/dist/rdf/calc-rdf.js +59 -44
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +84 -26
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.js +159 -482
- package/dist/spectral/Bands.svelte +151 -158
- package/dist/spectral/BrillouinBandsDos.svelte +4 -19
- package/dist/spectral/Dos.svelte +26 -24
- package/dist/spectral/helpers.js +40 -105
- package/dist/structure/AtomLegend.svelte +8 -13
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/CellSelect.svelte +35 -10
- package/dist/structure/Structure.svelte +177 -99
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureCarousel.svelte +10 -3
- package/dist/structure/StructureControls.svelte +8 -26
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +65 -76
- package/dist/structure/StructureScene.svelte +75 -109
- package/dist/structure/StructureScene.svelte.d.ts +3 -1
- package/dist/structure/StructureViewport.svelte +120 -55
- package/dist/structure/StructureViewport.svelte.d.ts +3 -1
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +4 -3
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +0 -1
- package/dist/structure/bonding.js +16 -23
- package/dist/structure/export.js +50 -74
- package/dist/structure/format-detect.js +5 -7
- package/dist/structure/index.js +6 -12
- package/dist/structure/parse.js +38 -100
- package/dist/structure/partial-occupancy.js +7 -4
- package/dist/structure/pbc.js +8 -10
- package/dist/structure/polyhedra.js +5 -4
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/symmetry/SymmetryStats.svelte +0 -4
- package/dist/symmetry/WyckoffTable.svelte +5 -4
- package/dist/symmetry/cell-transform.js +5 -14
- package/dist/symmetry/index.js +6 -9
- package/dist/table/HeatmapTable.svelte +61 -103
- package/dist/table/ToggleMenu.svelte +166 -44
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +1 -2
- package/dist/theme/themes.mjs +31 -60
- package/dist/tooltip/TooltipContent.svelte +1 -1
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +140 -120
- package/dist/trajectory/TrajectoryError.svelte +1 -66
- package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +19 -29
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +7 -5
- package/dist/trajectory/frame-reader.js +3 -4
- package/dist/trajectory/helpers.js +16 -49
- package/dist/trajectory/index.js +2 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/index.d.ts +4 -3
- package/dist/trajectory/parse/index.js +12 -17
- package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
- package/dist/trajectory/parse/vaspout-h5.js +1 -4
- package/dist/trajectory/parse/xyz.js +48 -2
- package/dist/trajectory/plotting.js +14 -37
- package/dist/xrd/XrdPlot.svelte +43 -68
- package/dist/xrd/calc-xrd.js +22 -58
- package/dist/xrd/parse.js +13 -22
- package/package.json +40 -8
- package/readme.md +6 -5
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
package/dist/FilePicker.svelte
CHANGED
|
@@ -56,12 +56,23 @@
|
|
|
56
56
|
// Timer for distinguishing click from double-click (per-component state)
|
|
57
57
|
let click_timer: ReturnType<typeof setTimeout> | null = null
|
|
58
58
|
let click_timer_file: string | null = null
|
|
59
|
+
const file_key = (file: FileInfo): string => file.url || file.name
|
|
59
60
|
|
|
60
61
|
const clear_click_timer = () => {
|
|
61
|
-
if (click_timer) clearTimeout(click_timer)
|
|
62
|
+
if (click_timer !== null) clearTimeout(click_timer)
|
|
62
63
|
click_timer = null
|
|
63
64
|
click_timer_file = null
|
|
64
65
|
}
|
|
66
|
+
const is_activation_key = (event: KeyboardEvent): boolean =>
|
|
67
|
+
event.key === `Enter` || event.key === ` `
|
|
68
|
+
|
|
69
|
+
const schedule_single_click = (file: FileInfo, event: MouseEvent) => {
|
|
70
|
+
click_timer_file = file_key(file)
|
|
71
|
+
click_timer = setTimeout(() => {
|
|
72
|
+
clear_click_timer()
|
|
73
|
+
on_click?.(file, event)
|
|
74
|
+
}, CLICK_DELAY)
|
|
75
|
+
}
|
|
65
76
|
|
|
66
77
|
// Helper function to get the base file type (removing .gz extension)
|
|
67
78
|
const get_base_file_type = (file: FileInfo): string => {
|
|
@@ -94,38 +105,29 @@
|
|
|
94
105
|
)
|
|
95
106
|
|
|
96
107
|
const toggle_filter = (kind: FilterKind, filter: string) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
} else {
|
|
101
|
-
active_type_filter = active_type_filter === filter ? null : filter
|
|
102
|
-
active_category_filter = null
|
|
103
|
-
}
|
|
108
|
+
const active_filter = kind === `category` ? active_category_filter : active_type_filter
|
|
109
|
+
active_category_filter = kind === `category` && active_filter !== filter ? filter : null
|
|
110
|
+
active_type_filter = kind === `type` && active_filter !== filter ? filter : null
|
|
104
111
|
}
|
|
105
112
|
|
|
106
113
|
const handle_drag_start = (file: FileInfo) => (event: DragEvent) => {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
// Also set plain text as fallback for external applications
|
|
119
|
-
event.dataTransfer?.setData(`text/plain`, file_url)
|
|
120
|
-
|
|
114
|
+
const url = file_key(file)
|
|
115
|
+
event.dataTransfer?.setData(
|
|
116
|
+
`application/json`,
|
|
117
|
+
JSON.stringify({
|
|
118
|
+
name: file.name,
|
|
119
|
+
url,
|
|
120
|
+
type: file.type || get_base_file_type(file),
|
|
121
|
+
category: file.category,
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
event.dataTransfer?.setData(`text/plain`, url)
|
|
121
125
|
on_drag_start?.(file, event)
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
// Get unique file types/categories for format/category filters
|
|
125
129
|
let uniq_formats = $derived([...new Set(files.map(get_base_file_type))].sort())
|
|
126
|
-
let uniq_categories = $derived(
|
|
127
|
-
[...new Set(files.map(get_category_id))].filter(Boolean).sort(),
|
|
128
|
-
)
|
|
130
|
+
let uniq_categories = $derived([...new Set(files.map(get_category_id))].sort())
|
|
129
131
|
</script>
|
|
130
132
|
|
|
131
133
|
<div class="file-picker" class:vertical={layout === `vertical`} {...rest}>
|
|
@@ -135,11 +137,8 @@
|
|
|
135
137
|
<span
|
|
136
138
|
class="legend-item"
|
|
137
139
|
class:active={is_active}
|
|
138
|
-
onclick={() =>
|
|
139
|
-
onkeydown={(
|
|
140
|
-
(evt.key === `Enter` || evt.key === ` `) &&
|
|
141
|
-
category &&
|
|
142
|
-
toggle_filter(`category`, category)}
|
|
140
|
+
onclick={() => toggle_filter(`category`, category)}
|
|
141
|
+
onkeydown={(event) => is_activation_key(event) && toggle_filter(`category`, category)}
|
|
143
142
|
role="button"
|
|
144
143
|
tabindex="0"
|
|
145
144
|
aria-pressed={is_active}
|
|
@@ -158,8 +157,7 @@
|
|
|
158
157
|
class="legend-item format-item"
|
|
159
158
|
class:active={is_active}
|
|
160
159
|
onclick={() => toggle_filter(`type`, format)}
|
|
161
|
-
onkeydown={(
|
|
162
|
-
(evt.key === `Enter` || evt.key === ` `) && toggle_filter(`type`, format)}
|
|
160
|
+
onkeydown={(event) => is_activation_key(event) && toggle_filter(`type`, format)}
|
|
163
161
|
role="button"
|
|
164
162
|
tabindex="0"
|
|
165
163
|
{@attach tooltip({ content: `Filter to show only ${format.toUpperCase()} files` })}
|
|
@@ -191,26 +189,17 @@
|
|
|
191
189
|
ondragend={() => on_drag_end?.()}
|
|
192
190
|
onclick={(event) => {
|
|
193
191
|
clear_click_timer()
|
|
194
|
-
if (on_dblclick)
|
|
195
|
-
|
|
196
|
-
const target_file = file.name
|
|
197
|
-
click_timer_file = target_file
|
|
198
|
-
click_timer = setTimeout(() => {
|
|
199
|
-
if (click_timer_file === target_file) {
|
|
200
|
-
clear_click_timer()
|
|
201
|
-
on_click?.(file, event)
|
|
202
|
-
}
|
|
203
|
-
}, CLICK_DELAY)
|
|
204
|
-
} else {
|
|
205
|
-
on_click?.(file, event)
|
|
206
|
-
}
|
|
192
|
+
if (on_dblclick) schedule_single_click(file, event)
|
|
193
|
+
else on_click?.(file, event)
|
|
207
194
|
}}
|
|
208
195
|
ondblclick={(event) => {
|
|
196
|
+
const pending = click_timer_file
|
|
209
197
|
clear_click_timer()
|
|
210
|
-
on_dblclick?.(file, event)
|
|
198
|
+
if (pending !== null && pending === file_key(file)) on_dblclick?.(file, event)
|
|
199
|
+
else schedule_single_click(file, event)
|
|
211
200
|
}}
|
|
212
201
|
onkeydown={(event) => {
|
|
213
|
-
if (
|
|
202
|
+
if (is_activation_key(event)) {
|
|
214
203
|
event.preventDefault()
|
|
215
204
|
clear_click_timer()
|
|
216
205
|
on_click?.(file, event)
|
|
@@ -230,7 +219,8 @@
|
|
|
230
219
|
>
|
|
231
220
|
{/if}
|
|
232
221
|
<div class="file-name">
|
|
233
|
-
{file.category ? `${file.category_icon} ` : ``}{file.label ??
|
|
222
|
+
{file.category && file.category_icon ? `${file.category_icon} ` : ``}{file.label ??
|
|
223
|
+
file.name}
|
|
234
224
|
</div>
|
|
235
225
|
</div>
|
|
236
226
|
{/each}
|
|
@@ -316,9 +306,9 @@
|
|
|
316
306
|
.file-item {
|
|
317
307
|
display: flex;
|
|
318
308
|
align-items: center;
|
|
319
|
-
padding:
|
|
309
|
+
padding: 2pt 8pt;
|
|
320
310
|
border: 1px solid light-dark(rgba(0, 0, 0, 0.15), rgba(255, 255, 255, 0.2));
|
|
321
|
-
border-radius:
|
|
311
|
+
border-radius: 9px;
|
|
322
312
|
cursor: grab;
|
|
323
313
|
background: light-dark(rgba(0, 0, 0, 0.02), rgba(255, 255, 255, 0.1));
|
|
324
314
|
transition: all 0.2s ease;
|
package/dist/api/optimade.js
CHANGED
|
@@ -110,12 +110,16 @@ export function detect_provider_from_slug(slug, providers) {
|
|
|
110
110
|
const prefix = decoded_slug.split(`-`)[0].toLowerCase();
|
|
111
111
|
return providers.find((provider) => provider.id === prefix)?.id ?? ``;
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
// Resolve a provider id to its versioned API base URL (throws on unknown provider)
|
|
114
|
+
async function get_api_base(provider, providers) {
|
|
114
115
|
const provider_config = providers.find((entry) => entry.id === provider);
|
|
115
116
|
if (!provider_config)
|
|
116
117
|
throw new Error(`Unknown provider: ${provider}`);
|
|
117
118
|
const base_url = await resolve_provider_url(provider_config.attributes.base_url);
|
|
118
|
-
|
|
119
|
+
return base_url.endsWith(`/v1`) ? base_url : `${base_url}/v1`;
|
|
120
|
+
}
|
|
121
|
+
export async function fetch_optimade_structure(structure_id, provider, providers) {
|
|
122
|
+
const api_base = await get_api_base(provider, providers);
|
|
119
123
|
const encoded_id = encode_structure_id(structure_id);
|
|
120
124
|
const response = await fetch_with_cors_proxy(`${api_base}/structures/${encoded_id}`);
|
|
121
125
|
const data = await response.json();
|
|
@@ -124,12 +128,11 @@ export async function fetch_optimade_structure(structure_id, provider, providers
|
|
|
124
128
|
return Array.isArray(data.data) ? data.data[0] : data.data;
|
|
125
129
|
}
|
|
126
130
|
export async function fetch_suggested_structures(provider, providers, limit = 12) {
|
|
127
|
-
const provider_config = providers.find((entry) => entry.id === provider);
|
|
128
|
-
if (!provider_config)
|
|
129
|
-
throw new Error(`Unknown provider: ${provider}`);
|
|
130
131
|
try {
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
// Keep get_api_base inside try: suggestions are optional, so unknown providers and
|
|
133
|
+
// URL-resolution failures both soft-fail to []. Note: unknown provider threw
|
|
134
|
+
// pre-cleanup, which left the sole caller's loading state stuck on rejection.
|
|
135
|
+
const api_base = await get_api_base(provider, providers);
|
|
133
136
|
const response = await fetch_with_cors_proxy(`${api_base}/structures?page_limit=${limit}&page_offset=0`);
|
|
134
137
|
const data = await response.json();
|
|
135
138
|
return Array.isArray(data.data) ? data.data : [];
|
package/dist/app.css
CHANGED
|
@@ -25,6 +25,21 @@
|
|
|
25
25
|
Override per viewer by setting this on its wrapper. */
|
|
26
26
|
--ctrl-btn-icon-size: clamp(0.7rem, 2cqmin, 0.85rem);
|
|
27
27
|
|
|
28
|
+
/* In-viewer overlay stack (inside one viewer container, above its WebGL
|
|
29
|
+
canvas): 1 viewport labels · 2 glass chips · 4–6 carousel chrome
|
|
30
|
+
(legend/resize-handle/pager) · 10 draggable panes · 100 dropdowns +
|
|
31
|
+
toasts · 1000 canvas tooltips + error banners. Components fall back to
|
|
32
|
+
these tiers; override per instance via their dedicated --*-z-index vars.
|
|
33
|
+
NOTE (WKWebView/Tauri): overlays that can overlap a WebGL canvas also
|
|
34
|
+
need their own compositing layer (will-change: transform) — after hiding
|
|
35
|
+
and re-showing the window, WebKit reattaches canvas layers above
|
|
36
|
+
non-composited overlays regardless of z-index. */
|
|
37
|
+
--z-index-viewer-label: 1;
|
|
38
|
+
--z-index-viewer-chip: 2;
|
|
39
|
+
--z-index-viewer-pane: 10;
|
|
40
|
+
--z-index-viewer-dropdown: 100;
|
|
41
|
+
--z-index-viewer-tooltip: 1000;
|
|
42
|
+
|
|
28
43
|
/* App-wide overlay stack: controls < fullscreen/nav < dialogs < floating options.
|
|
29
44
|
These must exceed Threlte HTML overlays, which use very high z-index values. */
|
|
30
45
|
--z-index-overlay-controls: 100000000;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import EmptyState from '../EmptyState.svelte'
|
|
4
4
|
import { StatusMessage } from '../feedback'
|
|
5
5
|
import Spinner from '../feedback/Spinner.svelte'
|
|
6
|
-
import
|
|
6
|
+
import * as io from '../io'
|
|
7
7
|
import { type FullscreenToggleProp, toggle_fullscreen, ViewerChrome } from '../layout'
|
|
8
8
|
import { sync_fullscreen } from '../layout/fullscreen.svelte'
|
|
9
9
|
import type { Vec3 } from '../math'
|
|
@@ -248,20 +248,29 @@
|
|
|
248
248
|
})
|
|
249
249
|
|
|
250
250
|
// Load structure from URL or string
|
|
251
|
+
let data_url_load_id = 0
|
|
251
252
|
$effect(() => {
|
|
252
253
|
const handle_error = (err: unknown, source: string) => {
|
|
253
254
|
error_msg = to_error(err).message
|
|
254
255
|
on_error?.({ error_msg, filename: source })
|
|
255
256
|
}
|
|
256
257
|
|
|
257
|
-
|
|
258
|
+
const requested_url = data_url
|
|
259
|
+
if (requested_url && !structure) {
|
|
260
|
+
const load_id = ++data_url_load_id
|
|
258
261
|
loading = true
|
|
259
262
|
error_msg = undefined
|
|
260
|
-
load_from_url(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
.
|
|
263
|
+
io.load_from_url(requested_url, (content, filename) => {
|
|
264
|
+
if (load_id !== data_url_load_id) return
|
|
265
|
+
return on_file_drop ? on_file_drop(content, filename) : safe_parse(content, filename)
|
|
266
|
+
})
|
|
267
|
+
.catch((err) => {
|
|
268
|
+
if (load_id !== data_url_load_id) return
|
|
269
|
+
handle_error(err, io.basename_from_url(requested_url))
|
|
270
|
+
})
|
|
271
|
+
.finally(() => {
|
|
272
|
+
if (load_id === data_url_load_id) loading = false
|
|
273
|
+
})
|
|
265
274
|
} else if (structure_string && !data_url) {
|
|
266
275
|
loading = true
|
|
267
276
|
error_msg = undefined
|
|
@@ -275,7 +284,7 @@
|
|
|
275
284
|
}
|
|
276
285
|
})
|
|
277
286
|
|
|
278
|
-
const handle_file_drop = create_file_drop_handler({
|
|
287
|
+
const handle_file_drop = io.create_file_drop_handler({
|
|
279
288
|
allow: () => allow_file_drop,
|
|
280
289
|
on_drop: (content, filename) => (on_file_drop || safe_parse)(content, filename),
|
|
281
290
|
on_error: (msg) => {
|
|
@@ -325,7 +334,7 @@
|
|
|
325
334
|
onmouseenter={() => (hovered = true)}
|
|
326
335
|
onmouseleave={() => (hovered = false)}
|
|
327
336
|
ondrop={handle_file_drop}
|
|
328
|
-
{...drag_over_handlers({
|
|
337
|
+
{...io.drag_over_handlers({
|
|
329
338
|
allow: () => allow_file_drop,
|
|
330
339
|
set_dragover: (over) => (dragover = over),
|
|
331
340
|
})}
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
auto_rotate = DEFAULTS.structure.auto_rotate,
|
|
49
49
|
scene = $bindable(),
|
|
50
50
|
camera = $bindable(),
|
|
51
|
-
k_path_points = [],
|
|
51
|
+
k_path_points: input_k_path_points = [],
|
|
52
52
|
k_path_labels = [],
|
|
53
53
|
hovered_k_point = null,
|
|
54
54
|
hovered_qpoint_index = null,
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
hover_data?: BZHoverData | null
|
|
76
76
|
on_kpath_hover?: (qpoint_index: number | null) => void
|
|
77
77
|
} = $props()
|
|
78
|
+
const k_path_points = $derived(input_k_path_points ?? [])
|
|
78
79
|
|
|
79
80
|
bind_renderer((threlte_scene, threlte_camera) => {
|
|
80
81
|
scene = threlte_scene
|
|
@@ -114,7 +115,7 @@
|
|
|
114
115
|
// Band paths are densely sampled, so legit segments are tiny; a discontinuity jumps by
|
|
115
116
|
// a fraction of the zone. Skip segments far longer than the median sampling step.
|
|
116
117
|
const k_path_seg_cutoff = $derived.by(() => {
|
|
117
|
-
if (
|
|
118
|
+
if (k_path_points.length < 3) return Infinity
|
|
118
119
|
const lens = k_path_points
|
|
119
120
|
.slice(1)
|
|
120
121
|
.map((pt, idx) => Math.hypot(...math.subtract(pt as Vec3, k_path_points[idx] as Vec3)))
|
|
@@ -290,7 +291,7 @@
|
|
|
290
291
|
{/if}
|
|
291
292
|
|
|
292
293
|
<!-- K-path visualization -->
|
|
293
|
-
{#if k_path_points
|
|
294
|
+
{#if k_path_points.length > 1}
|
|
294
295
|
{#each k_path_points.slice(0, -1) as from_point, idx (`${from_point}-${k_path_points[idx + 1]}#${idx}`)}
|
|
295
296
|
{@const to_point = k_path_points[idx + 1]}
|
|
296
297
|
{@const seg_len = Math.hypot(...math.subtract(to_point as Vec3, from_point as Vec3))}
|
|
@@ -317,32 +318,22 @@
|
|
|
317
318
|
{/each}
|
|
318
319
|
{/if}
|
|
319
320
|
|
|
320
|
-
<!-- Symmetry point spheres at labeled k-path points -->
|
|
321
|
-
{#
|
|
322
|
-
{#
|
|
323
|
-
{
|
|
324
|
-
<T.
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
{
|
|
335
|
-
|
|
336
|
-
<extras.HTML center position={position.map((coord) => coord * 1.1) as Vec3}>
|
|
337
|
-
<span
|
|
338
|
-
style="background: rgba(0, 0, 0, 0.3); padding: 0 3px; border-radius: 2px; color: white"
|
|
339
|
-
>
|
|
340
|
-
{label}
|
|
341
|
-
</span>
|
|
342
|
-
</extras.HTML>
|
|
343
|
-
{/if}
|
|
344
|
-
{/each}
|
|
345
|
-
{/if}
|
|
321
|
+
<!-- Symmetry point spheres + labels at labeled k-path points -->
|
|
322
|
+
{#each k_path_labels as { position, label }, idx (`${label}-${idx}`)}
|
|
323
|
+
{#if label}
|
|
324
|
+
<T.Mesh position={[position[0], position[1], position[2]]}>
|
|
325
|
+
<T.SphereGeometry args={[0.015, 16, 16]} />
|
|
326
|
+
<T.MeshStandardMaterial color="#ffcc00" metalness={0.3} roughness={0.7} />
|
|
327
|
+
</T.Mesh>
|
|
328
|
+
<extras.HTML center position={position.map((coord) => coord * 1.1) as Vec3}>
|
|
329
|
+
<span
|
|
330
|
+
style="background: rgba(0, 0, 0, 0.3); padding: 0 3px; border-radius: 2px; color: white"
|
|
331
|
+
>
|
|
332
|
+
{label}
|
|
333
|
+
</span>
|
|
334
|
+
</extras.HTML>
|
|
335
|
+
{/if}
|
|
336
|
+
{/each}
|
|
346
337
|
|
|
347
338
|
<!-- Hovered k-point highlight -->
|
|
348
339
|
{#if hovered_k_point}
|
|
@@ -3,8 +3,6 @@ import * as math from '../math';
|
|
|
3
3
|
import { Vector3 } from 'three';
|
|
4
4
|
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js';
|
|
5
5
|
const TOL = 1e-8;
|
|
6
|
-
// Check if rotation matrix is identity
|
|
7
|
-
const is_identity_rotation = (rot) => rot.every((row, idx) => row.every((val, jdx) => Math.abs(val - (idx === jdx ? 1 : 0)) < TOL));
|
|
8
6
|
// Extract unique point group rotation matrices from space group operations.
|
|
9
7
|
// Returns fractional-coordinate rotations (W matrices from spglib convention).
|
|
10
8
|
// These must be converted to Cartesian k-space before use in clipping.
|
|
@@ -111,12 +109,11 @@ export function generate_bz_vertices(k_lattice, order = 1,
|
|
|
111
109
|
// Higher values give more accurate zones but increase computation time significantly.
|
|
112
110
|
// Default values: 26 (1st order), 80 (2nd order), 150 (3rd+ order)
|
|
113
111
|
max_planes_by_order = { 1: 26, 2: 80, 3: 150 }) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const k_points = generate_k_space_grid(k_lattice, order);
|
|
112
|
+
const clamped_order = Math.min(order, 3);
|
|
113
|
+
const k_points = generate_k_space_grid(k_lattice, clamped_order);
|
|
117
114
|
const center_idx = Math.floor(k_points.length / 2);
|
|
118
|
-
//
|
|
119
|
-
const max_planes = max_planes_by_order[
|
|
115
|
+
// Fallback for partial records passed through compute_brillouin_zone
|
|
116
|
+
const max_planes = max_planes_by_order[clamped_order] ?? 150;
|
|
120
117
|
// Create Bragg planes (perpendicular bisectors of k-points)
|
|
121
118
|
const planes = k_points
|
|
122
119
|
.map((pt, idx) => {
|
|
@@ -152,12 +149,12 @@ max_planes_by_order = { 1: 26, 2: 80, 3: 150 }) {
|
|
|
152
149
|
vertex[2] * normals[p_idx][2];
|
|
153
150
|
if (dot > distances[p_idx] + TOL) {
|
|
154
151
|
beyond_count++;
|
|
155
|
-
if (beyond_count >=
|
|
152
|
+
if (beyond_count >= clamped_order)
|
|
156
153
|
break;
|
|
157
154
|
}
|
|
158
155
|
}
|
|
159
156
|
// Vertex belongs to nth BZ if it's beyond fewer than n planes
|
|
160
|
-
if (beyond_count <
|
|
157
|
+
if (beyond_count < clamped_order && !dedup.has_duplicate(vertex)) {
|
|
161
158
|
vertices.push(vertex);
|
|
162
159
|
dedup.add(vertex);
|
|
163
160
|
}
|
|
@@ -166,13 +163,10 @@ max_planes_by_order = { 1: 26, 2: 80, 3: 150 }) {
|
|
|
166
163
|
}
|
|
167
164
|
return vertices;
|
|
168
165
|
}
|
|
169
|
-
// Compute polyhedron volume via divergence theorem (sum of signed tetrahedral volumes)
|
|
166
|
+
// Compute polyhedron volume via divergence theorem (sum of signed tetrahedral volumes).
|
|
167
|
+
// Faces always come from compute_convex_hull, so each is a valid triangle.
|
|
170
168
|
function compute_hull_volume(vertices, faces) {
|
|
171
|
-
if (faces.length === 0)
|
|
172
|
-
return 0;
|
|
173
169
|
return Math.abs(faces.reduce((sum, face) => {
|
|
174
|
-
if (face.length < 3)
|
|
175
|
-
return sum;
|
|
176
170
|
const [v0, v1, v2] = face.slice(0, 3).map((idx) => vertices[idx]);
|
|
177
171
|
const area_normal = math.scale(math.cross_3d(math.subtract(v1, v0), math.subtract(v2, v0)), 0.5);
|
|
178
172
|
return sum + math.dot(v0, area_normal) / 3;
|
|
@@ -255,7 +249,7 @@ max_planes_by_order = { 1: 26, 2: 80, 3: 150 }) {
|
|
|
255
249
|
}
|
|
256
250
|
const hull = compute_convex_hull(vertices, edge_sharp_angle_deg);
|
|
257
251
|
return {
|
|
258
|
-
order,
|
|
252
|
+
order: Math.min(order, 3),
|
|
259
253
|
vertices: hull.vertices,
|
|
260
254
|
faces: hull.faces,
|
|
261
255
|
edges: hull.edges.map(([i1, i2]) => [hull.vertices[i1], hull.vertices[i2]]),
|
|
@@ -305,7 +299,7 @@ export function find_ibz_reference_direction(non_identity_ops) {
|
|
|
305
299
|
// of exactly volume(BZ)/|G|. (Using a different reference point per operation — or
|
|
306
300
|
// flipping individual planes — does NOT yield a fundamental domain in general.)
|
|
307
301
|
export function compute_ibz_clipping_planes(point_group_ops) {
|
|
308
|
-
const non_identity_ops = point_group_ops.filter((rot) => !
|
|
302
|
+
const non_identity_ops = point_group_ops.filter((rot) => !rot.every((row, idx) => row.every((val, jdx) => Math.abs(val - (idx === jdx ? 1 : 0)) < TOL)));
|
|
309
303
|
if (non_identity_ops.length === 0)
|
|
310
304
|
return [];
|
|
311
305
|
const ref_dir = find_ibz_reference_direction(non_identity_ops);
|
|
@@ -32,12 +32,12 @@ export function polyhedron_geometry(vertices, faces) {
|
|
|
32
32
|
geometry.computeBoundingSphere();
|
|
33
33
|
return geometry;
|
|
34
34
|
}
|
|
35
|
-
//
|
|
35
|
+
// Cartesian → fractional via transposed row-vector inverse; null if missing/singular
|
|
36
36
|
export function k_lattice_inverse(k_lattice) {
|
|
37
37
|
if (!k_lattice)
|
|
38
38
|
return null;
|
|
39
39
|
try {
|
|
40
|
-
return math.
|
|
40
|
+
return math.create_cart_to_frac_matrix(k_lattice);
|
|
41
41
|
}
|
|
42
42
|
catch {
|
|
43
43
|
return null;
|
|
@@ -9,7 +9,12 @@
|
|
|
9
9
|
import ChemPotDiagram2D from './ChemPotDiagram2D.svelte'
|
|
10
10
|
import ChemPotDiagram3D from './ChemPotDiagram3D.svelte'
|
|
11
11
|
import { get_ternary_combinations } from './compute'
|
|
12
|
-
import type {
|
|
12
|
+
import type {
|
|
13
|
+
AxisRangeData,
|
|
14
|
+
ChemPotDiagramConfig,
|
|
15
|
+
ChemPotHoverInfo,
|
|
16
|
+
ChemPotHoverInfo3D,
|
|
17
|
+
} from './types'
|
|
13
18
|
import { CHEMPOT_DEFAULTS } from './types'
|
|
14
19
|
import { to_error } from '../utils'
|
|
15
20
|
|
|
@@ -106,6 +111,16 @@
|
|
|
106
111
|
})
|
|
107
112
|
</script>
|
|
108
113
|
|
|
114
|
+
{#snippet axis_ranges_section(ranges: AxisRangeData[])}
|
|
115
|
+
<h5 id="axis-ranges">Axis ranges</h5>
|
|
116
|
+
{#each ranges as axis_range (axis_range.element)}
|
|
117
|
+
<p>
|
|
118
|
+
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
119
|
+
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
120
|
+
</p>
|
|
121
|
+
{/each}
|
|
122
|
+
{/snippet}
|
|
123
|
+
|
|
109
124
|
<div class="chempot-diagram-wrapper">
|
|
110
125
|
{#if n_display < 2}
|
|
111
126
|
<div
|
|
@@ -191,13 +206,7 @@
|
|
|
191
206
|
{#if hover_info.view === `2d`}
|
|
192
207
|
<p>2D domain · Points: {hover_info.n_points}</p>
|
|
193
208
|
{#if tooltip_detail_level === `detailed`}
|
|
194
|
-
|
|
195
|
-
{#each hover_info.axis_ranges as axis_range (axis_range.element)}
|
|
196
|
-
<p>
|
|
197
|
-
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
198
|
-
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
199
|
-
</p>
|
|
200
|
-
{/each}
|
|
209
|
+
{@render axis_ranges_section(hover_info.axis_ranges)}
|
|
201
210
|
{/if}
|
|
202
211
|
{:else if is_hover_info_3d(hover_info)}
|
|
203
212
|
<p>
|
|
@@ -218,13 +227,7 @@
|
|
|
218
227
|
{/if}
|
|
219
228
|
</p>
|
|
220
229
|
{#if tooltip_detail_level === `detailed`}
|
|
221
|
-
|
|
222
|
-
{#each hover_info.axis_ranges as axis_range (axis_range.element)}
|
|
223
|
-
<p>
|
|
224
|
-
{axis_range.element}: {format_num(axis_range.min_val, `.4~g`)} to
|
|
225
|
-
{format_num(axis_range.max_val, `.4~g`)} eV
|
|
226
|
-
</p>
|
|
227
|
-
{/each}
|
|
230
|
+
{@render axis_ranges_section(hover_info.axis_ranges)}
|
|
228
231
|
<p>
|
|
229
232
|
Centroid: ({hover_info.ann_loc
|
|
230
233
|
.map((value) => format_num(value, `.3~g`))
|