matterviz 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MillerIndexInput.svelte +5 -5
- package/dist/api/optimade.js +3 -3
- package/dist/brillouin/BrillouinZone.svelte +5 -2
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
- package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
- package/dist/brillouin/compute.js +21 -21
- package/dist/brillouin/index.d.ts +1 -1
- package/dist/brillouin/index.js +0 -1
- package/dist/brillouin/types.d.ts +8 -13
- package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
- package/dist/chempot-diagram/compute.js +1 -7
- package/dist/chempot-diagram/temperature.d.ts +1 -1
- package/dist/chempot-diagram/temperature.js +1 -3
- package/dist/chempot-diagram/types.d.ts +4 -9
- package/dist/colors/index.js +5 -5
- package/dist/composition/Composition.svelte +2 -1
- package/dist/composition/Formula.svelte +7 -4
- package/dist/composition/FormulaFilter.svelte +1 -3
- package/dist/composition/format.js +4 -4
- package/dist/composition/parse.d.ts +2 -1
- package/dist/composition/parse.js +61 -46
- package/dist/convex-hull/ConvexHull2D.svelte +62 -51
- package/dist/convex-hull/ConvexHull3D.svelte +101 -90
- package/dist/convex-hull/ConvexHull4D.svelte +70 -58
- package/dist/convex-hull/ConvexHullControls.svelte +24 -35
- package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
- package/dist/convex-hull/ConvexHullStats.svelte +9 -2
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
- package/dist/convex-hull/GasPressureControls.svelte +7 -7
- package/dist/convex-hull/StructurePopup.svelte +65 -30
- package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
- package/dist/convex-hull/TemperatureSlider.svelte +8 -5
- package/dist/convex-hull/barycentric-coords.d.ts +2 -2
- package/dist/convex-hull/barycentric-coords.js +2 -2
- package/dist/convex-hull/gas-thermodynamics.js +2 -4
- package/dist/convex-hull/helpers.d.ts +13 -2
- package/dist/convex-hull/helpers.js +37 -16
- package/dist/convex-hull/index.d.ts +1 -0
- package/dist/convex-hull/index.js +1 -0
- package/dist/convex-hull/thermodynamics.d.ts +2 -1
- package/dist/convex-hull/thermodynamics.js +7 -7
- package/dist/convex-hull/types.d.ts +15 -15
- package/dist/effects.svelte.d.ts +12 -0
- package/dist/effects.svelte.js +37 -0
- package/dist/element/BohrAtom.svelte +4 -4
- package/dist/element/data.json.gz.d.ts +3 -1
- package/dist/element/index.d.ts +1 -1
- package/dist/element/index.js +0 -1
- package/dist/fermi-surface/FermiSurface.svelte +4 -4
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
- package/dist/fermi-surface/compute.js +2 -2
- package/dist/fermi-surface/export.js +13 -26
- package/dist/fermi-surface/parse.js +8 -12
- package/dist/fermi-surface/types.d.ts +2 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
- package/dist/heatmap-matrix/index.js +6 -6
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.js +1 -1
- package/dist/io/index.d.ts +1 -1
- package/dist/io/index.js +0 -1
- package/dist/io/url-drop.js +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +11 -25
- package/dist/isosurface/slice.js +1 -1
- package/dist/isosurface/types.js +12 -12
- package/dist/labels.d.ts +1 -1
- package/dist/labels.js +14 -11
- package/dist/layout/InfoTag.svelte +6 -4
- package/dist/layout/PropertyFilter.svelte +4 -2
- package/dist/layout/json-tree/JsonTree.svelte +22 -14
- package/dist/layout/json-tree/JsonValue.svelte +2 -2
- package/dist/layout/json-tree/types.d.ts +3 -2
- package/dist/layout/json-tree/types.js +0 -1
- package/dist/layout/json-tree/utils.d.ts +4 -4
- package/dist/layout/json-tree/utils.js +12 -20
- package/dist/marching-cubes.js +13 -15
- package/dist/math.d.ts +11 -1
- package/dist/math.js +15 -6
- package/dist/overlays/DragControlTab.svelte +98 -0
- package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
- package/dist/overlays/DraggablePane.svelte +7 -84
- package/dist/overlays/index.d.ts +1 -0
- package/dist/overlays/index.js +1 -0
- package/dist/periodic-table/PeriodicTable.svelte +11 -11
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
- package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
- package/dist/phase-diagram/build-diagram.js +11 -18
- package/dist/phase-diagram/diagram-input.d.ts +5 -9
- package/dist/phase-diagram/index.d.ts +2 -2
- package/dist/phase-diagram/index.js +0 -2
- package/dist/phase-diagram/parse.d.ts +2 -2
- package/dist/phase-diagram/parse.js +6 -10
- package/dist/phase-diagram/svg-to-diagram.js +15 -15
- package/dist/phase-diagram/types.d.ts +5 -11
- package/dist/phase-diagram/utils.d.ts +2 -2
- package/dist/phase-diagram/utils.js +9 -11
- package/dist/plot/BarPlot.svelte +162 -314
- package/dist/plot/BarPlot.svelte.d.ts +5 -4
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/BinnedScatterPlot.svelte +1114 -0
- package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
- package/dist/plot/ColorBar.svelte +19 -17
- package/dist/plot/ColorBar.svelte.d.ts +1 -1
- package/dist/plot/FillArea.svelte +2 -4
- package/dist/plot/FillArea.svelte.d.ts +1 -1
- package/dist/plot/Histogram.svelte +167 -281
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +5 -3
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/PlotAxis.svelte +169 -0
- package/dist/plot/PlotAxis.svelte.d.ts +24 -0
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/ReferenceLine3D.svelte +53 -51
- package/dist/plot/ReferencePlane.svelte +39 -42
- package/dist/plot/ScatterPlot.svelte +300 -367
- package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
- package/dist/plot/ScatterPlot3D.svelte +33 -6
- package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
- package/dist/plot/ScatterPlot3DControls.svelte +9 -9
- package/dist/plot/ScatterPlotControls.svelte +3 -4
- package/dist/plot/ScatterPoint.svelte +18 -27
- package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
- package/dist/plot/Surface3D.svelte +4 -7
- package/dist/plot/ZeroLines.svelte +2 -1
- package/dist/plot/ZeroLines.svelte.d.ts +2 -1
- package/dist/plot/ZoomRect.svelte +2 -2
- package/dist/plot/ZoomRect.svelte.d.ts +3 -3
- package/dist/plot/adaptive-density.d.ts +69 -0
- package/dist/plot/adaptive-density.js +191 -0
- package/dist/plot/auto-place.d.ts +43 -0
- package/dist/plot/auto-place.js +122 -0
- package/dist/plot/axis-utils.js +3 -5
- package/dist/plot/binned-scatter-types.d.ts +59 -0
- package/dist/plot/binned-scatter-types.js +1 -0
- package/dist/plot/data-cleaning.js +1 -1
- package/dist/plot/data-transform.js +1 -1
- package/dist/plot/fill-utils.d.ts +4 -9
- package/dist/plot/fill-utils.js +29 -44
- package/dist/plot/index.d.ts +4 -0
- package/dist/plot/index.js +2 -0
- package/dist/plot/interactions.d.ts +4 -4
- package/dist/plot/interactions.js +4 -3
- package/dist/plot/layout.d.ts +20 -2
- package/dist/plot/layout.js +59 -16
- package/dist/plot/reference-line.d.ts +1 -1
- package/dist/plot/reference-line.js +9 -11
- package/dist/plot/scales.d.ts +1 -1
- package/dist/plot/scales.js +20 -23
- package/dist/plot/types.d.ts +30 -58
- package/dist/plot/types.js +2 -6
- package/dist/plot/utils/label-placement.d.ts +24 -3
- package/dist/plot/utils/label-placement.js +82 -12
- package/dist/plot/utils/series-visibility.d.ts +8 -2
- package/dist/plot/utils/series-visibility.js +23 -5
- package/dist/rdf/RdfPlot.svelte +5 -5
- package/dist/rdf/calc-rdf.js +3 -3
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.js +2 -0
- package/dist/spectral/Bands.svelte +1 -1
- package/dist/spectral/BandsAndDos.svelte +22 -16
- package/dist/spectral/BrillouinBandsDos.svelte +20 -16
- package/dist/spectral/Dos.svelte +1 -1
- package/dist/spectral/helpers.d.ts +4 -2
- package/dist/spectral/helpers.js +44 -35
- package/dist/spectral/index.d.ts +1 -1
- package/dist/spectral/index.js +0 -1
- package/dist/structure/AtomLegend.svelte +23 -6
- package/dist/structure/AtomLegend.svelte.d.ts +1 -0
- package/dist/structure/CanvasTooltip.svelte +9 -9
- package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
- package/dist/structure/CellSelect.svelte +14 -16
- package/dist/structure/Structure.svelte +317 -68
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureControls.svelte +20 -45
- package/dist/structure/StructureExportPane.svelte +2 -1
- package/dist/structure/StructureInfoPane.svelte +10 -8
- package/dist/structure/StructureScene.svelte +527 -177
- package/dist/structure/StructureScene.svelte.d.ts +5 -2
- package/dist/structure/atom-properties.js +4 -4
- package/dist/structure/bond-order-perception.js +115 -98
- package/dist/structure/bonding.d.ts +27 -1
- package/dist/structure/bonding.js +187 -16
- package/dist/structure/export.js +1 -1
- package/dist/structure/index.d.ts +3 -2
- package/dist/structure/index.js +0 -2
- package/dist/structure/parse.js +88 -59
- package/dist/symmetry/WyckoffTable.svelte +7 -0
- package/dist/symmetry/index.js +13 -14
- package/dist/table/HeatmapTable.svelte +45 -66
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +19 -10
- package/dist/theme/themes.mjs +12 -0
- package/dist/tooltip/index.d.ts +1 -1
- package/dist/tooltip/index.js +0 -1
- package/dist/trajectory/Trajectory.svelte +43 -15
- package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
- package/dist/trajectory/extract.js +1 -1
- package/dist/trajectory/frame-reader.js +4 -4
- package/dist/trajectory/helpers.d.ts +5 -4
- package/dist/trajectory/helpers.js +9 -17
- package/dist/trajectory/index.d.ts +2 -2
- package/dist/trajectory/index.js +2 -2
- package/dist/trajectory/parse/ase.js +4 -4
- package/dist/trajectory/parse/hdf5.js +1 -1
- package/dist/trajectory/parse/index.js +2 -3
- package/dist/trajectory/parse/lammps.js +1 -1
- package/dist/trajectory/parse/vasp.js +1 -1
- package/dist/trajectory/plotting.d.ts +1 -1
- package/dist/trajectory/plotting.js +38 -38
- package/dist/trajectory/types.d.ts +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +9 -0
- package/dist/xrd/calc-xrd.js +3 -4
- package/dist/xrd/parse.js +1 -1
- package/package.json +42 -22
|
@@ -9,10 +9,8 @@
|
|
|
9
9
|
vesta_hex,
|
|
10
10
|
watch_dark_mode,
|
|
11
11
|
} from '../colors'
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
type FormulaLabelSegment,
|
|
15
|
-
} from '../composition/format'
|
|
12
|
+
import { get_formula_label_segments } from '../composition/format'
|
|
13
|
+
import type { FormulaLabelSegment } from '../composition/format'
|
|
16
14
|
import { normalize_show_controls } from '../controls'
|
|
17
15
|
import { sanitize_html } from '../sanitize'
|
|
18
16
|
import { ClickFeedback, DragOverlay, Spinner } from '../feedback'
|
|
@@ -23,15 +21,11 @@
|
|
|
23
21
|
setup_fullscreen_effect,
|
|
24
22
|
toggle_fullscreen,
|
|
25
23
|
} from '../layout'
|
|
26
|
-
import { to_radians, type Vec3 } from '../math'
|
|
24
|
+
import { to_radians, type Point3D, type Vec3 } from '../math'
|
|
27
25
|
import { ColorBar, PlotTooltip } from '../plot'
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
rects_overlap,
|
|
32
|
-
rect_within_rect,
|
|
33
|
-
type Rect,
|
|
34
|
-
} from '../plot/layout'
|
|
26
|
+
import { centered_rect, pad_rect, rects_overlap, rect_within_rect } from '../plot/layout'
|
|
27
|
+
import type { Rect } from '../plot/layout'
|
|
28
|
+
import { create_pulse_animation } from '../effects.svelte'
|
|
35
29
|
import { DEFAULTS } from '../settings'
|
|
36
30
|
import type { AnyStructure } from '../structure'
|
|
37
31
|
import { Canvas, T } from '@threlte/core'
|
|
@@ -63,7 +57,6 @@
|
|
|
63
57
|
HoverData3D,
|
|
64
58
|
HullFaceColorMode,
|
|
65
59
|
LabelPlacement,
|
|
66
|
-
Point3D,
|
|
67
60
|
} from './types'
|
|
68
61
|
import { compute_hull_stability } from './helpers'
|
|
69
62
|
|
|
@@ -240,9 +233,9 @@
|
|
|
240
233
|
const hull_faces = $derived.by((): ConvexHullTriangle[] => {
|
|
241
234
|
if (coords_entries.length === 0) return []
|
|
242
235
|
// Excluded entries don't participate in hull construction
|
|
243
|
-
const hull_entries = coords_entries.filter((
|
|
236
|
+
const hull_entries = coords_entries.filter((entry) => !entry.exclude_from_hull)
|
|
244
237
|
if (hull_entries.length === 0) return []
|
|
245
|
-
const points = hull_entries.map((
|
|
238
|
+
const points = hull_entries.map(({ x, y, z }) => ({ x, y, z }))
|
|
246
239
|
try {
|
|
247
240
|
return thermo.compute_lower_hull_triangles(points)
|
|
248
241
|
} catch (error) {
|
|
@@ -258,7 +251,7 @@
|
|
|
258
251
|
const all_enriched_entries = $derived.by(() => {
|
|
259
252
|
if (coords_entries.length === 0) return []
|
|
260
253
|
if (energy_mode !== `on-the-fly`) return coords_entries
|
|
261
|
-
const pts = coords_entries.map((
|
|
254
|
+
const pts = coords_entries.map(({ x, y, z }) => ({ x, y, z }))
|
|
262
255
|
const raw_dists = thermo.compute_e_above_hull_for_points(pts, hull_model)
|
|
263
256
|
return coords_entries.map((entry, idx) => ({
|
|
264
257
|
...entry, ...compute_hull_stability(raw_dists[idx], entry.exclude_from_hull),
|
|
@@ -275,34 +268,32 @@
|
|
|
275
268
|
DEFAULTS.convex_hull.ternary.max_hull_dist_show_phases,
|
|
276
269
|
))
|
|
277
270
|
|
|
278
|
-
|
|
279
|
-
|
|
271
|
+
const next_auto_threshold = helpers.auto_threshold_reset(
|
|
272
|
+
DEFAULTS.convex_hull.ternary.max_hull_dist_show_phases,
|
|
273
|
+
)
|
|
280
274
|
$effect(() => {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
max_hull_dist_show_phases
|
|
284
|
-
|
|
275
|
+
max_hull_dist_show_phases = next_auto_threshold(
|
|
276
|
+
entries,
|
|
277
|
+
max_hull_dist_show_phases,
|
|
278
|
+
auto_default_threshold,
|
|
279
|
+
) ?? max_hull_dist_show_phases
|
|
285
280
|
})
|
|
286
281
|
|
|
287
|
-
// Filter by threshold
|
|
282
|
+
// Filter by threshold; visibility is a view predicate, not entry state.
|
|
288
283
|
const plot_entries = $derived(
|
|
289
|
-
all_enriched_entries
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
...e,
|
|
293
|
-
visible: ((e.is_stable || e.e_above_hull === 0) && show_stable) ||
|
|
294
|
-
(!(e.is_stable || e.e_above_hull === 0) && show_unstable),
|
|
295
|
-
})),
|
|
284
|
+
all_enriched_entries.filter((entry) =>
|
|
285
|
+
(entry.e_above_hull ?? 0) <= max_hull_dist_show_phases
|
|
286
|
+
),
|
|
296
287
|
)
|
|
288
|
+
const visible_entries = $derived(helpers.visible_entries(
|
|
289
|
+
plot_entries,
|
|
290
|
+
show_stable,
|
|
291
|
+
show_unstable,
|
|
292
|
+
))
|
|
297
293
|
|
|
298
294
|
$effect(() => {
|
|
299
|
-
stable_entries = plot_entries.filter(
|
|
300
|
-
|
|
301
|
-
)
|
|
302
|
-
unstable_entries = plot_entries.filter((entry: ConvexHullEntry) =>
|
|
303
|
-
typeof entry.e_above_hull === `number` && entry.e_above_hull > 0 &&
|
|
304
|
-
!entry.is_stable
|
|
305
|
-
)
|
|
295
|
+
stable_entries = plot_entries.filter(helpers.entry_is_stable)
|
|
296
|
+
unstable_entries = plot_entries.filter(helpers.entry_is_unstable)
|
|
306
297
|
})
|
|
307
298
|
|
|
308
299
|
// Canvas rendering
|
|
@@ -311,7 +302,6 @@
|
|
|
311
302
|
|
|
312
303
|
// Performance optimization
|
|
313
304
|
let frame_id = 0
|
|
314
|
-
let pulse_frame_id = 0
|
|
315
305
|
|
|
316
306
|
const camera_default = {
|
|
317
307
|
elevation: DEFAULTS.convex_hull.ternary.camera_elevation,
|
|
@@ -442,13 +432,39 @@
|
|
|
442
432
|
let modal_open = $state(false)
|
|
443
433
|
let selected_structure = $state<AnyStructure | null>(null)
|
|
444
434
|
let modal_place_right = $state(true)
|
|
435
|
+
$effect(() => {
|
|
436
|
+
const current_selection = helpers.current_entry(selected_entry, plot_entries)
|
|
437
|
+
const stale_selection = selected_entry && !current_selection
|
|
438
|
+
if (stale_selection) selected_entry = null
|
|
439
|
+
else if (current_selection && current_selection !== selected_entry) {
|
|
440
|
+
selected_entry = current_selection
|
|
441
|
+
}
|
|
442
|
+
const current_hover = helpers.current_entry(hover_data?.entry, plot_entries)
|
|
443
|
+
if (hover_data?.entry && !current_hover) {
|
|
444
|
+
hover_data = null
|
|
445
|
+
on_point_hover?.(null)
|
|
446
|
+
} else if (hover_data && current_hover && current_hover !== hover_data.entry) {
|
|
447
|
+
hover_data = { ...hover_data, entry: current_hover }
|
|
448
|
+
}
|
|
449
|
+
if (modal_open) {
|
|
450
|
+
const structure = current_selection && extract_structure_from_entry(current_selection)
|
|
451
|
+
if (structure) selected_structure = structure
|
|
452
|
+
else {
|
|
453
|
+
modal_open = false
|
|
454
|
+
selected_structure = null
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
})
|
|
445
458
|
|
|
446
459
|
// Hull face color (customizable via controls)
|
|
447
460
|
let hull_face_color = $state(`#4caf50`)
|
|
448
461
|
|
|
449
462
|
// Pulsating highlight for selected point
|
|
450
|
-
|
|
451
|
-
|
|
463
|
+
const pulse = create_pulse_animation(
|
|
464
|
+
() => selected_entry !== null || highlighted_entries.length > 0,
|
|
465
|
+
{ on_tick: render_once },
|
|
466
|
+
)
|
|
467
|
+
let pulse_opacity = $derived(0.3 + 0.4 * pulse.unit)
|
|
452
468
|
|
|
453
469
|
// Merge highlight style with defaults
|
|
454
470
|
const merged_highlight_style = $derived(
|
|
@@ -459,19 +475,6 @@
|
|
|
459
475
|
const is_highlighted = (entry: ConvexHullEntry): boolean =>
|
|
460
476
|
helpers.is_entry_highlighted(entry, highlighted_entries)
|
|
461
477
|
|
|
462
|
-
$effect(() => {
|
|
463
|
-
if (!selected_entry && !highlighted_entries.length) return
|
|
464
|
-
const animate = () => {
|
|
465
|
-
pulse_time += 0.02
|
|
466
|
-
render_once()
|
|
467
|
-
pulse_frame_id = requestAnimationFrame(animate)
|
|
468
|
-
}
|
|
469
|
-
pulse_frame_id = requestAnimationFrame(animate)
|
|
470
|
-
return () => {
|
|
471
|
-
if (pulse_frame_id) cancelAnimationFrame(pulse_frame_id)
|
|
472
|
-
}
|
|
473
|
-
})
|
|
474
|
-
|
|
475
478
|
// Re-render when important state changes
|
|
476
479
|
$effect(() => {
|
|
477
480
|
// oxfmt-ignore
|
|
@@ -511,8 +514,8 @@
|
|
|
511
514
|
}
|
|
512
515
|
|
|
513
516
|
const handle_keydown = (event: KeyboardEvent) => {
|
|
514
|
-
const target = event.target
|
|
515
|
-
if (target.tagName.match(/INPUT|TEXTAREA/)) return
|
|
517
|
+
const target = event.target
|
|
518
|
+
if (target instanceof HTMLElement && target.tagName.match(/INPUT|TEXTAREA/)) return
|
|
516
519
|
|
|
517
520
|
// Stop propagation if event came from canvas to prevent wrapper's handler
|
|
518
521
|
// from running again (both have onkeydown, causing duplicate handling)
|
|
@@ -796,25 +799,32 @@
|
|
|
796
799
|
if (!ctx || !show_hull_faces || hull_faces.length === 0) return
|
|
797
800
|
|
|
798
801
|
// Lazy computation for uniform mode: normalize alpha by formation energy
|
|
799
|
-
let norm_alpha: ((
|
|
802
|
+
let norm_alpha: ((e_form: number) => number) | null = null
|
|
800
803
|
if (hull_face_color_mode === `uniform`) {
|
|
801
|
-
const
|
|
802
|
-
norm_alpha = (
|
|
803
|
-
const
|
|
804
|
-
|
|
804
|
+
const min_uniform_e_form = energy_range.min
|
|
805
|
+
norm_alpha = (e_form: number) => {
|
|
806
|
+
const alpha_fraction = Math.max(
|
|
807
|
+
0,
|
|
808
|
+
Math.min(1, (0 - e_form) / Math.max(1e-6, 0 - min_uniform_e_form)),
|
|
809
|
+
)
|
|
810
|
+
return alpha_fraction * hull_face_opacity
|
|
805
811
|
}
|
|
806
812
|
}
|
|
807
813
|
|
|
808
814
|
// Lazy computation for formation_energy mode
|
|
809
815
|
let energy_face_scale: ((val: number) => string) | null = null
|
|
810
|
-
let
|
|
816
|
+
let min_face_e_form = 0
|
|
811
817
|
if (hull_face_color_mode === `formation_energy`) {
|
|
812
|
-
const
|
|
813
|
-
|
|
818
|
+
const all_e_form = hull_faces.flatMap((tri) =>
|
|
819
|
+
tri.vertices.map((vertex) => vertex.z)
|
|
820
|
+
)
|
|
821
|
+
min_face_e_form = Math.min(...all_e_form)
|
|
814
822
|
energy_face_scale = helpers.get_energy_color_scale(
|
|
815
823
|
`energy`,
|
|
816
824
|
color_scale,
|
|
817
|
-
|
|
825
|
+
all_e_form.map((e_form) => ({
|
|
826
|
+
e_above_hull: e_form - min_face_e_form,
|
|
827
|
+
})), // Normalize to 0-based
|
|
818
828
|
)
|
|
819
829
|
}
|
|
820
830
|
|
|
@@ -827,8 +837,8 @@
|
|
|
827
837
|
return hull_face_color
|
|
828
838
|
}
|
|
829
839
|
if (hull_face_color_mode === `formation_energy`) {
|
|
830
|
-
const
|
|
831
|
-
return energy_face_scale?.(
|
|
840
|
+
const avg_e_form = (tri.vertices[0].z + tri.vertices[1].z + tri.vertices[2].z) / 3
|
|
841
|
+
return energy_face_scale?.(avg_e_form - min_face_e_form) ?? hull_face_color
|
|
832
842
|
}
|
|
833
843
|
if (hull_face_color_mode === `dominant_element`) {
|
|
834
844
|
// Find element vertex closest to face centroid in 2D ternary space
|
|
@@ -855,7 +865,7 @@
|
|
|
855
865
|
return { tri, tri_idx, depth: centroid_proj.depth }
|
|
856
866
|
})
|
|
857
867
|
|
|
858
|
-
faces_with_depth.sort((
|
|
868
|
+
faces_with_depth.sort((left, right) => left.depth - right.depth) // Back to front
|
|
859
869
|
|
|
860
870
|
// Draw each face (lower hull only)
|
|
861
871
|
for (const { tri, tri_idx } of faces_with_depth) {
|
|
@@ -962,8 +972,8 @@
|
|
|
962
972
|
const denom = Math.max(1e-6, max_fe - min_fe)
|
|
963
973
|
return (value: number) => {
|
|
964
974
|
// alpha 0 at 0 eV, goes to hull_face_opacity at most negative energy
|
|
965
|
-
const
|
|
966
|
-
const alpha = (1 -
|
|
975
|
+
const energy_fraction = Math.max(0, Math.min(1, (value - min_fe) / denom))
|
|
976
|
+
const alpha = (1 - energy_fraction) * hull_face_opacity
|
|
967
977
|
return add_alpha(hull_face_color, alpha)
|
|
968
978
|
}
|
|
969
979
|
})
|
|
@@ -972,7 +982,7 @@
|
|
|
972
982
|
if (!ctx || sorted_points_cache.length === 0) return
|
|
973
983
|
|
|
974
984
|
for (const { entry, projected } of sorted_points_cache) {
|
|
975
|
-
const is_stable =
|
|
985
|
+
const is_stable = helpers.entry_is_stable(entry)
|
|
976
986
|
const is_entry_highlighted = is_highlighted(entry)
|
|
977
987
|
const color = get_point_color(entry)
|
|
978
988
|
const size = (entry.size || (is_stable ? 6 : 4)) * canvas_dims.scale
|
|
@@ -994,7 +1004,7 @@
|
|
|
994
1004
|
projected,
|
|
995
1005
|
size,
|
|
996
1006
|
canvas_dims.scale,
|
|
997
|
-
|
|
1007
|
+
pulse.time,
|
|
998
1008
|
pulse_opacity,
|
|
999
1009
|
)
|
|
1000
1010
|
}
|
|
@@ -1004,7 +1014,7 @@
|
|
|
1004
1014
|
projected,
|
|
1005
1015
|
size,
|
|
1006
1016
|
canvas_dims.scale,
|
|
1007
|
-
|
|
1017
|
+
pulse.time,
|
|
1008
1018
|
merged_highlight_style,
|
|
1009
1019
|
)
|
|
1010
1020
|
}
|
|
@@ -1120,9 +1130,9 @@
|
|
|
1120
1130
|
const label_height = hull_label_font_size + 2
|
|
1121
1131
|
|
|
1122
1132
|
const label_entries = helpers.get_composition_label_entries(
|
|
1123
|
-
|
|
1124
|
-
if (
|
|
1125
|
-
const is_stable_point =
|
|
1133
|
+
visible_entries.filter((entry) => {
|
|
1134
|
+
if (entry.is_element) return false
|
|
1135
|
+
const is_stable_point = helpers.entry_is_stable(entry)
|
|
1126
1136
|
return (is_stable_point && show_stable_labels) ||
|
|
1127
1137
|
(!is_stable_point && show_unstable_labels &&
|
|
1128
1138
|
(entry.e_above_hull ?? 0) <= max_hull_dist_show_labels)
|
|
@@ -1147,7 +1157,7 @@
|
|
|
1147
1157
|
const formula_segments = get_formula_label_segments(
|
|
1148
1158
|
helpers.get_entry_label(entry, elements),
|
|
1149
1159
|
)
|
|
1150
|
-
const is_stable_point =
|
|
1160
|
+
const is_stable_point = helpers.entry_is_stable(entry)
|
|
1151
1161
|
const point_size = (entry.size || (is_stable_point ? 6 : 4)) * canvas_dims.scale
|
|
1152
1162
|
const text_width = measure_formula_segments(ctx, formula_segments)
|
|
1153
1163
|
const placements = get_label_placements(
|
|
@@ -1257,7 +1267,7 @@
|
|
|
1257
1267
|
helpers.find_hull_entry_at_mouse(
|
|
1258
1268
|
canvas,
|
|
1259
1269
|
event,
|
|
1260
|
-
|
|
1270
|
+
visible_entries,
|
|
1261
1271
|
(x: number, y: number, z: number) => {
|
|
1262
1272
|
const pt = project_3d_point(x, y, z)
|
|
1263
1273
|
return { x: pt.x, y: pt.y }
|
|
@@ -1308,7 +1318,7 @@
|
|
|
1308
1318
|
}
|
|
1309
1319
|
}
|
|
1310
1320
|
|
|
1311
|
-
|
|
1321
|
+
function render_once() {
|
|
1312
1322
|
if (!frame_id) {
|
|
1313
1323
|
frame_id = requestAnimationFrame(() => {
|
|
1314
1324
|
render_frame()
|
|
@@ -1363,7 +1373,6 @@
|
|
|
1363
1373
|
|
|
1364
1374
|
return () => { // Cleanup on unmount
|
|
1365
1375
|
if (frame_id) cancelAnimationFrame(frame_id)
|
|
1366
|
-
if (pulse_frame_id) cancelAnimationFrame(pulse_frame_id)
|
|
1367
1376
|
resize_observer.disconnect()
|
|
1368
1377
|
}
|
|
1369
1378
|
})
|
|
@@ -1386,7 +1395,7 @@
|
|
|
1386
1395
|
const energy_range = $derived.by(() => {
|
|
1387
1396
|
let min = 0
|
|
1388
1397
|
let max = 0
|
|
1389
|
-
for (const entry of
|
|
1398
|
+
for (const entry of all_enriched_entries) {
|
|
1390
1399
|
const energy = entry.e_form_per_atom ?? 0
|
|
1391
1400
|
min = Math.min(min, energy)
|
|
1392
1401
|
max = Math.max(max, energy)
|
|
@@ -1397,14 +1406,13 @@
|
|
|
1397
1406
|
|
|
1398
1407
|
// Performance: Pre-compute and cache all point projections + depth sorting
|
|
1399
1408
|
const sorted_points_cache = $derived.by(() => {
|
|
1400
|
-
if (!canvas ||
|
|
1401
|
-
return
|
|
1402
|
-
.filter((entry) => entry.visible)
|
|
1409
|
+
if (!canvas || visible_entries.length === 0) return []
|
|
1410
|
+
return visible_entries
|
|
1403
1411
|
.map((entry) => ({
|
|
1404
1412
|
entry,
|
|
1405
1413
|
projected: project_3d_point(entry.x, entry.y, entry.z),
|
|
1406
1414
|
}))
|
|
1407
|
-
.sort((
|
|
1415
|
+
.sort((left, right) => left.projected.depth - right.projected.depth)
|
|
1408
1416
|
})
|
|
1409
1417
|
|
|
1410
1418
|
let style = $derived(
|
|
@@ -1479,8 +1487,8 @@
|
|
|
1479
1487
|
<!-- Formation Energy Color Bar (bottom-left corner) -->
|
|
1480
1488
|
{#if color_mode === `energy` && plot_entries.length > 0}
|
|
1481
1489
|
{@const hull_distances = plot_entries
|
|
1482
|
-
.map((
|
|
1483
|
-
.filter((
|
|
1490
|
+
.map((entry) => entry.e_above_hull)
|
|
1491
|
+
.filter((value): value is number => typeof value === `number`)}
|
|
1484
1492
|
{@const min_energy = hull_distances.length > 0 ? Math.min(...hull_distances) : 0}
|
|
1485
1493
|
{@const max_energy = hull_distances.length > 0 ? Math.max(...hull_distances, 0.1) : 0.1}
|
|
1486
1494
|
<ColorBar
|
|
@@ -1529,6 +1537,8 @@
|
|
|
1529
1537
|
{phase_stats}
|
|
1530
1538
|
{stable_entries}
|
|
1531
1539
|
{unstable_entries}
|
|
1540
|
+
{show_stable}
|
|
1541
|
+
{show_unstable}
|
|
1532
1542
|
{max_hull_dist_show_phases}
|
|
1533
1543
|
{max_hull_dist_show_labels}
|
|
1534
1544
|
{label_threshold}
|
|
@@ -1566,13 +1576,14 @@
|
|
|
1566
1576
|
{merged_controls}
|
|
1567
1577
|
toggle_props={{ class: `legend-controls-btn` }}
|
|
1568
1578
|
{show_hull_faces}
|
|
1569
|
-
on_hull_faces_change={(value) => show_hull_faces = value}
|
|
1579
|
+
on_hull_faces_change={(value: boolean) => show_hull_faces = value}
|
|
1570
1580
|
{hull_face_color}
|
|
1571
|
-
on_hull_face_color_change={(value) => hull_face_color = value}
|
|
1581
|
+
on_hull_face_color_change={(value: string) => hull_face_color = value}
|
|
1572
1582
|
{hull_face_opacity}
|
|
1573
|
-
on_hull_face_opacity_change={(value) => hull_face_opacity = value}
|
|
1583
|
+
on_hull_face_opacity_change={(value: number) => hull_face_opacity = value}
|
|
1574
1584
|
{hull_face_color_mode}
|
|
1575
|
-
on_hull_face_color_mode_change={(value) =>
|
|
1585
|
+
on_hull_face_color_mode_change={(value: HullFaceColorMode) =>
|
|
1586
|
+
hull_face_color_mode = value}
|
|
1576
1587
|
bind:energy_source_mode
|
|
1577
1588
|
{has_precomputed_e_form}
|
|
1578
1589
|
{can_compute_e_form}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
toggle_fullscreen,
|
|
18
18
|
} from '../layout'
|
|
19
19
|
import { ColorBar, PlotTooltip } from '../plot'
|
|
20
|
+
import { create_pulse_animation } from '../effects.svelte'
|
|
20
21
|
import { DEFAULTS } from '../settings'
|
|
21
22
|
import type { AnyStructure } from '../structure'
|
|
22
23
|
import {
|
|
@@ -276,39 +277,36 @@
|
|
|
276
277
|
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases,
|
|
277
278
|
))
|
|
278
279
|
|
|
279
|
-
|
|
280
|
-
|
|
280
|
+
const next_auto_threshold = helpers.auto_threshold_reset(
|
|
281
|
+
DEFAULTS.convex_hull.quaternary.max_hull_dist_show_phases,
|
|
282
|
+
)
|
|
281
283
|
$effect(() => {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
max_hull_dist_show_phases
|
|
285
|
-
|
|
284
|
+
max_hull_dist_show_phases = next_auto_threshold(
|
|
285
|
+
entries,
|
|
286
|
+
max_hull_dist_show_phases,
|
|
287
|
+
auto_default_threshold,
|
|
288
|
+
) ?? max_hull_dist_show_phases
|
|
286
289
|
})
|
|
287
290
|
|
|
288
|
-
// Filter by threshold
|
|
291
|
+
// Filter by threshold; visibility is a view predicate, not entry state.
|
|
289
292
|
const plot_entries = $derived(
|
|
290
293
|
all_enriched_entries.filter((entry) => {
|
|
291
294
|
// Always include stable entries and elemental reference points
|
|
292
|
-
if (
|
|
295
|
+
if (helpers.entry_is_stable(entry)) return true
|
|
293
296
|
return typeof entry.e_above_hull === `number` &&
|
|
294
297
|
entry.e_above_hull <= max_hull_dist_show_phases
|
|
295
|
-
}).map((entry) => {
|
|
296
|
-
const is_stable = entry.is_stable || entry.e_above_hull === 0
|
|
297
|
-
return {
|
|
298
|
-
...entry,
|
|
299
|
-
visible: (is_stable && show_stable) || (!is_stable && show_unstable),
|
|
300
|
-
}
|
|
301
298
|
}),
|
|
302
299
|
)
|
|
300
|
+
const visible_entries = $derived(helpers.visible_entries(
|
|
301
|
+
plot_entries,
|
|
302
|
+
show_stable,
|
|
303
|
+
show_unstable,
|
|
304
|
+
))
|
|
303
305
|
|
|
304
306
|
// Stable and unstable entries exposed as bindable props
|
|
305
307
|
$effect(() => {
|
|
306
|
-
stable_entries = plot_entries.filter(
|
|
307
|
-
|
|
308
|
-
)
|
|
309
|
-
unstable_entries = plot_entries.filter((entry: ConvexHullEntry) =>
|
|
310
|
-
(entry.e_above_hull ?? 0) > 0 && !entry.is_stable
|
|
311
|
-
)
|
|
308
|
+
stable_entries = plot_entries.filter(helpers.entry_is_stable)
|
|
309
|
+
unstable_entries = plot_entries.filter(helpers.entry_is_unstable)
|
|
312
310
|
})
|
|
313
311
|
|
|
314
312
|
let canvas: HTMLCanvasElement | undefined = undefined
|
|
@@ -338,14 +336,39 @@
|
|
|
338
336
|
let modal_open = $state(false)
|
|
339
337
|
let selected_structure = $state<AnyStructure | null>(null)
|
|
340
338
|
let modal_place_right = $state(true)
|
|
339
|
+
$effect(() => {
|
|
340
|
+
const current_selection = helpers.current_entry(selected_entry, plot_entries)
|
|
341
|
+
const stale_selection = selected_entry && !current_selection
|
|
342
|
+
if (stale_selection) selected_entry = null
|
|
343
|
+
else if (current_selection && current_selection !== selected_entry) {
|
|
344
|
+
selected_entry = current_selection
|
|
345
|
+
}
|
|
346
|
+
const current_hover = helpers.current_entry(hover_data?.entry, plot_entries)
|
|
347
|
+
if (hover_data?.entry && !current_hover) {
|
|
348
|
+
hover_data = null
|
|
349
|
+
on_point_hover?.(null)
|
|
350
|
+
} else if (hover_data && current_hover && current_hover !== hover_data.entry) {
|
|
351
|
+
hover_data = { ...hover_data, entry: current_hover }
|
|
352
|
+
}
|
|
353
|
+
if (modal_open) {
|
|
354
|
+
const structure = current_selection && extract_structure_from_entry(current_selection)
|
|
355
|
+
if (structure) selected_structure = structure
|
|
356
|
+
else {
|
|
357
|
+
modal_open = false
|
|
358
|
+
selected_structure = null
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
})
|
|
341
362
|
|
|
342
363
|
// Hull face color (customizable via controls)
|
|
343
364
|
let hull_face_color = $state(`#4caf50`)
|
|
344
365
|
|
|
345
366
|
// Pulsating highlight for selected point and highlighted entries
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
367
|
+
const pulse = create_pulse_animation(
|
|
368
|
+
() => selected_entry !== null || highlighted_entries.length > 0,
|
|
369
|
+
{ on_tick: render_once },
|
|
370
|
+
)
|
|
371
|
+
let pulse_opacity = $derived(0.3 + 0.4 * pulse.unit)
|
|
349
372
|
|
|
350
373
|
// Merge highlight style with defaults
|
|
351
374
|
const merged_highlight_style = $derived(
|
|
@@ -356,21 +379,6 @@
|
|
|
356
379
|
const is_highlighted = (entry: ConvexHullEntry): boolean =>
|
|
357
380
|
helpers.is_entry_highlighted(entry, highlighted_entries)
|
|
358
381
|
|
|
359
|
-
$effect(() => {
|
|
360
|
-
if (!selected_entry && !highlighted_entries.length) return
|
|
361
|
-
const reduce = globalThis.matchMedia?.(`(prefers-reduced-motion: reduce)`).matches
|
|
362
|
-
if (reduce) return
|
|
363
|
-
const animate = () => {
|
|
364
|
-
pulse_time += 0.02
|
|
365
|
-
render_once()
|
|
366
|
-
pulse_frame_id = requestAnimationFrame(animate)
|
|
367
|
-
}
|
|
368
|
-
pulse_frame_id = requestAnimationFrame(animate)
|
|
369
|
-
return () => {
|
|
370
|
-
if (pulse_frame_id) cancelAnimationFrame(pulse_frame_id)
|
|
371
|
-
}
|
|
372
|
-
})
|
|
373
|
-
|
|
374
382
|
// Re-render when important state changes
|
|
375
383
|
$effect(() => {
|
|
376
384
|
// oxfmt-ignore
|
|
@@ -432,11 +440,15 @@
|
|
|
432
440
|
}
|
|
433
441
|
|
|
434
442
|
const handle_keydown = (event: KeyboardEvent) => {
|
|
435
|
-
const target = event.target
|
|
443
|
+
const target = event.target
|
|
436
444
|
// Skip if focus is on an interactive element that handles Enter natively
|
|
437
445
|
const interactive_selector =
|
|
438
446
|
`input,textarea,select,button,a,[contenteditable="true"],[role="button"],[tabindex]:not([tabindex="-1"])`
|
|
439
|
-
if (
|
|
447
|
+
if (
|
|
448
|
+
target instanceof HTMLElement &&
|
|
449
|
+
target.matches(interactive_selector) &&
|
|
450
|
+
target !== canvas
|
|
451
|
+
) return
|
|
440
452
|
|
|
441
453
|
// Prevent double handling from canvas + wrapper bubbling
|
|
442
454
|
if (event.target !== event.currentTarget && event.currentTarget !== canvas) return
|
|
@@ -640,9 +652,7 @@
|
|
|
640
652
|
if (!ctx || !show_hull_faces || hull_4d.length === 0) return
|
|
641
653
|
|
|
642
654
|
// Get stable points to determine which hull facets to draw
|
|
643
|
-
const stable_points = plot_entries.filter(
|
|
644
|
-
entry.is_stable || entry.e_above_hull === 0
|
|
645
|
-
)
|
|
655
|
+
const stable_points = plot_entries.filter(helpers.entry_is_stable)
|
|
646
656
|
if (stable_points.length === 0) return
|
|
647
657
|
|
|
648
658
|
// Each tetrahedral facet has 4 triangular faces - we need to draw these
|
|
@@ -805,7 +815,7 @@
|
|
|
805
815
|
if (!ctx || sorted_points_cache.length === 0) return
|
|
806
816
|
|
|
807
817
|
for (const { entry, projected } of sorted_points_cache) {
|
|
808
|
-
const is_stable =
|
|
818
|
+
const is_stable = helpers.entry_is_stable(entry)
|
|
809
819
|
const is_entry_highlighted = is_highlighted(entry)
|
|
810
820
|
const color = get_point_color(entry)
|
|
811
821
|
const size = (entry.size || (is_stable ? 6 : 4)) * canvas_dims.scale
|
|
@@ -827,7 +837,7 @@
|
|
|
827
837
|
projected,
|
|
828
838
|
size,
|
|
829
839
|
canvas_dims.scale,
|
|
830
|
-
|
|
840
|
+
pulse.time,
|
|
831
841
|
pulse_opacity,
|
|
832
842
|
)
|
|
833
843
|
}
|
|
@@ -837,7 +847,7 @@
|
|
|
837
847
|
projected,
|
|
838
848
|
size,
|
|
839
849
|
canvas_dims.scale,
|
|
840
|
-
|
|
850
|
+
pulse.time,
|
|
841
851
|
merged_highlight_style,
|
|
842
852
|
)
|
|
843
853
|
}
|
|
@@ -864,7 +874,7 @@
|
|
|
864
874
|
.map(({ entry }) => entry)
|
|
865
875
|
.filter((entry) => {
|
|
866
876
|
if (entry.is_element) return false
|
|
867
|
-
const is_stable =
|
|
877
|
+
const is_stable = helpers.entry_is_stable(entry)
|
|
868
878
|
return (is_stable && show_stable_labels) ||
|
|
869
879
|
(!is_stable && show_unstable_labels &&
|
|
870
880
|
(entry.e_above_hull ?? 0) <= max_hull_dist_show_labels)
|
|
@@ -877,7 +887,7 @@
|
|
|
877
887
|
ctx.textBaseline = `middle`
|
|
878
888
|
|
|
879
889
|
for (const entry of label_entries) {
|
|
880
|
-
const is_stable =
|
|
890
|
+
const is_stable = helpers.entry_is_stable(entry)
|
|
881
891
|
const size = (entry.size || (is_stable ? 6 : 4)) * canvas_dims.scale
|
|
882
892
|
const projected = project_3d_point(entry.x, entry.y, entry.z)
|
|
883
893
|
const label = helpers.get_entry_label(entry, elements)
|
|
@@ -969,7 +979,7 @@
|
|
|
969
979
|
helpers.find_hull_entry_at_mouse(
|
|
970
980
|
canvas,
|
|
971
981
|
event,
|
|
972
|
-
|
|
982
|
+
visible_entries,
|
|
973
983
|
(x: number, y: number, z: number) => {
|
|
974
984
|
const projected = project_3d_point(x, y, z)
|
|
975
985
|
return { x: projected.x, y: projected.y }
|
|
@@ -1017,7 +1027,7 @@
|
|
|
1017
1027
|
}
|
|
1018
1028
|
}
|
|
1019
1029
|
|
|
1020
|
-
|
|
1030
|
+
function render_once() {
|
|
1021
1031
|
if (!frame_id) {
|
|
1022
1032
|
frame_id = requestAnimationFrame(() => {
|
|
1023
1033
|
render_frame()
|
|
@@ -1085,15 +1095,14 @@
|
|
|
1085
1095
|
let canvas_dims = $state({ width: 600, height: 600, scale: 1 })
|
|
1086
1096
|
const formation_energy_min = $derived.by(() => {
|
|
1087
1097
|
let min_energy = 0
|
|
1088
|
-
for (const entry of
|
|
1098
|
+
for (const entry of all_enriched_entries) {
|
|
1089
1099
|
min_energy = Math.min(min_energy, entry.e_form_per_atom ?? 0)
|
|
1090
1100
|
}
|
|
1091
1101
|
return min_energy
|
|
1092
1102
|
})
|
|
1093
1103
|
const sorted_points_cache = $derived.by(() => {
|
|
1094
|
-
if (!canvas ||
|
|
1095
|
-
return
|
|
1096
|
-
.filter((entry) => entry.visible)
|
|
1104
|
+
if (!canvas || visible_entries.length === 0) return []
|
|
1105
|
+
return visible_entries
|
|
1097
1106
|
.map((entry) => ({
|
|
1098
1107
|
entry,
|
|
1099
1108
|
projected: project_3d_point(entry.x, entry.y, entry.z),
|
|
@@ -1210,6 +1219,8 @@
|
|
|
1210
1219
|
{phase_stats}
|
|
1211
1220
|
{stable_entries}
|
|
1212
1221
|
{unstable_entries}
|
|
1222
|
+
{show_stable}
|
|
1223
|
+
{show_unstable}
|
|
1213
1224
|
{max_hull_dist_show_phases}
|
|
1214
1225
|
{max_hull_dist_show_labels}
|
|
1215
1226
|
{label_threshold}
|
|
@@ -1247,13 +1258,14 @@
|
|
|
1247
1258
|
{merged_controls}
|
|
1248
1259
|
toggle_props={{ class: `legend-controls-btn` }}
|
|
1249
1260
|
{show_hull_faces}
|
|
1250
|
-
on_hull_faces_change={(value) => show_hull_faces = value}
|
|
1261
|
+
on_hull_faces_change={(value: boolean) => show_hull_faces = value}
|
|
1251
1262
|
{hull_face_color}
|
|
1252
|
-
on_hull_face_color_change={(value) => hull_face_color = value}
|
|
1263
|
+
on_hull_face_color_change={(value: string) => hull_face_color = value}
|
|
1253
1264
|
{hull_face_opacity}
|
|
1254
|
-
on_hull_face_opacity_change={(value) => hull_face_opacity = value}
|
|
1265
|
+
on_hull_face_opacity_change={(value: number) => hull_face_opacity = value}
|
|
1255
1266
|
{hull_face_color_mode}
|
|
1256
|
-
on_hull_face_color_mode_change={(value) =>
|
|
1267
|
+
on_hull_face_color_mode_change={(value: HullFaceColorMode) =>
|
|
1268
|
+
hull_face_color_mode = value}
|
|
1257
1269
|
bind:energy_source_mode
|
|
1258
1270
|
{has_precomputed_e_form}
|
|
1259
1271
|
{can_compute_e_form}
|