matterviz 0.3.2 → 0.3.4
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/EmptyState.svelte +10 -2
- package/dist/FilePicker.svelte +123 -82
- package/dist/Icon.svelte +18 -12
- package/dist/MillerIndexInput.svelte +27 -21
- package/dist/api/optimade.js +6 -6
- package/dist/app.css +216 -207
- package/dist/brillouin/BrillouinZone.svelte +292 -149
- package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneControls.svelte +32 -5
- package/dist/brillouin/BrillouinZoneExportPane.svelte +69 -42
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +99 -68
- package/dist/brillouin/BrillouinZoneScene.svelte +275 -163
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneTooltip.svelte +17 -7
- package/dist/brillouin/compute.js +11 -6
- package/dist/chempot-diagram/ChemPotDiagram.svelte +162 -27
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +451 -281
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +2148 -1642
- package/dist/chempot-diagram/ChemPotScene3D.svelte +8 -5
- package/dist/chempot-diagram/async-compute.svelte.d.ts +3 -0
- package/dist/chempot-diagram/async-compute.svelte.js +77 -0
- package/dist/chempot-diagram/chempot-worker.d.ts +1 -0
- package/dist/chempot-diagram/chempot-worker.js +11 -0
- package/dist/chempot-diagram/color.js +1 -2
- package/dist/chempot-diagram/compute.d.ts +10 -0
- package/dist/chempot-diagram/compute.js +250 -88
- package/dist/chempot-diagram/index.d.ts +2 -1
- package/dist/chempot-diagram/index.js +2 -1
- package/dist/chempot-diagram/temperature.js +8 -9
- package/dist/chempot-diagram/types.d.ts +3 -0
- package/dist/chempot-diagram/types.js +1 -0
- package/dist/colors/index.d.ts +1 -1
- package/dist/colors/index.js +5 -3
- package/dist/composition/BarChart.svelte +128 -55
- package/dist/composition/BubbleChart.svelte +102 -49
- package/dist/composition/Composition.svelte +100 -79
- package/dist/composition/Formula.svelte +108 -62
- package/dist/composition/FormulaFilter.svelte +665 -537
- package/dist/composition/PieChart.svelte +183 -108
- package/dist/composition/format.d.ts +5 -0
- package/dist/composition/format.js +20 -3
- package/dist/composition/parse.js +14 -9
- package/dist/convex-hull/ConvexHull.svelte +93 -40
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +549 -360
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +1296 -827
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +1004 -688
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullControls.svelte +115 -28
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullInfoPane.svelte +29 -3
- package/dist/convex-hull/ConvexHullStats.svelte +425 -328
- package/dist/convex-hull/ConvexHullTooltip.svelte +40 -16
- package/dist/convex-hull/GasPressureControls.svelte +104 -61
- package/dist/convex-hull/StructurePopup.svelte +25 -4
- package/dist/convex-hull/TemperatureSlider.svelte +45 -25
- package/dist/convex-hull/barycentric-coords.js +13 -7
- package/dist/convex-hull/demo-temperature.js +8 -4
- package/dist/convex-hull/gas-thermodynamics.js +17 -12
- package/dist/convex-hull/helpers.d.ts +9 -0
- package/dist/convex-hull/helpers.js +77 -34
- package/dist/convex-hull/thermodynamics.js +61 -56
- package/dist/convex-hull/types.d.ts +9 -14
- package/dist/convex-hull/types.js +0 -17
- package/dist/coordination/CoordinationBarPlot.svelte +227 -154
- package/dist/element/BohrAtom.svelte +55 -12
- package/dist/element/ElementHeading.svelte +7 -2
- package/dist/element/ElementPhoto.svelte +15 -9
- package/dist/element/ElementStats.svelte +10 -4
- package/dist/element/ElementTile.svelte +137 -73
- package/dist/element/Nucleus.svelte +39 -11
- package/dist/element/data.js +1 -1
- package/dist/feedback/ClickFeedback.svelte +16 -5
- package/dist/feedback/DragOverlay.svelte +10 -2
- package/dist/feedback/Spinner.svelte +4 -2
- package/dist/feedback/StatusMessage.svelte +8 -2
- package/dist/fermi-surface/FermiSlice.svelte +118 -88
- package/dist/fermi-surface/FermiSurface.svelte +328 -187
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceControls.svelte +113 -46
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +535 -342
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +14 -5
- package/dist/fermi-surface/compute.js +16 -20
- package/dist/fermi-surface/parse.js +24 -14
- package/dist/fermi-surface/symmetry.js +2 -7
- package/dist/fermi-surface/types.d.ts +3 -5
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +1019 -765
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +1 -1
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +76 -22
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +2 -3
- package/dist/icons.js +47 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/io/decompress.js +1 -1
- package/dist/io/export.d.ts +3 -0
- package/dist/io/export.js +129 -143
- package/dist/io/is-binary.js +2 -3
- package/dist/io/url-drop.js +1 -2
- package/dist/isosurface/Isosurface.svelte +202 -148
- package/dist/isosurface/IsosurfaceControls.svelte +46 -28
- package/dist/isosurface/parse.js +34 -29
- package/dist/isosurface/slice.js +5 -10
- package/dist/isosurface/types.d.ts +2 -1
- package/dist/isosurface/types.js +61 -12
- package/dist/labels.js +11 -8
- package/dist/layout/FullscreenToggle.svelte +11 -2
- package/dist/layout/InfoCard.svelte +38 -6
- package/dist/layout/InfoTag.svelte +63 -32
- package/dist/layout/PropertyFilter.svelte +82 -37
- package/dist/layout/SettingsSection.svelte +85 -55
- package/dist/layout/SubpageGrid.svelte +10 -2
- package/dist/layout/json-tree/JsonNode.svelte +183 -138
- package/dist/layout/json-tree/JsonTree.svelte +499 -413
- package/dist/layout/json-tree/JsonValue.svelte +127 -99
- package/dist/layout/json-tree/utils.js +4 -2
- package/dist/marching-cubes.js +25 -2
- package/dist/math.d.ts +13 -17
- package/dist/math.js +133 -67
- package/dist/overlays/ContextMenu.svelte +65 -40
- package/dist/overlays/DraggablePane.svelte +211 -139
- package/dist/periodic-table/PeriodicTable.svelte +278 -145
- package/dist/periodic-table/PeriodicTableControls.svelte +178 -128
- package/dist/periodic-table/PropertySelect.svelte +25 -7
- package/dist/periodic-table/TableInset.svelte +8 -3
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +446 -309
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramControls.svelte +102 -43
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +63 -40
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +71 -28
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +158 -101
- package/dist/phase-diagram/TdbInfoPanel.svelte +28 -4
- package/dist/phase-diagram/build-diagram.js +9 -9
- package/dist/phase-diagram/colors.js +1 -3
- package/dist/phase-diagram/parse.js +10 -9
- package/dist/phase-diagram/svg-to-diagram.js +53 -49
- package/dist/phase-diagram/utils.d.ts +1 -0
- package/dist/phase-diagram/utils.js +80 -25
- package/dist/plot/AxisLabel.svelte +28 -3
- package/dist/plot/BarPlot.svelte +1182 -734
- package/dist/plot/BarPlot.svelte.d.ts +2 -2
- package/dist/plot/BarPlotControls.svelte +31 -5
- package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ColorBar.svelte +479 -329
- package/dist/plot/ColorScaleSelect.svelte +27 -6
- package/dist/plot/ElementScatter.svelte +36 -15
- package/dist/plot/FillArea.svelte +152 -95
- package/dist/plot/Histogram.svelte +934 -571
- package/dist/plot/Histogram.svelte.d.ts +1 -1
- package/dist/plot/HistogramControls.svelte +53 -9
- package/dist/plot/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/InteractiveAxisLabel.svelte +34 -11
- package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/Line.svelte +63 -28
- package/dist/plot/PlotControls.svelte +157 -114
- package/dist/plot/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/PlotLegend.svelte +174 -91
- package/dist/plot/PlotTooltip.svelte +45 -6
- package/dist/plot/PortalSelect.svelte +175 -147
- package/dist/plot/ReferenceLine.svelte +76 -22
- package/dist/plot/ReferenceLine3D.svelte +132 -107
- package/dist/plot/ReferencePlane.svelte +146 -121
- package/dist/plot/ScatterPlot.svelte +1681 -1091
- package/dist/plot/ScatterPlot.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3D.svelte +256 -131
- package/dist/plot/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlot3DControls.svelte +113 -63
- package/dist/plot/ScatterPlot3DControls.svelte.d.ts +2 -1
- package/dist/plot/ScatterPlot3DScene.svelte +608 -403
- package/dist/plot/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/ScatterPlotControls.svelte +65 -25
- package/dist/plot/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/ScatterPoint.svelte +98 -26
- package/dist/plot/ScatterPoint.svelte.d.ts +1 -0
- package/dist/plot/SpacegroupBarPlot.svelte +142 -85
- package/dist/plot/Surface3D.svelte +159 -108
- package/dist/plot/ZeroLines.svelte +55 -3
- package/dist/plot/ZoomRect.svelte +4 -2
- package/dist/plot/axis-utils.js +1 -3
- package/dist/plot/data-cleaning.js +12 -28
- package/dist/plot/data-transform.js +2 -1
- package/dist/plot/fill-utils.js +2 -0
- package/dist/plot/layout.d.ts +4 -1
- package/dist/plot/layout.js +33 -14
- package/dist/plot/reference-line.d.ts +2 -2
- package/dist/plot/reference-line.js +7 -5
- package/dist/plot/scales.js +24 -36
- package/dist/plot/types.d.ts +11 -23
- package/dist/plot/types.js +6 -11
- package/dist/plot/utils/label-placement.d.ts +32 -15
- package/dist/plot/utils/label-placement.js +227 -66
- package/dist/plot/utils/series-visibility.js +2 -3
- package/dist/rdf/RdfPlot.svelte +143 -91
- package/dist/rdf/calc-rdf.js +4 -5
- package/dist/sanitize.d.ts +4 -0
- package/dist/sanitize.js +107 -0
- package/dist/settings.d.ts +18 -6
- package/dist/settings.js +46 -16
- package/dist/spectral/Bands.svelte +632 -453
- package/dist/spectral/BandsAndDos.svelte +90 -49
- package/dist/spectral/BrillouinBandsDos.svelte +151 -93
- package/dist/spectral/Dos.svelte +389 -258
- package/dist/spectral/helpers.js +55 -43
- package/dist/state.svelte.d.ts +1 -1
- package/dist/state.svelte.js +3 -2
- package/dist/structure/Arrow.svelte +59 -20
- package/dist/structure/AtomLegend.svelte +215 -134
- package/dist/structure/Bond.svelte +73 -47
- package/dist/structure/CanvasTooltip.svelte +10 -2
- package/dist/structure/CellSelect.svelte +72 -45
- package/dist/structure/Cylinder.svelte +33 -17
- package/dist/structure/Lattice.svelte +88 -33
- package/dist/structure/Structure.svelte +1063 -797
- package/dist/structure/Structure.svelte.d.ts +1 -1
- package/dist/structure/StructureControls.svelte +349 -118
- package/dist/structure/StructureExportPane.svelte +124 -89
- package/dist/structure/StructureExportPane.svelte.d.ts +1 -1
- package/dist/structure/StructureInfoPane.svelte +304 -237
- package/dist/structure/StructureScene.svelte +879 -443
- package/dist/structure/StructureScene.svelte.d.ts +15 -7
- package/dist/structure/atom-properties.js +8 -8
- package/dist/structure/bonding.js +6 -7
- package/dist/structure/export.js +14 -29
- package/dist/structure/ferrox-wasm.js +1 -1
- package/dist/structure/index.d.ts +13 -3
- package/dist/structure/index.js +83 -23
- package/dist/structure/measure.d.ts +2 -2
- package/dist/structure/measure.js +4 -44
- package/dist/structure/parse.js +113 -141
- package/dist/structure/partial-occupancy.js +7 -10
- package/dist/structure/pbc.d.ts +1 -0
- package/dist/structure/pbc.js +16 -6
- package/dist/structure/supercell.d.ts +2 -2
- package/dist/structure/supercell.js +12 -22
- package/dist/structure/validation.js +1 -2
- package/dist/symmetry/SymmetryStats.svelte +84 -41
- package/dist/symmetry/WyckoffTable.svelte +26 -6
- package/dist/symmetry/cell-transform.js +5 -3
- package/dist/symmetry/index.js +8 -7
- package/dist/symmetry/spacegroups.js +148 -148
- package/dist/table/HeatmapTable.svelte +790 -554
- package/dist/table/HeatmapTable.svelte.d.ts +1 -1
- package/dist/table/ToggleMenu.svelte +125 -92
- package/dist/table/index.js +2 -4
- package/dist/theme/ThemeControl.svelte +21 -12
- package/dist/time.js +4 -1
- package/dist/tooltip/TooltipContent.svelte +33 -8
- package/dist/trajectory/Trajectory.svelte +758 -558
- package/dist/trajectory/TrajectoryError.svelte +14 -3
- package/dist/trajectory/TrajectoryExportPane.svelte +137 -83
- package/dist/trajectory/TrajectoryInfoPane.svelte +272 -143
- package/dist/trajectory/extract.js +10 -26
- package/dist/trajectory/format-detect.js +5 -5
- package/dist/trajectory/frame-reader.d.ts +1 -1
- package/dist/trajectory/frame-reader.js +5 -12
- package/dist/trajectory/helpers.d.ts +0 -1
- package/dist/trajectory/helpers.js +2 -17
- package/dist/trajectory/index.js +14 -12
- package/dist/trajectory/parse/ase.js +5 -4
- package/dist/trajectory/parse/hdf5.js +26 -18
- package/dist/trajectory/parse/index.js +13 -18
- package/dist/trajectory/parse/lammps.js +17 -7
- package/dist/trajectory/parse/vasp.js +5 -2
- package/dist/trajectory/parse/xyz.js +8 -7
- package/dist/trajectory/plotting.js +13 -8
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +13 -0
- package/dist/xrd/XrdPlot.svelte +337 -247
- package/dist/xrd/broadening.js +14 -9
- package/dist/xrd/calc-xrd.js +12 -18
- package/dist/xrd/parse.d.ts +1 -1
- package/dist/xrd/parse.js +17 -17
- package/package.json +99 -103
- package/readme.md +1 -1
- /package/dist/theme/{themes.js → themes.mjs} +0 -0
package/dist/io/export.js
CHANGED
|
@@ -1,182 +1,161 @@
|
|
|
1
1
|
import { download } from './fetch';
|
|
2
2
|
import { create_structure_filename } from '../structure/export';
|
|
3
|
-
import { Vector2
|
|
3
|
+
import { Vector2 } from 'three';
|
|
4
4
|
function is_webgl_renderer_like(value) {
|
|
5
5
|
if (typeof value !== `object` || !value)
|
|
6
6
|
return false;
|
|
7
7
|
const renderer_obj = value;
|
|
8
|
-
return typeof renderer_obj.render === `function` &&
|
|
8
|
+
return (typeof renderer_obj.render === `function` &&
|
|
9
9
|
typeof renderer_obj.getPixelRatio === `function` &&
|
|
10
10
|
typeof renderer_obj.setPixelRatio === `function` &&
|
|
11
11
|
typeof renderer_obj.getSize === `function` &&
|
|
12
|
-
typeof renderer_obj.setSize === `function
|
|
12
|
+
typeof renderer_obj.setSize === `function`);
|
|
13
13
|
}
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
let filename = typeof structure_or_filename === `string`
|
|
25
|
-
? structure_or_filename
|
|
26
|
-
: create_structure_filename(structure_or_filename, `png`);
|
|
27
|
-
// Inject DPI into filename
|
|
28
|
-
const suffix = `-${Math.round(png_dpi)}dpi`;
|
|
29
|
-
if (filename.toLowerCase().endsWith(`.png`)) {
|
|
30
|
-
filename = filename.replace(/\.png$/i, `${suffix}.png`);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
filename = `${filename}${suffix}.png`;
|
|
34
|
-
}
|
|
35
|
-
// Convert DPI to multiplier (72 DPI is baseline web resolution)
|
|
36
|
-
// Cap to a reasonable upper bound to avoid excessive memory use
|
|
37
|
-
const resolution_multiplier = Math.min(png_dpi / 72, 10);
|
|
38
|
-
const renderer_val = canvas.__renderer;
|
|
39
|
-
const renderer = is_webgl_renderer_like(renderer_val) ? renderer_val : undefined;
|
|
40
|
-
// Force render to populate buffer
|
|
14
|
+
// Capture a WebGL canvas as a PNG Blob at the given DPI.
|
|
15
|
+
// Temporarily adjusts renderer pixel ratio for high-res capture, then restores.
|
|
16
|
+
// Returns data directly (no browser download), suitable for programmatic capture
|
|
17
|
+
// in test suites, server-side rendering, or Python widget integration via anywidget.
|
|
18
|
+
// DPI is converted to a resolution multiplier relative to 72 DPI baseline, capped at 10x.
|
|
19
|
+
export function canvas_to_png_blob(canvas, png_dpi = 150, scene = null, camera = null) {
|
|
20
|
+
const resolution_multiplier = Math.min(png_dpi / 72, 10);
|
|
21
|
+
const renderer_val = canvas.__renderer;
|
|
22
|
+
const renderer = is_webgl_renderer_like(renderer_val) ? renderer_val : undefined;
|
|
23
|
+
if (resolution_multiplier <= 1.1 || !renderer) {
|
|
41
24
|
if (renderer && scene && camera)
|
|
42
25
|
renderer.render(scene, camera);
|
|
43
|
-
|
|
44
|
-
// Direct capture at current resolution (if DPI is close to 72 or renderer not available)
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
45
27
|
try {
|
|
46
28
|
canvas.toBlob((blob) => {
|
|
47
|
-
if (blob)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (typeof window !== `undefined`) {
|
|
52
|
-
console.warn(`Failed to generate PNG - canvas may be empty`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
29
|
+
if (blob)
|
|
30
|
+
resolve(blob);
|
|
31
|
+
else
|
|
32
|
+
reject(new Error(`Failed to generate PNG - canvas may be empty`));
|
|
55
33
|
}, `image/png`);
|
|
56
34
|
}
|
|
57
35
|
catch (error) {
|
|
58
|
-
|
|
36
|
+
reject(error);
|
|
59
37
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Temporarily modify the renderer's pixel ratio for high-res capture
|
|
41
|
+
const orig_pixel_ratio = renderer.getPixelRatio();
|
|
42
|
+
const orig_size = renderer.getSize(new Vector2());
|
|
43
|
+
const restore = () => {
|
|
44
|
+
renderer.setPixelRatio(orig_pixel_ratio);
|
|
45
|
+
renderer.setSize(orig_size.width, orig_size.height, false);
|
|
46
|
+
};
|
|
47
|
+
renderer.setPixelRatio(resolution_multiplier);
|
|
48
|
+
renderer.setSize(orig_size.width, orig_size.height, false);
|
|
49
|
+
if (scene && camera)
|
|
50
|
+
renderer.render(scene, camera);
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
65
52
|
try {
|
|
66
|
-
// Set higher pixel ratio to increase rendering resolution
|
|
67
|
-
renderer.setPixelRatio(resolution_multiplier);
|
|
68
|
-
// Force the canvas to update its resolution
|
|
69
|
-
renderer.setSize(orig_size.width, orig_size.height, false);
|
|
70
|
-
if (scene && camera) {
|
|
71
|
-
renderer.render(scene, camera);
|
|
72
|
-
}
|
|
73
|
-
// Capture the high-resolution render after paint completion
|
|
74
53
|
canvas.toBlob((blob) => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
if (typeof window !== `undefined`) {
|
|
83
|
-
console.warn(`Failed to generate high-resolution PNG`);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
54
|
+
restore();
|
|
55
|
+
if (blob)
|
|
56
|
+
resolve(blob);
|
|
57
|
+
else
|
|
58
|
+
reject(new Error(`Failed to generate high-resolution PNG`));
|
|
86
59
|
}, `image/png`);
|
|
87
60
|
}
|
|
88
61
|
catch (error) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
renderer.setPixelRatio(orig_pixel_ratio);
|
|
92
|
-
renderer.setSize(orig_size.width, orig_size.height, false);
|
|
93
|
-
if (typeof window !== `undefined`) {
|
|
94
|
-
console.warn(`Failed to render at high resolution: ${error instanceof Error ? error.message : String(error)}`);
|
|
95
|
-
}
|
|
62
|
+
restore();
|
|
63
|
+
reject(error);
|
|
96
64
|
}
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
// Export structure as PNG image from canvas (triggers browser download)
|
|
68
|
+
export function export_canvas_as_png(canvas, structure_or_filename, png_dpi = 150, scene = null, camera = null) {
|
|
69
|
+
if (!canvas) {
|
|
70
|
+
if (typeof window !== `undefined`)
|
|
71
|
+
console.warn(`Canvas not found for PNG export`);
|
|
72
|
+
return;
|
|
97
73
|
}
|
|
98
|
-
|
|
99
|
-
|
|
74
|
+
let filename = typeof structure_or_filename === `string`
|
|
75
|
+
? structure_or_filename
|
|
76
|
+
: create_structure_filename(structure_or_filename, `png`);
|
|
77
|
+
const suffix = `-${Math.round(png_dpi)}dpi`;
|
|
78
|
+
if (filename.toLowerCase().endsWith(`.png`)) {
|
|
79
|
+
filename = filename.replace(/\.png$/i, `${suffix}.png`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
filename = `${filename}${suffix}.png`;
|
|
100
83
|
}
|
|
84
|
+
canvas_to_png_blob(canvas, png_dpi, scene, camera)
|
|
85
|
+
.then((blob) => download(blob, filename, `image/png`))
|
|
86
|
+
.catch((error) => console.error(`Error exporting PNG:`, error));
|
|
101
87
|
}
|
|
102
88
|
// Helper to ensure font-family is set on SVG root
|
|
103
89
|
function set_svg_font_family(svg) {
|
|
104
90
|
const style = svg.getAttribute(`style`) || ``;
|
|
105
91
|
if (!/font-family/.test(style)) {
|
|
106
|
-
svg.setAttribute(`style`, `${style}
|
|
92
|
+
svg.setAttribute(`style`, `${style}${style ? `;` : ``}font-family:sans-serif;`);
|
|
107
93
|
}
|
|
108
94
|
// Also set as attribute for extra robustness
|
|
109
95
|
svg.setAttribute(`font-family`, `sans-serif`);
|
|
110
96
|
}
|
|
111
|
-
//
|
|
97
|
+
// Serialize an SVG element to a standalone SVG string with proper XML headers.
|
|
98
|
+
// Clones the element to avoid mutation, sets font-family/xmlns, and
|
|
99
|
+
// prepends XML declaration + SVG DOCTYPE. Returns a complete SVG document string
|
|
100
|
+
// suitable for saving to file or further processing.
|
|
101
|
+
export function svg_to_svg_string(svg_element) {
|
|
102
|
+
const cloned_svg = svg_element.cloneNode(true);
|
|
103
|
+
set_svg_font_family(cloned_svg);
|
|
104
|
+
if (!cloned_svg.hasAttribute(`xmlns`)) {
|
|
105
|
+
cloned_svg.setAttribute(`xmlns`, `http://www.w3.org/2000/svg`);
|
|
106
|
+
}
|
|
107
|
+
const svg_string = new XMLSerializer().serializeToString(cloned_svg);
|
|
108
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n${svg_string}`;
|
|
109
|
+
}
|
|
110
|
+
// Export SVG element as SVG file (triggers browser download)
|
|
112
111
|
export function export_svg_as_svg(svg_element, filename) {
|
|
112
|
+
if (!svg_element) {
|
|
113
|
+
console.warn(`SVG element not found for export`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
113
116
|
try {
|
|
114
|
-
|
|
115
|
-
console.warn(`SVG element not found for export`);
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
// Clone the SVG to avoid modifying the original
|
|
119
|
-
const cloned_svg = svg_element.cloneNode(true);
|
|
120
|
-
// Ensure the SVG has proper dimensions and viewBox
|
|
121
|
-
const viewBox = svg_element.getAttribute(`viewBox`);
|
|
122
|
-
if (viewBox)
|
|
123
|
-
cloned_svg.setAttribute(`viewBox`, viewBox);
|
|
124
|
-
// Ensure font-family is set
|
|
125
|
-
set_svg_font_family(cloned_svg);
|
|
126
|
-
// Ensure xmlns is set
|
|
127
|
-
if (!cloned_svg.hasAttribute(`xmlns`)) {
|
|
128
|
-
cloned_svg.setAttribute(`xmlns`, `http://www.w3.org/2000/svg`);
|
|
129
|
-
}
|
|
130
|
-
// Convert SVG to string
|
|
131
|
-
const svg_string = new XMLSerializer().serializeToString(cloned_svg);
|
|
132
|
-
// Add XML declaration and DOCTYPE for proper SVG format
|
|
133
|
-
const svg_content = `<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n${svg_string}`;
|
|
117
|
+
const svg_content = svg_to_svg_string(svg_element);
|
|
134
118
|
download(svg_content, filename, `image/svg+xml;charset=utf-8`);
|
|
135
119
|
}
|
|
136
120
|
catch (error) {
|
|
137
121
|
console.error(`Error exporting SVG:`, error);
|
|
138
122
|
}
|
|
139
123
|
}
|
|
140
|
-
//
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// Create an object URL from SVG Blob
|
|
176
|
-
const svg_string = new XMLSerializer().serializeToString(cloned_svg);
|
|
177
|
-
const svg_blob = new Blob([svg_string], { type: `image/svg+xml;charset=utf-8` });
|
|
178
|
-
const svg_data_url = URL.createObjectURL(svg_blob);
|
|
179
|
-
// Create an image element to load the SVG
|
|
124
|
+
// Rasterize an SVG element to a PNG Blob at the given DPI.
|
|
125
|
+
// Creates an offscreen canvas at the scaled resolution, draws the SVG via an
|
|
126
|
+
// Image element, and returns the resulting PNG Blob. Rejects if viewBox is
|
|
127
|
+
// missing or dimensions are invalid (zero width/height).
|
|
128
|
+
// DPI is converted to a resolution multiplier relative to 72 DPI baseline, capped at 10x.
|
|
129
|
+
export function svg_to_png_blob(svg_element, png_dpi = 150) {
|
|
130
|
+
const viewBox = svg_element.getAttribute(`viewBox`)?.trim();
|
|
131
|
+
if (!viewBox)
|
|
132
|
+
return Promise.reject(new Error(`SVG viewBox not found for PNG export`));
|
|
133
|
+
const parts = viewBox.split(/[\s,]+/).map(Number);
|
|
134
|
+
if (parts.length < 4 || !parts.every(Number.isFinite)) {
|
|
135
|
+
return Promise.reject(new Error(`Invalid SVG dimensions for PNG export`));
|
|
136
|
+
}
|
|
137
|
+
const [, , width, height] = parts;
|
|
138
|
+
if (!(width > 0) || !(height > 0)) {
|
|
139
|
+
return Promise.reject(new Error(`Invalid SVG dimensions for PNG export`));
|
|
140
|
+
}
|
|
141
|
+
if (!Number.isFinite(png_dpi) || png_dpi <= 0) {
|
|
142
|
+
return Promise.reject(new Error(`Invalid PNG DPI for export`));
|
|
143
|
+
}
|
|
144
|
+
const resolution_multiplier = Math.min(png_dpi / 72, 10);
|
|
145
|
+
const pixel_width = Math.round(width * resolution_multiplier);
|
|
146
|
+
const pixel_height = Math.round(height * resolution_multiplier);
|
|
147
|
+
const canvas = document.createElement(`canvas`);
|
|
148
|
+
const ctx = canvas.getContext(`2d`);
|
|
149
|
+
if (!ctx)
|
|
150
|
+
return Promise.reject(new Error(`Canvas 2D context not available`));
|
|
151
|
+
canvas.width = pixel_width;
|
|
152
|
+
canvas.height = pixel_height;
|
|
153
|
+
const cloned_svg = svg_element.cloneNode(true);
|
|
154
|
+
set_svg_font_family(cloned_svg);
|
|
155
|
+
const serialized = new XMLSerializer().serializeToString(cloned_svg);
|
|
156
|
+
const svg_blob = new Blob([serialized], { type: `image/svg+xml;charset=utf-8` });
|
|
157
|
+
const svg_data_url = URL.createObjectURL(svg_blob);
|
|
158
|
+
return new Promise((resolve, reject) => {
|
|
180
159
|
const img = new Image();
|
|
181
160
|
img.onload = () => {
|
|
182
161
|
try {
|
|
@@ -184,27 +163,34 @@ export function export_svg_as_png(svg_element, filename, png_dpi = 150) {
|
|
|
184
163
|
ctx.drawImage(img, 0, 0, pixel_width, pixel_height);
|
|
185
164
|
canvas.toBlob((blob) => {
|
|
186
165
|
if (blob)
|
|
187
|
-
|
|
166
|
+
resolve(blob);
|
|
188
167
|
else
|
|
189
|
-
|
|
168
|
+
reject(new Error(`Failed to generate PNG blob`));
|
|
190
169
|
}, `image/png`, 1);
|
|
191
170
|
}
|
|
192
171
|
catch (error) {
|
|
193
|
-
|
|
172
|
+
reject(error);
|
|
194
173
|
}
|
|
195
174
|
finally {
|
|
196
175
|
URL.revokeObjectURL(svg_data_url);
|
|
197
176
|
}
|
|
198
177
|
};
|
|
199
178
|
img.onerror = () => {
|
|
200
|
-
console.error(`Failed to load SVG for PNG export`);
|
|
201
179
|
URL.revokeObjectURL(svg_data_url);
|
|
180
|
+
reject(new Error(`Failed to load SVG for PNG export`));
|
|
202
181
|
};
|
|
203
182
|
img.src = svg_data_url;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Export SVG element as PNG (triggers browser download)
|
|
186
|
+
export function export_svg_as_png(svg_element, filename, png_dpi = 150) {
|
|
187
|
+
if (!svg_element) {
|
|
188
|
+
console.warn(`SVG element not found for PNG export`);
|
|
189
|
+
return;
|
|
204
190
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
191
|
+
svg_to_png_blob(svg_element, png_dpi)
|
|
192
|
+
.then((blob) => download(blob, filename, `image/png`))
|
|
193
|
+
.catch((error) => console.error(`Error exporting PNG:`, error));
|
|
208
194
|
}
|
|
209
195
|
// Generate FFmpeg command for WebM to MP4 conversion
|
|
210
196
|
export function get_ffmpeg_conversion_command(input_filename) {
|
package/dist/io/is-binary.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Simplified binary detection
|
|
2
2
|
export const is_binary = (content) => content.includes(`\0`) ||
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
content.length > 0.1 ||
|
|
3
|
+
(content.match(/[\u0000-\u0008\u000E-\u001F\u007F-\u00FF]/g) || []).length / content.length >
|
|
4
|
+
0.1 ||
|
|
6
5
|
(content.match(/[\u0020-\u007E]/g) || []).length / content.length < 0.7;
|
package/dist/io/url-drop.js
CHANGED
|
@@ -97,8 +97,7 @@ export async function load_from_url(url, callback) {
|
|
|
97
97
|
if (head.ok) {
|
|
98
98
|
const buf = new Uint8Array(await head.arrayBuffer());
|
|
99
99
|
const is_gzip = buf[0] === 0x1f && buf[1] === 0x8b;
|
|
100
|
-
const is_hdf5 = buf[0] === 0x89 && buf[1] === 0x48 && buf[2] === 0x44 &&
|
|
101
|
-
buf[3] === 0x46;
|
|
100
|
+
const is_hdf5 = buf[0] === 0x89 && buf[1] === 0x48 && buf[2] === 0x44 && buf[3] === 0x46;
|
|
102
101
|
if (is_gzip || is_hdf5) {
|
|
103
102
|
const resp = await fetch(url);
|
|
104
103
|
if (!resp.ok)
|