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
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
import { convex_hull_2d, cross_3d, merge_coplanar_triangles, normalize_vec } from '../math'
|
|
21
21
|
import DraggablePane from '../overlays/DraggablePane.svelte'
|
|
22
22
|
import { ColorBar, ScatterPlot3DControls } from '../plot'
|
|
23
|
+
import { page_visibility } from '../scene'
|
|
24
|
+
import { sanitize_html } from '../sanitize'
|
|
23
25
|
import { constrain_tooltip_position, pad_rect, rects_overlap } from '../plot/core/layout'
|
|
24
26
|
import type {
|
|
25
27
|
AxisConfig3D,
|
|
@@ -38,7 +40,7 @@
|
|
|
38
40
|
import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'
|
|
39
41
|
import { compute_chempot_async } from './async-compute.svelte'
|
|
40
42
|
import ChemPotScene3D from './ChemPotScene3D.svelte'
|
|
41
|
-
import { get_chempot_color_bar_config,
|
|
43
|
+
import { ARITY_COLORS, get_chempot_color_bar_config, get_domain_color_data } from './color'
|
|
42
44
|
import {
|
|
43
45
|
CHEMPOT_COLOR_MODE_OPTIONS,
|
|
44
46
|
CHEMPOT_COLOR_SCALE_OPTIONS,
|
|
@@ -56,12 +58,10 @@
|
|
|
56
58
|
import {
|
|
57
59
|
apply_element_padding,
|
|
58
60
|
bbox_diagonal,
|
|
59
|
-
best_form_energy_for_formula,
|
|
60
61
|
build_axis_ranges,
|
|
61
62
|
dedup_points,
|
|
62
|
-
formula_key_from_composition,
|
|
63
63
|
get_3d_domain_simplexes_and_ann_loc,
|
|
64
|
-
|
|
64
|
+
get_energy_stats_by_formula,
|
|
65
65
|
get_min_entries_and_el_refs,
|
|
66
66
|
get_ternary_combinations,
|
|
67
67
|
get_visible_domain_labels,
|
|
@@ -269,17 +269,14 @@
|
|
|
269
269
|
get_projection_source_entries(entries, temp_filtered_entries),
|
|
270
270
|
)
|
|
271
271
|
|
|
272
|
-
const all_entry_elements = $derived.by(() =>
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
),
|
|
281
|
-
).sort(),
|
|
282
|
-
)
|
|
272
|
+
const all_entry_elements = $derived.by(() => {
|
|
273
|
+
const elements = projection_source_entries.flatMap((entry) =>
|
|
274
|
+
Object.entries(entry.composition)
|
|
275
|
+
.filter(([, amount]) => amount > 0)
|
|
276
|
+
.map(([element]) => element),
|
|
277
|
+
)
|
|
278
|
+
return Array.from(new SvelteSet(elements)).sort()
|
|
279
|
+
})
|
|
283
280
|
const has_multinary_system = $derived(all_entry_elements.length > 3)
|
|
284
281
|
let projection_elements_override = $state<string[] | null>(null)
|
|
285
282
|
const config_projection_elements = $derived(
|
|
@@ -287,16 +284,14 @@
|
|
|
287
284
|
)
|
|
288
285
|
const projection_elements = $derived.by(() => {
|
|
289
286
|
if (all_entry_elements.length < 3) return []
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (config_projection_elements) return config_projection_elements
|
|
299
|
-
return all_entry_elements.slice(0, 3)
|
|
287
|
+
// User-picked projection axes only apply to multinary (4+ element) systems
|
|
288
|
+
const override_projection = has_multinary_system
|
|
289
|
+
? normalize_projection_triplet(
|
|
290
|
+
projection_elements_override ?? undefined,
|
|
291
|
+
all_entry_elements,
|
|
292
|
+
)
|
|
293
|
+
: null
|
|
294
|
+
return override_projection ?? config_projection_elements ?? all_entry_elements.slice(0, 3)
|
|
300
295
|
})
|
|
301
296
|
const effective_config = $derived({
|
|
302
297
|
...config,
|
|
@@ -361,7 +356,7 @@
|
|
|
361
356
|
})
|
|
362
357
|
const current_projection_key = $derived(plot_elements.join(`|`))
|
|
363
358
|
let formula_filter_query = $state(``)
|
|
364
|
-
const available_formulas = $derived
|
|
359
|
+
const available_formulas = $derived(Object.keys(diagram_data?.domains ?? {}).sort())
|
|
365
360
|
const filtered_formulas = $derived.by(() => {
|
|
366
361
|
const query = formula_filter_query.trim().toLowerCase()
|
|
367
362
|
if (!query) return available_formulas
|
|
@@ -383,12 +378,6 @@
|
|
|
383
378
|
info: ChemPotHoverInfo3D
|
|
384
379
|
}
|
|
385
380
|
|
|
386
|
-
interface FormulaEnergyStats {
|
|
387
|
-
matching_entry_count: number
|
|
388
|
-
min_energy_per_atom: number | null
|
|
389
|
-
max_energy_per_atom: number | null
|
|
390
|
-
}
|
|
391
|
-
type NumericColorMode = Exclude<ChemPotColorMode, `none` | `arity`>
|
|
392
381
|
const domain_annotation_cache = new Map<string, number[]>()
|
|
393
382
|
|
|
394
383
|
function get_domain_ann_loc(points_3d: number[][]): number[] {
|
|
@@ -444,122 +433,27 @@
|
|
|
444
433
|
return result
|
|
445
434
|
})
|
|
446
435
|
|
|
447
|
-
const entry_energy_stats_by_formula = $derived
|
|
448
|
-
()
|
|
449
|
-
const stats_by_formula = new SvelteMap<string, FormulaEnergyStats>()
|
|
450
|
-
for (const entry of temp_filtered_entries) {
|
|
451
|
-
const formula_key = formula_key_from_composition(entry.composition)
|
|
452
|
-
const energy_per_atom = get_energy_per_atom(entry)
|
|
453
|
-
const existing = stats_by_formula.get(formula_key)
|
|
454
|
-
if (!existing) {
|
|
455
|
-
stats_by_formula.set(formula_key, {
|
|
456
|
-
matching_entry_count: 1,
|
|
457
|
-
min_energy_per_atom: energy_per_atom,
|
|
458
|
-
max_energy_per_atom: energy_per_atom,
|
|
459
|
-
})
|
|
460
|
-
continue
|
|
461
|
-
}
|
|
462
|
-
stats_by_formula.set(formula_key, {
|
|
463
|
-
matching_entry_count: existing.matching_entry_count + 1,
|
|
464
|
-
min_energy_per_atom: Math.min(
|
|
465
|
-
existing.min_energy_per_atom ?? energy_per_atom,
|
|
466
|
-
energy_per_atom,
|
|
467
|
-
),
|
|
468
|
-
max_energy_per_atom: Math.max(
|
|
469
|
-
existing.max_energy_per_atom ?? energy_per_atom,
|
|
470
|
-
energy_per_atom,
|
|
471
|
-
),
|
|
472
|
-
})
|
|
473
|
-
}
|
|
474
|
-
return stats_by_formula
|
|
475
|
-
},
|
|
436
|
+
const entry_energy_stats_by_formula = $derived(
|
|
437
|
+
get_energy_stats_by_formula(temp_filtered_entries),
|
|
476
438
|
)
|
|
477
439
|
|
|
478
440
|
// === Region coloring ===
|
|
479
|
-
// Categorical palette for arity mode (element count)
|
|
480
|
-
const arity_colors = [`#3498db`, `#2ecc71`, `#e67e22`, `#9b59b6`] as const
|
|
481
|
-
|
|
482
441
|
// Original (non-renormalized) elemental references for formation energy computation.
|
|
483
442
|
// diagram_data.el_refs may be renormalized to zero when formal_chempots is true,
|
|
484
443
|
// so we compute our own from the raw entries to get true DFT reference energies.
|
|
485
444
|
const raw_el_refs = $derived(get_min_entries_and_el_refs(temp_filtered_entries).el_refs)
|
|
486
445
|
|
|
487
|
-
const
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
}
|
|
492
|
-
function get_numeric_color_value(
|
|
493
|
-
formula: string,
|
|
494
|
-
active_color_mode: NumericColorMode,
|
|
495
|
-
): number | null {
|
|
496
|
-
if (active_color_mode === `energy`) {
|
|
497
|
-
return entry_energy_stats_by_formula.get(formula)?.min_energy_per_atom ?? null
|
|
498
|
-
}
|
|
499
|
-
if (active_color_mode === `formation_energy`) {
|
|
500
|
-
return best_form_energy_for_formula(temp_filtered_entries, formula, raw_el_refs) ?? null
|
|
501
|
-
}
|
|
502
|
-
return entry_energy_stats_by_formula.get(formula)?.matching_entry_count ?? 0
|
|
503
|
-
}
|
|
504
|
-
const domain_color_values = $derived.by(
|
|
505
|
-
(): { value_by_formula: SvelteMap<string, number>; values: number[] } | null => {
|
|
506
|
-
if (color_mode === `none` || color_mode === `arity`) return null
|
|
507
|
-
const active_color_mode = color_mode as NumericColorMode
|
|
508
|
-
const value_by_formula = new SvelteMap<string, number>()
|
|
509
|
-
const values: number[] = []
|
|
510
|
-
for (const domain of render_domains) {
|
|
511
|
-
const value = get_numeric_color_value(domain.formula, active_color_mode)
|
|
512
|
-
if (value == null || !Number.isFinite(value)) continue
|
|
513
|
-
values.push(value)
|
|
514
|
-
value_by_formula.set(domain.formula, value)
|
|
515
|
-
}
|
|
516
|
-
return { value_by_formula, values }
|
|
517
|
-
},
|
|
518
|
-
)
|
|
519
|
-
|
|
520
|
-
// Per-domain color map keyed by formula
|
|
521
|
-
const domain_colors = $derived.by((): SvelteMap<string, string> => {
|
|
522
|
-
const colors = new SvelteMap<string, string>()
|
|
523
|
-
if (color_mode === `none`) return colors
|
|
524
|
-
|
|
525
|
-
if (color_mode === `arity`) {
|
|
526
|
-
for (const domain of render_domains) {
|
|
527
|
-
const n_elements = extract_formula_elements(domain.formula).length
|
|
528
|
-
const idx = Math.min(n_elements, arity_colors.length) - 1
|
|
529
|
-
colors.set(domain.formula, arity_colors[Math.max(0, idx)])
|
|
530
|
-
}
|
|
531
|
-
return colors
|
|
532
|
-
}
|
|
533
|
-
const values_payload = domain_color_values
|
|
534
|
-
const scale = make_chempot_color_scale(
|
|
535
|
-
values_payload?.values ?? [],
|
|
446
|
+
const { colors: domain_colors, color_range } = $derived(
|
|
447
|
+
get_domain_color_data({
|
|
448
|
+
formulas: render_domains.map((domain) => domain.formula),
|
|
449
|
+
color_mode,
|
|
536
450
|
color_scale,
|
|
537
451
|
reverse_color_scale,
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return colors
|
|
544
|
-
})
|
|
545
|
-
|
|
546
|
-
// Range and label for the color bar (null for none/arity which are categorical)
|
|
547
|
-
const color_range = $derived.by((): { min: number; max: number; label: string } | null => {
|
|
548
|
-
const values = domain_color_values?.values ?? []
|
|
549
|
-
if (values.length === 0) return null
|
|
550
|
-
let lo = values[0],
|
|
551
|
-
hi = values[0]
|
|
552
|
-
for (let idx = 1; idx < values.length; idx++) {
|
|
553
|
-
if (values[idx] < lo) lo = values[idx]
|
|
554
|
-
if (values[idx] > hi) hi = values[idx]
|
|
555
|
-
}
|
|
556
|
-
return {
|
|
557
|
-
min: lo,
|
|
558
|
-
max: Math.max(hi, lo + 1e-6),
|
|
559
|
-
label:
|
|
560
|
-
color_mode === `none` || color_mode === `arity` ? `` : color_mode_labels[color_mode],
|
|
561
|
-
}
|
|
562
|
-
})
|
|
452
|
+
entries: temp_filtered_entries,
|
|
453
|
+
el_refs: raw_el_refs,
|
|
454
|
+
energy_stats: entry_energy_stats_by_formula,
|
|
455
|
+
}),
|
|
456
|
+
)
|
|
563
457
|
|
|
564
458
|
const arity_legend_labels = $derived.by((): string[] => {
|
|
565
459
|
let has_four_plus_regions = false
|
|
@@ -604,10 +498,7 @@
|
|
|
604
498
|
]
|
|
605
499
|
})
|
|
606
500
|
|
|
607
|
-
|
|
608
|
-
const [scale_x, scale_y, scale_z] = render_axis_scale
|
|
609
|
-
return [point[1] * scale_x, point[2] * scale_y, point[0] * scale_z]
|
|
610
|
-
}
|
|
501
|
+
const to_render_xyz = (point: number[]): Vec3 => swiz(point[0], point[1], point[2])
|
|
611
502
|
|
|
612
503
|
// Compute data center and extent for camera positioning (in swizzled coords)
|
|
613
504
|
const { data_center, data_extent } = $derived.by(() => {
|
|
@@ -752,20 +643,8 @@
|
|
|
752
643
|
const point_b_idx = selected_coord_to_idx.get(
|
|
753
644
|
`${point_b[0].toFixed(6)},${point_b[1].toFixed(6)}`,
|
|
754
645
|
)
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
point_b_idx == null ||
|
|
758
|
-
point_a_idx >= pts.length ||
|
|
759
|
-
point_b_idx >= pts.length
|
|
760
|
-
) {
|
|
761
|
-
console.warn(`get_2d_hull_edges: invalid edge`, {
|
|
762
|
-
point_a,
|
|
763
|
-
point_b,
|
|
764
|
-
point_a_idx,
|
|
765
|
-
point_b_idx,
|
|
766
|
-
})
|
|
767
|
-
continue
|
|
768
|
-
}
|
|
646
|
+
// Hull vertices come from pts_2d, so lookups always succeed
|
|
647
|
+
if (point_a_idx == null || point_b_idx == null) continue
|
|
769
648
|
edges.push([pts[point_a_idx], pts[point_b_idx]])
|
|
770
649
|
}
|
|
771
650
|
|
|
@@ -1069,23 +948,21 @@
|
|
|
1069
948
|
return geom
|
|
1070
949
|
})
|
|
1071
950
|
|
|
951
|
+
const domain_label = (domain: DomainRenderData) => ({
|
|
952
|
+
formula: domain.formula,
|
|
953
|
+
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
954
|
+
label_font_size: domain.label_font_size,
|
|
955
|
+
})
|
|
956
|
+
|
|
1072
957
|
const visible_domain_labels = $derived.by(() => {
|
|
1073
958
|
if (!hull_base_geometry || face_domain_map.length === 0) {
|
|
1074
|
-
return render_domains.map(
|
|
1075
|
-
formula: domain.formula,
|
|
1076
|
-
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
1077
|
-
label_font_size: domain.label_font_size,
|
|
1078
|
-
}))
|
|
959
|
+
return render_domains.map(domain_label)
|
|
1079
960
|
}
|
|
1080
961
|
|
|
1081
962
|
const pos = hull_base_geometry.getAttribute(`position`)
|
|
1082
963
|
const pinned_labels = render_domains
|
|
1083
964
|
.filter((domain) => domain.is_draw_formula)
|
|
1084
|
-
.map(
|
|
1085
|
-
formula: domain.formula,
|
|
1086
|
-
position: swiz(domain.ann_loc[0], domain.ann_loc[1], domain.ann_loc[2]),
|
|
1087
|
-
label_font_size: domain.label_font_size,
|
|
1088
|
-
}))
|
|
965
|
+
.map(domain_label)
|
|
1089
966
|
const font_size_by_formula = new SvelteMap(
|
|
1090
967
|
render_domains.map((domain) => [domain.formula, domain.label_font_size]),
|
|
1091
968
|
)
|
|
@@ -1097,16 +974,24 @@
|
|
|
1097
974
|
)
|
|
1098
975
|
})
|
|
1099
976
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
977
|
+
// Register an effect that disposes the given geometries whenever they are
|
|
978
|
+
// recomputed or the component unmounts.
|
|
979
|
+
function dispose_on_change(
|
|
980
|
+
get_geometries: () => (THREE.BufferGeometry | null | undefined)[],
|
|
981
|
+
): void {
|
|
982
|
+
$effect(() => {
|
|
983
|
+
const geometries = get_geometries()
|
|
984
|
+
return () => {
|
|
985
|
+
for (const geometry of geometries) geometry?.dispose()
|
|
986
|
+
}
|
|
987
|
+
})
|
|
988
|
+
}
|
|
1104
989
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
990
|
+
dispose_on_change(() => [hull_base_geometry])
|
|
991
|
+
// Don't dispose colored hull if it's the same object as hull_base_geometry (no clone made)
|
|
992
|
+
dispose_on_change(() =>
|
|
993
|
+
colored_hull_geometry !== hull_base_geometry ? [colored_hull_geometry] : [],
|
|
994
|
+
)
|
|
1110
995
|
|
|
1111
996
|
// Domains on the outer surface (used by the "Surface" formula overlay quick-select).
|
|
1112
997
|
const surface_formulas = $derived.by((): SvelteSet<string> => {
|
|
@@ -1343,44 +1228,12 @@
|
|
|
1343
1228
|
return result
|
|
1344
1229
|
})
|
|
1345
1230
|
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
for (const geometry of geometries) dispose_geometry(geometry)
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
$effect(() => {
|
|
1356
|
-
const geometry = edge_geometry
|
|
1357
|
-
return () => dispose_geometry(geometry)
|
|
1358
|
-
})
|
|
1359
|
-
|
|
1360
|
-
$effect(() => {
|
|
1361
|
-
const geometry = occlusion_hull_geometry
|
|
1362
|
-
return () => dispose_geometry(geometry)
|
|
1363
|
-
})
|
|
1364
|
-
|
|
1365
|
-
$effect(() => {
|
|
1366
|
-
const geometry = bounding_box_geometry
|
|
1367
|
-
return () => dispose_geometry(geometry)
|
|
1368
|
-
})
|
|
1369
|
-
|
|
1370
|
-
$effect(() => {
|
|
1371
|
-
const geometries = formula_edge_data.map((data) => data.geometry)
|
|
1372
|
-
return () => dispose_geometries(geometries)
|
|
1373
|
-
})
|
|
1374
|
-
|
|
1375
|
-
$effect(() => {
|
|
1376
|
-
const geometries = formula_mesh_data.map((data) => data.geometry)
|
|
1377
|
-
return () => dispose_geometries(geometries)
|
|
1378
|
-
})
|
|
1379
|
-
|
|
1380
|
-
$effect(() => {
|
|
1381
|
-
const geometries = hover_mesh_data.map((data) => data.geometry)
|
|
1382
|
-
return () => dispose_geometries(geometries)
|
|
1383
|
-
})
|
|
1231
|
+
dispose_on_change(() => [edge_geometry])
|
|
1232
|
+
dispose_on_change(() => [occlusion_hull_geometry])
|
|
1233
|
+
dispose_on_change(() => [bounding_box_geometry])
|
|
1234
|
+
dispose_on_change(() => formula_edge_data.map((data) => data.geometry))
|
|
1235
|
+
dispose_on_change(() => formula_mesh_data.map((data) => data.geometry))
|
|
1236
|
+
dispose_on_change(() => hover_mesh_data.map((data) => data.geometry))
|
|
1384
1237
|
|
|
1385
1238
|
// === Grid, axes, ticks (matching ScatterPlot3D style) ===
|
|
1386
1239
|
|
|
@@ -1437,8 +1290,8 @@
|
|
|
1437
1290
|
// Niced ranges (from ticks) padded so the grid extends beyond the diagram.
|
|
1438
1291
|
// For horizontal axes (0,1): pad both sides.
|
|
1439
1292
|
// For vertical axis (2): use actual data range and round min down to an integer.
|
|
1440
|
-
const niced_range = $derived
|
|
1441
|
-
|
|
1293
|
+
const niced_range = $derived(
|
|
1294
|
+
[0, 1, 2].map((axis): Vec2 => {
|
|
1442
1295
|
const ticks = data_ticks[axis]
|
|
1443
1296
|
const lo = ticks[0]
|
|
1444
1297
|
const hi = ticks.at(-1) ?? lo
|
|
@@ -1448,8 +1301,8 @@
|
|
|
1448
1301
|
return [Math.floor(min_data), hi]
|
|
1449
1302
|
}
|
|
1450
1303
|
return [lo - step, hi + step]
|
|
1451
|
-
})
|
|
1452
|
-
|
|
1304
|
+
}),
|
|
1305
|
+
)
|
|
1453
1306
|
|
|
1454
1307
|
// Helper to create a line geometry from two Vec3 arrays
|
|
1455
1308
|
function make_line_geom(start: Vec3, end: Vec3): THREE.BufferGeometry {
|
|
@@ -1618,11 +1471,11 @@
|
|
|
1618
1471
|
tick_label.style.visibility = ``
|
|
1619
1472
|
}
|
|
1620
1473
|
const domain_rects = Array.from(wrapper.querySelectorAll<HTMLElement>(`.domain-label`))
|
|
1621
|
-
.filter((
|
|
1622
|
-
const style = getComputedStyle(
|
|
1474
|
+
.filter((label_el) => {
|
|
1475
|
+
const style = getComputedStyle(label_el)
|
|
1623
1476
|
return style.display !== `none` && style.visibility !== `hidden`
|
|
1624
1477
|
})
|
|
1625
|
-
.map((
|
|
1478
|
+
.map((label_el) => pad_rect(label_el.getBoundingClientRect(), 1))
|
|
1626
1479
|
if (domain_rects.length === 0) return
|
|
1627
1480
|
|
|
1628
1481
|
for (const tick_label of tick_labels) {
|
|
@@ -1750,20 +1603,13 @@
|
|
|
1750
1603
|
bg_css_var: `--chempot-3d-bg-fullscreen`,
|
|
1751
1604
|
})
|
|
1752
1605
|
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
}
|
|
1761
|
-
for (const line_geometry of grid_item.grid_geoms) {
|
|
1762
|
-
dispose_geometry(line_geometry)
|
|
1763
|
-
}
|
|
1764
|
-
}
|
|
1765
|
-
}
|
|
1766
|
-
})
|
|
1606
|
+
dispose_on_change(() =>
|
|
1607
|
+
grid_config.flatMap((grid_item) => [
|
|
1608
|
+
grid_item.line_geom,
|
|
1609
|
+
...grid_item.tick_geoms,
|
|
1610
|
+
...grid_item.grid_geoms,
|
|
1611
|
+
]),
|
|
1612
|
+
)
|
|
1767
1613
|
|
|
1768
1614
|
const projection_planes = $derived.by(() => {
|
|
1769
1615
|
const projections = display.projections
|
|
@@ -1997,15 +1843,12 @@
|
|
|
1997
1843
|
}
|
|
1998
1844
|
|
|
1999
1845
|
function stop_phase_pointer_event(raw_event: unknown): void {
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
if (!native_event || typeof native_event !== `object`) return
|
|
2007
|
-
const native_pointer_event = native_event as { stopPropagation?: () => void }
|
|
2008
|
-
native_pointer_event.stopPropagation?.()
|
|
1846
|
+
const event = raw_event as
|
|
1847
|
+
| { nativeEvent?: { stopPropagation?: () => void }; stopPropagation?: () => void }
|
|
1848
|
+
| null
|
|
1849
|
+
| undefined
|
|
1850
|
+
event?.stopPropagation?.()
|
|
1851
|
+
event?.nativeEvent?.stopPropagation?.()
|
|
2009
1852
|
}
|
|
2010
1853
|
|
|
2011
1854
|
function handle_phase_hover(domain_data: HoverMeshData, raw_event: unknown): void {
|
|
@@ -2307,6 +2150,17 @@
|
|
|
2307
2150
|
<p>Need at least 2 elements with elemental reference entries.</p>
|
|
2308
2151
|
</div>
|
|
2309
2152
|
{:else if mounted && typeof WebGLRenderingContext !== `undefined`}
|
|
2153
|
+
{#snippet orbit_controls()}
|
|
2154
|
+
<extras.OrbitControls
|
|
2155
|
+
bind:ref={orbit_controls_ref}
|
|
2156
|
+
enableRotate
|
|
2157
|
+
enableZoom
|
|
2158
|
+
enablePan
|
|
2159
|
+
autoRotate={auto_rotate > 0 && page_visibility.visible}
|
|
2160
|
+
autoRotateSpeed={auto_rotate}
|
|
2161
|
+
target={camera_target}
|
|
2162
|
+
/>
|
|
2163
|
+
{/snippet}
|
|
2310
2164
|
<Canvas
|
|
2311
2165
|
createRenderer={(cvs) =>
|
|
2312
2166
|
new THREE.WebGLRenderer({
|
|
@@ -2326,15 +2180,7 @@
|
|
|
2326
2180
|
near={0.1}
|
|
2327
2181
|
far={data_extent * 10}
|
|
2328
2182
|
>
|
|
2329
|
-
|
|
2330
|
-
bind:ref={orbit_controls_ref}
|
|
2331
|
-
enableRotate
|
|
2332
|
-
enableZoom
|
|
2333
|
-
enablePan
|
|
2334
|
-
autoRotate={auto_rotate > 0}
|
|
2335
|
-
autoRotateSpeed={auto_rotate}
|
|
2336
|
-
target={camera_target}
|
|
2337
|
-
/>
|
|
2183
|
+
{@render orbit_controls()}
|
|
2338
2184
|
</T.OrthographicCamera>
|
|
2339
2185
|
{:else}
|
|
2340
2186
|
<T.PerspectiveCamera
|
|
@@ -2344,15 +2190,7 @@
|
|
|
2344
2190
|
near={0.1}
|
|
2345
2191
|
far={data_extent * 10}
|
|
2346
2192
|
>
|
|
2347
|
-
|
|
2348
|
-
bind:ref={orbit_controls_ref}
|
|
2349
|
-
enableRotate
|
|
2350
|
-
enableZoom
|
|
2351
|
-
enablePan
|
|
2352
|
-
autoRotate={auto_rotate > 0}
|
|
2353
|
-
autoRotateSpeed={auto_rotate}
|
|
2354
|
-
target={camera_target}
|
|
2355
|
-
/>
|
|
2193
|
+
{@render orbit_controls()}
|
|
2356
2194
|
</T.PerspectiveCamera>
|
|
2357
2195
|
{/if}
|
|
2358
2196
|
|
|
@@ -2484,7 +2322,9 @@
|
|
|
2484
2322
|
portal={wrapper}
|
|
2485
2323
|
zIndexRange={[1, 0]}
|
|
2486
2324
|
>
|
|
2487
|
-
<span class="axis-label" style:color={gc.color}
|
|
2325
|
+
<span class="axis-label" style:color={gc.color}
|
|
2326
|
+
>{@html sanitize_html(gc.label)}</span
|
|
2327
|
+
>
|
|
2488
2328
|
</extras.HTML>
|
|
2489
2329
|
{/if}
|
|
2490
2330
|
{/each}
|
|
@@ -2512,7 +2352,7 @@
|
|
|
2512
2352
|
</ChemPotScene3D>
|
|
2513
2353
|
</Canvas>
|
|
2514
2354
|
<!-- Color bar for continuous modes -->
|
|
2515
|
-
{#if
|
|
2355
|
+
{#if color_range}
|
|
2516
2356
|
{@const color_bar_config = get_chempot_color_bar_config(
|
|
2517
2357
|
color_scale,
|
|
2518
2358
|
reverse_color_scale,
|
|
@@ -2532,7 +2372,7 @@
|
|
|
2532
2372
|
<div class="arity-legend">
|
|
2533
2373
|
{#each arity_legend_labels as label, idx (label)}
|
|
2534
2374
|
<span>
|
|
2535
|
-
<span style:background={
|
|
2375
|
+
<span style:background={ARITY_COLORS[idx]}></span>
|
|
2536
2376
|
{label}
|
|
2537
2377
|
</span>
|
|
2538
2378
|
{/each}
|
|
@@ -1,24 +1,13 @@
|
|
|
1
1
|
// Async wrapper for compute_chempot_diagram via Web Worker.
|
|
2
2
|
// Falls back to synchronous main-thread computation during SSR.
|
|
3
|
-
import { compute_chempot_diagram,
|
|
3
|
+
import { compute_chempot_diagram, entry_fingerprint } from './compute';
|
|
4
4
|
import { to_error } from '../utils';
|
|
5
5
|
let worker = null;
|
|
6
6
|
let next_id = 0;
|
|
7
7
|
const pending = new Map();
|
|
8
8
|
const pending_by_key = new Map();
|
|
9
9
|
function make_compute_request_key(entries, config) {
|
|
10
|
-
|
|
11
|
-
.map((entry) => [
|
|
12
|
-
formula_key_from_composition(entry.composition),
|
|
13
|
-
entry.energy,
|
|
14
|
-
entry.energy_per_atom ?? ``,
|
|
15
|
-
entry.e_form_per_atom ?? ``,
|
|
16
|
-
entry.is_stable ?? ``,
|
|
17
|
-
entry.e_above_hull ?? ``,
|
|
18
|
-
entry.exclude_from_hull ?? ``,
|
|
19
|
-
].join(`:`))
|
|
20
|
-
.sort();
|
|
21
|
-
return `${keyed_entries.join(`,`)}|${JSON.stringify(config)}`;
|
|
10
|
+
return `${entries.map(entry_fingerprint).sort().join(`,`)}|${JSON.stringify(config)}`;
|
|
22
11
|
}
|
|
23
12
|
function track_pending(request_key, promise) {
|
|
24
13
|
pending_by_key.set(request_key, promise);
|
|
@@ -53,6 +42,16 @@ function get_worker() {
|
|
|
53
42
|
return worker;
|
|
54
43
|
}
|
|
55
44
|
export function compute_chempot_async(entries, config = {}) {
|
|
45
|
+
// Never throw synchronously: callers handle errors via .catch() only, so key
|
|
46
|
+
// construction or Worker instantiation failures (e.g. CSP) must reject instead
|
|
47
|
+
try {
|
|
48
|
+
return compute_chempot_async_unsafe(entries, config);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
return Promise.reject(to_error(err));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function compute_chempot_async_unsafe(entries, config) {
|
|
56
55
|
const request_key = make_compute_request_key(entries, config);
|
|
57
56
|
const existing = pending_by_key.get(request_key);
|
|
58
57
|
if (existing)
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import { type D3InterpolateName } from '../colors';
|
|
2
|
+
import type { PhaseData } from '../convex-hull/types';
|
|
2
3
|
import type { Vec2 } from '../math';
|
|
3
|
-
|
|
4
|
+
import { type FormulaEnergyStats } from './compute';
|
|
5
|
+
import type { ChemPotColorMode } from './types';
|
|
6
|
+
export declare const ARITY_COLORS: readonly ["#3498db", "#2ecc71", "#e67e22", "#9b59b6"];
|
|
4
7
|
export declare function get_chempot_color_bar_config(color_scale: D3InterpolateName, reverse: boolean): {
|
|
5
8
|
color_scale_fn: (frac: number) => string;
|
|
6
9
|
color_scale_domain: Vec2;
|
|
7
10
|
};
|
|
11
|
+
export interface ChemPotDomainColorData {
|
|
12
|
+
colors: Map<string, string>;
|
|
13
|
+
color_range: {
|
|
14
|
+
min: number;
|
|
15
|
+
max: number;
|
|
16
|
+
label: string;
|
|
17
|
+
} | null;
|
|
18
|
+
}
|
|
19
|
+
export declare function get_domain_color_data(opts: {
|
|
20
|
+
formulas: string[];
|
|
21
|
+
color_mode: ChemPotColorMode;
|
|
22
|
+
color_scale: D3InterpolateName;
|
|
23
|
+
reverse_color_scale: boolean;
|
|
24
|
+
entries: PhaseData[];
|
|
25
|
+
el_refs: Record<string, PhaseData>;
|
|
26
|
+
energy_stats: Map<string, FormulaEnergyStats>;
|
|
27
|
+
}): ChemPotDomainColorData;
|