matterviz 0.3.1 → 0.3.2
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 +37 -20
- package/dist/Icon.svelte +2 -2
- package/dist/app.css +29 -0
- package/dist/brillouin/BrillouinZone.svelte +19 -61
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
- package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +33 -0
- package/dist/chempot-diagram/compute.d.ts +38 -0
- package/dist/chempot-diagram/compute.js +650 -0
- package/dist/chempot-diagram/index.d.ts +5 -0
- package/dist/chempot-diagram/index.js +5 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +37 -0
- package/dist/chempot-diagram/types.d.ts +83 -0
- package/dist/chempot-diagram/types.js +27 -0
- package/dist/colors/index.d.ts +3 -1
- package/dist/colors/index.js +4 -0
- package/dist/composition/BarChart.svelte +13 -22
- package/dist/composition/BubbleChart.svelte +5 -3
- package/dist/composition/FormulaFilter.svelte +586 -94
- package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
- package/dist/composition/PieChart.svelte +43 -18
- package/dist/composition/PieChart.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull.svelte +4 -2
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +13 -44
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +16 -7
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +17 -7
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullStats.svelte +701 -226
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +36 -0
- package/dist/convex-hull/helpers.d.ts +1 -1
- package/dist/convex-hull/helpers.js +2 -4
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +8 -21
- package/dist/convex-hull/thermodynamics.js +106 -17
- package/dist/convex-hull/types.d.ts +5 -0
- package/dist/convex-hull/types.js +5 -0
- package/dist/coordination/CoordinationBarPlot.svelte +29 -46
- package/dist/element/BohrAtom.svelte +1 -1
- package/dist/element/data.js +2 -14
- package/dist/element/data.json.gz +0 -0
- package/dist/element/types.d.ts +1 -0
- package/dist/fermi-surface/FermiSurface.svelte +20 -64
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/parse.js +16 -22
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +111 -0
- package/dist/icons.js +111 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/io/export.js +15 -3
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +2 -2
- package/dist/io/index.js +2 -112
- package/dist/io/types.d.ts +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +118 -0
- package/dist/isosurface/Isosurface.svelte +101 -45
- package/dist/isosurface/IsosurfaceControls.svelte +19 -0
- package/dist/isosurface/parse.js +73 -30
- package/dist/isosurface/slice.d.ts +2 -1
- package/dist/isosurface/slice.js +3 -3
- package/dist/isosurface/types.d.ts +13 -1
- package/dist/isosurface/types.js +98 -0
- package/dist/labels.d.ts +2 -1
- package/dist/labels.js +1 -0
- package/dist/layout/InfoTag.svelte +62 -62
- package/dist/layout/SubpageGrid.svelte +74 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +83 -85
- package/dist/layout/json-tree/JsonTree.svelte +20 -19
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
- package/dist/layout/json-tree/JsonValue.svelte +196 -116
- package/dist/layout/json-tree/types.d.ts +10 -2
- package/dist/layout/json-tree/utils.d.ts +2 -0
- package/dist/layout/json-tree/utils.js +33 -0
- package/dist/math.d.ts +7 -0
- package/dist/math.js +358 -7
- package/dist/overlays/ContextMenu.svelte +3 -2
- package/dist/overlays/DraggablePane.svelte +163 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
- package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
- package/dist/phase-diagram/index.d.ts +2 -0
- package/dist/phase-diagram/index.js +2 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +865 -0
- package/dist/phase-diagram/types.d.ts +10 -0
- package/dist/phase-diagram/utils.d.ts +7 -4
- package/dist/phase-diagram/utils.js +149 -59
- package/dist/plot/AxisLabel.svelte +26 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +473 -228
- package/dist/plot/BarPlot.svelte.d.ts +3 -3
- package/dist/plot/BarPlotControls.svelte +3 -2
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +54 -54
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/ColorScaleSelect.svelte +1 -1
- package/dist/plot/ElementScatter.svelte +3 -2
- package/dist/plot/FillArea.svelte +4 -1
- package/dist/plot/Histogram.svelte +320 -230
- package/dist/plot/Histogram.svelte.d.ts +2 -2
- package/dist/plot/HistogramControls.svelte +29 -10
- package/dist/plot/HistogramControls.svelte.d.ts +6 -2
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
- package/dist/plot/PlotControls.svelte +109 -27
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +1 -1
- package/dist/plot/PortalSelect.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte +2 -1
- package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
- package/dist/plot/ReferencePlane.svelte +1 -3
- package/dist/plot/ScatterPlot.svelte +343 -209
- package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +203 -250
- package/dist/plot/ScatterPlot3DScene.svelte +4 -7
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +95 -55
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ZeroLines.svelte +44 -0
- package/dist/plot/ZeroLines.svelte.d.ts +32 -0
- package/dist/plot/ZoomRect.svelte +21 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/axis-utils.d.ts +1 -1
- package/dist/plot/index.d.ts +6 -2
- package/dist/plot/index.js +6 -2
- package/dist/plot/interactions.d.ts +8 -10
- package/dist/plot/interactions.js +2 -3
- package/dist/plot/layout.d.ts +7 -1
- package/dist/plot/layout.js +12 -4
- package/dist/plot/reference-line.d.ts +4 -21
- package/dist/plot/reference-line.js +7 -81
- package/dist/plot/types.d.ts +42 -17
- package/dist/plot/types.js +10 -0
- package/dist/plot/utils/label-placement.js +13 -10
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +55 -66
- package/dist/settings.d.ts +3 -0
- package/dist/settings.js +17 -3
- package/dist/spectral/Bands.svelte +515 -143
- package/dist/spectral/Bands.svelte.d.ts +22 -2
- package/dist/spectral/helpers.d.ts +23 -1
- package/dist/spectral/helpers.js +65 -9
- package/dist/spectral/types.d.ts +2 -0
- package/dist/structure/AtomLegend.svelte +29 -8
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +92 -22
- package/dist/structure/Structure.svelte +108 -118
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureControls.svelte +25 -22
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +7 -1
- package/dist/structure/StructureScene.svelte +104 -66
- package/dist/structure/StructureScene.svelte.d.ts +2 -1
- package/dist/structure/atom-properties.d.ts +6 -2
- package/dist/structure/atom-properties.js +38 -25
- package/dist/structure/export.js +10 -7
- package/dist/structure/ferrox-wasm-types.d.ts +3 -2
- package/dist/structure/ferrox-wasm-types.js +0 -3
- package/dist/structure/ferrox-wasm.d.ts +3 -2
- package/dist/structure/ferrox-wasm.js +1 -2
- package/dist/structure/index.d.ts +6 -0
- package/dist/structure/index.js +22 -0
- package/dist/structure/parse.js +19 -16
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +102 -0
- package/dist/structure/validation.js +6 -3
- package/dist/symmetry/SymmetryStats.svelte +18 -4
- package/dist/symmetry/WyckoffTable.svelte +18 -10
- package/dist/symmetry/index.d.ts +7 -4
- package/dist/symmetry/index.js +83 -18
- package/dist/table/HeatmapTable.svelte +425 -65
- package/dist/table/HeatmapTable.svelte.d.ts +12 -1
- package/dist/table/ToggleMenu.svelte +2 -0
- package/dist/table/index.d.ts +2 -0
- package/dist/trajectory/Trajectory.svelte +147 -145
- package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.js +3 -5
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +339 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +187 -0
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +11 -4
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +76 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +121 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +304 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +169 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +65 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +109 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +4 -0
- package/dist/xrd/XrdPlot.svelte +6 -4
- package/dist/xrd/calc-xrd.js +0 -1
- package/package.json +30 -24
- package/readme.md +4 -4
- package/dist/trajectory/parse.d.ts +0 -42
- package/dist/trajectory/parse.js +0 -1267
- /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script lang="ts">import { ELEMENT_COLOR_SCHEMES } from '../colors';
|
|
2
2
|
import { normalize_show_controls } from '../controls';
|
|
3
|
+
import { StatusMessage } from '../feedback';
|
|
3
4
|
import Spinner from '../feedback/Spinner.svelte';
|
|
4
5
|
import Icon from '../Icon.svelte';
|
|
5
|
-
import {
|
|
6
|
+
import { create_file_drop_handler, load_from_url } from '../io';
|
|
6
7
|
import { parse_volumetric_file } from '../isosurface/parse';
|
|
7
8
|
import { auto_isosurface_settings, DEFAULT_ISOSURFACE_SETTINGS, } from '../isosurface/types';
|
|
8
9
|
import { ELEM_SYMBOLS } from '../labels';
|
|
@@ -10,7 +11,7 @@ import { set_fullscreen_bg, toggle_fullscreen } from '../layout';
|
|
|
10
11
|
import { create_cart_to_frac, create_frac_to_cart } from '../math';
|
|
11
12
|
import { DEFAULTS } from '../settings';
|
|
12
13
|
import { colors } from '../state.svelte';
|
|
13
|
-
import { get_element_counts, get_pbc_image_sites } from './';
|
|
14
|
+
import { get_element_counts, get_pbc_image_sites, get_site_vector, } from './';
|
|
14
15
|
import { wrap_to_unit_cell } from './pbc';
|
|
15
16
|
import { is_valid_supercell_input, make_supercell } from './supercell';
|
|
16
17
|
import * as symmetry from '../symmetry';
|
|
@@ -141,17 +142,18 @@ $effect(() => {
|
|
|
141
142
|
});
|
|
142
143
|
// Track if force vectors were auto-enabled to prevent repeated triggering
|
|
143
144
|
let force_vectors_auto_enabled = $state(false);
|
|
144
|
-
// Auto-enable force vectors when structure has force
|
|
145
|
+
// Auto-enable force vectors when structure has vector data (force, magmom, or spin)
|
|
145
146
|
$effect(() => {
|
|
146
147
|
if (structure?.sites && !force_vectors_auto_enabled) {
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
const has_vector_data = structure.sites.some((site) => get_site_vector(site) !== null);
|
|
149
|
+
if (!has_vector_data)
|
|
150
|
+
return;
|
|
151
|
+
if (!scene_props.show_force_vectors) {
|
|
150
152
|
scene_props.show_force_vectors = true;
|
|
151
153
|
scene_props.force_scale ??= DEFAULTS.structure.force_scale;
|
|
152
154
|
scene_props.force_color ??= DEFAULTS.structure.force_color;
|
|
153
|
-
force_vectors_auto_enabled = true;
|
|
154
155
|
}
|
|
156
|
+
force_vectors_auto_enabled = true;
|
|
155
157
|
}
|
|
156
158
|
});
|
|
157
159
|
// Optimize scene props for performance based on structure size and mode
|
|
@@ -172,6 +174,7 @@ $effect(() => {
|
|
|
172
174
|
let property_colors = $derived(get_property_colors(structure, atom_color_config, scene_props.bonding_strategy, sym_data));
|
|
173
175
|
let symmetry_run_id = 0;
|
|
174
176
|
let symmetry_error = $state();
|
|
177
|
+
let last_symmetry_structure_ref = null;
|
|
175
178
|
// Trigger symmetry analysis when structure is loaded or settings change.
|
|
176
179
|
// Skip during atom drags — symmetry doesn't change from moving atoms,
|
|
177
180
|
// and WASM analysis on every drag frame causes severe frame drops.
|
|
@@ -183,16 +186,28 @@ $effect(() => {
|
|
|
183
186
|
sym_data = null;
|
|
184
187
|
symmetry_error = undefined;
|
|
185
188
|
});
|
|
189
|
+
last_symmetry_structure_ref = null;
|
|
186
190
|
return;
|
|
187
191
|
}
|
|
188
192
|
const current_structure = structure;
|
|
193
|
+
const structure_changed = current_structure !== last_symmetry_structure_ref;
|
|
194
|
+
if (structure_changed) {
|
|
195
|
+
untrack(() => {
|
|
196
|
+
sym_data = null;
|
|
197
|
+
symmetry_error = undefined;
|
|
198
|
+
});
|
|
199
|
+
last_symmetry_structure_ref = current_structure;
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// Keep previous symmetry data while recomputing so bound consumers
|
|
203
|
+
// (e.g. SymmetryStats inputs) do not unmount and lose focus.
|
|
204
|
+
untrack(() => symmetry_error = undefined);
|
|
205
|
+
}
|
|
189
206
|
const run_id = ++symmetry_run_id;
|
|
190
207
|
// Destructure symmetry_settings to ensure Svelte tracks changes to symprec and algo
|
|
191
208
|
// (reading just the object reference isn't sufficient for fine-grained reactivity)
|
|
192
209
|
const { symprec, algo } = symmetry_settings ?? symmetry.default_sym_settings;
|
|
193
210
|
const current_settings = { symprec, algo };
|
|
194
|
-
// Use untrack to prevent cascading reactivity when resetting state
|
|
195
|
-
untrack(() => [sym_data, symmetry_error] = [null, undefined]);
|
|
196
211
|
symmetry.ensure_moyo_wasm_ready()
|
|
197
212
|
.then(() => run_id === symmetry_run_id
|
|
198
213
|
? symmetry.analyze_structure_symmetry(current_structure, current_settings)
|
|
@@ -204,6 +219,7 @@ $effect(() => {
|
|
|
204
219
|
})
|
|
205
220
|
.catch((err) => {
|
|
206
221
|
if (run_id === symmetry_run_id) {
|
|
222
|
+
untrack(() => sym_data = null);
|
|
207
223
|
symmetry_error = `Symmetry analysis failed: ${err?.message || err}`;
|
|
208
224
|
console.error(`Symmetry analysis failed:`, err);
|
|
209
225
|
}
|
|
@@ -458,7 +474,6 @@ let camera = $state(undefined);
|
|
|
458
474
|
let orbit_controls = $state(undefined);
|
|
459
475
|
let rotation_target_ref = $state(undefined);
|
|
460
476
|
let initial_computed_zoom = $state(undefined);
|
|
461
|
-
let camera_move_timeout = $state(null);
|
|
462
477
|
// Mutual exclusion: opening one pane closes others
|
|
463
478
|
$effect(() => {
|
|
464
479
|
if (info_pane_open) {
|
|
@@ -480,29 +495,53 @@ $effect(() => {
|
|
|
480
495
|
if (structure)
|
|
481
496
|
camera_has_moved = false;
|
|
482
497
|
});
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
498
|
+
const read_orbit_target = () => {
|
|
499
|
+
if (!orbit_controls?.target)
|
|
500
|
+
return;
|
|
501
|
+
const { x, y, z } = orbit_controls.target;
|
|
502
|
+
return [x, y, z];
|
|
503
|
+
};
|
|
504
|
+
const read_camera_position = () => camera
|
|
505
|
+
? [camera.position.x, camera.position.y, camera.position.z]
|
|
506
|
+
: scene_props.camera_position;
|
|
507
|
+
// Emit debounced camera updates while controls are active.
|
|
508
|
+
$effect(() => {
|
|
509
|
+
if (!camera_is_moving)
|
|
510
|
+
return;
|
|
511
|
+
camera_has_moved = true;
|
|
512
|
+
const emit_camera_move = () => {
|
|
513
|
+
const camera_position = read_camera_position();
|
|
514
|
+
if (camera_position === undefined)
|
|
515
|
+
return;
|
|
516
|
+
const camera_target = read_orbit_target();
|
|
517
|
+
scene_props.camera_position = camera_position;
|
|
518
|
+
scene_props.camera_target = camera_target;
|
|
519
|
+
on_camera_move?.({
|
|
520
|
+
structure,
|
|
521
|
+
camera_has_moved,
|
|
522
|
+
camera_position,
|
|
523
|
+
camera_target,
|
|
524
|
+
});
|
|
525
|
+
};
|
|
526
|
+
emit_camera_move();
|
|
527
|
+
const emit_interval = setInterval(emit_camera_move, 200);
|
|
528
|
+
return () => clearInterval(emit_interval);
|
|
529
|
+
});
|
|
496
530
|
function reset_camera() {
|
|
497
|
-
// Reset camera position to trigger automatic positioning
|
|
531
|
+
// Reset camera position to trigger automatic positioning.
|
|
498
532
|
scene_props.camera_position = [0, 0, 0];
|
|
533
|
+
scene_props.camera_target = rotation_target_ref;
|
|
499
534
|
camera_has_moved = false;
|
|
500
|
-
|
|
535
|
+
let camera_position = [0, 0, 0];
|
|
536
|
+
let camera_target = rotation_target_ref;
|
|
537
|
+
// Reset pan/zoom and ensure controls target returns to structure center.
|
|
501
538
|
if (orbit_controls && camera) {
|
|
502
|
-
|
|
539
|
+
if (`reset` in orbit_controls &&
|
|
540
|
+
typeof orbit_controls.reset === `function`)
|
|
541
|
+
orbit_controls.reset();
|
|
503
542
|
if (orbit_controls.target && rotation_target_ref) {
|
|
504
|
-
const [
|
|
505
|
-
orbit_controls.target.set(
|
|
543
|
+
const [target_x, target_y, target_z] = rotation_target_ref;
|
|
544
|
+
orbit_controls.target.set(target_x, target_y, target_z);
|
|
506
545
|
}
|
|
507
546
|
// Reset zoom for orthographic camera
|
|
508
547
|
if (`zoom` in camera && initial_computed_zoom !== undefined) {
|
|
@@ -511,11 +550,14 @@ function reset_camera() {
|
|
|
511
550
|
ortho_camera.updateProjectionMatrix();
|
|
512
551
|
}
|
|
513
552
|
// Call update to apply changes immediately
|
|
514
|
-
if (typeof orbit_controls.update === `function`)
|
|
553
|
+
if (typeof orbit_controls.update === `function`)
|
|
515
554
|
orbit_controls.update();
|
|
516
|
-
|
|
555
|
+
camera_position = read_camera_position() ?? camera_position;
|
|
556
|
+
camera_target = read_orbit_target();
|
|
517
557
|
}
|
|
518
|
-
|
|
558
|
+
scene_props.camera_position = camera_position;
|
|
559
|
+
scene_props.camera_target = camera_target;
|
|
560
|
+
on_camera_reset?.({ structure, camera_has_moved, camera_position, camera_target });
|
|
519
561
|
}
|
|
520
562
|
const emit_file_load_event = (structure, filename, content) => on_file_load?.({
|
|
521
563
|
structure: structure,
|
|
@@ -558,61 +600,33 @@ function parse_file_content(text_content, filename) {
|
|
|
558
600
|
structure = parsed;
|
|
559
601
|
return parsed;
|
|
560
602
|
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const text_content = content instanceof ArrayBuffer
|
|
573
|
-
? new TextDecoder().decode(content)
|
|
574
|
-
: content;
|
|
575
|
-
const parsed = parse_file_content(text_content, filename);
|
|
576
|
-
emit_file_load_event(parsed, filename, content);
|
|
577
|
-
}
|
|
578
|
-
catch (err) {
|
|
579
|
-
error_msg = `Failed to parse structure: ${err}`;
|
|
580
|
-
on_error?.({ error_msg, filename });
|
|
581
|
-
}
|
|
582
|
-
})).catch(() => false);
|
|
583
|
-
if (handled)
|
|
584
|
-
return;
|
|
585
|
-
// Handle file system drops
|
|
586
|
-
const file = event.dataTransfer?.files[0];
|
|
587
|
-
if (file) {
|
|
588
|
-
try {
|
|
589
|
-
const { content, filename } = await decompress_file(file);
|
|
590
|
-
if (content) {
|
|
591
|
-
if (on_file_drop)
|
|
592
|
-
on_file_drop(content, filename);
|
|
593
|
-
else {
|
|
594
|
-
// Parse structure internally when no handler provided
|
|
595
|
-
try {
|
|
596
|
-
const parsed = parse_file_content(content, filename);
|
|
597
|
-
emit_file_load_event(parsed, filename, content);
|
|
598
|
-
}
|
|
599
|
-
catch (err) {
|
|
600
|
-
error_msg = `Failed to parse structure: ${err}`;
|
|
601
|
-
on_error?.({ error_msg, filename });
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
catch (error) {
|
|
607
|
-
error_msg = `Failed to load file ${file.name}: ${error}`;
|
|
608
|
-
on_error?.({ error_msg, filename: file.name });
|
|
609
|
-
}
|
|
603
|
+
const handle_file_drop = create_file_drop_handler({
|
|
604
|
+
allow: () => allow_file_drop,
|
|
605
|
+
on_drop: (content, filename) => {
|
|
606
|
+
if (on_file_drop)
|
|
607
|
+
return on_file_drop(content, filename);
|
|
608
|
+
try {
|
|
609
|
+
const text_content = content instanceof ArrayBuffer
|
|
610
|
+
? new TextDecoder().decode(content)
|
|
611
|
+
: content;
|
|
612
|
+
const parsed = parse_file_content(text_content, filename);
|
|
613
|
+
emit_file_load_event(parsed, filename, content);
|
|
610
614
|
}
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
}
|
|
615
|
+
catch (err) {
|
|
616
|
+
error_msg = `Failed to parse structure: ${err instanceof Error ? err.message : String(err)}`;
|
|
617
|
+
on_error?.({ error_msg, filename });
|
|
618
|
+
}
|
|
619
|
+
},
|
|
620
|
+
on_error: (msg) => {
|
|
621
|
+
error_msg = msg;
|
|
622
|
+
on_error?.({ error_msg: msg });
|
|
623
|
+
},
|
|
624
|
+
set_loading: (val) => {
|
|
625
|
+
loading = val;
|
|
626
|
+
if (val)
|
|
627
|
+
[error_msg, dragover] = [undefined, false];
|
|
628
|
+
},
|
|
629
|
+
});
|
|
616
630
|
function handle_keydown(event) {
|
|
617
631
|
// Don't handle shortcuts if user is typing in an input field
|
|
618
632
|
const target = event.target;
|
|
@@ -726,11 +740,16 @@ function handle_keydown(event) {
|
|
|
726
740
|
}
|
|
727
741
|
}
|
|
728
742
|
}
|
|
729
|
-
// Interface shortcuts
|
|
730
|
-
|
|
743
|
+
// Interface shortcuts (require Ctrl/Cmd modifier to avoid accidental triggers)
|
|
744
|
+
const has_modifier = event.ctrlKey || event.metaKey;
|
|
745
|
+
if (event.key === `f` && has_modifier && fullscreen_toggle) {
|
|
746
|
+
event.preventDefault();
|
|
731
747
|
toggle_fullscreen(wrapper);
|
|
732
|
-
|
|
748
|
+
}
|
|
749
|
+
else if (event.key === `i` && has_modifier && enable_info_pane) {
|
|
750
|
+
event.preventDefault();
|
|
733
751
|
info_pane_open = !info_pane_open;
|
|
752
|
+
}
|
|
734
753
|
else if (event.key === `Escape`) {
|
|
735
754
|
// Prioritize closing panes, then exit edit modes, then exit fullscreen
|
|
736
755
|
if (info_pane_open)
|
|
@@ -948,10 +967,7 @@ $effect(() => {
|
|
|
948
967
|
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
|
949
968
|
/>
|
|
950
969
|
{:else if error_msg}
|
|
951
|
-
<
|
|
952
|
-
<p class="error">{error_msg}</p>
|
|
953
|
-
<button onclick={() => (error_msg = undefined)}>Dismiss</button>
|
|
954
|
-
</div>
|
|
970
|
+
<StatusMessage bind:message={error_msg} type="error" dismissible />
|
|
955
971
|
{:else if (structure?.sites?.length ?? 0) > 0}
|
|
956
972
|
<section
|
|
957
973
|
class="control-buttons {controls_config.class}"
|
|
@@ -1432,32 +1448,6 @@ $effect(() => {
|
|
|
1432
1448
|
display: grid;
|
|
1433
1449
|
place-content: center;
|
|
1434
1450
|
}
|
|
1435
|
-
.error-state {
|
|
1436
|
-
display: flex;
|
|
1437
|
-
flex-direction: column;
|
|
1438
|
-
align-items: center;
|
|
1439
|
-
justify-content: center;
|
|
1440
|
-
height: var(--struct-height, 500px);
|
|
1441
|
-
padding: 2rem;
|
|
1442
|
-
text-align: center;
|
|
1443
|
-
box-sizing: border-box;
|
|
1444
|
-
}
|
|
1445
|
-
.error-state p {
|
|
1446
|
-
color: var(--error-color, #ff6b6b);
|
|
1447
|
-
margin: 0 0 1rem;
|
|
1448
|
-
}
|
|
1449
|
-
.error-state button {
|
|
1450
|
-
padding: 0.5rem 1rem;
|
|
1451
|
-
background: var(--error-color, #ff6b6b);
|
|
1452
|
-
color: white;
|
|
1453
|
-
border: none;
|
|
1454
|
-
border-radius: var(--border-radius, 3pt);
|
|
1455
|
-
cursor: pointer;
|
|
1456
|
-
font-size: 0.9rem;
|
|
1457
|
-
}
|
|
1458
|
-
.error-state button:hover {
|
|
1459
|
-
background: var(--error-color-hover, #ff5252);
|
|
1460
|
-
}
|
|
1461
1451
|
.symmetry-error {
|
|
1462
1452
|
position: absolute;
|
|
1463
1453
|
bottom: 1rem;
|
|
@@ -78,6 +78,6 @@ type $$ComponentProps = {
|
|
|
78
78
|
on_camera_move?: EventHandler;
|
|
79
79
|
on_camera_reset?: EventHandler;
|
|
80
80
|
} & Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`> & Omit<HTMLAttributes<HTMLDivElement>, `children`>;
|
|
81
|
-
declare const Structure: import("svelte").Component<$$ComponentProps, {}, "height" | "width" | "dragover" | "
|
|
81
|
+
declare const Structure: import("svelte").Component<$$ComponentProps, {}, "structure" | "height" | "width" | "dragover" | "controls_open" | "loading" | "fullscreen" | "hovered" | "color_scheme" | "background_color" | "background_opacity" | "show_image_atoms" | "info_pane_open" | "wrapper" | "sym_data" | "error_msg" | "atom_color_config" | "hidden_elements" | "hidden_prop_vals" | "element_mapping" | "element_radius_overrides" | "site_radius_overrides" | "selected_sites" | "supercell_scaling" | "cell_type" | "active_volume_idx" | "measured_sites" | "scene_props" | "lattice_props" | "volumetric_data" | "isosurface_settings" | "png_dpi" | "measure_mode" | "enable_measure_mode" | "performance_mode" | "displayed_structure" | "symmetry_settings">;
|
|
82
82
|
type Structure = ReturnType<typeof Structure>;
|
|
83
83
|
export default Structure;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<script lang="ts">import { AXIS_COLORS, ELEMENT_COLOR_SCHEMES } from '../colors';
|
|
2
|
+
import IsosurfaceControls from '../isosurface/IsosurfaceControls.svelte';
|
|
2
3
|
import { format_num } from '../labels';
|
|
3
4
|
import { SettingsSection } from '../layout';
|
|
4
5
|
import { to_degrees, to_radians } from '../math';
|
|
5
6
|
import DraggablePane from '../overlays/DraggablePane.svelte';
|
|
6
7
|
import { ColorScaleSelect } from '../plot';
|
|
7
8
|
import { DEFAULTS, SETTINGS_CONFIG } from '../settings';
|
|
8
|
-
import IsosurfaceControls from '../isosurface/IsosurfaceControls.svelte';
|
|
9
9
|
import { Lattice, StructureScene } from './';
|
|
10
10
|
import { is_valid_supercell_input } from './supercell';
|
|
11
11
|
import Select from 'svelte-multiselect';
|
|
@@ -103,7 +103,12 @@ function get_representative_colors(scheme_name) {
|
|
|
103
103
|
|
|
104
104
|
<DraggablePane
|
|
105
105
|
bind:show={controls_open}
|
|
106
|
-
|
|
106
|
+
resizable="both"
|
|
107
|
+
pane_props={{
|
|
108
|
+
...pane_props,
|
|
109
|
+
class: `controls-pane ${pane_props?.class ?? ``}`,
|
|
110
|
+
style: `--pane-max-height: 70vh; ${pane_props?.style ?? ``}`,
|
|
111
|
+
}}
|
|
107
112
|
toggle_props={{
|
|
108
113
|
title: controls_open ? `` : `Structure controls`,
|
|
109
114
|
...toggle_props,
|
|
@@ -111,6 +116,14 @@ function get_representative_colors(scheme_name) {
|
|
|
111
116
|
}}
|
|
112
117
|
{...rest}
|
|
113
118
|
>
|
|
119
|
+
{#if volumetric_data?.length && isosurface_settings}
|
|
120
|
+
<IsosurfaceControls
|
|
121
|
+
bind:settings={isosurface_settings}
|
|
122
|
+
volumes={volumetric_data}
|
|
123
|
+
bind:active_volume_idx
|
|
124
|
+
/>
|
|
125
|
+
{/if}
|
|
126
|
+
|
|
114
127
|
<SettingsSection
|
|
115
128
|
title="Visibility"
|
|
116
129
|
current_values={{
|
|
@@ -424,9 +437,7 @@ function get_representative_colors(scheme_name) {
|
|
|
424
437
|
Same size atoms
|
|
425
438
|
<input type="checkbox" bind:checked={scene_props.same_size_atoms} />
|
|
426
439
|
</label>
|
|
427
|
-
<
|
|
428
|
-
class="label"
|
|
429
|
-
style="align-items: start"
|
|
440
|
+
<label
|
|
430
441
|
{@attach tooltip({ content: SETTINGS_CONFIG.color_scheme.description })}
|
|
431
442
|
>
|
|
432
443
|
Color scheme
|
|
@@ -436,7 +447,10 @@ function get_representative_colors(scheme_name) {
|
|
|
436
447
|
minSelect={1}
|
|
437
448
|
bind:selected={color_scheme_selected}
|
|
438
449
|
liOptionStyle="padding: 3pt 6pt;"
|
|
439
|
-
|
|
450
|
+
liSelectedStyle="background-color: transparent;"
|
|
451
|
+
ulSelectedStyle="display: contents;"
|
|
452
|
+
inputStyle="flex: none; min-width: 0; width: 0; opacity: 0;"
|
|
453
|
+
style="flex: 1; min-width: 0; border: none; margin-left: 4pt"
|
|
440
454
|
aria-label="Color scheme"
|
|
441
455
|
>
|
|
442
456
|
{#snippet children({ option })}
|
|
@@ -454,9 +468,8 @@ function get_representative_colors(scheme_name) {
|
|
|
454
468
|
</div>
|
|
455
469
|
{/snippet}
|
|
456
470
|
</Select>
|
|
457
|
-
</
|
|
471
|
+
</label>
|
|
458
472
|
<label
|
|
459
|
-
style="align-items: start"
|
|
460
473
|
{@attach tooltip({ content: SETTINGS_CONFIG.structure.atom_color_mode.description })}
|
|
461
474
|
>
|
|
462
475
|
Atom coloring
|
|
@@ -470,9 +483,7 @@ function get_representative_colors(scheme_name) {
|
|
|
470
483
|
</select>
|
|
471
484
|
</label>
|
|
472
485
|
{#if atom_color_config.mode !== `element`}
|
|
473
|
-
<
|
|
474
|
-
class="label"
|
|
475
|
-
style="align-items: start; white-space: nowrap"
|
|
486
|
+
<label
|
|
476
487
|
{@attach tooltip({ content: SETTINGS_CONFIG.structure.atom_color_scale.description })}
|
|
477
488
|
>
|
|
478
489
|
Color scale
|
|
@@ -484,10 +495,10 @@ function get_representative_colors(scheme_name) {
|
|
|
484
495
|
wrapper_style: `width: 100%;`,
|
|
485
496
|
title_style: `font-size: 0.95em;`,
|
|
486
497
|
}}
|
|
487
|
-
style="width:
|
|
498
|
+
style="flex: 1; min-width: 0; border: none"
|
|
488
499
|
aria-label="Color scale"
|
|
489
500
|
/>
|
|
490
|
-
</
|
|
501
|
+
</label>
|
|
491
502
|
{/if}
|
|
492
503
|
</SettingsSection>
|
|
493
504
|
|
|
@@ -884,14 +895,6 @@ function get_representative_colors(scheme_name) {
|
|
|
884
895
|
</label>
|
|
885
896
|
</SettingsSection>
|
|
886
897
|
{/if}
|
|
887
|
-
|
|
888
|
-
{#if volumetric_data?.length && isosurface_settings}
|
|
889
|
-
<IsosurfaceControls
|
|
890
|
-
bind:settings={isosurface_settings}
|
|
891
|
-
volumes={volumetric_data}
|
|
892
|
-
bind:active_volume_idx
|
|
893
|
-
/>
|
|
894
|
-
{/if}
|
|
895
898
|
</DraggablePane>
|
|
896
899
|
|
|
897
900
|
<style>
|
|
@@ -925,7 +928,7 @@ function get_representative_colors(scheme_name) {
|
|
|
925
928
|
justify-content: space-between;
|
|
926
929
|
width: 100%;
|
|
927
930
|
}
|
|
928
|
-
label
|
|
931
|
+
label {
|
|
929
932
|
display: flex;
|
|
930
933
|
align-items: center;
|
|
931
934
|
gap: 10pt;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import DraggablePane from '../overlays/DraggablePane.svelte';
|
|
2
1
|
import type { IsosurfaceSettings, VolumetricData } from '../isosurface/types';
|
|
2
|
+
import DraggablePane from '../overlays/DraggablePane.svelte';
|
|
3
3
|
import type { AnyStructure } from './';
|
|
4
4
|
import { Lattice, StructureScene } from './';
|
|
5
5
|
import type { AtomColorConfig } from './atom-properties';
|
|
@@ -96,12 +96,18 @@ let pane_data = $derived.by(() => {
|
|
|
96
96
|
else
|
|
97
97
|
roto_translations++;
|
|
98
98
|
}
|
|
99
|
+
const international_symbol = sym_data.international_short;
|
|
100
|
+
const space_group_symbol = (sym_data.hm_symbol ?? international_symbol)
|
|
101
|
+
?.replace(/\s+/g, ``);
|
|
102
|
+
const space_group_value = space_group_symbol
|
|
103
|
+
? `${sym_data.number} (${space_group_symbol})`
|
|
104
|
+
: String(sym_data.number);
|
|
99
105
|
sections.push({
|
|
100
106
|
title: `Symmetry`,
|
|
101
107
|
items: [
|
|
102
108
|
{
|
|
103
109
|
label: `Space Group`,
|
|
104
|
-
value:
|
|
110
|
+
value: space_group_value,
|
|
105
111
|
key: `symmetry-space-group`,
|
|
106
112
|
},
|
|
107
113
|
{
|