matterviz 0.3.4 → 0.3.6
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/.vscode/launch.json +13 -0
- package/.vscodeignore +7 -0
- package/dist/assets/STLExporter-BpTH3YHE.js +8 -0
- package/dist/assets/browser-DdDecX_W.js +1 -0
- package/dist/assets/export-qgn-H9y6.js +2 -0
- package/dist/assets/main-DiKYzti2.css +1 -0
- package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
- package/dist/extension.js +31293 -0
- package/dist/src/lib/FilePicker.svelte +360 -0
- package/dist/src/lib/MillerIndexInput.svelte +66 -0
- package/dist/src/lib/api/mp.ts +26 -0
- package/dist/src/lib/api/optimade.ts +204 -0
- package/dist/src/lib/app.css +247 -0
- package/dist/src/lib/brillouin/BrillouinZone.svelte +549 -0
- package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +144 -0
- package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +146 -0
- package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +146 -0
- package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +476 -0
- package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +92 -0
- package/dist/src/lib/brillouin/compute.ts +529 -0
- package/dist/src/lib/brillouin/index.ts +8 -0
- package/dist/src/lib/brillouin/types.ts +51 -0
- package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +327 -0
- package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
- package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
- package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +94 -0
- package/dist/src/lib/chempot-diagram/chempot-worker.ts +11 -0
- package/dist/src/lib/chempot-diagram/color.ts +42 -0
- package/dist/src/lib/chempot-diagram/compute.ts +1014 -0
- package/dist/src/lib/chempot-diagram/index.ts +6 -0
- package/dist/src/lib/chempot-diagram/pointer.ts +56 -0
- package/dist/src/lib/chempot-diagram/temperature.ts +77 -0
- package/dist/src/lib/chempot-diagram/types.ts +130 -0
- package/dist/src/lib/colors/index.ts +249 -0
- package/dist/src/lib/composition/BarChart.svelte +297 -0
- package/dist/src/lib/composition/BubbleChart.svelte +218 -0
- package/dist/src/lib/composition/Composition.svelte +165 -0
- package/dist/src/lib/composition/Formula.svelte +268 -0
- package/dist/src/lib/composition/FormulaFilter.svelte +1257 -0
- package/dist/src/lib/composition/PieChart.svelte +323 -0
- package/dist/src/lib/composition/format.ts +155 -0
- package/dist/src/lib/composition/index.ts +37 -0
- package/dist/src/lib/composition/parse.ts +605 -0
- package/dist/src/lib/constants.ts +134 -0
- package/dist/src/lib/controls.ts +42 -0
- package/dist/src/lib/convex-hull/ConvexHull.svelte +157 -0
- package/dist/src/lib/convex-hull/ConvexHull2D.svelte +825 -0
- package/dist/src/lib/convex-hull/ConvexHull3D.svelte +1801 -0
- package/dist/src/lib/convex-hull/ConvexHull4D.svelte +1398 -0
- package/dist/src/lib/convex-hull/ConvexHullControls.svelte +535 -0
- package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +125 -0
- package/dist/src/lib/convex-hull/ConvexHullStats.svelte +929 -0
- package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +131 -0
- package/dist/src/lib/convex-hull/GasPressureControls.svelte +247 -0
- package/dist/src/lib/convex-hull/StructurePopup.svelte +151 -0
- package/dist/src/lib/convex-hull/TemperatureSlider.svelte +140 -0
- package/dist/src/lib/convex-hull/barycentric-coords.ts +246 -0
- package/dist/src/lib/convex-hull/demo-temperature.ts +63 -0
- package/dist/src/lib/convex-hull/gas-thermodynamics.ts +405 -0
- package/dist/src/lib/convex-hull/helpers.ts +932 -0
- package/dist/src/lib/convex-hull/index.ts +202 -0
- package/dist/src/lib/convex-hull/thermodynamics.ts +2192 -0
- package/dist/src/lib/convex-hull/types.ts +267 -0
- package/dist/src/lib/coordination/CoordinationBarPlot.svelte +311 -0
- package/dist/src/lib/coordination/calc-coordination.ts +93 -0
- package/dist/src/lib/coordination/index.ts +9 -0
- package/dist/src/lib/effects.svelte.ts +48 -0
- package/dist/src/lib/element/BohrAtom.svelte +147 -0
- package/dist/src/lib/element/ElementHeading.svelte +26 -0
- package/dist/src/lib/element/ElementPhoto.svelte +57 -0
- package/dist/src/lib/element/ElementStats.svelte +80 -0
- package/dist/src/lib/element/ElementTile.svelte +484 -0
- package/dist/src/lib/element/data.json.gz.d.ts +4 -0
- package/dist/src/lib/element/data.ts +14 -0
- package/dist/src/lib/element/index.ts +8 -0
- package/dist/src/lib/element/types.ts +62 -0
- package/dist/src/lib/feedback/ClickFeedback.svelte +58 -0
- package/dist/src/lib/feedback/DragOverlay.svelte +42 -0
- package/dist/src/lib/feedback/index.ts +4 -0
- package/dist/src/lib/fermi-surface/FermiSlice.svelte +189 -0
- package/dist/src/lib/fermi-surface/FermiSurface.svelte +600 -0
- package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +448 -0
- package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +794 -0
- package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
- package/dist/src/lib/fermi-surface/compute.ts +728 -0
- package/dist/src/lib/fermi-surface/constants.ts +32 -0
- package/dist/src/lib/fermi-surface/export.ts +64 -0
- package/dist/src/lib/fermi-surface/index.ts +14 -0
- package/dist/src/lib/fermi-surface/marching-cubes.ts +3 -0
- package/dist/src/lib/fermi-surface/parse.ts +574 -0
- package/dist/src/lib/fermi-surface/symmetry.ts +56 -0
- package/dist/src/lib/fermi-surface/types.ts +159 -0
- package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
- package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
- package/dist/src/lib/heatmap-matrix/index.ts +167 -0
- package/dist/src/lib/heatmap-matrix/shared.ts +7 -0
- package/dist/src/lib/icons.ts +650 -0
- package/dist/src/lib/index.ts +61 -0
- package/dist/src/lib/io/decompress.ts +92 -0
- package/dist/src/lib/io/export.ts +385 -0
- package/dist/src/lib/io/fetch.ts +46 -0
- package/dist/src/lib/io/file-drop.ts +51 -0
- package/dist/src/lib/io/index.ts +7 -0
- package/dist/src/lib/io/is-binary.ts +24 -0
- package/dist/src/lib/io/types.ts +8 -0
- package/dist/src/lib/io/url-drop.ts +141 -0
- package/dist/src/lib/isosurface/Isosurface.svelte +285 -0
- package/dist/src/lib/isosurface/IsosurfaceControls.svelte +277 -0
- package/dist/src/lib/isosurface/index.ts +7 -0
- package/dist/src/lib/isosurface/parse.ts +656 -0
- package/dist/src/lib/isosurface/slice.ts +175 -0
- package/dist/src/lib/isosurface/types.ts +309 -0
- package/dist/src/lib/labels.ts +320 -0
- package/dist/src/lib/layout/FullscreenToggle.svelte +50 -0
- package/dist/src/lib/layout/InfoCard.svelte +120 -0
- package/dist/src/lib/layout/InfoTag.svelte +185 -0
- package/dist/src/lib/layout/PropertyFilter.svelte +246 -0
- package/dist/src/lib/layout/SettingsSection.svelte +148 -0
- package/dist/src/lib/layout/SubpageGrid.svelte +82 -0
- package/dist/src/lib/layout/fullscreen.ts +65 -0
- package/dist/src/lib/layout/index.ts +11 -0
- package/dist/src/lib/layout/json-tree/JsonNode.svelte +548 -0
- package/dist/src/lib/layout/json-tree/JsonTree.svelte +1230 -0
- package/dist/src/lib/layout/json-tree/JsonValue.svelte +334 -0
- package/dist/src/lib/layout/json-tree/index.ts +3 -0
- package/dist/src/lib/layout/json-tree/types.ts +126 -0
- package/dist/src/lib/layout/json-tree/utils.ts +682 -0
- package/dist/src/lib/marching-cubes.ts +614 -0
- package/dist/src/lib/math.ts +1081 -0
- package/dist/src/lib/overlays/ContextMenu.svelte +162 -0
- package/dist/src/lib/overlays/CopyButton.svelte +45 -0
- package/dist/src/lib/overlays/DragControlTab.svelte +98 -0
- package/dist/src/lib/overlays/DraggablePane.svelte +487 -0
- package/dist/src/lib/overlays/InfoPaneCards.svelte +149 -0
- package/dist/src/lib/overlays/index.ts +3 -0
- package/dist/src/lib/periodic-table/PeriodicTable.svelte +469 -0
- package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +557 -0
- package/dist/src/lib/periodic-table/PropertySelect.svelte +37 -0
- package/dist/src/lib/periodic-table/index.ts +12 -0
- package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
- package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +444 -0
- package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
- package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
- package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
- package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +203 -0
- package/dist/src/lib/phase-diagram/build-diagram.ts +186 -0
- package/dist/src/lib/phase-diagram/colors.ts +58 -0
- package/dist/src/lib/phase-diagram/diagram-input.ts +40 -0
- package/dist/src/lib/phase-diagram/index.ts +13 -0
- package/dist/src/lib/phase-diagram/parse.ts +348 -0
- package/dist/src/lib/phase-diagram/svg-to-diagram.ts +1023 -0
- package/dist/src/lib/phase-diagram/types.ts +144 -0
- package/dist/src/lib/phase-diagram/utils.ts +775 -0
- package/dist/src/lib/plot/AxisLabel.svelte +51 -0
- package/dist/src/lib/plot/BarPlot.svelte +2113 -0
- package/dist/src/lib/plot/BarPlotControls.svelte +66 -0
- package/dist/src/lib/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/src/lib/plot/ColorBar.svelte +721 -0
- package/dist/src/lib/plot/ColorScaleSelect.svelte +54 -0
- package/dist/src/lib/plot/ElementScatter.svelte +63 -0
- package/dist/src/lib/plot/FillArea.svelte +223 -0
- package/dist/src/lib/plot/Histogram.svelte +1558 -0
- package/dist/src/lib/plot/HistogramControls.svelte +212 -0
- package/dist/src/lib/plot/InteractiveAxisLabel.svelte +96 -0
- package/dist/src/lib/plot/Line.svelte +84 -0
- package/dist/src/lib/plot/PlotAxis.svelte +169 -0
- package/dist/src/lib/plot/PlotControls.svelte +537 -0
- package/dist/src/lib/plot/PlotLegend.svelte +569 -0
- package/dist/src/lib/plot/PlotTooltip.svelte +67 -0
- package/dist/src/lib/plot/PortalSelect.svelte +253 -0
- package/dist/src/lib/plot/ReferenceLine3D.svelte +156 -0
- package/dist/src/lib/plot/ReferencePlane.svelte +175 -0
- package/dist/src/lib/plot/ScatterPlot.svelte +2778 -0
- package/dist/src/lib/plot/ScatterPlot3D.svelte +529 -0
- package/dist/src/lib/plot/ScatterPlot3DControls.svelte +437 -0
- package/dist/src/lib/plot/ScatterPlot3DScene.svelte +912 -0
- package/dist/src/lib/plot/ScatterPlotControls.svelte +306 -0
- package/dist/src/lib/plot/ScatterPoint.svelte +182 -0
- package/dist/src/lib/plot/SpacegroupBarPlot.svelte +293 -0
- package/dist/src/lib/plot/Surface3D.svelte +197 -0
- package/dist/src/lib/plot/ZeroLines.svelte +97 -0
- package/dist/src/lib/plot/ZoomRect.svelte +23 -0
- package/dist/src/lib/plot/adaptive-density.ts +316 -0
- package/dist/src/lib/plot/auto-place.ts +184 -0
- package/dist/src/lib/plot/axis-utils.ts +122 -0
- package/dist/src/lib/plot/binned-scatter-types.ts +83 -0
- package/dist/src/lib/plot/data-cleaning.ts +1069 -0
- package/dist/src/lib/plot/data-transform.ts +69 -0
- package/dist/src/lib/plot/defaults.ts +9 -0
- package/dist/src/lib/plot/fill-utils.ts +494 -0
- package/dist/src/lib/plot/hover-lock.svelte.ts +60 -0
- package/dist/src/lib/plot/index.ts +53 -0
- package/dist/src/lib/plot/interactions.ts +119 -0
- package/dist/src/lib/plot/layout.ts +425 -0
- package/dist/src/lib/plot/reference-line.ts +426 -0
- package/dist/src/lib/plot/scales.ts +654 -0
- package/dist/src/lib/plot/svg.ts +23 -0
- package/dist/src/lib/plot/types.ts +1144 -0
- package/dist/src/lib/plot/utils/label-placement.ts +541 -0
- package/dist/src/lib/plot/utils/series-visibility.ts +140 -0
- package/dist/src/lib/plot/utils.ts +11 -0
- package/dist/src/lib/rdf/RdfPlot.svelte +247 -0
- package/dist/src/lib/rdf/calc-rdf.ts +167 -0
- package/dist/src/lib/rdf/index.ts +27 -0
- package/dist/src/lib/sanitize.ts +126 -0
- package/dist/src/lib/settings.ts +1479 -0
- package/dist/src/lib/spectral/Bands.svelte +1040 -0
- package/dist/src/lib/spectral/BandsAndDos.svelte +134 -0
- package/dist/src/lib/spectral/BrillouinBandsDos.svelte +252 -0
- package/dist/src/lib/spectral/Dos.svelte +697 -0
- package/dist/src/lib/spectral/helpers.ts +1381 -0
- package/dist/src/lib/spectral/index.ts +8 -0
- package/dist/src/lib/spectral/types.ts +112 -0
- package/dist/src/lib/state.svelte.ts +64 -0
- package/dist/src/lib/structure/Arrow.svelte +72 -0
- package/dist/src/lib/structure/AtomLegend.svelte +815 -0
- package/dist/src/lib/structure/Bond.svelte +140 -0
- package/dist/src/lib/structure/CanvasTooltip.svelte +33 -0
- package/dist/src/lib/structure/CellSelect.svelte +349 -0
- package/dist/src/lib/structure/Cylinder.svelte +45 -0
- package/dist/src/lib/structure/Lattice.svelte +196 -0
- package/dist/src/lib/structure/Structure.svelte +2248 -0
- package/dist/src/lib/structure/StructureControls.svelte +1273 -0
- package/dist/src/lib/structure/StructureExportPane.svelte +252 -0
- package/dist/src/lib/structure/StructureInfoPane.svelte +737 -0
- package/dist/src/lib/structure/StructureScene.svelte +2255 -0
- package/dist/src/lib/structure/atom-properties.ts +316 -0
- package/dist/src/lib/structure/bond-order-perception.ts +447 -0
- package/dist/src/lib/structure/bonding.ts +944 -0
- package/dist/src/lib/structure/export.ts +861 -0
- package/dist/src/lib/structure/index.ts +291 -0
- package/dist/src/lib/structure/label-placement.ts +130 -0
- package/dist/src/lib/structure/measure.ts +45 -0
- package/dist/src/lib/structure/parse.ts +1705 -0
- package/dist/src/lib/structure/partial-occupancy.ts +183 -0
- package/dist/src/lib/structure/pbc.ts +164 -0
- package/dist/src/lib/structure/supercell.ts +226 -0
- package/dist/src/lib/structure/validation.ts +11 -0
- package/dist/src/lib/symmetry/SymmetryStats.svelte +226 -0
- package/dist/src/lib/symmetry/WyckoffTable.svelte +120 -0
- package/dist/src/lib/symmetry/cell-transform.ts +118 -0
- package/dist/src/lib/symmetry/index.ts +348 -0
- package/dist/src/lib/symmetry/spacegroups.ts +404 -0
- package/dist/src/lib/table/HeatmapTable.svelte +1833 -0
- package/dist/src/lib/table/ToggleMenu.svelte +385 -0
- package/dist/src/lib/table/index.ts +139 -0
- package/dist/src/lib/theme/ThemeControl.svelte +53 -0
- package/dist/src/lib/theme/index.ts +107 -0
- package/dist/src/lib/theme/themes.mjs +297 -0
- package/dist/src/lib/time.ts +71 -0
- package/dist/src/lib/tooltip/TooltipContent.svelte +58 -0
- package/dist/src/lib/tooltip/index.ts +2 -0
- package/dist/src/lib/tooltip/types.ts +13 -0
- package/dist/src/lib/trajectory/Trajectory.svelte +1545 -0
- package/dist/src/lib/trajectory/TrajectoryError.svelte +128 -0
- package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +357 -0
- package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +313 -0
- package/dist/src/lib/trajectory/constants.ts +7 -0
- package/dist/src/lib/trajectory/extract.ts +196 -0
- package/dist/src/lib/trajectory/format-detect.ts +96 -0
- package/dist/src/lib/trajectory/frame-reader.ts +456 -0
- package/dist/src/lib/trajectory/helpers.ts +217 -0
- package/dist/src/lib/trajectory/index.ts +218 -0
- package/dist/src/lib/trajectory/parse/ase.ts +109 -0
- package/dist/src/lib/trajectory/parse/hdf5.ts +173 -0
- package/dist/src/lib/trajectory/parse/index.ts +411 -0
- package/dist/src/lib/trajectory/parse/lammps.ts +215 -0
- package/dist/src/lib/trajectory/parse/vasp.ts +102 -0
- package/dist/src/lib/trajectory/parse/xyz.ts +143 -0
- package/dist/src/lib/trajectory/plotting.ts +599 -0
- package/dist/src/lib/trajectory/types.ts +13 -0
- package/dist/src/lib/utils.ts +56 -0
- package/dist/src/lib/xrd/XrdPlot.svelte +615 -0
- package/dist/src/lib/xrd/broadening.ts +130 -0
- package/dist/src/lib/xrd/calc-xrd.ts +397 -0
- package/dist/src/lib/xrd/index.ts +38 -0
- package/dist/src/lib/xrd/parse.ts +858 -0
- package/dist/webview.js +29421 -0
- package/icon.png +0 -0
- package/license +1 -1
- package/matterviz-0.3.2.vsix +0 -0
- package/matterviz-0.3.4.vsix +0 -0
- package/matterviz-0.3.5.vsix +0 -0
- package/package.json +1461 -231
- package/readme.md +171 -98
- package/scripts/sync-config.ts +101 -0
- package/src/declarations.d.ts +2 -0
- package/src/extension.ts +972 -0
- package/src/node-io.ts +65 -0
- package/src/types.ts +17 -0
- package/src/webview/JsonBrowser.svelte +1079 -0
- package/src/webview/PlotPanel.svelte +346 -0
- package/src/webview/detect.ts +444 -0
- package/src/webview/main.ts +764 -0
- package/src/webview/plot-utils.ts +250 -0
- package/test-fixtures/all-viz-types.json.gz +0 -0
- package/test-fixtures/plot-demo-data.json.gz +0 -0
- package/tests/detect.test.ts +604 -0
- package/tests/extension.test.ts +2041 -0
- package/tests/node-io.test.ts +39 -0
- package/tests/plot-utils.test.ts +302 -0
- package/tests/vite-plugin-json-gz.test.ts +114 -0
- package/tests/vscode-mock.ts +18 -0
- package/tests/webview.test.ts +231 -0
- package/tsconfig.json +20 -0
- package/vite-plugin-json-gz.ts +29 -0
- package/vite.config.ts +34 -0
- package/vite.extension.config.ts +34 -0
- package/dist/EmptyState.svelte.d.ts +0 -9
- package/dist/FilePicker.svelte +0 -360
- package/dist/FilePicker.svelte.d.ts +0 -17
- package/dist/Icon.svelte.d.ts +0 -13
- package/dist/MillerIndexInput.svelte +0 -66
- package/dist/MillerIndexInput.svelte.d.ts +0 -7
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/api/optimade.d.ts +0 -45
- package/dist/api/optimade.js +0 -135
- package/dist/app.css +0 -240
- package/dist/brillouin/BrillouinZone.svelte +0 -543
- package/dist/brillouin/BrillouinZone.svelte.d.ts +0 -83
- package/dist/brillouin/BrillouinZoneControls.svelte +0 -144
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +0 -17
- package/dist/brillouin/BrillouinZoneExportPane.svelte +0 -148
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +0 -15
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +0 -146
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +0 -13
- package/dist/brillouin/BrillouinZoneScene.svelte +0 -476
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +0 -48
- package/dist/brillouin/BrillouinZoneTooltip.svelte +0 -92
- package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +0 -8
- package/dist/brillouin/compute.d.ts +0 -17
- package/dist/brillouin/compute.js +0 -422
- package/dist/brillouin/index.d.ts +0 -8
- package/dist/brillouin/index.js +0 -8
- package/dist/brillouin/types.d.ts +0 -48
- package/dist/brillouin/types.js +0 -1
- package/dist/chempot-diagram/ChemPotDiagram.svelte +0 -327
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +0 -13
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +0 -847
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +0 -16
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +0 -3194
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +0 -16
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +0 -7
- package/dist/chempot-diagram/async-compute.svelte.d.ts +0 -3
- package/dist/chempot-diagram/async-compute.svelte.js +0 -77
- package/dist/chempot-diagram/chempot-worker.d.ts +0 -1
- package/dist/chempot-diagram/chempot-worker.js +0 -11
- package/dist/chempot-diagram/color.d.ts +0 -10
- package/dist/chempot-diagram/color.js +0 -32
- package/dist/chempot-diagram/compute.d.ts +0 -48
- package/dist/chempot-diagram/compute.js +0 -812
- package/dist/chempot-diagram/index.d.ts +0 -6
- package/dist/chempot-diagram/index.js +0 -6
- package/dist/chempot-diagram/pointer.d.ts +0 -16
- package/dist/chempot-diagram/pointer.js +0 -40
- package/dist/chempot-diagram/temperature.d.ts +0 -15
- package/dist/chempot-diagram/temperature.js +0 -36
- package/dist/chempot-diagram/types.d.ts +0 -86
- package/dist/chempot-diagram/types.js +0 -28
- package/dist/colors/index.d.ts +0 -47
- package/dist/colors/index.js +0 -203
- package/dist/composition/BarChart.svelte +0 -297
- package/dist/composition/BarChart.svelte.d.ts +0 -39
- package/dist/composition/BubbleChart.svelte +0 -218
- package/dist/composition/BubbleChart.svelte.d.ts +0 -28
- package/dist/composition/Composition.svelte +0 -164
- package/dist/composition/Composition.svelte.d.ts +0 -15
- package/dist/composition/Formula.svelte +0 -265
- package/dist/composition/Formula.svelte.d.ts +0 -19
- package/dist/composition/FormulaFilter.svelte +0 -1259
- package/dist/composition/FormulaFilter.svelte.d.ts +0 -51
- package/dist/composition/PieChart.svelte +0 -323
- package/dist/composition/PieChart.svelte.d.ts +0 -37
- package/dist/composition/format.d.ts +0 -15
- package/dist/composition/format.js +0 -109
- package/dist/composition/index.d.ts +0 -20
- package/dist/composition/index.js +0 -14
- package/dist/composition/parse.d.ts +0 -55
- package/dist/composition/parse.js +0 -459
- package/dist/constants.d.ts +0 -29
- package/dist/constants.js +0 -105
- package/dist/controls.d.ts +0 -14
- package/dist/controls.js +0 -30
- package/dist/convex-hull/ConvexHull.svelte +0 -157
- package/dist/convex-hull/ConvexHull.svelte.d.ts +0 -13
- package/dist/convex-hull/ConvexHull2D.svelte +0 -813
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +0 -11
- package/dist/convex-hull/ConvexHull3D.svelte +0 -1788
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +0 -8
- package/dist/convex-hull/ConvexHull4D.svelte +0 -1374
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +0 -8
- package/dist/convex-hull/ConvexHullControls.svelte +0 -546
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +0 -48
- package/dist/convex-hull/ConvexHullInfoPane.svelte +0 -115
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +0 -18
- package/dist/convex-hull/ConvexHullStats.svelte +0 -905
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +0 -15
- package/dist/convex-hull/ConvexHullTooltip.svelte +0 -131
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +0 -33
- package/dist/convex-hull/GasPressureControls.svelte +0 -247
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +0 -11
- package/dist/convex-hull/StructurePopup.svelte +0 -116
- package/dist/convex-hull/StructurePopup.svelte.d.ts +0 -18
- package/dist/convex-hull/TemperatureSlider.svelte +0 -137
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +0 -8
- package/dist/convex-hull/barycentric-coords.d.ts +0 -18
- package/dist/convex-hull/barycentric-coords.js +0 -182
- package/dist/convex-hull/demo-temperature.d.ts +0 -6
- package/dist/convex-hull/demo-temperature.js +0 -40
- package/dist/convex-hull/gas-thermodynamics.d.ts +0 -16
- package/dist/convex-hull/gas-thermodynamics.js +0 -316
- package/dist/convex-hull/helpers.d.ts +0 -103
- package/dist/convex-hull/helpers.js +0 -671
- package/dist/convex-hull/index.d.ts +0 -118
- package/dist/convex-hull/index.js +0 -57
- package/dist/convex-hull/thermodynamics.d.ts +0 -66
- package/dist/convex-hull/thermodynamics.js +0 -1752
- package/dist/convex-hull/types.d.ts +0 -162
- package/dist/convex-hull/types.js +0 -36
- package/dist/coordination/CoordinationBarPlot.svelte +0 -311
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +0 -30
- package/dist/coordination/calc-coordination.d.ts +0 -15
- package/dist/coordination/calc-coordination.js +0 -63
- package/dist/coordination/index.d.ts +0 -8
- package/dist/coordination/index.js +0 -7
- package/dist/element/BohrAtom.svelte +0 -149
- package/dist/element/BohrAtom.svelte.d.ts +0 -20
- package/dist/element/ElementHeading.svelte +0 -26
- package/dist/element/ElementHeading.svelte.d.ts +0 -8
- package/dist/element/ElementPhoto.svelte +0 -57
- package/dist/element/ElementPhoto.svelte.d.ts +0 -9
- package/dist/element/ElementStats.svelte +0 -80
- package/dist/element/ElementStats.svelte.d.ts +0 -8
- package/dist/element/ElementTile.svelte +0 -484
- package/dist/element/ElementTile.svelte.d.ts +0 -29
- package/dist/element/Nucleus.svelte.d.ts +0 -17
- package/dist/element/data.d.ts +0 -3
- package/dist/element/data.js +0 -2
- package/dist/element/data.json.gz.d.ts +0 -2
- package/dist/element/index.d.ts +0 -8
- package/dist/element/index.js +0 -8
- package/dist/element/types.d.ts +0 -57
- package/dist/element/types.js +0 -1
- package/dist/feedback/ClickFeedback.svelte +0 -58
- package/dist/feedback/ClickFeedback.svelte.d.ts +0 -12
- package/dist/feedback/DragOverlay.svelte +0 -42
- package/dist/feedback/DragOverlay.svelte.d.ts +0 -7
- package/dist/feedback/Spinner.svelte.d.ts +0 -7
- package/dist/feedback/StatusMessage.svelte.d.ts +0 -9
- package/dist/feedback/index.d.ts +0 -4
- package/dist/feedback/index.js +0 -4
- package/dist/fermi-surface/FermiSlice.svelte +0 -189
- package/dist/fermi-surface/FermiSlice.svelte.d.ts +0 -24
- package/dist/fermi-surface/FermiSurface.svelte +0 -597
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +0 -83
- package/dist/fermi-surface/FermiSurfaceControls.svelte +0 -452
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +0 -35
- package/dist/fermi-surface/FermiSurfaceScene.svelte +0 -792
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +0 -50
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +0 -8
- package/dist/fermi-surface/compute.d.ts +0 -5
- package/dist/fermi-surface/compute.js +0 -538
- package/dist/fermi-surface/constants.d.ts +0 -9
- package/dist/fermi-surface/constants.js +0 -27
- package/dist/fermi-surface/export.d.ts +0 -5
- package/dist/fermi-surface/export.js +0 -63
- package/dist/fermi-surface/index.d.ts +0 -12
- package/dist/fermi-surface/index.js +0 -13
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/fermi-surface/parse.d.ts +0 -2
- package/dist/fermi-surface/parse.js +0 -495
- package/dist/fermi-surface/symmetry.d.ts +0 -3
- package/dist/fermi-surface/symmetry.js +0 -46
- package/dist/fermi-surface/types.d.ts +0 -113
- package/dist/fermi-surface/types.js +0 -4
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +0 -1527
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +0 -110
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +0 -30
- package/dist/heatmap-matrix/index.d.ts +0 -53
- package/dist/heatmap-matrix/index.js +0 -100
- package/dist/heatmap-matrix/shared.d.ts +0 -2
- package/dist/heatmap-matrix/shared.js +0 -4
- package/dist/icons.d.ts +0 -569
- package/dist/icons.js +0 -648
- package/dist/index.d.ts +0 -39
- package/dist/index.js +0 -39
- package/dist/io/decompress.d.ts +0 -10
- package/dist/io/decompress.js +0 -69
- package/dist/io/export.d.ts +0 -16
- package/dist/io/export.js +0 -312
- package/dist/io/fetch.d.ts +0 -5
- package/dist/io/fetch.js +0 -39
- package/dist/io/file-drop.d.ts +0 -7
- package/dist/io/file-drop.js +0 -43
- package/dist/io/index.d.ts +0 -7
- package/dist/io/index.js +0 -7
- package/dist/io/is-binary.d.ts +0 -1
- package/dist/io/is-binary.js +0 -5
- package/dist/io/types.d.ts +0 -8
- package/dist/io/types.js +0 -1
- package/dist/io/url-drop.d.ts +0 -2
- package/dist/io/url-drop.js +0 -117
- package/dist/isosurface/Isosurface.svelte +0 -285
- package/dist/isosurface/Isosurface.svelte.d.ts +0 -8
- package/dist/isosurface/IsosurfaceControls.svelte +0 -291
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +0 -9
- package/dist/isosurface/index.d.ts +0 -5
- package/dist/isosurface/index.js +0 -6
- package/dist/isosurface/parse.d.ts +0 -6
- package/dist/isosurface/parse.js +0 -553
- package/dist/isosurface/slice.d.ts +0 -11
- package/dist/isosurface/slice.js +0 -140
- package/dist/isosurface/types.d.ts +0 -56
- package/dist/isosurface/types.js +0 -227
- package/dist/labels.d.ts +0 -53
- package/dist/labels.js +0 -274
- package/dist/layout/FullscreenToggle.svelte +0 -50
- package/dist/layout/FullscreenToggle.svelte.d.ts +0 -7
- package/dist/layout/InfoCard.svelte +0 -120
- package/dist/layout/InfoCard.svelte.d.ts +0 -21
- package/dist/layout/InfoTag.svelte +0 -183
- package/dist/layout/InfoTag.svelte.d.ts +0 -19
- package/dist/layout/PropertyFilter.svelte +0 -244
- package/dist/layout/PropertyFilter.svelte.d.ts +0 -24
- package/dist/layout/SettingsSection.svelte +0 -148
- package/dist/layout/SettingsSection.svelte.d.ts +0 -17
- package/dist/layout/SubpageGrid.svelte +0 -82
- package/dist/layout/SubpageGrid.svelte.d.ts +0 -14
- package/dist/layout/fullscreen.d.ts +0 -9
- package/dist/layout/fullscreen.js +0 -53
- package/dist/layout/index.d.ts +0 -10
- package/dist/layout/index.js +0 -8
- package/dist/layout/json-tree/JsonNode.svelte +0 -547
- package/dist/layout/json-tree/JsonNode.svelte.d.ts +0 -11
- package/dist/layout/json-tree/JsonTree.svelte +0 -1222
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +0 -6
- package/dist/layout/json-tree/JsonValue.svelte +0 -334
- package/dist/layout/json-tree/JsonValue.svelte.d.ts +0 -9
- package/dist/layout/json-tree/index.d.ts +0 -3
- package/dist/layout/json-tree/index.js +0 -3
- package/dist/layout/json-tree/types.d.ts +0 -73
- package/dist/layout/json-tree/types.js +0 -3
- package/dist/layout/json-tree/utils.d.ts +0 -29
- package/dist/layout/json-tree/utils.js +0 -648
- package/dist/marching-cubes.d.ts +0 -14
- package/dist/marching-cubes.js +0 -542
- package/dist/math.d.ts +0 -91
- package/dist/math.js +0 -896
- package/dist/overlays/ContextMenu.svelte +0 -162
- package/dist/overlays/ContextMenu.svelte.d.ts +0 -25
- package/dist/overlays/DraggablePane.svelte +0 -564
- package/dist/overlays/DraggablePane.svelte.d.ts +0 -36
- package/dist/overlays/index.d.ts +0 -2
- package/dist/overlays/index.js +0 -2
- package/dist/periodic-table/PeriodicTable.svelte +0 -469
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +0 -55
- package/dist/periodic-table/PeriodicTableControls.svelte +0 -557
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +0 -24
- package/dist/periodic-table/PropertySelect.svelte +0 -37
- package/dist/periodic-table/PropertySelect.svelte.d.ts +0 -13
- package/dist/periodic-table/TableInset.svelte.d.ts +0 -9
- package/dist/periodic-table/index.d.ts +0 -10
- package/dist/periodic-table/index.js +0 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +0 -44
- package/dist/phase-diagram/PhaseDiagramControls.svelte +0 -451
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +0 -30
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +0 -15
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +0 -192
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +0 -19
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +0 -392
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +0 -16
- package/dist/phase-diagram/TdbInfoPanel.svelte +0 -203
- package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +0 -12
- package/dist/phase-diagram/build-diagram.d.ts +0 -11
- package/dist/phase-diagram/build-diagram.js +0 -167
- package/dist/phase-diagram/colors.d.ts +0 -35
- package/dist/phase-diagram/colors.js +0 -51
- package/dist/phase-diagram/diagram-input.d.ts +0 -33
- package/dist/phase-diagram/diagram-input.js +0 -3
- package/dist/phase-diagram/index.d.ts +0 -13
- package/dist/phase-diagram/index.js +0 -13
- package/dist/phase-diagram/parse.d.ts +0 -55
- package/dist/phase-diagram/parse.js +0 -276
- package/dist/phase-diagram/svg-to-diagram.d.ts +0 -2
- package/dist/phase-diagram/svg-to-diagram.js +0 -869
- package/dist/phase-diagram/types.d.ts +0 -99
- package/dist/phase-diagram/types.js +0 -1
- package/dist/phase-diagram/utils.d.ts +0 -118
- package/dist/phase-diagram/utils.js +0 -606
- package/dist/plot/AxisLabel.svelte +0 -51
- package/dist/plot/AxisLabel.svelte.d.ts +0 -16
- package/dist/plot/BarPlot.svelte +0 -2256
- package/dist/plot/BarPlot.svelte.d.ts +0 -82
- package/dist/plot/BarPlotControls.svelte +0 -66
- package/dist/plot/BarPlotControls.svelte.d.ts +0 -18
- package/dist/plot/ColorBar.svelte +0 -719
- package/dist/plot/ColorBar.svelte.d.ts +0 -31
- package/dist/plot/ColorScaleSelect.svelte +0 -54
- package/dist/plot/ColorScaleSelect.svelte.d.ts +0 -15
- package/dist/plot/ElementScatter.svelte +0 -63
- package/dist/plot/ElementScatter.svelte.d.ts +0 -14
- package/dist/plot/FillArea.svelte +0 -226
- package/dist/plot/FillArea.svelte.d.ts +0 -20
- package/dist/plot/Histogram.svelte +0 -1654
- package/dist/plot/Histogram.svelte.d.ts +0 -50
- package/dist/plot/HistogramControls.svelte +0 -212
- package/dist/plot/HistogramControls.svelte.d.ts +0 -22
- package/dist/plot/InteractiveAxisLabel.svelte +0 -94
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +0 -14
- package/dist/plot/Line.svelte +0 -85
- package/dist/plot/Line.svelte.d.ts +0 -15
- package/dist/plot/PlotControls.svelte +0 -537
- package/dist/plot/PlotControls.svelte.d.ts +0 -4
- package/dist/plot/PlotLegend.svelte +0 -498
- package/dist/plot/PlotLegend.svelte.d.ts +0 -25
- package/dist/plot/PlotTooltip.svelte +0 -67
- package/dist/plot/PlotTooltip.svelte.d.ts +0 -17
- package/dist/plot/PortalSelect.svelte +0 -253
- package/dist/plot/PortalSelect.svelte.d.ts +0 -16
- package/dist/plot/ReferenceLine.svelte.d.ts +0 -20
- package/dist/plot/ReferenceLine3D.svelte +0 -154
- package/dist/plot/ReferenceLine3D.svelte.d.ts +0 -14
- package/dist/plot/ReferencePlane.svelte +0 -178
- package/dist/plot/ReferencePlane.svelte.d.ts +0 -14
- package/dist/plot/ScatterPlot.svelte +0 -2831
- package/dist/plot/ScatterPlot.svelte.d.ts +0 -92
- package/dist/plot/ScatterPlot3D.svelte +0 -499
- package/dist/plot/ScatterPlot3D.svelte.d.ts +0 -94
- package/dist/plot/ScatterPlot3DControls.svelte +0 -437
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +0 -20
- package/dist/plot/ScatterPlot3DScene.svelte +0 -912
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +0 -74
- package/dist/plot/ScatterPlotControls.svelte +0 -307
- package/dist/plot/ScatterPlotControls.svelte.d.ts +0 -17
- package/dist/plot/ScatterPoint.svelte +0 -185
- package/dist/plot/ScatterPoint.svelte.d.ts +0 -19
- package/dist/plot/SpacegroupBarPlot.svelte +0 -292
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +0 -9
- package/dist/plot/Surface3D.svelte +0 -200
- package/dist/plot/Surface3D.svelte.d.ts +0 -13
- package/dist/plot/ZeroLines.svelte +0 -96
- package/dist/plot/ZeroLines.svelte.d.ts +0 -32
- package/dist/plot/ZoomRect.svelte +0 -23
- package/dist/plot/ZoomRect.svelte.d.ts +0 -8
- package/dist/plot/axis-utils.d.ts +0 -19
- package/dist/plot/axis-utils.js +0 -80
- package/dist/plot/data-cleaning.d.ts +0 -37
- package/dist/plot/data-cleaning.js +0 -855
- package/dist/plot/data-transform.d.ts +0 -16
- package/dist/plot/data-transform.js +0 -45
- package/dist/plot/defaults.d.ts +0 -19
- package/dist/plot/defaults.js +0 -9
- package/dist/plot/fill-utils.d.ts +0 -51
- package/dist/plot/fill-utils.js +0 -337
- package/dist/plot/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/hover-lock.svelte.js +0 -46
- package/dist/plot/index.d.ts +0 -43
- package/dist/plot/index.js +0 -37
- package/dist/plot/interactions.d.ts +0 -12
- package/dist/plot/interactions.js +0 -100
- package/dist/plot/layout.d.ts +0 -60
- package/dist/plot/layout.js +0 -230
- package/dist/plot/reference-line.d.ts +0 -60
- package/dist/plot/reference-line.js +0 -316
- package/dist/plot/scales.d.ts +0 -48
- package/dist/plot/scales.js +0 -484
- package/dist/plot/svg.d.ts +0 -1
- package/dist/plot/svg.js +0 -11
- package/dist/plot/types.d.ts +0 -863
- package/dist/plot/types.js +0 -103
- package/dist/plot/utils/label-placement.d.ts +0 -47
- package/dist/plot/utils/label-placement.js +0 -256
- package/dist/plot/utils/series-visibility.d.ts +0 -9
- package/dist/plot/utils/series-visibility.js +0 -67
- package/dist/plot/utils.d.ts +0 -1
- package/dist/plot/utils.js +0 -14
- package/dist/rdf/RdfPlot.svelte +0 -247
- package/dist/rdf/RdfPlot.svelte.d.ts +0 -27
- package/dist/rdf/calc-rdf.d.ts +0 -4
- package/dist/rdf/calc-rdf.js +0 -111
- package/dist/rdf/index.d.ts +0 -23
- package/dist/rdf/index.js +0 -2
- package/dist/sanitize.d.ts +0 -4
- package/dist/sanitize.js +0 -107
- package/dist/settings.d.ts +0 -253
- package/dist/settings.js +0 -1123
- package/dist/spectral/Bands.svelte +0 -1040
- package/dist/spectral/Bands.svelte.d.ts +0 -40
- package/dist/spectral/BandsAndDos.svelte +0 -128
- package/dist/spectral/BandsAndDos.svelte.d.ts +0 -18
- package/dist/spectral/BrillouinBandsDos.svelte +0 -248
- package/dist/spectral/BrillouinBandsDos.svelte.d.ts +0 -20
- package/dist/spectral/Dos.svelte +0 -697
- package/dist/spectral/Dos.svelte.d.ts +0 -29
- package/dist/spectral/helpers.d.ts +0 -117
- package/dist/spectral/helpers.js +0 -1023
- package/dist/spectral/index.d.ts +0 -6
- package/dist/spectral/index.js +0 -7
- package/dist/spectral/types.d.ts +0 -84
- package/dist/spectral/types.js +0 -2
- package/dist/state.svelte.d.ts +0 -25
- package/dist/state.svelte.js +0 -45
- package/dist/structure/Arrow.svelte +0 -72
- package/dist/structure/Arrow.svelte.d.ts +0 -15
- package/dist/structure/AtomLegend.svelte +0 -798
- package/dist/structure/AtomLegend.svelte.d.ts +0 -34
- package/dist/structure/Bond.svelte +0 -140
- package/dist/structure/Bond.svelte.d.ts +0 -9
- package/dist/structure/CanvasTooltip.svelte +0 -33
- package/dist/structure/CanvasTooltip.svelte.d.ts +0 -12
- package/dist/structure/CellSelect.svelte +0 -351
- package/dist/structure/CellSelect.svelte.d.ts +0 -13
- package/dist/structure/Cylinder.svelte +0 -45
- package/dist/structure/Cylinder.svelte.d.ts +0 -10
- package/dist/structure/Lattice.svelte +0 -196
- package/dist/structure/Lattice.svelte.d.ts +0 -17
- package/dist/structure/Structure.svelte +0 -1857
- package/dist/structure/Structure.svelte.d.ts +0 -83
- package/dist/structure/StructureControls.svelte +0 -1184
- package/dist/structure/StructureControls.svelte.d.ts +0 -31
- package/dist/structure/StructureExportPane.svelte +0 -251
- package/dist/structure/StructureExportPane.svelte.d.ts +0 -17
- package/dist/structure/StructureInfoPane.svelte +0 -434
- package/dist/structure/StructureInfoPane.svelte.d.ts +0 -18
- package/dist/structure/StructureScene.svelte +0 -1574
- package/dist/structure/StructureScene.svelte.d.ts +0 -104
- package/dist/structure/atom-properties.d.ts +0 -37
- package/dist/structure/atom-properties.js +0 -198
- package/dist/structure/bonding.d.ts +0 -33
- package/dist/structure/bonding.js +0 -304
- package/dist/structure/export.d.ts +0 -20
- package/dist/structure/export.js +0 -725
- package/dist/structure/ferrox-wasm-types.d.ts +0 -46
- package/dist/structure/ferrox-wasm-types.js +0 -18
- package/dist/structure/ferrox-wasm.d.ts +0 -94
- package/dist/structure/ferrox-wasm.js +0 -249
- package/dist/structure/index.d.ts +0 -110
- package/dist/structure/index.js +0 -168
- package/dist/structure/measure.d.ts +0 -6
- package/dist/structure/measure.js +0 -29
- package/dist/structure/parse.d.ts +0 -65
- package/dist/structure/parse.js +0 -1374
- package/dist/structure/partial-occupancy.d.ts +0 -25
- package/dist/structure/partial-occupancy.js +0 -99
- package/dist/structure/pbc.d.ts +0 -9
- package/dist/structure/pbc.js +0 -123
- package/dist/structure/supercell.d.ts +0 -8
- package/dist/structure/supercell.js +0 -137
- package/dist/structure/validation.d.ts +0 -2
- package/dist/structure/validation.js +0 -10
- package/dist/symmetry/SymmetryStats.svelte +0 -226
- package/dist/symmetry/SymmetryStats.svelte.d.ts +0 -21
- package/dist/symmetry/WyckoffTable.svelte +0 -113
- package/dist/symmetry/WyckoffTable.svelte.d.ts +0 -11
- package/dist/symmetry/cell-transform.d.ts +0 -12
- package/dist/symmetry/cell-transform.js +0 -77
- package/dist/symmetry/index.d.ts +0 -43
- package/dist/symmetry/index.js +0 -229
- package/dist/symmetry/spacegroups.d.ts +0 -9
- package/dist/symmetry/spacegroups.js +0 -394
- package/dist/table/HeatmapTable.svelte +0 -1854
- package/dist/table/HeatmapTable.svelte.d.ts +0 -49
- package/dist/table/ToggleMenu.svelte +0 -376
- package/dist/table/ToggleMenu.svelte.d.ts +0 -11
- package/dist/table/index.d.ts +0 -74
- package/dist/table/index.js +0 -38
- package/dist/theme/ThemeControl.svelte +0 -53
- package/dist/theme/ThemeControl.svelte.d.ts +0 -9
- package/dist/theme/index.d.ts +0 -29
- package/dist/theme/index.js +0 -79
- package/dist/theme/themes.mjs +0 -285
- package/dist/time.d.ts +0 -4
- package/dist/time.js +0 -70
- package/dist/tooltip/TooltipContent.svelte +0 -58
- package/dist/tooltip/TooltipContent.svelte.d.ts +0 -31
- package/dist/tooltip/index.d.ts +0 -2
- package/dist/tooltip/index.js +0 -2
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/tooltip/types.js +0 -1
- package/dist/trajectory/Trajectory.svelte +0 -1517
- package/dist/trajectory/Trajectory.svelte.d.ts +0 -77
- package/dist/trajectory/TrajectoryError.svelte +0 -128
- package/dist/trajectory/TrajectoryError.svelte.d.ts +0 -13
- package/dist/trajectory/TrajectoryExportPane.svelte +0 -357
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +0 -17
- package/dist/trajectory/TrajectoryInfoPane.svelte +0 -387
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +0 -17
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -7
- package/dist/trajectory/extract.d.ts +0 -5
- package/dist/trajectory/extract.js +0 -162
- package/dist/trajectory/format-detect.d.ts +0 -9
- package/dist/trajectory/format-detect.js +0 -76
- package/dist/trajectory/frame-reader.d.ts +0 -17
- package/dist/trajectory/frame-reader.js +0 -332
- package/dist/trajectory/helpers.d.ts +0 -14
- package/dist/trajectory/helpers.js +0 -172
- package/dist/trajectory/index.d.ts +0 -63
- package/dist/trajectory/index.js +0 -126
- package/dist/trajectory/parse/ase.d.ts +0 -2
- package/dist/trajectory/parse/ase.js +0 -77
- package/dist/trajectory/parse/hdf5.d.ts +0 -2
- package/dist/trajectory/parse/hdf5.js +0 -129
- package/dist/trajectory/parse/index.d.ts +0 -12
- package/dist/trajectory/parse/index.js +0 -299
- package/dist/trajectory/parse/lammps.d.ts +0 -5
- package/dist/trajectory/parse/lammps.js +0 -179
- package/dist/trajectory/parse/vasp.d.ts +0 -2
- package/dist/trajectory/parse/vasp.js +0 -68
- package/dist/trajectory/parse/xyz.d.ts +0 -2
- package/dist/trajectory/parse/xyz.js +0 -110
- package/dist/trajectory/plotting.d.ts +0 -28
- package/dist/trajectory/plotting.js +0 -423
- package/dist/trajectory/types.d.ts +0 -11
- package/dist/trajectory/types.js +0 -1
- package/dist/utils.d.ts +0 -5
- package/dist/utils.js +0 -36
- package/dist/xrd/XrdPlot.svelte +0 -615
- package/dist/xrd/XrdPlot.svelte.d.ts +0 -28
- package/dist/xrd/broadening.d.ts +0 -20
- package/dist/xrd/broadening.js +0 -97
- package/dist/xrd/calc-xrd.d.ts +0 -37
- package/dist/xrd/calc-xrd.js +0 -337
- package/dist/xrd/index.d.ts +0 -37
- package/dist/xrd/index.js +0 -4
- package/dist/xrd/parse.d.ts +0 -13
- package/dist/xrd/parse.js +0 -749
- /package/dist/{EmptyState.svelte → src/lib/EmptyState.svelte} +0 -0
- /package/dist/{Icon.svelte → src/lib/Icon.svelte} +0 -0
- /package/dist/{chempot-diagram → src/lib/chempot-diagram}/ChemPotScene3D.svelte +0 -0
- /package/dist/{colors → src/lib/colors}/alloy-colors.json +0 -0
- /package/dist/{colors → src/lib/colors}/dark-mode-colors.json +0 -0
- /package/dist/{colors → src/lib/colors}/jmol-colors.json +0 -0
- /package/dist/{colors → src/lib/colors}/muted-colors.json +0 -0
- /package/dist/{colors → src/lib/colors}/pastel-colors.json +0 -0
- /package/dist/{colors → src/lib/colors}/vesta-colors.json +0 -0
- /package/dist/{element → src/lib/element}/Nucleus.svelte +0 -0
- /package/dist/{element → src/lib/element}/data.json +0 -0
- /package/dist/{element → src/lib/element}/data.json.gz +0 -0
- /package/dist/{element → src/lib/element}/data.schema.json +0 -0
- /package/dist/{element-image-urls.json → src/lib/element-image-urls.json} +0 -0
- /package/dist/{feedback → src/lib/feedback}/Spinner.svelte +0 -0
- /package/dist/{feedback → src/lib/feedback}/StatusMessage.svelte +0 -0
- /package/dist/{periodic-table → src/lib/periodic-table}/TableInset.svelte +0 -0
- /package/dist/{plot → src/lib/plot}/ReferenceLine.svelte +0 -0
- /package/dist/{xrd → src/lib/xrd}/atomic_scattering_params.json +0 -0
|
@@ -1,1857 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { ColorSchemeName } from '../colors'
|
|
3
|
-
import { ELEMENT_COLOR_SCHEMES } from '../colors'
|
|
4
|
-
import type { ShowControlsProp } from '../controls'
|
|
5
|
-
import { normalize_show_controls } from '../controls'
|
|
6
|
-
import type { ElementSymbol } from '../element'
|
|
7
|
-
import { StatusMessage } from '../feedback'
|
|
8
|
-
import Spinner from '../feedback/Spinner.svelte'
|
|
9
|
-
import Icon from '../Icon.svelte'
|
|
10
|
-
import { create_file_drop_handler, load_from_url } from '../io'
|
|
11
|
-
import { parse_volumetric_file } from '../isosurface/parse'
|
|
12
|
-
import type { IsosurfaceSettings, VolumetricData } from '../isosurface/types'
|
|
13
|
-
import {
|
|
14
|
-
auto_isosurface_settings,
|
|
15
|
-
DEFAULT_ISOSURFACE_SETTINGS,
|
|
16
|
-
tile_volumetric_data,
|
|
17
|
-
} from '../isosurface/types'
|
|
18
|
-
import { ELEM_SYMBOLS } from '../labels'
|
|
19
|
-
import { set_fullscreen_bg, toggle_fullscreen } from '../layout'
|
|
20
|
-
import type { Vec3 } from '../math'
|
|
21
|
-
import { create_cart_to_frac, create_frac_to_cart } from '../math'
|
|
22
|
-
import { DEFAULTS } from '../settings'
|
|
23
|
-
import { sanitize_html } from '../sanitize'
|
|
24
|
-
import { colors } from '../state.svelte'
|
|
25
|
-
import type { AnyStructure, Crystal, MeasureMode } from './'
|
|
26
|
-
import {
|
|
27
|
-
default_vector_configs,
|
|
28
|
-
get_element_counts,
|
|
29
|
-
get_pbc_image_sites,
|
|
30
|
-
get_structure_vector_keys,
|
|
31
|
-
} from './'
|
|
32
|
-
import { wrap_to_unit_cell } from './pbc'
|
|
33
|
-
import {
|
|
34
|
-
is_valid_supercell_input,
|
|
35
|
-
make_supercell,
|
|
36
|
-
parse_supercell_scaling,
|
|
37
|
-
} from './supercell'
|
|
38
|
-
import type { CellType, SymmetrySettings } from '../symmetry'
|
|
39
|
-
import * as symmetry from '../symmetry'
|
|
40
|
-
import { transform_cell } from '../symmetry'
|
|
41
|
-
import type { MoyoDataset } from '@spglib/moyo-wasm'
|
|
42
|
-
import { Canvas } from '@threlte/core'
|
|
43
|
-
import type { ComponentProps, Snippet } from 'svelte'
|
|
44
|
-
import { untrack } from 'svelte'
|
|
45
|
-
import { click_outside, tooltip } from 'svelte-multiselect'
|
|
46
|
-
import type { HTMLAttributes } from 'svelte/elements'
|
|
47
|
-
import { SvelteMap, SvelteSet } from 'svelte/reactivity'
|
|
48
|
-
import type { Camera, OrthographicCamera, Scene } from 'three'
|
|
49
|
-
import type { AtomColorConfig } from './atom-properties'
|
|
50
|
-
import { get_property_colors } from './atom-properties'
|
|
51
|
-
import AtomLegend from './AtomLegend.svelte'
|
|
52
|
-
import CellSelect from './CellSelect.svelte'
|
|
53
|
-
import type { StructureHandlerData } from './index'
|
|
54
|
-
import { MAX_SELECTED_SITES } from './measure'
|
|
55
|
-
import { normalize_fractional_coords, parse_any_structure } from './parse'
|
|
56
|
-
import StructureControls from './StructureControls.svelte'
|
|
57
|
-
import StructureExportPane from './StructureExportPane.svelte'
|
|
58
|
-
import StructureInfoPane from './StructureInfoPane.svelte'
|
|
59
|
-
import StructureScene from './StructureScene.svelte'
|
|
60
|
-
|
|
61
|
-
// Type alias for event handlers to reduce verbosity
|
|
62
|
-
type EventHandler = (data: StructureHandlerData) => void
|
|
63
|
-
|
|
64
|
-
// Local reactive state for scene and lattice props. Deeply reactive so nested mutations propagate.
|
|
65
|
-
// Deep-clone to prevent mutations from leaking to global defaults across component instances.
|
|
66
|
-
let scene_props = $state(
|
|
67
|
-
structuredClone(DEFAULTS.structure) as typeof DEFAULTS.structure & {
|
|
68
|
-
camera_target?: Vec3
|
|
69
|
-
},
|
|
70
|
-
)
|
|
71
|
-
let lattice_props = $state({
|
|
72
|
-
cell_edge_opacity: DEFAULTS.structure.cell_edge_opacity,
|
|
73
|
-
cell_surface_opacity: DEFAULTS.structure.cell_surface_opacity,
|
|
74
|
-
cell_edge_color: DEFAULTS.structure.cell_edge_color,
|
|
75
|
-
cell_surface_color: DEFAULTS.structure.cell_surface_color,
|
|
76
|
-
cell_edge_width: DEFAULTS.structure.cell_edge_width,
|
|
77
|
-
show_cell_vectors: DEFAULTS.structure.show_cell_vectors,
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
let {
|
|
81
|
-
structure = $bindable(),
|
|
82
|
-
scene_props: scene_props_in = $bindable(),
|
|
83
|
-
lattice_props: lattice_props_in = $bindable(),
|
|
84
|
-
controls_open = $bindable(false),
|
|
85
|
-
info_pane_open = $bindable(false),
|
|
86
|
-
enable_measure_mode = $bindable(true),
|
|
87
|
-
measure_mode = $bindable<MeasureMode>(`distance`),
|
|
88
|
-
background_color = $bindable(),
|
|
89
|
-
background_opacity = $bindable(0.1),
|
|
90
|
-
show_controls,
|
|
91
|
-
fullscreen = $bindable(false),
|
|
92
|
-
wrapper = $bindable(),
|
|
93
|
-
width = $bindable(0),
|
|
94
|
-
height = $bindable(0),
|
|
95
|
-
reset_text = `Reset camera (or double-click)`,
|
|
96
|
-
color_scheme = $bindable(`Vesta`),
|
|
97
|
-
atom_color_config = $bindable({
|
|
98
|
-
mode: DEFAULTS.structure.atom_color_mode,
|
|
99
|
-
scale: DEFAULTS.structure.atom_color_scale,
|
|
100
|
-
scale_type: DEFAULTS.structure.atom_color_scale_type,
|
|
101
|
-
}),
|
|
102
|
-
hovered = $bindable(false),
|
|
103
|
-
dragover = $bindable(false),
|
|
104
|
-
allow_file_drop = true,
|
|
105
|
-
enable_info_pane = true,
|
|
106
|
-
png_dpi = $bindable(150),
|
|
107
|
-
show_image_atoms = $bindable(true),
|
|
108
|
-
supercell_scaling = $bindable(`1x1x1`),
|
|
109
|
-
fullscreen_toggle = DEFAULTS.structure.fullscreen_toggle,
|
|
110
|
-
bottom_left,
|
|
111
|
-
data_url,
|
|
112
|
-
structure_string,
|
|
113
|
-
on_file_drop,
|
|
114
|
-
spinner_props = {},
|
|
115
|
-
loading = $bindable(false),
|
|
116
|
-
error_msg = $bindable(),
|
|
117
|
-
performance_mode = $bindable(`quality`),
|
|
118
|
-
// expose selected site indices for external control/highlighting
|
|
119
|
-
selected_sites = $bindable([]),
|
|
120
|
-
// expose measured site indices for overlays/labels
|
|
121
|
-
measured_sites = $bindable([]),
|
|
122
|
-
// expose the displayed structure (with image atoms and supercell) for external use
|
|
123
|
-
displayed_structure = $bindable(),
|
|
124
|
-
// Track hidden elements across component lifecycle
|
|
125
|
-
hidden_elements = $bindable(new SvelteSet<ElementSymbol>()),
|
|
126
|
-
// Track hidden property values (e.g. Wyckoff positions, coordination numbers)
|
|
127
|
-
hidden_prop_vals = $bindable(new SvelteSet<number | string>()),
|
|
128
|
-
// Per-element radius overrides (absolute values in Angstroms)
|
|
129
|
-
element_radius_overrides = $bindable<Partial<Record<ElementSymbol, number>>>({}),
|
|
130
|
-
// Per-site radius overrides (absolute values in Angstroms)
|
|
131
|
-
site_radius_overrides = $bindable<SvelteMap<number, number>>(new SvelteMap()),
|
|
132
|
-
// Symmetry analysis data (bindable for external access)
|
|
133
|
-
sym_data = $bindable(null),
|
|
134
|
-
// Symmetry analysis settings (bindable for external control)
|
|
135
|
-
symmetry_settings = $bindable(symmetry.default_sym_settings),
|
|
136
|
-
// Map element symbols to different elements (e.g. {'H': 'Na', 'He': 'Cl'})
|
|
137
|
-
// Useful for LAMMPS files where atom types are mapped to H, He, Li by default
|
|
138
|
-
element_mapping = $bindable(),
|
|
139
|
-
// Cell type: original, conventional, or primitive (requires symmetry analysis)
|
|
140
|
-
cell_type = $bindable(`original`),
|
|
141
|
-
// Volumetric data for isosurface rendering (parsed from CHGCAR or .cube files)
|
|
142
|
-
volumetric_data = $bindable<VolumetricData[]>(),
|
|
143
|
-
// Isosurface rendering settings
|
|
144
|
-
isosurface_settings = $bindable<IsosurfaceSettings>({
|
|
145
|
-
...DEFAULT_ISOSURFACE_SETTINGS,
|
|
146
|
-
}),
|
|
147
|
-
// Active volume index when multiple volumes are present
|
|
148
|
-
active_volume_idx = $bindable(0),
|
|
149
|
-
children,
|
|
150
|
-
top_right_controls,
|
|
151
|
-
on_file_load,
|
|
152
|
-
on_error,
|
|
153
|
-
on_fullscreen_change,
|
|
154
|
-
on_camera_move,
|
|
155
|
-
on_camera_reset,
|
|
156
|
-
...rest
|
|
157
|
-
}:
|
|
158
|
-
& {
|
|
159
|
-
structure?: AnyStructure
|
|
160
|
-
scene_props?: ComponentProps<typeof StructureScene>
|
|
161
|
-
/**
|
|
162
|
-
* Controls visibility configuration.
|
|
163
|
-
* - 'always': controls always visible
|
|
164
|
-
* - 'hover': controls visible on component hover (default)
|
|
165
|
-
* - 'never': controls never visible
|
|
166
|
-
* - object: { mode, hidden, style } for fine-grained control
|
|
167
|
-
*
|
|
168
|
-
* Control names: 'reset-camera', 'fullscreen', 'measure-mode', 'info-pane', 'export-pane', 'controls'
|
|
169
|
-
*/
|
|
170
|
-
show_controls?: ShowControlsProp
|
|
171
|
-
fullscreen?: boolean
|
|
172
|
-
// bindable width of the canvas
|
|
173
|
-
width?: number
|
|
174
|
-
// bindable height of the canvas
|
|
175
|
-
height?: number
|
|
176
|
-
// Canvas wrapper element (for export pane)
|
|
177
|
-
wrapper?: HTMLDivElement
|
|
178
|
-
// PNG export DPI setting
|
|
179
|
-
png_dpi?: number
|
|
180
|
-
reset_text?: string
|
|
181
|
-
hovered?: boolean
|
|
182
|
-
dragover?: boolean
|
|
183
|
-
allow_file_drop?: boolean
|
|
184
|
-
enable_info_pane?: boolean
|
|
185
|
-
enable_measure_mode?: boolean
|
|
186
|
-
measure_mode?: MeasureMode
|
|
187
|
-
info_pane_open?: boolean
|
|
188
|
-
fullscreen_toggle?: Snippet<[{ fullscreen: boolean }]> | boolean
|
|
189
|
-
bottom_left?: Snippet<[{ structure?: AnyStructure }]>
|
|
190
|
-
top_right_controls?: Snippet // Additional controls to render at the end of the control buttons row
|
|
191
|
-
data_url?: string // URL to load structure from (alternative to providing structure directly)
|
|
192
|
-
// Generic callback for when files are dropped - receives raw content and filename
|
|
193
|
-
on_file_drop?: (content: string | ArrayBuffer, filename: string) => void
|
|
194
|
-
// spinner props (passed to Spinner component)
|
|
195
|
-
spinner_props?: ComponentProps<typeof Spinner>
|
|
196
|
-
loading?: boolean
|
|
197
|
-
error_msg?: string
|
|
198
|
-
// Performance mode: 'quality' (default) or 'speed' for large structures
|
|
199
|
-
performance_mode?: `quality` | `speed`
|
|
200
|
-
// allow parent components to control highlighted/selected site indices
|
|
201
|
-
selected_sites?: number[]
|
|
202
|
-
// explicit measured sites for distance/angle overlays
|
|
203
|
-
measured_sites?: number[]
|
|
204
|
-
// expose the displayed structure (with image atoms and/or supercell) for external use
|
|
205
|
-
displayed_structure?: AnyStructure
|
|
206
|
-
// Track which elements are hidden (bindable across frames in trajectories)
|
|
207
|
-
hidden_elements?: Set<ElementSymbol>
|
|
208
|
-
// Track which property values are hidden (e.g. Wyckoff positions, coordination numbers)
|
|
209
|
-
hidden_prop_vals?: Set<number | string>
|
|
210
|
-
// Per-element radius overrides (absolute values in Angstroms)
|
|
211
|
-
element_radius_overrides?: Partial<Record<ElementSymbol, number>>
|
|
212
|
-
// Per-site radius overrides (absolute values in Angstroms)
|
|
213
|
-
// Accepts Map or SvelteMap for flexibility with external callers
|
|
214
|
-
site_radius_overrides?: Map<number, number> | SvelteMap<number, number>
|
|
215
|
-
// Symmetry analysis data (bindable for external access)
|
|
216
|
-
sym_data?: MoyoDataset | null
|
|
217
|
-
// Symmetry analysis settings (bindable for external control)
|
|
218
|
-
symmetry_settings?: Partial<SymmetrySettings>
|
|
219
|
-
// Map element symbols to different elements (e.g. {'H': 'Na', 'He': 'Cl'})
|
|
220
|
-
element_mapping?: Partial<Record<ElementSymbol, ElementSymbol>>
|
|
221
|
-
// Cell type: original, conventional, or primitive (requires symmetry analysis)
|
|
222
|
-
cell_type?: CellType
|
|
223
|
-
// Volumetric data for isosurface rendering (parsed from CHGCAR or .cube files)
|
|
224
|
-
volumetric_data?: VolumetricData[]
|
|
225
|
-
// Isosurface rendering settings
|
|
226
|
-
isosurface_settings?: IsosurfaceSettings
|
|
227
|
-
// Active volume index when multiple volumes are present
|
|
228
|
-
active_volume_idx?: number
|
|
229
|
-
// structure content as string (alternative to providing structure directly or via data_url)
|
|
230
|
-
structure_string?: string
|
|
231
|
-
// Atom coloring configuration
|
|
232
|
-
atom_color_config?: Partial<AtomColorConfig>
|
|
233
|
-
children?: Snippet<[{ structure?: AnyStructure; fullscreen: boolean }]>
|
|
234
|
-
on_file_load?: EventHandler
|
|
235
|
-
on_error?: EventHandler
|
|
236
|
-
on_fullscreen_change?: EventHandler
|
|
237
|
-
on_camera_move?: EventHandler
|
|
238
|
-
on_camera_reset?: EventHandler
|
|
239
|
-
}
|
|
240
|
-
& Omit<ComponentProps<typeof StructureControls>, `children` | `onclose`>
|
|
241
|
-
& Omit<HTMLAttributes<HTMLDivElement>, `children`> = $props()
|
|
242
|
-
|
|
243
|
-
// Initialize models from incoming props; mutations come from UI controls; we mirror into local dicts (NOTE only doing shallow merge)
|
|
244
|
-
$effect.pre(() => {
|
|
245
|
-
if (scene_props_in && typeof scene_props_in === `object`) {
|
|
246
|
-
Object.assign(scene_props, scene_props_in)
|
|
247
|
-
}
|
|
248
|
-
if (lattice_props_in && typeof lattice_props_in === `object`) {
|
|
249
|
-
Object.assign(lattice_props, lattice_props_in)
|
|
250
|
-
}
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
// Load structure from URL when data_url is provided
|
|
254
|
-
$effect(() => {
|
|
255
|
-
if (data_url && !structure) {
|
|
256
|
-
loading = true
|
|
257
|
-
error_msg = undefined
|
|
258
|
-
|
|
259
|
-
load_from_url(data_url, (content, filename) => {
|
|
260
|
-
if (on_file_drop) on_file_drop(content, filename)
|
|
261
|
-
else {
|
|
262
|
-
// Parse structure internally when no handler provided
|
|
263
|
-
try {
|
|
264
|
-
const text_content = content instanceof ArrayBuffer
|
|
265
|
-
? new TextDecoder().decode(content)
|
|
266
|
-
: content
|
|
267
|
-
const parsed = parse_file_content(text_content, filename)
|
|
268
|
-
emit_file_load_event(parsed, filename, content)
|
|
269
|
-
} catch (error) {
|
|
270
|
-
error_msg = `Failed to parse structure: ${
|
|
271
|
-
error instanceof Error ? error.message : String(error)
|
|
272
|
-
}`
|
|
273
|
-
on_error?.({ error_msg, filename })
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
})
|
|
277
|
-
.then(() => loading = false)
|
|
278
|
-
.catch((error: Error) => {
|
|
279
|
-
console.error(`Failed to load structure from URL:`, error)
|
|
280
|
-
error_msg = `Failed to load structure: ${error.message}`
|
|
281
|
-
loading = false
|
|
282
|
-
on_error?.({ error_msg, filename: data_url })
|
|
283
|
-
})
|
|
284
|
-
}
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
$effect(() => { // Parse structure from string when structure_string is provided
|
|
288
|
-
if (!structure_string || data_url) return
|
|
289
|
-
loading = true
|
|
290
|
-
error_msg = undefined
|
|
291
|
-
clear_camera_state()
|
|
292
|
-
try {
|
|
293
|
-
const parsed = parse_any_structure(structure_string, `string`)
|
|
294
|
-
if (parsed) {
|
|
295
|
-
structure = parsed
|
|
296
|
-
untrack(() => emit_file_load_event(parsed, `string`, structure_string))
|
|
297
|
-
} else {
|
|
298
|
-
throw new Error(`Failed to parse structure from string`)
|
|
299
|
-
}
|
|
300
|
-
} catch (err) {
|
|
301
|
-
error_msg = `Failed to parse structure from string: ${
|
|
302
|
-
err instanceof Error ? err.message : String(err)
|
|
303
|
-
}`
|
|
304
|
-
untrack(() => on_error?.({ error_msg, filename: `string` }))
|
|
305
|
-
} finally {
|
|
306
|
-
loading = false
|
|
307
|
-
}
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
// Auto-populate vector_configs when structure has vector data (force, magmom, spin, etc.)
|
|
311
|
-
// Skip if configs were externally provided. Clear auto-generated configs on structure change.
|
|
312
|
-
let vectors_auto_populated_for: AnyStructure | undefined = undefined
|
|
313
|
-
let last_auto_configs: Record<string, unknown> | undefined = undefined
|
|
314
|
-
|
|
315
|
-
$effect(() => {
|
|
316
|
-
if (!structure?.sites || structure === vectors_auto_populated_for) return
|
|
317
|
-
const keys = get_structure_vector_keys(structure)
|
|
318
|
-
// Clear auto-generated configs from previous structure; preserve externally-modified ones
|
|
319
|
-
const existing = scene_props.vector_configs
|
|
320
|
-
if (last_auto_configs && existing === last_auto_configs) {
|
|
321
|
-
scene_props.vector_configs = {}
|
|
322
|
-
last_auto_configs = undefined
|
|
323
|
-
} else if (existing && Object.keys(existing).length > 0) {
|
|
324
|
-
vectors_auto_populated_for = structure
|
|
325
|
-
return
|
|
326
|
-
}
|
|
327
|
-
vectors_auto_populated_for = structure
|
|
328
|
-
if (keys.length === 0) return
|
|
329
|
-
const configs = default_vector_configs(keys)
|
|
330
|
-
scene_props.vector_configs = configs
|
|
331
|
-
// Read back the proxied reference — Svelte 5 $state wraps objects in
|
|
332
|
-
// proxies, so `scene_props.vector_configs !== configs`. Storing the proxy
|
|
333
|
-
// lets the identity check above detect unmodified auto-configs.
|
|
334
|
-
// See https://svelte.dev/e/state_proxy_equality_mismatch
|
|
335
|
-
last_auto_configs = scene_props.vector_configs
|
|
336
|
-
scene_props.vector_scale ??= DEFAULTS.structure.vector_scale
|
|
337
|
-
scene_props.vector_color ??= DEFAULTS.structure.vector_color
|
|
338
|
-
})
|
|
339
|
-
|
|
340
|
-
// Optimize scene props for performance based on structure size and mode
|
|
341
|
-
$effect(() => {
|
|
342
|
-
if (structure?.sites && performance_mode === `speed`) {
|
|
343
|
-
const site_count = structure.sites.length
|
|
344
|
-
const current_sphere_segments = scene_props.sphere_segments || 20
|
|
345
|
-
|
|
346
|
-
// Reduce sphere segments for large structures in speed mode
|
|
347
|
-
if (site_count > 200) {
|
|
348
|
-
scene_props.sphere_segments = Math.min(current_sphere_segments, 12)
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
})
|
|
352
|
-
|
|
353
|
-
$effect(() => {
|
|
354
|
-
colors.element = ELEMENT_COLOR_SCHEMES[color_scheme as ColorSchemeName]
|
|
355
|
-
})
|
|
356
|
-
|
|
357
|
-
// Compute property-based colors for legend display
|
|
358
|
-
let property_colors = $derived(
|
|
359
|
-
get_property_colors(
|
|
360
|
-
structure,
|
|
361
|
-
atom_color_config,
|
|
362
|
-
scene_props.bonding_strategy,
|
|
363
|
-
sym_data,
|
|
364
|
-
),
|
|
365
|
-
)
|
|
366
|
-
|
|
367
|
-
let symmetry_run_id = 0
|
|
368
|
-
let symmetry_error = $state<string>()
|
|
369
|
-
let last_symmetry_structure_ref: AnyStructure | null = null
|
|
370
|
-
|
|
371
|
-
// Trigger symmetry analysis when structure is loaded or settings change.
|
|
372
|
-
// Skip during atom drags — symmetry doesn't change from moving atoms,
|
|
373
|
-
// and WASM analysis on every drag frame causes severe frame drops.
|
|
374
|
-
$effect(() => {
|
|
375
|
-
if (dragging_atoms) return
|
|
376
|
-
if (!structure || !(`lattice` in structure)) {
|
|
377
|
-
untrack(() => {
|
|
378
|
-
sym_data = null
|
|
379
|
-
symmetry_error = undefined
|
|
380
|
-
})
|
|
381
|
-
last_symmetry_structure_ref = null
|
|
382
|
-
return
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const current_structure = structure
|
|
386
|
-
const structure_changed = current_structure !== last_symmetry_structure_ref
|
|
387
|
-
if (structure_changed) {
|
|
388
|
-
untrack(() => {
|
|
389
|
-
sym_data = null
|
|
390
|
-
symmetry_error = undefined
|
|
391
|
-
})
|
|
392
|
-
last_symmetry_structure_ref = current_structure
|
|
393
|
-
} else {
|
|
394
|
-
// Keep previous symmetry data while recomputing so bound consumers
|
|
395
|
-
// (e.g. SymmetryStats inputs) do not unmount and lose focus.
|
|
396
|
-
untrack(() => symmetry_error = undefined)
|
|
397
|
-
}
|
|
398
|
-
const run_id = ++symmetry_run_id
|
|
399
|
-
// Destructure symmetry_settings to ensure Svelte tracks changes to symprec and algo
|
|
400
|
-
// (reading just the object reference isn't sufficient for fine-grained reactivity)
|
|
401
|
-
const { symprec, algo } = symmetry_settings ?? symmetry.default_sym_settings
|
|
402
|
-
const current_settings = { symprec, algo }
|
|
403
|
-
// Skip symmetry auto-analysis in unit tests; happy-dom can't fetch WASM assets
|
|
404
|
-
if (typeof process !== `undefined` && process.env?.VITEST) return
|
|
405
|
-
|
|
406
|
-
symmetry.ensure_moyo_wasm_ready()
|
|
407
|
-
.then(() =>
|
|
408
|
-
run_id === symmetry_run_id
|
|
409
|
-
? symmetry.analyze_structure_symmetry(current_structure, current_settings)
|
|
410
|
-
: null
|
|
411
|
-
)
|
|
412
|
-
.then((data) => {
|
|
413
|
-
if (data && run_id === symmetry_run_id) {
|
|
414
|
-
untrack(() => sym_data = data)
|
|
415
|
-
}
|
|
416
|
-
})
|
|
417
|
-
.catch((err) => {
|
|
418
|
-
if (run_id === symmetry_run_id) {
|
|
419
|
-
untrack(() => sym_data = null)
|
|
420
|
-
symmetry_error = `Symmetry analysis failed: ${err?.message || err}`
|
|
421
|
-
console.error(`Symmetry analysis failed:`, err)
|
|
422
|
-
}
|
|
423
|
-
})
|
|
424
|
-
})
|
|
425
|
-
|
|
426
|
-
let measure_menu_open = $state(false)
|
|
427
|
-
let export_pane_open = $state(false)
|
|
428
|
-
|
|
429
|
-
// Bond customization state
|
|
430
|
-
let added_bonds = $state<[number, number][]>([])
|
|
431
|
-
let removed_bonds = $state<[number, number][]>([])
|
|
432
|
-
|
|
433
|
-
// === Edit-atoms mode state ===
|
|
434
|
-
let dragging_atoms = $state(false)
|
|
435
|
-
let undo_stack = $state<AnyStructure[]>([])
|
|
436
|
-
let redo_stack = $state<AnyStructure[]>([])
|
|
437
|
-
const MAX_HISTORY = 20
|
|
438
|
-
// Flag set before internal edits (undo/redo/delete/add/move) to distinguish
|
|
439
|
-
// them from external structure changes (file load, trajectory step, etc.)
|
|
440
|
-
let is_internal_edit = false
|
|
441
|
-
// Add-atom sub-mode state (bound to StructureScene)
|
|
442
|
-
let add_atom_mode = $state(false)
|
|
443
|
-
let add_element = $state<ElementSymbol>(`C` as ElementSymbol)
|
|
444
|
-
let canvas_cursor = $state(`default`)
|
|
445
|
-
let change_element_mode = $state(false)
|
|
446
|
-
let change_element_value = $state(``)
|
|
447
|
-
// Ephemeral toast message for edit operations
|
|
448
|
-
let toast_msg = $state<string | null>(null)
|
|
449
|
-
let toast_timer: ReturnType<typeof setTimeout> | undefined
|
|
450
|
-
function show_toast(msg: string, duration_ms = 2000) {
|
|
451
|
-
clearTimeout(toast_timer)
|
|
452
|
-
toast_msg = msg
|
|
453
|
-
toast_timer = setTimeout(() => (toast_msg = null), duration_ms)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// Normalize and validate element symbol (e.g. "fe" → "Fe", "Xx" → null)
|
|
457
|
-
function normalize_element(input: string): ElementSymbol | null {
|
|
458
|
-
const normalized = (input.charAt(0).toUpperCase() +
|
|
459
|
-
input.slice(1).toLowerCase()) as ElementSymbol
|
|
460
|
-
return ELEM_SYMBOLS.includes(normalized) ? normalized : null
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
function clear_selection() {
|
|
464
|
-
selected_sites = []
|
|
465
|
-
measured_sites = []
|
|
466
|
-
dragging_atoms = false
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
function push_undo() {
|
|
470
|
-
if (!structure) return
|
|
471
|
-
if (undo_stack.length >= MAX_HISTORY) {
|
|
472
|
-
undo_stack.splice(0, undo_stack.length - MAX_HISTORY + 1)
|
|
473
|
-
}
|
|
474
|
-
undo_stack.push($state.snapshot(structure) as AnyStructure)
|
|
475
|
-
redo_stack.length = 0
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
// Shared undo/redo: pop from `source`, push current state onto `target`
|
|
479
|
-
function apply_history(source: AnyStructure[], target: AnyStructure[]) {
|
|
480
|
-
if (source.length === 0 || !structure) return
|
|
481
|
-
const restored = source.pop()
|
|
482
|
-
if (!restored) return
|
|
483
|
-
is_internal_edit = true
|
|
484
|
-
target.push($state.snapshot(structure) as AnyStructure)
|
|
485
|
-
structure = restored
|
|
486
|
-
clear_selection()
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
const undo = () => apply_history(undo_stack, redo_stack)
|
|
490
|
-
const redo = () => apply_history(redo_stack, undo_stack)
|
|
491
|
-
|
|
492
|
-
// Clear undo/redo stacks when structure changes externally (file load, etc.)
|
|
493
|
-
// Internal edits set is_internal_edit=true before modifying structure.
|
|
494
|
-
// This $effect runs after microtask, so the flag is still set from the edit.
|
|
495
|
-
$effect(() => {
|
|
496
|
-
// Track structure to re-run when it changes
|
|
497
|
-
void structure
|
|
498
|
-
if (is_internal_edit) {
|
|
499
|
-
is_internal_edit = false
|
|
500
|
-
return
|
|
501
|
-
}
|
|
502
|
-
// External change — clear history and stale edit-atoms state
|
|
503
|
-
untrack(() => {
|
|
504
|
-
if (undo_stack.length > 0 || redo_stack.length > 0) {
|
|
505
|
-
undo_stack = []
|
|
506
|
-
redo_stack = []
|
|
507
|
-
}
|
|
508
|
-
if (measure_mode === `edit-atoms`) {
|
|
509
|
-
if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
|
|
510
|
-
if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
|
|
511
|
-
}
|
|
512
|
-
})
|
|
513
|
-
})
|
|
514
|
-
|
|
515
|
-
// Clear selection when switching measure/edit mode so stale state doesn't carry over
|
|
516
|
-
let mode_first_run = true
|
|
517
|
-
$effect(() => {
|
|
518
|
-
void measure_mode // track reactively
|
|
519
|
-
if (mode_first_run) {
|
|
520
|
-
mode_first_run = false
|
|
521
|
-
return
|
|
522
|
-
}
|
|
523
|
-
untrack(() => {
|
|
524
|
-
if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
|
|
525
|
-
})
|
|
526
|
-
})
|
|
527
|
-
|
|
528
|
-
// Auto-bake cell type transform and clear stale state when entering edit-atoms mode
|
|
529
|
-
$effect(() => {
|
|
530
|
-
if (measure_mode !== `edit-atoms`) return
|
|
531
|
-
untrack(() => {
|
|
532
|
-
// Clear bond edits from edit-bonds mode to avoid stale state
|
|
533
|
-
if (added_bonds.length > 0 || removed_bonds.length > 0) {
|
|
534
|
-
added_bonds = []
|
|
535
|
-
removed_bonds = []
|
|
536
|
-
}
|
|
537
|
-
if (cell_type !== `original` && cell_transformed_structure && structure) {
|
|
538
|
-
// Bake the transformed cell: push original to undo, replace structure
|
|
539
|
-
is_internal_edit = true
|
|
540
|
-
push_undo()
|
|
541
|
-
structure = $state.snapshot(cell_transformed_structure) as AnyStructure
|
|
542
|
-
cell_type = `original`
|
|
543
|
-
}
|
|
544
|
-
})
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
let controls_config = $derived(normalize_show_controls(show_controls))
|
|
548
|
-
|
|
549
|
-
// Normalize structure coordinates: wrap fractional coords to [0,1) and recompute Cartesian
|
|
550
|
-
// This ensures atoms are rendered inside the unit cell regardless of data source
|
|
551
|
-
let normalized_structure = $derived.by(() => {
|
|
552
|
-
if (!structure || !(`lattice` in structure)) return structure
|
|
553
|
-
return normalize_fractional_coords(structure) as AnyStructure
|
|
554
|
-
})
|
|
555
|
-
|
|
556
|
-
// Apply cell type transformation (original, conventional, or primitive)
|
|
557
|
-
// This must happen BEFORE supercell transformation
|
|
558
|
-
let cell_transformed_structure = $derived.by(() => {
|
|
559
|
-
if (
|
|
560
|
-
!normalized_structure || !(`lattice` in normalized_structure) ||
|
|
561
|
-
cell_type === `original`
|
|
562
|
-
) {
|
|
563
|
-
return normalized_structure
|
|
564
|
-
}
|
|
565
|
-
// Cell type transformation requires symmetry data
|
|
566
|
-
if (!sym_data) {
|
|
567
|
-
return normalized_structure
|
|
568
|
-
}
|
|
569
|
-
try {
|
|
570
|
-
return transform_cell(normalized_structure as Crystal, cell_type, sym_data)
|
|
571
|
-
} catch (error) {
|
|
572
|
-
console.error(`Failed to transform cell to ${cell_type}:`, error)
|
|
573
|
-
return normalized_structure
|
|
574
|
-
}
|
|
575
|
-
})
|
|
576
|
-
|
|
577
|
-
// Create supercell if needed (uses cell_transformed_structure as base)
|
|
578
|
-
let supercell_structure = $state(structure)
|
|
579
|
-
let supercell_loading = $state(false)
|
|
580
|
-
let has_supercell = $derived(
|
|
581
|
-
!!supercell_scaling && ![``, `1x1x1`, `1`].includes(supercell_scaling),
|
|
582
|
-
)
|
|
583
|
-
|
|
584
|
-
// Tile volumetric data to match supercell when active.
|
|
585
|
-
// Gate on !supercell_loading so the tiled volume and supercell structure update
|
|
586
|
-
// in the same frame (large supercells defer structure via setTimeout).
|
|
587
|
-
let supercell_volume = $derived.by(() => {
|
|
588
|
-
const vol = volumetric_data?.[active_volume_idx]
|
|
589
|
-
if (!vol || !has_supercell || supercell_loading) return vol
|
|
590
|
-
try {
|
|
591
|
-
return tile_volumetric_data(vol, parse_supercell_scaling(supercell_scaling))
|
|
592
|
-
} catch {
|
|
593
|
-
return vol
|
|
594
|
-
}
|
|
595
|
-
})
|
|
596
|
-
|
|
597
|
-
let supercell_timeout: ReturnType<typeof setTimeout> | undefined
|
|
598
|
-
$effect(() => {
|
|
599
|
-
const base_structure = cell_transformed_structure
|
|
600
|
-
clearTimeout(supercell_timeout)
|
|
601
|
-
if (!base_structure || !(`lattice` in base_structure) || !has_supercell) {
|
|
602
|
-
supercell_structure = base_structure
|
|
603
|
-
supercell_loading = false
|
|
604
|
-
} else if (!is_valid_supercell_input(supercell_scaling)) {
|
|
605
|
-
supercell_structure = base_structure
|
|
606
|
-
supercell_loading = false
|
|
607
|
-
} else {
|
|
608
|
-
// For large supercells, show loading state and use async generation
|
|
609
|
-
const sites_count = base_structure.sites?.length || 0
|
|
610
|
-
const [nx_str, ny_str, nz_str] = supercell_scaling.split(/[x×]/)
|
|
611
|
-
const scaling_mult = (parseInt(nx_str) || 1) * (parseInt(ny_str) || 1) *
|
|
612
|
-
(parseInt(nz_str) || 1)
|
|
613
|
-
const estimated_sites = sites_count * scaling_mult
|
|
614
|
-
|
|
615
|
-
// Show spinner for supercells with >1000 estimated sites or scaling >8
|
|
616
|
-
const show_loading = estimated_sites > 1000 || scaling_mult > 8
|
|
617
|
-
|
|
618
|
-
if (show_loading) {
|
|
619
|
-
supercell_loading = true
|
|
620
|
-
// Use setTimeout to allow UI to update before heavy computation
|
|
621
|
-
supercell_timeout = setTimeout(() => {
|
|
622
|
-
try {
|
|
623
|
-
if (base_structure && `lattice` in base_structure) {
|
|
624
|
-
supercell_structure = make_supercell(
|
|
625
|
-
base_structure as Crystal,
|
|
626
|
-
supercell_scaling,
|
|
627
|
-
)
|
|
628
|
-
}
|
|
629
|
-
} catch (error) {
|
|
630
|
-
console.error(`Failed to create supercell:`, error)
|
|
631
|
-
supercell_structure = base_structure
|
|
632
|
-
} finally {
|
|
633
|
-
supercell_loading = false
|
|
634
|
-
}
|
|
635
|
-
}, 10)
|
|
636
|
-
} else {
|
|
637
|
-
if (base_structure && `lattice` in base_structure) {
|
|
638
|
-
supercell_structure = make_supercell(
|
|
639
|
-
base_structure as Crystal,
|
|
640
|
-
supercell_scaling,
|
|
641
|
-
)
|
|
642
|
-
}
|
|
643
|
-
supercell_loading = false
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
})
|
|
647
|
-
|
|
648
|
-
// Clear selections, site overrides, and stale camera target when transformations
|
|
649
|
-
// change site indices (skip first run to preserve parent-provided selections)
|
|
650
|
-
let first_run = true
|
|
651
|
-
$effect(() => {
|
|
652
|
-
void [supercell_scaling, show_image_atoms, structure, cell_type] // track reactively
|
|
653
|
-
if (first_run) {
|
|
654
|
-
first_run = false
|
|
655
|
-
return
|
|
656
|
-
}
|
|
657
|
-
untrack(() => {
|
|
658
|
-
// In edit-atoms mode, structure changes are intentional user edits
|
|
659
|
-
// (move/add/delete) — preserve the selection so TransformControls stays active
|
|
660
|
-
if (measure_mode === `edit-atoms`) return
|
|
661
|
-
if (selected_sites.length > 0 || measured_sites.length > 0) clear_selection()
|
|
662
|
-
// Clear site radius overrides since site indices are no longer valid
|
|
663
|
-
if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
|
|
664
|
-
// Clear stale camera target so orbit controls re-center on the new cell
|
|
665
|
-
scene_props.camera_target = undefined
|
|
666
|
-
})
|
|
667
|
-
})
|
|
668
|
-
|
|
669
|
-
// Apply element mapping then image atoms to the supercell structure.
|
|
670
|
-
// Skip get_pbc_image_sites during atom drags — the vector math + doubled site
|
|
671
|
-
// count causes frame drops. Image atoms reappear instantly on drag release.
|
|
672
|
-
$effect(() => {
|
|
673
|
-
let struct = supercell_structure
|
|
674
|
-
if (struct && element_mapping && Object.keys(element_mapping).length > 0) {
|
|
675
|
-
const mapping = element_mapping // capture for TypeScript narrowing
|
|
676
|
-
struct = {
|
|
677
|
-
...struct,
|
|
678
|
-
sites: struct.sites.map((site) => ({
|
|
679
|
-
...site,
|
|
680
|
-
species: site.species.map((sp) => ({
|
|
681
|
-
...sp,
|
|
682
|
-
element: mapping[sp.element as ElementSymbol] ?? sp.element,
|
|
683
|
-
})),
|
|
684
|
-
label: mapping[site.label as ElementSymbol] ?? site.label,
|
|
685
|
-
})),
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
displayed_structure =
|
|
689
|
-
!dragging_atoms && show_image_atoms && struct && `lattice` in struct &&
|
|
690
|
-
struct.lattice
|
|
691
|
-
? get_pbc_image_sites(struct)
|
|
692
|
-
: struct
|
|
693
|
-
})
|
|
694
|
-
|
|
695
|
-
// Track if camera has ever been moved from initial position
|
|
696
|
-
let camera_has_moved = $state(false)
|
|
697
|
-
let camera_is_moving = $state(false)
|
|
698
|
-
let scene = $state<Scene | undefined>(undefined)
|
|
699
|
-
let camera = $state<Camera | undefined>(undefined)
|
|
700
|
-
let orbit_controls = $state<
|
|
701
|
-
ComponentProps<typeof StructureScene>[`orbit_controls`]
|
|
702
|
-
>(undefined)
|
|
703
|
-
let rotation_target_ref = $state<Vec3 | undefined>(undefined)
|
|
704
|
-
let initial_computed_zoom = $state<number | undefined>(undefined)
|
|
705
|
-
|
|
706
|
-
// Mutual exclusion: opening one pane closes others
|
|
707
|
-
$effect(() => {
|
|
708
|
-
if (info_pane_open) {
|
|
709
|
-
untrack(() => [controls_open, export_pane_open] = [false, false])
|
|
710
|
-
}
|
|
711
|
-
})
|
|
712
|
-
$effect(() => {
|
|
713
|
-
if (controls_open) {
|
|
714
|
-
untrack(() => [info_pane_open, export_pane_open] = [false, false])
|
|
715
|
-
}
|
|
716
|
-
})
|
|
717
|
-
$effect(() => {
|
|
718
|
-
if (export_pane_open) {
|
|
719
|
-
untrack(() => [info_pane_open, controls_open] = [false, false])
|
|
720
|
-
}
|
|
721
|
-
})
|
|
722
|
-
|
|
723
|
-
// Reset tracking when structure changes
|
|
724
|
-
$effect(() => {
|
|
725
|
-
if (structure) camera_has_moved = false
|
|
726
|
-
})
|
|
727
|
-
|
|
728
|
-
// Clear stale camera target and position so StructureScene uses the new
|
|
729
|
-
// structure's rotation_target (unit cell center) and auto-positions the camera.
|
|
730
|
-
function clear_camera_state() {
|
|
731
|
-
scene_props.camera_target = undefined
|
|
732
|
-
scene_props.camera_position = [0, 0, 0]
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
const read_orbit_target = (): Vec3 | undefined => {
|
|
736
|
-
if (!orbit_controls?.target) return
|
|
737
|
-
const { x, y, z } = orbit_controls.target
|
|
738
|
-
return [x, y, z]
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
const read_camera_position = (): Vec3 | undefined =>
|
|
742
|
-
camera
|
|
743
|
-
? [camera.position.x, camera.position.y, camera.position.z]
|
|
744
|
-
: scene_props.camera_position
|
|
745
|
-
|
|
746
|
-
// Emit debounced camera updates while controls are active.
|
|
747
|
-
$effect(() => {
|
|
748
|
-
if (!camera_is_moving) return
|
|
749
|
-
camera_has_moved = true
|
|
750
|
-
|
|
751
|
-
const emit_camera_move = () => {
|
|
752
|
-
const camera_position = read_camera_position()
|
|
753
|
-
if (camera_position === undefined) return
|
|
754
|
-
const camera_target = read_orbit_target()
|
|
755
|
-
scene_props.camera_position = camera_position
|
|
756
|
-
scene_props.camera_target = camera_target
|
|
757
|
-
on_camera_move?.({
|
|
758
|
-
structure,
|
|
759
|
-
camera_has_moved,
|
|
760
|
-
camera_position,
|
|
761
|
-
camera_target,
|
|
762
|
-
})
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
emit_camera_move()
|
|
766
|
-
const emit_interval = setInterval(emit_camera_move, 200)
|
|
767
|
-
return () => clearInterval(emit_interval)
|
|
768
|
-
})
|
|
769
|
-
|
|
770
|
-
function reset_camera() {
|
|
771
|
-
// Reset camera position to trigger automatic positioning.
|
|
772
|
-
scene_props.camera_position = [0, 0, 0]
|
|
773
|
-
scene_props.camera_target = rotation_target_ref
|
|
774
|
-
camera_has_moved = false
|
|
775
|
-
|
|
776
|
-
let camera_position: Vec3 = [0, 0, 0]
|
|
777
|
-
let camera_target: Vec3 | undefined = rotation_target_ref
|
|
778
|
-
|
|
779
|
-
// Reset pan/zoom and ensure controls target returns to structure center.
|
|
780
|
-
if (orbit_controls && camera) {
|
|
781
|
-
if (
|
|
782
|
-
`reset` in orbit_controls &&
|
|
783
|
-
typeof orbit_controls.reset === `function`
|
|
784
|
-
) orbit_controls.reset()
|
|
785
|
-
if (orbit_controls.target && rotation_target_ref) {
|
|
786
|
-
const [target_x, target_y, target_z] = rotation_target_ref
|
|
787
|
-
orbit_controls.target.set(target_x, target_y, target_z)
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
// Reset zoom for orthographic camera
|
|
791
|
-
if (`zoom` in camera && initial_computed_zoom !== undefined) {
|
|
792
|
-
const ortho_camera = camera as OrthographicCamera
|
|
793
|
-
ortho_camera.zoom = initial_computed_zoom
|
|
794
|
-
ortho_camera.updateProjectionMatrix()
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
// Call update to apply changes immediately
|
|
798
|
-
if (typeof orbit_controls.update === `function`) orbit_controls.update()
|
|
799
|
-
camera_position = read_camera_position() ?? camera_position
|
|
800
|
-
camera_target = read_orbit_target()
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
scene_props.camera_position = camera_position
|
|
804
|
-
scene_props.camera_target = camera_target
|
|
805
|
-
on_camera_reset?.({ structure, camera_has_moved, camera_position, camera_target })
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
const emit_file_load_event = (
|
|
809
|
-
structure: AnyStructure,
|
|
810
|
-
filename: string,
|
|
811
|
-
content: string | ArrayBuffer,
|
|
812
|
-
) =>
|
|
813
|
-
on_file_load?.({
|
|
814
|
-
structure: structure,
|
|
815
|
-
filename,
|
|
816
|
-
file_size: typeof content === `string`
|
|
817
|
-
? new Blob([content]).size
|
|
818
|
-
: content.byteLength,
|
|
819
|
-
total_atoms: structure.sites?.length || 0,
|
|
820
|
-
})
|
|
821
|
-
|
|
822
|
-
// Try to parse content as a volumetric file, setting both structure and volumetric data.
|
|
823
|
-
// Delegates format detection entirely to parse_volumetric_file (filename + content sniffing).
|
|
824
|
-
// Returns the parsed structure on success, or null if the file isn't a volumetric format.
|
|
825
|
-
function try_parse_volumetric(
|
|
826
|
-
text_content: string,
|
|
827
|
-
filename: string,
|
|
828
|
-
): AnyStructure | null {
|
|
829
|
-
const vol_result = parse_volumetric_file(text_content, filename)
|
|
830
|
-
if (!vol_result) return null
|
|
831
|
-
// parse_volumetric_file extracts structure from file header;
|
|
832
|
-
// parsers set pbc so the lattice conforms to Crystal's LatticeType
|
|
833
|
-
structure = vol_result.structure as AnyStructure
|
|
834
|
-
volumetric_data = vol_result.volumes
|
|
835
|
-
// Auto-compute reasonable isosurface settings from data range
|
|
836
|
-
const vol = vol_result.volumes[0]
|
|
837
|
-
if (vol) {
|
|
838
|
-
isosurface_settings = auto_isosurface_settings(vol.data_range)
|
|
839
|
-
active_volume_idx = 0
|
|
840
|
-
}
|
|
841
|
-
return structure
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
// Parse file content, trying volumetric format first then falling back to plain structure.
|
|
845
|
-
// Returns the parsed structure on success, throws on failure.
|
|
846
|
-
function parse_file_content(text_content: string, filename: string): AnyStructure {
|
|
847
|
-
clear_camera_state()
|
|
848
|
-
const vol_struct = try_parse_volumetric(text_content, filename)
|
|
849
|
-
if (vol_struct) return vol_struct
|
|
850
|
-
// Clear stale volumetric data when loading a non-volumetric file
|
|
851
|
-
volumetric_data = []
|
|
852
|
-
const parsed = parse_any_structure(text_content, filename)
|
|
853
|
-
if (!parsed) throw new Error(`Failed to parse structure from ${filename}`)
|
|
854
|
-
structure = parsed
|
|
855
|
-
return parsed
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
const handle_file_drop = create_file_drop_handler({
|
|
859
|
-
allow: () => allow_file_drop,
|
|
860
|
-
on_drop: (content, filename) => {
|
|
861
|
-
if (on_file_drop) return on_file_drop(content, filename)
|
|
862
|
-
try {
|
|
863
|
-
const text_content = content instanceof ArrayBuffer
|
|
864
|
-
? new TextDecoder().decode(content)
|
|
865
|
-
: content
|
|
866
|
-
const parsed = parse_file_content(text_content, filename)
|
|
867
|
-
emit_file_load_event(parsed, filename, content)
|
|
868
|
-
} catch (err) {
|
|
869
|
-
error_msg = `Failed to parse structure: ${
|
|
870
|
-
err instanceof Error ? err.message : String(err)
|
|
871
|
-
}`
|
|
872
|
-
on_error?.({ error_msg, filename })
|
|
873
|
-
}
|
|
874
|
-
},
|
|
875
|
-
on_error: (msg) => {
|
|
876
|
-
error_msg = msg
|
|
877
|
-
on_error?.({ error_msg: msg })
|
|
878
|
-
},
|
|
879
|
-
set_loading: (val) => {
|
|
880
|
-
loading = val
|
|
881
|
-
if (val) [error_msg, dragover] = [undefined, false]
|
|
882
|
-
},
|
|
883
|
-
})
|
|
884
|
-
|
|
885
|
-
function handle_keydown(event: KeyboardEvent) {
|
|
886
|
-
// Don't handle shortcuts if user is typing in an input field
|
|
887
|
-
const target = event.target as HTMLElement
|
|
888
|
-
const is_input_focused = target.tagName === `INPUT` ||
|
|
889
|
-
target.tagName === `TEXTAREA`
|
|
890
|
-
|
|
891
|
-
// Allow Escape to cancel add-atom mode even when the element input is focused
|
|
892
|
-
if (event.key === `Escape` && measure_mode === `edit-atoms` && add_atom_mode) {
|
|
893
|
-
event.preventDefault()
|
|
894
|
-
add_atom_mode = false
|
|
895
|
-
return
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
if (is_input_focused) return
|
|
899
|
-
|
|
900
|
-
// Edit-atoms mode shortcuts (including undo/redo)
|
|
901
|
-
if (measure_mode === `edit-atoms`) {
|
|
902
|
-
// Undo/redo shortcuts (Ctrl/Cmd + Z/Y) — only active in edit-atoms mode
|
|
903
|
-
if (event.ctrlKey || event.metaKey) {
|
|
904
|
-
const key = event.key.toLowerCase()
|
|
905
|
-
if (key === `z` && !event.shiftKey) {
|
|
906
|
-
event.preventDefault()
|
|
907
|
-
undo()
|
|
908
|
-
show_toast(`Undo (${undo_stack.length} left)`)
|
|
909
|
-
return
|
|
910
|
-
} else if (key === `y` || (key === `z` && event.shiftKey)) {
|
|
911
|
-
event.preventDefault()
|
|
912
|
-
redo()
|
|
913
|
-
show_toast(`Redo (${redo_stack.length} left)`)
|
|
914
|
-
return
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
if (event.key === `Delete` || event.key === `Backspace`) {
|
|
919
|
-
// Delete selected atoms
|
|
920
|
-
if (selected_sites.length > 0 && structure?.sites) {
|
|
921
|
-
event.preventDefault()
|
|
922
|
-
is_internal_edit = true
|
|
923
|
-
push_undo()
|
|
924
|
-
const to_delete = scene_to_structure_indices(selected_sites, true)
|
|
925
|
-
const n_deleted = to_delete.size
|
|
926
|
-
clear_selection()
|
|
927
|
-
structure = {
|
|
928
|
-
...structure,
|
|
929
|
-
sites: structure.sites.filter((_, idx) => !to_delete.has(idx)),
|
|
930
|
-
}
|
|
931
|
-
// Clear per-site overrides since indices shifted after deletion
|
|
932
|
-
if (site_radius_overrides?.size > 0) site_radius_overrides.clear()
|
|
933
|
-
added_bonds = []
|
|
934
|
-
removed_bonds = []
|
|
935
|
-
show_toast(`Deleted ${n_deleted} site${n_deleted > 1 ? `s` : ``}`)
|
|
936
|
-
}
|
|
937
|
-
return
|
|
938
|
-
}
|
|
939
|
-
const key = event.key.toLowerCase()
|
|
940
|
-
const plain = !event.ctrlKey && !event.metaKey && !event.altKey
|
|
941
|
-
|
|
942
|
-
if (key === `a` && plain) {
|
|
943
|
-
// Enter add-atom sub-mode (plain 'a' only, not Ctrl+A/Cmd+A/Alt+A)
|
|
944
|
-
event.preventDefault()
|
|
945
|
-
add_atom_mode = !add_atom_mode
|
|
946
|
-
return
|
|
947
|
-
}
|
|
948
|
-
// Change element of selected atoms
|
|
949
|
-
if (key === `e` && plain && selected_sites.length > 0) {
|
|
950
|
-
event.preventDefault()
|
|
951
|
-
change_element_mode = !change_element_mode
|
|
952
|
-
return
|
|
953
|
-
}
|
|
954
|
-
// Duplicate selected atoms at a small offset
|
|
955
|
-
if (
|
|
956
|
-
key === `d` && (event.ctrlKey || event.metaKey) &&
|
|
957
|
-
selected_sites.length > 0 && structure?.sites
|
|
958
|
-
) {
|
|
959
|
-
event.preventDefault()
|
|
960
|
-
is_internal_edit = true
|
|
961
|
-
push_undo()
|
|
962
|
-
const orig_indices = scene_to_structure_indices(selected_sites)
|
|
963
|
-
const cart_to_frac = get_cart_to_frac()
|
|
964
|
-
const new_sites = structure.sites
|
|
965
|
-
.filter((_, idx) => orig_indices.has(idx))
|
|
966
|
-
.map((site) => {
|
|
967
|
-
const new_xyz: Vec3 = [
|
|
968
|
-
site.xyz[0] + 0.5,
|
|
969
|
-
site.xyz[1] + 0.5,
|
|
970
|
-
site.xyz[2] + 0.5,
|
|
971
|
-
]
|
|
972
|
-
return {
|
|
973
|
-
...site,
|
|
974
|
-
xyz: new_xyz,
|
|
975
|
-
abc: cart_to_frac?.(new_xyz) ?? new_xyz,
|
|
976
|
-
properties: { ...site.properties },
|
|
977
|
-
}
|
|
978
|
-
})
|
|
979
|
-
const base_idx = structure.sites.length
|
|
980
|
-
structure = {
|
|
981
|
-
...structure,
|
|
982
|
-
sites: [...structure.sites, ...new_sites],
|
|
983
|
-
}
|
|
984
|
-
// Select the newly duplicated atoms
|
|
985
|
-
selected_sites = new_sites.map((_, idx) => base_idx + idx)
|
|
986
|
-
measured_sites = [...selected_sites]
|
|
987
|
-
show_toast(
|
|
988
|
-
`Duplicated ${new_sites.length} site${new_sites.length > 1 ? `s` : ``}`,
|
|
989
|
-
)
|
|
990
|
-
return
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// add_atom_mode Escape is already handled above (before is_input_focused guard)
|
|
994
|
-
if (event.key === `Escape`) {
|
|
995
|
-
if (change_element_mode) {
|
|
996
|
-
change_element_mode = false
|
|
997
|
-
return
|
|
998
|
-
}
|
|
999
|
-
if (selected_sites.length > 0) {
|
|
1000
|
-
clear_selection()
|
|
1001
|
-
return
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
// Interface shortcuts (require Ctrl/Cmd modifier to avoid accidental triggers)
|
|
1007
|
-
const has_modifier = event.ctrlKey || event.metaKey
|
|
1008
|
-
if (event.key === `f` && has_modifier && fullscreen_toggle) {
|
|
1009
|
-
event.preventDefault()
|
|
1010
|
-
toggle_fullscreen(wrapper)
|
|
1011
|
-
} else if (event.key === `i` && has_modifier && enable_info_pane) {
|
|
1012
|
-
event.preventDefault()
|
|
1013
|
-
info_pane_open = !info_pane_open
|
|
1014
|
-
} else if (event.key === `Escape`) {
|
|
1015
|
-
// Prioritize closing panes, then exit edit modes, then exit fullscreen
|
|
1016
|
-
if (info_pane_open) info_pane_open = false
|
|
1017
|
-
else if (controls_open) controls_open = false
|
|
1018
|
-
else if (export_pane_open) export_pane_open = false
|
|
1019
|
-
else if (measure_mode === `edit-bonds` || measure_mode === `edit-atoms`) {
|
|
1020
|
-
measure_mode = `distance`
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
|
|
1025
|
-
// === Edit-atoms mode helpers ===
|
|
1026
|
-
|
|
1027
|
-
// Map scene indices (into displayed_structure) back to raw structure indices.
|
|
1028
|
-
// Handles supercell atoms via orig_unit_cell_idx property.
|
|
1029
|
-
// skip_image_atoms: when true, image atoms (PBC ghosts) are excluded from the result.
|
|
1030
|
-
function scene_to_structure_indices(
|
|
1031
|
-
scene_indices: number[],
|
|
1032
|
-
skip_image_atoms = false,
|
|
1033
|
-
): SvelteSet<number> {
|
|
1034
|
-
const result = new SvelteSet<number>()
|
|
1035
|
-
for (const scene_idx of scene_indices) {
|
|
1036
|
-
const displayed_site = displayed_structure?.sites?.[scene_idx]
|
|
1037
|
-
if (!displayed_site) continue
|
|
1038
|
-
if (skip_image_atoms && displayed_site.properties?.orig_site_idx != null) {
|
|
1039
|
-
continue
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (has_supercell && displayed_site.properties?.orig_unit_cell_idx != null) {
|
|
1043
|
-
result.add(displayed_site.properties.orig_unit_cell_idx as number)
|
|
1044
|
-
} else if (displayed_site.properties?.orig_site_idx != null) {
|
|
1045
|
-
// Image atom (PBC ghost) — map back to its original site index
|
|
1046
|
-
result.add(displayed_site.properties.orig_site_idx as number)
|
|
1047
|
-
} else {
|
|
1048
|
-
result.add(scene_idx)
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
return result
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
// Try to create a Cartesian→fractional converter for the current structure's lattice
|
|
1055
|
-
function get_cart_to_frac(): ((xyz: Vec3) => Vec3) | undefined {
|
|
1056
|
-
if (!structure || !(`lattice` in structure)) return undefined
|
|
1057
|
-
try {
|
|
1058
|
-
return create_cart_to_frac((structure as Crystal).lattice.matrix)
|
|
1059
|
-
} catch {
|
|
1060
|
-
console.warn(`Failed to compute lattice inverse for fractional coordinates`)
|
|
1061
|
-
return undefined
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
// Handle atom moves from TransformControls. Applies Cartesian delta and wraps
|
|
1066
|
-
// fractional coords inline so normalize_fractional_coords hits its fast path.
|
|
1067
|
-
function handle_sites_moved(scene_indices: number[], delta: Vec3) {
|
|
1068
|
-
if (!structure?.sites) return
|
|
1069
|
-
is_internal_edit = true
|
|
1070
|
-
|
|
1071
|
-
const orig_indices = scene_to_structure_indices(scene_indices)
|
|
1072
|
-
// For crystals, wrap to [0,1) inline so normalize_fractional_coords fast-paths.
|
|
1073
|
-
// For molecules (no lattice), just apply the Cartesian delta directly.
|
|
1074
|
-
const lattice = `lattice` in structure
|
|
1075
|
-
? (structure as Crystal).lattice.matrix
|
|
1076
|
-
: null
|
|
1077
|
-
const cart_to_frac = lattice ? create_cart_to_frac(lattice) : null
|
|
1078
|
-
const frac_to_cart = lattice ? create_frac_to_cart(lattice) : null
|
|
1079
|
-
structure = {
|
|
1080
|
-
...structure,
|
|
1081
|
-
sites: structure.sites.map((site, idx) => {
|
|
1082
|
-
if (!orig_indices.has(idx)) return site
|
|
1083
|
-
const new_xyz: Vec3 = [
|
|
1084
|
-
site.xyz[0] + delta[0],
|
|
1085
|
-
site.xyz[1] + delta[1],
|
|
1086
|
-
site.xyz[2] + delta[2],
|
|
1087
|
-
]
|
|
1088
|
-
if (!cart_to_frac || !frac_to_cart) {
|
|
1089
|
-
return { ...site, xyz: new_xyz, abc: new_xyz }
|
|
1090
|
-
}
|
|
1091
|
-
const wrapped_abc = wrap_to_unit_cell(cart_to_frac(new_xyz))
|
|
1092
|
-
return { ...site, xyz: frac_to_cart(wrapped_abc), abc: wrapped_abc }
|
|
1093
|
-
}),
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// Change element symbol of selected atoms
|
|
1098
|
-
function handle_change_element(new_element: string) {
|
|
1099
|
-
if (!structure?.sites || selected_sites.length === 0) return
|
|
1100
|
-
const elem = normalize_element(new_element)
|
|
1101
|
-
if (!elem) return
|
|
1102
|
-
is_internal_edit = true
|
|
1103
|
-
push_undo()
|
|
1104
|
-
const orig_indices = scene_to_structure_indices(selected_sites)
|
|
1105
|
-
structure = {
|
|
1106
|
-
...structure,
|
|
1107
|
-
sites: structure.sites.map((site, idx) => {
|
|
1108
|
-
if (!orig_indices.has(idx)) return site
|
|
1109
|
-
return {
|
|
1110
|
-
...site,
|
|
1111
|
-
species: [{ element: elem, occu: 1, oxidation_state: 0 }],
|
|
1112
|
-
label: elem,
|
|
1113
|
-
}
|
|
1114
|
-
}),
|
|
1115
|
-
}
|
|
1116
|
-
change_element_mode = false
|
|
1117
|
-
change_element_value = ``
|
|
1118
|
-
show_toast(
|
|
1119
|
-
`Changed ${orig_indices.size} site${
|
|
1120
|
-
orig_indices.size > 1 ? `s` : ``
|
|
1121
|
-
} to ${elem}`,
|
|
1122
|
-
)
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
// Handle add-atom from StructureScene click-to-place
|
|
1126
|
-
function handle_add_atom(xyz: Vec3, element: ElementSymbol) {
|
|
1127
|
-
if (!structure) return
|
|
1128
|
-
const elem = normalize_element(element)
|
|
1129
|
-
if (!elem) {
|
|
1130
|
-
return console.warn(`Invalid element symbol "${element}", ignoring add-atom`)
|
|
1131
|
-
}
|
|
1132
|
-
is_internal_edit = true
|
|
1133
|
-
push_undo()
|
|
1134
|
-
structure = {
|
|
1135
|
-
...structure,
|
|
1136
|
-
sites: [...structure.sites, {
|
|
1137
|
-
species: [{ element: elem, occu: 1, oxidation_state: 0 }],
|
|
1138
|
-
xyz,
|
|
1139
|
-
abc: get_cart_to_frac()?.(xyz) ?? xyz,
|
|
1140
|
-
label: elem,
|
|
1141
|
-
properties: {},
|
|
1142
|
-
}],
|
|
1143
|
-
}
|
|
1144
|
-
show_toast(`Added ${elem} at (${xyz.map((c) => c.toFixed(2)).join(`, `)})`)
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
// Only set background override when background_color is explicitly provided
|
|
1148
|
-
$effect(() => {
|
|
1149
|
-
if (typeof window !== `undefined` && wrapper && background_color) {
|
|
1150
|
-
// Convert opacity (0-1) to hex alpha value (00-FF)
|
|
1151
|
-
const alpha_hex = Math.round(background_opacity * 255)
|
|
1152
|
-
.toString(16)
|
|
1153
|
-
.padStart(2, `0`)
|
|
1154
|
-
wrapper.style.setProperty(
|
|
1155
|
-
`--struct-bg-override`,
|
|
1156
|
-
`${background_color}${alpha_hex}`,
|
|
1157
|
-
)
|
|
1158
|
-
} else if (typeof window !== `undefined` && wrapper) {
|
|
1159
|
-
// Remove override to use theme system
|
|
1160
|
-
wrapper.style.removeProperty(`--struct-bg-override`)
|
|
1161
|
-
}
|
|
1162
|
-
})
|
|
1163
|
-
|
|
1164
|
-
$effect(() => { // fullscreen and background
|
|
1165
|
-
if (typeof window !== `undefined`) {
|
|
1166
|
-
if (fullscreen && !document.fullscreenElement && wrapper) {
|
|
1167
|
-
wrapper.requestFullscreen().catch(console.error)
|
|
1168
|
-
} else if (!fullscreen && document.fullscreenElement) {
|
|
1169
|
-
document.exitFullscreen()
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
|
-
set_fullscreen_bg(wrapper, fullscreen, `--struct-bg-fullscreen`)
|
|
1173
|
-
})
|
|
1174
|
-
</script>
|
|
1175
|
-
|
|
1176
|
-
<svelte:document
|
|
1177
|
-
onfullscreenchange={() => {
|
|
1178
|
-
fullscreen = Boolean(document.fullscreenElement)
|
|
1179
|
-
on_fullscreen_change?.({ structure, fullscreen })
|
|
1180
|
-
}}
|
|
1181
|
-
/>
|
|
1182
|
-
|
|
1183
|
-
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
1184
|
-
<div
|
|
1185
|
-
class:dragover
|
|
1186
|
-
class:active={info_pane_open || controls_open || export_pane_open}
|
|
1187
|
-
role="application"
|
|
1188
|
-
tabindex="0"
|
|
1189
|
-
style:--canvas-cursor={canvas_cursor}
|
|
1190
|
-
aria-label="Structure viewer"
|
|
1191
|
-
bind:this={wrapper}
|
|
1192
|
-
bind:clientWidth={width}
|
|
1193
|
-
bind:clientHeight={height}
|
|
1194
|
-
onmouseenter={() => (hovered = true)}
|
|
1195
|
-
onmouseleave={() => (hovered = false)}
|
|
1196
|
-
ondblclick={(event) => {
|
|
1197
|
-
const target = event.target as HTMLElement
|
|
1198
|
-
// Don't reset if double-click was on UI controls/panes/legend
|
|
1199
|
-
if (
|
|
1200
|
-
target.closest(`.control-buttons`) ||
|
|
1201
|
-
target.closest(`.structure-legend`) ||
|
|
1202
|
-
target.closest(`.atom-legend`) ||
|
|
1203
|
-
target.closest(`.info-pane`) ||
|
|
1204
|
-
target.closest(`.export-pane`) ||
|
|
1205
|
-
target.closest(`.controls-pane`) ||
|
|
1206
|
-
target.tagName === `BUTTON` ||
|
|
1207
|
-
target.tagName === `INPUT` ||
|
|
1208
|
-
target.tagName === `SELECT`
|
|
1209
|
-
) return
|
|
1210
|
-
// Reset camera for double-clicks on the 3D scene
|
|
1211
|
-
reset_camera()
|
|
1212
|
-
}}
|
|
1213
|
-
ondrop={handle_file_drop}
|
|
1214
|
-
ondragover={(event) => {
|
|
1215
|
-
event.preventDefault()
|
|
1216
|
-
if (!allow_file_drop) return
|
|
1217
|
-
dragover = true
|
|
1218
|
-
}}
|
|
1219
|
-
ondragleave={(event) => {
|
|
1220
|
-
event.preventDefault()
|
|
1221
|
-
dragover = false
|
|
1222
|
-
}}
|
|
1223
|
-
onkeydown={handle_keydown}
|
|
1224
|
-
{...rest}
|
|
1225
|
-
class="structure {rest.class ?? ``}"
|
|
1226
|
-
>
|
|
1227
|
-
{@render children?.({ structure, fullscreen })}
|
|
1228
|
-
{#if loading}
|
|
1229
|
-
<Spinner
|
|
1230
|
-
text="Loading structure..."
|
|
1231
|
-
{...spinner_props}
|
|
1232
|
-
style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%)"
|
|
1233
|
-
/>
|
|
1234
|
-
{:else if error_msg}
|
|
1235
|
-
<StatusMessage bind:message={error_msg} type="error" dismissible />
|
|
1236
|
-
{:else if (structure?.sites?.length ?? 0) > 0}
|
|
1237
|
-
<section
|
|
1238
|
-
class="control-buttons {controls_config.class}"
|
|
1239
|
-
style={controls_config.style}
|
|
1240
|
-
>
|
|
1241
|
-
{#if controls_config.mode !== `never`}
|
|
1242
|
-
{#if camera_has_moved && controls_config.visible(`reset-camera`)}
|
|
1243
|
-
<button class="reset-camera" onclick={reset_camera} title={reset_text}>
|
|
1244
|
-
<!-- Target/Focus icon for reset camera -->
|
|
1245
|
-
<Icon icon="Reset" />
|
|
1246
|
-
</button>
|
|
1247
|
-
{/if}
|
|
1248
|
-
{#if fullscreen_toggle && controls_config.visible(`fullscreen`)}
|
|
1249
|
-
<button
|
|
1250
|
-
type="button"
|
|
1251
|
-
onclick={() => fullscreen_toggle && toggle_fullscreen(wrapper)}
|
|
1252
|
-
title="{fullscreen ? `Exit` : `Enter`} fullscreen"
|
|
1253
|
-
aria-pressed={fullscreen}
|
|
1254
|
-
class="fullscreen-toggle"
|
|
1255
|
-
style="padding: 0 3px"
|
|
1256
|
-
{@attach tooltip()}
|
|
1257
|
-
>
|
|
1258
|
-
{#if typeof fullscreen_toggle === `function`}
|
|
1259
|
-
{@render fullscreen_toggle({ fullscreen })}
|
|
1260
|
-
{:else}
|
|
1261
|
-
<Icon icon="{fullscreen ? `Exit` : ``}Fullscreen" />
|
|
1262
|
-
{/if}
|
|
1263
|
-
</button>
|
|
1264
|
-
{/if}
|
|
1265
|
-
|
|
1266
|
-
{#if enable_measure_mode && controls_config.visible(`measure-mode`)}
|
|
1267
|
-
<div
|
|
1268
|
-
class="measure-mode-dropdown"
|
|
1269
|
-
{@attach click_outside({ callback: () => measure_menu_open = false })}
|
|
1270
|
-
>
|
|
1271
|
-
<button
|
|
1272
|
-
onclick={() => (measure_menu_open = !measure_menu_open)}
|
|
1273
|
-
title="Measure / Edit"
|
|
1274
|
-
class="view-mode-button"
|
|
1275
|
-
class:active={measure_menu_open}
|
|
1276
|
-
aria-expanded={measure_menu_open}
|
|
1277
|
-
style="transform: scale(1.2)"
|
|
1278
|
-
>
|
|
1279
|
-
{#if (measured_sites?.length ?? 0) >= MAX_SELECTED_SITES}
|
|
1280
|
-
<span class="selection-limit-text">
|
|
1281
|
-
{measured_sites.length}/{MAX_SELECTED_SITES}
|
|
1282
|
-
</span>
|
|
1283
|
-
{:else}
|
|
1284
|
-
<Icon
|
|
1285
|
-
icon={({
|
|
1286
|
-
distance: `Ruler`,
|
|
1287
|
-
angle: `Angle`,
|
|
1288
|
-
'edit-bonds': `Link`,
|
|
1289
|
-
'edit-atoms': `Edit`,
|
|
1290
|
-
} as const)[measure_mode]}
|
|
1291
|
-
/>
|
|
1292
|
-
{/if}
|
|
1293
|
-
<Icon
|
|
1294
|
-
icon="Arrow{measure_menu_open ? `Up` : `Down`}"
|
|
1295
|
-
style="margin-left: -2px"
|
|
1296
|
-
/>
|
|
1297
|
-
</button>
|
|
1298
|
-
{#if (measured_sites?.length ?? 0) > 0 || added_bonds.length > 0 ||
|
|
1299
|
-
removed_bonds.length > 0}
|
|
1300
|
-
<button
|
|
1301
|
-
type="button"
|
|
1302
|
-
aria-label="Reset selection and bond edits"
|
|
1303
|
-
onclick={() => {
|
|
1304
|
-
clear_selection()
|
|
1305
|
-
added_bonds = []
|
|
1306
|
-
removed_bonds = []
|
|
1307
|
-
}}
|
|
1308
|
-
>
|
|
1309
|
-
<Icon icon="Reset" style="margin-left: -4px" />
|
|
1310
|
-
</button>
|
|
1311
|
-
{/if}
|
|
1312
|
-
{#if measure_menu_open}
|
|
1313
|
-
<div class="view-mode-dropdown">
|
|
1314
|
-
{#each [
|
|
1315
|
-
{ mode: `distance`, icon: `Ruler`, label: `Distance`, scale: 1.1 },
|
|
1316
|
-
{ mode: `angle`, icon: `Angle`, label: `Angle`, scale: 1.3 },
|
|
1317
|
-
{
|
|
1318
|
-
mode: `edit-atoms`,
|
|
1319
|
-
icon: `Edit`,
|
|
1320
|
-
label: `Edit Atoms`,
|
|
1321
|
-
scale: 1.0,
|
|
1322
|
-
},
|
|
1323
|
-
{
|
|
1324
|
-
mode: `edit-bonds`,
|
|
1325
|
-
icon: `Link`,
|
|
1326
|
-
label: `Edit Bonds`,
|
|
1327
|
-
scale: 1.0,
|
|
1328
|
-
},
|
|
1329
|
-
] as const as
|
|
1330
|
-
{ mode, icon, label, scale }
|
|
1331
|
-
(mode)
|
|
1332
|
-
}
|
|
1333
|
-
<button
|
|
1334
|
-
class="view-mode-option"
|
|
1335
|
-
class:selected={measure_mode === mode}
|
|
1336
|
-
onclick={() => [measure_mode, measure_menu_open] = [mode, false]}
|
|
1337
|
-
>
|
|
1338
|
-
<Icon {icon} style="transform: scale({scale})" />
|
|
1339
|
-
<span>{@html sanitize_html(label)}</span>
|
|
1340
|
-
</button>
|
|
1341
|
-
{/each}
|
|
1342
|
-
</div>
|
|
1343
|
-
{/if}
|
|
1344
|
-
</div>
|
|
1345
|
-
|
|
1346
|
-
<!-- Undo/redo buttons (only in edit-atoms mode) -->
|
|
1347
|
-
{#if measure_mode === `edit-atoms`}
|
|
1348
|
-
<div class="undo-redo-container">
|
|
1349
|
-
<button
|
|
1350
|
-
type="button"
|
|
1351
|
-
aria-label="Undo (Ctrl+Z)"
|
|
1352
|
-
disabled={undo_stack.length === 0}
|
|
1353
|
-
onclick={undo}
|
|
1354
|
-
title="Undo (Ctrl+Z)"
|
|
1355
|
-
class="undo-redo-btn"
|
|
1356
|
-
>
|
|
1357
|
-
<Icon icon="Undo" />
|
|
1358
|
-
{#if undo_stack.length > 0}
|
|
1359
|
-
<span class="history-count">{undo_stack.length}</span>
|
|
1360
|
-
{/if}
|
|
1361
|
-
</button>
|
|
1362
|
-
<button
|
|
1363
|
-
type="button"
|
|
1364
|
-
aria-label="Redo (Ctrl+Y)"
|
|
1365
|
-
disabled={redo_stack.length === 0}
|
|
1366
|
-
onclick={redo}
|
|
1367
|
-
title="Redo (Ctrl+Y)"
|
|
1368
|
-
class="undo-redo-btn"
|
|
1369
|
-
>
|
|
1370
|
-
<Icon icon="Redo" />
|
|
1371
|
-
{#if redo_stack.length > 0}
|
|
1372
|
-
<span class="history-count">{redo_stack.length}</span>
|
|
1373
|
-
{/if}
|
|
1374
|
-
</button>
|
|
1375
|
-
</div>
|
|
1376
|
-
{/if}
|
|
1377
|
-
|
|
1378
|
-
<!-- Add-atom element input (shown when add_atom_mode is active) -->
|
|
1379
|
-
{#if measure_mode === `edit-atoms` && add_atom_mode}
|
|
1380
|
-
<div class="add-atom-input">
|
|
1381
|
-
<label>
|
|
1382
|
-
<span>Element:</span>
|
|
1383
|
-
<input
|
|
1384
|
-
type="text"
|
|
1385
|
-
bind:value={add_element}
|
|
1386
|
-
maxlength="2"
|
|
1387
|
-
placeholder="C"
|
|
1388
|
-
style="width: 3em; text-align: center"
|
|
1389
|
-
/>
|
|
1390
|
-
</label>
|
|
1391
|
-
<span style="font-size: 0.75em; opacity: 0.7">Click to place</span>
|
|
1392
|
-
</div>
|
|
1393
|
-
{/if}
|
|
1394
|
-
|
|
1395
|
-
<!-- Change-element input (shown when 'e' pressed with selection) -->
|
|
1396
|
-
{#if measure_mode === `edit-atoms` && change_element_mode &&
|
|
1397
|
-
selected_sites.length > 0}
|
|
1398
|
-
<div class="add-atom-input">
|
|
1399
|
-
<label>
|
|
1400
|
-
<span>New element:</span>
|
|
1401
|
-
<input
|
|
1402
|
-
type="text"
|
|
1403
|
-
bind:value={change_element_value}
|
|
1404
|
-
maxlength="2"
|
|
1405
|
-
placeholder="Fe"
|
|
1406
|
-
style="width: 3em; text-align: center"
|
|
1407
|
-
onkeydown={(event: KeyboardEvent) => {
|
|
1408
|
-
if (event.key === `Enter`) {
|
|
1409
|
-
handle_change_element(change_element_value)
|
|
1410
|
-
} else if (event.key === `Escape`) {
|
|
1411
|
-
change_element_mode = false
|
|
1412
|
-
}
|
|
1413
|
-
event.stopPropagation()
|
|
1414
|
-
}}
|
|
1415
|
-
{@attach (node: HTMLInputElement) => {
|
|
1416
|
-
node.focus()
|
|
1417
|
-
}}
|
|
1418
|
-
/>
|
|
1419
|
-
</label>
|
|
1420
|
-
<span style="font-size: 0.75em; opacity: 0.7">Enter to apply</span>
|
|
1421
|
-
</div>
|
|
1422
|
-
{/if}
|
|
1423
|
-
{/if}
|
|
1424
|
-
|
|
1425
|
-
{#if enable_info_pane && normalized_structure &&
|
|
1426
|
-
controls_config.visible(`info-pane`)}
|
|
1427
|
-
<StructureInfoPane
|
|
1428
|
-
structure={normalized_structure}
|
|
1429
|
-
bind:pane_open={info_pane_open}
|
|
1430
|
-
{selected_sites}
|
|
1431
|
-
{sym_data}
|
|
1432
|
-
{@attach tooltip({ content: `Structure info pane` })}
|
|
1433
|
-
/>
|
|
1434
|
-
{/if}
|
|
1435
|
-
|
|
1436
|
-
{#if controls_config.visible(`export-pane`)}
|
|
1437
|
-
<StructureExportPane
|
|
1438
|
-
bind:export_pane_open
|
|
1439
|
-
structure={normalized_structure}
|
|
1440
|
-
{wrapper}
|
|
1441
|
-
{scene}
|
|
1442
|
-
{camera}
|
|
1443
|
-
bind:png_dpi
|
|
1444
|
-
pane_props={{ style: `max-height: calc(${height}px - 50px)` }}
|
|
1445
|
-
/>
|
|
1446
|
-
{/if}
|
|
1447
|
-
|
|
1448
|
-
{#if controls_config.visible(`controls`)}
|
|
1449
|
-
<StructureControls
|
|
1450
|
-
bind:controls_open
|
|
1451
|
-
bind:scene_props
|
|
1452
|
-
bind:lattice_props
|
|
1453
|
-
bind:show_image_atoms
|
|
1454
|
-
bind:supercell_scaling
|
|
1455
|
-
bind:background_color
|
|
1456
|
-
bind:background_opacity
|
|
1457
|
-
bind:color_scheme
|
|
1458
|
-
bind:atom_color_config
|
|
1459
|
-
bind:cell_type
|
|
1460
|
-
bind:volumetric_data
|
|
1461
|
-
bind:isosurface_settings
|
|
1462
|
-
bind:active_volume_idx
|
|
1463
|
-
{structure}
|
|
1464
|
-
{supercell_loading}
|
|
1465
|
-
{sym_data}
|
|
1466
|
-
/>
|
|
1467
|
-
{/if}
|
|
1468
|
-
|
|
1469
|
-
{@render top_right_controls?.()}
|
|
1470
|
-
{/if}
|
|
1471
|
-
</section>
|
|
1472
|
-
|
|
1473
|
-
<AtomLegend
|
|
1474
|
-
bind:atom_color_config
|
|
1475
|
-
{property_colors}
|
|
1476
|
-
elements={get_element_counts(supercell_structure ?? structure!)}
|
|
1477
|
-
bind:hidden_elements
|
|
1478
|
-
bind:hidden_prop_vals
|
|
1479
|
-
bind:element_mapping
|
|
1480
|
-
bind:element_radius_overrides
|
|
1481
|
-
bind:site_radius_overrides
|
|
1482
|
-
{selected_sites}
|
|
1483
|
-
structure={displayed_structure}
|
|
1484
|
-
{sym_data}
|
|
1485
|
-
>
|
|
1486
|
-
{#if structure && `lattice` in structure}
|
|
1487
|
-
<CellSelect
|
|
1488
|
-
bind:supercell_scaling
|
|
1489
|
-
bind:cell_type
|
|
1490
|
-
{sym_data}
|
|
1491
|
-
loading={supercell_loading}
|
|
1492
|
-
direction="up"
|
|
1493
|
-
/>
|
|
1494
|
-
{/if}
|
|
1495
|
-
</AtomLegend>
|
|
1496
|
-
|
|
1497
|
-
<!-- prevent from rendering in vitest runner since WebGLRenderingContext not available -->
|
|
1498
|
-
{#if typeof WebGLRenderingContext !== `undefined`}
|
|
1499
|
-
<!-- prevent HTML labels from rendering outside of the canvas -->
|
|
1500
|
-
<div style="overflow: hidden; height: 100%; width: 100%">
|
|
1501
|
-
<Canvas>
|
|
1502
|
-
<StructureScene
|
|
1503
|
-
structure={displayed_structure}
|
|
1504
|
-
base_structure={cell_transformed_structure}
|
|
1505
|
-
{...scene_props}
|
|
1506
|
-
{lattice_props}
|
|
1507
|
-
volumetric_data={supercell_volume}
|
|
1508
|
-
{isosurface_settings}
|
|
1509
|
-
bind:camera_is_moving
|
|
1510
|
-
bind:selected_sites
|
|
1511
|
-
bind:measured_sites
|
|
1512
|
-
bind:scene
|
|
1513
|
-
bind:camera
|
|
1514
|
-
bind:orbit_controls
|
|
1515
|
-
bind:rotation_target_ref
|
|
1516
|
-
bind:initial_computed_zoom
|
|
1517
|
-
bind:hidden_elements
|
|
1518
|
-
bind:hidden_prop_vals
|
|
1519
|
-
bind:element_radius_overrides
|
|
1520
|
-
bind:site_radius_overrides
|
|
1521
|
-
bind:added_bonds
|
|
1522
|
-
bind:removed_bonds
|
|
1523
|
-
{measure_mode}
|
|
1524
|
-
{width}
|
|
1525
|
-
{height}
|
|
1526
|
-
{atom_color_config}
|
|
1527
|
-
{sym_data}
|
|
1528
|
-
on_sites_moved={handle_sites_moved}
|
|
1529
|
-
on_operation_start={push_undo}
|
|
1530
|
-
on_add_atom={handle_add_atom}
|
|
1531
|
-
bind:add_atom_mode
|
|
1532
|
-
bind:add_element
|
|
1533
|
-
bind:cursor={canvas_cursor}
|
|
1534
|
-
bind:dragging_atoms
|
|
1535
|
-
/>
|
|
1536
|
-
</Canvas>
|
|
1537
|
-
</div>
|
|
1538
|
-
{/if}
|
|
1539
|
-
|
|
1540
|
-
<div class="bottom-left">
|
|
1541
|
-
{@render bottom_left?.({ structure: displayed_structure })}
|
|
1542
|
-
</div>
|
|
1543
|
-
|
|
1544
|
-
{#if toast_msg}
|
|
1545
|
-
<div class="edit-toast">{toast_msg}</div>
|
|
1546
|
-
{/if}
|
|
1547
|
-
|
|
1548
|
-
{#if measure_mode === `edit-bonds` &&
|
|
1549
|
-
(added_bonds.length > 0 || removed_bonds.length > 0)}
|
|
1550
|
-
<div class="bond-edit-status">
|
|
1551
|
-
{#if added_bonds.length > 0}
|
|
1552
|
-
<span class="added">+{added_bonds.length} added</span>
|
|
1553
|
-
{/if}
|
|
1554
|
-
{#if removed_bonds.length > 0}
|
|
1555
|
-
<span class="removed">-{removed_bonds.length} removed</span>
|
|
1556
|
-
{/if}
|
|
1557
|
-
</div>
|
|
1558
|
-
{/if}
|
|
1559
|
-
|
|
1560
|
-
{#if symmetry_error}
|
|
1561
|
-
<div class="symmetry-error">
|
|
1562
|
-
<span>{symmetry_error}</span>
|
|
1563
|
-
<button onclick={() => (symmetry_error = undefined)} aria-label="Dismiss">
|
|
1564
|
-
×
|
|
1565
|
-
</button>
|
|
1566
|
-
</div>
|
|
1567
|
-
{/if}
|
|
1568
|
-
{:else if structure}
|
|
1569
|
-
<p class="warn">No sites found in structure</p>
|
|
1570
|
-
{:else}
|
|
1571
|
-
<p class="warn">No structure provided</p>
|
|
1572
|
-
{/if}
|
|
1573
|
-
</div>
|
|
1574
|
-
|
|
1575
|
-
<style>
|
|
1576
|
-
.structure {
|
|
1577
|
-
position: relative;
|
|
1578
|
-
container-type: size; /* enable cqh/cqw for internal panes */
|
|
1579
|
-
height: var(--struct-height, 500px);
|
|
1580
|
-
width: var(--struct-width, 100%);
|
|
1581
|
-
max-width: var(--struct-max-width, 100%);
|
|
1582
|
-
min-width: var(--struct-min-width, 300px);
|
|
1583
|
-
border-radius: var(--struct-border-radius, var(--border-radius, 3pt));
|
|
1584
|
-
background: var(--struct-bg-override, var(--struct-bg));
|
|
1585
|
-
color: var(--struct-text-color);
|
|
1586
|
-
display: flex;
|
|
1587
|
-
}
|
|
1588
|
-
.structure.active {
|
|
1589
|
-
z-index: var(--struct-active-z-index, 2);
|
|
1590
|
-
}
|
|
1591
|
-
.structure:fullscreen {
|
|
1592
|
-
background: var(--struct-bg-fullscreen, var(--struct-bg));
|
|
1593
|
-
overflow: hidden;
|
|
1594
|
-
}
|
|
1595
|
-
.structure:fullscreen :global(canvas) {
|
|
1596
|
-
height: 100vh !important;
|
|
1597
|
-
width: 100vw !important;
|
|
1598
|
-
}
|
|
1599
|
-
.structure.dragover {
|
|
1600
|
-
background: var(--struct-dragover-bg, var(--dragover-bg));
|
|
1601
|
-
border: var(--struct-dragover-border, var(--dragover-border));
|
|
1602
|
-
}
|
|
1603
|
-
/* Ensure canvas is transparent so the themed --struct-bg shows through */
|
|
1604
|
-
.structure :global(canvas) {
|
|
1605
|
-
background: transparent;
|
|
1606
|
-
cursor: var(--canvas-cursor, default);
|
|
1607
|
-
}
|
|
1608
|
-
/* Avoid accidental text selection while interacting with the viewer */
|
|
1609
|
-
.structure :global(canvas),
|
|
1610
|
-
.structure section.control-buttons,
|
|
1611
|
-
.structure .bottom-left {
|
|
1612
|
-
user-select: none;
|
|
1613
|
-
}
|
|
1614
|
-
div.bottom-left {
|
|
1615
|
-
position: absolute;
|
|
1616
|
-
bottom: 0;
|
|
1617
|
-
left: 0;
|
|
1618
|
-
font-size: var(--struct-bottom-left-font-size, 1.2em);
|
|
1619
|
-
padding: var(--struct-bottom-left-padding, 1pt 5pt);
|
|
1620
|
-
}
|
|
1621
|
-
section.control-buttons {
|
|
1622
|
-
position: absolute;
|
|
1623
|
-
display: flex;
|
|
1624
|
-
top: var(--struct-buttons-top, var(--ctrl-btn-top, 1ex));
|
|
1625
|
-
right: var(--struct-buttons-right, var(--ctrl-btn-right, 1ex));
|
|
1626
|
-
gap: 4pt;
|
|
1627
|
-
/* buttons need higher z-index than AtomLegend to make info/controls panes occlude legend */
|
|
1628
|
-
/* we also need crazy high z-index to make info/control pane occlude threlte/extras' <HTML> elements for site labels */
|
|
1629
|
-
z-index: var(--struct-buttons-z-index, 100000000);
|
|
1630
|
-
opacity: 0;
|
|
1631
|
-
pointer-events: none;
|
|
1632
|
-
transition: opacity 0.2s ease;
|
|
1633
|
-
}
|
|
1634
|
-
/* Mode: always - controls always visible */
|
|
1635
|
-
section.control-buttons.always-visible {
|
|
1636
|
-
opacity: 1;
|
|
1637
|
-
pointer-events: auto;
|
|
1638
|
-
}
|
|
1639
|
-
/* Mode: hover - controls visible on component hover */
|
|
1640
|
-
.structure:hover section.control-buttons.hover-visible,
|
|
1641
|
-
.structure:focus-within section.control-buttons.hover-visible {
|
|
1642
|
-
opacity: 1;
|
|
1643
|
-
pointer-events: auto;
|
|
1644
|
-
}
|
|
1645
|
-
/* Mode: never - stays hidden (default state, no additional CSS needed) */
|
|
1646
|
-
section.control-buttons > :global(button) {
|
|
1647
|
-
background-color: transparent;
|
|
1648
|
-
display: flex;
|
|
1649
|
-
padding: 1px 6px;
|
|
1650
|
-
border-radius: var(--border-radius, 3pt);
|
|
1651
|
-
font-size: clamp(0.85em, 2cqmin, 1.3em);
|
|
1652
|
-
}
|
|
1653
|
-
section.control-buttons :global(button:hover) {
|
|
1654
|
-
background-color: color-mix(in srgb, currentColor 8%, transparent);
|
|
1655
|
-
}
|
|
1656
|
-
/* Match Trajectory dropdown UI */
|
|
1657
|
-
.view-mode-dropdown {
|
|
1658
|
-
position: absolute;
|
|
1659
|
-
top: 115%;
|
|
1660
|
-
right: 0;
|
|
1661
|
-
background: var(--surface-bg);
|
|
1662
|
-
border-radius: var(--border-radius, 3pt);
|
|
1663
|
-
box-shadow: 0 8px 16px -4px rgba(0, 0, 0, 0.3), 0 4px 8px -2px rgba(0, 0, 0, 0.1);
|
|
1664
|
-
display: flex;
|
|
1665
|
-
flex-direction: column;
|
|
1666
|
-
}
|
|
1667
|
-
.view-mode-option {
|
|
1668
|
-
display: flex;
|
|
1669
|
-
align-items: center;
|
|
1670
|
-
gap: 1ex;
|
|
1671
|
-
width: 100%;
|
|
1672
|
-
padding: var(--trajectory-view-mode-option-padding, 5pt);
|
|
1673
|
-
box-sizing: border-box;
|
|
1674
|
-
background: transparent;
|
|
1675
|
-
border-radius: 0;
|
|
1676
|
-
text-align: left;
|
|
1677
|
-
transition: background-color 0.15s ease;
|
|
1678
|
-
}
|
|
1679
|
-
.view-mode-option:first-child {
|
|
1680
|
-
border-top-left-radius: 3px;
|
|
1681
|
-
border-top-right-radius: 3px;
|
|
1682
|
-
}
|
|
1683
|
-
.view-mode-option.selected {
|
|
1684
|
-
color: var(--accent-color);
|
|
1685
|
-
}
|
|
1686
|
-
.view-mode-option span {
|
|
1687
|
-
font-weight: 500;
|
|
1688
|
-
white-space: nowrap;
|
|
1689
|
-
overflow: hidden;
|
|
1690
|
-
text-overflow: ellipsis;
|
|
1691
|
-
flex: 1;
|
|
1692
|
-
}
|
|
1693
|
-
.measure-mode-dropdown {
|
|
1694
|
-
display: flex;
|
|
1695
|
-
position: relative;
|
|
1696
|
-
height: fit-content;
|
|
1697
|
-
place-self: center;
|
|
1698
|
-
}
|
|
1699
|
-
.measure-mode-dropdown > button {
|
|
1700
|
-
background: transparent;
|
|
1701
|
-
padding: 1px 6px;
|
|
1702
|
-
font-size: clamp(0.85em, 2cqmin, 1.3em);
|
|
1703
|
-
}
|
|
1704
|
-
.selection-limit-text {
|
|
1705
|
-
font-weight: bold;
|
|
1706
|
-
font-size: 0.9em;
|
|
1707
|
-
color: var(--accent-color, #ff6b6b);
|
|
1708
|
-
min-width: 2.5em;
|
|
1709
|
-
text-align: center;
|
|
1710
|
-
}
|
|
1711
|
-
p.warn {
|
|
1712
|
-
position: absolute;
|
|
1713
|
-
inset: 0;
|
|
1714
|
-
display: grid;
|
|
1715
|
-
place-content: center;
|
|
1716
|
-
}
|
|
1717
|
-
.symmetry-error {
|
|
1718
|
-
position: absolute;
|
|
1719
|
-
bottom: 1rem;
|
|
1720
|
-
right: 1rem;
|
|
1721
|
-
background: rgba(255, 165, 0, 0.95);
|
|
1722
|
-
color: #000;
|
|
1723
|
-
padding: 0.75rem 1rem;
|
|
1724
|
-
border-radius: var(--border-radius, 3pt);
|
|
1725
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1726
|
-
display: flex;
|
|
1727
|
-
gap: 1rem;
|
|
1728
|
-
max-width: min(90%, 400px);
|
|
1729
|
-
font-size: 0.9rem;
|
|
1730
|
-
z-index: 1000;
|
|
1731
|
-
}
|
|
1732
|
-
.symmetry-error span {
|
|
1733
|
-
flex: 1;
|
|
1734
|
-
}
|
|
1735
|
-
.symmetry-error button {
|
|
1736
|
-
background: transparent;
|
|
1737
|
-
border: none;
|
|
1738
|
-
font-size: 1.5rem;
|
|
1739
|
-
line-height: 1;
|
|
1740
|
-
padding: 0;
|
|
1741
|
-
cursor: pointer;
|
|
1742
|
-
opacity: 0.7;
|
|
1743
|
-
}
|
|
1744
|
-
.symmetry-error button:hover {
|
|
1745
|
-
opacity: 1;
|
|
1746
|
-
}
|
|
1747
|
-
.edit-toast {
|
|
1748
|
-
position: absolute;
|
|
1749
|
-
bottom: 3rem;
|
|
1750
|
-
left: 50%;
|
|
1751
|
-
transform: translateX(-50%);
|
|
1752
|
-
background: color-mix(in srgb, var(--page-bg, Canvas) 85%, currentColor);
|
|
1753
|
-
color: var(--text-color, currentColor);
|
|
1754
|
-
padding: 0.4rem 0.8rem;
|
|
1755
|
-
border-radius: var(--border-radius, 3pt);
|
|
1756
|
-
font-size: 0.8rem;
|
|
1757
|
-
z-index: 100;
|
|
1758
|
-
pointer-events: none;
|
|
1759
|
-
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
|
1760
|
-
animation: toast-fade 2s ease-in-out;
|
|
1761
|
-
opacity: 0;
|
|
1762
|
-
}
|
|
1763
|
-
@keyframes toast-fade {
|
|
1764
|
-
0%, 70% {
|
|
1765
|
-
opacity: 1;
|
|
1766
|
-
}
|
|
1767
|
-
100% {
|
|
1768
|
-
opacity: 0;
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
.bond-edit-status {
|
|
1772
|
-
position: absolute;
|
|
1773
|
-
bottom: 1rem;
|
|
1774
|
-
left: 50%;
|
|
1775
|
-
transform: translateX(-50%);
|
|
1776
|
-
background: color-mix(in srgb, var(--page-bg, Canvas) 85%, currentColor);
|
|
1777
|
-
color: var(--text-color, currentColor);
|
|
1778
|
-
padding: 0.5rem 1rem;
|
|
1779
|
-
border-radius: var(--border-radius, 3pt);
|
|
1780
|
-
font-size: 0.85rem;
|
|
1781
|
-
display: flex;
|
|
1782
|
-
gap: 0.75rem;
|
|
1783
|
-
z-index: 100;
|
|
1784
|
-
pointer-events: none;
|
|
1785
|
-
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
|
1786
|
-
}
|
|
1787
|
-
.bond-edit-status .added {
|
|
1788
|
-
color: #4caf50;
|
|
1789
|
-
font-weight: bold;
|
|
1790
|
-
}
|
|
1791
|
-
.bond-edit-status .removed {
|
|
1792
|
-
color: #f44336;
|
|
1793
|
-
font-weight: bold;
|
|
1794
|
-
}
|
|
1795
|
-
/* CellSelect: position at left of legend, show on hover */
|
|
1796
|
-
.structure :global(.cell-select) {
|
|
1797
|
-
order: -1; /* Move to left side of AtomLegend flex container */
|
|
1798
|
-
opacity: 0;
|
|
1799
|
-
pointer-events: none;
|
|
1800
|
-
transition: opacity 0.3s ease;
|
|
1801
|
-
}
|
|
1802
|
-
.structure:hover :global(.cell-select) {
|
|
1803
|
-
opacity: 1;
|
|
1804
|
-
pointer-events: auto;
|
|
1805
|
-
}
|
|
1806
|
-
.undo-redo-container {
|
|
1807
|
-
display: flex;
|
|
1808
|
-
}
|
|
1809
|
-
.undo-redo-btn {
|
|
1810
|
-
position: relative;
|
|
1811
|
-
display: flex;
|
|
1812
|
-
align-items: center;
|
|
1813
|
-
justify-content: center;
|
|
1814
|
-
}
|
|
1815
|
-
.history-count {
|
|
1816
|
-
position: absolute;
|
|
1817
|
-
bottom: -2px;
|
|
1818
|
-
right: -2px;
|
|
1819
|
-
background: var(--accent-color, #007acc);
|
|
1820
|
-
color: white;
|
|
1821
|
-
border-radius: 50%;
|
|
1822
|
-
width: 12px;
|
|
1823
|
-
height: 12px;
|
|
1824
|
-
font-size: 8px;
|
|
1825
|
-
font-weight: bold;
|
|
1826
|
-
display: flex;
|
|
1827
|
-
align-items: center;
|
|
1828
|
-
justify-content: center;
|
|
1829
|
-
line-height: 1;
|
|
1830
|
-
pointer-events: none;
|
|
1831
|
-
z-index: 1;
|
|
1832
|
-
}
|
|
1833
|
-
.add-atom-input {
|
|
1834
|
-
display: flex;
|
|
1835
|
-
align-items: center;
|
|
1836
|
-
gap: 0.5em;
|
|
1837
|
-
background: color-mix(in srgb, var(--page-bg, Canvas) 85%, currentColor);
|
|
1838
|
-
color: var(--text-color, currentColor);
|
|
1839
|
-
padding: 0.3em 0.6em;
|
|
1840
|
-
border-radius: var(--border-radius, 3pt);
|
|
1841
|
-
font-size: 0.8rem;
|
|
1842
|
-
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
|
1843
|
-
label {
|
|
1844
|
-
display: flex;
|
|
1845
|
-
align-items: center;
|
|
1846
|
-
gap: 0.3em;
|
|
1847
|
-
}
|
|
1848
|
-
input {
|
|
1849
|
-
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
1850
|
-
border: 1px solid color-mix(in srgb, currentColor 20%, transparent);
|
|
1851
|
-
border-radius: 3px;
|
|
1852
|
-
color: inherit;
|
|
1853
|
-
font-size: 0.85rem;
|
|
1854
|
-
padding: 0.1em 0.3em;
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
</style>
|