matterviz 0.3.6 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/EmptyState.svelte.d.ts +9 -0
- package/dist/FilePicker.svelte +360 -0
- package/dist/FilePicker.svelte.d.ts +17 -0
- package/dist/Icon.svelte.d.ts +13 -0
- package/dist/MillerIndexInput.svelte +66 -0
- package/dist/MillerIndexInput.svelte.d.ts +7 -0
- package/dist/api/mp.d.ts +6 -0
- package/dist/api/mp.js +22 -0
- package/dist/api/optimade.d.ts +45 -0
- package/dist/api/optimade.js +135 -0
- package/dist/brillouin/BrillouinZone.svelte +549 -0
- package/dist/brillouin/BrillouinZone.svelte.d.ts +83 -0
- package/dist/brillouin/BrillouinZoneControls.svelte +144 -0
- package/dist/brillouin/BrillouinZoneControls.svelte.d.ts +17 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +15 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +146 -0
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +13 -0
- package/dist/brillouin/BrillouinZoneScene.svelte +476 -0
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +48 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte +92 -0
- package/dist/brillouin/BrillouinZoneTooltip.svelte.d.ts +8 -0
- package/dist/brillouin/compute.d.ts +17 -0
- package/dist/brillouin/compute.js +426 -0
- package/dist/brillouin/index.d.ts +8 -0
- package/dist/brillouin/index.js +7 -0
- package/dist/brillouin/types.d.ts +43 -0
- package/dist/brillouin/types.js +1 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte +327 -0
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +846 -0
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +3193 -0
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
- package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
- package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
- package/dist/chempot-diagram/async-compute.svelte.js +78 -0
- package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
- package/dist/chempot-diagram/chempot-worker.js +11 -0
- package/dist/chempot-diagram/color.d.ts +10 -0
- package/dist/chempot-diagram/color.js +32 -0
- package/dist/chempot-diagram/compute.d.ts +48 -0
- package/dist/chempot-diagram/compute.js +806 -0
- package/dist/chempot-diagram/index.d.ts +6 -0
- package/dist/chempot-diagram/index.js +6 -0
- package/dist/chempot-diagram/pointer.d.ts +16 -0
- package/dist/chempot-diagram/pointer.js +40 -0
- package/dist/chempot-diagram/temperature.d.ts +15 -0
- package/dist/chempot-diagram/temperature.js +34 -0
- package/dist/chempot-diagram/types.d.ts +81 -0
- package/dist/chempot-diagram/types.js +28 -0
- package/dist/colors/index.d.ts +47 -0
- package/dist/colors/index.js +203 -0
- package/dist/composition/BarChart.svelte +297 -0
- package/dist/composition/BarChart.svelte.d.ts +39 -0
- package/dist/composition/BubbleChart.svelte +218 -0
- package/dist/composition/BubbleChart.svelte.d.ts +28 -0
- package/dist/composition/Composition.svelte +165 -0
- package/dist/composition/Composition.svelte.d.ts +15 -0
- package/dist/composition/Formula.svelte +268 -0
- package/dist/composition/Formula.svelte.d.ts +19 -0
- package/dist/composition/FormulaFilter.svelte +1257 -0
- package/dist/composition/FormulaFilter.svelte.d.ts +51 -0
- package/dist/composition/PieChart.svelte +323 -0
- package/dist/composition/PieChart.svelte.d.ts +37 -0
- package/dist/composition/format.d.ts +15 -0
- package/dist/composition/format.js +109 -0
- package/dist/composition/index.d.ts +20 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +56 -0
- package/dist/composition/parse.js +474 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.js +99 -0
- package/dist/controls.d.ts +14 -0
- package/dist/controls.js +30 -0
- package/dist/convex-hull/ConvexHull.svelte +157 -0
- package/dist/convex-hull/ConvexHull.svelte.d.ts +13 -0
- package/dist/convex-hull/ConvexHull2D.svelte +825 -0
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +11 -0
- package/dist/convex-hull/ConvexHull3D.svelte +1801 -0
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHull4D.svelte +1398 -0
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +8 -0
- package/dist/convex-hull/ConvexHullControls.svelte +535 -0
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +48 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte +125 -0
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +20 -0
- package/dist/convex-hull/ConvexHullStats.svelte +929 -0
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +17 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte +131 -0
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +33 -0
- package/dist/convex-hull/GasPressureControls.svelte +247 -0
- package/dist/convex-hull/GasPressureControls.svelte.d.ts +11 -0
- package/dist/convex-hull/StructurePopup.svelte +151 -0
- package/dist/convex-hull/StructurePopup.svelte.d.ts +18 -0
- package/dist/convex-hull/TemperatureSlider.svelte.d.ts +8 -0
- package/dist/convex-hull/barycentric-coords.d.ts +18 -0
- package/dist/convex-hull/barycentric-coords.js +182 -0
- package/dist/convex-hull/demo-temperature.d.ts +6 -0
- package/dist/convex-hull/demo-temperature.js +40 -0
- package/dist/convex-hull/gas-thermodynamics.d.ts +16 -0
- package/dist/convex-hull/gas-thermodynamics.js +314 -0
- package/dist/convex-hull/helpers.d.ts +114 -0
- package/dist/convex-hull/helpers.js +710 -0
- package/dist/convex-hull/index.d.ts +119 -0
- package/dist/convex-hull/index.js +58 -0
- package/dist/convex-hull/thermodynamics.d.ts +67 -0
- package/dist/convex-hull/thermodynamics.js +1752 -0
- package/dist/convex-hull/types.d.ts +162 -0
- package/dist/convex-hull/types.js +36 -0
- package/dist/coordination/CoordinationBarPlot.svelte +311 -0
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +30 -0
- package/dist/coordination/calc-coordination.d.ts +15 -0
- package/dist/coordination/calc-coordination.js +63 -0
- package/dist/coordination/index.d.ts +8 -0
- package/dist/coordination/index.js +7 -0
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte.d.ts +20 -0
- package/dist/element/ElementHeading.svelte +26 -0
- package/dist/element/ElementHeading.svelte.d.ts +8 -0
- package/dist/element/ElementPhoto.svelte +57 -0
- package/dist/element/ElementPhoto.svelte.d.ts +9 -0
- package/dist/element/ElementStats.svelte +80 -0
- package/dist/element/ElementStats.svelte.d.ts +8 -0
- package/dist/element/ElementTile.svelte +484 -0
- package/dist/element/ElementTile.svelte.d.ts +29 -0
- package/dist/element/Nucleus.svelte.d.ts +17 -0
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +2 -0
- package/dist/element/index.d.ts +8 -0
- package/dist/element/index.js +7 -0
- package/dist/element/types.d.ts +57 -0
- package/dist/element/types.js +1 -0
- package/dist/feedback/ClickFeedback.svelte +58 -0
- package/dist/feedback/ClickFeedback.svelte.d.ts +12 -0
- package/dist/feedback/DragOverlay.svelte +42 -0
- package/dist/feedback/DragOverlay.svelte.d.ts +7 -0
- package/dist/feedback/Spinner.svelte.d.ts +7 -0
- package/dist/feedback/StatusMessage.svelte.d.ts +9 -0
- package/dist/feedback/index.d.ts +4 -0
- package/dist/feedback/index.js +4 -0
- package/dist/fermi-surface/FermiSlice.svelte +189 -0
- package/dist/fermi-surface/FermiSlice.svelte.d.ts +24 -0
- package/dist/fermi-surface/FermiSurface.svelte +600 -0
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +83 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte +448 -0
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +35 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte +794 -0
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +50 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +111 -0
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte.d.ts +8 -0
- package/dist/fermi-surface/compute.d.ts +5 -0
- package/dist/fermi-surface/compute.js +538 -0
- package/dist/fermi-surface/constants.d.ts +9 -0
- package/dist/fermi-surface/constants.js +27 -0
- package/dist/fermi-surface/export.d.ts +5 -0
- package/dist/fermi-surface/export.js +50 -0
- package/dist/fermi-surface/index.d.ts +12 -0
- package/dist/fermi-surface/index.js +13 -0
- package/dist/fermi-surface/marching-cubes.d.ts +2 -0
- package/dist/fermi-surface/marching-cubes.js +2 -0
- package/dist/fermi-surface/parse.d.ts +2 -0
- package/dist/fermi-surface/parse.js +491 -0
- package/dist/fermi-surface/symmetry.d.ts +3 -0
- package/dist/fermi-surface/symmetry.js +46 -0
- package/dist/fermi-surface/types.d.ts +110 -0
- package/dist/fermi-surface/types.js +4 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1545 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +225 -0
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +30 -0
- package/dist/heatmap-matrix/index.d.ts +53 -0
- package/dist/heatmap-matrix/index.js +100 -0
- package/dist/heatmap-matrix/shared.d.ts +2 -0
- package/dist/heatmap-matrix/shared.js +4 -0
- package/dist/icons.d.ts +569 -0
- package/dist/icons.js +648 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +39 -0
- package/dist/io/decompress.d.ts +11 -0
- package/dist/io/decompress.js +74 -0
- package/dist/io/export.d.ts +16 -0
- package/dist/io/export.js +316 -0
- package/dist/io/fetch.d.ts +5 -0
- package/dist/io/fetch.js +39 -0
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +43 -0
- package/dist/io/index.d.ts +7 -0
- package/dist/io/index.js +6 -0
- package/dist/io/is-binary.d.ts +1 -0
- package/dist/io/is-binary.js +20 -0
- package/dist/io/types.d.ts +8 -0
- package/dist/io/types.js +1 -0
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +123 -0
- package/dist/isosurface/Isosurface.svelte +285 -0
- package/dist/isosurface/Isosurface.svelte.d.ts +8 -0
- package/dist/isosurface/IsosurfaceControls.svelte +277 -0
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +9 -0
- package/dist/isosurface/index.d.ts +5 -0
- package/dist/isosurface/index.js +6 -0
- package/dist/isosurface/parse.d.ts +6 -0
- package/dist/isosurface/parse.js +553 -0
- package/dist/isosurface/slice.d.ts +11 -0
- package/dist/isosurface/slice.js +140 -0
- package/dist/isosurface/types.d.ts +56 -0
- package/dist/isosurface/types.js +227 -0
- package/dist/labels.d.ts +53 -0
- package/dist/labels.js +277 -0
- package/dist/layout/FullscreenToggle.svelte +50 -0
- package/dist/layout/FullscreenToggle.svelte.d.ts +7 -0
- package/dist/layout/InfoCard.svelte +120 -0
- package/dist/layout/InfoCard.svelte.d.ts +21 -0
- package/dist/layout/InfoTag.svelte +185 -0
- package/dist/layout/InfoTag.svelte.d.ts +19 -0
- package/dist/layout/PropertyFilter.svelte +246 -0
- package/dist/layout/PropertyFilter.svelte.d.ts +24 -0
- package/dist/layout/SettingsSection.svelte +148 -0
- package/dist/layout/SettingsSection.svelte.d.ts +17 -0
- package/dist/layout/SubpageGrid.svelte +82 -0
- package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
- package/dist/layout/fullscreen.d.ts +9 -0
- package/dist/layout/fullscreen.js +53 -0
- package/dist/layout/index.d.ts +10 -0
- package/dist/layout/index.js +8 -0
- package/dist/layout/json-tree/JsonNode.svelte +548 -0
- package/dist/layout/json-tree/JsonNode.svelte.d.ts +11 -0
- package/dist/layout/json-tree/JsonTree.svelte +1230 -0
- package/dist/layout/json-tree/JsonTree.svelte.d.ts +6 -0
- package/dist/layout/json-tree/JsonValue.svelte.d.ts +9 -0
- package/dist/layout/json-tree/index.d.ts +3 -0
- package/dist/layout/json-tree/index.js +3 -0
- package/dist/layout/json-tree/types.d.ts +74 -0
- package/dist/layout/json-tree/types.js +2 -0
- package/dist/layout/json-tree/utils.d.ts +29 -0
- package/dist/layout/json-tree/utils.js +641 -0
- package/dist/marching-cubes.d.ts +14 -0
- package/dist/marching-cubes.js +540 -0
- package/dist/math.d.ts +101 -0
- package/dist/math.js +905 -0
- package/dist/overlays/ContextMenu.svelte +162 -0
- package/dist/overlays/ContextMenu.svelte.d.ts +25 -0
- package/dist/overlays/CopyButton.svelte +45 -0
- package/dist/overlays/CopyButton.svelte.d.ts +8 -0
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +487 -0
- package/dist/overlays/DraggablePane.svelte.d.ts +36 -0
- package/dist/overlays/InfoPaneCards.svelte +149 -0
- package/dist/overlays/InfoPaneCards.svelte.d.ts +22 -0
- package/dist/overlays/index.d.ts +3 -0
- package/dist/overlays/index.js +3 -0
- package/dist/periodic-table/PeriodicTable.svelte +469 -0
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +55 -0
- package/dist/periodic-table/PeriodicTableControls.svelte +557 -0
- package/dist/periodic-table/PeriodicTableControls.svelte.d.ts +24 -0
- package/dist/periodic-table/PropertySelect.svelte +37 -0
- package/dist/periodic-table/PropertySelect.svelte.d.ts +13 -0
- package/dist/periodic-table/TableInset.svelte.d.ts +9 -0
- package/dist/periodic-table/index.d.ts +10 -0
- package/dist/periodic-table/index.js +4 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +1086 -0
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +44 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte +444 -0
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +30 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +126 -0
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +184 -0
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +19 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +391 -0
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +16 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte +203 -0
- package/dist/phase-diagram/TdbInfoPanel.svelte.d.ts +12 -0
- package/dist/phase-diagram/build-diagram.d.ts +11 -0
- package/dist/phase-diagram/build-diagram.js +160 -0
- package/dist/phase-diagram/colors.d.ts +35 -0
- package/dist/phase-diagram/colors.js +51 -0
- package/dist/phase-diagram/diagram-input.d.ts +29 -0
- package/dist/phase-diagram/diagram-input.js +3 -0
- package/dist/phase-diagram/index.d.ts +13 -0
- package/dist/phase-diagram/index.js +11 -0
- package/dist/phase-diagram/parse.d.ts +55 -0
- package/dist/phase-diagram/parse.js +272 -0
- package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
- package/dist/phase-diagram/svg-to-diagram.js +867 -0
- package/dist/phase-diagram/types.d.ts +93 -0
- package/dist/phase-diagram/types.js +1 -0
- package/dist/phase-diagram/utils.d.ts +118 -0
- package/dist/phase-diagram/utils.js +604 -0
- package/dist/plot/AxisLabel.svelte +51 -0
- package/dist/plot/AxisLabel.svelte.d.ts +16 -0
- package/dist/plot/BarPlot.svelte +2113 -0
- package/dist/plot/BarPlot.svelte.d.ts +84 -0
- package/dist/plot/BarPlotControls.svelte +66 -0
- package/dist/plot/BarPlotControls.svelte.d.ts +18 -0
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +721 -0
- package/dist/plot/ColorBar.svelte.d.ts +31 -0
- package/dist/plot/ColorScaleSelect.svelte +54 -0
- package/dist/plot/ColorScaleSelect.svelte.d.ts +15 -0
- package/dist/plot/ElementScatter.svelte +63 -0
- package/dist/plot/ElementScatter.svelte.d.ts +14 -0
- package/dist/plot/FillArea.svelte.d.ts +21 -0
- package/dist/plot/Histogram.svelte +1558 -0
- package/dist/plot/Histogram.svelte.d.ts +50 -0
- package/dist/plot/HistogramControls.svelte +212 -0
- package/dist/plot/HistogramControls.svelte.d.ts +22 -0
- package/dist/plot/InteractiveAxisLabel.svelte +96 -0
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +14 -0
- package/dist/plot/Line.svelte +84 -0
- package/dist/plot/Line.svelte.d.ts +15 -0
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte +537 -0
- package/dist/plot/PlotControls.svelte.d.ts +4 -0
- package/dist/plot/PlotLegend.svelte +569 -0
- package/dist/plot/PlotLegend.svelte.d.ts +29 -0
- package/dist/plot/PlotTooltip.svelte +67 -0
- package/dist/plot/PlotTooltip.svelte.d.ts +17 -0
- package/dist/plot/PortalSelect.svelte +253 -0
- package/dist/plot/PortalSelect.svelte.d.ts +16 -0
- package/dist/plot/ReferenceLine.svelte.d.ts +20 -0
- package/dist/plot/ReferenceLine3D.svelte +156 -0
- package/dist/plot/ReferenceLine3D.svelte.d.ts +14 -0
- package/dist/plot/ReferencePlane.svelte +175 -0
- package/dist/plot/ReferencePlane.svelte.d.ts +14 -0
- package/dist/plot/ScatterPlot.svelte +2778 -0
- package/dist/plot/ScatterPlot.svelte.d.ts +96 -0
- package/dist/plot/ScatterPlot3D.svelte +529 -0
- package/dist/plot/ScatterPlot3D.svelte.d.ts +95 -0
- package/dist/plot/ScatterPlot3DControls.svelte +437 -0
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +20 -0
- package/dist/plot/ScatterPlot3DScene.svelte +912 -0
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +74 -0
- package/dist/plot/ScatterPlotControls.svelte +306 -0
- package/dist/plot/ScatterPlotControls.svelte.d.ts +17 -0
- package/dist/plot/ScatterPoint.svelte +182 -0
- package/dist/plot/ScatterPoint.svelte.d.ts +22 -0
- package/dist/plot/SpacegroupBarPlot.svelte +293 -0
- package/dist/plot/SpacegroupBarPlot.svelte.d.ts +9 -0
- package/dist/plot/Surface3D.svelte +197 -0
- package/dist/plot/Surface3D.svelte.d.ts +13 -0
- package/dist/plot/ZeroLines.svelte +97 -0
- package/dist/plot/ZeroLines.svelte.d.ts +33 -0
- package/dist/plot/ZoomRect.svelte +23 -0
- package/dist/plot/ZoomRect.svelte.d.ts +8 -0
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.d.ts +19 -0
- package/dist/plot/axis-utils.js +78 -0
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.d.ts +37 -0
- package/dist/plot/data-cleaning.js +855 -0
- package/dist/plot/data-transform.d.ts +16 -0
- package/dist/plot/data-transform.js +45 -0
- package/dist/plot/defaults.d.ts +19 -0
- package/dist/plot/defaults.js +9 -0
- package/dist/plot/fill-utils.d.ts +46 -0
- package/dist/plot/fill-utils.js +322 -0
- package/dist/plot/hover-lock.svelte.d.ts +14 -0
- package/dist/plot/hover-lock.svelte.js +46 -0
- package/dist/plot/index.d.ts +41 -0
- package/dist/plot/index.js +39 -0
- package/dist/plot/interactions.d.ts +12 -0
- package/dist/plot/interactions.js +101 -0
- package/dist/plot/layout.d.ts +78 -0
- package/dist/plot/layout.js +273 -0
- package/dist/plot/reference-line.d.ts +60 -0
- package/dist/plot/reference-line.js +314 -0
- package/dist/plot/scales.d.ts +48 -0
- package/dist/plot/scales.js +481 -0
- package/dist/plot/svg.d.ts +1 -0
- package/dist/plot/svg.js +11 -0
- package/dist/plot/types.d.ts +831 -0
- package/dist/plot/types.js +99 -0
- package/dist/plot/utils/label-placement.d.ts +68 -0
- package/dist/plot/utils/label-placement.js +326 -0
- package/dist/plot/utils/series-visibility.d.ts +15 -0
- package/dist/plot/utils/series-visibility.js +85 -0
- package/dist/plot/utils.d.ts +1 -0
- package/dist/plot/utils.js +14 -0
- package/dist/rdf/RdfPlot.svelte +247 -0
- package/dist/rdf/RdfPlot.svelte.d.ts +27 -0
- package/dist/rdf/calc-rdf.d.ts +4 -0
- package/dist/rdf/calc-rdf.js +111 -0
- package/dist/rdf/index.d.ts +23 -0
- package/dist/rdf/index.js +2 -0
- package/dist/sanitize.d.ts +6 -0
- package/dist/sanitize.js +116 -0
- package/dist/settings.d.ts +255 -0
- package/dist/settings.js +1132 -0
- package/dist/spectral/Bands.svelte +1040 -0
- package/dist/spectral/Bands.svelte.d.ts +40 -0
- package/dist/spectral/BandsAndDos.svelte +134 -0
- package/dist/spectral/BandsAndDos.svelte.d.ts +18 -0
- package/dist/spectral/BrillouinBandsDos.svelte +252 -0
- package/dist/spectral/BrillouinBandsDos.svelte.d.ts +20 -0
- package/dist/spectral/Dos.svelte +697 -0
- package/dist/spectral/Dos.svelte.d.ts +29 -0
- package/dist/spectral/helpers.d.ts +119 -0
- package/dist/spectral/helpers.js +1032 -0
- package/dist/spectral/index.d.ts +6 -0
- package/dist/spectral/index.js +6 -0
- package/dist/spectral/types.d.ts +84 -0
- package/dist/spectral/types.js +2 -0
- package/dist/state.svelte.d.ts +25 -0
- package/dist/state.svelte.js +45 -0
- package/dist/structure/Arrow.svelte +72 -0
- package/dist/structure/Arrow.svelte.d.ts +15 -0
- package/dist/structure/AtomLegend.svelte +815 -0
- package/dist/structure/AtomLegend.svelte.d.ts +35 -0
- package/dist/structure/Bond.svelte +140 -0
- package/dist/structure/Bond.svelte.d.ts +9 -0
- package/dist/structure/CanvasTooltip.svelte +33 -0
- package/dist/structure/CanvasTooltip.svelte.d.ts +12 -0
- package/dist/structure/CellSelect.svelte +349 -0
- package/dist/structure/CellSelect.svelte.d.ts +13 -0
- package/dist/structure/Cylinder.svelte +45 -0
- package/dist/structure/Cylinder.svelte.d.ts +10 -0
- package/dist/structure/Lattice.svelte +196 -0
- package/dist/structure/Lattice.svelte.d.ts +17 -0
- package/dist/structure/Structure.svelte +2248 -0
- package/dist/structure/Structure.svelte.d.ts +89 -0
- package/dist/structure/StructureControls.svelte +1273 -0
- package/dist/structure/StructureControls.svelte.d.ts +31 -0
- package/dist/structure/StructureExportPane.svelte +252 -0
- package/dist/structure/StructureExportPane.svelte.d.ts +17 -0
- package/dist/structure/StructureInfoPane.svelte +737 -0
- package/dist/structure/StructureInfoPane.svelte.d.ts +19 -0
- package/dist/structure/StructureScene.svelte +2255 -0
- package/dist/structure/StructureScene.svelte.d.ts +111 -0
- package/dist/structure/atom-properties.d.ts +37 -0
- package/dist/structure/atom-properties.js +200 -0
- package/dist/structure/bond-order-perception.d.ts +13 -0
- package/dist/structure/bond-order-perception.js +384 -0
- package/dist/structure/bonding.d.ts +68 -0
- package/dist/structure/bonding.js +696 -0
- package/dist/structure/export.d.ts +20 -0
- package/dist/structure/export.js +727 -0
- package/dist/structure/index.d.ts +126 -0
- package/dist/structure/index.js +169 -0
- package/dist/structure/label-placement.d.ts +14 -0
- package/dist/structure/label-placement.js +72 -0
- package/dist/structure/measure.d.ts +6 -0
- package/dist/structure/measure.js +29 -0
- package/dist/structure/parse.d.ts +66 -0
- package/dist/structure/parse.js +1392 -0
- package/dist/structure/partial-occupancy.d.ts +25 -0
- package/dist/structure/partial-occupancy.js +99 -0
- package/dist/structure/pbc.d.ts +9 -0
- package/dist/structure/pbc.js +123 -0
- package/dist/structure/supercell.d.ts +8 -0
- package/dist/structure/supercell.js +170 -0
- package/dist/structure/validation.d.ts +2 -0
- package/dist/structure/validation.js +10 -0
- package/dist/symmetry/SymmetryStats.svelte +226 -0
- package/dist/symmetry/SymmetryStats.svelte.d.ts +21 -0
- package/dist/symmetry/WyckoffTable.svelte +120 -0
- package/dist/symmetry/WyckoffTable.svelte.d.ts +11 -0
- package/dist/symmetry/cell-transform.d.ts +12 -0
- package/dist/symmetry/cell-transform.js +91 -0
- package/dist/symmetry/index.d.ts +43 -0
- package/dist/symmetry/index.js +228 -0
- package/dist/symmetry/spacegroups.d.ts +9 -0
- package/dist/symmetry/spacegroups.js +394 -0
- package/dist/table/HeatmapTable.svelte +1833 -0
- package/dist/table/HeatmapTable.svelte.d.ts +49 -0
- package/dist/table/ToggleMenu.svelte +385 -0
- package/dist/table/ToggleMenu.svelte.d.ts +11 -0
- package/dist/table/index.d.ts +74 -0
- package/dist/table/index.js +38 -0
- package/dist/theme/ThemeControl.svelte +53 -0
- package/dist/theme/ThemeControl.svelte.d.ts +9 -0
- package/dist/theme/index.d.ts +29 -0
- package/dist/theme/index.js +79 -0
- package/dist/time.d.ts +4 -0
- package/dist/time.js +70 -0
- package/dist/tooltip/TooltipContent.svelte +58 -0
- package/dist/tooltip/TooltipContent.svelte.d.ts +31 -0
- package/dist/tooltip/index.d.ts +2 -0
- package/dist/tooltip/index.js +1 -0
- package/dist/tooltip/types.d.ts +8 -0
- package/dist/tooltip/types.js +1 -0
- package/dist/trajectory/Trajectory.svelte +1545 -0
- package/dist/trajectory/Trajectory.svelte.d.ts +77 -0
- package/dist/trajectory/TrajectoryError.svelte +128 -0
- package/dist/trajectory/TrajectoryError.svelte.d.ts +13 -0
- package/dist/trajectory/TrajectoryExportPane.svelte +357 -0
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +17 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte +313 -0
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +17 -0
- package/dist/trajectory/constants.d.ts +6 -0
- package/dist/trajectory/constants.js +7 -0
- package/dist/trajectory/extract.d.ts +5 -0
- package/dist/trajectory/extract.js +162 -0
- package/dist/trajectory/format-detect.d.ts +9 -0
- package/dist/trajectory/format-detect.js +76 -0
- package/dist/trajectory/frame-reader.d.ts +17 -0
- package/dist/trajectory/frame-reader.js +332 -0
- package/dist/trajectory/helpers.d.ts +15 -0
- package/dist/trajectory/helpers.js +164 -0
- package/dist/trajectory/index.d.ts +63 -0
- package/dist/trajectory/index.js +126 -0
- package/dist/trajectory/parse/ase.d.ts +2 -0
- package/dist/trajectory/parse/ase.js +73 -0
- package/dist/trajectory/parse/hdf5.d.ts +2 -0
- package/dist/trajectory/parse/hdf5.js +127 -0
- package/dist/trajectory/parse/index.d.ts +12 -0
- package/dist/trajectory/parse/index.js +298 -0
- package/dist/trajectory/parse/lammps.d.ts +5 -0
- package/dist/trajectory/parse/lammps.js +179 -0
- package/dist/trajectory/parse/vasp.d.ts +2 -0
- package/dist/trajectory/parse/vasp.js +68 -0
- package/dist/trajectory/parse/xyz.d.ts +2 -0
- package/dist/trajectory/parse/xyz.js +110 -0
- package/dist/trajectory/plotting.d.ts +28 -0
- package/dist/trajectory/plotting.js +423 -0
- package/dist/trajectory/types.d.ts +11 -0
- package/dist/trajectory/types.js +1 -0
- package/dist/utils.d.ts +6 -0
- package/dist/utils.js +45 -0
- package/dist/xrd/XrdPlot.svelte +615 -0
- package/dist/xrd/XrdPlot.svelte.d.ts +28 -0
- package/dist/xrd/broadening.d.ts +20 -0
- package/dist/xrd/broadening.js +97 -0
- package/dist/xrd/calc-xrd.d.ts +37 -0
- package/dist/xrd/calc-xrd.js +336 -0
- package/dist/xrd/index.d.ts +37 -0
- package/dist/xrd/index.js +4 -0
- package/dist/xrd/parse.d.ts +13 -0
- package/dist/xrd/parse.js +749 -0
- package/license +1 -1
- package/package.json +232 -1457
- package/readme.md +98 -171
- package/.vscode/launch.json +0 -13
- package/.vscodeignore +0 -7
- package/dist/assets/STLExporter-BpTH3YHE.js +0 -8
- package/dist/assets/browser-DdDecX_W.js +0 -1
- package/dist/assets/export-qgn-H9y6.js +0 -2
- package/dist/assets/main-DiKYzti2.css +0 -1
- package/dist/assets/moyo_wasm_bg-0ocwg7xY.wasm +0 -0
- package/dist/extension.js +0 -31293
- package/dist/src/lib/FilePicker.svelte +0 -360
- package/dist/src/lib/MillerIndexInput.svelte +0 -66
- package/dist/src/lib/api/mp.ts +0 -26
- package/dist/src/lib/api/optimade.ts +0 -204
- package/dist/src/lib/brillouin/BrillouinZone.svelte +0 -549
- package/dist/src/lib/brillouin/BrillouinZoneControls.svelte +0 -144
- package/dist/src/lib/brillouin/BrillouinZoneExportPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneInfoPane.svelte +0 -146
- package/dist/src/lib/brillouin/BrillouinZoneScene.svelte +0 -476
- package/dist/src/lib/brillouin/BrillouinZoneTooltip.svelte +0 -92
- package/dist/src/lib/brillouin/compute.ts +0 -529
- package/dist/src/lib/brillouin/index.ts +0 -8
- package/dist/src/lib/brillouin/types.ts +0 -51
- package/dist/src/lib/chempot-diagram/ChemPotDiagram.svelte +0 -327
- package/dist/src/lib/chempot-diagram/ChemPotDiagram2D.svelte +0 -846
- package/dist/src/lib/chempot-diagram/ChemPotDiagram3D.svelte +0 -3193
- package/dist/src/lib/chempot-diagram/async-compute.svelte.ts +0 -94
- package/dist/src/lib/chempot-diagram/chempot-worker.ts +0 -11
- package/dist/src/lib/chempot-diagram/color.ts +0 -42
- package/dist/src/lib/chempot-diagram/compute.ts +0 -1014
- package/dist/src/lib/chempot-diagram/index.ts +0 -6
- package/dist/src/lib/chempot-diagram/pointer.ts +0 -56
- package/dist/src/lib/chempot-diagram/temperature.ts +0 -77
- package/dist/src/lib/chempot-diagram/types.ts +0 -130
- package/dist/src/lib/colors/index.ts +0 -249
- package/dist/src/lib/composition/BarChart.svelte +0 -297
- package/dist/src/lib/composition/BubbleChart.svelte +0 -218
- package/dist/src/lib/composition/Composition.svelte +0 -165
- package/dist/src/lib/composition/Formula.svelte +0 -268
- package/dist/src/lib/composition/FormulaFilter.svelte +0 -1257
- package/dist/src/lib/composition/PieChart.svelte +0 -323
- package/dist/src/lib/composition/format.ts +0 -155
- package/dist/src/lib/composition/index.ts +0 -37
- package/dist/src/lib/composition/parse.ts +0 -605
- package/dist/src/lib/constants.ts +0 -134
- package/dist/src/lib/controls.ts +0 -42
- package/dist/src/lib/convex-hull/ConvexHull.svelte +0 -157
- package/dist/src/lib/convex-hull/ConvexHull2D.svelte +0 -825
- package/dist/src/lib/convex-hull/ConvexHull3D.svelte +0 -1801
- package/dist/src/lib/convex-hull/ConvexHull4D.svelte +0 -1398
- package/dist/src/lib/convex-hull/ConvexHullControls.svelte +0 -535
- package/dist/src/lib/convex-hull/ConvexHullInfoPane.svelte +0 -125
- package/dist/src/lib/convex-hull/ConvexHullStats.svelte +0 -929
- package/dist/src/lib/convex-hull/ConvexHullTooltip.svelte +0 -131
- package/dist/src/lib/convex-hull/GasPressureControls.svelte +0 -247
- package/dist/src/lib/convex-hull/StructurePopup.svelte +0 -151
- package/dist/src/lib/convex-hull/barycentric-coords.ts +0 -246
- package/dist/src/lib/convex-hull/demo-temperature.ts +0 -63
- package/dist/src/lib/convex-hull/gas-thermodynamics.ts +0 -405
- package/dist/src/lib/convex-hull/helpers.ts +0 -932
- package/dist/src/lib/convex-hull/index.ts +0 -202
- package/dist/src/lib/convex-hull/thermodynamics.ts +0 -2192
- package/dist/src/lib/convex-hull/types.ts +0 -267
- package/dist/src/lib/coordination/CoordinationBarPlot.svelte +0 -311
- package/dist/src/lib/coordination/calc-coordination.ts +0 -93
- package/dist/src/lib/coordination/index.ts +0 -9
- package/dist/src/lib/effects.svelte.ts +0 -48
- package/dist/src/lib/element/ElementHeading.svelte +0 -26
- package/dist/src/lib/element/ElementPhoto.svelte +0 -57
- package/dist/src/lib/element/ElementStats.svelte +0 -80
- package/dist/src/lib/element/ElementTile.svelte +0 -484
- package/dist/src/lib/element/data.ts +0 -14
- package/dist/src/lib/element/index.ts +0 -8
- package/dist/src/lib/element/types.ts +0 -62
- package/dist/src/lib/feedback/ClickFeedback.svelte +0 -58
- package/dist/src/lib/feedback/DragOverlay.svelte +0 -42
- package/dist/src/lib/feedback/index.ts +0 -4
- package/dist/src/lib/fermi-surface/FermiSlice.svelte +0 -189
- package/dist/src/lib/fermi-surface/FermiSurface.svelte +0 -600
- package/dist/src/lib/fermi-surface/FermiSurfaceControls.svelte +0 -448
- package/dist/src/lib/fermi-surface/FermiSurfaceScene.svelte +0 -794
- package/dist/src/lib/fermi-surface/FermiSurfaceTooltip.svelte +0 -111
- package/dist/src/lib/fermi-surface/compute.ts +0 -728
- package/dist/src/lib/fermi-surface/constants.ts +0 -32
- package/dist/src/lib/fermi-surface/export.ts +0 -64
- package/dist/src/lib/fermi-surface/index.ts +0 -14
- package/dist/src/lib/fermi-surface/marching-cubes.ts +0 -3
- package/dist/src/lib/fermi-surface/parse.ts +0 -574
- package/dist/src/lib/fermi-surface/symmetry.ts +0 -56
- package/dist/src/lib/fermi-surface/types.ts +0 -159
- package/dist/src/lib/heatmap-matrix/HeatmapMatrix.svelte +0 -1545
- package/dist/src/lib/heatmap-matrix/HeatmapMatrixControls.svelte +0 -225
- package/dist/src/lib/heatmap-matrix/index.ts +0 -167
- package/dist/src/lib/heatmap-matrix/shared.ts +0 -7
- package/dist/src/lib/icons.ts +0 -650
- package/dist/src/lib/index.ts +0 -61
- package/dist/src/lib/io/decompress.ts +0 -92
- package/dist/src/lib/io/export.ts +0 -385
- package/dist/src/lib/io/fetch.ts +0 -46
- package/dist/src/lib/io/file-drop.ts +0 -51
- package/dist/src/lib/io/index.ts +0 -7
- package/dist/src/lib/io/is-binary.ts +0 -24
- package/dist/src/lib/io/types.ts +0 -8
- package/dist/src/lib/io/url-drop.ts +0 -141
- package/dist/src/lib/isosurface/Isosurface.svelte +0 -285
- package/dist/src/lib/isosurface/IsosurfaceControls.svelte +0 -277
- package/dist/src/lib/isosurface/index.ts +0 -7
- package/dist/src/lib/isosurface/parse.ts +0 -656
- package/dist/src/lib/isosurface/slice.ts +0 -175
- package/dist/src/lib/isosurface/types.ts +0 -309
- package/dist/src/lib/labels.ts +0 -320
- package/dist/src/lib/layout/FullscreenToggle.svelte +0 -50
- package/dist/src/lib/layout/InfoCard.svelte +0 -120
- package/dist/src/lib/layout/InfoTag.svelte +0 -185
- package/dist/src/lib/layout/PropertyFilter.svelte +0 -246
- package/dist/src/lib/layout/SettingsSection.svelte +0 -148
- package/dist/src/lib/layout/SubpageGrid.svelte +0 -82
- package/dist/src/lib/layout/fullscreen.ts +0 -65
- package/dist/src/lib/layout/index.ts +0 -11
- package/dist/src/lib/layout/json-tree/JsonNode.svelte +0 -548
- package/dist/src/lib/layout/json-tree/JsonTree.svelte +0 -1230
- package/dist/src/lib/layout/json-tree/index.ts +0 -3
- package/dist/src/lib/layout/json-tree/types.ts +0 -126
- package/dist/src/lib/layout/json-tree/utils.ts +0 -682
- package/dist/src/lib/marching-cubes.ts +0 -614
- package/dist/src/lib/math.ts +0 -1081
- package/dist/src/lib/overlays/ContextMenu.svelte +0 -162
- package/dist/src/lib/overlays/CopyButton.svelte +0 -45
- package/dist/src/lib/overlays/DragControlTab.svelte +0 -98
- package/dist/src/lib/overlays/DraggablePane.svelte +0 -487
- package/dist/src/lib/overlays/InfoPaneCards.svelte +0 -149
- package/dist/src/lib/overlays/index.ts +0 -3
- package/dist/src/lib/periodic-table/PeriodicTable.svelte +0 -469
- package/dist/src/lib/periodic-table/PeriodicTableControls.svelte +0 -557
- package/dist/src/lib/periodic-table/PropertySelect.svelte +0 -37
- package/dist/src/lib/periodic-table/index.ts +0 -12
- package/dist/src/lib/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +0 -1086
- package/dist/src/lib/phase-diagram/PhaseDiagramControls.svelte +0 -444
- package/dist/src/lib/phase-diagram/PhaseDiagramEditorPane.svelte +0 -126
- package/dist/src/lib/phase-diagram/PhaseDiagramExportPane.svelte +0 -184
- package/dist/src/lib/phase-diagram/PhaseDiagramTooltip.svelte +0 -391
- package/dist/src/lib/phase-diagram/TdbInfoPanel.svelte +0 -203
- package/dist/src/lib/phase-diagram/build-diagram.ts +0 -186
- package/dist/src/lib/phase-diagram/colors.ts +0 -58
- package/dist/src/lib/phase-diagram/diagram-input.ts +0 -40
- package/dist/src/lib/phase-diagram/index.ts +0 -13
- package/dist/src/lib/phase-diagram/parse.ts +0 -348
- package/dist/src/lib/phase-diagram/svg-to-diagram.ts +0 -1023
- package/dist/src/lib/phase-diagram/types.ts +0 -144
- package/dist/src/lib/phase-diagram/utils.ts +0 -775
- package/dist/src/lib/plot/AxisLabel.svelte +0 -51
- package/dist/src/lib/plot/BarPlot.svelte +0 -2113
- package/dist/src/lib/plot/BarPlotControls.svelte +0 -66
- package/dist/src/lib/plot/BinnedScatterPlot.svelte +0 -1114
- package/dist/src/lib/plot/ColorBar.svelte +0 -721
- package/dist/src/lib/plot/ColorScaleSelect.svelte +0 -54
- package/dist/src/lib/plot/ElementScatter.svelte +0 -63
- package/dist/src/lib/plot/Histogram.svelte +0 -1558
- package/dist/src/lib/plot/HistogramControls.svelte +0 -212
- package/dist/src/lib/plot/InteractiveAxisLabel.svelte +0 -96
- package/dist/src/lib/plot/Line.svelte +0 -84
- package/dist/src/lib/plot/PlotAxis.svelte +0 -169
- package/dist/src/lib/plot/PlotControls.svelte +0 -537
- package/dist/src/lib/plot/PlotLegend.svelte +0 -569
- package/dist/src/lib/plot/PlotTooltip.svelte +0 -67
- package/dist/src/lib/plot/PortalSelect.svelte +0 -253
- package/dist/src/lib/plot/ReferenceLine3D.svelte +0 -156
- package/dist/src/lib/plot/ReferencePlane.svelte +0 -175
- package/dist/src/lib/plot/ScatterPlot.svelte +0 -2778
- package/dist/src/lib/plot/ScatterPlot3D.svelte +0 -529
- package/dist/src/lib/plot/ScatterPlot3DControls.svelte +0 -437
- package/dist/src/lib/plot/ScatterPlot3DScene.svelte +0 -912
- package/dist/src/lib/plot/ScatterPlotControls.svelte +0 -306
- package/dist/src/lib/plot/ScatterPoint.svelte +0 -182
- package/dist/src/lib/plot/SpacegroupBarPlot.svelte +0 -293
- package/dist/src/lib/plot/Surface3D.svelte +0 -197
- package/dist/src/lib/plot/ZeroLines.svelte +0 -97
- package/dist/src/lib/plot/ZoomRect.svelte +0 -23
- package/dist/src/lib/plot/adaptive-density.ts +0 -316
- package/dist/src/lib/plot/auto-place.ts +0 -184
- package/dist/src/lib/plot/axis-utils.ts +0 -122
- package/dist/src/lib/plot/binned-scatter-types.ts +0 -83
- package/dist/src/lib/plot/data-cleaning.ts +0 -1069
- package/dist/src/lib/plot/data-transform.ts +0 -69
- package/dist/src/lib/plot/defaults.ts +0 -9
- package/dist/src/lib/plot/fill-utils.ts +0 -494
- package/dist/src/lib/plot/hover-lock.svelte.ts +0 -60
- package/dist/src/lib/plot/index.ts +0 -53
- package/dist/src/lib/plot/interactions.ts +0 -119
- package/dist/src/lib/plot/layout.ts +0 -425
- package/dist/src/lib/plot/reference-line.ts +0 -426
- package/dist/src/lib/plot/scales.ts +0 -654
- package/dist/src/lib/plot/svg.ts +0 -23
- package/dist/src/lib/plot/types.ts +0 -1144
- package/dist/src/lib/plot/utils/label-placement.ts +0 -541
- package/dist/src/lib/plot/utils/series-visibility.ts +0 -140
- package/dist/src/lib/plot/utils.ts +0 -11
- package/dist/src/lib/rdf/RdfPlot.svelte +0 -247
- package/dist/src/lib/rdf/calc-rdf.ts +0 -167
- package/dist/src/lib/rdf/index.ts +0 -27
- package/dist/src/lib/sanitize.ts +0 -126
- package/dist/src/lib/settings.ts +0 -1479
- package/dist/src/lib/spectral/Bands.svelte +0 -1040
- package/dist/src/lib/spectral/BandsAndDos.svelte +0 -134
- package/dist/src/lib/spectral/BrillouinBandsDos.svelte +0 -252
- package/dist/src/lib/spectral/Dos.svelte +0 -697
- package/dist/src/lib/spectral/helpers.ts +0 -1381
- package/dist/src/lib/spectral/index.ts +0 -8
- package/dist/src/lib/spectral/types.ts +0 -112
- package/dist/src/lib/state.svelte.ts +0 -64
- package/dist/src/lib/structure/Arrow.svelte +0 -72
- package/dist/src/lib/structure/AtomLegend.svelte +0 -815
- package/dist/src/lib/structure/Bond.svelte +0 -140
- package/dist/src/lib/structure/CanvasTooltip.svelte +0 -33
- package/dist/src/lib/structure/CellSelect.svelte +0 -349
- package/dist/src/lib/structure/Cylinder.svelte +0 -45
- package/dist/src/lib/structure/Lattice.svelte +0 -196
- package/dist/src/lib/structure/Structure.svelte +0 -2248
- package/dist/src/lib/structure/StructureControls.svelte +0 -1273
- package/dist/src/lib/structure/StructureExportPane.svelte +0 -252
- package/dist/src/lib/structure/StructureInfoPane.svelte +0 -737
- package/dist/src/lib/structure/StructureScene.svelte +0 -2255
- package/dist/src/lib/structure/atom-properties.ts +0 -316
- package/dist/src/lib/structure/bond-order-perception.ts +0 -447
- package/dist/src/lib/structure/bonding.ts +0 -944
- package/dist/src/lib/structure/export.ts +0 -861
- package/dist/src/lib/structure/index.ts +0 -291
- package/dist/src/lib/structure/label-placement.ts +0 -130
- package/dist/src/lib/structure/measure.ts +0 -45
- package/dist/src/lib/structure/parse.ts +0 -1705
- package/dist/src/lib/structure/partial-occupancy.ts +0 -183
- package/dist/src/lib/structure/pbc.ts +0 -164
- package/dist/src/lib/structure/supercell.ts +0 -226
- package/dist/src/lib/structure/validation.ts +0 -11
- package/dist/src/lib/symmetry/SymmetryStats.svelte +0 -226
- package/dist/src/lib/symmetry/WyckoffTable.svelte +0 -120
- package/dist/src/lib/symmetry/cell-transform.ts +0 -118
- package/dist/src/lib/symmetry/index.ts +0 -348
- package/dist/src/lib/symmetry/spacegroups.ts +0 -404
- package/dist/src/lib/table/HeatmapTable.svelte +0 -1833
- package/dist/src/lib/table/ToggleMenu.svelte +0 -385
- package/dist/src/lib/table/index.ts +0 -139
- package/dist/src/lib/theme/ThemeControl.svelte +0 -53
- package/dist/src/lib/theme/index.ts +0 -107
- package/dist/src/lib/time.ts +0 -71
- package/dist/src/lib/tooltip/TooltipContent.svelte +0 -58
- package/dist/src/lib/tooltip/index.ts +0 -2
- package/dist/src/lib/tooltip/types.ts +0 -13
- package/dist/src/lib/trajectory/Trajectory.svelte +0 -1545
- package/dist/src/lib/trajectory/TrajectoryError.svelte +0 -128
- package/dist/src/lib/trajectory/TrajectoryExportPane.svelte +0 -357
- package/dist/src/lib/trajectory/TrajectoryInfoPane.svelte +0 -313
- package/dist/src/lib/trajectory/constants.ts +0 -7
- package/dist/src/lib/trajectory/extract.ts +0 -196
- package/dist/src/lib/trajectory/format-detect.ts +0 -96
- package/dist/src/lib/trajectory/frame-reader.ts +0 -456
- package/dist/src/lib/trajectory/helpers.ts +0 -217
- package/dist/src/lib/trajectory/index.ts +0 -218
- package/dist/src/lib/trajectory/parse/ase.ts +0 -109
- package/dist/src/lib/trajectory/parse/hdf5.ts +0 -173
- package/dist/src/lib/trajectory/parse/index.ts +0 -411
- package/dist/src/lib/trajectory/parse/lammps.ts +0 -215
- package/dist/src/lib/trajectory/parse/vasp.ts +0 -102
- package/dist/src/lib/trajectory/parse/xyz.ts +0 -143
- package/dist/src/lib/trajectory/plotting.ts +0 -599
- package/dist/src/lib/trajectory/types.ts +0 -13
- package/dist/src/lib/utils.ts +0 -56
- package/dist/src/lib/xrd/XrdPlot.svelte +0 -615
- package/dist/src/lib/xrd/broadening.ts +0 -130
- package/dist/src/lib/xrd/calc-xrd.ts +0 -397
- package/dist/src/lib/xrd/index.ts +0 -38
- package/dist/src/lib/xrd/parse.ts +0 -858
- package/dist/webview.js +0 -29421
- package/icon.png +0 -0
- 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/scripts/sync-config.ts +0 -101
- package/src/declarations.d.ts +0 -2
- package/src/extension.ts +0 -972
- package/src/node-io.ts +0 -65
- package/src/types.ts +0 -17
- package/src/webview/JsonBrowser.svelte +0 -1079
- package/src/webview/PlotPanel.svelte +0 -346
- package/src/webview/detect.ts +0 -444
- package/src/webview/main.ts +0 -764
- package/src/webview/plot-utils.ts +0 -250
- 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 +0 -604
- package/tests/extension.test.ts +0 -2041
- package/tests/node-io.test.ts +0 -39
- package/tests/plot-utils.test.ts +0 -302
- package/tests/vite-plugin-json-gz.test.ts +0 -114
- package/tests/vscode-mock.ts +0 -18
- package/tests/webview.test.ts +0 -231
- package/tsconfig.json +0 -20
- package/vite-plugin-json-gz.ts +0 -29
- package/vite.config.ts +0 -34
- package/vite.extension.config.ts +0 -34
- /package/dist/{src/lib/EmptyState.svelte → EmptyState.svelte} +0 -0
- /package/dist/{src/lib/Icon.svelte → Icon.svelte} +0 -0
- /package/dist/{src/lib/app.css → app.css} +0 -0
- /package/dist/{src/lib/chempot-diagram → chempot-diagram}/ChemPotScene3D.svelte +0 -0
- /package/dist/{src/lib/colors → colors}/alloy-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/dark-mode-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/jmol-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/muted-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/pastel-colors.json +0 -0
- /package/dist/{src/lib/colors → colors}/vesta-colors.json +0 -0
- /package/dist/{src/lib/convex-hull → convex-hull}/TemperatureSlider.svelte +0 -0
- /package/dist/{src/lib/element → element}/BohrAtom.svelte +0 -0
- /package/dist/{src/lib/element → element}/Nucleus.svelte +0 -0
- /package/dist/{src/lib/element → element}/data.json +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz +0 -0
- /package/dist/{src/lib/element → element}/data.json.gz.d.ts +0 -0
- /package/dist/{src/lib/element → element}/data.schema.json +0 -0
- /package/dist/{src/lib/element-image-urls.json → element-image-urls.json} +0 -0
- /package/dist/{src/lib/feedback → feedback}/Spinner.svelte +0 -0
- /package/dist/{src/lib/feedback → feedback}/StatusMessage.svelte +0 -0
- /package/dist/{src/lib/layout → layout}/json-tree/JsonValue.svelte +0 -0
- /package/dist/{src/lib/periodic-table → periodic-table}/TableInset.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/FillArea.svelte +0 -0
- /package/dist/{src/lib/plot → plot}/ReferenceLine.svelte +0 -0
- /package/dist/{src/lib/theme → theme}/themes.mjs +0 -0
- /package/dist/{src/lib/xrd → xrd}/atomic_scattering_params.json +0 -0
|
@@ -1,2255 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { D3InterpolateName } from '$lib/colors'
|
|
3
|
-
import { AXIS_COLORS, get_d3_interpolator, NEG_AXIS_COLORS } from '$lib/colors'
|
|
4
|
-
import type { ElementSymbol } from '$lib/element'
|
|
5
|
-
import { element_data } from '$lib/element'
|
|
6
|
-
import Isosurface from '$lib/isosurface/Isosurface.svelte'
|
|
7
|
-
import type { IsosurfaceSettings, VolumetricData } from '$lib/isosurface/types'
|
|
8
|
-
import { DEFAULT_ISOSURFACE_SETTINGS } from '$lib/isosurface/types'
|
|
9
|
-
import { format_num } from '$lib/labels'
|
|
10
|
-
import type { Vec3 } from '$lib/math'
|
|
11
|
-
import * as math from '$lib/math'
|
|
12
|
-
import type {
|
|
13
|
-
CameraProjection,
|
|
14
|
-
ShowBonds,
|
|
15
|
-
VectorColorMode,
|
|
16
|
-
VectorLayerConfig,
|
|
17
|
-
} from '$lib/settings'
|
|
18
|
-
import { DEFAULTS } from '$lib/settings'
|
|
19
|
-
import { create_pulse_animation } from '$lib/effects.svelte'
|
|
20
|
-
import { colors } from '$lib/state.svelte'
|
|
21
|
-
import type {
|
|
22
|
-
AnyStructure,
|
|
23
|
-
BondEditMode,
|
|
24
|
-
BondOrder,
|
|
25
|
-
BondPair,
|
|
26
|
-
MeasureMode,
|
|
27
|
-
Site,
|
|
28
|
-
StructureBond,
|
|
29
|
-
} from '$lib/structure'
|
|
30
|
-
import {
|
|
31
|
-
Arrow,
|
|
32
|
-
atomic_radii,
|
|
33
|
-
Cylinder,
|
|
34
|
-
get_all_site_vectors,
|
|
35
|
-
get_center_of_mass,
|
|
36
|
-
get_structure_vector_keys,
|
|
37
|
-
Lattice,
|
|
38
|
-
VECTOR_PALETTE,
|
|
39
|
-
} from '$lib/structure'
|
|
40
|
-
import type { AtomColorConfig } from '$lib/structure/atom-properties'
|
|
41
|
-
import {
|
|
42
|
-
get_orig_site_idx,
|
|
43
|
-
get_property_colors,
|
|
44
|
-
} from '$lib/structure/atom-properties'
|
|
45
|
-
import * as measure from '$lib/structure/measure'
|
|
46
|
-
import {
|
|
47
|
-
compute_slice_geometry,
|
|
48
|
-
merge_split_partial_sites,
|
|
49
|
-
PARTIAL_OCCUPANCY_CAP_ARC,
|
|
50
|
-
} from '$lib/structure/partial-occupancy'
|
|
51
|
-
import type { MoyoDataset } from '@spglib/moyo-wasm'
|
|
52
|
-
import { T, useThrelte } from '@threlte/core'
|
|
53
|
-
import * as extras from '@threlte/extras'
|
|
54
|
-
import { type ComponentProps, type Snippet, untrack } from 'svelte'
|
|
55
|
-
import { SvelteMap, SvelteSet } from 'svelte/reactivity'
|
|
56
|
-
import { type Camera, Color, type Mesh, type Object3D, type Scene, Vector3 } from 'three'
|
|
57
|
-
import Bond from './Bond.svelte'
|
|
58
|
-
import type { BondEditResult, BondingStrategy, BondKeyTarget } from './bonding'
|
|
59
|
-
import {
|
|
60
|
-
add_or_restore_bond,
|
|
61
|
-
BONDING_STRATEGIES,
|
|
62
|
-
BOND_ORDER_OPTIONS,
|
|
63
|
-
canonicalize_bond_target,
|
|
64
|
-
delete_bond as apply_delete_bond,
|
|
65
|
-
get_bond_key,
|
|
66
|
-
get_bond_render_matrices,
|
|
67
|
-
get_explicit_bond_metadata,
|
|
68
|
-
set_bond_order as apply_set_bond_order,
|
|
69
|
-
structure_bond_to_bond_pair,
|
|
70
|
-
} from './bonding'
|
|
71
|
-
import {
|
|
72
|
-
CanvasTooltip,
|
|
73
|
-
compose_perceived_bonds,
|
|
74
|
-
perceive_bond_orders,
|
|
75
|
-
} from './index'
|
|
76
|
-
import {
|
|
77
|
-
choose_site_label_offset,
|
|
78
|
-
LABEL_OFFSET_EPS,
|
|
79
|
-
make_label_position_calculator,
|
|
80
|
-
} from './label-placement'
|
|
81
|
-
|
|
82
|
-
type InstancedAtomGroup = {
|
|
83
|
-
element: string
|
|
84
|
-
radius: number
|
|
85
|
-
color: string
|
|
86
|
-
is_image_atom: boolean
|
|
87
|
-
atoms: (typeof atom_data)[number][]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function instanced_atom_group_key(
|
|
91
|
-
{ element, radius, color, is_image_atom, atoms }: InstancedAtomGroup,
|
|
92
|
-
measure_mode: MeasureMode,
|
|
93
|
-
): string {
|
|
94
|
-
const edit_mode_image = measure_mode === `edit-atoms` && is_image_atom
|
|
95
|
-
return `${element}-${format_num(radius, `.3~`)}-${color}-${
|
|
96
|
-
is_image_atom ? `img` : `base`
|
|
97
|
-
}-${edit_mode_image}-${atoms.length}`
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
type EditableAtomHitTarget = {
|
|
101
|
-
site_idx: number
|
|
102
|
-
position: Vec3
|
|
103
|
-
radius: number
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
type BondContextMenu = {
|
|
107
|
-
site_idx_1: number
|
|
108
|
-
site_idx_2: number
|
|
109
|
-
cell_shift?: Vec3
|
|
110
|
-
position: Vec3
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
type BondPointerEvent = PointerEvent & {
|
|
114
|
-
nativeEvent?: PointerEvent
|
|
115
|
-
object?: Object3D
|
|
116
|
-
point?: Vector3
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
type BondContextMenuEvent = MouseEvent & {
|
|
120
|
-
nativeEvent?: MouseEvent
|
|
121
|
-
object?: Object3D
|
|
122
|
-
point?: Vector3
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
let {
|
|
126
|
-
structure = undefined,
|
|
127
|
-
base_structure = undefined,
|
|
128
|
-
atom_radius = DEFAULTS.structure.atom_radius,
|
|
129
|
-
same_size_atoms = false,
|
|
130
|
-
camera_position = DEFAULTS.structure.camera_position,
|
|
131
|
-
camera_target = undefined,
|
|
132
|
-
camera_projection = DEFAULTS.structure.camera_projection,
|
|
133
|
-
rotation_damping = DEFAULTS.structure.rotation_damping,
|
|
134
|
-
max_zoom = DEFAULTS.structure.max_zoom,
|
|
135
|
-
min_zoom = DEFAULTS.structure.min_zoom,
|
|
136
|
-
rotate_speed = DEFAULTS.structure.rotate_speed,
|
|
137
|
-
zoom_speed = DEFAULTS.structure.zoom_speed,
|
|
138
|
-
pan_speed = DEFAULTS.structure.pan_speed,
|
|
139
|
-
zoom_to_cursor = DEFAULTS.structure.zoom_to_cursor,
|
|
140
|
-
show_atoms = DEFAULTS.structure.show_atoms,
|
|
141
|
-
show_bonds = DEFAULTS.structure.show_bonds,
|
|
142
|
-
show_site_labels = DEFAULTS.structure.show_site_labels,
|
|
143
|
-
show_site_indices = DEFAULTS.structure.show_site_indices,
|
|
144
|
-
site_label_size = DEFAULTS.structure.site_label_size,
|
|
145
|
-
site_label_offset = $bindable(DEFAULTS.structure.site_label_offset),
|
|
146
|
-
site_label_bg_color = DEFAULTS.structure.site_label_bg_color,
|
|
147
|
-
site_label_color = DEFAULTS.structure.site_label_color,
|
|
148
|
-
site_label_padding = DEFAULTS.structure.site_label_padding,
|
|
149
|
-
vector_configs = $bindable<Record<string, VectorLayerConfig>>({}),
|
|
150
|
-
vector_scale = DEFAULTS.structure.vector_scale,
|
|
151
|
-
vector_color = DEFAULTS.structure.vector_color,
|
|
152
|
-
vector_color_mode = DEFAULTS.structure.vector_color_mode as VectorColorMode,
|
|
153
|
-
vector_color_scale = DEFAULTS.structure.vector_color_scale,
|
|
154
|
-
vector_normalize = DEFAULTS.structure.vector_normalize,
|
|
155
|
-
vector_uniform_thickness = DEFAULTS.structure.vector_uniform_thickness,
|
|
156
|
-
vector_origin_gap = DEFAULTS.structure.vector_origin_gap,
|
|
157
|
-
vector_shaft_radius = DEFAULTS.structure.vector_shaft_radius,
|
|
158
|
-
vector_arrow_head_radius = DEFAULTS.structure.vector_arrow_head_radius,
|
|
159
|
-
vector_arrow_head_length = DEFAULTS.structure.vector_arrow_head_length,
|
|
160
|
-
gizmo = DEFAULTS.structure.show_gizmo,
|
|
161
|
-
hovered_idx = $bindable(null),
|
|
162
|
-
hovered_site = $bindable(null),
|
|
163
|
-
float_fmt = `.3~f`,
|
|
164
|
-
auto_rotate = DEFAULTS.structure.auto_rotate,
|
|
165
|
-
bond_thickness = DEFAULTS.structure.bond_thickness,
|
|
166
|
-
bond_color = DEFAULTS.structure.bond_color,
|
|
167
|
-
bonding_strategy = DEFAULTS.structure.bonding_strategy,
|
|
168
|
-
auto_bond_order = DEFAULTS.structure.auto_bond_order,
|
|
169
|
-
aromatic_display = DEFAULTS.structure.aromatic_display,
|
|
170
|
-
bonding_options = {},
|
|
171
|
-
fov = DEFAULTS.structure.fov,
|
|
172
|
-
initial_zoom = DEFAULTS.structure.initial_zoom,
|
|
173
|
-
ambient_light = DEFAULTS.structure.ambient_light,
|
|
174
|
-
directional_light = DEFAULTS.structure.directional_light,
|
|
175
|
-
sphere_segments = DEFAULTS.structure.sphere_segments,
|
|
176
|
-
lattice_props = {},
|
|
177
|
-
atom_label,
|
|
178
|
-
camera_is_moving = $bindable(false),
|
|
179
|
-
width = 0,
|
|
180
|
-
height = 0,
|
|
181
|
-
measure_mode = `distance`,
|
|
182
|
-
selected_sites = $bindable([]),
|
|
183
|
-
measured_sites = $bindable([]),
|
|
184
|
-
added_bonds = $bindable([]),
|
|
185
|
-
removed_bonds = $bindable([]),
|
|
186
|
-
bond_order_overrides = $bindable([]),
|
|
187
|
-
bond_edits_enabled = true,
|
|
188
|
-
bond_edit_mode = $bindable<BondEditMode>(`add`),
|
|
189
|
-
bond_edit_order = 1,
|
|
190
|
-
selection_highlight_color = `#6cf0ff`,
|
|
191
|
-
// Active highlight group with different color
|
|
192
|
-
active_sites = $bindable([]),
|
|
193
|
-
active_highlight_color = `var(--struct-active-highlight-color, #2563eb)`,
|
|
194
|
-
rotation = DEFAULTS.structure.rotation,
|
|
195
|
-
scene = $bindable(),
|
|
196
|
-
camera = $bindable(),
|
|
197
|
-
orbit_controls = $bindable(),
|
|
198
|
-
rotation_target_ref = $bindable(),
|
|
199
|
-
initial_computed_zoom = $bindable(),
|
|
200
|
-
hidden_elements = $bindable(new SvelteSet()),
|
|
201
|
-
hidden_prop_vals = $bindable(new SvelteSet<number | string>()),
|
|
202
|
-
element_radius_overrides = $bindable<Partial<Record<ElementSymbol, number>>>({}),
|
|
203
|
-
site_radius_overrides = $bindable<SvelteMap<number, number>>(new SvelteMap()),
|
|
204
|
-
atom_color_config = {
|
|
205
|
-
mode: DEFAULTS.structure.atom_color_mode,
|
|
206
|
-
scale: DEFAULTS.structure.atom_color_scale as D3InterpolateName,
|
|
207
|
-
scale_type: DEFAULTS.structure.atom_color_scale_type,
|
|
208
|
-
},
|
|
209
|
-
sym_data = null,
|
|
210
|
-
// Edit-atoms mode callbacks
|
|
211
|
-
on_sites_moved,
|
|
212
|
-
on_operation_start,
|
|
213
|
-
on_bond_edit_start,
|
|
214
|
-
on_add_atom,
|
|
215
|
-
add_atom_mode = $bindable(false),
|
|
216
|
-
add_element = $bindable(`C`),
|
|
217
|
-
cursor = $bindable(`default`),
|
|
218
|
-
dragging_atoms = $bindable(false),
|
|
219
|
-
volumetric_data = undefined,
|
|
220
|
-
isosurface_settings = DEFAULT_ISOSURFACE_SETTINGS,
|
|
221
|
-
}: {
|
|
222
|
-
structure?: AnyStructure
|
|
223
|
-
base_structure?: AnyStructure // The original structure without image atoms, used for property color calculation
|
|
224
|
-
atom_radius?: number // scale factor for atomic radii
|
|
225
|
-
same_size_atoms?: boolean // whether to use the same radius for all atoms. if not, the radius will be
|
|
226
|
-
// determined by the atomic radius of the element
|
|
227
|
-
camera_position?: [x: number, y: number, z: number] // initial camera position from which to render the scene
|
|
228
|
-
camera_target?: Vec3 // external orbit-controls target for pan synchronization
|
|
229
|
-
camera_projection?: CameraProjection // camera projection type
|
|
230
|
-
rotation_damping?: number // rotation damping factor (how quickly the rotation comes to rest after mouse release)
|
|
231
|
-
// zoom level of the camera
|
|
232
|
-
max_zoom?: number
|
|
233
|
-
min_zoom?: number
|
|
234
|
-
rotate_speed?: number // rotation speed. set to 0 to disable rotation.
|
|
235
|
-
zoom_speed?: number // zoom speed. set to 0 to disable zooming.
|
|
236
|
-
pan_speed?: number // pan speed. set to 0 to disable panning.
|
|
237
|
-
zoom_to_cursor?: boolean // zoom toward cursor position instead of scene center
|
|
238
|
-
show_atoms?: boolean
|
|
239
|
-
show_bonds?: ShowBonds
|
|
240
|
-
show_site_labels?: boolean
|
|
241
|
-
show_site_indices?: boolean
|
|
242
|
-
vector_configs?: Record<string, VectorLayerConfig>
|
|
243
|
-
vector_scale?: number
|
|
244
|
-
vector_color?: string
|
|
245
|
-
vector_color_mode?: VectorColorMode
|
|
246
|
-
vector_color_scale?: D3InterpolateName
|
|
247
|
-
vector_normalize?: boolean
|
|
248
|
-
vector_uniform_thickness?: boolean
|
|
249
|
-
vector_origin_gap?: number
|
|
250
|
-
vector_shaft_radius?: number
|
|
251
|
-
vector_arrow_head_radius?: number
|
|
252
|
-
vector_arrow_head_length?: number
|
|
253
|
-
gizmo?: boolean | ComponentProps<typeof extras.Gizmo>
|
|
254
|
-
hovered_idx?: number | null
|
|
255
|
-
hovered_site?: Site | null
|
|
256
|
-
float_fmt?: string
|
|
257
|
-
auto_rotate?: number
|
|
258
|
-
initial_zoom?: number
|
|
259
|
-
bond_thickness?: number
|
|
260
|
-
bond_color?: string
|
|
261
|
-
bonding_strategy?: BondingStrategy
|
|
262
|
-
auto_bond_order?: boolean
|
|
263
|
-
aromatic_display?: `aromatic` | `kekule`
|
|
264
|
-
bonding_options?: Record<string, unknown>
|
|
265
|
-
fov?: number
|
|
266
|
-
ambient_light?: number
|
|
267
|
-
directional_light?: number
|
|
268
|
-
sphere_segments?: number
|
|
269
|
-
lattice_props?: ComponentProps<typeof Lattice>
|
|
270
|
-
atom_label?: Snippet<[{ site: Site; site_idx: number }]>
|
|
271
|
-
site_label_size?: number
|
|
272
|
-
site_label_offset?: Vec3
|
|
273
|
-
site_label_bg_color?: string
|
|
274
|
-
site_label_color?: string
|
|
275
|
-
site_label_padding?: number
|
|
276
|
-
camera_is_moving?: boolean // used to prevent tooltip from showing while camera is moving
|
|
277
|
-
width?: number // Viewer dimensions for responsive zoom
|
|
278
|
-
height?: number
|
|
279
|
-
// measurement props
|
|
280
|
-
measure_mode?: MeasureMode
|
|
281
|
-
selected_sites?: number[]
|
|
282
|
-
measured_sites?: number[]
|
|
283
|
-
added_bonds?: StructureBond[]
|
|
284
|
-
removed_bonds?: StructureBond[]
|
|
285
|
-
bond_order_overrides?: StructureBond[]
|
|
286
|
-
bond_edits_enabled?: boolean
|
|
287
|
-
bond_edit_mode?: BondEditMode
|
|
288
|
-
bond_edit_order?: BondOrder
|
|
289
|
-
selection_highlight_color?: string
|
|
290
|
-
// Support for active highlight group with different color
|
|
291
|
-
active_sites?: number[]
|
|
292
|
-
active_highlight_color?: string
|
|
293
|
-
rotation?: Vec3 // rotation control prop
|
|
294
|
-
// Expose scene and camera for external use (e.g. export pane)
|
|
295
|
-
scene?: Scene
|
|
296
|
-
camera?: Camera
|
|
297
|
-
orbit_controls?: ComponentProps<typeof extras.OrbitControls>[`ref`] // OrbitControls instance
|
|
298
|
-
rotation_target_ref?: Vec3 // Expose rotation target for reset
|
|
299
|
-
initial_computed_zoom?: number // Expose initial zoom for reset
|
|
300
|
-
hidden_elements?: Set<ElementSymbol>
|
|
301
|
-
hidden_prop_vals?: Set<number | string> // Track hidden property values (e.g. Wyckoff positions, coordination numbers)
|
|
302
|
-
element_radius_overrides?: Partial<Record<ElementSymbol, number>> // Per-element absolute radius in Angstroms
|
|
303
|
-
site_radius_overrides?: Map<number, number> | SvelteMap<number, number> // Per-site absolute radius in Angstroms
|
|
304
|
-
atom_color_config?: Partial<AtomColorConfig> // Atom coloring configuration
|
|
305
|
-
sym_data?: MoyoDataset | null // Symmetry data for Wyckoff coloring
|
|
306
|
-
// Edit-atoms mode callbacks and state
|
|
307
|
-
on_sites_moved?: (scene_indices: number[], delta: Vec3) => void
|
|
308
|
-
on_operation_start?: () => void
|
|
309
|
-
on_bond_edit_start?: () => void
|
|
310
|
-
on_add_atom?: (xyz: Vec3, element: ElementSymbol) => void
|
|
311
|
-
add_atom_mode?: boolean // whether user is in click-to-place add-atom sub-mode
|
|
312
|
-
add_element?: ElementSymbol // element to add when clicking in add-atom mode
|
|
313
|
-
cursor?: string // cursor style for the 3D canvas
|
|
314
|
-
dragging_atoms?: boolean // true while TransformControls drag is active (skips expensive recalculations)
|
|
315
|
-
volumetric_data?: VolumetricData // Active volumetric data for isosurface rendering
|
|
316
|
-
isosurface_settings?: IsosurfaceSettings // Isosurface rendering settings
|
|
317
|
-
} = $props()
|
|
318
|
-
|
|
319
|
-
const pulse = create_pulse_animation(
|
|
320
|
-
() => selected_sites.length > 0 || active_sites.length > 0,
|
|
321
|
-
{ step: 0.015, frequency: 5 },
|
|
322
|
-
)
|
|
323
|
-
let pulse_opacity = $derived(0.15 + 0.25 * pulse.unit)
|
|
324
|
-
|
|
325
|
-
const threlte = useThrelte()
|
|
326
|
-
$effect(() => {
|
|
327
|
-
scene = threlte.scene
|
|
328
|
-
camera = threlte.camera.current
|
|
329
|
-
if (threlte.renderer) {
|
|
330
|
-
Object.assign(threlte.renderer.domElement, { __renderer: threlte.renderer })
|
|
331
|
-
}
|
|
332
|
-
})
|
|
333
|
-
|
|
334
|
-
// Expose rotation target for external reset
|
|
335
|
-
$effect(() => {
|
|
336
|
-
rotation_target_ref = rotation_target
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
// Track initial computed zoom for reset
|
|
340
|
-
let stored_initial_zoom = $state<number | undefined>(undefined)
|
|
341
|
-
$effect(() => {
|
|
342
|
-
if (stored_initial_zoom === undefined && computed_zoom > 0) {
|
|
343
|
-
stored_initial_zoom = computed_zoom
|
|
344
|
-
}
|
|
345
|
-
initial_computed_zoom = stored_initial_zoom
|
|
346
|
-
})
|
|
347
|
-
|
|
348
|
-
let bond_pairs: BondPair[] = $state([])
|
|
349
|
-
let atom_tooltip_active = $state(false)
|
|
350
|
-
let hovered_bond_key = $state<string | null>(null)
|
|
351
|
-
const ATOM_HOVER_CLEAR_DELAY_MS = 200
|
|
352
|
-
let clear_atom_hover_timeout: ReturnType<typeof setTimeout> | null = null
|
|
353
|
-
|
|
354
|
-
function cancel_atom_hover_clear(): void {
|
|
355
|
-
if (clear_atom_hover_timeout == null) return
|
|
356
|
-
clearTimeout(clear_atom_hover_timeout)
|
|
357
|
-
clear_atom_hover_timeout = null
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
function set_atom_hover(site_idx: number): void {
|
|
361
|
-
cancel_atom_hover_clear()
|
|
362
|
-
if (hovered_idx !== site_idx) hovered_idx = site_idx
|
|
363
|
-
if (!atom_tooltip_active) atom_tooltip_active = true
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function schedule_atom_hover_clear(site_idx: number): void {
|
|
367
|
-
cancel_atom_hover_clear()
|
|
368
|
-
clear_atom_hover_timeout = setTimeout(() => {
|
|
369
|
-
clear_atom_hover_timeout = null
|
|
370
|
-
if (hovered_idx !== site_idx) return
|
|
371
|
-
hovered_idx = null
|
|
372
|
-
atom_tooltip_active = false
|
|
373
|
-
}, ATOM_HOVER_CLEAR_DELAY_MS)
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const atom_hover_props = (site_idx: number | null, disabled = false) => ({
|
|
377
|
-
onpointerenter: () => {
|
|
378
|
-
if (!disabled && site_idx != null) set_atom_hover(site_idx)
|
|
379
|
-
},
|
|
380
|
-
onpointermove: () => {
|
|
381
|
-
if (!disabled && site_idx != null) set_atom_hover(site_idx)
|
|
382
|
-
},
|
|
383
|
-
onpointerleave: () => {
|
|
384
|
-
if (!disabled && site_idx != null) schedule_atom_hover_clear(site_idx)
|
|
385
|
-
},
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
// Cursor style for the canvas, derived from mode and hover state
|
|
389
|
-
let canvas_cursor = $derived.by(() => {
|
|
390
|
-
if (measure_mode === `edit-atoms` && add_atom_mode) return `crosshair`
|
|
391
|
-
if (measure_mode === `edit-bonds` && hovered_bond_key != null) {
|
|
392
|
-
return bond_edits_enabled ? `pointer` : `not-allowed`
|
|
393
|
-
}
|
|
394
|
-
if (hovered_idx != null) {
|
|
395
|
-
if (measure_mode === `edit-bonds`) {
|
|
396
|
-
return bond_edit_mode === `add` && can_select_bond_site(hovered_idx)
|
|
397
|
-
? `pointer`
|
|
398
|
-
: `not-allowed`
|
|
399
|
-
}
|
|
400
|
-
if (measure_mode === `edit-atoms`) {
|
|
401
|
-
const site = structure?.sites?.[hovered_idx]
|
|
402
|
-
if (site?.properties?.orig_site_idx != null) return `not-allowed`
|
|
403
|
-
return `pointer`
|
|
404
|
-
}
|
|
405
|
-
return `pointer`
|
|
406
|
-
}
|
|
407
|
-
return `default`
|
|
408
|
-
})
|
|
409
|
-
|
|
410
|
-
// Desaturate a color by blending it toward gray (for ghosting image atoms in edit mode)
|
|
411
|
-
const gray = new Color(0x999999)
|
|
412
|
-
function desaturate(hex: string | undefined, amount = 0.4): string {
|
|
413
|
-
return `#${new Color(hex ?? 0x999999).lerp(gray, amount).getHexString()}`
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// === Edit-atoms mode state ===
|
|
417
|
-
let transform_object = $state<Mesh | undefined>(undefined)
|
|
418
|
-
// Plain variable — only used imperatively in TransformControls drag handlers
|
|
419
|
-
let drag_start_centroid: Vec3 | null = null
|
|
420
|
-
// Frozen centroid set on drag start. While non-null, the TransformControls mesh
|
|
421
|
-
// position stays at this fixed value so Svelte's reactive centroid updates (from
|
|
422
|
-
// PBC wrapping) don't fight TransformControls. Cleared on mouseUp so the mesh
|
|
423
|
-
// snaps to the new wrapped centroid.
|
|
424
|
-
let frozen_centroid = $state<Vec3 | null>(null)
|
|
425
|
-
|
|
426
|
-
let bond_context_menu = $state<BondContextMenu | null>(null)
|
|
427
|
-
// Threlte/HTML pointer events can close the visible menu before a button
|
|
428
|
-
// handler runs, so keep the target bond separately for menu actions.
|
|
429
|
-
let bond_context_target: BondContextMenu | null = null
|
|
430
|
-
|
|
431
|
-
function close_bond_context_menu() {
|
|
432
|
-
bond_context_menu = null
|
|
433
|
-
bond_context_target = null
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
const canonical_bond_target = (bond: BondKeyTarget): BondKeyTarget =>
|
|
437
|
-
canonicalize_bond_target(bond, structure?.sites)
|
|
438
|
-
|
|
439
|
-
const bond_key_for = (bond: BondKeyTarget): string => {
|
|
440
|
-
const target = canonical_bond_target(bond)
|
|
441
|
-
return get_bond_key(target.site_idx_1, target.site_idx_2, target.cell_shift)
|
|
442
|
-
}
|
|
443
|
-
const rendered_bond_key_for = (bond: BondKeyTarget): string =>
|
|
444
|
-
get_bond_key(bond.site_idx_1, bond.site_idx_2, bond.cell_shift)
|
|
445
|
-
|
|
446
|
-
const matches_bond_key = (bond: BondKeyTarget, key: string): boolean =>
|
|
447
|
-
bond_key_for(bond) === key
|
|
448
|
-
|
|
449
|
-
const find_added_bond_by_rendered_key = (key: string): StructureBond | undefined =>
|
|
450
|
-
added_bonds.find((bond) => rendered_bond_key_for(bond) === key)
|
|
451
|
-
|
|
452
|
-
function resolve_bond_edit_target(
|
|
453
|
-
site_idx_1: number,
|
|
454
|
-
site_idx_2: number,
|
|
455
|
-
cell_shift?: Vec3,
|
|
456
|
-
): BondKeyTarget {
|
|
457
|
-
const rendered_target = { site_idx_1, site_idx_2, cell_shift }
|
|
458
|
-
const rendered_key = rendered_bond_key_for(rendered_target)
|
|
459
|
-
return find_added_bond_by_rendered_key(rendered_key) ??
|
|
460
|
-
canonical_bond_target(rendered_target)
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
const is_image_bond_site = (site_idx: number): boolean =>
|
|
464
|
-
structure?.sites?.[site_idx]?.properties?.orig_site_idx != null
|
|
465
|
-
|
|
466
|
-
const can_select_bond_site = (site_idx: number): boolean =>
|
|
467
|
-
bond_edits_enabled && structure?.sites?.[site_idx] != null
|
|
468
|
-
|
|
469
|
-
const can_edit_bond = (bond: BondKeyTarget): boolean => {
|
|
470
|
-
const target = canonical_bond_target(bond)
|
|
471
|
-
return bond_edits_enabled &&
|
|
472
|
-
!is_image_bond_site(target.site_idx_1) &&
|
|
473
|
-
!is_image_bond_site(target.site_idx_2)
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const format_bond_order = (order: BondOrder | undefined): string =>
|
|
477
|
-
order === undefined ? `1` : `${order}`
|
|
478
|
-
|
|
479
|
-
function get_current_bond_order(
|
|
480
|
-
site_idx_1: number,
|
|
481
|
-
site_idx_2: number,
|
|
482
|
-
cell_shift?: Vec3,
|
|
483
|
-
): BondOrder | undefined {
|
|
484
|
-
const key = get_bond_key(site_idx_1, site_idx_2, cell_shift)
|
|
485
|
-
return find_added_bond_by_rendered_key(key)?.order ??
|
|
486
|
-
bond_order_overrides.find((bond) => matches_bond_key(bond, key))?.order ??
|
|
487
|
-
added_bonds.find((bond) => matches_bond_key(bond, key))?.order ??
|
|
488
|
-
filtered_bond_pairs.find((bond) => matches_bond_key(bond, key))?.bond_order
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
const midpoint = (pos_1: Vec3, pos_2: Vec3): Vec3 => [
|
|
492
|
-
(pos_1[0] + pos_2[0]) / 2,
|
|
493
|
-
(pos_1[1] + pos_2[1]) / 2,
|
|
494
|
-
(pos_1[2] + pos_2[2]) / 2,
|
|
495
|
-
]
|
|
496
|
-
|
|
497
|
-
const BOND_ENDPOINT_HIT_FRACTION = 0.3
|
|
498
|
-
const BOND_ENDPOINT_SITE_MATCH_TOLERANCE = 1e-6
|
|
499
|
-
const EDITABLE_ATOM_HIT_RADIUS_SCALE = 1.15
|
|
500
|
-
const skip_raycast = (): void => undefined
|
|
501
|
-
|
|
502
|
-
function apply_bond_transform(mesh: Mesh, bond: BondPair): void {
|
|
503
|
-
mesh.matrix.fromArray(bond.transform_matrix)
|
|
504
|
-
mesh.matrixWorldNeedsUpdate = true
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
function apply_non_raycastable_bond_hit_transform(mesh: Mesh, bond: BondPair): void {
|
|
508
|
-
apply_bond_transform(mesh, bond)
|
|
509
|
-
disable_raycast(mesh)
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
function disable_raycast(mesh: Mesh): void {
|
|
513
|
-
mesh.raycast = skip_raycast
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
function site_world_position(parent: Object3D, site: Site): Vector3 {
|
|
517
|
-
const position = new Vector3(...site.xyz)
|
|
518
|
-
return parent.localToWorld(position)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
function get_bond_endpoint_site_idx(
|
|
522
|
-
site_idx: number,
|
|
523
|
-
world_position: Vector3,
|
|
524
|
-
parent: Object3D,
|
|
525
|
-
): number {
|
|
526
|
-
if (!structure?.sites) return site_idx
|
|
527
|
-
const site = structure.sites[site_idx]
|
|
528
|
-
if (!site) return site_idx
|
|
529
|
-
|
|
530
|
-
const matches_world_position = (candidate_site: Site): boolean =>
|
|
531
|
-
site_world_position(parent, candidate_site).distanceTo(world_position) <=
|
|
532
|
-
BOND_ENDPOINT_SITE_MATCH_TOLERANCE
|
|
533
|
-
|
|
534
|
-
if (matches_world_position(site)) {
|
|
535
|
-
return site_idx
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
const image_site_idx = structure.sites.findIndex((candidate_site) =>
|
|
539
|
-
candidate_site.properties?.orig_site_idx === site_idx &&
|
|
540
|
-
matches_world_position(candidate_site)
|
|
541
|
-
)
|
|
542
|
-
return image_site_idx === -1 ? site_idx : image_site_idx
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
function get_bond_endpoint_hit_site_idx(
|
|
546
|
-
bond: BondPair,
|
|
547
|
-
event: BondPointerEvent,
|
|
548
|
-
): number | null {
|
|
549
|
-
if (!event.point) return null
|
|
550
|
-
const parent = event.object?.parent
|
|
551
|
-
if (!parent) return null
|
|
552
|
-
|
|
553
|
-
const world_pos_1 = new Vector3(...bond.pos_1)
|
|
554
|
-
const world_pos_2 = new Vector3(...bond.pos_2)
|
|
555
|
-
parent.localToWorld(world_pos_1)
|
|
556
|
-
parent.localToWorld(world_pos_2)
|
|
557
|
-
|
|
558
|
-
const bond_vec = world_pos_2.clone().sub(world_pos_1)
|
|
559
|
-
const length_sq = bond_vec.lengthSq()
|
|
560
|
-
if (length_sq <= math.EPS) return null
|
|
561
|
-
|
|
562
|
-
const hit_vec = event.point.clone().sub(world_pos_1)
|
|
563
|
-
const bond_fraction = hit_vec.dot(bond_vec) / length_sq
|
|
564
|
-
if (bond_fraction <= BOND_ENDPOINT_HIT_FRACTION) {
|
|
565
|
-
return get_bond_endpoint_site_idx(bond.site_idx_1, world_pos_1, parent)
|
|
566
|
-
}
|
|
567
|
-
if (bond_fraction >= 1 - BOND_ENDPOINT_HIT_FRACTION) {
|
|
568
|
-
return get_bond_endpoint_site_idx(bond.site_idx_2, world_pos_2, parent)
|
|
569
|
-
}
|
|
570
|
-
return null
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
let label_screen_margin = $derived(site_label_size * 10 + site_label_padding)
|
|
574
|
-
|
|
575
|
-
function get_bond_context_menu_position(
|
|
576
|
-
bond: BondPair,
|
|
577
|
-
event?: BondContextMenuEvent,
|
|
578
|
-
): Vec3 {
|
|
579
|
-
const parent = event?.object?.parent
|
|
580
|
-
if (!event?.point || !parent) return midpoint(bond.pos_1, bond.pos_2)
|
|
581
|
-
|
|
582
|
-
const local_point = event.point.clone()
|
|
583
|
-
parent.worldToLocal(local_point)
|
|
584
|
-
return [local_point.x, local_point.y, local_point.z]
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
function open_bond_context_menu(bond: BondPair, event?: BondContextMenuEvent) {
|
|
588
|
-
if (!can_edit_bond(bond)) return
|
|
589
|
-
bond_context_target = {
|
|
590
|
-
site_idx_1: bond.site_idx_1,
|
|
591
|
-
site_idx_2: bond.site_idx_2,
|
|
592
|
-
cell_shift: bond.cell_shift,
|
|
593
|
-
position: get_bond_context_menu_position(bond, event),
|
|
594
|
-
}
|
|
595
|
-
bond_context_menu = bond_context_target
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const current_bond_edit_state = () => ({
|
|
599
|
-
added_bonds,
|
|
600
|
-
removed_bonds,
|
|
601
|
-
bond_order_overrides,
|
|
602
|
-
})
|
|
603
|
-
|
|
604
|
-
function apply_bond_edit_result(result: BondEditResult, close_menu = true) {
|
|
605
|
-
if (!result.changed) return
|
|
606
|
-
on_bond_edit_start?.()
|
|
607
|
-
added_bonds = result.state.added_bonds
|
|
608
|
-
removed_bonds = result.state.removed_bonds
|
|
609
|
-
bond_order_overrides = result.state.bond_order_overrides
|
|
610
|
-
if (close_menu) close_bond_context_menu()
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
const find_visible_bond = (
|
|
614
|
-
target: BondKeyTarget,
|
|
615
|
-
canonical_target: BondKeyTarget = target,
|
|
616
|
-
): BondPair | undefined => {
|
|
617
|
-
const rendered_key = rendered_bond_key_for(target)
|
|
618
|
-
const canonical_key = bond_key_for(canonical_target)
|
|
619
|
-
return filtered_bond_pairs.find((bond) => rendered_bond_key_for(bond) === rendered_key) ??
|
|
620
|
-
filtered_bond_pairs.find((bond) => bond_key_for(bond) === canonical_key)
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
function open_bond_order_menu_for_target(
|
|
624
|
-
target: BondKeyTarget,
|
|
625
|
-
canonical_target: BondKeyTarget = target,
|
|
626
|
-
) {
|
|
627
|
-
const bond = find_visible_bond(target, canonical_target)
|
|
628
|
-
if (bond) open_bond_context_menu(bond)
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
function add_or_restore_pair(site_idx_1: number, site_idx_2: number) {
|
|
632
|
-
const rendered_target = { site_idx_1, site_idx_2 }
|
|
633
|
-
if (!can_edit_bond(rendered_target)) return
|
|
634
|
-
const edit_state = current_bond_edit_state()
|
|
635
|
-
const canonical_target = canonical_bond_target(rendered_target)
|
|
636
|
-
const canonical_result = add_or_restore_bond(
|
|
637
|
-
edit_state,
|
|
638
|
-
canonical_target,
|
|
639
|
-
editable_perceived_bond_pairs,
|
|
640
|
-
bond_edit_order,
|
|
641
|
-
)
|
|
642
|
-
const use_rendered_target =
|
|
643
|
-
canonical_result.action === `added` &&
|
|
644
|
-
rendered_bond_key_for(canonical_target) !== rendered_bond_key_for(rendered_target)
|
|
645
|
-
const target = use_rendered_target ? rendered_target : canonical_target
|
|
646
|
-
const result = use_rendered_target
|
|
647
|
-
? add_or_restore_bond(
|
|
648
|
-
edit_state,
|
|
649
|
-
rendered_target,
|
|
650
|
-
editable_perceived_bond_pairs,
|
|
651
|
-
bond_edit_order,
|
|
652
|
-
)
|
|
653
|
-
: canonical_result
|
|
654
|
-
if (result.action === `already-visible`) {
|
|
655
|
-
open_bond_order_menu_for_target(rendered_target, target)
|
|
656
|
-
return
|
|
657
|
-
}
|
|
658
|
-
apply_bond_edit_result(result, false)
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
function set_bond_order(
|
|
662
|
-
site_idx_1: number,
|
|
663
|
-
site_idx_2: number,
|
|
664
|
-
order: BondOrder,
|
|
665
|
-
cell_shift?: Vec3,
|
|
666
|
-
) {
|
|
667
|
-
const target = resolve_bond_edit_target(site_idx_1, site_idx_2, cell_shift)
|
|
668
|
-
if (!can_edit_bond(target)) return
|
|
669
|
-
apply_bond_edit_result(
|
|
670
|
-
apply_set_bond_order(
|
|
671
|
-
current_bond_edit_state(),
|
|
672
|
-
target,
|
|
673
|
-
editable_perceived_bond_pairs,
|
|
674
|
-
order,
|
|
675
|
-
),
|
|
676
|
-
)
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
function set_context_bond_order(order: BondOrder) {
|
|
680
|
-
const menu = bond_context_target ?? bond_context_menu
|
|
681
|
-
if (!menu) return
|
|
682
|
-
set_bond_order(menu.site_idx_1, menu.site_idx_2, order, menu.cell_shift)
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
function remove_bond(site_idx_1: number, site_idx_2: number, cell_shift?: Vec3) {
|
|
686
|
-
const target = resolve_bond_edit_target(site_idx_1, site_idx_2, cell_shift)
|
|
687
|
-
if (!can_edit_bond(target)) return
|
|
688
|
-
apply_bond_edit_result(
|
|
689
|
-
apply_delete_bond(
|
|
690
|
-
current_bond_edit_state(),
|
|
691
|
-
target,
|
|
692
|
-
editable_perceived_bond_pairs,
|
|
693
|
-
),
|
|
694
|
-
)
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function remove_context_bond() {
|
|
698
|
-
const menu = bond_context_target ?? bond_context_menu
|
|
699
|
-
if (!menu) return
|
|
700
|
-
remove_bond(menu.site_idx_1, menu.site_idx_2, menu.cell_shift)
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
// Deduplicate clicks: when a highlight sphere and the underlying atom both
|
|
704
|
-
// intercept the same native click, only the first intersection should fire.
|
|
705
|
-
// All threlte intersection events from one click share the same nativeEvent ref.
|
|
706
|
-
let last_native_event: Event | null = null
|
|
707
|
-
// extras.Instance does not always emit pointerdown, so edit-bonds also falls
|
|
708
|
-
// back to click. When pointerdown did fire, skip the matching click once.
|
|
709
|
-
let last_edit_bonds_pointerdown_site_idx: number | null = null
|
|
710
|
-
let clear_edit_bonds_pointerdown_site_timeout:
|
|
711
|
-
| ReturnType<typeof setTimeout>
|
|
712
|
-
| null = null
|
|
713
|
-
|
|
714
|
-
function remember_edit_bonds_pointerdown_site(site_idx: number) {
|
|
715
|
-
last_edit_bonds_pointerdown_site_idx = site_idx
|
|
716
|
-
if (clear_edit_bonds_pointerdown_site_timeout != null) {
|
|
717
|
-
clearTimeout(clear_edit_bonds_pointerdown_site_timeout)
|
|
718
|
-
}
|
|
719
|
-
clear_edit_bonds_pointerdown_site_timeout = setTimeout(() => {
|
|
720
|
-
last_edit_bonds_pointerdown_site_idx = null
|
|
721
|
-
clear_edit_bonds_pointerdown_site_timeout = null
|
|
722
|
-
}, 250)
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
function select_edit_bonds_site(site_idx: number, event: Event): void {
|
|
726
|
-
toggle_selection(site_idx, event)
|
|
727
|
-
remember_edit_bonds_pointerdown_site(site_idx)
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
function skip_duplicate_edit_bonds_click(site_idx: number) {
|
|
731
|
-
if (last_edit_bonds_pointerdown_site_idx !== site_idx) return false
|
|
732
|
-
|
|
733
|
-
last_edit_bonds_pointerdown_site_idx = null
|
|
734
|
-
if (clear_edit_bonds_pointerdown_site_timeout != null) {
|
|
735
|
-
clearTimeout(clear_edit_bonds_pointerdown_site_timeout)
|
|
736
|
-
clear_edit_bonds_pointerdown_site_timeout = null
|
|
737
|
-
}
|
|
738
|
-
return true
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
function toggle_selection(site_index: number, evt?: Event) {
|
|
742
|
-
evt?.stopPropagation?.()
|
|
743
|
-
const event_with_native = evt as Event & { nativeEvent?: unknown } | undefined
|
|
744
|
-
const native_event = event_with_native?.nativeEvent ?? evt
|
|
745
|
-
if (native_event instanceof Event) {
|
|
746
|
-
if (native_event === last_native_event) return
|
|
747
|
-
last_native_event = native_event
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
if (measure_mode === `edit-bonds`) {
|
|
751
|
-
if (bond_edit_mode === `delete`) {
|
|
752
|
-
measured_sites = []
|
|
753
|
-
selected_sites = []
|
|
754
|
-
return
|
|
755
|
-
}
|
|
756
|
-
if (!can_select_bond_site(site_index)) return
|
|
757
|
-
// In Add mode, select atom pairs without making existing bonds destructive.
|
|
758
|
-
const new_sites = measured_sites.includes(site_index)
|
|
759
|
-
? measured_sites.filter((idx) => idx !== site_index)
|
|
760
|
-
: [...measured_sites, site_index]
|
|
761
|
-
|
|
762
|
-
measured_sites = new_sites
|
|
763
|
-
selected_sites = new_sites
|
|
764
|
-
|
|
765
|
-
// When two atoms are selected, add/restore or open order editing.
|
|
766
|
-
if (new_sites.length === 2) {
|
|
767
|
-
add_or_restore_pair(new_sites[0], new_sites[1])
|
|
768
|
-
measured_sites = []
|
|
769
|
-
selected_sites = []
|
|
770
|
-
}
|
|
771
|
-
return
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
if (measure_mode === `edit-atoms`) {
|
|
775
|
-
// Block image atoms (detected by orig_site_idx property from PBC)
|
|
776
|
-
const site = structure?.sites?.[site_index]
|
|
777
|
-
if (site?.properties?.orig_site_idx != null) return
|
|
778
|
-
|
|
779
|
-
const is_selected = selected_sites.includes(site_index)
|
|
780
|
-
const is_shift = evt instanceof MouseEvent && evt.shiftKey
|
|
781
|
-
|
|
782
|
-
// In edit-atoms mode, selected_sites and measured_sites always stay in sync
|
|
783
|
-
let new_sites: number[]
|
|
784
|
-
if (is_shift) {
|
|
785
|
-
// Multi-select: toggle this site in/out of selection
|
|
786
|
-
new_sites = is_selected
|
|
787
|
-
? selected_sites.filter((idx) => idx !== site_index)
|
|
788
|
-
: [...selected_sites, site_index]
|
|
789
|
-
} else {
|
|
790
|
-
// Single-select: replace selection (or deselect if already selected)
|
|
791
|
-
new_sites = is_selected ? [] : [site_index]
|
|
792
|
-
}
|
|
793
|
-
selected_sites = new_sites
|
|
794
|
-
measured_sites = new_sites
|
|
795
|
-
return
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
if (
|
|
799
|
-
!measured_sites.includes(site_index) &&
|
|
800
|
-
measured_sites.length >= measure.MAX_SELECTED_SITES
|
|
801
|
-
) {
|
|
802
|
-
console.warn(
|
|
803
|
-
`Selection size limit reached (${measure.MAX_SELECTED_SITES}). Deselect some sites first.`,
|
|
804
|
-
)
|
|
805
|
-
return
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
measured_sites = measured_sites.includes(site_index)
|
|
809
|
-
? measured_sites.filter((idx) => idx !== site_index)
|
|
810
|
-
: [...measured_sites, site_index]
|
|
811
|
-
selected_sites = selected_sites.includes(site_index)
|
|
812
|
-
? selected_sites.filter((idx) => idx !== site_index)
|
|
813
|
-
: [...selected_sites, site_index]
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
$effect(() => {
|
|
817
|
-
void structure
|
|
818
|
-
void measure_mode
|
|
819
|
-
void bond_edit_mode
|
|
820
|
-
void bond_edits_enabled
|
|
821
|
-
untrack(() => {
|
|
822
|
-
close_bond_context_menu()
|
|
823
|
-
hovered_bond_key = null
|
|
824
|
-
})
|
|
825
|
-
})
|
|
826
|
-
|
|
827
|
-
$effect(() => {
|
|
828
|
-
const count = structure?.sites?.length ?? 0
|
|
829
|
-
if (count <= 0) {
|
|
830
|
-
measured_sites = []
|
|
831
|
-
return
|
|
832
|
-
}
|
|
833
|
-
untrack(() => {
|
|
834
|
-
measured_sites = measured_sites.filter((idx) => idx >= 0 && idx < count)
|
|
835
|
-
})
|
|
836
|
-
})
|
|
837
|
-
|
|
838
|
-
$effect(() => {
|
|
839
|
-
cursor = canvas_cursor
|
|
840
|
-
})
|
|
841
|
-
|
|
842
|
-
extras.interactivity()
|
|
843
|
-
$effect.pre(() => {
|
|
844
|
-
hovered_site = structure?.sites?.[hovered_idx ?? -1] ?? null
|
|
845
|
-
})
|
|
846
|
-
let lattice = $derived(
|
|
847
|
-
structure && `lattice` in structure ? structure.lattice : null,
|
|
848
|
-
)
|
|
849
|
-
|
|
850
|
-
let visual_lattice = $derived(
|
|
851
|
-
base_structure && `lattice` in base_structure ? base_structure.lattice : lattice,
|
|
852
|
-
)
|
|
853
|
-
|
|
854
|
-
let rotation_target = $derived(
|
|
855
|
-
lattice
|
|
856
|
-
? (math.scale(math.add(...lattice.matrix), 0.5) as Vec3)
|
|
857
|
-
: structure
|
|
858
|
-
? get_center_of_mass(structure)
|
|
859
|
-
: [0, 0, 0] as Vec3,
|
|
860
|
-
)
|
|
861
|
-
|
|
862
|
-
let structure_size = $derived.by(() => {
|
|
863
|
-
if (lattice) return (lattice.a + lattice.b + lattice.c) / 2
|
|
864
|
-
if (!structure?.sites?.length) return 10
|
|
865
|
-
|
|
866
|
-
const ranges = [0, 1, 2].map((axis_idx) => {
|
|
867
|
-
const coords = structure.sites.map((site) => site.xyz[axis_idx])
|
|
868
|
-
return Math.max(...coords) - Math.min(...coords)
|
|
869
|
-
})
|
|
870
|
-
return Math.max(1, ...ranges)
|
|
871
|
-
})
|
|
872
|
-
|
|
873
|
-
// Characteristic inter-atomic spacing: cube root of volume per atom.
|
|
874
|
-
// Excludes PBC image atoms (orig_site_idx) so toggling image atoms doesn't affect arrow sizing.
|
|
875
|
-
let char_atom_spacing = $derived.by(() => {
|
|
876
|
-
if (!lattice || !structure?.sites?.length) return structure_size
|
|
877
|
-
const n_real = structure.sites.filter((site) =>
|
|
878
|
-
site.properties?.orig_site_idx == null
|
|
879
|
-
).length
|
|
880
|
-
return n_real > 0 ? Math.cbrt(lattice.volume / n_real) : structure_size
|
|
881
|
-
})
|
|
882
|
-
|
|
883
|
-
// When uniform thickness is on, convert negative (length-relative) radii to
|
|
884
|
-
// positive (absolute) values scaled by inter-atomic spacing.
|
|
885
|
-
// Already-positive (absolute) values are preserved as-is.
|
|
886
|
-
let eff_shaft_radius = $derived(
|
|
887
|
-
vector_uniform_thickness && vector_shaft_radius < 0
|
|
888
|
-
? char_atom_spacing * -vector_shaft_radius
|
|
889
|
-
: vector_shaft_radius,
|
|
890
|
-
)
|
|
891
|
-
let eff_head_radius = $derived(
|
|
892
|
-
vector_uniform_thickness && vector_arrow_head_radius < 0
|
|
893
|
-
? char_atom_spacing * -vector_arrow_head_radius
|
|
894
|
-
: vector_arrow_head_radius,
|
|
895
|
-
)
|
|
896
|
-
let eff_head_length = $derived(
|
|
897
|
-
vector_uniform_thickness && vector_arrow_head_length < 0
|
|
898
|
-
? char_atom_spacing * -vector_arrow_head_length
|
|
899
|
-
: vector_arrow_head_length,
|
|
900
|
-
)
|
|
901
|
-
|
|
902
|
-
// Compute dynamic camera clipping planes based on structure size
|
|
903
|
-
// This prevents z-fighting and disappearing objects when zooming in close on large supercells
|
|
904
|
-
let camera_near = $derived(Math.max(0.01, structure_size * 0.01))
|
|
905
|
-
let camera_far = $derived(Math.max(1000, structure_size * 100))
|
|
906
|
-
|
|
907
|
-
// Using $state because this is mutated in an effect based on viewport/structure size
|
|
908
|
-
let computed_zoom = $state(untrack(() => initial_zoom))
|
|
909
|
-
$effect(() => {
|
|
910
|
-
if (!(width > 0) || !(height > 0)) return
|
|
911
|
-
const structure_max_dim = Math.max(1, untrack(() => structure_size))
|
|
912
|
-
const viewer_min_dim = Math.min(width, height)
|
|
913
|
-
const scale_factor = viewer_min_dim / (structure_max_dim * 50) // 50px per unit
|
|
914
|
-
let new_zoom = initial_zoom * scale_factor
|
|
915
|
-
if (min_zoom && min_zoom > 0) new_zoom = Math.max(min_zoom, new_zoom)
|
|
916
|
-
if (max_zoom && max_zoom > 0) new_zoom = Math.min(max_zoom, new_zoom)
|
|
917
|
-
computed_zoom = new_zoom
|
|
918
|
-
})
|
|
919
|
-
|
|
920
|
-
$effect.pre(() => { // Simple initial camera auto-position: proportional to structure size and fov
|
|
921
|
-
if (camera_position.every((val) => val === 0) && structure) {
|
|
922
|
-
stored_initial_zoom = undefined
|
|
923
|
-
const distance = Math.max(1, structure_size) * (60 / fov)
|
|
924
|
-
camera_position = [distance, distance * 0.3, distance * 0.8]
|
|
925
|
-
}
|
|
926
|
-
})
|
|
927
|
-
$effect(() => {
|
|
928
|
-
if (structure && show_bonds !== `never`) {
|
|
929
|
-
// Determine if we should show bonds based on the setting and structure type
|
|
930
|
-
const should_show_bonds = show_bonds === `always` ||
|
|
931
|
-
(show_bonds === `crystals` && lattice) ||
|
|
932
|
-
(show_bonds === `molecules` && !lattice)
|
|
933
|
-
|
|
934
|
-
if (should_show_bonds) {
|
|
935
|
-
bond_pairs = BONDING_STRATEGIES[bonding_strategy](structure, bonding_options)
|
|
936
|
-
} else bond_pairs = []
|
|
937
|
-
} else bond_pairs = []
|
|
938
|
-
})
|
|
939
|
-
|
|
940
|
-
// Compute property-based colors when not using element coloring
|
|
941
|
-
// Use base_structure (original unit cell) for color calculation
|
|
942
|
-
let property_colors = $derived(
|
|
943
|
-
get_property_colors(
|
|
944
|
-
base_structure || structure,
|
|
945
|
-
atom_color_config,
|
|
946
|
-
bonding_strategy,
|
|
947
|
-
sym_data,
|
|
948
|
-
),
|
|
949
|
-
)
|
|
950
|
-
// Compute weighted average radius for a site based on species occupancies
|
|
951
|
-
// Normalizes by total occupancy so vacancy-containing sites render at full size
|
|
952
|
-
const calc_weighted_radius = (site: Site): number => {
|
|
953
|
-
const total_occu = site.species.reduce((sum, { occu }) => sum + occu, 0)
|
|
954
|
-
const weighted_sum = site.species.reduce((sum, { element, occu }) => {
|
|
955
|
-
const override = element_radius_overrides?.[element as ElementSymbol]
|
|
956
|
-
return sum + occu * (override ?? atomic_radii[element] ?? 1)
|
|
957
|
-
}, 0)
|
|
958
|
-
return total_occu > 0 ? weighted_sum / total_occu : 1
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
let atom_data = $derived.by(() => {
|
|
962
|
-
if (!show_atoms || !structure?.sites) return []
|
|
963
|
-
const render_sites = merge_split_partial_sites(structure.sites, hidden_elements)
|
|
964
|
-
return render_sites.flatMap(({ site_idx, site, is_image_atom }) => {
|
|
965
|
-
const orig_idx = get_orig_site_idx(site, site_idx)
|
|
966
|
-
|
|
967
|
-
// Skip sites with hidden property values
|
|
968
|
-
const prop_val = property_colors?.values[orig_idx]
|
|
969
|
-
if (prop_val !== undefined && hidden_prop_vals.has(prop_val)) return []
|
|
970
|
-
|
|
971
|
-
// Calculate radius: same_size > site override > element override > default
|
|
972
|
-
// All radii scale uniformly with atom_radius for consistent slider behavior
|
|
973
|
-
const base_radius = same_size_atoms
|
|
974
|
-
? 1
|
|
975
|
-
: site_radius_overrides?.get(site_idx) ?? calc_weighted_radius(site)
|
|
976
|
-
const radius = base_radius * atom_radius
|
|
977
|
-
|
|
978
|
-
// Use property color if available (e.g. coordination number, Wyckoff position)
|
|
979
|
-
// Otherwise, each species gets its own element color (important for disordered sites)
|
|
980
|
-
const site_property_color = property_colors?.colors[orig_idx]
|
|
981
|
-
|
|
982
|
-
const visible_species = site.species.filter(({ element }) =>
|
|
983
|
-
!hidden_elements.has(element)
|
|
984
|
-
)
|
|
985
|
-
const slice_geometry = compute_slice_geometry(visible_species)
|
|
986
|
-
return slice_geometry.map((slice_data) => {
|
|
987
|
-
return {
|
|
988
|
-
site_idx,
|
|
989
|
-
element: slice_data.element,
|
|
990
|
-
occupancy: slice_data.occupancy,
|
|
991
|
-
position: site.xyz,
|
|
992
|
-
radius,
|
|
993
|
-
color: site_property_color ?? colors.element?.[slice_data.element],
|
|
994
|
-
has_partial_occupancy: slice_data.occupancy < 1,
|
|
995
|
-
start_phi: slice_data.start_phi,
|
|
996
|
-
end_phi: slice_data.end_phi,
|
|
997
|
-
phi_length: slice_data.phi_length,
|
|
998
|
-
render_start_cap: slice_data.render_start_cap,
|
|
999
|
-
render_end_cap: slice_data.render_end_cap,
|
|
1000
|
-
is_image_atom,
|
|
1001
|
-
}
|
|
1002
|
-
})
|
|
1003
|
-
})
|
|
1004
|
-
})
|
|
1005
|
-
|
|
1006
|
-
// Shared visibility check: site has at least one non-hidden element and
|
|
1007
|
-
// its property value (if any) isn't hidden. Used by both bond and vector filtering.
|
|
1008
|
-
const is_site_visible = (site_idx: number): boolean => {
|
|
1009
|
-
if (!structure?.sites) return false
|
|
1010
|
-
const site = structure.sites[site_idx]
|
|
1011
|
-
const has_visible_element = site?.species.some(({ element }) =>
|
|
1012
|
-
!hidden_elements.has(element)
|
|
1013
|
-
)
|
|
1014
|
-
const orig_idx = get_orig_site_idx(site, site_idx)
|
|
1015
|
-
const prop_val = property_colors?.values[orig_idx]
|
|
1016
|
-
const prop_visible = prop_val === undefined ||
|
|
1017
|
-
!hidden_prop_vals.has(prop_val)
|
|
1018
|
-
return has_visible_element && prop_visible
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
// Perception layer: bond_pairs with optional bond-order perception applied.
|
|
1022
|
-
// Off by default (pass-through). Manual overrides are applied downstream in
|
|
1023
|
-
// filtered_bond_pairs, so they still win over perceived orders.
|
|
1024
|
-
let perceived_bond_pairs: BondPair[] = $derived.by(() => {
|
|
1025
|
-
if (!auto_bond_order || !structure?.sites || bond_pairs.length === 0) {
|
|
1026
|
-
return bond_pairs
|
|
1027
|
-
}
|
|
1028
|
-
const total_charge = (`charge` in structure ? structure.charge : 0) ?? 0
|
|
1029
|
-
const perceived = perceive_bond_orders(structure.sites, bond_pairs, {
|
|
1030
|
-
total_charge,
|
|
1031
|
-
})
|
|
1032
|
-
// Explicit structure.properties.bonds are user-authoritative and must
|
|
1033
|
-
// never be clobbered by perception. Composition + precedence is a pure,
|
|
1034
|
-
// unit-tested helper (see compose_perceived_bonds).
|
|
1035
|
-
return compose_perceived_bonds(
|
|
1036
|
-
perceived,
|
|
1037
|
-
get_explicit_bond_metadata(structure),
|
|
1038
|
-
aromatic_display,
|
|
1039
|
-
)
|
|
1040
|
-
})
|
|
1041
|
-
|
|
1042
|
-
let editable_perceived_bond_pairs = $derived(
|
|
1043
|
-
perceived_bond_pairs.map((bond) => ({ ...bond, ...canonical_bond_target(bond) })),
|
|
1044
|
-
)
|
|
1045
|
-
|
|
1046
|
-
let filtered_bond_pairs = $derived.by(() => {
|
|
1047
|
-
if (!structure?.sites) return perceived_bond_pairs
|
|
1048
|
-
|
|
1049
|
-
// Build set of removed bond keys for efficient lookup
|
|
1050
|
-
const removed_keys = new Set(
|
|
1051
|
-
removed_bonds.map(bond_key_for),
|
|
1052
|
-
)
|
|
1053
|
-
const added_keys = new Set(
|
|
1054
|
-
added_bonds.map(bond_key_for),
|
|
1055
|
-
)
|
|
1056
|
-
const order_overrides = new Map(
|
|
1057
|
-
bond_order_overrides.map((bond) => [bond_key_for(bond), bond.order]),
|
|
1058
|
-
)
|
|
1059
|
-
|
|
1060
|
-
// Filter calculated bonds: exclude removed, replaced by manual additions, and hidden.
|
|
1061
|
-
const calculated = perceived_bond_pairs
|
|
1062
|
-
.filter((bond) => {
|
|
1063
|
-
const key = bond_key_for(bond)
|
|
1064
|
-
if (removed_keys.has(key) || added_keys.has(key)) return false
|
|
1065
|
-
return is_site_visible(bond.site_idx_1) && is_site_visible(bond.site_idx_2)
|
|
1066
|
-
})
|
|
1067
|
-
.map((bond) => {
|
|
1068
|
-
const override = order_overrides.get(bond_key_for(bond))
|
|
1069
|
-
return override === undefined ? bond : { ...bond, bond_order: override }
|
|
1070
|
-
})
|
|
1071
|
-
|
|
1072
|
-
// Create BondPair objects for manually added bonds
|
|
1073
|
-
const added: BondPair[] = []
|
|
1074
|
-
for (const added_bond of added_bonds) {
|
|
1075
|
-
const { site_idx_1: idx_i, site_idx_2: idx_j } = added_bond
|
|
1076
|
-
if (!is_site_visible(idx_i) || !is_site_visible(idx_j)) continue
|
|
1077
|
-
added.push(structure_bond_to_bond_pair(structure, added_bond))
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
return [...calculated, ...added]
|
|
1081
|
-
})
|
|
1082
|
-
|
|
1083
|
-
let editable_bond_pairs = $derived(
|
|
1084
|
-
bond_edits_enabled ? filtered_bond_pairs.filter(can_edit_bond) : [],
|
|
1085
|
-
)
|
|
1086
|
-
|
|
1087
|
-
let smart_site_label_offsets = $derived.by(() => {
|
|
1088
|
-
const offsets = new SvelteMap<number, Vec3>()
|
|
1089
|
-
if (filtered_bond_pairs.length === 0) return offsets
|
|
1090
|
-
|
|
1091
|
-
const bond_directions_by_site = new SvelteMap<number, Vec3[]>()
|
|
1092
|
-
const add_bond_direction = (site_idx: number, pos_1: Vec3, pos_2: Vec3) => {
|
|
1093
|
-
const direction = math.normalize_vec3(
|
|
1094
|
-
math.subtract(pos_2, pos_1),
|
|
1095
|
-
[0, 0, 0],
|
|
1096
|
-
)
|
|
1097
|
-
if (Math.hypot(...direction) < LABEL_OFFSET_EPS) return
|
|
1098
|
-
bond_directions_by_site.set(site_idx, [
|
|
1099
|
-
...(bond_directions_by_site.get(site_idx) ?? []),
|
|
1100
|
-
direction,
|
|
1101
|
-
])
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
for (const { site_idx_1, site_idx_2, pos_1, pos_2 } of filtered_bond_pairs) {
|
|
1105
|
-
add_bond_direction(site_idx_1, pos_1, pos_2)
|
|
1106
|
-
add_bond_direction(site_idx_2, pos_2, pos_1)
|
|
1107
|
-
}
|
|
1108
|
-
for (const [site_idx, bond_directions] of bond_directions_by_site) {
|
|
1109
|
-
offsets.set(site_idx, choose_site_label_offset(bond_directions, site_label_offset))
|
|
1110
|
-
}
|
|
1111
|
-
return offsets
|
|
1112
|
-
})
|
|
1113
|
-
|
|
1114
|
-
let instanced_bond_groups = $derived.by(() => {
|
|
1115
|
-
if (!structure?.sites || filtered_bond_pairs.length === 0) return []
|
|
1116
|
-
|
|
1117
|
-
const group = {
|
|
1118
|
-
thickness: bond_thickness,
|
|
1119
|
-
ambient_light,
|
|
1120
|
-
directional_light,
|
|
1121
|
-
instances: [] as {
|
|
1122
|
-
matrix: Float32Array
|
|
1123
|
-
color_start: string
|
|
1124
|
-
color_end: string
|
|
1125
|
-
}[],
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
for (const bond_data of filtered_bond_pairs) {
|
|
1129
|
-
const site_a = structure.sites[bond_data.site_idx_1]
|
|
1130
|
-
const site_b = structure.sites[bond_data.site_idx_2]
|
|
1131
|
-
|
|
1132
|
-
const get_majority_color = (site: typeof site_a) => {
|
|
1133
|
-
if (!site?.species || site.species.length === 0) return bond_color
|
|
1134
|
-
const majority_species = site.species.reduce((max, spec) =>
|
|
1135
|
-
spec.occu > max.occu ? spec : max
|
|
1136
|
-
)
|
|
1137
|
-
return colors.element?.[majority_species.element] || bond_color
|
|
1138
|
-
}
|
|
1139
|
-
|
|
1140
|
-
const color_start = get_majority_color(site_a)
|
|
1141
|
-
const color_end = get_majority_color(site_b)
|
|
1142
|
-
for (const matrix of get_bond_render_matrices(bond_data, bond_thickness)) {
|
|
1143
|
-
group.instances.push({ matrix, color_start, color_end })
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
return group.instances.length > 0 ? [group] : []
|
|
1148
|
-
})
|
|
1149
|
-
|
|
1150
|
-
let radius_by_site_idx = $derived.by(() => {
|
|
1151
|
-
const map = new SvelteMap<number, number>()
|
|
1152
|
-
for (const atom of atom_data) {
|
|
1153
|
-
if (!map.has(atom.site_idx)) map.set(atom.site_idx, atom.radius)
|
|
1154
|
-
}
|
|
1155
|
-
return map
|
|
1156
|
-
})
|
|
1157
|
-
|
|
1158
|
-
let editable_atom_hit_targets = $derived.by(() => {
|
|
1159
|
-
if (
|
|
1160
|
-
measure_mode !== `edit-bonds` ||
|
|
1161
|
-
bond_edit_mode !== `add` ||
|
|
1162
|
-
!bond_edits_enabled
|
|
1163
|
-
) {
|
|
1164
|
-
return []
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
const targets = new SvelteMap<number, EditableAtomHitTarget>()
|
|
1168
|
-
for (const atom of atom_data) {
|
|
1169
|
-
if (!can_select_bond_site(atom.site_idx)) continue
|
|
1170
|
-
if (targets.has(atom.site_idx)) continue
|
|
1171
|
-
targets.set(atom.site_idx, {
|
|
1172
|
-
site_idx: atom.site_idx,
|
|
1173
|
-
position: atom.position,
|
|
1174
|
-
radius: atom.radius,
|
|
1175
|
-
})
|
|
1176
|
-
}
|
|
1177
|
-
return [...targets.values()]
|
|
1178
|
-
})
|
|
1179
|
-
|
|
1180
|
-
// Get radius for a site (for highlight fallback when site is hidden/filtered)
|
|
1181
|
-
// Checks site_radius_overrides first for consistency with visible atoms
|
|
1182
|
-
const get_site_radius = (site: Site, site_idx: number | null): number => {
|
|
1183
|
-
const override = site_idx !== null
|
|
1184
|
-
? site_radius_overrides?.get(site_idx)
|
|
1185
|
-
: undefined
|
|
1186
|
-
const base_radius = same_size_atoms ? 1 : override ?? calc_weighted_radius(site)
|
|
1187
|
-
return base_radius * atom_radius
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
// Interpolate between spin-down (#3498db blue) and spin-up (#e74c3c red)
|
|
1191
|
-
// based on the z-component direction of a magnetic vector
|
|
1192
|
-
function spin_direction_color(vec: Vec3): string {
|
|
1193
|
-
const mag = Math.hypot(...vec)
|
|
1194
|
-
const z_frac = mag > 1e-10 ? (vec[2] / mag + 1) / 2 : 0.5 // 0=down, 1=up
|
|
1195
|
-
const red = Math.round(52 + (231 - 52) * z_frac)
|
|
1196
|
-
const grn = Math.round(152 + (76 - 152) * z_frac)
|
|
1197
|
-
const blu = Math.round(219 + (60 - 219) * z_frac)
|
|
1198
|
-
return `#${red.toString(16).padStart(2, `0`)}${
|
|
1199
|
-
grn.toString(16).padStart(2, `0`)
|
|
1200
|
-
}${blu.toString(16).padStart(2, `0`)}`
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// Build one arrow layer per visible vector key. Auto-scales the longest
|
|
1204
|
-
// vector to 1.8× char_atom_spacing (cube root of volume per atom).
|
|
1205
|
-
// When vector_normalize is on, effective_max is 1 so all arrows get equal length.
|
|
1206
|
-
// Single active key preserves legacy coloring (element for force,
|
|
1207
|
-
// spin-direction for magmom/spin). Multiple keys use flat palette colors.
|
|
1208
|
-
let vector_layers = $derived.by(() => {
|
|
1209
|
-
if (!structure?.sites) return []
|
|
1210
|
-
const keys = get_structure_vector_keys(structure)
|
|
1211
|
-
const active_keys = keys.filter((key) => vector_configs[key]?.visible !== false)
|
|
1212
|
-
if (active_keys.length === 0) return []
|
|
1213
|
-
|
|
1214
|
-
// Build per-site lookup; skip hidden sites so they don't contribute
|
|
1215
|
-
// arrows or affect autoscaling. null entries = hidden site.
|
|
1216
|
-
const active_set = new Set(active_keys)
|
|
1217
|
-
let max_mag = 0
|
|
1218
|
-
const site_vec_maps = structure.sites.map((site, site_idx) => {
|
|
1219
|
-
if (!is_site_visible(site_idx)) return null
|
|
1220
|
-
const map = new SvelteMap<string, Vec3>()
|
|
1221
|
-
for (const { key, vec } of get_all_site_vectors(site)) {
|
|
1222
|
-
map.set(key, vec)
|
|
1223
|
-
if (active_set.has(key)) {
|
|
1224
|
-
max_mag = Math.max(max_mag, Math.hypot(...vec))
|
|
1225
|
-
}
|
|
1226
|
-
}
|
|
1227
|
-
return map
|
|
1228
|
-
})
|
|
1229
|
-
|
|
1230
|
-
// When normalize is on, treat all magnitudes as 1 so arrows have equal length
|
|
1231
|
-
const effective_max = vector_normalize ? 1 : max_mag
|
|
1232
|
-
const auto_scale = effective_max > 1e-10
|
|
1233
|
-
? (char_atom_spacing * 1.8) / effective_max
|
|
1234
|
-
: 1
|
|
1235
|
-
const is_single = active_keys.length === 1
|
|
1236
|
-
const effective_global_scale = auto_scale * vector_scale
|
|
1237
|
-
|
|
1238
|
-
// When vector_origin_gap > 0 and multiple vectors exist at a site,
|
|
1239
|
-
// arrange arrow origins on a regular polygon centered on the atom, in a
|
|
1240
|
-
// plane perpendicular to the mean vector direction. The gap is a fraction
|
|
1241
|
-
// of the visual atom radius (0 = center, 0.5 = halfway to surface).
|
|
1242
|
-
// get_site_radius() returns the uniform scale applied to SphereGeometry(0.5),
|
|
1243
|
-
// so visual_radius = get_site_radius() * 0.5.
|
|
1244
|
-
const site_offsets = (vector_origin_gap > 0 && !is_single)
|
|
1245
|
-
? structure.sites.map((site, site_idx) => {
|
|
1246
|
-
const vec_map = site_vec_maps[site_idx]
|
|
1247
|
-
if (!vec_map) return null
|
|
1248
|
-
const site_keys = active_keys.filter((key) => vec_map.has(key))
|
|
1249
|
-
const n_keys = site_keys.length
|
|
1250
|
-
if (n_keys <= 1) return null
|
|
1251
|
-
const visual_radius = get_site_radius(site, site_idx) * 0.5
|
|
1252
|
-
const gap_abs = vector_origin_gap * visual_radius
|
|
1253
|
-
let mean: Vec3 = [0, 0, 0]
|
|
1254
|
-
for (const key of site_keys) {
|
|
1255
|
-
const vec = vec_map.get(key)
|
|
1256
|
-
if (vec) mean = math.add(mean, math.normalize_vec3(vec)) as Vec3
|
|
1257
|
-
}
|
|
1258
|
-
const mean_dir = math.normalize_vec3(mean, [0, 1, 0] as Vec3)
|
|
1259
|
-
const [u_vec, v_vec] = math.compute_in_plane_basis(mean_dir)
|
|
1260
|
-
const offsets = new SvelteMap<string, Vec3>()
|
|
1261
|
-
for (const [idx, key] of site_keys.entries()) {
|
|
1262
|
-
const angle = (2 * Math.PI * idx) / n_keys
|
|
1263
|
-
const dx = math.scale(u_vec, gap_abs * Math.cos(angle)) as Vec3
|
|
1264
|
-
const dy = math.scale(v_vec, gap_abs * Math.sin(angle)) as Vec3
|
|
1265
|
-
offsets.set(key, math.add(dx, dy) as Vec3)
|
|
1266
|
-
}
|
|
1267
|
-
return offsets
|
|
1268
|
-
})
|
|
1269
|
-
: null
|
|
1270
|
-
|
|
1271
|
-
const mag_interpolator = get_d3_interpolator(vector_color_scale)
|
|
1272
|
-
|
|
1273
|
-
return active_keys.map((key, layer_idx) => {
|
|
1274
|
-
const layer_cfg = vector_configs[key]
|
|
1275
|
-
const layer_scale = effective_global_scale * (layer_cfg?.scale ?? 1.0)
|
|
1276
|
-
const layer_color = layer_cfg?.color ??
|
|
1277
|
-
VECTOR_PALETTE[layer_idx % VECTOR_PALETTE.length]
|
|
1278
|
-
|
|
1279
|
-
const arrows = structure.sites
|
|
1280
|
-
.map((site, site_idx) => {
|
|
1281
|
-
const vec_map = site_vec_maps[site_idx]
|
|
1282
|
-
if (!vec_map) return null
|
|
1283
|
-
const vec = vec_map.get(key)
|
|
1284
|
-
if (!vec) return null
|
|
1285
|
-
|
|
1286
|
-
// Resolve color mode: explicit per-key color always wins,
|
|
1287
|
-
// then multi-key uses palette, then mode-based coloring
|
|
1288
|
-
let arrow_color: string
|
|
1289
|
-
if (layer_cfg?.color) {
|
|
1290
|
-
arrow_color = layer_cfg.color
|
|
1291
|
-
} else if (!is_single) arrow_color = layer_color
|
|
1292
|
-
else {
|
|
1293
|
-
const effective_mode = vector_color_mode === `auto`
|
|
1294
|
-
? (key.startsWith(`magmom`) || key.startsWith(`spin`)
|
|
1295
|
-
? `spin_direction`
|
|
1296
|
-
: `element`)
|
|
1297
|
-
: vector_color_mode
|
|
1298
|
-
if (effective_mode === `magnitude`) {
|
|
1299
|
-
const mag = Math.hypot(...vec)
|
|
1300
|
-
const norm = max_mag > 1e-10 ? mag / max_mag : 0
|
|
1301
|
-
arrow_color = mag_interpolator(norm)
|
|
1302
|
-
} else if (effective_mode === `spin_direction`) {
|
|
1303
|
-
arrow_color = spin_direction_color(vec)
|
|
1304
|
-
} else if (effective_mode === `uniform`) {
|
|
1305
|
-
arrow_color = vector_color
|
|
1306
|
-
} else {
|
|
1307
|
-
const majority_element = site.species.length > 0
|
|
1308
|
-
? site.species.reduce((max, spec) =>
|
|
1309
|
-
spec.occu > max.occu ? spec : max
|
|
1310
|
-
).element
|
|
1311
|
-
: undefined
|
|
1312
|
-
arrow_color =
|
|
1313
|
-
(majority_element && colors.element?.[majority_element]) ||
|
|
1314
|
-
vector_color
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
const offset = site_offsets?.[site_idx]?.get(key)
|
|
1319
|
-
const position = offset ? math.add(site.xyz, offset) as Vec3 : site.xyz
|
|
1320
|
-
const arrow_vec = vector_normalize ? math.normalize_vec3(vec) : vec
|
|
1321
|
-
|
|
1322
|
-
return {
|
|
1323
|
-
site_idx,
|
|
1324
|
-
position,
|
|
1325
|
-
vector: arrow_vec,
|
|
1326
|
-
scale: layer_scale,
|
|
1327
|
-
color: arrow_color,
|
|
1328
|
-
}
|
|
1329
|
-
})
|
|
1330
|
-
.filter((item): item is NonNullable<typeof item> => item !== null)
|
|
1331
|
-
|
|
1332
|
-
return { key, arrows }
|
|
1333
|
-
})
|
|
1334
|
-
})
|
|
1335
|
-
|
|
1336
|
-
let instanced_atom_groups = $derived(
|
|
1337
|
-
Object.values(
|
|
1338
|
-
atom_data
|
|
1339
|
-
.filter((atom) => !atom.has_partial_occupancy)
|
|
1340
|
-
.reduce(
|
|
1341
|
-
(groups, atom) => {
|
|
1342
|
-
const { element, radius, color, is_image_atom } = atom
|
|
1343
|
-
// Separate image atoms into their own groups for distinct styling in edit-atoms mode
|
|
1344
|
-
const key = `${element}-${format_num(radius, `.3~`)}-${color}-${
|
|
1345
|
-
is_image_atom ? `img` : `base`
|
|
1346
|
-
}`
|
|
1347
|
-
const bucket = groups[key] ||
|
|
1348
|
-
(groups[key] = { element, radius, color, is_image_atom, atoms: [] })
|
|
1349
|
-
bucket.atoms.push(atom)
|
|
1350
|
-
return groups
|
|
1351
|
-
},
|
|
1352
|
-
{} as Record<string, InstancedAtomGroup>,
|
|
1353
|
-
),
|
|
1354
|
-
),
|
|
1355
|
-
)
|
|
1356
|
-
|
|
1357
|
-
let unique_instanced_atoms = $derived(
|
|
1358
|
-
Object.values(
|
|
1359
|
-
instanced_atom_groups
|
|
1360
|
-
.flatMap((group) => group.atoms)
|
|
1361
|
-
.reduce((acc, atom) => {
|
|
1362
|
-
acc[atom.site_idx] = atom
|
|
1363
|
-
return acc
|
|
1364
|
-
}, {} as Record<number, (typeof atom_data)[number]>),
|
|
1365
|
-
),
|
|
1366
|
-
)
|
|
1367
|
-
|
|
1368
|
-
let gizmo_props = $derived.by(() => {
|
|
1369
|
-
const axis_options = Object.fromEntries(
|
|
1370
|
-
[...AXIS_COLORS, ...NEG_AXIS_COLORS].map(([axis, color, hover_color]) => [
|
|
1371
|
-
axis,
|
|
1372
|
-
{
|
|
1373
|
-
color,
|
|
1374
|
-
labelColor: `#111`,
|
|
1375
|
-
opacity: axis.startsWith(`n`) ? 0.9 : 0.8,
|
|
1376
|
-
hover: {
|
|
1377
|
-
color: hover_color,
|
|
1378
|
-
labelColor: `#222222`,
|
|
1379
|
-
opacity: axis.startsWith(`n`) ? 1 : 0.9,
|
|
1380
|
-
},
|
|
1381
|
-
},
|
|
1382
|
-
]),
|
|
1383
|
-
)
|
|
1384
|
-
return {
|
|
1385
|
-
background: { enabled: false },
|
|
1386
|
-
className: `responsive-gizmo`,
|
|
1387
|
-
...axis_options,
|
|
1388
|
-
...(typeof gizmo === `boolean` ? {} : gizmo),
|
|
1389
|
-
offset: { left: 5, bottom: 5 },
|
|
1390
|
-
}
|
|
1391
|
-
})
|
|
1392
|
-
|
|
1393
|
-
let orbit_controls_props = $derived({
|
|
1394
|
-
position: [0, 0, 0],
|
|
1395
|
-
enableRotate: rotate_speed > 0,
|
|
1396
|
-
rotateSpeed: rotate_speed,
|
|
1397
|
-
enableZoom: zoom_speed > 0,
|
|
1398
|
-
zoomSpeed: camera_projection === `orthographic` ? zoom_speed * 2 : zoom_speed,
|
|
1399
|
-
zoomToCursor: zoom_to_cursor,
|
|
1400
|
-
enablePan: pan_speed > 0,
|
|
1401
|
-
panSpeed: pan_speed,
|
|
1402
|
-
target: camera_target ?? rotation_target,
|
|
1403
|
-
maxZoom: max_zoom,
|
|
1404
|
-
minZoom: min_zoom,
|
|
1405
|
-
autoRotate: Boolean(auto_rotate),
|
|
1406
|
-
autoRotateSpeed: auto_rotate,
|
|
1407
|
-
enableDamping: Boolean(rotation_damping),
|
|
1408
|
-
dampingFactor: rotation_damping,
|
|
1409
|
-
onstart: () => {
|
|
1410
|
-
camera_is_moving = true
|
|
1411
|
-
cancel_atom_hover_clear()
|
|
1412
|
-
hovered_idx = null
|
|
1413
|
-
bond_context_menu = null
|
|
1414
|
-
},
|
|
1415
|
-
onend: () => {
|
|
1416
|
-
camera_is_moving = false
|
|
1417
|
-
},
|
|
1418
|
-
})
|
|
1419
|
-
|
|
1420
|
-
let measure_line_color = $derived.by(() => {
|
|
1421
|
-
if (typeof window === `undefined`) return
|
|
1422
|
-
const root_styles = getComputedStyle(document.documentElement)
|
|
1423
|
-
const text_color = root_styles.getPropertyValue(`--text-color`).trim()
|
|
1424
|
-
return text_color || `#808080`
|
|
1425
|
-
})
|
|
1426
|
-
</script>
|
|
1427
|
-
|
|
1428
|
-
{#snippet bond_instanced_mesh_snippet(
|
|
1429
|
-
group: ComponentProps<typeof Bond>[`group`],
|
|
1430
|
-
)}
|
|
1431
|
-
{#key group.instances.length}
|
|
1432
|
-
<Bond {group} />
|
|
1433
|
-
{/key}
|
|
1434
|
-
{/snippet}
|
|
1435
|
-
|
|
1436
|
-
{#snippet site_label_snippet(position: Vec3, site_idx: number)}
|
|
1437
|
-
{@const site = structure!.sites[site_idx]}
|
|
1438
|
-
{@const visual_radius = (radius_by_site_idx.get(site_idx) ?? 1) * 0.5}
|
|
1439
|
-
<extras.HTML
|
|
1440
|
-
center
|
|
1441
|
-
position={position}
|
|
1442
|
-
calculatePosition={make_label_position_calculator(
|
|
1443
|
-
position,
|
|
1444
|
-
() => smart_site_label_offsets.get(site_idx) ?? site_label_offset,
|
|
1445
|
-
visual_radius,
|
|
1446
|
-
label_screen_margin,
|
|
1447
|
-
)}
|
|
1448
|
-
>
|
|
1449
|
-
{#if atom_label}
|
|
1450
|
-
{@render atom_label({ site, site_idx })}
|
|
1451
|
-
{:else}
|
|
1452
|
-
<button
|
|
1453
|
-
type="button"
|
|
1454
|
-
class="atom-label"
|
|
1455
|
-
style:font-size="{site_label_size * 0.85}em"
|
|
1456
|
-
style:background={site_label_bg_color}
|
|
1457
|
-
style:padding="{site_label_padding}px"
|
|
1458
|
-
style:color={site_label_color}
|
|
1459
|
-
onpointerdown={(event) => {
|
|
1460
|
-
event.preventDefault()
|
|
1461
|
-
event.stopImmediatePropagation()
|
|
1462
|
-
toggle_selection(site_idx, event)
|
|
1463
|
-
}}
|
|
1464
|
-
onclick={(event) => {
|
|
1465
|
-
event.preventDefault()
|
|
1466
|
-
event.stopImmediatePropagation()
|
|
1467
|
-
}}
|
|
1468
|
-
onkeydown={(event) => {
|
|
1469
|
-
if (event.key !== `Enter` && event.key !== ` `) return
|
|
1470
|
-
event.preventDefault()
|
|
1471
|
-
event.stopPropagation()
|
|
1472
|
-
toggle_selection(site_idx, event)
|
|
1473
|
-
}}
|
|
1474
|
-
>
|
|
1475
|
-
{#if show_site_labels}
|
|
1476
|
-
{#if site.species.length === 1}
|
|
1477
|
-
{site.species[0].element}{#if show_site_indices}-{site_idx + 1}{/if}
|
|
1478
|
-
{:else}
|
|
1479
|
-
{#each site.species as
|
|
1480
|
-
{ element, occu, oxidation_state }
|
|
1481
|
-
(`${element}-${occu}-${oxidation_state}`)
|
|
1482
|
-
}
|
|
1483
|
-
{element}<sub>{format_num(occu, `.3~`).replace(`0.`, `.`)}</sub>
|
|
1484
|
-
{/each}
|
|
1485
|
-
{#if show_site_indices}-{site_idx + 1}{/if}
|
|
1486
|
-
{/if}
|
|
1487
|
-
{:else if show_site_indices}
|
|
1488
|
-
{site_idx + 1}
|
|
1489
|
-
{/if}
|
|
1490
|
-
</button>
|
|
1491
|
-
{/if}
|
|
1492
|
-
</extras.HTML>
|
|
1493
|
-
{/snippet}
|
|
1494
|
-
|
|
1495
|
-
{#if camera_projection === `perspective`}
|
|
1496
|
-
<T.PerspectiveCamera
|
|
1497
|
-
makeDefault
|
|
1498
|
-
position={camera_position}
|
|
1499
|
-
{fov}
|
|
1500
|
-
near={camera_near}
|
|
1501
|
-
far={camera_far}
|
|
1502
|
-
>
|
|
1503
|
-
<extras.OrbitControls bind:ref={orbit_controls} {...orbit_controls_props}>
|
|
1504
|
-
{#if gizmo}<extras.Gizmo {...gizmo_props} />{/if}
|
|
1505
|
-
</extras.OrbitControls>
|
|
1506
|
-
</T.PerspectiveCamera>
|
|
1507
|
-
{:else}
|
|
1508
|
-
<T.OrthographicCamera
|
|
1509
|
-
makeDefault
|
|
1510
|
-
position={camera_position}
|
|
1511
|
-
zoom={computed_zoom}
|
|
1512
|
-
near={-100}
|
|
1513
|
-
far={camera_far}
|
|
1514
|
-
>
|
|
1515
|
-
<extras.OrbitControls bind:ref={orbit_controls} {...orbit_controls_props}>
|
|
1516
|
-
{#if gizmo}<extras.Gizmo {...gizmo_props} />{/if}
|
|
1517
|
-
</extras.OrbitControls>
|
|
1518
|
-
</T.OrthographicCamera>
|
|
1519
|
-
{/if}
|
|
1520
|
-
|
|
1521
|
-
<T.DirectionalLight position={[3, 10, 10]} intensity={directional_light} />
|
|
1522
|
-
<T.AmbientLight intensity={ambient_light} />
|
|
1523
|
-
|
|
1524
|
-
<!-- Apply manual rotation around center: translate to origin, rotate, translate back -->
|
|
1525
|
-
<T.Group position={rotation_target}>
|
|
1526
|
-
<T.Group {rotation}>
|
|
1527
|
-
<T.Group position={math.scale(rotation_target, -1)}>
|
|
1528
|
-
{#if show_atoms}
|
|
1529
|
-
<!-- Instanced rendering for full occupancy atoms -->
|
|
1530
|
-
{#each instanced_atom_groups as atom_group (instanced_atom_group_key(atom_group, measure_mode))}
|
|
1531
|
-
{@const { element, radius, color, is_image_atom, atoms } = atom_group}
|
|
1532
|
-
{@const edit_mode_image = measure_mode === `edit-atoms` && is_image_atom}
|
|
1533
|
-
<extras.InstancedMesh
|
|
1534
|
-
key={instanced_atom_group_key(atom_group, measure_mode)}
|
|
1535
|
-
limit={atoms.length}
|
|
1536
|
-
range={atoms.length}
|
|
1537
|
-
frustumCulled={false}
|
|
1538
|
-
>
|
|
1539
|
-
<T.SphereGeometry args={[0.5, sphere_segments, sphere_segments]} />
|
|
1540
|
-
<T.MeshStandardMaterial
|
|
1541
|
-
color={edit_mode_image ? desaturate(color) : color}
|
|
1542
|
-
opacity={edit_mode_image ? 0.5 : 1}
|
|
1543
|
-
transparent={edit_mode_image}
|
|
1544
|
-
/>
|
|
1545
|
-
{#each atoms as atom (atom.site_idx)}
|
|
1546
|
-
<extras.Instance
|
|
1547
|
-
position={atom.position}
|
|
1548
|
-
scale={atom.radius}
|
|
1549
|
-
{...atom_hover_props(atom.site_idx, edit_mode_image)}
|
|
1550
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1551
|
-
if (
|
|
1552
|
-
edit_mode_image ||
|
|
1553
|
-
measure_mode !== `edit-bonds` ||
|
|
1554
|
-
bond_edit_mode !== `add`
|
|
1555
|
-
) {
|
|
1556
|
-
return
|
|
1557
|
-
}
|
|
1558
|
-
select_edit_bonds_site(atom.site_idx, event)
|
|
1559
|
-
}}
|
|
1560
|
-
onclick={(event: MouseEvent) => {
|
|
1561
|
-
if (edit_mode_image) return
|
|
1562
|
-
if (measure_mode === `edit-bonds`) {
|
|
1563
|
-
if (bond_edit_mode !== `add`) return
|
|
1564
|
-
if (skip_duplicate_edit_bonds_click(atom.site_idx)) {
|
|
1565
|
-
event.stopPropagation()
|
|
1566
|
-
return
|
|
1567
|
-
}
|
|
1568
|
-
}
|
|
1569
|
-
toggle_selection(atom.site_idx, event)
|
|
1570
|
-
}}
|
|
1571
|
-
/>
|
|
1572
|
-
{/each}
|
|
1573
|
-
</extras.InstancedMesh>
|
|
1574
|
-
{/each}
|
|
1575
|
-
|
|
1576
|
-
<!-- Regular rendering for partial occupancy atoms -->
|
|
1577
|
-
{#each atom_data.filter((atom) => atom.has_partial_occupancy) as
|
|
1578
|
-
atom
|
|
1579
|
-
(atom.site_idx + atom.element + atom.occupancy)
|
|
1580
|
-
}
|
|
1581
|
-
{@const partial_edit_image = measure_mode === `edit-atoms` && atom.is_image_atom}
|
|
1582
|
-
{@const ghost_opacity = partial_edit_image ? 0.5 : 1}
|
|
1583
|
-
<T.Group
|
|
1584
|
-
position={atom.position}
|
|
1585
|
-
scale={atom.radius}
|
|
1586
|
-
{...atom_hover_props(atom.site_idx, partial_edit_image)}
|
|
1587
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1588
|
-
if (
|
|
1589
|
-
partial_edit_image ||
|
|
1590
|
-
measure_mode !== `edit-bonds` ||
|
|
1591
|
-
bond_edit_mode !== `add`
|
|
1592
|
-
) {
|
|
1593
|
-
return
|
|
1594
|
-
}
|
|
1595
|
-
select_edit_bonds_site(atom.site_idx, event)
|
|
1596
|
-
}}
|
|
1597
|
-
onclick={(event: MouseEvent) => {
|
|
1598
|
-
if (partial_edit_image) return
|
|
1599
|
-
if (measure_mode === `edit-bonds`) {
|
|
1600
|
-
if (bond_edit_mode !== `add`) return
|
|
1601
|
-
if (skip_duplicate_edit_bonds_click(atom.site_idx)) {
|
|
1602
|
-
event.stopPropagation()
|
|
1603
|
-
return
|
|
1604
|
-
}
|
|
1605
|
-
}
|
|
1606
|
-
toggle_selection(atom.site_idx, event)
|
|
1607
|
-
}}
|
|
1608
|
-
>
|
|
1609
|
-
{@const partial_color = partial_edit_image
|
|
1610
|
-
? desaturate(atom.color)
|
|
1611
|
-
: atom.color}
|
|
1612
|
-
<T.Mesh>
|
|
1613
|
-
<T.SphereGeometry
|
|
1614
|
-
args={[
|
|
1615
|
-
0.5,
|
|
1616
|
-
sphere_segments,
|
|
1617
|
-
sphere_segments,
|
|
1618
|
-
atom.start_phi,
|
|
1619
|
-
atom.phi_length,
|
|
1620
|
-
]}
|
|
1621
|
-
/>
|
|
1622
|
-
<T.MeshStandardMaterial
|
|
1623
|
-
color={partial_color}
|
|
1624
|
-
opacity={ghost_opacity}
|
|
1625
|
-
transparent={partial_edit_image}
|
|
1626
|
-
/>
|
|
1627
|
-
</T.Mesh>
|
|
1628
|
-
|
|
1629
|
-
{#if atom.has_partial_occupancy && atom.render_start_cap}
|
|
1630
|
-
<T.Mesh rotation={[0, atom.start_phi, 0]}>
|
|
1631
|
-
<T.CircleGeometry
|
|
1632
|
-
args={[
|
|
1633
|
-
0.5,
|
|
1634
|
-
sphere_segments,
|
|
1635
|
-
PARTIAL_OCCUPANCY_CAP_ARC.start_cap_arc_start,
|
|
1636
|
-
PARTIAL_OCCUPANCY_CAP_ARC.arc_length,
|
|
1637
|
-
]}
|
|
1638
|
-
/>
|
|
1639
|
-
<T.MeshStandardMaterial
|
|
1640
|
-
color={partial_color}
|
|
1641
|
-
side={2}
|
|
1642
|
-
opacity={ghost_opacity}
|
|
1643
|
-
transparent={partial_edit_image}
|
|
1644
|
-
/>
|
|
1645
|
-
</T.Mesh>
|
|
1646
|
-
{/if}
|
|
1647
|
-
{#if atom.has_partial_occupancy && atom.render_end_cap}
|
|
1648
|
-
<T.Mesh rotation={[0, atom.end_phi, 0]}>
|
|
1649
|
-
<T.CircleGeometry
|
|
1650
|
-
args={[
|
|
1651
|
-
0.5,
|
|
1652
|
-
sphere_segments,
|
|
1653
|
-
PARTIAL_OCCUPANCY_CAP_ARC.end_cap_arc_start,
|
|
1654
|
-
PARTIAL_OCCUPANCY_CAP_ARC.arc_length,
|
|
1655
|
-
]}
|
|
1656
|
-
/>
|
|
1657
|
-
<T.MeshStandardMaterial
|
|
1658
|
-
color={partial_color}
|
|
1659
|
-
side={2}
|
|
1660
|
-
opacity={ghost_opacity}
|
|
1661
|
-
transparent={partial_edit_image}
|
|
1662
|
-
/>
|
|
1663
|
-
</T.Mesh>
|
|
1664
|
-
{/if}
|
|
1665
|
-
</T.Group>
|
|
1666
|
-
|
|
1667
|
-
<!-- Render label only for the first species of this site to avoid duplicates -->
|
|
1668
|
-
{#if (show_site_labels || show_site_indices) &&
|
|
1669
|
-
atom.element === structure!.sites[atom.site_idx].species[0].element}
|
|
1670
|
-
{@render site_label_snippet(atom.position, atom.site_idx)}
|
|
1671
|
-
{/if}
|
|
1672
|
-
{/each}
|
|
1673
|
-
|
|
1674
|
-
<!-- Site labels/indices for instanced atoms -->
|
|
1675
|
-
{#if show_site_labels || show_site_indices}
|
|
1676
|
-
{#each unique_instanced_atoms as atom (atom.site_idx)}
|
|
1677
|
-
{@render site_label_snippet(atom.position, atom.site_idx)}
|
|
1678
|
-
{/each}
|
|
1679
|
-
{/if}
|
|
1680
|
-
{/if}
|
|
1681
|
-
|
|
1682
|
-
{#each vector_layers as layer (layer.key)}
|
|
1683
|
-
{#each layer.arrows as arrow (`${layer.key}-${arrow.site_idx}`)}
|
|
1684
|
-
<Arrow
|
|
1685
|
-
{...arrow}
|
|
1686
|
-
shaft_radius={eff_shaft_radius}
|
|
1687
|
-
arrow_head_radius={eff_head_radius}
|
|
1688
|
-
arrow_head_length={eff_head_length}
|
|
1689
|
-
/>
|
|
1690
|
-
{/each}
|
|
1691
|
-
{/each}
|
|
1692
|
-
|
|
1693
|
-
<!-- Instanced bond rendering with gradient colors -->
|
|
1694
|
-
{#if instanced_bond_groups.length > 0}
|
|
1695
|
-
{#each instanced_bond_groups as group (group.thickness + group.instances.length)}
|
|
1696
|
-
{@render bond_instanced_mesh_snippet(group)}
|
|
1697
|
-
{/each}
|
|
1698
|
-
{/if}
|
|
1699
|
-
|
|
1700
|
-
<!-- Clickable bond hit-test cylinders in edit-bonds mode -->
|
|
1701
|
-
{#if measure_mode === `edit-bonds` && editable_bond_pairs.length > 0}
|
|
1702
|
-
{#each editable_bond_pairs as
|
|
1703
|
-
bond
|
|
1704
|
-
(`bond-hit-${bond_edit_mode}-${rendered_bond_key_for(bond)}`)
|
|
1705
|
-
}
|
|
1706
|
-
{@const bond_key = rendered_bond_key_for(bond)}
|
|
1707
|
-
{@const is_hovered = hovered_bond_key === bond_key}
|
|
1708
|
-
{@const is_delete_mode = bond_edit_mode === `delete`}
|
|
1709
|
-
{@const bond_hit_radius =
|
|
1710
|
-
bond_thickness * (is_delete_mode ? 5 : 1.25)}
|
|
1711
|
-
{@const bond_hover_radius = bond_thickness * 1.1}
|
|
1712
|
-
<T.Mesh
|
|
1713
|
-
matrixAutoUpdate={false}
|
|
1714
|
-
oncreate={(ref) => apply_bond_transform(ref, bond)}
|
|
1715
|
-
onpointerdown={(event: BondPointerEvent) => {
|
|
1716
|
-
if (event.nativeEvent?.button === 2) return
|
|
1717
|
-
event.stopPropagation()
|
|
1718
|
-
if (is_delete_mode) {
|
|
1719
|
-
remove_bond(bond.site_idx_1, bond.site_idx_2, bond.cell_shift)
|
|
1720
|
-
measured_sites = []
|
|
1721
|
-
selected_sites = []
|
|
1722
|
-
hovered_bond_key = null
|
|
1723
|
-
} else {
|
|
1724
|
-
const endpoint_site_idx = get_bond_endpoint_hit_site_idx(bond, event)
|
|
1725
|
-
if (endpoint_site_idx != null) {
|
|
1726
|
-
select_edit_bonds_site(endpoint_site_idx, event)
|
|
1727
|
-
}
|
|
1728
|
-
}
|
|
1729
|
-
}}
|
|
1730
|
-
oncontextmenu={(event: BondContextMenuEvent) => {
|
|
1731
|
-
event.nativeEvent?.preventDefault()
|
|
1732
|
-
event.stopPropagation?.()
|
|
1733
|
-
open_bond_context_menu(bond, event)
|
|
1734
|
-
}}
|
|
1735
|
-
onpointerenter={() => (hovered_bond_key = bond_key)}
|
|
1736
|
-
onpointermove={() => (hovered_bond_key = bond_key)}
|
|
1737
|
-
onpointerleave={() => (hovered_bond_key = null)}
|
|
1738
|
-
>
|
|
1739
|
-
<T.CylinderGeometry
|
|
1740
|
-
args={[
|
|
1741
|
-
bond_hit_radius,
|
|
1742
|
-
bond_hit_radius,
|
|
1743
|
-
1,
|
|
1744
|
-
6,
|
|
1745
|
-
]}
|
|
1746
|
-
/>
|
|
1747
|
-
<T.MeshBasicMaterial
|
|
1748
|
-
transparent
|
|
1749
|
-
opacity={0}
|
|
1750
|
-
depthWrite={false}
|
|
1751
|
-
/>
|
|
1752
|
-
</T.Mesh>
|
|
1753
|
-
{#if is_hovered}
|
|
1754
|
-
<T.Mesh
|
|
1755
|
-
matrixAutoUpdate={false}
|
|
1756
|
-
oncreate={(ref) => apply_non_raycastable_bond_hit_transform(ref, bond)}
|
|
1757
|
-
>
|
|
1758
|
-
<T.CylinderGeometry args={[bond_hover_radius, bond_hover_radius, 1, 6]} />
|
|
1759
|
-
<T.MeshBasicMaterial
|
|
1760
|
-
transparent
|
|
1761
|
-
opacity={0.25}
|
|
1762
|
-
color={is_delete_mode ? `#ff4444` : `#6cf0ff`}
|
|
1763
|
-
depthWrite={false}
|
|
1764
|
-
/>
|
|
1765
|
-
</T.Mesh>
|
|
1766
|
-
{/if}
|
|
1767
|
-
{/each}
|
|
1768
|
-
{/if}
|
|
1769
|
-
|
|
1770
|
-
{#if editable_atom_hit_targets.length > 0}
|
|
1771
|
-
{#each editable_atom_hit_targets as atom_hit (atom_hit.site_idx)}
|
|
1772
|
-
<T.Mesh
|
|
1773
|
-
position={atom_hit.position}
|
|
1774
|
-
scale={atom_hit.radius * EDITABLE_ATOM_HIT_RADIUS_SCALE}
|
|
1775
|
-
{...atom_hover_props(atom_hit.site_idx)}
|
|
1776
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1777
|
-
select_edit_bonds_site(atom_hit.site_idx, event)
|
|
1778
|
-
}}
|
|
1779
|
-
>
|
|
1780
|
-
<T.SphereGeometry args={[0.5, 12, 12]} />
|
|
1781
|
-
<T.MeshBasicMaterial
|
|
1782
|
-
transparent
|
|
1783
|
-
opacity={0}
|
|
1784
|
-
depthWrite={false}
|
|
1785
|
-
/>
|
|
1786
|
-
</T.Mesh>
|
|
1787
|
-
{/each}
|
|
1788
|
-
{/if}
|
|
1789
|
-
|
|
1790
|
-
{#if measure_mode === `edit-bonds` && bond_context_menu}
|
|
1791
|
-
{@const current_order = get_current_bond_order(
|
|
1792
|
-
bond_context_menu.site_idx_1,
|
|
1793
|
-
bond_context_menu.site_idx_2,
|
|
1794
|
-
bond_context_menu.cell_shift,
|
|
1795
|
-
)}
|
|
1796
|
-
<extras.HTML autoRender={false} position={bond_context_menu.position}>
|
|
1797
|
-
<div class="bond-context-menu">
|
|
1798
|
-
<strong>Bond Order ({format_bond_order(current_order)})</strong>
|
|
1799
|
-
{#each BOND_ORDER_OPTIONS as { order, label } (label)}
|
|
1800
|
-
<button
|
|
1801
|
-
type="button"
|
|
1802
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1803
|
-
event.preventDefault()
|
|
1804
|
-
event.stopPropagation()
|
|
1805
|
-
set_context_bond_order(order)
|
|
1806
|
-
}}
|
|
1807
|
-
onkeydown={(event: KeyboardEvent) => {
|
|
1808
|
-
if (event.key !== `Enter` && event.key !== ` `) return
|
|
1809
|
-
event.preventDefault()
|
|
1810
|
-
event.stopPropagation()
|
|
1811
|
-
set_context_bond_order(order)
|
|
1812
|
-
}}
|
|
1813
|
-
>
|
|
1814
|
-
{label}
|
|
1815
|
-
</button>
|
|
1816
|
-
{/each}
|
|
1817
|
-
<button
|
|
1818
|
-
type="button"
|
|
1819
|
-
class="remove"
|
|
1820
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1821
|
-
event.preventDefault()
|
|
1822
|
-
event.stopPropagation()
|
|
1823
|
-
remove_context_bond()
|
|
1824
|
-
}}
|
|
1825
|
-
onkeydown={(event: KeyboardEvent) => {
|
|
1826
|
-
if (event.key !== `Enter` && event.key !== ` `) return
|
|
1827
|
-
event.preventDefault()
|
|
1828
|
-
event.stopPropagation()
|
|
1829
|
-
remove_context_bond()
|
|
1830
|
-
}}
|
|
1831
|
-
>
|
|
1832
|
-
Remove
|
|
1833
|
-
</button>
|
|
1834
|
-
<button
|
|
1835
|
-
type="button"
|
|
1836
|
-
onpointerdown={(event: PointerEvent) => {
|
|
1837
|
-
event.preventDefault()
|
|
1838
|
-
event.stopPropagation()
|
|
1839
|
-
close_bond_context_menu()
|
|
1840
|
-
}}
|
|
1841
|
-
onkeydown={(event: KeyboardEvent) => {
|
|
1842
|
-
if (event.key !== `Enter` && event.key !== ` `) return
|
|
1843
|
-
event.preventDefault()
|
|
1844
|
-
event.stopPropagation()
|
|
1845
|
-
close_bond_context_menu()
|
|
1846
|
-
}}
|
|
1847
|
-
>
|
|
1848
|
-
Close
|
|
1849
|
-
</button>
|
|
1850
|
-
</div>
|
|
1851
|
-
</extras.HTML>
|
|
1852
|
-
{/if}
|
|
1853
|
-
|
|
1854
|
-
<!-- highlight hovered, active and selected sites -->
|
|
1855
|
-
{#each [
|
|
1856
|
-
{
|
|
1857
|
-
kind: `hover`,
|
|
1858
|
-
site: hovered_site,
|
|
1859
|
-
opacity: 0.28,
|
|
1860
|
-
color: `white`,
|
|
1861
|
-
site_idx: hovered_idx,
|
|
1862
|
-
},
|
|
1863
|
-
...((selected_sites ?? []).map((idx) => ({
|
|
1864
|
-
kind: `selected`,
|
|
1865
|
-
site: structure?.sites?.[idx] ?? null,
|
|
1866
|
-
site_idx: idx,
|
|
1867
|
-
opacity: pulse_opacity,
|
|
1868
|
-
color: selection_highlight_color,
|
|
1869
|
-
}))),
|
|
1870
|
-
...((active_sites ?? []).map((idx) => ({
|
|
1871
|
-
kind: `active`,
|
|
1872
|
-
site: structure?.sites?.[idx] ?? null,
|
|
1873
|
-
site_idx: idx,
|
|
1874
|
-
opacity: pulse_opacity, // Let it pulse freely
|
|
1875
|
-
color: active_highlight_color,
|
|
1876
|
-
}))),
|
|
1877
|
-
] as
|
|
1878
|
-
entry
|
|
1879
|
-
(`${entry.kind}-${entry.site_idx}`)
|
|
1880
|
-
}
|
|
1881
|
-
{@const { site, opacity, color, kind, site_idx } = entry}
|
|
1882
|
-
{#if site}
|
|
1883
|
-
{@const xyz = site.xyz}
|
|
1884
|
-
{@const highlight_radius = site_idx !== null
|
|
1885
|
-
? radius_by_site_idx.get(site_idx) ?? get_site_radius(site, site_idx)
|
|
1886
|
-
: get_site_radius(site, site_idx)}
|
|
1887
|
-
<T.Mesh
|
|
1888
|
-
position={xyz}
|
|
1889
|
-
scale={1.2 * highlight_radius}
|
|
1890
|
-
oncreate={disable_raycast}
|
|
1891
|
-
>
|
|
1892
|
-
<T.SphereGeometry args={[0.5, 22, 22]} />
|
|
1893
|
-
<T.MeshStandardMaterial
|
|
1894
|
-
{color}
|
|
1895
|
-
transparent
|
|
1896
|
-
{opacity}
|
|
1897
|
-
emissive={color}
|
|
1898
|
-
emissiveIntensity={kind === `selected` || kind === `active` ? 0.7 : 0.2}
|
|
1899
|
-
depthTest={false}
|
|
1900
|
-
depthWrite={false}
|
|
1901
|
-
/>
|
|
1902
|
-
</T.Mesh>
|
|
1903
|
-
{/if}
|
|
1904
|
-
{/each}
|
|
1905
|
-
|
|
1906
|
-
<!-- selection order labels (1, 2, 3, ...) for measurements and bond editing -->
|
|
1907
|
-
{#if structure?.sites && (measured_sites?.length ?? 0) > 0 &&
|
|
1908
|
-
(measure_mode === `distance` || measure_mode === `angle` ||
|
|
1909
|
-
measure_mode === `edit-bonds`)}
|
|
1910
|
-
{#each measured_sites as site_index, loop_idx (site_index)}
|
|
1911
|
-
{@const site = structure.sites[site_index]}
|
|
1912
|
-
{#if site}
|
|
1913
|
-
<!-- shift selected site labels down to avoid overlapping regular site labels-->
|
|
1914
|
-
{@const selection_offset = math.add(site_label_offset, [0, -0.5, 0])}
|
|
1915
|
-
{@const pos = math.add(site.xyz, selection_offset) as Vec3}
|
|
1916
|
-
<extras.HTML center position={pos}>
|
|
1917
|
-
<span class="selection-label">{loop_idx + 1}</span>
|
|
1918
|
-
</extras.HTML>
|
|
1919
|
-
{/if}
|
|
1920
|
-
{/each}
|
|
1921
|
-
{/if}
|
|
1922
|
-
|
|
1923
|
-
<!-- hovered site tooltip -->
|
|
1924
|
-
{#if hovered_site && !camera_is_moving &&
|
|
1925
|
-
(atom_tooltip_active || active_sites.includes(hovered_idx ?? -1))}
|
|
1926
|
-
{@const abc = hovered_site.abc.map((val) => format_num(val, float_fmt)).join(
|
|
1927
|
-
`, `,
|
|
1928
|
-
)}
|
|
1929
|
-
{@const xyz = hovered_site.xyz.map((val) => format_num(val, float_fmt)).join(
|
|
1930
|
-
`, `,
|
|
1931
|
-
)}
|
|
1932
|
-
{@const bond_neighbors = (() => {
|
|
1933
|
-
if (hovered_idx == null || !structure?.sites) return []
|
|
1934
|
-
return filtered_bond_pairs
|
|
1935
|
-
.filter((bond) =>
|
|
1936
|
-
bond.site_idx_1 === hovered_idx || bond.site_idx_2 === hovered_idx
|
|
1937
|
-
)
|
|
1938
|
-
.map((bond) => {
|
|
1939
|
-
const neighbor_idx = bond.site_idx_1 === hovered_idx
|
|
1940
|
-
? bond.site_idx_2
|
|
1941
|
-
: bond.site_idx_1
|
|
1942
|
-
return structure.sites[neighbor_idx]?.species[0]?.element ?? `?`
|
|
1943
|
-
})
|
|
1944
|
-
})()}
|
|
1945
|
-
{@const bond_summary = (() => {
|
|
1946
|
-
if (bond_neighbors.length === 0) return ``
|
|
1947
|
-
const counts: Record<string, number> = {}
|
|
1948
|
-
for (const elem of bond_neighbors) {
|
|
1949
|
-
counts[elem] = (counts[elem] ?? 0) + 1
|
|
1950
|
-
}
|
|
1951
|
-
const parts = Object.entries(counts)
|
|
1952
|
-
.sort(([a], [b]) => a.localeCompare(b))
|
|
1953
|
-
.map(([elem, count]) => `${elem}: ${count}`)
|
|
1954
|
-
return ` (${parts.join(`, `)})`
|
|
1955
|
-
})()}
|
|
1956
|
-
<CanvasTooltip position={hovered_site.xyz}>
|
|
1957
|
-
<!-- Element symbols with occupancies for disordered sites -->
|
|
1958
|
-
<div class="elements">
|
|
1959
|
-
{#each hovered_site.species ?? [] as
|
|
1960
|
-
{ element, occu, oxidation_state: oxi_state },
|
|
1961
|
-
idx
|
|
1962
|
-
(`${element ?? ``}-${occu ?? ``}-${oxi_state ?? ``}-${idx}`)
|
|
1963
|
-
}
|
|
1964
|
-
{@const element_name = element_data.find((elem) =>
|
|
1965
|
-
elem.symbol === element
|
|
1966
|
-
)?.name ??
|
|
1967
|
-
``}
|
|
1968
|
-
{#if idx > 0} {/if}
|
|
1969
|
-
{#if occu !== 1}<span class="occupancy">{
|
|
1970
|
-
format_num(occu, `.3~f`)
|
|
1971
|
-
}</span>{/if}
|
|
1972
|
-
<strong>
|
|
1973
|
-
{element}{#if oxi_state != null && oxi_state !== 0}<sup>{Math.abs(
|
|
1974
|
-
oxi_state,
|
|
1975
|
-
)}{oxi_state > 0 ? `+` : `−`}</sup>{/if}
|
|
1976
|
-
</strong>
|
|
1977
|
-
{#if element_name}<span class="elem-name">{element_name}</span>{/if}
|
|
1978
|
-
{/each}
|
|
1979
|
-
</div>
|
|
1980
|
-
<div class="coordinates fractional">abc: ({abc})</div>
|
|
1981
|
-
<div class="coordinates cartesian">xyz: ({xyz}) Å</div>
|
|
1982
|
-
{#if bond_neighbors.length > 0}
|
|
1983
|
-
<div class="coordinates">Bonds: {bond_neighbors.length}{bond_summary}</div>
|
|
1984
|
-
{/if}
|
|
1985
|
-
</CanvasTooltip>
|
|
1986
|
-
{/if}
|
|
1987
|
-
|
|
1988
|
-
{#if visual_lattice}
|
|
1989
|
-
<Lattice matrix={visual_lattice.matrix} {...lattice_props} />
|
|
1990
|
-
{/if}
|
|
1991
|
-
|
|
1992
|
-
<!-- TransformControls for editing atoms in edit-atoms mode -->
|
|
1993
|
-
{#if measure_mode === `edit-atoms` && selected_sites.length > 0 &&
|
|
1994
|
-
structure?.sites}
|
|
1995
|
-
{@const selected_atoms = selected_sites
|
|
1996
|
-
.map((idx) => structure?.sites?.[idx])
|
|
1997
|
-
.filter((site): site is Site => site != null)}
|
|
1998
|
-
{#if selected_atoms.length > 0}
|
|
1999
|
-
{@const avg = (dim: number) =>
|
|
2000
|
-
selected_atoms.reduce((sum, atom) => sum + atom.xyz[dim], 0) /
|
|
2001
|
-
selected_atoms.length}
|
|
2002
|
-
{@const centroid = [avg(0), avg(1), avg(2)] as Vec3}
|
|
2003
|
-
<!-- Invisible mesh at centroid for TransformControls to manipulate.
|
|
2004
|
-
During drag, use frozen_centroid so Svelte doesn't override TransformControls
|
|
2005
|
-
with the wrapped centroid (which jumps on PBC boundary crossings). -->
|
|
2006
|
-
<T.Mesh
|
|
2007
|
-
position={frozen_centroid ?? centroid}
|
|
2008
|
-
bind:ref={transform_object}
|
|
2009
|
-
>
|
|
2010
|
-
<T.SphereGeometry args={[0.01, 4, 4]} />
|
|
2011
|
-
<T.MeshBasicMaterial transparent opacity={0} />
|
|
2012
|
-
</T.Mesh>
|
|
2013
|
-
<extras.TransformControls
|
|
2014
|
-
object={transform_object}
|
|
2015
|
-
translationSnap={0.1}
|
|
2016
|
-
size={1.2}
|
|
2017
|
-
space="world"
|
|
2018
|
-
onobjectChange={() => {
|
|
2019
|
-
if (!transform_object?.position || !drag_start_centroid) return
|
|
2020
|
-
const { x: tx, y: ty, z: tz } = transform_object.position
|
|
2021
|
-
const delta: Vec3 = [
|
|
2022
|
-
tx - drag_start_centroid[0],
|
|
2023
|
-
ty - drag_start_centroid[1],
|
|
2024
|
-
tz - drag_start_centroid[2],
|
|
2025
|
-
]
|
|
2026
|
-
// Update reference point so deltas are incremental, not cumulative.
|
|
2027
|
-
// Without this, each frame compounds: sites already moved by previous
|
|
2028
|
-
// delta get the full cumulative delta re-applied.
|
|
2029
|
-
drag_start_centroid = [tx, ty, tz]
|
|
2030
|
-
on_sites_moved?.(selected_sites, delta)
|
|
2031
|
-
}}
|
|
2032
|
-
onmouseDown={() => {
|
|
2033
|
-
dragging_atoms = true
|
|
2034
|
-
drag_start_centroid = frozen_centroid = [...centroid] as Vec3
|
|
2035
|
-
on_operation_start?.()
|
|
2036
|
-
}}
|
|
2037
|
-
onmouseUp={() => {
|
|
2038
|
-
dragging_atoms = false
|
|
2039
|
-
frozen_centroid = null
|
|
2040
|
-
drag_start_centroid = null
|
|
2041
|
-
}}
|
|
2042
|
-
/>
|
|
2043
|
-
{/if}
|
|
2044
|
-
{/if}
|
|
2045
|
-
|
|
2046
|
-
<!-- Invisible plane for click-to-place atom in add-atom mode -->
|
|
2047
|
-
<!-- Uses onBeforeRender to orient normal toward camera so raycasts always hit -->
|
|
2048
|
-
{#if measure_mode === `edit-atoms` && add_atom_mode}
|
|
2049
|
-
{@const center = rotation_target ?? [0, 0, 0]}
|
|
2050
|
-
<T.Mesh
|
|
2051
|
-
position={center}
|
|
2052
|
-
onBeforeRender={(mesh: Mesh) => {
|
|
2053
|
-
if (camera) {
|
|
2054
|
-
mesh.lookAt(camera.position)
|
|
2055
|
-
}
|
|
2056
|
-
}}
|
|
2057
|
-
onclick={(event: { point: { x: number; y: number; z: number } }) => {
|
|
2058
|
-
const { x, y, z } = event.point
|
|
2059
|
-
on_add_atom?.([x, y, z] as Vec3, add_element as ElementSymbol)
|
|
2060
|
-
}}
|
|
2061
|
-
>
|
|
2062
|
-
<T.PlaneGeometry
|
|
2063
|
-
args={[
|
|
2064
|
-
Math.max(200, structure_size * 4),
|
|
2065
|
-
Math.max(200, structure_size * 4),
|
|
2066
|
-
]}
|
|
2067
|
-
/>
|
|
2068
|
-
<T.MeshBasicMaterial transparent opacity={0} side={2} depthWrite={false} />
|
|
2069
|
-
</T.Mesh>
|
|
2070
|
-
{/if}
|
|
2071
|
-
|
|
2072
|
-
<!-- Isosurface rendering from volumetric data (CHGCAR, .cube files) -->
|
|
2073
|
-
{#if volumetric_data && isosurface_settings}
|
|
2074
|
-
<Isosurface volume={volumetric_data} settings={isosurface_settings} />
|
|
2075
|
-
{/if}
|
|
2076
|
-
|
|
2077
|
-
<!-- Measurement overlays for measured sites -->
|
|
2078
|
-
{#if structure?.sites && (measured_sites?.length ?? 0) > 0}
|
|
2079
|
-
{#if measure_mode === `distance`}
|
|
2080
|
-
{#each measured_sites as idx_i, loop_idx (idx_i)}
|
|
2081
|
-
{#each measured_sites.slice(loop_idx + 1) as idx_j (idx_i + `-` + idx_j)}
|
|
2082
|
-
{@const site_i = structure.sites[idx_i]}
|
|
2083
|
-
{@const site_j = structure.sites[idx_j]}
|
|
2084
|
-
{@const pos_i = site_i.xyz}
|
|
2085
|
-
{@const pos_j = site_j.xyz}
|
|
2086
|
-
<Cylinder
|
|
2087
|
-
from={pos_i}
|
|
2088
|
-
to={pos_j}
|
|
2089
|
-
thickness={0.12}
|
|
2090
|
-
color={measure_line_color}
|
|
2091
|
-
/>
|
|
2092
|
-
{@const midpoint = [
|
|
2093
|
-
(pos_i[0] + pos_j[0]) / 2,
|
|
2094
|
-
(pos_i[1] + pos_j[1]) / 2,
|
|
2095
|
-
(pos_i[2] + pos_j[2]) / 2,
|
|
2096
|
-
] as Vec3}
|
|
2097
|
-
{@const direct = math.euclidean_dist(pos_i, pos_j)}
|
|
2098
|
-
{@const pbc = lattice
|
|
2099
|
-
? measure.distance_pbc(pos_i, pos_j, lattice.matrix)
|
|
2100
|
-
: direct}
|
|
2101
|
-
{@const differ = lattice ? Math.abs(pbc - direct) > 1e-6 : false}
|
|
2102
|
-
<extras.HTML center position={midpoint}>
|
|
2103
|
-
<span class="measure-label">
|
|
2104
|
-
{#if differ}
|
|
2105
|
-
PBC: {format_num(pbc, float_fmt)} Å<br /><small>
|
|
2106
|
-
Direct: {format_num(direct, float_fmt)} Å</small>
|
|
2107
|
-
{:else}
|
|
2108
|
-
{format_num(pbc, float_fmt)} Å
|
|
2109
|
-
{/if}
|
|
2110
|
-
</span>
|
|
2111
|
-
</extras.HTML>
|
|
2112
|
-
{/each}
|
|
2113
|
-
{/each}
|
|
2114
|
-
{:else if measure_mode === `angle` && measured_sites.length >= 3}
|
|
2115
|
-
{#each measured_sites as idx_center (idx_center)}
|
|
2116
|
-
{@const center = structure.sites[idx_center]}
|
|
2117
|
-
{#each measured_sites.filter((idx) => idx !== idx_center) as
|
|
2118
|
-
idx_a,
|
|
2119
|
-
loop_idx
|
|
2120
|
-
(idx_center + `-` + idx_a)
|
|
2121
|
-
}
|
|
2122
|
-
{#each measured_sites.filter((idx) => idx !== idx_center).slice(loop_idx + 1) as
|
|
2123
|
-
idx_b
|
|
2124
|
-
(idx_center + `-` + idx_a + `-` + idx_b)
|
|
2125
|
-
}
|
|
2126
|
-
{@const site_a = structure.sites[idx_a]}
|
|
2127
|
-
{@const site_b = structure.sites[idx_b]}
|
|
2128
|
-
{@const v1 = measure.displacement_pbc(center.xyz, site_a.xyz, lattice?.matrix)}
|
|
2129
|
-
{@const v2 = measure.displacement_pbc(center.xyz, site_b.xyz, lattice?.matrix)}
|
|
2130
|
-
{@const n1 = Math.hypot(v1[0], v1[1], v1[2])}
|
|
2131
|
-
{@const n2 = Math.hypot(v2[0], v2[1], v2[2])}
|
|
2132
|
-
{@const angle_deg = measure.angle_between_vectors(v1, v2, `degrees`)}
|
|
2133
|
-
{#if n1 > math.EPS && n2 > math.EPS}
|
|
2134
|
-
<!-- draw rays from center to the two sites -->
|
|
2135
|
-
<Cylinder
|
|
2136
|
-
from={center.xyz}
|
|
2137
|
-
to={site_a.xyz}
|
|
2138
|
-
thickness={0.05}
|
|
2139
|
-
color={measure_line_color}
|
|
2140
|
-
/>
|
|
2141
|
-
<Cylinder
|
|
2142
|
-
from={center.xyz}
|
|
2143
|
-
to={site_b.xyz}
|
|
2144
|
-
thickness={0.05}
|
|
2145
|
-
color={measure_line_color}
|
|
2146
|
-
/>
|
|
2147
|
-
{@const bisector = math.add(math.scale(v1, 1 / n1), math.scale(v2, 1 / n2))}
|
|
2148
|
-
{@const bis_norm = Math.hypot(...bisector) || 1}
|
|
2149
|
-
{@const offset_dir = math.scale(bisector, 1 / bis_norm)}
|
|
2150
|
-
{@const label_pos = math.add(center.xyz, math.scale(offset_dir, 0.6))}
|
|
2151
|
-
<extras.HTML center position={label_pos}>
|
|
2152
|
-
<span class="measure-label">{format_num(angle_deg, float_fmt)}°</span>
|
|
2153
|
-
</extras.HTML>
|
|
2154
|
-
{/if}
|
|
2155
|
-
{/each}
|
|
2156
|
-
{/each}
|
|
2157
|
-
{/each}
|
|
2158
|
-
{/if}
|
|
2159
|
-
{/if}
|
|
2160
|
-
</T.Group>
|
|
2161
|
-
</T.Group>
|
|
2162
|
-
</T.Group>
|
|
2163
|
-
|
|
2164
|
-
<style>
|
|
2165
|
-
:global(.structure .responsive-gizmo) {
|
|
2166
|
-
width: clamp(70px, 18cqmin, 100px) !important;
|
|
2167
|
-
height: clamp(70px, 18cqmin, 100px) !important;
|
|
2168
|
-
}
|
|
2169
|
-
.atom-label {
|
|
2170
|
-
background: var(--struct-atom-label-bg, rgba(0, 0, 0, 0.1));
|
|
2171
|
-
border: 0;
|
|
2172
|
-
border-radius: var(--struct-atom-label-border-radius, var(--border-radius, 3pt));
|
|
2173
|
-
color: inherit;
|
|
2174
|
-
cursor: pointer;
|
|
2175
|
-
font: inherit;
|
|
2176
|
-
padding: var(--struct-atom-label-padding, 0 3px);
|
|
2177
|
-
white-space: nowrap;
|
|
2178
|
-
}
|
|
2179
|
-
.elements {
|
|
2180
|
-
margin-bottom: var(--canvas-tooltip-elements-margin);
|
|
2181
|
-
}
|
|
2182
|
-
.occupancy {
|
|
2183
|
-
font-size: var(--canvas-tooltip-occu-font-size);
|
|
2184
|
-
opacity: var(--canvas-tooltip-occu-opacity);
|
|
2185
|
-
margin-right: var(--canvas-tooltip-occu-margin);
|
|
2186
|
-
}
|
|
2187
|
-
.elem-name {
|
|
2188
|
-
font-size: var(--canvas-tooltip-elem-name-font-size, 0.85em);
|
|
2189
|
-
opacity: var(--canvas-tooltip-elem-name-opacity, 0.7);
|
|
2190
|
-
margin: var(--canvas-tooltip-elem-name-margin, 0 0 0 0.3em);
|
|
2191
|
-
font-weight: var(--canvas-tooltip-elem-name-font-weight, normal);
|
|
2192
|
-
}
|
|
2193
|
-
.coordinates {
|
|
2194
|
-
font-size: var(--canvas-tooltip-coords-font-size);
|
|
2195
|
-
margin: var(--canvas-tooltip-coords-margin);
|
|
2196
|
-
}
|
|
2197
|
-
.measure-label {
|
|
2198
|
-
background: var(--measure-label-bg, var(--surface-bg));
|
|
2199
|
-
color: var(--measure-label-color, var(--text-color));
|
|
2200
|
-
border-radius: var(--border-radius, 3pt);
|
|
2201
|
-
padding: 0 5px;
|
|
2202
|
-
user-select: none;
|
|
2203
|
-
white-space: pre;
|
|
2204
|
-
display: grid;
|
|
2205
|
-
place-items: center;
|
|
2206
|
-
line-height: 1.2;
|
|
2207
|
-
font-size: var(--canvas-tooltip-font-size, clamp(8pt, 2cqmin, 18pt));
|
|
2208
|
-
box-shadow: var(--measure-label-shadow, 0 1px 6px rgba(0, 0, 0, 0.2));
|
|
2209
|
-
}
|
|
2210
|
-
.bond-context-menu {
|
|
2211
|
-
display: grid;
|
|
2212
|
-
min-width: 8rem;
|
|
2213
|
-
gap: 2pt;
|
|
2214
|
-
padding: 3pt 5pt;
|
|
2215
|
-
border-radius: var(--border-radius, 3pt);
|
|
2216
|
-
background: var(--surface-bg, Canvas);
|
|
2217
|
-
color: var(--text-color, currentColor);
|
|
2218
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
|
|
2219
|
-
pointer-events: auto;
|
|
2220
|
-
strong {
|
|
2221
|
-
font-size: 0.85em;
|
|
2222
|
-
padding: 0 2pt 2pt;
|
|
2223
|
-
white-space: nowrap;
|
|
2224
|
-
}
|
|
2225
|
-
button {
|
|
2226
|
-
border: none;
|
|
2227
|
-
border-radius: var(--border-radius, 3pt);
|
|
2228
|
-
background: transparent;
|
|
2229
|
-
color: inherit;
|
|
2230
|
-
cursor: pointer;
|
|
2231
|
-
padding: 2pt 5pt;
|
|
2232
|
-
text-align: left;
|
|
2233
|
-
}
|
|
2234
|
-
button:hover {
|
|
2235
|
-
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
2236
|
-
}
|
|
2237
|
-
button.remove {
|
|
2238
|
-
color: var(--error-color, #f44336);
|
|
2239
|
-
}
|
|
2240
|
-
}
|
|
2241
|
-
.selection-label {
|
|
2242
|
-
display: inline-flex;
|
|
2243
|
-
align-items: center;
|
|
2244
|
-
justify-content: center;
|
|
2245
|
-
min-width: 1.2em;
|
|
2246
|
-
height: 1.2em;
|
|
2247
|
-
padding: 0 0.25em;
|
|
2248
|
-
border-radius: 999px;
|
|
2249
|
-
background: var(--pane-btn-bg-hover);
|
|
2250
|
-
color: var(--struct-text-color);
|
|
2251
|
-
font-size: 0.85em;
|
|
2252
|
-
line-height: 1;
|
|
2253
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
2254
|
-
}
|
|
2255
|
-
</style>
|