matterviz 0.4.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/FilePicker.svelte +40 -50
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +15 -0
- package/dist/brillouin/BrillouinZone.svelte +18 -9
- package/dist/brillouin/BrillouinZoneScene.svelte +20 -29
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +18 -15
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +17 -113
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +104 -264
- package/dist/chempot-diagram/async-compute.svelte.js +12 -13
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/composition/BarChart.svelte +7 -9
- package/dist/composition/Composition.svelte +3 -8
- package/dist/composition/Formula.svelte +2 -2
- package/dist/composition/FormulaFilter.svelte +27 -93
- package/dist/composition/format.js +6 -8
- package/dist/composition/parse.js +50 -105
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +6 -17
- package/dist/convex-hull/ConvexHull2D.svelte +0 -2
- package/dist/convex-hull/ConvexHull3D.svelte +19 -47
- package/dist/convex-hull/ConvexHull4D.svelte +65 -95
- package/dist/convex-hull/StructurePopup.svelte +1 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.js +1 -7
- package/dist/convex-hull/thermodynamics.js +19 -27
- package/dist/coordination/CoordinationBarPlot.svelte +12 -21
- package/dist/element/BohrAtom.svelte +0 -1
- package/dist/element/ElementTile.svelte +26 -44
- package/dist/element/data.d.ts +2 -0
- package/dist/element/data.js +5 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +1 -1
- package/dist/fermi-surface/FermiSurface.svelte +22 -23
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +2 -6
- package/dist/fermi-surface/FermiSurfaceScene.svelte +32 -77
- package/dist/fermi-surface/compute.js +22 -55
- package/dist/fermi-surface/parse.js +38 -70
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +57 -84
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +1 -1
- package/dist/io/decompress.d.ts +2 -0
- package/dist/io/decompress.js +3 -2
- package/dist/io/export.d.ts +7 -4
- package/dist/io/export.js +70 -18
- package/dist/io/file-drop.js +60 -35
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +28 -16
- package/dist/isosurface/Isosurface.svelte +687 -196
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +564 -85
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.js +1 -1
- package/dist/layout/InfoCard.svelte +1 -3
- package/dist/layout/SettingsSection.svelte +52 -61
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/ViewerChrome.svelte +7 -1
- package/dist/layout/json-tree/JsonNode.svelte +14 -48
- package/dist/layout/json-tree/JsonTree.svelte +48 -95
- package/dist/layout/json-tree/JsonValue.svelte +3 -18
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -179
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +3 -2
- package/dist/math.js +29 -38
- package/dist/overlays/ContextMenu.svelte +15 -32
- package/dist/overlays/DraggablePane.svelte +39 -58
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -1
- package/dist/overlays/GlassChip.svelte +3 -1
- package/dist/periodic-table/PeriodicTableControls.svelte +26 -52
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +18 -34
- package/dist/phase-diagram/build-diagram.js +1 -6
- package/dist/phase-diagram/svg-to-diagram.js +9 -14
- package/dist/plot/bar/BarPlot.svelte +38 -42
- package/dist/plot/bar/SpacegroupBarPlot.svelte +18 -42
- package/dist/plot/box/BoxPlot.svelte +27 -23
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +1 -1
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +0 -10
- package/dist/plot/core/layout.d.ts +12 -5
- package/dist/plot/core/layout.js +37 -27
- package/dist/plot/core/pan-zoom.svelte.d.ts +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/svg.js +0 -1
- package/dist/plot/core/utils/hierarchy-chart.d.ts +1 -0
- package/dist/plot/core/utils/hierarchy-chart.js +12 -0
- package/dist/plot/core/utils/hierarchy-labels.js +3 -2
- package/dist/plot/histogram/Histogram.svelte +21 -26
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +59 -43
- package/dist/plot/scatter/ScatterPlot.svelte +67 -52
- package/dist/plot/scatter/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/sunburst/Sunburst.svelte +20 -20
- package/dist/plot/treemap/Treemap.svelte +175 -60
- package/dist/plot/treemap/Treemap.svelte.d.ts +6 -0
- package/dist/plot/treemap/index.d.ts +1 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +4 -2
- package/dist/plot/treemap/treemap.js +5 -2
- package/dist/rdf/RdfPlot.svelte +17 -35
- package/dist/rdf/calc-rdf.js +59 -44
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +84 -26
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.js +159 -482
- package/dist/spectral/Bands.svelte +151 -158
- package/dist/spectral/BrillouinBandsDos.svelte +4 -19
- package/dist/spectral/Dos.svelte +26 -24
- package/dist/spectral/helpers.js +40 -105
- package/dist/structure/AtomLegend.svelte +8 -13
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/CellSelect.svelte +35 -10
- package/dist/structure/Structure.svelte +177 -99
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureCarousel.svelte +10 -3
- package/dist/structure/StructureControls.svelte +8 -26
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +65 -76
- package/dist/structure/StructureScene.svelte +75 -109
- package/dist/structure/StructureScene.svelte.d.ts +3 -1
- package/dist/structure/StructureViewport.svelte +120 -55
- package/dist/structure/StructureViewport.svelte.d.ts +3 -1
- package/dist/structure/atom-properties.d.ts +1 -1
- package/dist/structure/atom-properties.js +4 -3
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +0 -1
- package/dist/structure/bonding.js +16 -23
- package/dist/structure/export.js +50 -74
- package/dist/structure/format-detect.js +5 -7
- package/dist/structure/index.js +6 -12
- package/dist/structure/parse.js +38 -100
- package/dist/structure/partial-occupancy.js +7 -4
- package/dist/structure/pbc.js +8 -10
- package/dist/structure/polyhedra.js +5 -4
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/symmetry/SymmetryStats.svelte +0 -4
- package/dist/symmetry/WyckoffTable.svelte +5 -4
- package/dist/symmetry/cell-transform.js +5 -14
- package/dist/symmetry/index.js +6 -9
- package/dist/table/HeatmapTable.svelte +61 -103
- package/dist/table/ToggleMenu.svelte +166 -44
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- package/dist/theme/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +4 -0
- package/dist/theme/index.js +1 -2
- package/dist/theme/themes.mjs +31 -60
- package/dist/tooltip/TooltipContent.svelte +1 -1
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +140 -120
- package/dist/trajectory/TrajectoryError.svelte +1 -66
- package/dist/trajectory/TrajectoryExportPane.svelte +0 -1
- package/dist/trajectory/TrajectoryInfoPane.svelte +55 -80
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +19 -29
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +7 -5
- package/dist/trajectory/frame-reader.js +3 -4
- package/dist/trajectory/helpers.js +16 -49
- package/dist/trajectory/index.js +2 -8
- package/dist/trajectory/parse/ase.js +1 -1
- package/dist/trajectory/parse/index.d.ts +4 -3
- package/dist/trajectory/parse/index.js +12 -17
- package/dist/trajectory/parse/vaspout-h5.d.ts +0 -1
- package/dist/trajectory/parse/vaspout-h5.js +1 -4
- package/dist/trajectory/parse/xyz.js +48 -2
- package/dist/trajectory/plotting.js +14 -37
- package/dist/xrd/XrdPlot.svelte +43 -68
- package/dist/xrd/calc-xrd.js +22 -58
- package/dist/xrd/parse.js +13 -22
- package/package.json +40 -8
- package/readme.md +6 -5
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { StatusMessage } from '../feedback'
|
|
6
6
|
import Spinner from '../feedback/Spinner.svelte'
|
|
7
7
|
import Icon from '../Icon.svelte'
|
|
8
|
-
import
|
|
8
|
+
import * as io from '../io'
|
|
9
9
|
import { forward_window_keydown, handle_and_prevent } from '../keyboard'
|
|
10
10
|
import { format_num, trajectory_property_config, type TrajPropertyConfig } from '../labels'
|
|
11
11
|
import type { Vec2 } from '../math'
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { Histogram, ScatterPlot } from '../plot'
|
|
18
18
|
import { toggle_series_visibility } from '../plot/core/utils/series-visibility'
|
|
19
19
|
import { DEFAULTS } from '../settings'
|
|
20
|
+
import type { AnyStructure } from '../structure'
|
|
20
21
|
import Structure from '../structure/Structure.svelte'
|
|
21
22
|
import { scaleLinear } from 'd3-scale'
|
|
22
23
|
import type { ComponentProps, Snippet } from 'svelte'
|
|
@@ -233,6 +234,9 @@
|
|
|
233
234
|
let element_size = $state({ width: 0, height: 0 })
|
|
234
235
|
let filename_copied = $state(false)
|
|
235
236
|
let orig_data = $state<string | ArrayBuffer | null>(null)
|
|
237
|
+
let data_url_load_id = 0
|
|
238
|
+
let loaded_data_url: string | undefined
|
|
239
|
+
let url_owned_trajectory: TrajectoryType | undefined
|
|
236
240
|
|
|
237
241
|
let controls_config = $derived(normalize_show_controls(show_controls))
|
|
238
242
|
|
|
@@ -280,6 +284,7 @@
|
|
|
280
284
|
if (trajectory && current_step_idx >= 0 && current_step_idx < total_frames) {
|
|
281
285
|
if (trajectory.frame_loader) {
|
|
282
286
|
// Load frame on demand (works for both indexed files and external streaming)
|
|
287
|
+
current_frame = null
|
|
283
288
|
schedule_frame_load_on_demand(current_step_idx)
|
|
284
289
|
} else {
|
|
285
290
|
clear_frame_load_timeout()
|
|
@@ -310,22 +315,28 @@
|
|
|
310
315
|
frame_load_timeout = undefined
|
|
311
316
|
}
|
|
312
317
|
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
318
|
+
const skip_stale_url_stream = () =>
|
|
319
|
+
Boolean(data_url && loaded_data_url && data_url !== loaded_data_url)
|
|
320
|
+
|
|
321
|
+
// Replace the trajectory with an updated copy, keeping URL ownership if it applied.
|
|
322
|
+
// No-ops while a data_url switch is in flight so stale streams can't mutate the old model.
|
|
323
|
+
const update_trajectory = (updates: Partial<TrajectoryType>) => {
|
|
324
|
+
if (!trajectory || skip_stale_url_stream()) return
|
|
325
|
+
const preserves_url_ownership = trajectory === url_owned_trajectory
|
|
326
|
+
trajectory = { ...trajectory, ...updates }
|
|
327
|
+
if (preserves_url_ownership) url_owned_trajectory = trajectory
|
|
319
328
|
}
|
|
320
329
|
|
|
321
|
-
const
|
|
322
|
-
if (
|
|
323
|
-
trajectory
|
|
324
|
-
...trajectory,
|
|
325
|
-
metadata: { ...trajectory.metadata, plot_metadata_loading: false },
|
|
326
|
-
}
|
|
330
|
+
const merge_plot_metadata = (batch: TrajectoryMetadata[]) => {
|
|
331
|
+
if (batch.length === 0) return
|
|
332
|
+
update_trajectory({ plot_metadata: [...(trajectory?.plot_metadata ?? []), ...batch] })
|
|
327
333
|
}
|
|
328
334
|
|
|
335
|
+
const finish_plot_metadata_loading = () =>
|
|
336
|
+
update_trajectory({
|
|
337
|
+
metadata: { ...trajectory?.metadata, plot_metadata_loading: false },
|
|
338
|
+
})
|
|
339
|
+
|
|
329
340
|
onMount(() => {
|
|
330
341
|
const handle_plot_metadata_stream = (event: MessageEvent<PlotMetadataStreamMessage>) => {
|
|
331
342
|
// Global listener: other code posts arbitrary messages (including null data)
|
|
@@ -489,8 +500,14 @@
|
|
|
489
500
|
}
|
|
490
501
|
}
|
|
491
502
|
|
|
492
|
-
// Current frame structure for display
|
|
493
|
-
|
|
503
|
+
// Current frame structure for display. Holds the last resolved structure so the 3D
|
|
504
|
+
// view doesn't blank while an uncached frame loads on demand (current_frame is nulled
|
|
505
|
+
// during loads to keep the info pane from showing the previous frame's data).
|
|
506
|
+
let current_structure = $state<AnyStructure | undefined>(undefined)
|
|
507
|
+
$effect(() => {
|
|
508
|
+
if (current_frame?.structure) current_structure = current_frame.structure
|
|
509
|
+
else if (!trajectory) current_structure = undefined
|
|
510
|
+
})
|
|
494
511
|
|
|
495
512
|
// Track hidden elements (persists across frame changes)
|
|
496
513
|
let hidden_elements = $state(new SvelteSet<ElementSymbol>())
|
|
@@ -637,10 +654,7 @@
|
|
|
637
654
|
display_mode !== `structure` &&
|
|
638
655
|
(plot_metadata_loading || !should_hide_plot(trajectory, plot_series)),
|
|
639
656
|
)
|
|
640
|
-
|
|
641
|
-
// Determine what to show based on display mode
|
|
642
657
|
let show_structure = $derived(![`scatter`, `histogram`].includes(display_mode))
|
|
643
|
-
let actual_show_plot = $derived(display_mode !== `structure` && show_plot)
|
|
644
658
|
|
|
645
659
|
// Check if there are any Y2 series to determine padding
|
|
646
660
|
let has_y2_series = $derived(plot_series.some((srs) => srs.y_axis === `y2` && srs.visible))
|
|
@@ -659,11 +673,10 @@
|
|
|
659
673
|
frame: current_frame || undefined,
|
|
660
674
|
})
|
|
661
675
|
}
|
|
662
|
-
// Step navigation functions
|
|
676
|
+
// Step navigation functions (streaming frame loading is handled by the reactive effect)
|
|
663
677
|
function next_step() {
|
|
664
678
|
if (current_step_idx < total_frames - 1) {
|
|
665
679
|
current_step_idx++
|
|
666
|
-
// Streaming frame loading handled by reactive effect
|
|
667
680
|
notify_step_change()
|
|
668
681
|
}
|
|
669
682
|
}
|
|
@@ -671,7 +684,6 @@
|
|
|
671
684
|
function prev_step() {
|
|
672
685
|
if (current_step_idx > 0) {
|
|
673
686
|
current_step_idx--
|
|
674
|
-
// Streaming frame loading handled by reactive effect
|
|
675
687
|
notify_step_change()
|
|
676
688
|
}
|
|
677
689
|
}
|
|
@@ -679,8 +691,6 @@
|
|
|
679
691
|
function go_to_step(idx: number) {
|
|
680
692
|
if (idx >= 0 && idx < total_frames) {
|
|
681
693
|
current_step_idx = idx
|
|
682
|
-
// Note: streaming frame loading is handled by reactive effect
|
|
683
|
-
// Handle callbacks for both traditional and streaming modes
|
|
684
694
|
notify_step_change()
|
|
685
695
|
}
|
|
686
696
|
}
|
|
@@ -816,16 +826,16 @@
|
|
|
816
826
|
}
|
|
817
827
|
|
|
818
828
|
// Handle URL-based files (e.g. from FilePicker)
|
|
819
|
-
const handled = await
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
+
const handled = await io
|
|
830
|
+
.handle_url_drop(event, async (content, filename) => {
|
|
831
|
+
current_filename = filename
|
|
832
|
+
file_size =
|
|
833
|
+
content instanceof ArrayBuffer ? content.byteLength : new Blob([content]).size
|
|
834
|
+
await load_trajectory_data(content, filename)
|
|
835
|
+
})
|
|
836
|
+
.catch(() => false)
|
|
837
|
+
|
|
838
|
+
if (handled) return
|
|
829
839
|
|
|
830
840
|
// Handle file system drops with optimized large file support
|
|
831
841
|
const file = event.dataTransfer?.files[0]
|
|
@@ -857,33 +867,58 @@
|
|
|
857
867
|
}
|
|
858
868
|
}
|
|
859
869
|
|
|
870
|
+
// Load trajectory from URL when data_url is provided. Track the model produced by
|
|
871
|
+
// this effect so caller-owned trajectory props keep precedence while URL-owned
|
|
872
|
+
// models can reload when data_url changes.
|
|
860
873
|
$effect(() => {
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
874
|
+
const requested_url = data_url
|
|
875
|
+
const current_trajectory = trajectory
|
|
876
|
+
const caller_owns_trajectory = Boolean(
|
|
877
|
+
current_trajectory && current_trajectory !== url_owned_trajectory,
|
|
878
|
+
)
|
|
879
|
+
if (!requested_url || caller_owns_trajectory) {
|
|
880
|
+
loaded_data_url = undefined
|
|
881
|
+
url_owned_trajectory = undefined
|
|
882
|
+
return
|
|
883
|
+
}
|
|
884
|
+
if (loaded_data_url === requested_url) return
|
|
885
|
+
|
|
886
|
+
const load_id = ++data_url_load_id
|
|
887
|
+
const is_current = () => load_id === data_url_load_id
|
|
888
|
+
loading = true
|
|
889
|
+
error_msg = null
|
|
890
|
+
|
|
891
|
+
io.load_from_url(requested_url, async (content, filename) => {
|
|
892
|
+
if (!is_current()) return
|
|
893
|
+
current_filename = filename
|
|
894
|
+
file_size =
|
|
895
|
+
content instanceof ArrayBuffer ? content.byteLength : new Blob([content]).size
|
|
896
|
+
await load_trajectory_data(content, filename, {
|
|
897
|
+
on_trajectory_loaded: (loaded_trajectory) => {
|
|
898
|
+
if (!is_current()) return
|
|
899
|
+
url_owned_trajectory = loaded_trajectory
|
|
900
|
+
loaded_data_url = requested_url
|
|
901
|
+
},
|
|
902
|
+
should_commit: is_current,
|
|
871
903
|
})
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
.
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
904
|
+
})
|
|
905
|
+
.catch((err: Error) => {
|
|
906
|
+
if (!is_current()) return
|
|
907
|
+
console.error(`Failed to load trajectory from URL:`, err)
|
|
908
|
+
error_msg = `Failed to load trajectory: ${err.message}`
|
|
909
|
+
current_filename = undefined
|
|
910
|
+
file_size = undefined
|
|
911
|
+
on_error?.({ error_msg, filename: io.basename_from_url(requested_url) })
|
|
912
|
+
})
|
|
913
|
+
.finally(() => {
|
|
914
|
+
if (is_current()) loading = false
|
|
915
|
+
})
|
|
916
|
+
|
|
917
|
+
return () => {
|
|
918
|
+
if (is_current()) {
|
|
919
|
+
data_url_load_id += 1
|
|
920
|
+
loading = false
|
|
921
|
+
}
|
|
887
922
|
}
|
|
888
923
|
})
|
|
889
924
|
|
|
@@ -892,13 +927,23 @@
|
|
|
892
927
|
on_frame_rate_change?.({ trajectory, fps })
|
|
893
928
|
})
|
|
894
929
|
|
|
895
|
-
async function load_trajectory_data(
|
|
930
|
+
async function load_trajectory_data(
|
|
931
|
+
data: string | ArrayBuffer,
|
|
932
|
+
filename: string,
|
|
933
|
+
options: {
|
|
934
|
+
on_trajectory_loaded?: (loaded_trajectory: TrajectoryType) => void
|
|
935
|
+
should_commit?: () => boolean
|
|
936
|
+
} = {},
|
|
937
|
+
) {
|
|
938
|
+
const { on_trajectory_loaded, should_commit = () => true } = options
|
|
896
939
|
loading = true
|
|
897
940
|
error_msg = null
|
|
898
941
|
parsing_progress = null
|
|
899
942
|
|
|
900
943
|
// Reset previous loading state
|
|
901
944
|
orig_data = null
|
|
945
|
+
const file_size_bytes =
|
|
946
|
+
data instanceof ArrayBuffer ? data.byteLength : new Blob([data]).size
|
|
902
947
|
|
|
903
948
|
try {
|
|
904
949
|
const data_size = data instanceof ArrayBuffer ? data.byteLength : data.length
|
|
@@ -906,84 +951,58 @@
|
|
|
906
951
|
// Determine loading strategy based on file size
|
|
907
952
|
const bin_file_threshold = loading_options.bin_file_threshold ?? MAX_BIN_FILE_SIZE
|
|
908
953
|
const text_file_threshold = loading_options.text_file_threshold ?? MAX_TEXT_FILE_SIZE
|
|
909
|
-
|
|
954
|
+
const is_large_file =
|
|
910
955
|
(data instanceof ArrayBuffer && data_size > bin_file_threshold) ||
|
|
911
956
|
(typeof data === `string` && data_size > text_file_threshold)
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
(
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
957
|
+
|
|
958
|
+
// Large files get indexed loading by default (loading_options can override)
|
|
959
|
+
const parsed_trajectory = await parse_trajectory_async(
|
|
960
|
+
data,
|
|
961
|
+
filename,
|
|
962
|
+
(progress) => {
|
|
963
|
+
if (should_commit()) parsing_progress = progress
|
|
964
|
+
},
|
|
965
|
+
{
|
|
966
|
+
...(is_large_file ? { use_indexing: true } : {}),
|
|
967
|
+
...loading_options,
|
|
968
|
+
atom_type_mapping,
|
|
969
|
+
},
|
|
970
|
+
)
|
|
971
|
+
if (!should_commit()) return
|
|
972
|
+
trajectory = parsed_trajectory
|
|
973
|
+
if (trajectory) on_trajectory_loaded?.(trajectory)
|
|
974
|
+
// Keep original data only when parsing attached a frame_loader for on-demand loads.
|
|
975
|
+
// Direct-parse fallbacks load all frames upfront, so retaining a duplicate wastes memory.
|
|
976
|
+
orig_data = trajectory?.frame_loader ? data : null
|
|
927
977
|
|
|
928
978
|
current_step_idx = 0
|
|
929
979
|
current_filename = filename
|
|
980
|
+
file_size = file_size_bytes
|
|
930
981
|
|
|
931
|
-
const
|
|
932
|
-
data instanceof ArrayBuffer ? data.byteLength : new Blob([data]).size
|
|
982
|
+
const loaded_trajectory = trajectory
|
|
933
983
|
on_file_load?.({
|
|
934
984
|
// emit file load event
|
|
935
|
-
trajectory,
|
|
936
|
-
frame_count:
|
|
937
|
-
total_atoms:
|
|
985
|
+
trajectory: loaded_trajectory,
|
|
986
|
+
frame_count: loaded_trajectory?.frames.length ?? 0,
|
|
987
|
+
total_atoms: loaded_trajectory?.frames[0]?.structure.sites.length ?? 0,
|
|
938
988
|
filename,
|
|
939
989
|
file_size: file_size_bytes,
|
|
940
990
|
})
|
|
941
991
|
} catch (err) {
|
|
992
|
+
if (!should_commit()) return
|
|
942
993
|
const unsupported_message = get_unsupported_format_message(
|
|
943
994
|
filename,
|
|
944
995
|
typeof data === `string` ? data : ``,
|
|
945
996
|
)
|
|
946
997
|
error_msg = unsupported_message || `Failed to parse trajectory: ${err}`
|
|
998
|
+
on_error?.({ error_msg, filename, file_size: file_size_bytes })
|
|
947
999
|
current_filename = undefined
|
|
948
1000
|
file_size = undefined
|
|
949
|
-
|
|
950
|
-
on_error?.({
|
|
951
|
-
// emit error event
|
|
952
|
-
error_msg,
|
|
953
|
-
filename: current_filename || undefined,
|
|
954
|
-
file_size: file_size || undefined,
|
|
955
|
-
})
|
|
956
1001
|
} finally {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
// Load using indexed parsing for large files
|
|
963
|
-
async function load_with_indexing(data: string | ArrayBuffer, filename: string) {
|
|
964
|
-
try {
|
|
965
|
-
// Use indexed parsing for efficient large file handling
|
|
966
|
-
const merged_options = {
|
|
967
|
-
use_indexing: true,
|
|
968
|
-
...loading_options,
|
|
969
|
-
atom_type_mapping,
|
|
1002
|
+
if (should_commit()) {
|
|
1003
|
+
parsing_progress = null
|
|
1004
|
+
loading = false
|
|
970
1005
|
}
|
|
971
|
-
trajectory = await parse_trajectory_async(
|
|
972
|
-
data,
|
|
973
|
-
filename,
|
|
974
|
-
(progress) => {
|
|
975
|
-
parsing_progress = progress
|
|
976
|
-
},
|
|
977
|
-
merged_options,
|
|
978
|
-
)
|
|
979
|
-
|
|
980
|
-
// Keep original data for on-demand frame loads only when indexed parsing attached a
|
|
981
|
-
// frame_loader. Direct-parse fallbacks (e.g. large JSON or extensionless blob:
|
|
982
|
-
// filenames) load all frames upfront, so retaining a full duplicate payload wastes memory.
|
|
983
|
-
orig_data = trajectory?.frame_loader ? data : null
|
|
984
|
-
} catch (error) {
|
|
985
|
-
console.error(`Indexed loading failed:`, error)
|
|
986
|
-
throw error
|
|
987
1006
|
}
|
|
988
1007
|
}
|
|
989
1008
|
|
|
@@ -1113,7 +1132,7 @@
|
|
|
1113
1132
|
onmouseenter={() => (hovered = true)}
|
|
1114
1133
|
onmouseleave={() => (hovered = false)}
|
|
1115
1134
|
ondrop={handle_file_drop}
|
|
1116
|
-
{...drag_over_handlers({
|
|
1135
|
+
{...io.drag_over_handlers({
|
|
1117
1136
|
allow: () => allow_file_drop,
|
|
1118
1137
|
set_dragover: (over) => (dragover = over),
|
|
1119
1138
|
})}
|
|
@@ -1122,7 +1141,7 @@
|
|
|
1122
1141
|
{...rest}
|
|
1123
1142
|
class={[`trajectory`, actual_layout, rest.class]}
|
|
1124
1143
|
class:show-both-views={[`structure+scatter`, `structure+histogram`].includes(display_mode) &&
|
|
1125
|
-
|
|
1144
|
+
show_plot &&
|
|
1126
1145
|
show_structure}
|
|
1127
1146
|
>
|
|
1128
1147
|
{#if loading}
|
|
@@ -1283,6 +1302,7 @@
|
|
|
1283
1302
|
{#if trajectory && controls_config.visible(`info-pane`)}
|
|
1284
1303
|
<TrajectoryInfoPane
|
|
1285
1304
|
{trajectory}
|
|
1305
|
+
{current_frame}
|
|
1286
1306
|
{current_step_idx}
|
|
1287
1307
|
{current_filename}
|
|
1288
1308
|
{current_file_path}
|
|
@@ -1363,7 +1383,7 @@
|
|
|
1363
1383
|
|
|
1364
1384
|
<div
|
|
1365
1385
|
class="content-area"
|
|
1366
|
-
class:hide-plot={!
|
|
1386
|
+
class:hide-plot={!show_plot}
|
|
1367
1387
|
class:hide-structure={!show_structure}
|
|
1368
1388
|
class:show-both={[`structure+scatter`, `structure+histogram`].includes(display_mode)}
|
|
1369
1389
|
class:show-structure-only={display_mode === `structure`}
|
|
@@ -1384,7 +1404,7 @@
|
|
|
1384
1404
|
/>
|
|
1385
1405
|
{/if}
|
|
1386
1406
|
|
|
1387
|
-
{#if
|
|
1407
|
+
{#if show_plot}
|
|
1388
1408
|
{#if plot_metadata_loading}
|
|
1389
1409
|
<div class="plot-metadata-loading plot">
|
|
1390
1410
|
<Spinner text="Sampling trajectory plot data..." style="--spinner-size: 1.4em" />
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
{#if error_snippet}
|
|
21
21
|
{@render error_snippet({ error_msg, on_dismiss })}
|
|
22
22
|
{:else if error_msg.startsWith(`<`)}
|
|
23
|
-
<!-- Render HTML
|
|
23
|
+
<!-- Render HTML error messages (sanitized) -->
|
|
24
24
|
{@html sanitize_html(error_msg)}
|
|
25
25
|
<button onclick={on_dismiss}>Dismiss</button>
|
|
26
26
|
{:else}
|
|
@@ -63,69 +63,4 @@
|
|
|
63
63
|
div button:hover {
|
|
64
64
|
background: var(--error-btn-bg-hover);
|
|
65
65
|
}
|
|
66
|
-
/* Styles for unsupported format messages */
|
|
67
|
-
div :global(.unsupported-format) {
|
|
68
|
-
text-align: left;
|
|
69
|
-
max-width: 90%;
|
|
70
|
-
max-height: 70vh;
|
|
71
|
-
margin: 0 auto;
|
|
72
|
-
overflow-y: auto;
|
|
73
|
-
overflow-x: hidden;
|
|
74
|
-
}
|
|
75
|
-
div :global(.unsupported-format h4) {
|
|
76
|
-
color: var(--error-color);
|
|
77
|
-
margin: 0 0 1rem 0;
|
|
78
|
-
font-size: 1.1rem;
|
|
79
|
-
display: flex;
|
|
80
|
-
align-items: center;
|
|
81
|
-
gap: 0.5rem;
|
|
82
|
-
}
|
|
83
|
-
div :global(.unsupported-format h5) {
|
|
84
|
-
margin: 0.75rem 0 0.25rem 0;
|
|
85
|
-
font-size: 0.9rem;
|
|
86
|
-
font-weight: 600;
|
|
87
|
-
}
|
|
88
|
-
div :global(.unsupported-format p) {
|
|
89
|
-
margin: 0.25rem 0;
|
|
90
|
-
text-align: left;
|
|
91
|
-
font-size: 0.85rem;
|
|
92
|
-
}
|
|
93
|
-
div :global(.unsupported-format ul) {
|
|
94
|
-
text-align: left;
|
|
95
|
-
margin: 0.5rem 0;
|
|
96
|
-
padding-left: 1.5rem;
|
|
97
|
-
}
|
|
98
|
-
div :global(.unsupported-format li) {
|
|
99
|
-
margin: 0.25rem 0;
|
|
100
|
-
}
|
|
101
|
-
div :global(.unsupported-format .code-options) {
|
|
102
|
-
margin: 1rem 0 0 0;
|
|
103
|
-
display: grid;
|
|
104
|
-
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
105
|
-
gap: 1.5rem;
|
|
106
|
-
}
|
|
107
|
-
div :global(.unsupported-format .code-options > div) {
|
|
108
|
-
margin: 0;
|
|
109
|
-
}
|
|
110
|
-
div :global(.unsupported-format .code-options strong) {
|
|
111
|
-
display: block;
|
|
112
|
-
margin-bottom: 0.25rem;
|
|
113
|
-
font-size: 0.85rem;
|
|
114
|
-
font-weight: 600;
|
|
115
|
-
}
|
|
116
|
-
div :global(.unsupported-format pre) {
|
|
117
|
-
padding: 0.5rem;
|
|
118
|
-
margin: 0;
|
|
119
|
-
overflow-x: auto;
|
|
120
|
-
font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', monospace;
|
|
121
|
-
font-size: 0.75rem;
|
|
122
|
-
line-height: 1.2;
|
|
123
|
-
max-height: 150px;
|
|
124
|
-
overflow-y: auto;
|
|
125
|
-
}
|
|
126
|
-
div :global(.unsupported-format p code) {
|
|
127
|
-
padding: 0.2em 0.4em;
|
|
128
|
-
border-radius: 3px;
|
|
129
|
-
font-family: 'SFMono-Regular', 'Consolas', 'Liberation Mono', 'Menlo', monospace;
|
|
130
|
-
}
|
|
131
66
|
</style>
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import ExportPane from '../io/ExportPane.svelte'
|
|
10
10
|
import SettingsSection from '../layout/SettingsSection.svelte'
|
|
11
11
|
import type { TrajectoryType } from './'
|
|
12
|
-
import type { ComponentProps } from 'svelte'
|
|
13
12
|
import { tooltip } from 'svelte-multiselect/attachments'
|
|
14
13
|
import { to_error } from '../utils'
|
|
15
14
|
|