matterviz 0.3.1 → 0.3.2

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.
Files changed (257) hide show
  1. package/dist/FilePicker.svelte +37 -20
  2. package/dist/Icon.svelte +2 -2
  3. package/dist/app.css +29 -0
  4. package/dist/brillouin/BrillouinZone.svelte +19 -61
  5. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  6. package/dist/brillouin/BrillouinZoneExportPane.svelte +12 -20
  7. package/dist/brillouin/BrillouinZoneScene.svelte +2 -2
  8. package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
  9. package/dist/chempot-diagram/ChemPotDiagram.svelte +192 -0
  10. package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +13 -0
  11. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +677 -0
  12. package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +16 -0
  13. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2688 -0
  14. package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +16 -0
  15. package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -0
  16. package/dist/chempot-diagram/ChemPotScene3D.svelte.d.ts +7 -0
  17. package/dist/chempot-diagram/color.d.ts +10 -0
  18. package/dist/chempot-diagram/color.js +33 -0
  19. package/dist/chempot-diagram/compute.d.ts +38 -0
  20. package/dist/chempot-diagram/compute.js +650 -0
  21. package/dist/chempot-diagram/index.d.ts +5 -0
  22. package/dist/chempot-diagram/index.js +5 -0
  23. package/dist/chempot-diagram/pointer.d.ts +16 -0
  24. package/dist/chempot-diagram/pointer.js +40 -0
  25. package/dist/chempot-diagram/temperature.d.ts +15 -0
  26. package/dist/chempot-diagram/temperature.js +37 -0
  27. package/dist/chempot-diagram/types.d.ts +83 -0
  28. package/dist/chempot-diagram/types.js +27 -0
  29. package/dist/colors/index.d.ts +3 -1
  30. package/dist/colors/index.js +4 -0
  31. package/dist/composition/BarChart.svelte +13 -22
  32. package/dist/composition/BubbleChart.svelte +5 -3
  33. package/dist/composition/FormulaFilter.svelte +586 -94
  34. package/dist/composition/FormulaFilter.svelte.d.ts +35 -1
  35. package/dist/composition/PieChart.svelte +43 -18
  36. package/dist/composition/PieChart.svelte.d.ts +1 -1
  37. package/dist/convex-hull/ConvexHull.svelte +4 -2
  38. package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
  39. package/dist/convex-hull/ConvexHull2D.svelte +13 -44
  40. package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
  41. package/dist/convex-hull/ConvexHull3D.svelte +16 -7
  42. package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
  43. package/dist/convex-hull/ConvexHull4D.svelte +17 -7
  44. package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
  45. package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
  46. package/dist/convex-hull/ConvexHullStats.svelte +701 -226
  47. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +6 -1
  48. package/dist/convex-hull/ConvexHullTooltip.svelte +1 -0
  49. package/dist/convex-hull/demo-temperature.d.ts +6 -0
  50. package/dist/convex-hull/demo-temperature.js +36 -0
  51. package/dist/convex-hull/helpers.d.ts +1 -1
  52. package/dist/convex-hull/helpers.js +2 -4
  53. package/dist/convex-hull/index.d.ts +1 -0
  54. package/dist/convex-hull/index.js +1 -0
  55. package/dist/convex-hull/thermodynamics.d.ts +8 -21
  56. package/dist/convex-hull/thermodynamics.js +106 -17
  57. package/dist/convex-hull/types.d.ts +5 -0
  58. package/dist/convex-hull/types.js +5 -0
  59. package/dist/coordination/CoordinationBarPlot.svelte +29 -46
  60. package/dist/element/BohrAtom.svelte +1 -1
  61. package/dist/element/data.js +2 -14
  62. package/dist/element/data.json.gz +0 -0
  63. package/dist/element/types.d.ts +1 -0
  64. package/dist/fermi-surface/FermiSurface.svelte +20 -64
  65. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  66. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  67. package/dist/fermi-surface/FermiSurfaceScene.svelte +1 -1
  68. package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
  69. package/dist/fermi-surface/parse.js +16 -22
  70. package/dist/heatmap-matrix/HeatmapMatrix.svelte +1273 -0
  71. package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +110 -0
  72. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +171 -0
  73. package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +31 -0
  74. package/dist/heatmap-matrix/index.d.ts +53 -0
  75. package/dist/heatmap-matrix/index.js +100 -0
  76. package/dist/heatmap-matrix/shared.d.ts +2 -0
  77. package/dist/heatmap-matrix/shared.js +4 -0
  78. package/dist/icons.d.ts +111 -0
  79. package/dist/icons.js +111 -0
  80. package/dist/index.d.ts +3 -1
  81. package/dist/index.js +3 -1
  82. package/dist/io/export.js +15 -3
  83. package/dist/io/file-drop.d.ts +7 -0
  84. package/dist/io/file-drop.js +43 -0
  85. package/dist/io/index.d.ts +2 -2
  86. package/dist/io/index.js +2 -112
  87. package/dist/io/types.d.ts +1 -0
  88. package/dist/io/url-drop.d.ts +2 -0
  89. package/dist/io/url-drop.js +118 -0
  90. package/dist/isosurface/Isosurface.svelte +101 -45
  91. package/dist/isosurface/IsosurfaceControls.svelte +19 -0
  92. package/dist/isosurface/parse.js +73 -30
  93. package/dist/isosurface/slice.d.ts +2 -1
  94. package/dist/isosurface/slice.js +3 -3
  95. package/dist/isosurface/types.d.ts +13 -1
  96. package/dist/isosurface/types.js +98 -0
  97. package/dist/labels.d.ts +2 -1
  98. package/dist/labels.js +1 -0
  99. package/dist/layout/InfoTag.svelte +62 -62
  100. package/dist/layout/SubpageGrid.svelte +74 -0
  101. package/dist/layout/SubpageGrid.svelte.d.ts +14 -0
  102. package/dist/layout/index.d.ts +1 -0
  103. package/dist/layout/index.js +1 -0
  104. package/dist/layout/json-tree/JsonNode.svelte +83 -85
  105. package/dist/layout/json-tree/JsonTree.svelte +20 -19
  106. package/dist/layout/json-tree/JsonTree.svelte.d.ts +1 -1
  107. package/dist/layout/json-tree/JsonValue.svelte +196 -116
  108. package/dist/layout/json-tree/types.d.ts +10 -2
  109. package/dist/layout/json-tree/utils.d.ts +2 -0
  110. package/dist/layout/json-tree/utils.js +33 -0
  111. package/dist/math.d.ts +7 -0
  112. package/dist/math.js +358 -7
  113. package/dist/overlays/ContextMenu.svelte +3 -2
  114. package/dist/overlays/DraggablePane.svelte +163 -58
  115. package/dist/overlays/DraggablePane.svelte.d.ts +2 -0
  116. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +232 -77
  117. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -2
  118. package/dist/phase-diagram/PhaseDiagramControls.svelte +32 -11
  119. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +3 -2
  120. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +103 -0
  121. package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +15 -0
  122. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +102 -95
  123. package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +7 -0
  124. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +100 -26
  125. package/dist/phase-diagram/PhaseDiagramTooltip.svelte.d.ts +6 -3
  126. package/dist/phase-diagram/index.d.ts +2 -0
  127. package/dist/phase-diagram/index.js +2 -0
  128. package/dist/phase-diagram/svg-to-diagram.d.ts +2 -0
  129. package/dist/phase-diagram/svg-to-diagram.js +865 -0
  130. package/dist/phase-diagram/types.d.ts +10 -0
  131. package/dist/phase-diagram/utils.d.ts +7 -4
  132. package/dist/phase-diagram/utils.js +149 -59
  133. package/dist/plot/AxisLabel.svelte +26 -0
  134. package/dist/plot/AxisLabel.svelte.d.ts +16 -0
  135. package/dist/plot/BarPlot.svelte +473 -228
  136. package/dist/plot/BarPlot.svelte.d.ts +3 -3
  137. package/dist/plot/BarPlotControls.svelte +3 -2
  138. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  139. package/dist/plot/ColorBar.svelte +54 -54
  140. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  141. package/dist/plot/ColorScaleSelect.svelte +1 -1
  142. package/dist/plot/ElementScatter.svelte +3 -2
  143. package/dist/plot/FillArea.svelte +4 -1
  144. package/dist/plot/Histogram.svelte +320 -230
  145. package/dist/plot/Histogram.svelte.d.ts +2 -2
  146. package/dist/plot/HistogramControls.svelte +29 -10
  147. package/dist/plot/HistogramControls.svelte.d.ts +6 -2
  148. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +2 -2
  149. package/dist/plot/PlotControls.svelte +109 -27
  150. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  151. package/dist/plot/PlotLegend.svelte +1 -1
  152. package/dist/plot/PortalSelect.svelte +2 -1
  153. package/dist/plot/ReferenceLine.svelte +2 -1
  154. package/dist/plot/ReferenceLine.svelte.d.ts +1 -0
  155. package/dist/plot/ReferencePlane.svelte +1 -3
  156. package/dist/plot/ScatterPlot.svelte +343 -209
  157. package/dist/plot/ScatterPlot.svelte.d.ts +3 -3
  158. package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
  159. package/dist/plot/ScatterPlot3DControls.svelte +203 -250
  160. package/dist/plot/ScatterPlot3DScene.svelte +4 -7
  161. package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
  162. package/dist/plot/ScatterPlotControls.svelte +95 -55
  163. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  164. package/dist/plot/ZeroLines.svelte +44 -0
  165. package/dist/plot/ZeroLines.svelte.d.ts +32 -0
  166. package/dist/plot/ZoomRect.svelte +21 -0
  167. package/dist/plot/ZoomRect.svelte.d.ts +8 -0
  168. package/dist/plot/axis-utils.d.ts +1 -1
  169. package/dist/plot/index.d.ts +6 -2
  170. package/dist/plot/index.js +6 -2
  171. package/dist/plot/interactions.d.ts +8 -10
  172. package/dist/plot/interactions.js +2 -3
  173. package/dist/plot/layout.d.ts +7 -1
  174. package/dist/plot/layout.js +12 -4
  175. package/dist/plot/reference-line.d.ts +4 -21
  176. package/dist/plot/reference-line.js +7 -81
  177. package/dist/plot/types.d.ts +42 -17
  178. package/dist/plot/types.js +10 -0
  179. package/dist/plot/utils/label-placement.js +13 -10
  180. package/dist/plot/utils.d.ts +1 -0
  181. package/dist/plot/utils.js +14 -0
  182. package/dist/rdf/RdfPlot.svelte +55 -66
  183. package/dist/settings.d.ts +3 -0
  184. package/dist/settings.js +17 -3
  185. package/dist/spectral/Bands.svelte +515 -143
  186. package/dist/spectral/Bands.svelte.d.ts +22 -2
  187. package/dist/spectral/helpers.d.ts +23 -1
  188. package/dist/spectral/helpers.js +65 -9
  189. package/dist/spectral/types.d.ts +2 -0
  190. package/dist/structure/AtomLegend.svelte +29 -8
  191. package/dist/structure/AtomLegend.svelte.d.ts +1 -1
  192. package/dist/structure/CellSelect.svelte +92 -22
  193. package/dist/structure/Structure.svelte +108 -118
  194. package/dist/structure/Structure.svelte.d.ts +1 -1
  195. package/dist/structure/StructureControls.svelte +25 -22
  196. package/dist/structure/StructureControls.svelte.d.ts +1 -1
  197. package/dist/structure/StructureInfoPane.svelte +7 -1
  198. package/dist/structure/StructureScene.svelte +104 -66
  199. package/dist/structure/StructureScene.svelte.d.ts +2 -1
  200. package/dist/structure/atom-properties.d.ts +6 -2
  201. package/dist/structure/atom-properties.js +38 -25
  202. package/dist/structure/export.js +10 -7
  203. package/dist/structure/ferrox-wasm-types.d.ts +3 -2
  204. package/dist/structure/ferrox-wasm-types.js +0 -3
  205. package/dist/structure/ferrox-wasm.d.ts +3 -2
  206. package/dist/structure/ferrox-wasm.js +1 -2
  207. package/dist/structure/index.d.ts +6 -0
  208. package/dist/structure/index.js +22 -0
  209. package/dist/structure/parse.js +19 -16
  210. package/dist/structure/partial-occupancy.d.ts +25 -0
  211. package/dist/structure/partial-occupancy.js +102 -0
  212. package/dist/structure/validation.js +6 -3
  213. package/dist/symmetry/SymmetryStats.svelte +18 -4
  214. package/dist/symmetry/WyckoffTable.svelte +18 -10
  215. package/dist/symmetry/index.d.ts +7 -4
  216. package/dist/symmetry/index.js +83 -18
  217. package/dist/table/HeatmapTable.svelte +425 -65
  218. package/dist/table/HeatmapTable.svelte.d.ts +12 -1
  219. package/dist/table/ToggleMenu.svelte +2 -0
  220. package/dist/table/index.d.ts +2 -0
  221. package/dist/trajectory/Trajectory.svelte +147 -145
  222. package/dist/trajectory/TrajectoryExportPane.svelte +13 -9
  223. package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +1 -1
  224. package/dist/trajectory/constants.d.ts +6 -0
  225. package/dist/trajectory/constants.js +7 -0
  226. package/dist/trajectory/extract.js +3 -5
  227. package/dist/trajectory/format-detect.d.ts +9 -0
  228. package/dist/trajectory/format-detect.js +76 -0
  229. package/dist/trajectory/frame-reader.d.ts +17 -0
  230. package/dist/trajectory/frame-reader.js +339 -0
  231. package/dist/trajectory/helpers.d.ts +15 -0
  232. package/dist/trajectory/helpers.js +187 -0
  233. package/dist/trajectory/index.d.ts +1 -0
  234. package/dist/trajectory/index.js +11 -4
  235. package/dist/trajectory/parse/ase.d.ts +2 -0
  236. package/dist/trajectory/parse/ase.js +76 -0
  237. package/dist/trajectory/parse/hdf5.d.ts +2 -0
  238. package/dist/trajectory/parse/hdf5.js +121 -0
  239. package/dist/trajectory/parse/index.d.ts +12 -0
  240. package/dist/trajectory/parse/index.js +304 -0
  241. package/dist/trajectory/parse/lammps.d.ts +5 -0
  242. package/dist/trajectory/parse/lammps.js +169 -0
  243. package/dist/trajectory/parse/vasp.d.ts +2 -0
  244. package/dist/trajectory/parse/vasp.js +65 -0
  245. package/dist/trajectory/parse/xyz.d.ts +2 -0
  246. package/dist/trajectory/parse/xyz.js +109 -0
  247. package/dist/trajectory/types.d.ts +11 -0
  248. package/dist/trajectory/types.js +1 -0
  249. package/dist/utils.d.ts +2 -0
  250. package/dist/utils.js +4 -0
  251. package/dist/xrd/XrdPlot.svelte +6 -4
  252. package/dist/xrd/calc-xrd.js +0 -1
  253. package/package.json +30 -24
  254. package/readme.md +4 -4
  255. package/dist/trajectory/parse.d.ts +0 -42
  256. package/dist/trajectory/parse.js +0 -1267
  257. /package/dist/element/{data.json.d.ts → data.json.gz.d.ts} +0 -0
@@ -0,0 +1,103 @@
1
+ <script lang="ts">import { JsonTree } from '../layout/json-tree';
2
+ import { set_at_path } from '../layout/json-tree/utils';
3
+ import DraggablePane from '../overlays/DraggablePane.svelte';
4
+ import { build_diagram } from './build-diagram';
5
+ let { editor_open = $bindable(false), diagram_input = $bindable(null), data = null, ondata, icon_style = ``, toggle_props: caller_toggle_props = {}, } = $props();
6
+ // The source object currently displayed (DiagramInput or PhaseDiagramData)
7
+ const display_source = $derived(diagram_input ?? data);
8
+ const root_label = `diagram`;
9
+ // Brief error flash when an edit is rejected by build_diagram
10
+ let rejection_msg = $state(null);
11
+ let rejection_timer;
12
+ function show_rejection(msg) {
13
+ if (rejection_timer)
14
+ clearTimeout(rejection_timer);
15
+ rejection_msg = msg;
16
+ rejection_timer = setTimeout(() => (rejection_msg = null), 3000);
17
+ }
18
+ // Shared format detection: true if obj looks like a DiagramInput
19
+ function is_diagram_input(obj) {
20
+ const meta = obj.meta;
21
+ return Boolean(meta && Array.isArray(meta.components) && `curves` in obj);
22
+ }
23
+ // Handle inline value edits from JsonTree
24
+ function handle_change(path, new_value, _old_value) {
25
+ if (!display_source)
26
+ return;
27
+ const updated = set_at_path(display_source, path, new_value, root_label);
28
+ if (is_diagram_input(updated)) {
29
+ try {
30
+ build_diagram(updated);
31
+ diagram_input = updated;
32
+ }
33
+ catch (err) {
34
+ const msg = err instanceof Error ? err.message : String(err);
35
+ show_rejection(msg);
36
+ }
37
+ return;
38
+ }
39
+ // PhaseDiagramData format — clear diagram_input so rebuilt_data doesn't shadow
40
+ diagram_input = null;
41
+ ondata?.(updated);
42
+ }
43
+ </script>
44
+
45
+ <DraggablePane
46
+ bind:show={editor_open}
47
+ open_icon="Cross"
48
+ closed_icon="Edit"
49
+ {icon_style}
50
+ persistent
51
+ pane_props={{ class: `pd-editor-pane` }}
52
+ toggle_props={{
53
+ class: `pd-editor-toggle`,
54
+ title: editor_open ? `` : `Edit diagram data`,
55
+ ...caller_toggle_props,
56
+ }}
57
+ max_width="600px"
58
+ >
59
+ {#if rejection_msg}
60
+ <div class="rejection-flash">{rejection_msg}</div>
61
+ {/if}
62
+ {#if display_source}
63
+ <JsonTree
64
+ value={display_source}
65
+ {root_label}
66
+ default_fold_level={2}
67
+ download_filename="diagram-data.json"
68
+ editable
69
+ onchange={handle_change}
70
+ />
71
+ {:else}
72
+ <p class="placeholder">
73
+ No diagram data loaded. Drop an SVG or JSON file onto the diagram.
74
+ </p>
75
+ {/if}
76
+ </DraggablePane>
77
+
78
+ <style>
79
+ .rejection-flash {
80
+ color: #d32f2f;
81
+ font-size: 11px;
82
+ padding: 4px 8px;
83
+ background: rgba(211, 47, 47, 0.08);
84
+ border-radius: 3px;
85
+ word-break: break-word;
86
+ animation: fade-out 3s ease-out forwards;
87
+ }
88
+ @keyframes fade-out {
89
+ 0%, 80% {
90
+ opacity: 1;
91
+ }
92
+ 100% {
93
+ opacity: 0;
94
+ }
95
+ }
96
+ .placeholder {
97
+ color: var(--text-muted, #888);
98
+ font-style: italic;
99
+ text-align: center;
100
+ padding: 20px;
101
+ margin: 0;
102
+ }
103
+ </style>
@@ -0,0 +1,15 @@
1
+ import DraggablePane from '../overlays/DraggablePane.svelte';
2
+ import type { ComponentProps } from 'svelte';
3
+ import type { DiagramInput } from './diagram-input';
4
+ import type { PhaseDiagramData } from './types';
5
+ type $$ComponentProps = {
6
+ editor_open?: boolean;
7
+ diagram_input?: DiagramInput | null;
8
+ data?: PhaseDiagramData | null;
9
+ ondata?: (data: PhaseDiagramData) => void;
10
+ icon_style?: string;
11
+ toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
12
+ };
13
+ declare const PhaseDiagramEditorPane: import("svelte").Component<$$ComponentProps, {}, "editor_open" | "diagram_input">;
14
+ type PhaseDiagramEditorPane = ReturnType<typeof PhaseDiagramEditorPane>;
15
+ export default PhaseDiagramEditorPane;
@@ -1,30 +1,22 @@
1
- <script lang="ts">import DraggablePane from '../overlays/DraggablePane.svelte';
2
- import { export_svg_as_png, export_svg_as_svg } from '../io/export';
1
+ <script lang="ts">import { export_svg_as_png, export_svg_as_svg } from '../io/export';
2
+ import DraggablePane from '../overlays/DraggablePane.svelte';
3
+ import { CopyButton } from 'svelte-multiselect';
3
4
  import { tooltip } from 'svelte-multiselect/attachments';
4
- let { export_pane_open = $bindable(false), data, wrapper, filename = `phase-diagram`, png_dpi = $bindable(150), ...rest } = $props();
5
- // Copy button feedback state
6
- let copy_status = $state({
7
- json: false,
8
- svg: false,
9
- });
10
- const copy_confirm = `✅`;
5
+ let { export_pane_open = $bindable(false), data, json_payload = undefined, wrapper, svg_element = undefined, svg_query_selector = `svg.binary-phase-diagram`, filename = `phase-diagram`, png_dpi = $bindable(150), icon_style = ``, toggle_props: caller_toggle_props = {}, ...rest } = $props();
6
+ let json_copy_state = $state(`ready`);
7
+ let svg_copy_state = $state(`ready`);
11
8
  // Generate filename with components if available (requires exactly 2 components)
12
9
  const full_filename = $derived(data?.components?.length === 2
13
10
  ? `${filename}-${data.components[0]}-${data.components[1]}`
14
11
  : filename);
15
- const svg = $derived(wrapper?.querySelector(`svg.binary-phase-diagram`));
16
- async function copy_svg() {
17
- if (!svg)
18
- return;
19
- const svg_string = new XMLSerializer().serializeToString(svg);
20
- await navigator.clipboard.writeText(svg_string);
21
- copy_status.svg = true;
22
- setTimeout(() => (copy_status.svg = false), 1500);
23
- }
12
+ const svg = $derived(svg_element ??
13
+ wrapper?.querySelector(svg_query_selector));
14
+ const json_export_data = $derived(json_payload ?? data);
15
+ const svg_string = $derived(svg ? new XMLSerializer().serializeToString(svg) : null);
24
16
  function download_json() {
25
- if (!data)
17
+ if (!json_export_data)
26
18
  return;
27
- const json_string = JSON.stringify(data, null, 2);
19
+ const json_string = JSON.stringify(json_export_data, null, 2);
28
20
  const blob = new Blob([json_string], { type: `application/json` });
29
21
  const url = URL.createObjectURL(blob);
30
22
  const link = document.createElement(`a`);
@@ -33,14 +25,7 @@ function download_json() {
33
25
  link.click();
34
26
  URL.revokeObjectURL(url);
35
27
  }
36
- async function copy_json() {
37
- if (!data)
38
- return;
39
- const json_string = JSON.stringify(data, null, 2);
40
- await navigator.clipboard.writeText(json_string);
41
- copy_status.json = true;
42
- setTimeout(() => (copy_status.json = false), 1500);
43
- }
28
+ const json_string = $derived(json_export_data ? JSON.stringify(json_export_data, null, 2) : null);
44
29
  </script>
45
30
 
46
31
  <DraggablePane
@@ -48,95 +33,117 @@ async function copy_json() {
48
33
  open_icon="Cross"
49
34
  closed_icon="Export"
50
35
  pane_props={{ ...rest, class: `export-pane ${rest.class ?? ``}` }}
36
+ {icon_style}
51
37
  toggle_props={{
52
38
  class: `pd-export-toggle`,
53
39
  title: export_pane_open ? `` : `Export phase diagram`,
40
+ ...caller_toggle_props,
54
41
  }}
55
42
  >
56
- <h4 id="export-as-image"
57
- {@attach tooltip({
58
- content: `Download or copy the phase diagram`,
59
- })}
60
- >
61
- Export as image
62
- </h4>
63
- <label>
64
- SVG
65
- <button
66
- type="button"
67
- onclick={() => svg && export_svg_as_svg(svg, `${full_filename}.svg`)}
68
- disabled={!svg}
69
- title="Download SVG"
43
+ <div class="export-grid">
44
+ <h4 id="image"
45
+ {@attach tooltip({
46
+ content: `Download or copy the phase diagram`,
47
+ })}
70
48
  >
71
-
72
- </button>
73
- <button
74
- type="button"
75
- onclick={copy_svg}
76
- disabled={!svg}
77
- title="Copy SVG to clipboard"
78
- >
79
- {copy_status.svg ? copy_confirm : `📋`}
80
- </button>
81
- </label>
82
- <label>
83
- PNG
84
- <button
85
- type="button"
86
- onclick={() => svg && export_svg_as_png(svg, `${full_filename}.png`, png_dpi)}
87
- disabled={!svg}
88
- title={`Download PNG (${png_dpi} DPI)`}
89
- >
90
-
91
- </button>
92
- &nbsp;(DPI: <input
93
- type="number"
94
- min={50}
95
- max={600}
96
- bind:value={png_dpi}
97
- title="Export resolution in dots per inch"
98
- />)
99
- </label>
49
+ Image
50
+ </h4>
51
+ <label>
52
+ SVG
53
+ <button
54
+ type="button"
55
+ onclick={() => svg && export_svg_as_svg(svg, `${full_filename}.svg`)}
56
+ disabled={!svg}
57
+ title="Download SVG"
58
+ >
59
+
60
+ </button>
61
+ <CopyButton
62
+ content={svg_string ?? ``}
63
+ title="Copy SVG to clipboard"
64
+ bind:state={svg_copy_state}
65
+ disabled={!svg_string}
66
+ />
67
+ </label>
68
+ <label>
69
+ PNG
70
+ <button
71
+ type="button"
72
+ onclick={() => svg && export_svg_as_png(svg, `${full_filename}.png`, png_dpi)}
73
+ disabled={!svg}
74
+ title={`Download PNG (${png_dpi} DPI)`}
75
+ >
76
+
77
+ </button>
78
+ <span class="dpi-input"
79
+ >(DPI: <input
80
+ type="number"
81
+ min={50}
82
+ max={600}
83
+ bind:value={png_dpi}
84
+ title="Export resolution in dots per inch"
85
+ />)</span>
86
+ </label>
100
87
 
101
- <h4 id="export-as-data"
102
- {@attach tooltip({
103
- content: `Export phase diagram data as JSON`,
104
- })}
105
- >
106
- Export as data
107
- </h4>
108
- <label>
109
- JSON
110
- <button type="button" onclick={download_json} disabled={!data} title="Download JSON">
111
-
112
- </button>
113
- <button
114
- type="button"
115
- onclick={copy_json}
116
- disabled={!data}
117
- title="Copy JSON to clipboard"
88
+ <h4 id="data"
89
+ {@attach tooltip({
90
+ content: `Export phase diagram data as JSON`,
91
+ })}
118
92
  >
119
- {copy_status.json ? copy_confirm : `📋`}
120
- </button>
121
- </label>
93
+ Data
94
+ </h4>
95
+ <label>
96
+ JSON
97
+ <button
98
+ type="button"
99
+ onclick={download_json}
100
+ disabled={!json_export_data}
101
+ title="Download JSON"
102
+ >
103
+
104
+ </button>
105
+ <CopyButton
106
+ content={json_string ?? ``}
107
+ title="Copy JSON to clipboard"
108
+ bind:state={json_copy_state}
109
+ disabled={!json_string}
110
+ />
111
+ </label>
112
+ </div>
122
113
  </DraggablePane>
123
114
 
124
115
  <style>
125
- label {
116
+ .export-grid {
126
117
  display: flex;
127
118
  flex-wrap: wrap;
128
119
  align-items: center;
129
- gap: 4pt;
120
+ gap: 4pt 10pt;
121
+ }
122
+ .export-grid h4 {
123
+ display: inline-flex;
124
+ align-items: center;
125
+ margin: 0;
126
+ }
127
+ label {
128
+ display: flex;
129
+ align-items: center;
130
+ gap: 8pt;
130
131
  font-size: 0.95em;
132
+ white-space: nowrap;
133
+ }
134
+ .dpi-input {
135
+ display: inline-flex;
136
+ align-items: center;
137
+ gap: 2pt;
138
+ white-space: nowrap;
131
139
  }
132
140
  button {
133
141
  width: 1.9em;
134
142
  height: 1.6em;
135
143
  padding: 0 6pt;
136
- margin: 0 0 0 4pt;
137
144
  box-sizing: border-box;
138
145
  }
139
146
  input {
140
- margin: 0 0 0 2pt;
147
+ width: 3.5em;
141
148
  }
142
149
  </style>
@@ -1,11 +1,18 @@
1
+ import DraggablePane from '../overlays/DraggablePane.svelte';
2
+ import type { ComponentProps } from 'svelte';
1
3
  import type { HTMLAttributes } from 'svelte/elements';
2
4
  import type { PhaseDiagramData } from './types';
3
5
  type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
4
6
  export_pane_open?: boolean;
5
7
  data?: PhaseDiagramData;
8
+ json_payload?: unknown;
6
9
  wrapper?: HTMLDivElement;
10
+ svg_element?: SVGSVGElement | null;
11
+ svg_query_selector?: string;
7
12
  filename?: string;
8
13
  png_dpi?: number;
14
+ icon_style?: string;
15
+ toggle_props?: ComponentProps<typeof DraggablePane>[`toggle_props`];
9
16
  };
10
17
  declare const PhaseDiagramExportPane: import("svelte").Component<$$ComponentProps, {}, "export_pane_open" | "png_dpi">;
11
18
  type PhaseDiagramExportPane = ReturnType<typeof PhaseDiagramExportPane>;
@@ -1,8 +1,14 @@
1
1
  <script lang="ts">import { ATOMIC_WEIGHTS } from '../composition/parse';
2
2
  import { format_num } from '../labels';
3
3
  import { TooltipContent } from '../tooltip';
4
- import { format_composition, format_temperature, get_phase_stability_range, } from './utils';
5
- let { hover_info, temperature_unit = `K`, composition_unit = `at%`, component_a = `A`, component_b = `B`, boundaries = [], tooltip, } = $props();
4
+ import { convert_temp, format_composition, format_formula_html, format_label_html, format_temperature, get_phase_stability_range, } from './utils';
5
+ let { hover_info, temperature_unit = `K`, data_temperature_unit, composition_unit = `at%`, component_a = `A`, component_b = `B`, boundaries = [], lever_rule_mode = `horizontal`, use_subscripts = true, tooltip, } = $props();
6
+ // The unit that hover_info.temperature is actually in
7
+ const data_unit = $derived(data_temperature_unit ?? temperature_unit);
8
+ // Convert a temperature from data unit to display unit
9
+ function to_display(temp) {
10
+ return convert_temp(temp, data_unit, temperature_unit);
11
+ }
6
12
  // Convert atomic fraction to weight fraction: wt_B = (x_B * M_B) / (x_A * M_A + x_B * M_B)
7
13
  const wt_fraction_b = $derived.by(() => {
8
14
  const mass_a = ATOMIC_WEIGHTS.get(component_a);
@@ -22,7 +28,7 @@ const special_point_info = $derived.by(() => {
22
28
  return null;
23
29
  const type = point.type;
24
30
  const position = point.position;
25
- const temp = format_temperature(position[1], temperature_unit);
31
+ const temp = format_temperature(to_display(position[1]), temperature_unit);
26
32
  // Check if this is a melting point (at composition edge)
27
33
  const is_at_edge = position[0] <= 0.01 || position[0] >= 0.99;
28
34
  const is_melting = type === `melting_point` || type === `congruent`;
@@ -69,12 +75,41 @@ const boundary_distance = $derived.by(() => {
69
75
  }
70
76
  return min_dist;
71
77
  });
78
+ // Normalized lever rule display data (unifies horizontal and vertical modes)
79
+ const lever_display = $derived.by(() => {
80
+ if (lever_rule_mode === `vertical` && hover_info.vertical_lever_rule) {
81
+ const vlr = hover_info.vertical_lever_rule;
82
+ return {
83
+ label: `Lever Rule (vertical)`,
84
+ phase_a: vlr.bottom_phase,
85
+ phase_b: vlr.top_phase,
86
+ fraction_a: vlr.fraction_bottom,
87
+ fraction_b: vlr.fraction_top,
88
+ detail_a: format_temperature(to_display(vlr.bottom_temperature), temperature_unit),
89
+ detail_b: format_temperature(to_display(vlr.top_temperature), temperature_unit),
90
+ };
91
+ }
92
+ if (lever_rule_mode === `horizontal` && hover_info.lever_rule) {
93
+ const lr = hover_info.lever_rule;
94
+ return {
95
+ label: `Lever Rule`,
96
+ phase_a: lr.left_phase,
97
+ phase_b: lr.right_phase,
98
+ fraction_a: lr.fraction_left,
99
+ fraction_b: lr.fraction_right,
100
+ detail_a: format_composition(lr.left_composition, composition_unit),
101
+ detail_b: format_composition(lr.right_composition, composition_unit),
102
+ };
103
+ }
104
+ return null;
105
+ });
72
106
  </script>
73
107
 
74
108
  <TooltipContent data={hover_info} snippet_arg={hover_info} {tooltip}>
75
109
  <div class="phase-diagram-tooltip">
110
+ <!-- Note: {@html} is safe here because region/phase names come from trusted JSON data files -->
76
111
  <header>
77
- <strong>{hover_info.region.name}</strong>
112
+ <strong>{@html format_label_html(hover_info.region.name, use_subscripts)}</strong>
78
113
  {#if special_point_info}<span class="special-point-badge">{
79
114
  special_point_info.badge
80
115
  }</span>{/if}
@@ -86,49 +121,84 @@ const boundary_distance = $derived.by(() => {
86
121
 
87
122
  <dl>
88
123
  <dt>Temperature</dt>
89
- <dd>{format_temperature(hover_info.temperature, temperature_unit)}</dd>
124
+ <dd>
125
+ {
126
+ format_temperature(
127
+ to_display(hover_info.temperature),
128
+ temperature_unit,
129
+ )
130
+ }
131
+ {#if temperature_unit !== `°C`}
132
+ <small>({
133
+ format_temperature(
134
+ convert_temp(hover_info.temperature, data_unit, `°C`),
135
+ `°C`,
136
+ )
137
+ })</small>
138
+ {/if}
139
+ </dd>
90
140
  <dt>Composition</dt>
91
141
  <dd>
92
- {format_composition(hover_info.composition, composition_unit)} {component_b}
93
- <small>({format_composition(1 - hover_info.composition, composition_unit)} {
94
- component_a
95
- })</small>
142
+ {format_composition(hover_info.composition, composition_unit)}
143
+ {@html format_formula_html(component_b, use_subscripts)}
144
+ <small>({format_composition(1 - hover_info.composition, composition_unit)}
145
+ {@html format_formula_html(component_a, use_subscripts)})</small>
96
146
  </dd>
97
147
  {#if wt_fraction_b !== null}
98
148
  <dt>Weight</dt>
99
149
  <dd>
100
- {format_num(wt_fraction_b * 100, `.1f`)}% {component_b}
101
- <small>({format_num((1 - wt_fraction_b) * 100, `.1f`)}% {component_a})</small>
150
+ {format_num(wt_fraction_b * 100, `.1f`)}%
151
+ {@html format_formula_html(component_b, use_subscripts)}
152
+ <small>({format_num((1 - wt_fraction_b) * 100, `.1f`)}%
153
+ {@html format_formula_html(component_a, use_subscripts)})</small>
102
154
  </dd>
103
155
  {/if}
104
156
  {#if stability}
105
- <dt>Stable</dt><dd>{stability.t_min} – {stability.t_max} {temperature_unit}</dd>
157
+ <dt>Stable</dt><dd>
158
+ {format_num(to_display(stability.t_min), `.0f`)} – {
159
+ format_num(to_display(stability.t_max), `.0f`)
160
+ } {temperature_unit}
161
+ {#if temperature_unit !== `°C`}
162
+ <small>({
163
+ format_num(
164
+ convert_temp(stability.t_min, data_unit, `°C`),
165
+ `.0f`,
166
+ )
167
+ } – {
168
+ format_num(
169
+ convert_temp(stability.t_max, data_unit, `°C`),
170
+ `.0f`,
171
+ )
172
+ } °C)</small>
173
+ {/if}
174
+ </dd>
106
175
  {/if}
107
176
  </dl>
108
177
 
109
- {#if hover_info.lever_rule}
110
- {@const lr = hover_info.lever_rule}
178
+ {#if lever_display}
179
+ {@const ld = lever_display}
111
180
  <div class="lever">
112
- <span>Lever Rule</span>
181
+ <span>{ld.label}</span>
113
182
  <div class="bar">
114
183
  <div
115
- style:width="{lr.fraction_left * 100}%"
116
- title="{lr.left_phase}: {format_num(lr.fraction_left * 100, `.1f`)}%"
184
+ style:width="{ld.fraction_a * 100}%"
185
+ title="{ld.phase_a}: {format_num(ld.fraction_a * 100, `.1f`)}%"
117
186
  >
118
187
  </div>
119
188
  <div
120
- style:width="{lr.fraction_right * 100}%"
121
- title="{lr.right_phase}: {format_num(lr.fraction_right * 100, `.1f`)}%"
189
+ style:width="{ld.fraction_b * 100}%"
190
+ title="{ld.phase_b}: {format_num(ld.fraction_b * 100, `.1f`)}%"
122
191
  >
123
192
  </div>
124
- <i style:left="{lr.fraction_left * 100}%"></i>
193
+ <i style:left="{ld.fraction_a * 100}%"></i>
125
194
  </div>
126
195
  <div class="phase-info">
127
- <span>{lr.left_phase}: {format_num(lr.fraction_left * 100, `.0f`)}% <small>at {
128
- format_composition(lr.left_composition, composition_unit)
129
- }</small></span>
130
- <span>{lr.right_phase}: {format_num(lr.fraction_right * 100, `.0f`)}% <small>at
131
- {format_composition(lr.right_composition, composition_unit)}</small></span>
196
+ <span>{@html format_formula_html(ld.phase_a, use_subscripts)}: {
197
+ format_num(ld.fraction_a * 100, `.0f`)
198
+ }% <small>at {ld.detail_a}</small></span>
199
+ <span>{@html format_formula_html(ld.phase_b, use_subscripts)}: {
200
+ format_num(ld.fraction_b * 100, `.0f`)
201
+ }% <small>at {ld.detail_b}</small></span>
132
202
  </div>
133
203
  </div>
134
204
  {/if}
@@ -136,8 +206,12 @@ const boundary_distance = $derived.by(() => {
136
206
  {#if boundary_distance}
137
207
  {@const { type, delta_t } = boundary_distance}
138
208
  {@const label = delta_t > 0 ? `above` : `below`}
209
+ {@const display_delta = Math.abs(
210
+ to_display(hover_info.temperature) -
211
+ to_display(hover_info.temperature - delta_t),
212
+ )}
139
213
  <div class="boundary-info">
140
- {Math.round(Math.abs(delta_t))} {temperature_unit} {label} {type}
214
+ {Math.round(display_delta)} {temperature_unit} {label} {type}
141
215
  </div>
142
216
  {/if}
143
217
  </div>
@@ -1,11 +1,14 @@
1
- import type { PhaseBoundary, PhaseDiagramTooltipProp, PhaseHoverInfo } from './types';
1
+ import type { CompUnit, LeverRuleMode, PhaseBoundary, PhaseDiagramTooltipProp, PhaseHoverInfo, TempUnit } from './types';
2
2
  type $$ComponentProps = {
3
3
  hover_info: PhaseHoverInfo;
4
- temperature_unit?: string;
5
- composition_unit?: string;
4
+ temperature_unit?: TempUnit;
5
+ data_temperature_unit?: TempUnit;
6
+ composition_unit?: CompUnit;
6
7
  component_a?: string;
7
8
  component_b?: string;
8
9
  boundaries?: PhaseBoundary[];
10
+ lever_rule_mode?: LeverRuleMode;
11
+ use_subscripts?: boolean;
9
12
  tooltip?: PhaseDiagramTooltipProp;
10
13
  };
11
14
  declare const PhaseDiagramTooltip: import("svelte").Component<$$ComponentProps, {}, "">;
@@ -4,8 +4,10 @@ export * from './diagram-input';
4
4
  export { default as IsobaricBinaryPhaseDiagram } from './IsobaricBinaryPhaseDiagram.svelte';
5
5
  export * from './parse';
6
6
  export { default as PhaseDiagramControls } from './PhaseDiagramControls.svelte';
7
+ export { default as PhaseDiagramEditorPane } from './PhaseDiagramEditorPane.svelte';
7
8
  export { default as PhaseDiagramExportPane } from './PhaseDiagramExportPane.svelte';
8
9
  export { default as PhaseDiagramTooltip } from './PhaseDiagramTooltip.svelte';
10
+ export { parse_phase_diagram_svg } from './svg-to-diagram';
9
11
  export { default as TdbInfoPanel } from './TdbInfoPanel.svelte';
10
12
  export * from './types';
11
13
  export * from './utils';
@@ -4,8 +4,10 @@ export * from './diagram-input';
4
4
  export { default as IsobaricBinaryPhaseDiagram } from './IsobaricBinaryPhaseDiagram.svelte';
5
5
  export * from './parse';
6
6
  export { default as PhaseDiagramControls } from './PhaseDiagramControls.svelte';
7
+ export { default as PhaseDiagramEditorPane } from './PhaseDiagramEditorPane.svelte';
7
8
  export { default as PhaseDiagramExportPane } from './PhaseDiagramExportPane.svelte';
8
9
  export { default as PhaseDiagramTooltip } from './PhaseDiagramTooltip.svelte';
10
+ export { parse_phase_diagram_svg } from './svg-to-diagram';
9
11
  export { default as TdbInfoPanel } from './TdbInfoPanel.svelte';
10
12
  export * from './types';
11
13
  export * from './utils';
@@ -0,0 +1,2 @@
1
+ import type { DiagramInput } from './diagram-input';
2
+ export declare function parse_phase_diagram_svg(svg_string: string): DiagramInput;