react-cheminfo 0.65.0 → 0.67.0
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/README.md +33 -17
- package/lib/download/ui/FigureDownloadPanel.d.ts +7 -1
- package/lib/download/ui/FigureDownloadPanel.d.ts.map +1 -1
- package/lib/download/ui/FigureDownloadPanel.js +2 -2
- package/lib/download/ui/FigureDownloadPanel.js.map +1 -1
- package/lib/ecosystem/core/sites.js +3 -3
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/core/types.d.ts +1 -1
- package/lib/ecosystem/core/types.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +1 -1
- package/lib/ecosystem/ui/glyphs.js.map +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts +1 -1
- package/lib/i18n/core/chromeCatalog.d.ts.map +1 -1
- package/lib/i18n/core/messageCatalog.d.ts +2 -2
- package/lib/i18n/vite/localeCatalog.d.ts +1 -1
- package/lib/ir/core/analysisSpectra.d.ts +23 -6
- package/lib/ir/core/analysisSpectra.d.ts.map +1 -1
- package/lib/ir/core/analysisSpectra.js.map +1 -1
- package/lib/ir/core/bandLabelPlan.d.ts.map +1 -1
- package/lib/ir/core/bandLabelPlan.js +11 -6
- package/lib/ir/core/bandLabelPlan.js.map +1 -1
- package/lib/ir/core/index.d.ts +15 -11
- package/lib/ir/core/index.d.ts.map +1 -1
- package/lib/ir/core/index.js +9 -6
- package/lib/ir/core/index.js.map +1 -1
- package/lib/ir/core/irBand.d.ts +45 -14
- package/lib/ir/core/irBand.d.ts.map +1 -1
- package/lib/ir/core/irBand.js +28 -6
- package/lib/ir/core/irBand.js.map +1 -1
- package/lib/ir/core/irCommands.d.ts +11 -0
- package/lib/ir/core/irCommands.d.ts.map +1 -1
- package/lib/ir/core/irCommands.js +11 -1
- package/lib/ir/core/irCommands.js.map +1 -1
- package/lib/ir/core/irDomain.d.ts +4 -3
- package/lib/ir/core/irDomain.d.ts.map +1 -1
- package/lib/ir/core/irDomain.js +10 -7
- package/lib/ir/core/irDomain.js.map +1 -1
- package/lib/ir/core/irEditorApi.d.ts +12 -0
- package/lib/ir/core/irEditorApi.d.ts.map +1 -1
- package/lib/ir/core/irFormat.d.ts +14 -2
- package/lib/ir/core/irFormat.d.ts.map +1 -1
- package/lib/ir/core/irFormat.js +33 -4
- package/lib/ir/core/irFormat.js.map +1 -1
- package/lib/ir/core/irMode.d.ts +35 -8
- package/lib/ir/core/irMode.d.ts.map +1 -1
- package/lib/ir/core/irMode.js +38 -10
- package/lib/ir/core/irMode.js.map +1 -1
- package/lib/ir/core/irReducer.d.ts +2 -30
- package/lib/ir/core/irReducer.d.ts.map +1 -1
- package/lib/ir/core/irReducer.js +1 -24
- package/lib/ir/core/irReducer.js.map +1 -1
- package/lib/ir/core/irSidePanels.d.ts +7 -1
- package/lib/ir/core/irSidePanels.d.ts.map +1 -1
- package/lib/ir/core/irSpectrum.d.ts +52 -26
- package/lib/ir/core/irSpectrum.d.ts.map +1 -1
- package/lib/ir/core/irSpectrum.js +21 -15
- package/lib/ir/core/irSpectrum.js.map +1 -1
- package/lib/ir/core/irState.d.ts +46 -5
- package/lib/ir/core/irState.d.ts.map +1 -1
- package/lib/ir/core/irState.js +38 -1
- package/lib/ir/core/irState.js.map +1 -1
- package/lib/ir/core/irTechnique.d.ts +94 -0
- package/lib/ir/core/irTechnique.d.ts.map +1 -0
- package/lib/ir/core/irTechnique.js +87 -0
- package/lib/ir/core/irTechnique.js.map +1 -0
- package/lib/ir/core/irTechniqueCommands.d.ts +26 -0
- package/lib/ir/core/irTechniqueCommands.d.ts.map +1 -0
- package/lib/ir/core/irTechniqueCommands.js +68 -0
- package/lib/ir/core/irTechniqueCommands.js.map +1 -0
- package/lib/ir/core/pickBands.d.ts +6 -5
- package/lib/ir/core/pickBands.d.ts.map +1 -1
- package/lib/ir/core/pickBands.js +49 -26
- package/lib/ir/core/pickBands.js.map +1 -1
- package/lib/ir/core/ramanBands.d.ts +30 -0
- package/lib/ir/core/ramanBands.d.ts.map +1 -0
- package/lib/ir/core/ramanBands.js +83 -0
- package/lib/ir/core/ramanBands.js.map +1 -0
- package/lib/ir/core/spectrumJcamp.d.ts +10 -5
- package/lib/ir/core/spectrumJcamp.d.ts.map +1 -1
- package/lib/ir/core/spectrumJcamp.js +63 -15
- package/lib/ir/core/spectrumJcamp.js.map +1 -1
- package/lib/ir/core/toIrSpectrum.d.ts.map +1 -1
- package/lib/ir/core/toIrSpectrum.js +17 -2
- package/lib/ir/core/toIrSpectrum.js.map +1 -1
- package/lib/ir/ui/BandRow.d.ts +30 -0
- package/lib/ir/ui/BandRow.d.ts.map +1 -0
- package/lib/ir/ui/BandRow.js +42 -0
- package/lib/ir/ui/BandRow.js.map +1 -0
- package/lib/ir/ui/BandsPanel.d.ts +4 -0
- package/lib/ir/ui/BandsPanel.d.ts.map +1 -1
- package/lib/ir/ui/BandsPanel.js +14 -59
- package/lib/ir/ui/BandsPanel.js.map +1 -1
- package/lib/ir/ui/IrAboutDialog.d.ts +7 -0
- package/lib/ir/ui/IrAboutDialog.d.ts.map +1 -1
- package/lib/ir/ui/IrAboutDialog.js +16 -3
- package/lib/ir/ui/IrAboutDialog.js.map +1 -1
- package/lib/ir/ui/IrCanvas.d.ts +7 -0
- package/lib/ir/ui/IrCanvas.d.ts.map +1 -1
- package/lib/ir/ui/IrCanvas.js +9 -4
- package/lib/ir/ui/IrCanvas.js.map +1 -1
- package/lib/ir/ui/IrChart.d.ts +2 -1
- package/lib/ir/ui/IrChart.d.ts.map +1 -1
- package/lib/ir/ui/IrChart.js +22 -21
- package/lib/ir/ui/IrChart.js.map +1 -1
- package/lib/ir/ui/IrCommandProvider.d.ts +7 -0
- package/lib/ir/ui/IrCommandProvider.d.ts.map +1 -1
- package/lib/ir/ui/IrCommandProvider.js +2 -2
- package/lib/ir/ui/IrCommandProvider.js.map +1 -1
- package/lib/ir/ui/IrCommandTooltip.d.ts +7 -0
- package/lib/ir/ui/IrCommandTooltip.d.ts.map +1 -1
- package/lib/ir/ui/IrCommandTooltip.js +3 -2
- package/lib/ir/ui/IrCommandTooltip.js.map +1 -1
- package/lib/ir/ui/IrDocumentationDialog.d.ts +8 -1
- package/lib/ir/ui/IrDocumentationDialog.d.ts.map +1 -1
- package/lib/ir/ui/IrDocumentationDialog.js +30 -7
- package/lib/ir/ui/IrDocumentationDialog.js.map +1 -1
- package/lib/ir/ui/IrEditor.d.ts +25 -5
- package/lib/ir/ui/IrEditor.d.ts.map +1 -1
- package/lib/ir/ui/IrEditor.js +3 -20
- package/lib/ir/ui/IrEditor.js.map +1 -1
- package/lib/ir/ui/IrHeader.d.ts.map +1 -1
- package/lib/ir/ui/IrHeader.js +5 -1
- package/lib/ir/ui/IrHeader.js.map +1 -1
- package/lib/ir/ui/IrLogo.d.ts +11 -3
- package/lib/ir/ui/IrLogo.d.ts.map +1 -1
- package/lib/ir/ui/IrLogo.js +14 -5
- package/lib/ir/ui/IrLogo.js.map +1 -1
- package/lib/ir/ui/IrShell.d.ts +9 -1
- package/lib/ir/ui/IrShell.d.ts.map +1 -1
- package/lib/ir/ui/IrShell.js +26 -74
- package/lib/ir/ui/IrShell.js.map +1 -1
- package/lib/ir/ui/IrSidePanel.d.ts +11 -0
- package/lib/ir/ui/IrSidePanel.d.ts.map +1 -1
- package/lib/ir/ui/IrSidePanel.js +12 -3
- package/lib/ir/ui/IrSidePanel.js.map +1 -1
- package/lib/ir/ui/IrStatusBar.d.ts +3 -2
- package/lib/ir/ui/IrStatusBar.d.ts.map +1 -1
- package/lib/ir/ui/IrStatusBar.js +14 -9
- package/lib/ir/ui/IrStatusBar.js.map +1 -1
- package/lib/ir/ui/IrToolbar.d.ts +3 -0
- package/lib/ir/ui/IrToolbar.d.ts.map +1 -1
- package/lib/ir/ui/IrToolbar.js +10 -3
- package/lib/ir/ui/IrToolbar.js.map +1 -1
- package/lib/ir/ui/IrTraces.d.ts +4 -1
- package/lib/ir/ui/IrTraces.d.ts.map +1 -1
- package/lib/ir/ui/IrTraces.js +2 -0
- package/lib/ir/ui/IrTraces.js.map +1 -1
- package/lib/ir/ui/RamanEditor.d.ts +64 -0
- package/lib/ir/ui/RamanEditor.d.ts.map +1 -0
- package/lib/ir/ui/RamanEditor.js +17 -0
- package/lib/ir/ui/RamanEditor.js.map +1 -0
- package/lib/ir/ui/SpectraPanel.d.ts.map +1 -1
- package/lib/ir/ui/SpectraPanel.js +2 -2
- package/lib/ir/ui/SpectraPanel.js.map +1 -1
- package/lib/ir/ui/SpectrumRow.d.ts +7 -0
- package/lib/ir/ui/SpectrumRow.d.ts.map +1 -1
- package/lib/ir/ui/SpectrumRow.js +4 -5
- package/lib/ir/ui/SpectrumRow.js.map +1 -1
- package/lib/ir/ui/VibrationalEditor.d.ts +62 -0
- package/lib/ir/ui/VibrationalEditor.d.ts.map +1 -0
- package/lib/ir/ui/VibrationalEditor.js +33 -0
- package/lib/ir/ui/VibrationalEditor.js.map +1 -0
- package/lib/ir/ui/bandsTsv.d.ts +19 -0
- package/lib/ir/ui/bandsTsv.d.ts.map +1 -0
- package/lib/ir/ui/bandsTsv.js +38 -0
- package/lib/ir/ui/bandsTsv.js.map +1 -0
- package/lib/ir/ui/index.d.ts +1 -0
- package/lib/ir/ui/index.d.ts.map +1 -1
- package/lib/ir/ui/index.js.map +1 -1
- package/lib/ir/ui/irActions.d.ts +3 -3
- package/lib/ir/ui/irActions.d.ts.map +1 -1
- package/lib/ir/ui/irChartProps.d.ts +21 -4
- package/lib/ir/ui/irChartProps.d.ts.map +1 -1
- package/lib/ir/ui/irChartProps.js +3 -2
- package/lib/ir/ui/irChartProps.js.map +1 -1
- package/lib/ir/ui/irCommandContext.d.ts +8 -0
- package/lib/ir/ui/irCommandContext.d.ts.map +1 -1
- package/lib/ir/ui/irCommandContext.js +14 -3
- package/lib/ir/ui/irCommandContext.js.map +1 -1
- package/lib/ir/ui/irHostPanels.d.ts +53 -0
- package/lib/ir/ui/irHostPanels.d.ts.map +1 -0
- package/lib/ir/ui/irHostPanels.js +41 -0
- package/lib/ir/ui/irHostPanels.js.map +1 -0
- package/lib/ir/ui/useIrEditor.d.ts +3 -3
- package/lib/ir/ui/useIrEditor.d.ts.map +1 -1
- package/lib/ir/ui/useIrEditor.js +13 -4
- package/lib/ir/ui/useIrEditor.js.map +1 -1
- package/lib/ir/ui/useIrHandle.d.ts +14 -0
- package/lib/ir/ui/useIrHandle.d.ts.map +1 -0
- package/lib/ir/ui/useIrHandle.js +39 -0
- package/lib/ir/ui/useIrHandle.js.map +1 -0
- package/lib/ir/ui/useIrSide.d.ts +27 -0
- package/lib/ir/ui/useIrSide.d.ts.map +1 -0
- package/lib/ir/ui/useIrSide.js +42 -0
- package/lib/ir/ui/useIrSide.js.map +1 -0
- package/lib/ir/ui/useIrText.d.ts +40 -0
- package/lib/ir/ui/useIrText.d.ts.map +1 -0
- package/lib/ir/ui/useIrText.js +118 -0
- package/lib/ir/ui/useIrText.js.map +1 -0
- package/lib/ir/ui/useIrZoom.d.ts +15 -0
- package/lib/ir/ui/useIrZoom.d.ts.map +1 -1
- package/lib/ir/ui/useIrZoom.js +6 -4
- package/lib/ir/ui/useIrZoom.js.map +1 -1
- package/lib/ir/ui/useValueAxisZoom.d.ts +20 -0
- package/lib/ir/ui/useValueAxisZoom.d.ts.map +1 -0
- package/lib/ir/ui/useValueAxisZoom.js +54 -0
- package/lib/ir/ui/useValueAxisZoom.js.map +1 -0
- package/lib/ir.d.ts +3 -0
- package/lib/ir.d.ts.map +1 -1
- package/lib/ir.js +3 -0
- package/lib/ir.js.map +1 -1
- package/lib/locales/de.json +29 -2
- package/lib/locales/en.json +29 -2
- package/lib/locales/es.json +29 -2
- package/lib/locales/fr.json +29 -2
- package/lib/locales/it.json +29 -2
- package/lib/molecule3d/core/animatedPng.d.ts +25 -0
- package/lib/molecule3d/core/animatedPng.d.ts.map +1 -0
- package/lib/molecule3d/core/animatedPng.js +59 -0
- package/lib/molecule3d/core/animatedPng.js.map +1 -0
- package/lib/molecule3d/core/file.d.ts +24 -0
- package/lib/molecule3d/core/file.d.ts.map +1 -0
- package/lib/molecule3d/core/file.js +2 -0
- package/lib/molecule3d/core/file.js.map +1 -0
- package/lib/molecule3d/core/index.d.ts +4 -1
- package/lib/molecule3d/core/index.d.ts.map +1 -1
- package/lib/molecule3d/core/index.js +1 -0
- package/lib/molecule3d/core/index.js.map +1 -1
- package/lib/molecule3d/core/settings.d.ts +0 -7
- package/lib/molecule3d/core/settings.d.ts.map +1 -1
- package/lib/molecule3d/core/settings.js.map +1 -1
- package/lib/molecule3d/ui/Molecule3DExport.d.ts +10 -2
- package/lib/molecule3d/ui/Molecule3DExport.d.ts.map +1 -1
- package/lib/molecule3d/ui/Molecule3DExport.js +15 -2
- package/lib/molecule3d/ui/Molecule3DExport.js.map +1 -1
- package/lib/molecule3d/ui/Molecule3DToolbar.js +9 -2
- package/lib/molecule3d/ui/Molecule3DToolbar.js.map +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.d.ts.map +1 -1
- package/lib/molecule3d/ui/MoleculeCanvas3D.js +23 -41
- package/lib/molecule3d/ui/MoleculeCanvas3D.js.map +1 -1
- package/lib/molecule3d/ui/drawScene.d.ts +2 -1
- package/lib/molecule3d/ui/drawScene.d.ts.map +1 -1
- package/lib/molecule3d/ui/drawScene.js.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts +15 -1
- package/lib/molecule3d/ui/exportMoleculeImage.d.ts.map +1 -1
- package/lib/molecule3d/ui/exportMoleculeImage.js +14 -2
- package/lib/molecule3d/ui/exportMoleculeImage.js.map +1 -1
- package/lib/molecule3d/ui/moleculeFrames.d.ts +47 -0
- package/lib/molecule3d/ui/moleculeFrames.d.ts.map +1 -0
- package/lib/molecule3d/ui/moleculeFrames.js +65 -0
- package/lib/molecule3d/ui/moleculeFrames.js.map +1 -0
- package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts +14 -1
- package/lib/molecule3d/ui/moleculeViewer3DProps.d.ts.map +1 -1
- package/lib/molecule3d/ui/renderMolecule.d.ts +3 -3
- package/lib/molecule3d/ui/renderMolecule.d.ts.map +1 -1
- package/lib/molecule3d/ui/renderMolecule.js +2 -1
- package/lib/molecule3d/ui/renderMolecule.js.map +1 -1
- package/lib/molecule3d/ui/sceneDrawer.d.ts +2 -1
- package/lib/molecule3d/ui/sceneDrawer.d.ts.map +1 -1
- package/lib/molecule3d/ui/sceneDrawer.js +9 -1
- package/lib/molecule3d/ui/sceneDrawer.js.map +1 -1
- package/lib/molecule3d/ui/useImageExport.d.ts +8 -3
- package/lib/molecule3d/ui/useImageExport.d.ts.map +1 -1
- package/lib/molecule3d/ui/useImageExport.js +13 -4
- package/lib/molecule3d/ui/useImageExport.js.map +1 -1
- package/lib/molecule3d/ui/useMoleculeScene.d.ts +2 -1
- package/lib/molecule3d/ui/useMoleculeScene.d.ts.map +1 -1
- package/lib/molecule3d/ui/useMoleculeScene.js.map +1 -1
- package/lib/molecule3d/ui/useMoleculeViewer.d.ts +16 -0
- package/lib/molecule3d/ui/useMoleculeViewer.d.ts.map +1 -0
- package/lib/molecule3d/ui/useMoleculeViewer.js +37 -0
- package/lib/molecule3d/ui/useMoleculeViewer.js.map +1 -0
- package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts +3 -3
- package/lib/molecule3d/ui/usePolarSurfaceArea.d.ts.map +1 -1
- package/lib/molecule3d/ui/usePolarSurfaceArea.js +4 -3
- package/lib/molecule3d/ui/usePolarSurfaceArea.js.map +1 -1
- package/lib/molecule3d/ui/viewer.d.ts +4 -1
- package/lib/molecule3d/ui/viewer.d.ts.map +1 -1
- package/lib/molecule3d/ui/viewer.js +21 -19
- package/lib/molecule3d/ui/viewer.js.map +1 -1
- package/lib/molecule3d/ui/viewerTypes.d.ts +6 -0
- package/lib/molecule3d/ui/viewerTypes.d.ts.map +1 -1
- package/lib/molstar/core/captureScene.d.ts +19 -1
- package/lib/molstar/core/captureScene.d.ts.map +1 -1
- package/lib/molstar/core/captureScene.js +57 -2
- package/lib/molstar/core/captureScene.js.map +1 -1
- package/lib/molstar/core/index.d.ts +5 -2
- package/lib/molstar/core/index.d.ts.map +1 -1
- package/lib/molstar/core/index.js +4 -2
- package/lib/molstar/core/index.js.map +1 -1
- package/lib/molstar/core/trajectory.d.ts +56 -0
- package/lib/molstar/core/trajectory.d.ts.map +1 -0
- package/lib/molstar/core/trajectory.js +96 -0
- package/lib/molstar/core/trajectory.js.map +1 -0
- package/lib/panel/ui/PanelRail.d.ts.map +1 -1
- package/lib/panel/ui/PanelRail.js +1 -1
- package/lib/panel/ui/PanelRail.js.map +1 -1
- package/lib/raman.d.ts +17 -0
- package/lib/raman.d.ts.map +1 -0
- package/lib/raman.js +12 -0
- package/lib/raman.js.map +1 -0
- package/lib/router/core/basePath.d.ts +2 -2
- package/lib/router/core/basePath.js +2 -2
- package/lib/router/core/siteAddresses.d.ts +1 -1
- package/lib/router/core/siteAddresses.js +1 -1
- package/lib/seo/core/siteFiles.js +1 -1
- package/lib/seo/core/siteFiles.js.map +1 -1
- package/lib/server/answerAddresses.d.ts +3 -3
- package/lib/server/answerAddresses.js +3 -3
- package/lib/structure/core/index.d.ts +2 -0
- package/lib/structure/core/index.d.ts.map +1 -1
- package/lib/structure/core/index.js +1 -0
- package/lib/structure/core/index.js.map +1 -1
- package/lib/structure/core/structureTransfer.d.ts +29 -0
- package/lib/structure/core/structureTransfer.d.ts.map +1 -0
- package/lib/structure/core/structureTransfer.js +26 -0
- package/lib/structure/core/structureTransfer.js.map +1 -0
- package/lib/structure/ui/EditorImportButton.d.ts +20 -0
- package/lib/structure/ui/EditorImportButton.d.ts.map +1 -0
- package/lib/structure/ui/EditorImportButton.js +24 -0
- package/lib/structure/ui/EditorImportButton.js.map +1 -0
- package/lib/structure/ui/EditorImportProblem.d.ts +17 -0
- package/lib/structure/ui/EditorImportProblem.d.ts.map +1 -0
- package/lib/structure/ui/EditorImportProblem.js +32 -0
- package/lib/structure/ui/EditorImportProblem.js.map +1 -0
- package/lib/structure/ui/StructureDrop.d.ts +39 -0
- package/lib/structure/ui/StructureDrop.d.ts.map +1 -0
- package/lib/structure/ui/StructureDrop.js +19 -0
- package/lib/structure/ui/StructureDrop.js.map +1 -0
- package/lib/structure/ui/StructureDropOverlay.d.ts +16 -0
- package/lib/structure/ui/StructureDropOverlay.d.ts.map +1 -0
- package/lib/structure/ui/StructureDropOverlay.js +29 -0
- package/lib/structure/ui/StructureDropOverlay.js.map +1 -0
- package/lib/structure/ui/StructureEditor.d.ts +3 -80
- package/lib/structure/ui/StructureEditor.d.ts.map +1 -1
- package/lib/structure/ui/StructureEditor.js +21 -33
- package/lib/structure/ui/StructureEditor.js.map +1 -1
- package/lib/structure/ui/importedStructure.d.ts +25 -0
- package/lib/structure/ui/importedStructure.d.ts.map +1 -0
- package/lib/structure/ui/importedStructure.js +74 -0
- package/lib/structure/ui/importedStructure.js.map +1 -0
- package/lib/structure/ui/index.d.ts +2 -0
- package/lib/structure/ui/index.d.ts.map +1 -1
- package/lib/structure/ui/index.js +1 -0
- package/lib/structure/ui/index.js.map +1 -1
- package/lib/structure/ui/structureEditorProps.d.ts +98 -0
- package/lib/structure/ui/structureEditorProps.d.ts.map +1 -0
- package/lib/structure/ui/structureEditorProps.js +2 -0
- package/lib/structure/ui/structureEditorProps.js.map +1 -0
- package/lib/structure/ui/useDebouncedChange.d.ts +16 -0
- package/lib/structure/ui/useDebouncedChange.d.ts.map +1 -0
- package/lib/structure/ui/useDebouncedChange.js +30 -0
- package/lib/structure/ui/useDebouncedChange.js.map +1 -0
- package/lib/structure/ui/useStructureDrop.d.ts +30 -0
- package/lib/structure/ui/useStructureDrop.d.ts.map +1 -0
- package/lib/structure/ui/useStructureDrop.js +49 -0
- package/lib/structure/ui/useStructureDrop.js.map +1 -0
- package/lib/structure/ui/useStructureImport.d.ts +45 -0
- package/lib/structure/ui/useStructureImport.d.ts.map +1 -0
- package/lib/structure/ui/useStructureImport.js +62 -0
- package/lib/structure/ui/useStructureImport.js.map +1 -0
- package/package.json +5 -1
- package/src/download/ui/FigureDownloadPanel.tsx +9 -2
- package/src/ecosystem/core/sites.ts +3 -3
- package/src/ecosystem/core/types.ts +1 -1
- package/src/ecosystem/ui/glyphs.tsx +1 -1
- package/src/i18n/core/messageCatalog.ts +2 -2
- package/src/i18n/vite/localeCatalog.ts +1 -1
- package/src/ir/core/analysisSpectra.ts +26 -10
- package/src/ir/core/bandLabelPlan.ts +21 -10
- package/src/ir/core/index.ts +31 -7
- package/src/ir/core/irBand.ts +52 -14
- package/src/ir/core/irCommands.ts +15 -1
- package/src/ir/core/irDomain.ts +9 -7
- package/src/ir/core/irEditorApi.ts +13 -0
- package/src/ir/core/irFormat.ts +39 -6
- package/src/ir/core/irMode.ts +42 -10
- package/src/ir/core/irReducer.ts +3 -51
- package/src/ir/core/irSidePanels.ts +8 -1
- package/src/ir/core/irSpectrum.ts +59 -30
- package/src/ir/core/irState.ts +73 -5
- package/src/ir/core/irTechnique.ts +115 -0
- package/src/ir/core/irTechniqueCommands.ts +82 -0
- package/src/ir/core/pickBands.ts +63 -28
- package/src/ir/core/ramanBands.ts +105 -0
- package/src/ir/core/spectrumJcamp.ts +65 -16
- package/src/ir/core/toIrSpectrum.ts +20 -2
- package/src/ir/ui/BandRow.tsx +107 -0
- package/src/ir/ui/BandsPanel.tsx +32 -125
- package/src/ir/ui/IrAboutDialog.tsx +69 -28
- package/src/ir/ui/IrCanvas.tsx +29 -3
- package/src/ir/ui/IrChart.tsx +31 -24
- package/src/ir/ui/IrCommandProvider.tsx +10 -3
- package/src/ir/ui/IrCommandTooltip.tsx +11 -2
- package/src/ir/ui/IrDocumentationDialog.tsx +99 -55
- package/src/ir/ui/IrEditor.tsx +27 -40
- package/src/ir/ui/IrHeader.tsx +10 -3
- package/src/ir/ui/IrLogo.tsx +28 -9
- package/src/ir/ui/IrShell.tsx +47 -96
- package/src/ir/ui/IrSidePanel.tsx +36 -10
- package/src/ir/ui/IrStatusBar.tsx +17 -12
- package/src/ir/ui/IrToolbar.tsx +26 -15
- package/src/ir/ui/IrTraces.tsx +5 -1
- package/src/ir/ui/RamanEditor.tsx +71 -0
- package/src/ir/ui/SpectraPanel.tsx +2 -1
- package/src/ir/ui/SpectrumRow.tsx +14 -5
- package/src/ir/ui/VibrationalEditor.tsx +113 -0
- package/src/ir/ui/bandsTsv.ts +46 -0
- package/src/ir/ui/index.ts +1 -0
- package/src/ir/ui/irActions.ts +3 -3
- package/src/ir/ui/irChartProps.ts +21 -4
- package/src/ir/ui/irCommandContext.tsx +18 -3
- package/src/ir/ui/irHostPanels.ts +76 -0
- package/src/ir/ui/useIrEditor.ts +20 -8
- package/src/ir/ui/useIrHandle.ts +51 -0
- package/src/ir/ui/useIrSide.ts +60 -0
- package/src/ir/ui/useIrText.ts +170 -0
- package/src/ir/ui/useIrZoom.ts +22 -3
- package/src/ir/ui/useValueAxisZoom.ts +67 -0
- package/src/ir.ts +3 -0
- package/src/locales/de.json +29 -2
- package/src/locales/en.json +29 -2
- package/src/locales/es.json +29 -2
- package/src/locales/fr.json +29 -2
- package/src/locales/it.json +29 -2
- package/src/molecule3d/core/animatedPng.ts +79 -0
- package/src/molecule3d/core/file.ts +23 -0
- package/src/molecule3d/core/index.ts +3 -1
- package/src/molecule3d/core/settings.ts +0 -8
- package/src/molecule3d/ui/Molecule3DExport.tsx +43 -5
- package/src/molecule3d/ui/Molecule3DToolbar.tsx +9 -2
- package/src/molecule3d/ui/MoleculeCanvas3D.tsx +24 -38
- package/src/molecule3d/ui/drawScene.ts +2 -1
- package/src/molecule3d/ui/exportMoleculeImage.ts +28 -3
- package/src/molecule3d/ui/moleculeFrames.ts +88 -0
- package/src/molecule3d/ui/moleculeViewer3DProps.ts +14 -5
- package/src/molecule3d/ui/renderMolecule.ts +5 -3
- package/src/molecule3d/ui/sceneDrawer.ts +14 -2
- package/src/molecule3d/ui/useImageExport.ts +22 -5
- package/src/molecule3d/ui/useMoleculeScene.ts +2 -1
- package/src/molecule3d/ui/useMoleculeViewer.ts +46 -0
- package/src/molecule3d/ui/usePolarSurfaceArea.ts +6 -4
- package/src/molecule3d/ui/viewer.ts +34 -27
- package/src/molecule3d/ui/viewerTypes.ts +6 -0
- package/src/molstar/core/captureScene.ts +85 -2
- package/src/molstar/core/index.ts +13 -2
- package/src/molstar/core/trajectory.ts +117 -0
- package/src/panel/ui/PanelRail.tsx +3 -0
- package/src/raman.ts +20 -0
- package/src/router/core/basePath.ts +2 -2
- package/src/router/core/siteAddresses.ts +1 -1
- package/src/seo/core/siteFiles.ts +1 -1
- package/src/server/answerAddresses.ts +3 -3
- package/src/structure/core/index.ts +8 -0
- package/src/structure/core/structureTransfer.ts +37 -0
- package/src/structure/ui/EditorImportButton.tsx +59 -0
- package/src/structure/ui/EditorImportProblem.tsx +63 -0
- package/src/structure/ui/StructureDrop.tsx +66 -0
- package/src/structure/ui/StructureDropOverlay.tsx +50 -0
- package/src/structure/ui/StructureEditor.tsx +49 -134
- package/src/structure/ui/importedStructure.ts +83 -0
- package/src/structure/ui/index.ts +2 -0
- package/src/structure/ui/structureEditorProps.ts +103 -0
- package/src/structure/ui/useDebouncedChange.ts +41 -0
- package/src/structure/ui/useStructureDrop.ts +76 -0
- package/src/structure/ui/useStructureImport.ts +122 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Frames of a scene as one animated PNG, which loops forever.
|
|
3
|
+
*
|
|
4
|
+
* An APNG is a PNG whose frames every browser plays, and whose first frame
|
|
5
|
+
* any program that does not play them still shows. It keeps every colour of a
|
|
6
|
+
* shaded molecule, which a GIF's 256 cannot.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type * as Upng from '@pdf-lib/upng';
|
|
10
|
+
|
|
11
|
+
/** How many frames a second are played, and saved, when nobody says. */
|
|
12
|
+
export const DEFAULT_FRAMES_PER_SECOND = 25;
|
|
13
|
+
|
|
14
|
+
/** One frame: its pixels as RGBA bytes, row by row from the top. */
|
|
15
|
+
export interface RgbaFrame {
|
|
16
|
+
width: number;
|
|
17
|
+
height: number;
|
|
18
|
+
data: Uint8ClampedArray | Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Encode frames as one animated PNG, every frame shown for the same time, the
|
|
23
|
+
* whole looping forever. The encoder is loaded on first use.
|
|
24
|
+
* @param frames - The frames, in order, all the same size.
|
|
25
|
+
* @param framesPerSecond - How many are shown per second.
|
|
26
|
+
* @returns The PNG file.
|
|
27
|
+
* @throws {Error} When there is no frame, or the frames differ in size.
|
|
28
|
+
*/
|
|
29
|
+
export async function encodeAnimatedPng(
|
|
30
|
+
frames: readonly RgbaFrame[],
|
|
31
|
+
framesPerSecond: number,
|
|
32
|
+
): Promise<Uint8Array<ArrayBuffer>> {
|
|
33
|
+
const first = frames[0];
|
|
34
|
+
if (first === undefined) throw new Error('There is no frame to encode.');
|
|
35
|
+
const { width, height } = first;
|
|
36
|
+
const buffers: ArrayBuffer[] = [];
|
|
37
|
+
const delays: number[] = [];
|
|
38
|
+
const delay = Math.max(1, Math.round(1000 / framesPerSecond));
|
|
39
|
+
for (const frame of frames) {
|
|
40
|
+
if (frame.width !== width || frame.height !== height) {
|
|
41
|
+
throw new Error('Every frame of an animated PNG must be the same size.');
|
|
42
|
+
}
|
|
43
|
+
buffers.push(rgbaBuffer(frame));
|
|
44
|
+
delays.push(delay);
|
|
45
|
+
}
|
|
46
|
+
const upng = await loadEncoder();
|
|
47
|
+
// 0 colours: lossless.
|
|
48
|
+
return new Uint8Array(upng.encode(buffers, width, height, 0, delays));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The bytes of a frame in an ArrayBuffer of their own size, which the encoder
|
|
53
|
+
* reads whole.
|
|
54
|
+
* @param frame - The frame.
|
|
55
|
+
* @returns Its RGBA bytes.
|
|
56
|
+
*/
|
|
57
|
+
function rgbaBuffer(frame: RgbaFrame): ArrayBuffer {
|
|
58
|
+
const { data } = frame;
|
|
59
|
+
const { buffer, byteOffset, byteLength } = data;
|
|
60
|
+
if (
|
|
61
|
+
buffer instanceof ArrayBuffer &&
|
|
62
|
+
byteOffset === 0 &&
|
|
63
|
+
byteLength === buffer.byteLength
|
|
64
|
+
) {
|
|
65
|
+
return buffer;
|
|
66
|
+
}
|
|
67
|
+
return new Uint8Array(data).buffer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type Encoder = Pick<typeof Upng, 'encode'>;
|
|
71
|
+
|
|
72
|
+
async function loadEncoder(): Promise<Encoder> {
|
|
73
|
+
const { default: loaded } = (await import('@pdf-lib/upng')) as {
|
|
74
|
+
default: Encoder | { default: Encoder };
|
|
75
|
+
};
|
|
76
|
+
// A bundler hands the ES build's one default object; Node's own import hands
|
|
77
|
+
// the exports of the CommonJS build, whose default is that object.
|
|
78
|
+
return 'encode' in loaded ? loaded : loaded.default;
|
|
79
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A molfile for the viewer, with the parser molstar has to read it with.
|
|
3
|
+
*
|
|
4
|
+
* A file of several models — an SDF of several records, an XYZ of several
|
|
5
|
+
* frames — is a series of frames of one molecule, which the viewer can play
|
|
6
|
+
* and export as an animated PNG.
|
|
7
|
+
*/
|
|
8
|
+
export interface Molecule3DFile {
|
|
9
|
+
/**
|
|
10
|
+
* molstar's format id: `mol` reads V2000, `sdf` reads V2000 and V3000, `xyz`
|
|
11
|
+
* reads bare coordinates and infers the bonds from the distances.
|
|
12
|
+
*/
|
|
13
|
+
format: 'mol' | 'sdf' | 'xyz';
|
|
14
|
+
/** The file text. It must carry 3D coordinates. */
|
|
15
|
+
data: string;
|
|
16
|
+
/**
|
|
17
|
+
* Names the molecule the file draws, when several files draw one — one per
|
|
18
|
+
* normal mode, say. Replacing a file by another of the same name keeps the
|
|
19
|
+
* camera where the reader left it, instead of framing a new molecule.
|
|
20
|
+
* @default undefined — every other file is another molecule
|
|
21
|
+
*/
|
|
22
|
+
moleculeId?: string;
|
|
23
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export type { RgbaFrame } from './animatedPng.ts';
|
|
2
|
+
export { DEFAULT_FRAMES_PER_SECOND, encodeAnimatedPng } from './animatedPng.ts';
|
|
1
3
|
export type {
|
|
2
4
|
Molecule3DCamera,
|
|
3
5
|
Molecule3DRotation,
|
|
@@ -33,8 +35,8 @@ export {
|
|
|
33
35
|
MEASUREMENT_LABELS,
|
|
34
36
|
sameMeasurements,
|
|
35
37
|
} from './measurement.ts';
|
|
38
|
+
export type { Molecule3DFile } from './file.ts';
|
|
36
39
|
export type {
|
|
37
|
-
Molecule3DFile,
|
|
38
40
|
Molecule3DSettings,
|
|
39
41
|
Molecule3DTools,
|
|
40
42
|
RepresentationId,
|
|
@@ -3,14 +3,6 @@
|
|
|
3
3
|
* free of React and molstar so a site can persist and validate them.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
/** A molfile for the viewer, with the parser molstar has to read it with. */
|
|
7
|
-
export interface Molecule3DFile {
|
|
8
|
-
/** molstar's format id: `mol` reads V2000, `sdf` reads V2000 and V3000. */
|
|
9
|
-
format: 'mol' | 'sdf';
|
|
10
|
-
/** The molfile text. It must carry 3D coordinates. */
|
|
11
|
-
data: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
/** Ways the model can be drawn, in the order the picker offers them. */
|
|
15
7
|
export const REPRESENTATIONS = [
|
|
16
8
|
'ball-and-stick',
|
|
@@ -16,15 +16,28 @@ import {
|
|
|
16
16
|
import { FigureDownloadPanel } from '../../download/ui/FigureDownloadPanel.tsx';
|
|
17
17
|
import { useFigureTask } from '../../download/ui/useFigureTask.ts';
|
|
18
18
|
import { useChromeT } from '../../i18n/ui/useT.ts';
|
|
19
|
+
import { OverlaySegmented } from '../../overlay/ui/OverlaySegmented.tsx';
|
|
19
20
|
|
|
20
21
|
/** Props of {@link Molecule3DExport}. */
|
|
21
22
|
export interface Molecule3DExportProps {
|
|
22
23
|
/** Reads the size of the canvas on screen, when the popover opens. */
|
|
23
24
|
getSize: () => FigurePixels | null;
|
|
24
|
-
/**
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Writes the file: every frame, as an animated PNG, when `animated` is set.
|
|
27
|
+
*/
|
|
28
|
+
onExport: (
|
|
29
|
+
format: FigureFormat,
|
|
30
|
+
scale: number,
|
|
31
|
+
animated: boolean,
|
|
32
|
+
) => Promise<void>;
|
|
26
33
|
/** Puts a PNG at that scale on the clipboard, and says what came of it. */
|
|
27
34
|
onCopy: (scale: number) => Promise<FigureNotice>;
|
|
35
|
+
/**
|
|
36
|
+
* How many frames the scene holds. Above one, a PNG may hold them all, as an
|
|
37
|
+
* animation.
|
|
38
|
+
* @default 1
|
|
39
|
+
*/
|
|
40
|
+
frameCount?: number;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
/**
|
|
@@ -33,11 +46,14 @@ export interface Molecule3DExportProps {
|
|
|
33
46
|
* @returns The panel.
|
|
34
47
|
*/
|
|
35
48
|
export function Molecule3DExport(props: Molecule3DExportProps): ReactElement {
|
|
36
|
-
const { getSize, onExport, onCopy } = props;
|
|
49
|
+
const { getSize, onExport, onCopy, frameCount = 1 } = props;
|
|
37
50
|
const t = useChromeT();
|
|
38
51
|
const [size] = useState(getSize);
|
|
39
52
|
const [format, setFormat] = useState<FigureFormat>('png');
|
|
40
53
|
const [scale, setScale] = useState(DEFAULT_FIGURE_SCALE);
|
|
54
|
+
const [frames, setFrames] = useState<FrameChoice>('all');
|
|
55
|
+
const offerFrames = frameCount > 1 && format === 'png';
|
|
56
|
+
const animated = offerFrames && frames === 'all';
|
|
41
57
|
const { run, busy, failure, notice, clear } = useFigureTask();
|
|
42
58
|
|
|
43
59
|
// What the last copy came to only describes the choices it was made with.
|
|
@@ -61,8 +77,30 @@ export function Molecule3DExport(props: Molecule3DExportProps): ReactElement {
|
|
|
61
77
|
rasterSvg
|
|
62
78
|
onFormatChange={changed(setFormat)}
|
|
63
79
|
onScaleChange={changed(setScale)}
|
|
64
|
-
onSave={() => run(onExport(format, scale).then(() => null))}
|
|
80
|
+
onSave={() => run(onExport(format, scale, animated).then(() => null))}
|
|
65
81
|
onCopy={() => run(onCopy(scale))}
|
|
66
|
-
|
|
82
|
+
>
|
|
83
|
+
{offerFrames && (
|
|
84
|
+
<OverlaySegmented<FrameChoice>
|
|
85
|
+
label={t('molecule3d.frames')}
|
|
86
|
+
help={{
|
|
87
|
+
title: t('molecule3d.frames'),
|
|
88
|
+
body: t('molecule3d.framesHelp'),
|
|
89
|
+
}}
|
|
90
|
+
value={frames}
|
|
91
|
+
options={[
|
|
92
|
+
{ value: 'one', label: t('molecule3d.frames.one') },
|
|
93
|
+
{
|
|
94
|
+
value: 'all',
|
|
95
|
+
label: t('molecule3d.frames.all', { count: frameCount }),
|
|
96
|
+
},
|
|
97
|
+
]}
|
|
98
|
+
onChange={changed(setFrames)}
|
|
99
|
+
/>
|
|
100
|
+
)}
|
|
101
|
+
</FigureDownloadPanel>
|
|
67
102
|
);
|
|
68
103
|
}
|
|
104
|
+
|
|
105
|
+
/** The frame on screen, or every frame as an animated PNG. */
|
|
106
|
+
type FrameChoice = 'one' | 'all';
|
|
@@ -225,11 +225,18 @@ export function Molecule3DToolbar(props: Molecule3DToolbarProps): ReactElement {
|
|
|
225
225
|
|
|
226
226
|
const TOOLTIP_PROPS = { placement: 'right' } as const;
|
|
227
227
|
|
|
228
|
+
// A canvas too short for both cards puts the second one beside the first,
|
|
229
|
+
// rather than cutting it off; the column itself lets clicks through to the
|
|
230
|
+
// canvas between and below the cards.
|
|
228
231
|
const COLUMN_STYLE: CSSProperties = {
|
|
229
232
|
display: 'flex',
|
|
230
233
|
flexDirection: 'column',
|
|
234
|
+
flexWrap: 'wrap',
|
|
235
|
+
alignContent: 'flex-start',
|
|
236
|
+
alignItems: 'flex-start',
|
|
231
237
|
gap: 6,
|
|
232
|
-
|
|
238
|
+
height: '100%',
|
|
239
|
+
pointerEvents: 'none',
|
|
233
240
|
};
|
|
234
241
|
|
|
235
|
-
const CARD_STYLE: CSSProperties = { padding: 0 };
|
|
242
|
+
const CARD_STYLE: CSSProperties = { padding: 0, pointerEvents: 'auto' };
|
|
@@ -10,6 +10,7 @@ import type { CSSProperties, ReactElement } from 'react';
|
|
|
10
10
|
import { useEffect, useRef, useState } from 'react';
|
|
11
11
|
|
|
12
12
|
import { DEFAULT_SPIN_SPEED } from '../../molstar/core/index.ts';
|
|
13
|
+
import { DEFAULT_FRAMES_PER_SECOND } from '../core/animatedPng.ts';
|
|
13
14
|
import type { Molecule3DHighlight } from '../core/highlight.ts';
|
|
14
15
|
import type { Measurement, MeasurementKind } from '../core/measurement.ts';
|
|
15
16
|
import {
|
|
@@ -21,14 +22,13 @@ import { Molecule3DExport } from './Molecule3DExport.tsx';
|
|
|
21
22
|
import { Molecule3DOptions } from './Molecule3DOptions.tsx';
|
|
22
23
|
import { Molecule3DStage } from './Molecule3DStage.tsx';
|
|
23
24
|
import { Molecule3DToolbar } from './Molecule3DToolbar.tsx';
|
|
24
|
-
import { createMolecule3DViewer } from './createViewer.ts';
|
|
25
25
|
import { highlightColorOf } from './highlightColor.ts';
|
|
26
26
|
import type { MoleculeViewer3DProps } from './moleculeViewer3DProps.ts';
|
|
27
27
|
import { useControlledState } from './useControlledState.ts';
|
|
28
28
|
import { useImageExport } from './useImageExport.ts';
|
|
29
29
|
import { useMoleculeScene } from './useMoleculeScene.ts';
|
|
30
|
+
import { useMoleculeViewer } from './useMoleculeViewer.ts';
|
|
30
31
|
import { usePolarSurfaceArea } from './usePolarSurfaceArea.ts';
|
|
31
|
-
import type { Molecule3DViewer } from './viewer.ts';
|
|
32
32
|
|
|
33
33
|
/** Props of {@link MoleculeCanvas3D}. */
|
|
34
34
|
export interface MoleculeCanvas3DProps extends Omit<
|
|
@@ -56,6 +56,8 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
56
56
|
defaultSpinning = false,
|
|
57
57
|
onSpinningChange,
|
|
58
58
|
spinSpeed = DEFAULT_SPIN_SPEED,
|
|
59
|
+
playing = false,
|
|
60
|
+
framesPerSecond = DEFAULT_FRAMES_PER_SECOND,
|
|
59
61
|
measurements: measurementsProp,
|
|
60
62
|
onMeasurementsChange,
|
|
61
63
|
highlights = NO_HIGHLIGHTS,
|
|
@@ -82,6 +84,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
82
84
|
readonly Measurement[]
|
|
83
85
|
>(measurementsProp, NO_MEASUREMENTS, onMeasurementsChange);
|
|
84
86
|
const [measureKind, setMeasureKind] = useState<MeasurementKind | null>(null);
|
|
87
|
+
const [frameCount, setFrameCount] = useState(0);
|
|
85
88
|
const polarSurfaceArea = usePolarSurfaceArea(
|
|
86
89
|
molfile,
|
|
87
90
|
settings.surfaceColoring === 'polarity',
|
|
@@ -90,51 +93,31 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
90
93
|
// A callback ref: the element arriving is what creates the viewer, and every
|
|
91
94
|
// effect keyed on it runs again, in order, after the viewer exists.
|
|
92
95
|
const [container, setContainer] = useState<HTMLDivElement | null>(null);
|
|
93
|
-
const viewerRef = useRef<Molecule3DViewer | null>(null);
|
|
94
96
|
// The viewer is created once, so what its callbacks read is kept fresh here.
|
|
95
|
-
const latest = useRef({
|
|
96
|
-
measurements,
|
|
97
|
-
setMeasurements,
|
|
98
|
-
onFailureChange,
|
|
99
|
-
background,
|
|
100
|
-
});
|
|
97
|
+
const latest = useRef({ measurements, setMeasurements });
|
|
101
98
|
useEffect(() => {
|
|
102
|
-
latest.current = {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
99
|
+
latest.current = { measurements, setMeasurements };
|
|
100
|
+
});
|
|
101
|
+
const viewerRef = useMoleculeViewer(container, {
|
|
102
|
+
background,
|
|
103
|
+
onMeasure: (measurement) => {
|
|
104
|
+
const current = latest.current;
|
|
105
|
+
current.setMeasurements([...current.measurements, measurement]);
|
|
106
|
+
},
|
|
107
|
+
onFrameCountChange: setFrameCount,
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
useEffect(() => {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
background: latest.current.background,
|
|
114
|
-
onMeasure: (measurement) => {
|
|
115
|
-
const current = latest.current;
|
|
116
|
-
current.setMeasurements([...current.measurements, measurement]);
|
|
117
|
-
},
|
|
118
|
-
});
|
|
119
|
-
viewerRef.current = viewer;
|
|
120
|
-
const observer = new ResizeObserver(() => {
|
|
121
|
-
viewer.handleResize();
|
|
122
|
-
});
|
|
123
|
-
observer.observe(container);
|
|
124
|
-
return () => {
|
|
125
|
-
observer.disconnect();
|
|
126
|
-
viewerRef.current = null;
|
|
127
|
-
viewer.dispose();
|
|
128
|
-
};
|
|
129
|
-
}, [container]);
|
|
111
|
+
void viewerRef.current?.setSpin(spinning, spinSpeed);
|
|
112
|
+
}, [container, viewerRef, spinning, spinSpeed]);
|
|
130
113
|
|
|
131
114
|
useEffect(() => {
|
|
132
|
-
void viewerRef.current?.
|
|
133
|
-
}, [container,
|
|
115
|
+
void viewerRef.current?.frames.play(playing, framesPerSecond);
|
|
116
|
+
}, [container, viewerRef, playing, framesPerSecond]);
|
|
134
117
|
|
|
135
118
|
useEffect(() => {
|
|
136
119
|
void viewerRef.current?.setMeasureKind(measureKind);
|
|
137
|
-
}, [container, measureKind]);
|
|
120
|
+
}, [container, viewerRef, measureKind]);
|
|
138
121
|
|
|
139
122
|
// Kept out of the scene: a new highlight repaints the model, never redraws it.
|
|
140
123
|
useEffect(() => {
|
|
@@ -142,7 +125,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
142
125
|
highlights,
|
|
143
126
|
highlightColorOf(container),
|
|
144
127
|
);
|
|
145
|
-
}, [container, highlights]);
|
|
128
|
+
}, [container, viewerRef, highlights]);
|
|
146
129
|
|
|
147
130
|
const { resetView } = useMoleculeScene({
|
|
148
131
|
container,
|
|
@@ -160,6 +143,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
160
143
|
container,
|
|
161
144
|
viewerRef,
|
|
162
145
|
fileName,
|
|
146
|
+
framesPerSecond,
|
|
163
147
|
);
|
|
164
148
|
|
|
165
149
|
return (
|
|
@@ -202,6 +186,7 @@ export function MoleculeCanvas3D(props: MoleculeCanvas3DProps): ReactElement {
|
|
|
202
186
|
getSize={canvasSize}
|
|
203
187
|
onExport={exportImage}
|
|
204
188
|
onCopy={copyImage}
|
|
189
|
+
frameCount={frameCount}
|
|
205
190
|
/>
|
|
206
191
|
}
|
|
207
192
|
/>
|
|
@@ -231,6 +216,7 @@ const CANVAS_STYLE: CSSProperties = { position: 'absolute', inset: 0 };
|
|
|
231
216
|
const OVERLAY_STYLE: CSSProperties = {
|
|
232
217
|
position: 'absolute',
|
|
233
218
|
top: 8,
|
|
219
|
+
bottom: 8,
|
|
234
220
|
left: 8,
|
|
235
221
|
zIndex: 2,
|
|
236
222
|
display: 'flex',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { Molecule3DFile } from '../core/file.ts';
|
|
1
2
|
import type { Measurement } from '../core/measurement.ts';
|
|
2
|
-
import type {
|
|
3
|
+
import type { Molecule3DSettings } from '../core/settings.ts';
|
|
3
4
|
import { normalizeMolecule3DSettings } from '../core/settings.ts';
|
|
4
5
|
|
|
5
6
|
import type { Molecule3DViewer } from './viewer.ts';
|
|
@@ -4,13 +4,22 @@ import { FIGURE_PNG_TYPE } from '../../download/core/figurePng.ts';
|
|
|
4
4
|
import { figurePixels } from '../../download/core/figureScale.ts';
|
|
5
5
|
import { FIGURE_SVG_TYPE } from '../../download/core/figureSvg.ts';
|
|
6
6
|
import { sanitizeFileName } from '../../download/core/sanitizeFileName.ts';
|
|
7
|
+
import { encodeAnimatedPng } from '../core/animatedPng.ts';
|
|
7
8
|
import type { ImageSize } from '../core/exportImage.ts';
|
|
8
9
|
import { dataUriBytes, rasterSvgMarkup } from '../core/exportImage.ts';
|
|
9
10
|
|
|
10
|
-
/**
|
|
11
|
+
/** What an export asks of a viewer: a picture of its scene. */
|
|
11
12
|
export interface SceneCapture {
|
|
12
13
|
/** Render the scene at that pixel size, as a `data:` URI. */
|
|
13
14
|
captureImage: (size: ImageSize) => Promise<string | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* The frames of the scene, each rendered at that pixel size, for an animated
|
|
17
|
+
* PNG.
|
|
18
|
+
* @default undefined — the viewer has a single frame to give
|
|
19
|
+
*/
|
|
20
|
+
frames?: {
|
|
21
|
+
capture: (size: ImageSize) => Promise<ImageData[] | undefined>;
|
|
22
|
+
};
|
|
14
23
|
}
|
|
15
24
|
|
|
16
25
|
/** What {@link exportMoleculeImage} writes. */
|
|
@@ -22,6 +31,12 @@ export interface MoleculeImageRequest {
|
|
|
22
31
|
size: ImageSize;
|
|
23
32
|
/** File name without its extension. */
|
|
24
33
|
fileName: string;
|
|
34
|
+
/**
|
|
35
|
+
* Every frame of the scene as one animated PNG, played at this many frames a
|
|
36
|
+
* second, rather than the frame on screen. Ignored for an SVG.
|
|
37
|
+
* @default undefined — the frame on screen
|
|
38
|
+
*/
|
|
39
|
+
framesPerSecond?: number;
|
|
25
40
|
}
|
|
26
41
|
|
|
27
42
|
/**
|
|
@@ -54,11 +69,21 @@ export async function exportMoleculeImage(
|
|
|
54
69
|
viewer: SceneCapture,
|
|
55
70
|
request: MoleculeImageRequest,
|
|
56
71
|
): Promise<void> {
|
|
57
|
-
const { format, scale, size, fileName } = request;
|
|
72
|
+
const { format, scale, size, fileName, framesPerSecond } = request;
|
|
58
73
|
const pixels = figurePixels(size, scale);
|
|
74
|
+
const base = sanitizeFileName(fileName, 'molecule');
|
|
75
|
+
if (format === 'png' && framesPerSecond !== undefined) {
|
|
76
|
+
if (viewer.frames === undefined) {
|
|
77
|
+
throw new Error('This viewer has no frames to animate.');
|
|
78
|
+
}
|
|
79
|
+
const frames = await viewer.frames.capture(pixels);
|
|
80
|
+
if (frames === undefined) return;
|
|
81
|
+
const bytes = await encodeAnimatedPng(frames, framesPerSecond);
|
|
82
|
+
downloadBlob(new Blob([bytes], { type: FIGURE_PNG_TYPE }), `${base}.png`);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
59
85
|
const dataUri = await viewer.captureImage(pixels);
|
|
60
86
|
if (dataUri === undefined) return;
|
|
61
|
-
const base = sanitizeFileName(fileName, 'molecule');
|
|
62
87
|
if (format === 'png') {
|
|
63
88
|
downloadBlob(
|
|
64
89
|
new Blob([dataUriBytes(dataUri)], { type: FIGURE_PNG_TYPE }),
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The frames of the file a viewer shows: how many there are, whether they
|
|
3
|
+
* play, and a picture of each.
|
|
4
|
+
*
|
|
5
|
+
* Kept apart from the viewer because every redraw of the scene has to go
|
|
6
|
+
* through it: a running animation must not step a state tree being rebuilt —
|
|
7
|
+
* it finds no model and stops itself — so the frames are stopped first and
|
|
8
|
+
* started again once the new file is drawn.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { PluginContext } from 'molstar/lib/mol-plugin/context.js';
|
|
12
|
+
|
|
13
|
+
import type { FramePlayback, MolstarPlugin } from '../../molstar/core/index.ts';
|
|
14
|
+
import {
|
|
15
|
+
captureFrames,
|
|
16
|
+
setTrajectoryPlayback,
|
|
17
|
+
stopTrajectory,
|
|
18
|
+
} from '../../molstar/core/index.ts';
|
|
19
|
+
import { DEFAULT_FRAMES_PER_SECOND } from '../core/animatedPng.ts';
|
|
20
|
+
import type { ImageSize } from '../core/exportImage.ts';
|
|
21
|
+
|
|
22
|
+
/** The frames of what one viewer shows. */
|
|
23
|
+
export class MoleculeFrames {
|
|
24
|
+
readonly #plugin: MolstarPlugin;
|
|
25
|
+
readonly #onCountChange: (frameCount: number) => void;
|
|
26
|
+
// Kept across redraws, so the next file plays as the last one did.
|
|
27
|
+
#playback: FramePlayback = {
|
|
28
|
+
playing: false,
|
|
29
|
+
framesPerSecond: DEFAULT_FRAMES_PER_SECOND,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Follow the frames of what `plugin` draws.
|
|
34
|
+
* @param plugin - The canvas.
|
|
35
|
+
* @param onCountChange - Called with how many frames each scene drawn holds.
|
|
36
|
+
*/
|
|
37
|
+
constructor(
|
|
38
|
+
plugin: MolstarPlugin,
|
|
39
|
+
onCountChange: (frameCount: number) => void,
|
|
40
|
+
) {
|
|
41
|
+
this.#plugin = plugin;
|
|
42
|
+
this.#onCountChange = onCountChange;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Redraw the scene with the frames stopped, then report how many the new
|
|
47
|
+
* scene holds and play them if playback is on.
|
|
48
|
+
* @param plugin - The molstar context.
|
|
49
|
+
* @param draw - Draws the scene, and resolves with how many frames it holds.
|
|
50
|
+
* @returns Nothing; resolves once the scene is drawn and playing.
|
|
51
|
+
*/
|
|
52
|
+
async redraw(
|
|
53
|
+
plugin: PluginContext,
|
|
54
|
+
draw: () => Promise<number>,
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
await stopTrajectory(plugin);
|
|
57
|
+
this.#onCountChange(await draw());
|
|
58
|
+
const { playing, framesPerSecond } = this.#playback;
|
|
59
|
+
await setTrajectoryPlayback(plugin, playing, framesPerSecond);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Play the frames in a loop, or stop them, now and for every scene drawn
|
|
64
|
+
* afterwards. A scene of one frame stays still.
|
|
65
|
+
* @param playing - Whether to play.
|
|
66
|
+
* @param framesPerSecond - How fast.
|
|
67
|
+
* @returns Nothing; resolves once the animation is started or stopped.
|
|
68
|
+
*/
|
|
69
|
+
play(playing: boolean, framesPerSecond: number): Promise<void> {
|
|
70
|
+
this.#playback = { playing, framesPerSecond };
|
|
71
|
+
return this.#plugin.run((plugin) =>
|
|
72
|
+
setTrajectoryPlayback(plugin, playing, framesPerSecond),
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Render every frame off screen, as a still picture of the scene is
|
|
78
|
+
* rendered. Playback pauses while they are taken.
|
|
79
|
+
* @param size - Pixel size of each picture.
|
|
80
|
+
* @returns The pictures, in order; `undefined` once the canvas is disposed.
|
|
81
|
+
* @throws {Error} When the plugin has no screenshot helper.
|
|
82
|
+
*/
|
|
83
|
+
capture(size: ImageSize): Promise<ImageData[] | undefined> {
|
|
84
|
+
return this.#plugin.run((plugin) =>
|
|
85
|
+
captureFrames(plugin, size, this.#playback),
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -2,13 +2,10 @@ import type { ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import type { ViewerCapability } from '../../orbital/ui/capability.ts';
|
|
4
4
|
import type { Molecule3DCamera } from '../core/camera.ts';
|
|
5
|
+
import type { Molecule3DFile } from '../core/file.ts';
|
|
5
6
|
import type { Molecule3DHighlight } from '../core/highlight.ts';
|
|
6
7
|
import type { Measurement } from '../core/measurement.ts';
|
|
7
|
-
import type {
|
|
8
|
-
Molecule3DFile,
|
|
9
|
-
Molecule3DSettings,
|
|
10
|
-
Molecule3DTools,
|
|
11
|
-
} from '../core/settings.ts';
|
|
8
|
+
import type { Molecule3DSettings, Molecule3DTools } from '../core/settings.ts';
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
11
|
* Props of `MoleculeViewer3D`.
|
|
@@ -69,6 +66,18 @@ export interface MoleculeViewer3DProps {
|
|
|
69
66
|
* @default 1 / 3
|
|
70
67
|
*/
|
|
71
68
|
spinSpeed?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Whether the frames of a file holding several are played in a loop. A file
|
|
71
|
+
* of one model stays still whatever this says.
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
playing?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* How many frames are shown per second while playing, and in an animated
|
|
77
|
+
* PNG; molstar plays between 5 and 60.
|
|
78
|
+
* @default 25
|
|
79
|
+
*/
|
|
80
|
+
framesPerSecond?: number;
|
|
72
81
|
/**
|
|
73
82
|
* The measurements drawn over the model, when the site owns them. They name
|
|
74
83
|
* atoms by position, so they carry over to another conformer of the same
|
|
@@ -15,7 +15,8 @@ import { StructureFromModel } from 'molstar/lib/mol-plugin-state/transforms/mode
|
|
|
15
15
|
import { StructureRepresentation3D } from 'molstar/lib/mol-plugin-state/transforms/representation.js';
|
|
16
16
|
import type { StateTransformer } from 'molstar/lib/mol-state/index.js';
|
|
17
17
|
|
|
18
|
-
import type { Molecule3DFile
|
|
18
|
+
import type { Molecule3DFile } from '../core/file.ts';
|
|
19
|
+
import type { RepresentationId } from '../core/settings.ts';
|
|
19
20
|
|
|
20
21
|
import type { MoleculeStyle } from './viewerTypes.ts';
|
|
21
22
|
|
|
@@ -48,7 +49,7 @@ const STICK_SCALE = 1.2;
|
|
|
48
49
|
* @param plugin - The molstar context.
|
|
49
50
|
* @param molfile - Molfile text plus the format id.
|
|
50
51
|
* @param style - See {@link MoleculeStyle}.
|
|
51
|
-
* @returns
|
|
52
|
+
* @returns How many frames the file holds, the first of which is on screen.
|
|
52
53
|
* @throws {Error} When the file parses to zero atoms. molstar's `mol` parser returns
|
|
53
54
|
* exactly that on a V3000 file, with no error, so without this check the viewer
|
|
54
55
|
* would show an empty scene and report nothing.
|
|
@@ -57,7 +58,7 @@ export async function renderMolecule(
|
|
|
57
58
|
plugin: PluginContext,
|
|
58
59
|
molfile: Molecule3DFile,
|
|
59
60
|
style: MoleculeStyle = {},
|
|
60
|
-
): Promise<
|
|
61
|
+
): Promise<number> {
|
|
61
62
|
const { representation = 'ball-and-stick', sizeFactor = 1 } = style;
|
|
62
63
|
await clearMolecule(plugin);
|
|
63
64
|
const data = await plugin.builders.data.rawData(
|
|
@@ -99,6 +100,7 @@ export async function renderMolecule(
|
|
|
99
100
|
),
|
|
100
101
|
)
|
|
101
102
|
.commit();
|
|
103
|
+
return trajectory.data?.frameCount ?? 1;
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
/**
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import type { Molecule3DCamera } from '../core/camera.ts';
|
|
14
|
+
import type { Molecule3DFile } from '../core/file.ts';
|
|
14
15
|
import type { Measurement } from '../core/measurement.ts';
|
|
15
16
|
import { sameMeasurements } from '../core/measurement.ts';
|
|
16
|
-
import type {
|
|
17
|
+
import type { Molecule3DSettings } from '../core/settings.ts';
|
|
17
18
|
import { sameMolecule3DSettings } from '../core/settings.ts';
|
|
18
19
|
|
|
19
20
|
import type { SceneViewer } from './drawScene.ts';
|
|
@@ -103,7 +104,7 @@ export class SceneDrawer {
|
|
|
103
104
|
const { molfile, settings, measurements, frameNewMolecule } = request;
|
|
104
105
|
const isNew =
|
|
105
106
|
molfile !== null &&
|
|
106
|
-
(this.#framed === null || !
|
|
107
|
+
(this.#framed === null || !sameMolecule(this.#framed, molfile));
|
|
107
108
|
this.#framed = molfile;
|
|
108
109
|
// A link's camera is spent on the first molecule framed; afterwards the
|
|
109
110
|
// camera is the reader's and a new molecule is framed as usual.
|
|
@@ -119,6 +120,17 @@ export class SceneDrawer {
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
// Two files a site names alike draw one molecule, whatever their text.
|
|
124
|
+
function sameMolecule(first: Molecule3DFile, second: Molecule3DFile): boolean {
|
|
125
|
+
if (
|
|
126
|
+
first.moleculeId !== undefined &&
|
|
127
|
+
first.moleculeId === second.moleculeId
|
|
128
|
+
) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
return sameFile(first, second);
|
|
132
|
+
}
|
|
133
|
+
|
|
122
134
|
function sameFile(
|
|
123
135
|
first: Molecule3DFile | null,
|
|
124
136
|
second: Molecule3DFile | null,
|