matterviz 0.1.0 → 0.1.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 (74) hide show
  1. package/dist/ControlPanel.svelte +43 -34
  2. package/dist/ControlPanel.svelte.d.ts +2 -1
  3. package/dist/api.js +12 -2
  4. package/dist/composition/parse.d.ts +4 -0
  5. package/dist/composition/parse.js +6 -6
  6. package/dist/element/ElementTile.svelte +58 -73
  7. package/dist/icons.d.ts +8 -24
  8. package/dist/icons.js +8 -24
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.js +1 -1
  11. package/dist/io/decompress.d.ts +0 -1
  12. package/dist/io/decompress.js +1 -3
  13. package/dist/io/export.d.ts +5 -1
  14. package/dist/io/export.js +112 -101
  15. package/dist/io/index.d.ts +3 -0
  16. package/dist/io/index.js +3 -0
  17. package/dist/io/parse.d.ts +3 -0
  18. package/dist/io/parse.js +130 -1
  19. package/dist/labels.d.ts +4 -3
  20. package/dist/labels.js +38 -60
  21. package/dist/math.d.ts +3 -2
  22. package/dist/math.js +4 -2
  23. package/dist/plot/ColorBar.svelte +10 -9
  24. package/dist/plot/Histogram.svelte +319 -0
  25. package/dist/plot/Histogram.svelte.d.ts +40 -0
  26. package/dist/plot/ScatterPlot.svelte +79 -230
  27. package/dist/plot/ScatterPlot.svelte.d.ts +9 -4
  28. package/dist/plot/ScatterPlotControls.svelte +25 -34
  29. package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
  30. package/dist/plot/ScatterPoint.svelte +4 -4
  31. package/dist/plot/data-transform.d.ts +13 -0
  32. package/dist/plot/data-transform.js +35 -0
  33. package/dist/plot/formatting.d.ts +1 -0
  34. package/dist/plot/formatting.js +40 -0
  35. package/dist/plot/index.d.ts +1 -1
  36. package/dist/plot/index.js +1 -2
  37. package/dist/plot/interactions.d.ts +5 -0
  38. package/dist/plot/interactions.js +15 -0
  39. package/dist/plot/layout.d.ts +13 -0
  40. package/dist/plot/layout.js +14 -0
  41. package/dist/plot/scales.d.ts +16 -0
  42. package/dist/plot/scales.js +167 -0
  43. package/dist/structure/Bond.svelte +4 -3
  44. package/dist/structure/Bond.svelte.d.ts +4 -5
  45. package/dist/structure/Lattice.svelte +7 -8
  46. package/dist/structure/Structure.svelte +161 -79
  47. package/dist/structure/Structure.svelte.d.ts +3 -5
  48. package/dist/structure/StructureCard.svelte +6 -2
  49. package/dist/structure/StructureControls.svelte +182 -27
  50. package/dist/structure/StructureControls.svelte.d.ts +18 -5
  51. package/dist/structure/StructureLegend.svelte +13 -72
  52. package/dist/structure/StructureLegend.svelte.d.ts +2 -6
  53. package/dist/structure/StructureScene.svelte +31 -10
  54. package/dist/structure/StructureScene.svelte.d.ts +11 -7
  55. package/dist/structure/StructureSidebar.svelte +402 -0
  56. package/dist/structure/StructureSidebar.svelte.d.ts +9 -0
  57. package/dist/structure/Vector.svelte +37 -0
  58. package/dist/structure/Vector.svelte.d.ts +13 -0
  59. package/dist/structure/index.d.ts +24 -14
  60. package/dist/structure/index.js +33 -30
  61. package/dist/structure/pbc.js +3 -3
  62. package/dist/trajectory/Trajectory.svelte +360 -218
  63. package/dist/trajectory/Trajectory.svelte.d.ts +8 -4
  64. package/dist/trajectory/{Sidebar.svelte → TrajectorySidebar.svelte} +5 -6
  65. package/dist/trajectory/{Sidebar.svelte.d.ts → TrajectorySidebar.svelte.d.ts} +3 -3
  66. package/dist/trajectory/extract.js +24 -2
  67. package/dist/trajectory/index.d.ts +1 -1
  68. package/dist/trajectory/index.js +1 -1
  69. package/dist/trajectory/parse.d.ts +7 -10
  70. package/dist/trajectory/parse.js +597 -958
  71. package/dist/trajectory/plotting.d.ts +16 -5
  72. package/dist/trajectory/plotting.js +290 -58
  73. package/package.json +11 -13
  74. package/readme.md +20 -2
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">import { Icon } from './';
2
- let { controls_open = $bindable(false), show_controls = true, controls_content, toggle_button = {}, panel_props = {}, show_toggle_button = true, open_icon = `Cross`, closed_icon = `Settings`, toggle_controls_btn, controls, } = $props();
2
+ let { controls_open = $bindable(false), show_controls = true, controls_content, toggle_button = {}, panel_props = {}, show_toggle_button = true, open_icon = `Cross`, closed_icon = `Settings`, toggle_controls_btn, controls_div, icon_style = `width: 24px; height: 24px`, } = $props();
3
+ const [panel_class, toggle_class] = [`controls-panel`, `controls-toggle`];
3
4
  function on_keydown(event) {
4
5
  if (event.key === `Escape`)
5
6
  controls_open = false;
@@ -7,9 +8,20 @@ function on_keydown(event) {
7
8
  function toggle_controls() {
8
9
  controls_open = !controls_open;
9
10
  }
11
+ function handle_click_outside(event) {
12
+ if (!controls_open)
13
+ return;
14
+ const target = event.target;
15
+ const control_panel = target.closest(`.${panel_class}`);
16
+ const toggle_btn = target.closest(`.${toggle_class}`);
17
+ // Don't close if clicking inside panel or on toggle button
18
+ if (!control_panel && !toggle_btn)
19
+ controls_open = false;
20
+ }
10
21
  </script>
11
22
 
12
23
  <svelte:window onkeydown={on_keydown} />
24
+ <svelte:document onclick={handle_click_outside} />
13
25
 
14
26
  {#if show_controls}
15
27
  {#if show_toggle_button}
@@ -20,21 +32,18 @@ function toggle_controls() {
20
32
  aria-controls="controls-panel"
21
33
  title={toggle_button.title ?? (controls_open ? `Close controls` : `Open controls`)}
22
34
  {...toggle_button}
23
- class="controls-toggle {toggle_button.class ?? ``}"
35
+ class="{toggle_class} {toggle_button.class ?? ``}"
24
36
  >
25
- <Icon
26
- icon={controls_open ? open_icon : closed_icon}
27
- style="width: 24px; height: 24px"
28
- />
37
+ <Icon icon={controls_open ? open_icon : closed_icon} style={icon_style} />
29
38
  </button>
30
39
  {/if}
31
40
 
32
41
  <div
33
42
  class:controls-open={controls_open}
34
- bind:this={controls}
43
+ bind:this={controls_div}
35
44
  role="dialog"
36
45
  {...panel_props}
37
- class="controls {panel_props.class ?? ``}"
46
+ class="{panel_class} {panel_props.class ?? ``}"
38
47
  >
39
48
  {#if controls_content}
40
49
  {@render controls_content()}
@@ -45,16 +54,18 @@ function toggle_controls() {
45
54
  <style>
46
55
  .controls-toggle {
47
56
  background-color: transparent;
48
- min-width: 28px;
49
- height: 28px;
50
- padding: 0.125rem 0.25rem;
51
- font-size: 0.8rem;
57
+ width: 30px;
58
+ height: 30px;
52
59
  box-sizing: border-box;
60
+ display: flex;
61
+ place-items: center;
62
+ padding: 4pt 4pt;
63
+ border-radius: 50%;
53
64
  }
54
65
  .controls-toggle:hover {
55
- background-color: transparent !important;
66
+ background-color: rgba(255, 255, 255, 0.1);
56
67
  }
57
- .controls {
68
+ .controls-panel {
58
69
  position: absolute;
59
70
  left: unset;
60
71
  background: transparent;
@@ -62,16 +73,14 @@ function toggle_controls() {
62
73
  display: grid;
63
74
  gap: var(--controls-gap, 4pt);
64
75
  text-align: var(--controls-text-align, left);
65
- transition:
66
- visibility var(--controls-transition-duration, 0.3s),
67
- opacity var(--controls-transition-duration, 0.3s);
76
+ transition: var(--controls-transition, 0.3s);
68
77
  box-sizing: border-box;
69
- top: var(--controls-top, 30pt);
78
+ top: var(--controls-top, 20pt);
70
79
  right: var(--controls-right, 6pt);
71
80
  background: var(--controls-bg, rgba(10, 10, 10, 0.95));
72
81
  padding: var(--controls-padding, 6pt 9pt);
73
82
  border-radius: var(--controls-border-radius, 3pt);
74
- width: var(--controls-width, 20em);
83
+ width: var(--controls-width, 28em);
75
84
  max-width: var(--controls-max-width, 90cqw);
76
85
  color: var(--controls-text-color);
77
86
  overflow: auto;
@@ -81,31 +90,31 @@ function toggle_controls() {
81
90
  z-index: var(--controls-z-index, 1);
82
91
  pointer-events: none;
83
92
  }
84
- .controls.controls-open {
93
+ .controls-panel.controls-open {
85
94
  visibility: visible !important;
86
95
  opacity: 1 !important;
87
96
  pointer-events: auto !important;
88
97
  }
89
- .controls :global(hr) {
98
+ .controls-panel :global(hr) {
90
99
  border: none;
91
100
  background: var(--controls-hr-bg, gray);
92
101
  margin: var(--controls-hr-margin, 0);
93
102
  height: var(--controls-hr-height, 0.5px);
94
103
  }
95
- .controls :global(label) {
104
+ .controls-panel :global(label) {
96
105
  display: flex;
97
106
  align-items: center;
98
107
  gap: var(--controls-label-gap, 2pt);
99
108
  }
100
- .controls :global(input[type='range']) {
109
+ .controls-panel :global(input[type='range']) {
101
110
  margin-left: auto;
102
111
  width: var(--controls-input-range-width, 100px);
103
112
  flex-shrink: 0;
104
113
  }
105
- .controls :global(.slider-control input[type='range']) {
114
+ .controls-panel :global(.slider-control input[type='range']) {
106
115
  margin-left: 0;
107
116
  }
108
- .controls :global(input[type='number']) {
117
+ .controls-panel :global(input[type='number']) {
109
118
  box-sizing: border-box;
110
119
  text-align: center;
111
120
  border-radius: var(--controls-input-num-border-radius, 3pt);
@@ -116,43 +125,43 @@ function toggle_controls() {
116
125
  margin-left: var(--controls-input-num-margin-left, 6pt);
117
126
  flex-shrink: 0;
118
127
  }
119
- .controls :global(input::-webkit-inner-spin-button) {
128
+ .controls-panel :global(input::-webkit-inner-spin-button) {
120
129
  display: none;
121
130
  }
122
- .controls :global(button) {
131
+ .controls-panel :global(button) {
123
132
  width: max-content;
124
133
  background-color: var(--controls-btn-bg, rgba(255, 255, 255, 0.2));
125
134
  }
126
- .controls :global(select) {
135
+ .controls-panel :global(select) {
127
136
  margin: var(--controls-select-margin, 0 0 0 5pt);
128
137
  color: var(--controls-select-color, white);
129
138
  background-color: var(--controls-select-bg, rgba(255, 255, 255, 0.1));
130
139
  }
131
- .controls :global(input[type='color']) {
140
+ .controls-panel :global(input[type='color']) {
132
141
  width: var(--input-color-width, 40px);
133
142
  height: var(--input-color-height, 16px);
134
143
  margin: var(--input-color-margin, 0 0 0 5pt);
135
144
  border: var(--input-color-border, 1px solid rgba(255, 255, 255, 0.05));
136
145
  box-sizing: border-box;
137
146
  }
138
- .controls :global(.section-heading) {
147
+ .controls-panel :global(.section-heading) {
139
148
  margin: 8pt 0 2pt;
140
149
  font-size: 0.9em;
141
150
  color: var(--text-muted, #ccc);
142
151
  }
143
- .controls :global(.control-row) {
152
+ .controls-panel :global(.control-row) {
144
153
  display: flex;
145
154
  gap: 4pt;
146
155
  align-items: flex-start;
147
156
  }
148
- .controls :global(.control-row label) {
157
+ .controls-panel :global(.control-row label) {
149
158
  min-width: 0;
150
159
  }
151
- .controls :global(.control-row label.compact) {
160
+ .controls-panel :global(.control-row label.compact) {
152
161
  flex: 0 0 auto;
153
162
  margin-right: 8pt;
154
163
  }
155
- .controls :global(.control-row label.slider-control) {
164
+ .controls-panel :global(.control-row label.slider-control) {
156
165
  flex: 1;
157
166
  }
158
167
  </style>
@@ -11,7 +11,8 @@ interface Props {
11
11
  open_icon?: IconName;
12
12
  closed_icon?: IconName;
13
13
  toggle_controls_btn?: HTMLButtonElement;
14
- controls?: HTMLDivElement;
14
+ controls_div?: HTMLDivElement;
15
+ icon_style?: string;
15
16
  }
16
17
  declare const ControlPanel: import("svelte").Component<Props, {}, "controls_open">;
17
18
  type ControlPanel = ReturnType<typeof ControlPanel>;
package/dist/api.js CHANGED
@@ -15,8 +15,8 @@ export async function fetch_zipped(url, { unzip = true } = {}) {
15
15
  return (await response.blob());
16
16
  return JSON.parse(await decompress(response.body));
17
17
  }
18
- // Function to download data to a file
19
- export function download(data, filename, type) {
18
+ // Original download implementation
19
+ function default_download(data, filename, type) {
20
20
  const file = new Blob([data], { type });
21
21
  const link = document.createElement(`a`);
22
22
  const url = URL.createObjectURL(file);
@@ -28,3 +28,13 @@ export function download(data, filename, type) {
28
28
  link.remove();
29
29
  URL.revokeObjectURL(url);
30
30
  }
31
+ // Function to download data to a file - checks for global override first
32
+ export function download(data, filename, type) {
33
+ // Check if there's a global download override (used by VSCode extension)
34
+ const global_download = globalThis.download;
35
+ if (typeof global_download === `function` && global_download !== download) {
36
+ return global_download(data, filename, type);
37
+ }
38
+ // Use default browser download
39
+ return default_download(data, filename, type);
40
+ }
@@ -1,4 +1,8 @@
1
1
  import type { CompositionType, ElementSymbol } from '..';
2
+ export declare const atomic_number_to_symbol: Partial<Record<number, ElementSymbol>>;
3
+ export declare const symbol_to_atomic_number: Partial<Record<ElementSymbol, number>>;
4
+ export declare const atomic_weights: Map<"K" | "H" | "He" | "Li" | "Be" | "B" | "C" | "N" | "O" | "F" | "Ne" | "Na" | "Mg" | "Al" | "Si" | "P" | "S" | "Cl" | "Ar" | "Ca" | "Sc" | "Ti" | "V" | "Cr" | "Mn" | "Fe" | "Co" | "Ni" | "Cu" | "Zn" | "Ga" | "Ge" | "As" | "Se" | "Br" | "Kr" | "Rb" | "Sr" | "Y" | "Zr" | "Nb" | "Mo" | "Tc" | "Ru" | "Rh" | "Pd" | "Ag" | "Cd" | "In" | "Sn" | "Sb" | "Te" | "I" | "Xe" | "Cs" | "Ba" | "La" | "Ce" | "Pr" | "Nd" | "Pm" | "Sm" | "Eu" | "Gd" | "Tb" | "Dy" | "Ho" | "Er" | "Tm" | "Yb" | "Lu" | "Hf" | "Ta" | "W" | "Re" | "Os" | "Ir" | "Pt" | "Au" | "Hg" | "Tl" | "Pb" | "Bi" | "Po" | "At" | "Rn" | "Fr" | "Ra" | "Ac" | "Th" | "Pa" | "U" | "Np" | "Pu" | "Am" | "Cm" | "Bk" | "Cf" | "Es" | "Fm" | "Md" | "No" | "Lr" | "Rf" | "Db" | "Sg" | "Bh" | "Hs" | "Mt" | "Ds" | "Rg" | "Cn" | "Nh" | "Fl" | "Mc" | "Lv" | "Ts" | "Og", number>;
5
+ export declare const element_electronegativity_map: Map<"K" | "H" | "He" | "Li" | "Be" | "B" | "C" | "N" | "O" | "F" | "Ne" | "Na" | "Mg" | "Al" | "Si" | "P" | "S" | "Cl" | "Ar" | "Ca" | "Sc" | "Ti" | "V" | "Cr" | "Mn" | "Fe" | "Co" | "Ni" | "Cu" | "Zn" | "Ga" | "Ge" | "As" | "Se" | "Br" | "Kr" | "Rb" | "Sr" | "Y" | "Zr" | "Nb" | "Mo" | "Tc" | "Ru" | "Rh" | "Pd" | "Ag" | "Cd" | "In" | "Sn" | "Sb" | "Te" | "I" | "Xe" | "Cs" | "Ba" | "La" | "Ce" | "Pr" | "Nd" | "Pm" | "Sm" | "Eu" | "Gd" | "Tb" | "Dy" | "Ho" | "Er" | "Tm" | "Yb" | "Lu" | "Hf" | "Ta" | "W" | "Re" | "Os" | "Ir" | "Pt" | "Au" | "Hg" | "Tl" | "Pb" | "Bi" | "Po" | "At" | "Rn" | "Fr" | "Ra" | "Ac" | "Th" | "Pa" | "U" | "Np" | "Pu" | "Am" | "Cm" | "Bk" | "Cf" | "Es" | "Fm" | "Md" | "No" | "Lr" | "Rf" | "Db" | "Sg" | "Bh" | "Hs" | "Mt" | "Ds" | "Rg" | "Cn" | "Nh" | "Fl" | "Mc" | "Lv" | "Ts" | "Og", number>;
2
6
  export declare function atomic_number_to_element_symbol(atomic_number: number): ElementSymbol | null;
3
7
  export declare function element_symbol_to_atomic_number(symbol: ElementSymbol): number | null;
4
8
  export declare function convert_atomic_numbers_to_symbols(atomic_composition: Record<number, number>): CompositionType;
@@ -1,16 +1,16 @@
1
1
  import { elem_symbols } from '..';
2
2
  import element_data from '../element/data';
3
3
  // Create a mapping from atomic numbers to element symbols
4
- const atomic_number_to_symbol = {};
5
- const symbol_to_atomic_number = {};
4
+ export const atomic_number_to_symbol = {};
5
+ export const symbol_to_atomic_number = {};
6
6
  // Create mass/electronegativity maps for O(1) lookups in loops below
7
- const element_atomic_mass_map = new Map();
8
- const element_electronegativity_map = new Map();
7
+ export const atomic_weights = new Map();
8
+ export const element_electronegativity_map = new Map();
9
9
  // Populate maps at module load time
10
10
  for (const element of element_data) {
11
11
  atomic_number_to_symbol[element.number] = element.symbol;
12
12
  symbol_to_atomic_number[element.symbol] = element.number;
13
- element_atomic_mass_map.set(element.symbol, element.atomic_mass);
13
+ atomic_weights.set(element.symbol, element.atomic_mass);
14
14
  element_electronegativity_map.set(element.symbol, element.electronegativity ?? 0);
15
15
  }
16
16
  // Convert atomic number to element symbol
@@ -134,7 +134,7 @@ export function composition_to_percentages(composition, by_weight = false) {
134
134
  // Calculate weight for each element
135
135
  for (const [element, amount] of Object.entries(composition)) {
136
136
  if (typeof amount === `number` && amount > 0) {
137
- const atomic_mass = element_atomic_mass_map.get(element);
137
+ const atomic_mass = atomic_weights.get(element);
138
138
  if (atomic_mass === undefined) {
139
139
  throw new Error(`Unknown element: ${element}`);
140
140
  }
@@ -8,14 +8,14 @@ let category = $derived(element.category.replaceAll(` `, `-`));
8
8
  // background color defaults to category color (initialized in colors/index.ts, user editable in PeriodicTableControls.svelte)
9
9
  let fallback_bg_color = $derived(bg_color ?? default_category_colors[category] ?? `var(--${category}-bg-color)`);
10
10
  let contrast_bg_color = $derived(bg_color ?? default_category_colors[category]);
11
- // Determine if we should show the atomic number - default to false for multi-value splits to avoid overlap
11
+ // Determine if we should show the atomic number
12
12
  const should_show_number = $derived.by(() => {
13
13
  if (show_number !== undefined)
14
14
  return show_number;
15
- // Auto-hide number for multi-value splits to prevent overlap with value labels
15
+ // Hide number for multi-value splits to prevent overlap with value labels
16
16
  if (Array.isArray(value) && value.length > 1)
17
17
  return false;
18
- return true; // default to true for single values
18
+ return true;
19
19
  });
20
20
  // Helper function to format values appropriately
21
21
  const format_value = (val) => {
@@ -40,84 +40,69 @@ const format_value = (val) => {
40
40
  const should_show_values = $derived.by(() => {
41
41
  if (show_values !== undefined)
42
42
  return show_values;
43
- if (Array.isArray(value)) {
43
+ if (Array.isArray(value))
44
44
  return !value.some((v) => is_color(v));
45
- }
46
45
  return !is_color(value);
47
46
  });
48
- // Determine the actual layout to use based on value count and split_layout prop
49
- const actual_layout = $derived.by(() => {
50
- if (!Array.isArray(value))
51
- return null;
52
- if (split_layout)
53
- return split_layout;
54
- // Auto-determine layout based on value count (backwards compatibility)
55
- const layout_map = { 2: `diagonal`, 3: `horizontal`, 4: `quadrant` };
56
- if (value.length in layout_map) {
57
- return layout_map[value.length];
58
- }
59
- console.error(`Only 2, 3, or 4 values are supported for split_layout`);
60
- return null;
61
- });
62
47
  // Get the appropriate CSS classes for segments and positions based on layout
63
48
  const layout_config = $derived.by(() => {
64
- if (!Array.isArray(value) || !actual_layout)
49
+ if (!Array.isArray(value))
65
50
  return null;
66
51
  const count = value.length;
67
- switch (actual_layout) {
68
- case `diagonal`:
69
- return count === 2
70
- ? {
71
- segments: [`diagonal-top`, `diagonal-bottom`],
72
- positions: [`top-left`, `bottom-right`],
73
- }
74
- : null;
75
- case `horizontal`:
76
- return count === 3
77
- ? {
78
- segments: [`horizontal-top`, `horizontal-middle`, `horizontal-bottom`],
79
- positions: [`bar-top-left`, `bar-middle-right`, `bar-bottom-left`],
80
- }
81
- : null;
82
- case `vertical`:
83
- return count === 3
84
- ? {
85
- segments: [`vertical-left`, `vertical-middle`, `vertical-right`],
86
- positions: [`bar-left-top`, `bar-middle-bottom`, `bar-right-top`],
87
- }
88
- : null;
89
- case `triangular`:
90
- return count === 4
91
- ? {
92
- segments: [
93
- `triangle-top`,
94
- `triangle-right`,
95
- `triangle-bottom`,
96
- `triangle-left`,
97
- ],
98
- positions: [
99
- `triangle-top-pos`,
100
- `triangle-right-pos`,
101
- `triangle-bottom-pos`,
102
- `triangle-left-pos`,
103
- ],
104
- }
105
- : null;
106
- case `quadrant`:
107
- return count === 4
108
- ? {
109
- segments: [`quadrant-tl`, `quadrant-tr`, `quadrant-bl`, `quadrant-br`],
110
- positions: [
111
- `value-quadrant-tl`,
112
- `value-quadrant-tr`,
113
- `value-quadrant-bl`,
114
- `value-quadrant-br`,
115
- ],
116
- }
117
- : null;
118
- default:
119
- return null;
52
+ // Use explicit split_layout or auto-determine based on count
53
+ const layout = split_layout ?? {
54
+ 2: `diagonal`,
55
+ 3: `horizontal`,
56
+ 4: `quadrant`,
57
+ }[count];
58
+ if (!layout)
59
+ return null;
60
+ if (layout === `diagonal` && count === 2) {
61
+ return {
62
+ segments: [`diagonal-top`, `diagonal-bottom`],
63
+ positions: [`top-left`, `bottom-right`],
64
+ };
65
+ }
66
+ if (layout === `horizontal` && count === 3) {
67
+ return {
68
+ segments: [`horizontal-top`, `horizontal-middle`, `horizontal-bottom`],
69
+ positions: [`bar-top-left`, `bar-middle-right`, `bar-bottom-left`],
70
+ };
71
+ }
72
+ if (layout === `vertical` && count === 3) {
73
+ return {
74
+ segments: [`vertical-left`, `vertical-middle`, `vertical-right`],
75
+ positions: [`bar-left-top`, `bar-middle-bottom`, `bar-right-top`],
76
+ };
120
77
  }
78
+ if (layout === `triangular` && count === 4) {
79
+ return {
80
+ segments: [
81
+ `triangle-top`,
82
+ `triangle-right`,
83
+ `triangle-bottom`,
84
+ `triangle-left`,
85
+ ],
86
+ positions: [
87
+ `triangle-top-pos`,
88
+ `triangle-right-pos`,
89
+ `triangle-bottom-pos`,
90
+ `triangle-left-pos`,
91
+ ],
92
+ };
93
+ }
94
+ if (layout === `quadrant` && count === 4) {
95
+ return {
96
+ segments: [`quadrant-tl`, `quadrant-tr`, `quadrant-bl`, `quadrant-br`],
97
+ positions: [
98
+ `value-quadrant-tl`,
99
+ `value-quadrant-tr`,
100
+ `value-quadrant-bl`,
101
+ `value-quadrant-br`,
102
+ ],
103
+ };
104
+ }
105
+ return null;
121
106
  });
122
107
  </script>
123
108
 
package/dist/icons.d.ts CHANGED
@@ -77,24 +77,12 @@ export declare const icon_data: {
77
77
  readonly height: "24";
78
78
  readonly path: "M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4M9 18c-4.51 2-5-2-7-2";
79
79
  };
80
- readonly Contact: {
81
- readonly viewBox: "0 0 24 24";
82
- readonly width: "24";
83
- readonly height: "24";
84
- readonly path: "M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zM22 7l-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7";
85
- };
86
80
  readonly Changelog: {
87
81
  readonly viewBox: "0 0 24 24";
88
82
  readonly width: "24";
89
83
  readonly height: "24";
90
84
  readonly path: "M13 3a9 9 0 0 0-9 9H1l4 4l4-4H6c0-3.87 3.13-7 7-7s7 3.13 7 7s-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.95 8.95 0 0 0 13 21a9 9 0 0 0 0-18m-1 5v5l4.25 2.52l.77-1.28l-3.52-2.09V8z";
91
85
  };
92
- readonly GitHubMark: {
93
- readonly viewBox: "0 0 16 16";
94
- readonly width: "24";
95
- readonly height: "24";
96
- readonly path: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z";
97
- };
98
86
  readonly Info: {
99
87
  readonly viewBox: "0 0 24 24";
100
88
  readonly width: "24";
@@ -107,18 +95,6 @@ export declare const icon_data: {
107
95
  readonly height: "24";
108
96
  readonly path: "M14 21v-1.65q0-.2.075-.387t.225-.338l5.225-5.2q.225-.225.5-.325t.55-.1q.3 0 .575.113t.5.337l.925.925q.2.225.313.5t.112.55t-.1.563t-.325.512l-5.2 5.2q-.15.15-.337.225T16.65 22H15q-.425 0-.712-.287T14 21m7.5-5.575l-.925-.925zm-6 5.075h.95l3.025-3.05l-.925-.925l-3.05 3.025zM6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h7.175q.4 0 .763.15t.637.425l4.85 4.85q.275.275.425.638t.15.762v1.425q0 .425-.288.713T19 11.25t-.712-.288T18 10.25V9h-4q-.425 0-.712-.288T13 8V4H6v16h5q.425 0 .713.288T12 21t-.288.713T11 22zm0-2V4zm13.025-3.025l-.475-.45l.925.925z";
109
97
  };
110
- readonly Mail: {
111
- readonly viewBox: "0 0 24 24";
112
- readonly width: "24";
113
- readonly height: "24";
114
- readonly path: "M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z M22 6l-10 7L2 6";
115
- };
116
- readonly Globe: {
117
- readonly viewBox: "0 0 24 24";
118
- readonly width: "24";
119
- readonly height: "24";
120
- readonly path: "M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zM2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z";
121
- };
122
98
  readonly CheckCircle: {
123
99
  readonly viewBox: "0 0 24 24";
124
100
  readonly width: "24";
@@ -431,5 +407,13 @@ export declare const icon_data: {
431
407
  readonly height: "24";
432
408
  readonly path: "M2 2h2v18h18v2H2zm7 8a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3m4-8a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3m5 10a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3";
433
409
  };
410
+ readonly Histogram: {
411
+ readonly viewBox: "0 0 48 48";
412
+ readonly width: "24";
413
+ readonly height: "24";
414
+ readonly stroke: "currentColor";
415
+ readonly fill: "currentColor";
416
+ readonly path: "M4 42h40z M4 42h40 M8 28h6v14H8zm13-10h6v24h-6zM34 6h6v36h-6z";
417
+ };
434
418
  };
435
419
  export type IconName = keyof typeof icon_data;
package/dist/icons.js CHANGED
@@ -78,24 +78,12 @@ export const icon_data = {
78
78
  height: `24`,
79
79
  path: `M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4M9 18c-4.51 2-5-2-7-2`,
80
80
  },
81
- Contact: {
82
- viewBox: `0 0 24 24`,
83
- width: `24`,
84
- height: `24`,
85
- path: `M4 4h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2zM22 7l-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7`,
86
- },
87
81
  Changelog: {
88
82
  viewBox: `0 0 24 24`,
89
83
  width: `24`,
90
84
  height: `24`,
91
85
  path: `M13 3a9 9 0 0 0-9 9H1l4 4l4-4H6c0-3.87 3.13-7 7-7s7 3.13 7 7s-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.95 8.95 0 0 0 13 21a9 9 0 0 0 0-18m-1 5v5l4.25 2.52l.77-1.28l-3.52-2.09V8z`,
92
86
  },
93
- GitHubMark: {
94
- viewBox: `0 0 16 16`,
95
- width: `24`,
96
- height: `24`,
97
- path: `M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z`,
98
- },
99
87
  Info: {
100
88
  viewBox: `0 0 24 24`,
101
89
  width: `24`,
@@ -108,18 +96,6 @@ export const icon_data = {
108
96
  height: `24`,
109
97
  path: `M14 21v-1.65q0-.2.075-.387t.225-.338l5.225-5.2q.225-.225.5-.325t.55-.1q.3 0 .575.113t.5.337l.925.925q.2.225.313.5t.112.55t-.1.563t-.325.512l-5.2 5.2q-.15.15-.337.225T16.65 22H15q-.425 0-.712-.287T14 21m7.5-5.575l-.925-.925zm-6 5.075h.95l3.025-3.05l-.925-.925l-3.05 3.025zM6 22q-.825 0-1.412-.587T4 20V4q0-.825.588-1.412T6 2h7.175q.4 0 .763.15t.637.425l4.85 4.85q.275.275.425.638t.15.762v1.425q0 .425-.288.713T19 11.25t-.712-.288T18 10.25V9h-4q-.425 0-.712-.288T13 8V4H6v16h5q.425 0 .713.288T12 21t-.288.713T11 22zm0-2V4zm13.025-3.025l-.475-.45l.925.925z`,
110
98
  },
111
- Mail: {
112
- viewBox: `0 0 24 24`,
113
- width: `24`,
114
- height: `24`,
115
- path: `M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z M22 6l-10 7L2 6`,
116
- },
117
- Globe: {
118
- viewBox: `0 0 24 24`,
119
- width: `24`,
120
- height: `24`,
121
- path: `M12 2a10 10 0 1 1 0 20 10 10 0 0 1 0-20zM2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z`,
122
- },
123
99
  CheckCircle: {
124
100
  viewBox: `0 0 24 24`,
125
101
  width: `24`,
@@ -432,4 +408,12 @@ export const icon_data = {
432
408
  height: `24`,
433
409
  path: `M2 2h2v18h18v2H2zm7 8a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3m4-8a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3m5 10a3 3 0 0 1 3 3a3 3 0 0 1-3 3a3 3 0 0 1-3-3a3 3 0 0 1 3-3`,
434
410
  },
411
+ Histogram: {
412
+ viewBox: `0 0 48 48`,
413
+ width: `24`,
414
+ height: `24`,
415
+ stroke: `currentColor`,
416
+ fill: `currentColor`,
417
+ path: `M4 42h40z M4 42h40 M8 28h6v14H8zm13-10h6v24h-6zM34 6h6v36h-6z`,
418
+ },
435
419
  };
package/dist/index.d.ts CHANGED
@@ -13,9 +13,9 @@ export { default as Nucleus } from './Nucleus.svelte';
13
13
  export * from './periodic-table';
14
14
  export * from './plot';
15
15
  export { default as Spinner } from './Spinner.svelte';
16
+ export * from './structure';
16
17
  export { default as Structure } from './structure/Structure.svelte';
17
18
  export { default as Trajectory } from './trajectory/Trajectory.svelte';
18
- export * from './structure';
19
19
  export type Category = (typeof categories)[number];
20
20
  export type ElementSymbol = (typeof elem_symbols)[number];
21
21
  export type CompositionType = Partial<Record<ElementSymbol, number>>;
package/dist/index.js CHANGED
@@ -12,9 +12,9 @@ export { default as Nucleus } from './Nucleus.svelte';
12
12
  export * from './periodic-table';
13
13
  export * from './plot';
14
14
  export { default as Spinner } from './Spinner.svelte';
15
+ export * from './structure';
15
16
  export { default as Structure } from './structure/Structure.svelte';
16
17
  export { default as Trajectory } from './trajectory/Trajectory.svelte';
17
- export * from './structure';
18
18
  export const crystal_systems = [
19
19
  `triclinic`,
20
20
  `monoclinic`,
@@ -8,7 +8,6 @@ export declare function is_compressed_file(filename: string): boolean;
8
8
  export declare function remove_compression_extension(filename: string): string;
9
9
  export declare function detect_compression_format(filename: string): CompressionFormat | null;
10
10
  export declare function decompress_data(data: ArrayBuffer, format: CompressionFormat): Promise<string>;
11
- export declare const decompress_gzip: (data: ArrayBuffer) => Promise<string>;
12
11
  export declare function decompress_file(file: File): Promise<{
13
12
  content: string;
14
13
  filename: string;
@@ -40,8 +40,6 @@ export async function decompress_data(data, format) {
40
40
  throw `Failed to decompress ${format} file: ${error}`;
41
41
  }
42
42
  }
43
- // Legacy compatibility
44
- export const decompress_gzip = (data) => decompress_data(data, `gzip`);
45
43
  export function decompress_file(file) {
46
44
  const compressed = is_compressed_file(file.name);
47
45
  return new Promise((resolve, reject) => {
@@ -69,7 +67,7 @@ export function decompress_file(file) {
69
67
  reject(error);
70
68
  }
71
69
  };
72
- reader.onerror = () => reject(new Error(`Failed to read file`));
70
+ reader.onerror = () => reject(new Error(`Failed to read file ${file.name}`));
73
71
  if (compressed)
74
72
  reader.readAsArrayBuffer(file);
75
73
  else
@@ -1,9 +1,13 @@
1
1
  import type { AnyStructure } from '..';
2
+ import type * as THREE from 'three';
2
3
  import { WebGLRenderer } from 'three';
3
4
  export interface CanvasWithRenderer extends HTMLCanvasElement {
4
5
  __customRenderer?: WebGLRenderer;
5
6
  }
6
7
  export declare function generate_structure_filename(structure: AnyStructure | undefined, extension: string): string;
8
+ export declare function generate_xyz_content(structure?: AnyStructure): string;
9
+ export declare function generate_json_content(structure?: AnyStructure): string;
10
+ export declare function copy_to_clipboard(text: string): Promise<void>;
7
11
  export declare function export_xyz(structure?: AnyStructure): void;
8
12
  export declare function export_json(structure?: AnyStructure): void;
9
- export declare function export_png(canvas: HTMLCanvasElement | null, structure: AnyStructure | undefined, png_dpi?: number): void;
13
+ export declare function export_png(canvas: HTMLCanvasElement | null, structure: AnyStructure | undefined, png_dpi?: number, scene?: THREE.Scene | null, camera?: THREE.Camera | null): void;