matterviz 0.4.0 → 0.4.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.
- package/dist/EmptyState.svelte +10 -4
- package/dist/FilePicker.svelte +12 -14
- package/dist/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +2 -2
- package/dist/app.css +53 -0
- package/dist/brillouin/BrillouinZone.svelte +132 -219
- package/dist/brillouin/BrillouinZone.svelte.d.ts +9 -20
- package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
- package/dist/brillouin/BrillouinZoneExportPane.svelte +47 -96
- package/dist/brillouin/BrillouinZoneExportPane.svelte.d.ts +1 -1
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +15 -42
- package/dist/brillouin/BrillouinZoneInfoPane.svelte.d.ts +2 -3
- package/dist/brillouin/BrillouinZoneScene.svelte +63 -230
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +3 -23
- package/dist/brillouin/ReciprocalVectors.svelte +39 -0
- package/dist/brillouin/ReciprocalVectors.svelte.d.ts +9 -0
- package/dist/brillouin/compute.d.ts +2 -0
- package/dist/brillouin/compute.js +80 -77
- package/dist/brillouin/geometry.d.ts +8 -0
- package/dist/brillouin/geometry.js +57 -0
- package/dist/brillouin/index.d.ts +2 -0
- package/dist/brillouin/index.js +2 -0
- package/dist/brillouin/types.d.ts +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +33 -38
- package/dist/chempot-diagram/ChemPotDiagram.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +143 -246
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +4 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +652 -976
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +7 -1
- package/dist/chempot-diagram/async-compute.svelte.js +1 -1
- package/dist/chempot-diagram/color.d.ts +3 -6
- package/dist/chempot-diagram/color.js +5 -5
- package/dist/chempot-diagram/compute.d.ts +3 -3
- package/dist/chempot-diagram/compute.js +3 -1
- package/dist/chempot-diagram/controls-state.svelte.d.ts +10 -0
- package/dist/chempot-diagram/controls-state.svelte.js +42 -0
- package/dist/chempot-diagram/export.d.ts +47 -0
- package/dist/chempot-diagram/export.js +133 -0
- package/dist/chempot-diagram/index.d.ts +1 -0
- package/dist/chempot-diagram/index.js +1 -0
- package/dist/chempot-diagram/pointer.d.ts +0 -10
- package/dist/chempot-diagram/pointer.js +4 -4
- package/dist/chempot-diagram/types.d.ts +3 -3
- package/dist/colors/index.d.ts +0 -4
- package/dist/colors/index.js +21 -22
- package/dist/composition/BarChart.svelte +37 -31
- package/dist/composition/BubbleChart.svelte +17 -17
- package/dist/composition/Composition.svelte +7 -11
- package/dist/composition/Formula.svelte +18 -25
- package/dist/composition/FormulaFilter.svelte +96 -98
- package/dist/composition/PieChart.svelte +60 -46
- package/dist/composition/chem-sys.js +3 -2
- package/dist/composition/format.js +4 -3
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +2 -3
- package/dist/composition/parse.js +27 -28
- package/dist/constants.js +11 -9
- package/dist/controls.d.ts +1 -0
- package/dist/controls.js +0 -1
- package/dist/convex-hull/ConvexHull.svelte +20 -25
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -4
- package/dist/convex-hull/ConvexHull2D.svelte +176 -256
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +269 -804
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +236 -755
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +264 -0
- package/dist/convex-hull/ConvexHullChrome.svelte.d.ts +30 -0
- package/dist/convex-hull/ConvexHullControls.svelte +128 -49
- package/dist/convex-hull/ConvexHullControls.svelte.d.ts +7 -6
- package/dist/convex-hull/ConvexHullInfoPane.svelte +18 -5
- package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +6 -5
- package/dist/convex-hull/ConvexHullStats.svelte +210 -351
- package/dist/convex-hull/ConvexHullStats.svelte.d.ts +3 -1
- package/dist/convex-hull/ConvexHullTooltip.svelte +16 -14
- package/dist/convex-hull/ConvexHullTooltip.svelte.d.ts +2 -1
- package/dist/convex-hull/GasPressureControls.svelte +5 -12
- package/dist/convex-hull/StructurePopup.svelte +17 -21
- package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
- package/dist/convex-hull/TemperatureSlider.svelte +4 -10
- package/dist/convex-hull/barycentric-coords.d.ts +2 -4
- package/dist/convex-hull/barycentric-coords.js +6 -33
- package/dist/convex-hull/canvas-interactions.svelte.d.ts +79 -0
- package/dist/convex-hull/canvas-interactions.svelte.js +279 -0
- package/dist/convex-hull/helpers.d.ts +47 -17
- package/dist/convex-hull/helpers.js +186 -101
- package/dist/convex-hull/hull-state.svelte.d.ts +44 -0
- package/dist/convex-hull/hull-state.svelte.js +124 -0
- package/dist/convex-hull/index.d.ts +9 -7
- package/dist/convex-hull/index.js +7 -2
- package/dist/convex-hull/thermodynamics.js +109 -937
- package/dist/convex-hull/types.d.ts +12 -4
- package/dist/convex-hull/types.js +12 -0
- package/dist/coordination/CoordinationBarPlot.svelte +41 -43
- package/dist/coordination/CoordinationBarPlot.svelte.d.ts +1 -1
- package/dist/coordination/calc-coordination.d.ts +1 -1
- package/dist/coordination/calc-coordination.js +28 -25
- package/dist/element/BohrAtom.svelte +6 -8
- package/dist/element/ElementHeading.svelte +4 -1
- package/dist/element/ElementPhoto.svelte +11 -9
- package/dist/element/ElementStats.svelte +12 -10
- package/dist/element/ElementTile.svelte +24 -29
- package/dist/element/ElementTile.svelte.d.ts +1 -1
- package/dist/element/Nucleus.svelte +4 -2
- package/dist/element/data.d.ts +1 -2
- package/dist/element/helpers.d.ts +4 -0
- package/dist/element/helpers.js +18 -0
- package/dist/element/index.d.ts +1 -0
- package/dist/element/index.js +3 -0
- package/dist/feedback/DragOverlay.svelte +5 -3
- package/dist/feedback/DragOverlay.svelte.d.ts +2 -1
- package/dist/feedback/StatusMessage.svelte +20 -7
- package/dist/fermi-surface/FermiSlice.svelte +21 -18
- package/dist/fermi-surface/FermiSurface.svelte +78 -165
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +9 -20
- package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
- package/dist/fermi-surface/FermiSurfaceScene.svelte +93 -272
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +3 -23
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
- package/dist/fermi-surface/compute.js +14 -13
- package/dist/fermi-surface/export.js +4 -15
- package/dist/fermi-surface/index.d.ts +0 -1
- package/dist/fermi-surface/index.js +0 -1
- package/dist/fermi-surface/parse.d.ts +1 -1
- package/dist/fermi-surface/parse.js +84 -97
- package/dist/fermi-surface/types.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +161 -185
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +6 -5
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +12 -9
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +5 -5
- package/dist/heatmap-matrix/index.d.ts +8 -2
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/io/ExportPane.svelte +170 -0
- package/dist/io/ExportPane.svelte.d.ts +17 -0
- package/dist/io/decompress.d.ts +2 -1
- package/dist/io/decompress.js +22 -36
- package/dist/io/export.d.ts +9 -1
- package/dist/io/export.js +37 -29
- package/dist/io/fetch.d.ts +2 -4
- package/dist/io/fetch.js +0 -11
- package/dist/io/file-drop.d.ts +7 -0
- package/dist/io/file-drop.js +13 -0
- package/dist/io/index.d.ts +1 -0
- package/dist/io/index.js +3 -0
- package/dist/io/is-binary.d.ts +9 -0
- package/dist/io/is-binary.js +45 -1
- package/dist/io/types.d.ts +13 -0
- package/dist/io/url-drop.js +13 -25
- package/dist/isosurface/Isosurface.svelte +17 -23
- package/dist/isosurface/IsosurfaceControls.svelte +37 -42
- package/dist/isosurface/parse-vaspwave.d.ts +3 -0
- package/dist/isosurface/parse-vaspwave.js +138 -0
- package/dist/isosurface/parse.js +50 -48
- package/dist/labels.d.ts +6 -2
- package/dist/labels.js +44 -14
- package/dist/layout/FullscreenButton.svelte +34 -0
- package/dist/layout/FullscreenButton.svelte.d.ts +10 -0
- package/dist/layout/FullscreenToggle.svelte +12 -12
- package/dist/layout/InfoCard.svelte +7 -18
- package/dist/layout/InfoTag.svelte +1 -3
- package/dist/layout/NumberRangeInput.svelte +46 -0
- package/dist/layout/NumberRangeInput.svelte.d.ts +12 -0
- package/dist/layout/PropertyFilter.svelte +2 -6
- package/dist/layout/SettingsSection.svelte +21 -17
- package/dist/layout/SubpageGrid.svelte +3 -1
- package/dist/layout/ViewerChrome.svelte +115 -0
- package/dist/layout/ViewerChrome.svelte.d.ts +18 -0
- package/dist/layout/fullscreen.d.ts +4 -0
- package/dist/layout/fullscreen.js +3 -5
- package/dist/layout/fullscreen.svelte.d.ts +8 -0
- package/dist/layout/fullscreen.svelte.js +36 -0
- package/dist/layout/index.d.ts +4 -0
- package/dist/layout/index.js +4 -0
- package/dist/layout/json-tree/JsonNode.svelte +8 -11
- package/dist/layout/json-tree/JsonTree.svelte +53 -77
- package/dist/layout/json-tree/JsonValue.svelte +7 -15
- package/dist/layout/json-tree/utils.js +14 -23
- package/dist/math.d.ts +9 -3
- package/dist/math.js +37 -21
- package/dist/overlays/ContextMenu.svelte +4 -2
- package/dist/overlays/CopyButton.svelte +11 -5
- package/dist/overlays/DragControlTab.svelte +6 -1
- package/dist/overlays/DraggablePane.svelte +81 -26
- package/dist/overlays/DraggablePane.svelte.d.ts +1 -0
- package/dist/overlays/GlassChip.svelte +30 -0
- package/dist/overlays/GlassChip.svelte.d.ts +8 -0
- package/dist/overlays/InfoPaneCards.svelte +11 -23
- package/dist/overlays/index.d.ts +11 -0
- package/dist/overlays/index.js +26 -0
- package/dist/overlays/portal.d.ts +2 -0
- package/dist/overlays/portal.js +14 -0
- package/dist/periodic-table/PeriodicTable.svelte +115 -146
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
- package/dist/periodic-table/PeriodicTableControls.svelte +11 -63
- package/dist/periodic-table/TableInset.svelte +9 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +50 -71
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
- package/dist/phase-diagram/PhaseDiagramControls.svelte +73 -96
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +4 -3
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +4 -2
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte.d.ts +2 -3
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +49 -134
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte.d.ts +3 -4
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
- package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
- package/dist/phase-diagram/build-diagram.js +3 -3
- package/dist/phase-diagram/colors.js +1 -1
- package/dist/phase-diagram/diagram-input.d.ts +1 -2
- package/dist/phase-diagram/parse.d.ts +2 -1
- package/dist/phase-diagram/parse.js +15 -15
- package/dist/phase-diagram/svg-to-diagram.js +21 -15
- package/dist/phase-diagram/utils.js +2 -3
- package/dist/plot/bar/BarPlot.svelte +494 -692
- package/dist/plot/bar/BarPlot.svelte.d.ts +9 -15
- package/dist/plot/bar/BarPlotControls.svelte +1 -3
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +5 -7
- package/dist/plot/bar/SpacegroupBarPlot.svelte +31 -37
- package/dist/plot/bar/data.d.ts +5 -4
- package/dist/plot/bar/data.js +2 -1
- package/dist/plot/box/BoxPlot.svelte +361 -439
- package/dist/plot/box/BoxPlot.svelte.d.ts +6 -3
- package/dist/plot/box/BoxPlotControls.svelte.d.ts +1 -1
- package/dist/plot/box/Violin.svelte.d.ts +2 -1
- package/dist/plot/box/box-plot.d.ts +3 -2
- package/dist/plot/box/box-plot.js +6 -3
- package/dist/plot/box/kde.d.ts +2 -1
- package/dist/plot/box/kde.js +4 -4
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +5 -2
- package/dist/plot/core/axis-utils.d.ts +12 -7
- package/dist/plot/core/axis-utils.js +48 -48
- package/dist/plot/core/components/AxisLabel.svelte +82 -20
- package/dist/plot/core/components/AxisLabel.svelte.d.ts +1 -0
- package/dist/plot/core/components/ColorBar.svelte +106 -111
- package/dist/plot/core/components/ColorBar.svelte.d.ts +5 -4
- package/dist/plot/core/components/ColorScaleSelect.svelte +1 -1
- package/dist/plot/core/components/FillArea.svelte +10 -17
- package/dist/plot/core/components/HierarchyControls.svelte +249 -0
- package/dist/plot/{sunburst/SunburstControls.svelte.d.ts → core/components/HierarchyControls.svelte.d.ts} +12 -8
- package/dist/plot/core/components/InteractiveAxisLabel.svelte +1 -1
- package/dist/plot/core/components/InteractiveAxisLabel.svelte.d.ts +1 -1
- package/dist/plot/core/components/Line.svelte +21 -11
- package/dist/plot/core/components/Line.svelte.d.ts +5 -2
- package/dist/plot/core/components/PlotAxis.svelte +42 -18
- package/dist/plot/core/components/PlotAxis.svelte.d.ts +2 -1
- package/dist/plot/core/components/PlotControls.svelte +65 -41
- package/dist/plot/core/components/PlotControls.svelte.d.ts +1 -1
- package/dist/plot/core/components/PlotLegend.svelte +31 -35
- package/dist/plot/core/components/PlotMarginals.svelte +616 -0
- package/dist/plot/core/components/PlotMarginals.svelte.d.ts +15 -0
- package/dist/plot/core/components/PlotTooltip.svelte +1 -1
- package/dist/plot/core/components/PortalSelect.svelte +4 -8
- package/dist/plot/core/components/ReferenceLine.svelte +27 -24
- package/dist/plot/core/components/ReferenceLine3D.svelte +56 -59
- package/dist/plot/core/components/ReferenceLine3D.svelte.d.ts +4 -4
- package/dist/plot/core/components/ReferencePlane.svelte +9 -10
- package/dist/plot/core/components/ReferencePlane.svelte.d.ts +4 -4
- package/dist/plot/core/components/ZeroLines.svelte +4 -8
- package/dist/plot/core/components/ZoomRect.svelte +1 -2
- package/dist/plot/core/components/index.d.ts +1 -0
- package/dist/plot/core/components/index.js +1 -0
- package/dist/plot/core/data-cleaning-signal.d.ts +46 -0
- package/dist/plot/core/data-cleaning-signal.js +467 -0
- package/dist/plot/core/data-cleaning.d.ts +2 -42
- package/dist/plot/core/data-cleaning.js +29 -476
- package/dist/plot/core/data-transform.js +9 -5
- package/dist/plot/core/fill-utils.d.ts +7 -4
- package/dist/plot/core/fill-utils.js +34 -9
- package/dist/plot/core/index.d.ts +1 -0
- package/dist/plot/core/index.js +1 -0
- package/dist/plot/core/interactions.d.ts +5 -1
- package/dist/plot/core/interactions.js +14 -2
- package/dist/plot/core/layout.d.ts +3 -1
- package/dist/plot/core/layout.js +22 -13
- package/dist/plot/core/marginals.d.ts +170 -0
- package/dist/plot/core/marginals.js +436 -0
- package/dist/plot/core/pan-zoom.svelte.d.ts +35 -0
- package/dist/plot/core/pan-zoom.svelte.js +221 -0
- package/dist/plot/core/placed-tween.svelte.d.ts +21 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -0
- package/dist/plot/core/reference-line.d.ts +10 -10
- package/dist/plot/core/reference-line.js +7 -7
- package/dist/plot/core/scales.d.ts +40 -25
- package/dist/plot/core/scales.js +49 -21
- package/dist/plot/core/svg.d.ts +2 -1
- package/dist/plot/core/types/fills.d.ts +101 -0
- package/dist/plot/core/types/fills.js +15 -0
- package/dist/plot/core/types/plot-3d.d.ts +87 -0
- package/dist/plot/core/types/plot-3d.js +4 -0
- package/dist/plot/core/types/reference-lines.d.ts +140 -0
- package/dist/plot/core/types/reference-lines.js +9 -0
- package/dist/plot/core/types.d.ts +47 -331
- package/dist/plot/core/types.js +23 -20
- package/dist/plot/core/utils/hierarchy-chart.d.ts +51 -0
- package/dist/plot/core/utils/hierarchy-chart.js +179 -0
- package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
- package/dist/plot/core/utils/hierarchy-labels.js +99 -0
- package/dist/plot/core/utils/label-placement.d.ts +1 -1
- package/dist/plot/core/utils/label-placement.js +5 -5
- package/dist/plot/core/utils.d.ts +2 -1
- package/dist/plot/histogram/Histogram.svelte +373 -631
- package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
- package/dist/plot/histogram/HistogramControls.svelte +30 -28
- package/dist/plot/histogram/HistogramControls.svelte.d.ts +1 -1
- package/dist/plot/histogram/histogram.d.ts +31 -0
- package/dist/plot/histogram/histogram.js +70 -0
- package/dist/plot/histogram/index.d.ts +1 -0
- package/dist/plot/histogram/index.js +1 -0
- package/dist/plot/index.d.ts +1 -0
- package/dist/plot/index.js +1 -0
- package/dist/plot/sankey/Sankey.svelte +79 -73
- package/dist/plot/sankey/Sankey.svelte.d.ts +3 -3
- package/dist/plot/sankey/SankeyControls.svelte +22 -16
- package/dist/plot/sankey/sankey.js +3 -1
- package/dist/plot/scatter/BinnedScatterPlot.svelte +264 -112
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +11 -4
- package/dist/plot/scatter/ElementScatter.svelte +4 -1
- package/dist/plot/scatter/ScatterPlot.svelte +623 -821
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +9 -15
- package/dist/plot/scatter/ScatterPlotControls.svelte +18 -19
- package/dist/plot/scatter/ScatterPlotControls.svelte.d.ts +1 -1
- package/dist/plot/scatter/ScatterPoint.svelte +16 -9
- package/dist/plot/scatter/binned-scatter-types.d.ts +6 -12
- package/dist/plot/scatter/binned-scatter-types.js +6 -1
- package/dist/plot/scatter/index.d.ts +1 -1
- package/dist/plot/scatter/scatter-data.d.ts +1 -1
- package/dist/plot/scatter/scatter-data.js +8 -7
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte +40 -60
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +6 -14
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +17 -15
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte.d.ts +5 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +232 -234
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +5 -14
- package/dist/plot/scatter-3d/Surface3D.svelte +9 -17
- package/dist/plot/scatter-3d/Surface3D.svelte.d.ts +4 -3
- package/dist/plot/sunburst/Sunburst.svelte +256 -338
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +4 -3
- package/dist/plot/sunburst/index.d.ts +1 -1
- package/dist/plot/sunburst/index.js +2 -1
- package/dist/plot/sunburst/render.d.ts +2 -2
- package/dist/plot/sunburst/render.js +47 -22
- package/dist/plot/sunburst/sunburst.d.ts +5 -1
- package/dist/plot/sunburst/sunburst.js +14 -4
- package/dist/plot/treemap/Treemap.svelte +907 -0
- package/dist/plot/treemap/Treemap.svelte.d.ts +84 -0
- package/dist/plot/treemap/index.d.ts +3 -0
- package/dist/plot/treemap/index.js +4 -0
- package/dist/plot/treemap/treemap.d.ts +26 -0
- package/dist/plot/treemap/treemap.js +99 -0
- package/dist/rdf/RdfPlot.svelte +22 -26
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +4 -8
- package/dist/sanitize.js +14 -3
- package/dist/scene/SceneCamera.svelte +62 -0
- package/dist/scene/SceneCamera.svelte.d.ts +19 -0
- package/dist/scene/bind-renderer.svelte.d.ts +2 -0
- package/dist/scene/bind-renderer.svelte.js +22 -0
- package/dist/scene/index.d.ts +4 -0
- package/dist/scene/index.js +5 -0
- package/dist/scene/props.js +52 -0
- package/dist/scene/types.d.ts +26 -0
- package/dist/scene/types.js +1 -0
- package/dist/settings.d.ts +33 -11
- package/dist/settings.js +136 -51
- package/dist/spectral/Bands.svelte +231 -237
- package/dist/spectral/Bands.svelte.d.ts +3 -2
- package/dist/spectral/BandsAndDos.svelte +29 -29
- package/dist/spectral/BrillouinBandsDos.svelte +21 -29
- package/dist/spectral/Dos.svelte +75 -77
- package/dist/spectral/Dos.svelte.d.ts +2 -1
- package/dist/spectral/helpers.d.ts +9 -9
- package/dist/spectral/helpers.js +66 -70
- package/dist/state.svelte.d.ts +0 -7
- package/dist/state.svelte.js +5 -24
- package/dist/structure/Arrow.svelte +6 -21
- package/dist/structure/ArrowInstances.svelte +160 -0
- package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
- package/dist/structure/AtomLegend.svelte +115 -75
- package/dist/structure/AtomLegend.svelte.d.ts +1 -1
- package/dist/structure/Bond.svelte +31 -23
- package/dist/structure/CanvasTooltip.svelte +16 -3
- package/dist/structure/CellSelect.svelte +22 -29
- package/dist/structure/CellSelect.svelte.d.ts +2 -1
- package/dist/structure/Cylinder.svelte +24 -40
- package/dist/structure/InstancedAtoms.svelte +114 -0
- package/dist/structure/InstancedAtoms.svelte.d.ts +15 -0
- package/dist/structure/Lattice.svelte +85 -149
- package/dist/structure/SiteLabels.svelte +122 -0
- package/dist/structure/SiteLabels.svelte.d.ts +18 -0
- package/dist/structure/Structure.svelte +725 -735
- package/dist/structure/Structure.svelte.d.ts +8 -16
- package/dist/structure/StructureCarousel.svelte +630 -0
- package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
- package/dist/structure/StructureControls.svelte +298 -325
- package/dist/structure/StructureControls.svelte.d.ts +5 -3
- package/dist/structure/StructureExportPane.svelte +62 -168
- package/dist/structure/StructureExportPane.svelte.d.ts +4 -5
- package/dist/structure/StructureInfoPane.svelte +77 -69
- package/dist/structure/StructureInfoPane.svelte.d.ts +6 -6
- package/dist/structure/StructureScene.svelte +758 -600
- package/dist/structure/StructureScene.svelte.d.ts +24 -20
- package/dist/structure/StructureViewport.svelte +386 -0
- package/dist/structure/StructureViewport.svelte.d.ts +63 -0
- package/dist/structure/atom-label-placement.d.ts +18 -0
- package/dist/structure/atom-label-placement.js +115 -0
- package/dist/structure/atom-properties.d.ts +3 -1
- package/dist/structure/atom-properties.js +115 -54
- package/dist/structure/bond-order-perception.js +2 -4
- package/dist/structure/bonding.d.ts +12 -2
- package/dist/structure/bonding.js +172 -73
- package/dist/structure/edit-history.d.ts +6 -0
- package/dist/structure/edit-history.js +27 -0
- package/dist/structure/export.d.ts +25 -4
- package/dist/structure/export.js +103 -153
- package/dist/structure/format-detect.d.ts +1 -0
- package/dist/structure/format-detect.js +22 -0
- package/dist/structure/geometry.d.ts +9 -0
- package/dist/structure/geometry.js +27 -0
- package/dist/structure/index.d.ts +18 -1
- package/dist/structure/index.js +15 -2
- package/dist/structure/measure.d.ts +1 -1
- package/dist/structure/measure.js +6 -12
- package/dist/structure/parse.d.ts +5 -3
- package/dist/structure/parse.js +551 -567
- package/dist/structure/partial-occupancy.d.ts +0 -1
- package/dist/structure/partial-occupancy.js +5 -3
- package/dist/structure/pbc.d.ts +1 -1
- package/dist/structure/pbc.js +204 -51
- package/dist/structure/polyhedra.d.ts +40 -0
- package/dist/structure/polyhedra.js +587 -0
- package/dist/structure/site.d.ts +4 -0
- package/dist/structure/site.js +1 -0
- package/dist/structure/supercell.d.ts +1 -2
- package/dist/structure/supercell.js +10 -15
- package/dist/structure/validation.js +5 -6
- package/dist/symmetry/SymmetryElementControls.svelte +69 -0
- package/dist/symmetry/SymmetryElementControls.svelte.d.ts +9 -0
- package/dist/symmetry/SymmetryElements.svelte +350 -0
- package/dist/symmetry/SymmetryElements.svelte.d.ts +24 -0
- package/dist/symmetry/SymmetryStats.svelte +142 -49
- package/dist/symmetry/WyckoffTable.svelte +58 -16
- package/dist/symmetry/WyckoffTable.svelte.d.ts +3 -0
- package/dist/symmetry/cell-transform.js +8 -14
- package/dist/symmetry/index.d.ts +15 -4
- package/dist/symmetry/index.js +308 -81
- package/dist/symmetry/spacegroups.d.ts +5 -1
- package/dist/symmetry/spacegroups.js +18 -3
- package/dist/symmetry/symmetry-elements.d.ts +33 -0
- package/dist/symmetry/symmetry-elements.js +521 -0
- package/dist/symmetry/wyckoff-db.d.ts +9 -0
- package/dist/symmetry/wyckoff-db.js +87 -0
- package/dist/table/HeatmapTable.svelte +1104 -378
- package/dist/table/HeatmapTable.svelte.d.ts +12 -2
- package/dist/table/ToggleMenu.svelte +5 -12
- package/dist/table/index.d.ts +21 -6
- package/dist/table/index.js +34 -21
- package/dist/theme/ThemeControl.svelte +16 -8
- package/dist/theme/index.d.ts +1 -5
- package/dist/theme/index.js +4 -10
- package/dist/theme/themes.mjs +14 -7
- package/dist/tooltip/KCoords.svelte +4 -1
- package/dist/tooltip/TooltipContent.svelte +2 -5
- package/dist/trajectory/Trajectory.svelte +556 -352
- package/dist/trajectory/Trajectory.svelte.d.ts +10 -22
- package/dist/trajectory/TrajectoryError.svelte +11 -8
- package/dist/trajectory/TrajectoryExportPane.svelte +28 -54
- package/dist/trajectory/TrajectoryExportPane.svelte.d.ts +4 -5
- package/dist/trajectory/TrajectoryInfoPane.svelte +88 -99
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +3 -2
- package/dist/trajectory/constants.js +6 -2
- package/dist/trajectory/extract.js +73 -71
- package/dist/trajectory/format-detect.d.ts +0 -1
- package/dist/trajectory/format-detect.js +13 -17
- package/dist/trajectory/frame-reader.d.ts +2 -1
- package/dist/trajectory/frame-reader.js +74 -136
- package/dist/trajectory/helpers.d.ts +12 -2
- package/dist/trajectory/helpers.js +68 -37
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +3 -0
- package/dist/trajectory/parse/ase.d.ts +9 -1
- package/dist/trajectory/parse/ase.js +47 -32
- package/dist/trajectory/parse/diagnostics.d.ts +3 -0
- package/dist/trajectory/parse/diagnostics.js +14 -0
- package/dist/trajectory/parse/h5-utils.d.ts +13 -0
- package/dist/trajectory/parse/h5-utils.js +109 -0
- package/dist/trajectory/parse/hdf5.d.ts +1 -1
- package/dist/trajectory/parse/hdf5.js +116 -106
- package/dist/trajectory/parse/index.d.ts +3 -4
- package/dist/trajectory/parse/index.js +68 -119
- package/dist/trajectory/parse/lammps.d.ts +0 -2
- package/dist/trajectory/parse/lammps.js +14 -16
- package/dist/trajectory/parse/pymatgen.d.ts +2 -0
- package/dist/trajectory/parse/pymatgen.js +74 -0
- package/dist/trajectory/parse/vasp.js +13 -9
- package/dist/trajectory/parse/vaspout-electronic.d.ts +13 -0
- package/dist/trajectory/parse/vaspout-electronic.js +207 -0
- package/dist/trajectory/parse/vaspout-h5.d.ts +5 -0
- package/dist/trajectory/parse/vaspout-h5.js +284 -0
- package/dist/trajectory/parse/xyz.d.ts +9 -21
- package/dist/trajectory/parse/xyz.js +38 -39
- package/dist/trajectory/plotting.d.ts +8 -10
- package/dist/trajectory/plotting.js +102 -127
- package/dist/utils.d.ts +4 -0
- package/dist/utils.js +8 -1
- package/dist/xrd/XrdPlot.svelte +56 -85
- package/dist/xrd/broadening.d.ts +2 -1
- package/dist/xrd/broadening.js +2 -1
- package/dist/xrd/calc-xrd.js +8 -15
- package/dist/xrd/index.d.ts +2 -2
- package/dist/xrd/parse.d.ts +0 -1
- package/dist/xrd/parse.js +56 -73
- package/package.json +77 -36
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/element/data.json +0 -11864
- package/dist/fermi-surface/marching-cubes.d.ts +0 -2
- package/dist/fermi-surface/marching-cubes.js +0 -2
- package/dist/plot/core/hover-lock.svelte.d.ts +0 -14
- package/dist/plot/core/hover-lock.svelte.js +0 -45
- package/dist/plot/sunburst/SunburstControls.svelte +0 -200
- package/dist/structure/label-placement.d.ts +0 -14
- package/dist/structure/label-placement.js +0 -72
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
<script
|
|
2
|
+
lang="ts"
|
|
3
|
+
generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
|
|
4
|
+
>
|
|
5
|
+
import type { D3InterpolateName } from '../../colors'
|
|
6
|
+
import { format_value } from '../../labels'
|
|
7
|
+
import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
|
|
8
|
+
import type { Vec2 } from '../../math'
|
|
9
|
+
import type {
|
|
10
|
+
BasePlotProps,
|
|
11
|
+
LegendConfig,
|
|
12
|
+
LegendItem,
|
|
13
|
+
SunburstLabelText,
|
|
14
|
+
SunburstSort,
|
|
15
|
+
SunburstValueMode,
|
|
16
|
+
} from '..'
|
|
17
|
+
import { ColorBar, PlotLegend, PlotTooltip, TreemapControls } from '..'
|
|
18
|
+
import { closest_data_idx } from '../core/interactions'
|
|
19
|
+
import { compute_element_placement, filter_padding } from '../core/layout'
|
|
20
|
+
import {
|
|
21
|
+
ancestor_chain,
|
|
22
|
+
compute_metric_colors,
|
|
23
|
+
compute_node_dim,
|
|
24
|
+
compute_node_infos,
|
|
25
|
+
handle_hierarchy_escape,
|
|
26
|
+
hierarchy_legend_items,
|
|
27
|
+
is_activation_key,
|
|
28
|
+
node_handler_props,
|
|
29
|
+
pointer_pos,
|
|
30
|
+
prune_muted_ids,
|
|
31
|
+
safe_hierarchy_layout,
|
|
32
|
+
selection_within,
|
|
33
|
+
svg_label_font,
|
|
34
|
+
toggle_muted,
|
|
35
|
+
} from '../core/utils/hierarchy-chart'
|
|
36
|
+
import {
|
|
37
|
+
export_hierarchy_chart,
|
|
38
|
+
make_cached_contrast,
|
|
39
|
+
make_cached_text_width,
|
|
40
|
+
} from '../core/utils/hierarchy-labels'
|
|
41
|
+
import { SCALE_DEFAULTS } from '../core/types'
|
|
42
|
+
import type { Rect, Sides } from '../core/layout'
|
|
43
|
+
import { arrow_nav_target } from '../sunburst/render'
|
|
44
|
+
import type { PositionedArc } from '../sunburst/sunburst'
|
|
45
|
+
import type { TreemapNode, TreemapNodeHandlerProps } from './treemap'
|
|
46
|
+
import { lerp_rects, tile_rects } from './treemap'
|
|
47
|
+
import { DEFAULTS } from '../../settings'
|
|
48
|
+
import type { ComponentProps, Snippet } from 'svelte'
|
|
49
|
+
import { tick, untrack } from 'svelte'
|
|
50
|
+
import { cubicInOut } from 'svelte/easing'
|
|
51
|
+
import type { HTMLAttributes } from 'svelte/elements'
|
|
52
|
+
import { Tween, type TweenOptions } from 'svelte/motion'
|
|
53
|
+
import { SvelteSet } from 'svelte/reactivity'
|
|
54
|
+
|
|
55
|
+
const DEFAULT_PADDING: Required<Sides> = { t: 10, b: 10, l: 10, r: 10 }
|
|
56
|
+
|
|
57
|
+
let {
|
|
58
|
+
data = $bindable([]),
|
|
59
|
+
value_mode = $bindable(DEFAULTS.treemap.value_mode),
|
|
60
|
+
sort = `none`,
|
|
61
|
+
level_lighten = 0,
|
|
62
|
+
min_fraction = $bindable(DEFAULTS.treemap.min_fraction),
|
|
63
|
+
other_label = `Other`,
|
|
64
|
+
max_depth = $bindable(DEFAULTS.treemap.max_depth),
|
|
65
|
+
padding_inner = $bindable(DEFAULTS.treemap.padding_inner),
|
|
66
|
+
padding_top = $bindable(DEFAULTS.treemap.padding_top),
|
|
67
|
+
padding_outer = $bindable(DEFAULTS.treemap.padding_outer),
|
|
68
|
+
show_labels = $bindable(DEFAULTS.treemap.show_labels),
|
|
69
|
+
label_text = $bindable(DEFAULTS.treemap.label_text),
|
|
70
|
+
zoom_on_click = $bindable(DEFAULTS.treemap.zoom_on_click),
|
|
71
|
+
zoom_root_id = $bindable(null),
|
|
72
|
+
show_breadcrumbs = $bindable(DEFAULTS.treemap.show_breadcrumbs),
|
|
73
|
+
color_values,
|
|
74
|
+
color_scale = SCALE_DEFAULTS.scheme,
|
|
75
|
+
color_range,
|
|
76
|
+
colorbar = {},
|
|
77
|
+
export_buttons = true,
|
|
78
|
+
export_filename = `treemap`,
|
|
79
|
+
tween,
|
|
80
|
+
value_format = `,`,
|
|
81
|
+
padding = DEFAULT_PADDING,
|
|
82
|
+
legend = {},
|
|
83
|
+
show_legend = false,
|
|
84
|
+
tooltip,
|
|
85
|
+
cell_content,
|
|
86
|
+
hovered = $bindable(false),
|
|
87
|
+
change = () => {},
|
|
88
|
+
on_node_click,
|
|
89
|
+
on_node_hover,
|
|
90
|
+
on_zoom,
|
|
91
|
+
show_controls = $bindable(true),
|
|
92
|
+
controls_open = $bindable(false),
|
|
93
|
+
controls_toggle_props,
|
|
94
|
+
controls_pane_props,
|
|
95
|
+
fullscreen = $bindable(false),
|
|
96
|
+
fullscreen_toggle = true,
|
|
97
|
+
children,
|
|
98
|
+
header_controls,
|
|
99
|
+
controls_extra,
|
|
100
|
+
...rest
|
|
101
|
+
}: HTMLAttributes<HTMLDivElement> &
|
|
102
|
+
Omit<BasePlotProps, `change`> & {
|
|
103
|
+
data?: TreemapNode<Metadata> | TreemapNode<Metadata>[]
|
|
104
|
+
value_mode?: SunburstValueMode
|
|
105
|
+
sort?: SunburstSort
|
|
106
|
+
level_lighten?: number
|
|
107
|
+
// Aggregate sibling cells below this fraction of the total into one 'Other'
|
|
108
|
+
// cell per parent (only when >= 2 qualify); 0 disables
|
|
109
|
+
min_fraction?: number
|
|
110
|
+
other_label?: string
|
|
111
|
+
max_depth?: number // levels shown below the current zoom root (0 = all)
|
|
112
|
+
padding_inner?: number // px gap between sibling cells
|
|
113
|
+
padding_top?: number // px header strip on branch cells (0 = no headers)
|
|
114
|
+
padding_outer?: number // px inset of children within their parent (plotly marker.pad)
|
|
115
|
+
show_labels?: boolean
|
|
116
|
+
label_text?: SunburstLabelText // what labels display (plotly textinfo equivalent)
|
|
117
|
+
zoom_on_click?: boolean
|
|
118
|
+
zoom_root_id?: string | number | null // id of the cell the view is rooted on
|
|
119
|
+
show_breadcrumbs?: boolean // clickable ancestor trail when zoomed
|
|
120
|
+
// Color cells by a numeric metric (continuous colormap) instead of categorical
|
|
121
|
+
// inheritance; return null to keep a cell's categorical color
|
|
122
|
+
color_values?: (rect: PositionedArc<Metadata>) => number | null
|
|
123
|
+
color_scale?: D3InterpolateName
|
|
124
|
+
color_range?: Vec2 // defaults to the metric's [min, max]
|
|
125
|
+
colorbar?: ComponentProps<typeof ColorBar> | null // null hides it
|
|
126
|
+
export_buttons?: boolean // SVG/PNG download buttons in the controls pane
|
|
127
|
+
export_filename?: string
|
|
128
|
+
// Zoom transition timing (resizes/data swaps snap instantly, plotly-style).
|
|
129
|
+
// interpolate is not overridable: the component's rect interpolator also
|
|
130
|
+
// handles rect-array length changes on data swaps (default would throw)
|
|
131
|
+
tween?: Omit<TweenOptions<Rect[]>, `interpolate`>
|
|
132
|
+
value_format?: string
|
|
133
|
+
padding?: Sides
|
|
134
|
+
legend?: LegendConfig | null
|
|
135
|
+
show_legend?: boolean
|
|
136
|
+
tooltip?: Snippet<[TreemapNodeHandlerProps<Metadata>]>
|
|
137
|
+
// Fully replace the default cell rect + labels. NOTE: this also replaces the
|
|
138
|
+
// built-in hover/focus/click + tooltip wiring, so re-implement any
|
|
139
|
+
// interactivity you need inside the snippet.
|
|
140
|
+
cell_content?: Snippet<[{ arc: PositionedArc<Metadata>; rect: Rect }]>
|
|
141
|
+
change?: (data: TreemapNodeHandlerProps<Metadata> | null) => void
|
|
142
|
+
on_node_click?: (
|
|
143
|
+
data: TreemapNodeHandlerProps<Metadata> & { event: MouseEvent | KeyboardEvent },
|
|
144
|
+
) => void
|
|
145
|
+
on_node_hover?: (
|
|
146
|
+
data: (TreemapNodeHandlerProps<Metadata> & { event: MouseEvent | FocusEvent }) | null,
|
|
147
|
+
) => void
|
|
148
|
+
on_zoom?: (data: { root: TreemapNodeHandlerProps<Metadata> | null }) => void
|
|
149
|
+
header_controls?: Snippet<[{ height: number; width: number; fullscreen: boolean }]>
|
|
150
|
+
controls_extra?: Snippet<[{ zoom_root_id: string | number | null }]>
|
|
151
|
+
} = $props()
|
|
152
|
+
|
|
153
|
+
let [width, height] = $state([0, 0])
|
|
154
|
+
let wrapper: HTMLDivElement | undefined = $state()
|
|
155
|
+
let svg_element: SVGSVGElement | null = $state(null)
|
|
156
|
+
// Unique per instance so multiple treemaps on one page don't collide on the
|
|
157
|
+
// hatch pattern's SVG id.
|
|
158
|
+
const uid = $props.id()
|
|
159
|
+
const hatch_pattern_id = `treemap-hatch-${uid}`
|
|
160
|
+
|
|
161
|
+
let hovered_idx = $state<number | null>(null)
|
|
162
|
+
let hover_info = $state<TreemapNodeHandlerProps<Metadata> | null>(null)
|
|
163
|
+
let hover_pos = $state<{ x: number; y: number }>({ x: 0, y: 0 })
|
|
164
|
+
// Depth-1 category ids muted via legend toggle (dimmed, not removed - keeps layout stable)
|
|
165
|
+
let muted_ids = new SvelteSet<string | number>()
|
|
166
|
+
|
|
167
|
+
let pad = $derived(filter_padding(padding, DEFAULT_PADDING))
|
|
168
|
+
let inner_width = $derived(Math.max(0, width - pad.l - pad.r))
|
|
169
|
+
let avail_height = $derived(Math.max(0, height - pad.t - pad.b))
|
|
170
|
+
// measured height of the bottom colorbar, reserved from the chart so it never
|
|
171
|
+
// overlaps the cells; reset to 0 when hidden (effect below); capped at half the
|
|
172
|
+
// area so a bad measurement can't collapse the chart
|
|
173
|
+
let colorbar_height = $state(0)
|
|
174
|
+
let colorbar_reserve = $derived(
|
|
175
|
+
colorbar_height > 0 ? Math.min(colorbar_height + 16, avail_height / 2) : 0,
|
|
176
|
+
)
|
|
177
|
+
let inner_height = $derived(avail_height - colorbar_reserve)
|
|
178
|
+
|
|
179
|
+
// Tree semantics (values, colors, ids, pre-order indexing) are shared with
|
|
180
|
+
// Sunburst; only the pixel tiling below is treemap-specific.
|
|
181
|
+
let layout = $derived(
|
|
182
|
+
safe_hierarchy_layout(data, {
|
|
183
|
+
value_mode,
|
|
184
|
+
sort,
|
|
185
|
+
level_lighten,
|
|
186
|
+
min_fraction,
|
|
187
|
+
other_label,
|
|
188
|
+
}),
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
// Resolve the zoom root; stale ids (e.g. after a data swap) fall back to the root
|
|
192
|
+
let zoom_root = $derived(layout.arcs.find((arc) => arc.id === zoom_root_id) ?? layout.root)
|
|
193
|
+
let zoomed = $derived((zoom_root?.depth ?? 0) > 0)
|
|
194
|
+
|
|
195
|
+
// Drop muted ids that no longer exist when data changes (untrack avoids a
|
|
196
|
+
// self-trigger loop from reading/writing muted_ids in the same effect).
|
|
197
|
+
// Hover/focus state is index-based, so a layout swap would otherwise leave a stale
|
|
198
|
+
// tooltip and highlight whatever unrelated node now occupies the old index.
|
|
199
|
+
$effect(() => {
|
|
200
|
+
const { arcs } = layout
|
|
201
|
+
untrack(() => {
|
|
202
|
+
prune_muted_ids(arcs, muted_ids)
|
|
203
|
+
set_cell_hover(null)
|
|
204
|
+
focused_idx = null
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
// Re-tile the zoom root's subtree to the full plot area (plotly behavior:
|
|
209
|
+
// squarified aspect ratios stay correct at every zoom level, unlike projecting
|
|
210
|
+
// one fixed tiling through a window, which would distort cells and scale the
|
|
211
|
+
// fixed-px header strips). Zoom animation interpolates between tilings.
|
|
212
|
+
let target_rects = $derived(
|
|
213
|
+
tile_rects(
|
|
214
|
+
layout.arcs,
|
|
215
|
+
zoom_root?.node_idx ?? 0,
|
|
216
|
+
{ width: inner_width, height: inner_height },
|
|
217
|
+
{ padding_inner, padding_top, padding_outer },
|
|
218
|
+
),
|
|
219
|
+
)
|
|
220
|
+
// Seeded at the current target (charts load fully drawn); untrack reads the
|
|
221
|
+
// tween options once at init (not meant to be reactive). The rect interpolator
|
|
222
|
+
// is applied after the user's options: Svelte's default interpolator throws
|
|
223
|
+
// when the rect-array length changes (data swaps), so it must not be overridable.
|
|
224
|
+
const rects_tween = new Tween<Rect[]>(
|
|
225
|
+
untrack(() => target_rects),
|
|
226
|
+
untrack(() => ({
|
|
227
|
+
duration: 400,
|
|
228
|
+
easing: cubicInOut,
|
|
229
|
+
...tween,
|
|
230
|
+
interpolate: (from: Rect[], to: Rect[]) => (t: number) => lerp_rects(from, to, t),
|
|
231
|
+
})),
|
|
232
|
+
)
|
|
233
|
+
// Animate only zoom transitions; resizes, data swaps and padding tweaks snap
|
|
234
|
+
// instantly (animating a container drag-resize would chase the pointer with a
|
|
235
|
+
// 400ms lerp on every width change, and morphing between unrelated datasets
|
|
236
|
+
// is meaningless)
|
|
237
|
+
let prev_zoom_idx = untrack(() => zoom_root?.node_idx ?? 0)
|
|
238
|
+
let prev_arcs = untrack(() => layout.arcs)
|
|
239
|
+
$effect(() => {
|
|
240
|
+
const [target, zoom_idx, arcs] = [target_rects, zoom_root?.node_idx ?? 0, layout.arcs]
|
|
241
|
+
const zoom_changed = zoom_idx !== prev_zoom_idx && arcs === prev_arcs
|
|
242
|
+
;[prev_zoom_idx, prev_arcs] = [zoom_idx, arcs]
|
|
243
|
+
rects_tween.set(target, zoom_changed ? undefined : { duration: 0 })
|
|
244
|
+
})
|
|
245
|
+
let rects = $derived(rects_tween.current)
|
|
246
|
+
|
|
247
|
+
// Deepest level rendered below the current zoom root (0 = unlimited)
|
|
248
|
+
let depth_cutoff = $derived(max_depth > 0 ? (zoom_root?.depth ?? 0) + max_depth : Infinity)
|
|
249
|
+
// Shared by rendering and legend placement. The zoom root fills the viewport
|
|
250
|
+
// and is represented by the breadcrumbs, not a cell — except when it's a leaf
|
|
251
|
+
// (e.g. programmatic zoom_root_id onto a compound), which renders as one full-
|
|
252
|
+
// viewport cell instead of a blank chart. Nodes outside the zoomed subtree
|
|
253
|
+
// hold zero rects from tile_rects.
|
|
254
|
+
const cell_visible = (arc: PositionedArc<Metadata>, rect: Rect): boolean =>
|
|
255
|
+
arc.depth > 0 &&
|
|
256
|
+
(arc.node_idx !== zoom_root?.node_idx || arc.is_leaf) &&
|
|
257
|
+
arc.depth <= depth_cutoff &&
|
|
258
|
+
rect.width > 0.5 &&
|
|
259
|
+
rect.height > 0.5
|
|
260
|
+
const idx_visible = (idx: number): boolean => {
|
|
261
|
+
const [arc, rect] = [layout.arcs[idx], rects[idx]]
|
|
262
|
+
return Boolean(arc && rect && cell_visible(arc, rect))
|
|
263
|
+
}
|
|
264
|
+
// Indices (= keys) of cells to render. A plain number array: arcs/rects/
|
|
265
|
+
// cell_info/cell_dim are all index-aligned, so rendering reads them by idx
|
|
266
|
+
// instead of rebuilding N wrapper objects per tween frame.
|
|
267
|
+
let visible_idxs = $derived.by(() => {
|
|
268
|
+
const idxs: number[] = []
|
|
269
|
+
for (let idx = 0; idx < layout.arcs.length; idx++) {
|
|
270
|
+
if (idx_visible(idx)) idxs.push(idx)
|
|
271
|
+
}
|
|
272
|
+
return idxs
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
// Roving tabindex: exactly one cell is in the tab order (the last-focused one,
|
|
276
|
+
// else the first visible cell); arrow keys move focus between cells. Every
|
|
277
|
+
// visible cell is focusable (not just clickable ones) so keyboard users can
|
|
278
|
+
// reach tooltips, and so zooming into a branch of plain leaves doesn't strand
|
|
279
|
+
// focus outside the chart. role="button" stays limited to clickable cells.
|
|
280
|
+
let focused_idx = $state<number | null>(null)
|
|
281
|
+
let roving_idx = $derived(
|
|
282
|
+
focused_idx != null && idx_visible(focused_idx) ? focused_idx : (visible_idxs[0] ?? null),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
// Continuous metric coloring: when color_values is given, cells are colored by
|
|
286
|
+
// their metric on a d3 colormap (cells returning null keep their categorical color)
|
|
287
|
+
let metric = $derived(
|
|
288
|
+
compute_metric_colors(layout.arcs, color_values, color_scale, color_range),
|
|
289
|
+
)
|
|
290
|
+
const cell_color = (arc: PositionedArc<Metadata>): string =>
|
|
291
|
+
metric?.colors[arc.node_idx] ?? arc.color
|
|
292
|
+
// release the colorbar's reserved chart space when it's not rendered
|
|
293
|
+
$effect(() => {
|
|
294
|
+
if (!metric || colorbar == null) colorbar_height = 0
|
|
295
|
+
})
|
|
296
|
+
|
|
297
|
+
// Hovered cell + its ancestors/descendants stay fully opaque, others dim
|
|
298
|
+
let cell_dim = $derived(compute_node_dim(layout.arcs, muted_ids, hovered_idx))
|
|
299
|
+
|
|
300
|
+
const contrast_for = make_cached_contrast()
|
|
301
|
+
|
|
302
|
+
const make_node_props = (arc: PositionedArc<Metadata>): TreemapNodeHandlerProps<Metadata> =>
|
|
303
|
+
node_handler_props(layout.arcs, arc, cell_color(arc))
|
|
304
|
+
|
|
305
|
+
// Rect center in container (pad-offset) pixel space, for tooltip + legend placement
|
|
306
|
+
const rect_center = (rect: Rect): { x: number; y: number } => ({
|
|
307
|
+
x: pad.l + rect.x + rect.width / 2,
|
|
308
|
+
y: pad.t + rect.y + rect.height / 2,
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
function set_cell_hover(idx: number | null, event?: MouseEvent | FocusEvent) {
|
|
312
|
+
// Same cell as before: only the cursor anchor moves - skip rebuilding the
|
|
313
|
+
// handler payload and re-firing change/on_node_hover on every mousemove.
|
|
314
|
+
// Requires hover_info: legend item hover sets hovered_idx alone (for dimming).
|
|
315
|
+
if (idx != null && idx === hovered_idx && hover_info) {
|
|
316
|
+
hover_pos = pointer_pos(event, svg_element) ?? hover_pos
|
|
317
|
+
return
|
|
318
|
+
}
|
|
319
|
+
if (idx != null) {
|
|
320
|
+
hovered = true
|
|
321
|
+
hovered_idx = idx
|
|
322
|
+
hover_info = make_node_props(layout.arcs[idx])
|
|
323
|
+
hover_pos =
|
|
324
|
+
pointer_pos(event, svg_element) ?? (rects[idx] ? rect_center(rects[idx]) : hover_pos)
|
|
325
|
+
change(hover_info)
|
|
326
|
+
if (event) on_node_hover?.({ ...hover_info, event })
|
|
327
|
+
} else {
|
|
328
|
+
if (hovered_idx == null && hover_info == null) return
|
|
329
|
+
hovered = false
|
|
330
|
+
hovered_idx = null
|
|
331
|
+
hover_info = null
|
|
332
|
+
change(null)
|
|
333
|
+
on_node_hover?.(null)
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// Node idx carried by the event's nearest [data-treemap-node-idx] element
|
|
338
|
+
const idx_from_event = (event: Event): number | null => {
|
|
339
|
+
const idx = closest_data_idx(event, `data-treemap-node-idx`, svg_element)
|
|
340
|
+
return idx != null && layout.arcs[idx] ? idx : null
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
function handle_cell_hover_event(event: MouseEvent | FocusEvent) {
|
|
344
|
+
const idx = idx_from_event(event)
|
|
345
|
+
// roving tabindex follows keyboard focus
|
|
346
|
+
if (event.type === `focusin` && idx != null) focused_idx = idx
|
|
347
|
+
set_cell_hover(idx, event)
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Re-root the view on the given arc (or the data root when null) and notify
|
|
351
|
+
function zoom_to(arc: PositionedArc<Metadata> | null) {
|
|
352
|
+
const root = arc && arc.depth > 0 ? arc : null
|
|
353
|
+
zoom_root_id = root?.id ?? null
|
|
354
|
+
// The clicked cell expands to fill the viewport - drop the stale hover/tooltip
|
|
355
|
+
set_cell_hover(null)
|
|
356
|
+
on_zoom?.({ root: root && make_node_props(root) })
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Plotly semantics: clicking any cell (leaves included) zooms into it;
|
|
360
|
+
// clicking the current zoom root (the full-viewport cell a leaf zoom renders)
|
|
361
|
+
// zooms back out one level
|
|
362
|
+
function handle_cell_click(event: MouseEvent | KeyboardEvent) {
|
|
363
|
+
if (event instanceof MouseEvent && selection_within(wrapper)) return
|
|
364
|
+
const idx = idx_from_event(event)
|
|
365
|
+
if (idx == null) return
|
|
366
|
+
const arc = layout.arcs[idx]
|
|
367
|
+
on_node_click?.({ ...make_node_props(arc), event })
|
|
368
|
+
if (!zoom_on_click) return
|
|
369
|
+
if (arc.id === zoom_root?.id) zoom_out()
|
|
370
|
+
else zoom_to(arc)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function zoom_out() {
|
|
374
|
+
if (!zoomed) return
|
|
375
|
+
zoom_to(breadcrumb_arcs.at(-2) ?? null)
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Double-clicking empty chart background resets the zoom to the root (double-
|
|
379
|
+
// clicking a cell or label is click-to-zoom/text-selection territory, not a reset)
|
|
380
|
+
function handle_dblclick(event: MouseEvent) {
|
|
381
|
+
if (idx_from_event(event) != null || selection_within(wrapper)) return
|
|
382
|
+
if (zoomed) zoom_to(null)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const focus_cell = (idx: number | null) => {
|
|
386
|
+
if (idx == null) return
|
|
387
|
+
svg_element
|
|
388
|
+
?.querySelector<SVGRectElement>(`.cells [data-treemap-node-idx="${idx}"]`)
|
|
389
|
+
?.focus()
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Arrow-key navigation: left/right cycle through visible siblings (wrapping),
|
|
393
|
+
// down enters the first child, up returns to the parent (shared with Sunburst
|
|
394
|
+
// via the pre-order walk in render.ts)
|
|
395
|
+
const nav_target_from_event = (event: KeyboardEvent): number | null => {
|
|
396
|
+
const cur_idx = idx_from_event(event)
|
|
397
|
+
if (cur_idx == null) return null
|
|
398
|
+
return arrow_nav_target(layout.arcs, idx_visible, cur_idx, event.key)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function handle_cell_keydown(event: KeyboardEvent) {
|
|
402
|
+
const nav_target = nav_target_from_event(event)
|
|
403
|
+
if (nav_target != null) {
|
|
404
|
+
event.preventDefault()
|
|
405
|
+
focus_cell(nav_target)
|
|
406
|
+
return
|
|
407
|
+
}
|
|
408
|
+
if (!is_activation_key(event)) return
|
|
409
|
+
event.preventDefault()
|
|
410
|
+
const prev_root = zoom_root_id
|
|
411
|
+
handle_cell_click(event)
|
|
412
|
+
// Zooming via keyboard unmounts the focused cell - move focus to the new
|
|
413
|
+
// root's first child (pre-order: node_idx + 1), or the root cell itself for
|
|
414
|
+
// leaf zooms (rendered full-viewport), so keyboard users stay in the chart
|
|
415
|
+
if (zoom_root_id !== prev_root) {
|
|
416
|
+
tick().then(() => {
|
|
417
|
+
if (!zoom_root) return focus_cell(roving_idx)
|
|
418
|
+
focus_cell(zoom_root.is_leaf ? zoom_root.node_idx : zoom_root.node_idx + 1)
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// Uniform now that any cell zooms (plotly semantics), not just branches
|
|
424
|
+
let cells_clickable = $derived(Boolean(on_node_click) || zoom_on_click)
|
|
425
|
+
|
|
426
|
+
let label_font = $derived(svg_label_font(svg_element))
|
|
427
|
+
const cached_text_width = make_cached_text_width()
|
|
428
|
+
|
|
429
|
+
// Per-cell label text, measured width, fill/label colors and aria string -
|
|
430
|
+
// all zoom-independent, so computed once per layout/option change
|
|
431
|
+
let cell_info = $derived(
|
|
432
|
+
compute_node_infos(layout.arcs, {
|
|
433
|
+
label_text,
|
|
434
|
+
value_format,
|
|
435
|
+
label_font,
|
|
436
|
+
color_for: cell_color,
|
|
437
|
+
text_width: cached_text_width,
|
|
438
|
+
contrast: contrast_for,
|
|
439
|
+
}),
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
const LABEL_MARGIN = 6 // px clearance between label text and cell edges
|
|
443
|
+
// Label text + placement for a cell; null = no variant fits, hide the label.
|
|
444
|
+
// Branch cells label their header strip (top-left); leaves (and branches at the
|
|
445
|
+
// depth cutoff, which render as plain cells) center their label, rotating 90°
|
|
446
|
+
// in thin-but-tall cells like the icicle shape does. Richest label variant
|
|
447
|
+
// that fits wins: extended -> label -> label_short.
|
|
448
|
+
function label_attrs(
|
|
449
|
+
arc: PositionedArc<Metadata>,
|
|
450
|
+
rect: Rect,
|
|
451
|
+
): { x: number; y: number; text: string; transform?: string; header: boolean } | null {
|
|
452
|
+
const { variants } = cell_info[arc.node_idx]
|
|
453
|
+
const { x, y, width: cell_w, height: cell_h } = rect
|
|
454
|
+
// Branches with visible children only ever label their header strip: a
|
|
455
|
+
// centered label would paint over the descendant cells that cover the rest
|
|
456
|
+
// of the cell, so when the strip is missing/too thin the label is dropped
|
|
457
|
+
const has_visible_children = !arc.is_leaf && arc.depth < depth_cutoff
|
|
458
|
+
if (has_visible_children) {
|
|
459
|
+
if (padding_top < 12) return null
|
|
460
|
+
const fitting = variants.find((entry) => entry.width <= cell_w - 2 * LABEL_MARGIN)
|
|
461
|
+
if (!fitting) return null
|
|
462
|
+
return { x: x + LABEL_MARGIN, y: y + padding_top / 2, text: fitting.text, header: true }
|
|
463
|
+
}
|
|
464
|
+
const fits = (text_w: number, along: number, across: number) =>
|
|
465
|
+
text_w <= along - 2 * LABEL_MARGIN && across >= 12
|
|
466
|
+
const [cx, cy] = [x + cell_w / 2, y + cell_h / 2]
|
|
467
|
+
for (const { text, width: text_w } of variants) {
|
|
468
|
+
if (fits(text_w, cell_w, cell_h)) return { x: cx, y: cy, text, header: false }
|
|
469
|
+
if (fits(text_w, cell_h, cell_w)) {
|
|
470
|
+
return { x: cx, y: cy, text, transform: `rotate(-90, ${cx}, ${cy})`, header: false }
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return null
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Legend: one item per depth-1 category, toggling mutes (dims) rather than removes.
|
|
477
|
+
let depth1_arcs = $derived(layout.arcs.filter((arc) => arc.depth === 1))
|
|
478
|
+
let legend_visible = $derived(show_legend && legend != null && depth1_arcs.length > 1)
|
|
479
|
+
let legend_element = $state<HTMLDivElement | undefined>()
|
|
480
|
+
let legend_placement = $derived.by(() => {
|
|
481
|
+
if (!legend_visible || !width || !height) return null
|
|
482
|
+
// Place against the settled (target) tiling, not the animated one - placement
|
|
483
|
+
// is stable during zoom tweens. Same visibility rule as rendering so hidden
|
|
484
|
+
// cells (zoom root, beyond max_depth) don't repel the legend.
|
|
485
|
+
const settled = layout.arcs.flatMap((arc, idx) =>
|
|
486
|
+
cell_visible(arc, target_rects[idx]) ? [rect_center(target_rects[idx])] : [],
|
|
487
|
+
)
|
|
488
|
+
return compute_element_placement({
|
|
489
|
+
plot_bounds: { x: pad.l, y: pad.t, width: inner_width, height: inner_height },
|
|
490
|
+
element: legend_element,
|
|
491
|
+
element_size: { width: 120, height: 60 },
|
|
492
|
+
axis_clearance: legend?.axis_clearance,
|
|
493
|
+
exclude_rects: [],
|
|
494
|
+
points: settled,
|
|
495
|
+
})
|
|
496
|
+
})
|
|
497
|
+
let legend_data: LegendItem[] = $derived(
|
|
498
|
+
hierarchy_legend_items(depth1_arcs, muted_ids, cell_color),
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
const toggle_category = (series_idx: number) =>
|
|
502
|
+
toggle_muted(muted_ids, depth1_arcs[series_idx]?.id)
|
|
503
|
+
|
|
504
|
+
$effect(() => set_fullscreen_bg(wrapper, fullscreen, `--treemap-fullscreen-bg`))
|
|
505
|
+
|
|
506
|
+
let breadcrumb_arcs = $derived(ancestor_chain(layout.arcs, zoom_root))
|
|
507
|
+
|
|
508
|
+
const export_chart = (format: `svg` | `png`) =>
|
|
509
|
+
export_hierarchy_chart(svg_element, export_filename, format)
|
|
510
|
+
</script>
|
|
511
|
+
|
|
512
|
+
<svelte:window
|
|
513
|
+
onkeydown={(evt) =>
|
|
514
|
+
handle_hierarchy_escape(evt, {
|
|
515
|
+
wrapper,
|
|
516
|
+
fullscreen,
|
|
517
|
+
zoomed,
|
|
518
|
+
zoom_out,
|
|
519
|
+
exit_fullscreen: () => (fullscreen = false),
|
|
520
|
+
})}
|
|
521
|
+
/>
|
|
522
|
+
|
|
523
|
+
<div
|
|
524
|
+
bind:this={wrapper}
|
|
525
|
+
bind:clientWidth={width}
|
|
526
|
+
bind:clientHeight={height}
|
|
527
|
+
{...rest}
|
|
528
|
+
class={[`treemap`, rest.class]}
|
|
529
|
+
class:fullscreen
|
|
530
|
+
>
|
|
531
|
+
{#if width && height}
|
|
532
|
+
<div class="header-controls">
|
|
533
|
+
{@render header_controls?.({ height, width, fullscreen })}
|
|
534
|
+
{#if show_controls}
|
|
535
|
+
<TreemapControls
|
|
536
|
+
chart="treemap"
|
|
537
|
+
toggle_props={{
|
|
538
|
+
...controls_toggle_props,
|
|
539
|
+
// join the header flex row instead of absolute positioning
|
|
540
|
+
style: `position: static; ${controls_toggle_props?.style ?? ``}`,
|
|
541
|
+
}}
|
|
542
|
+
pane_props={controls_pane_props}
|
|
543
|
+
bind:show_controls
|
|
544
|
+
bind:controls_open
|
|
545
|
+
bind:value_mode
|
|
546
|
+
bind:max_depth
|
|
547
|
+
bind:padding_inner
|
|
548
|
+
bind:padding_top
|
|
549
|
+
bind:padding_outer
|
|
550
|
+
bind:min_fraction
|
|
551
|
+
bind:show_labels
|
|
552
|
+
bind:label_text
|
|
553
|
+
bind:zoom_on_click
|
|
554
|
+
bind:show_breadcrumbs
|
|
555
|
+
{export_buttons}
|
|
556
|
+
on_export={export_chart}
|
|
557
|
+
>
|
|
558
|
+
{@render controls_extra?.({ zoom_root_id })}
|
|
559
|
+
</TreemapControls>
|
|
560
|
+
{/if}
|
|
561
|
+
{#if fullscreen_toggle}
|
|
562
|
+
<FullscreenToggle bind:fullscreen />
|
|
563
|
+
{/if}
|
|
564
|
+
</div>
|
|
565
|
+
{#if show_breadcrumbs && breadcrumb_arcs.length > 0}
|
|
566
|
+
<!-- plotly-style pathbar: chevron segments, current root last (disabled) -->
|
|
567
|
+
<nav class="breadcrumbs" aria-label="zoom path">
|
|
568
|
+
{#each breadcrumb_arcs as crumb, crumb_idx (crumb.node_idx)}
|
|
569
|
+
<button
|
|
570
|
+
type="button"
|
|
571
|
+
class="breadcrumb"
|
|
572
|
+
disabled={crumb_idx === breadcrumb_arcs.length - 1}
|
|
573
|
+
onclick={() => zoom_to(crumb)}
|
|
574
|
+
>
|
|
575
|
+
{crumb.depth === 0 ? `all` : (crumb.label ?? crumb.id)}
|
|
576
|
+
</button>
|
|
577
|
+
{/each}
|
|
578
|
+
</nav>
|
|
579
|
+
{/if}
|
|
580
|
+
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
581
|
+
<svg
|
|
582
|
+
bind:this={svg_element}
|
|
583
|
+
viewBox="0 0 {width} {height}"
|
|
584
|
+
role="application"
|
|
585
|
+
aria-label={rest[`aria-label`] ?? `Treemap chart`}
|
|
586
|
+
onmouseleave={() => set_cell_hover(null)}
|
|
587
|
+
ondblclick={handle_dblclick}
|
|
588
|
+
>
|
|
589
|
+
<!-- inert unless some cell references it via fill -->
|
|
590
|
+
<defs>
|
|
591
|
+
<pattern id={hatch_pattern_id} patternUnits="userSpaceOnUse" width="8" height="8">
|
|
592
|
+
<path class="hatch-pattern-line" d="M-1,1 l2,-2 M0,8 l8,-8 M7,9 l2,-2" />
|
|
593
|
+
</pattern>
|
|
594
|
+
</defs>
|
|
595
|
+
<!-- Hover/click delegation sits on the chart group (not the cells group) so
|
|
596
|
+
labels - which carry the same data-treemap-node-idx and are selectable text -
|
|
597
|
+
forward interactions to their cell instead of swallowing them -->
|
|
598
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
599
|
+
<g
|
|
600
|
+
transform={`translate(${pad.l}, ${pad.t})`}
|
|
601
|
+
onmousemove={handle_cell_hover_event}
|
|
602
|
+
onmouseleave={() => set_cell_hover(null)}
|
|
603
|
+
onfocusin={handle_cell_hover_event}
|
|
604
|
+
onfocusout={() => set_cell_hover(null)}
|
|
605
|
+
onclick={handle_cell_click}
|
|
606
|
+
onkeydown={handle_cell_keydown}
|
|
607
|
+
>
|
|
608
|
+
<!-- Cells: pre-order document order paints parents first, children on top -->
|
|
609
|
+
<g class="cells">
|
|
610
|
+
{#each visible_idxs as idx (idx)}
|
|
611
|
+
{@const rect = rects[idx]}
|
|
612
|
+
{#if cell_content}
|
|
613
|
+
{@render cell_content({ arc: layout.arcs[idx], rect })}
|
|
614
|
+
{:else}
|
|
615
|
+
{@const info = cell_info[idx]}
|
|
616
|
+
{@const opacity = cell_dim[idx].opacity}
|
|
617
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
618
|
+
<rect
|
|
619
|
+
x={rect.x}
|
|
620
|
+
y={rect.y}
|
|
621
|
+
width={rect.width}
|
|
622
|
+
height={rect.height}
|
|
623
|
+
data-treemap-node-idx={idx}
|
|
624
|
+
fill={info.fill}
|
|
625
|
+
fill-opacity={opacity}
|
|
626
|
+
role={cells_clickable ? `button` : undefined}
|
|
627
|
+
tabindex={idx === roving_idx ? 0 : -1}
|
|
628
|
+
aria-label={info.aria}
|
|
629
|
+
style:cursor={cells_clickable ? `pointer` : `default`}
|
|
630
|
+
/>
|
|
631
|
+
{#if layout.arcs[idx].hatch}
|
|
632
|
+
<!-- Decorative texture overlay; ignores pointer events -->
|
|
633
|
+
<rect
|
|
634
|
+
class="cell-hatch"
|
|
635
|
+
aria-hidden="true"
|
|
636
|
+
x={rect.x}
|
|
637
|
+
y={rect.y}
|
|
638
|
+
width={rect.width}
|
|
639
|
+
height={rect.height}
|
|
640
|
+
fill="url(#{hatch_pattern_id})"
|
|
641
|
+
fill-opacity={opacity}
|
|
642
|
+
/>
|
|
643
|
+
{/if}
|
|
644
|
+
{/if}
|
|
645
|
+
{/each}
|
|
646
|
+
</g>
|
|
647
|
+
|
|
648
|
+
<!-- Cell labels: selectable text; data-treemap-node-idx forwards hover/click
|
|
649
|
+
to the underlying cell via the chart-group delegation above -->
|
|
650
|
+
{#if show_labels && !cell_content}
|
|
651
|
+
<g class="cell-labels">
|
|
652
|
+
{#each visible_idxs as idx (idx)}
|
|
653
|
+
{@const lbl = label_attrs(layout.arcs[idx], rects[idx])}
|
|
654
|
+
{#if lbl}
|
|
655
|
+
<text
|
|
656
|
+
class="cell-label"
|
|
657
|
+
class:header={lbl.header}
|
|
658
|
+
data-treemap-node-idx={idx}
|
|
659
|
+
x={lbl.x}
|
|
660
|
+
y={lbl.y}
|
|
661
|
+
transform={lbl.transform}
|
|
662
|
+
fill={cell_info[idx].label_fill}
|
|
663
|
+
fill-opacity={cell_dim[idx].label_opacity}
|
|
664
|
+
style:cursor={cells_clickable ? `pointer` : `text`}
|
|
665
|
+
>
|
|
666
|
+
{lbl.text}
|
|
667
|
+
</text>
|
|
668
|
+
{/if}
|
|
669
|
+
{/each}
|
|
670
|
+
</g>
|
|
671
|
+
{/if}
|
|
672
|
+
</g>
|
|
673
|
+
</svg>
|
|
674
|
+
{/if}
|
|
675
|
+
|
|
676
|
+
{#if hover_info}
|
|
677
|
+
<PlotTooltip
|
|
678
|
+
x={hover_pos.x}
|
|
679
|
+
y={hover_pos.y}
|
|
680
|
+
offset={{ x: 10, y: 5 }}
|
|
681
|
+
constrain_to={{ width, height }}
|
|
682
|
+
fallback_size={{ width: 140, height: 44 }}
|
|
683
|
+
bg_color={hover_info.color}
|
|
684
|
+
>
|
|
685
|
+
{#if tooltip}
|
|
686
|
+
{@render tooltip(hover_info)}
|
|
687
|
+
{:else}
|
|
688
|
+
<strong>{hover_info.label_path.join(` › `)}</strong>: {format_value(
|
|
689
|
+
hover_info.value,
|
|
690
|
+
value_format,
|
|
691
|
+
)}
|
|
692
|
+
({format_value(hover_info.fraction, `.1%`)} of total{hover_info.depth > 1
|
|
693
|
+
? `, ${format_value(hover_info.parent_fraction, `.1%`)} of parent`
|
|
694
|
+
: ``})
|
|
695
|
+
{/if}
|
|
696
|
+
</PlotTooltip>
|
|
697
|
+
{/if}
|
|
698
|
+
|
|
699
|
+
{#if legend_visible}
|
|
700
|
+
{@const legend_left = legend_placement?.x ?? pad.l + 10}
|
|
701
|
+
{@const legend_top = legend_placement?.y ?? pad.t + 10}
|
|
702
|
+
<PlotLegend
|
|
703
|
+
bind:root_element={legend_element}
|
|
704
|
+
{...legend}
|
|
705
|
+
series_data={legend_data}
|
|
706
|
+
on_toggle={legend?.on_toggle ?? toggle_category}
|
|
707
|
+
on_item_hover={(item) =>
|
|
708
|
+
(hovered_idx =
|
|
709
|
+
item != null && item.series_idx >= 0
|
|
710
|
+
? (depth1_arcs[item.series_idx]?.node_idx ?? null)
|
|
711
|
+
: null)}
|
|
712
|
+
style={`position: absolute; left: ${legend_left}px; top: ${legend_top}px; pointer-events: auto; ${
|
|
713
|
+
legend?.style ?? ``
|
|
714
|
+
}`}
|
|
715
|
+
/>
|
|
716
|
+
{/if}
|
|
717
|
+
|
|
718
|
+
{#if metric && colorbar != null}
|
|
719
|
+
<div
|
|
720
|
+
bind:clientHeight={colorbar_height}
|
|
721
|
+
style="position: absolute; bottom: var(--treemap-colorbar-bottom, 8px); left: 50%; transform: translateX(-50%); width: var(--treemap-colorbar-width, 40%); min-width: 120px; pointer-events: auto;"
|
|
722
|
+
>
|
|
723
|
+
<ColorBar
|
|
724
|
+
{color_scale}
|
|
725
|
+
range={metric.range}
|
|
726
|
+
{...colorbar}
|
|
727
|
+
wrapper_style={`width: 100%; ${colorbar?.wrapper_style ?? ``}`}
|
|
728
|
+
/>
|
|
729
|
+
</div>
|
|
730
|
+
{/if}
|
|
731
|
+
|
|
732
|
+
{@render children?.({ height, width, fullscreen })}
|
|
733
|
+
</div>
|
|
734
|
+
|
|
735
|
+
<style>
|
|
736
|
+
.treemap {
|
|
737
|
+
position: relative;
|
|
738
|
+
width: var(--treemap-width, 100%);
|
|
739
|
+
height: var(--treemap-height, auto);
|
|
740
|
+
min-height: var(--treemap-min-height, 300px);
|
|
741
|
+
container-type: size;
|
|
742
|
+
z-index: var(--treemap-z-index, auto);
|
|
743
|
+
/* flex-basis auto (not 1 = 0%) so an authored height wins over flex sizing in
|
|
744
|
+
column-flex parents while the chart still grows/shrinks to fill fixed layouts */
|
|
745
|
+
flex: var(--treemap-flex, 1 1 auto);
|
|
746
|
+
display: var(--treemap-display, flex);
|
|
747
|
+
flex-direction: column;
|
|
748
|
+
background: var(--treemap-bg, var(--plot-bg));
|
|
749
|
+
border-radius: var(--treemap-border-radius, var(--border-radius, 3pt));
|
|
750
|
+
}
|
|
751
|
+
.treemap.fullscreen {
|
|
752
|
+
position: fixed;
|
|
753
|
+
top: 0;
|
|
754
|
+
left: 0;
|
|
755
|
+
width: 100vw !important;
|
|
756
|
+
height: 100vh !important;
|
|
757
|
+
z-index: var(--treemap-fullscreen-z-index, var(--z-index-overlay-nav, 100000001));
|
|
758
|
+
margin: 0;
|
|
759
|
+
border-radius: 0;
|
|
760
|
+
background: var(--treemap-fullscreen-bg, var(--treemap-bg, var(--plot-bg)));
|
|
761
|
+
max-height: none !important;
|
|
762
|
+
overflow: hidden;
|
|
763
|
+
/* border-top (not padding-top): bind:clientHeight includes padding but excludes
|
|
764
|
+
borders */
|
|
765
|
+
border-top: var(--plot-fullscreen-padding-top, 2em) solid
|
|
766
|
+
var(--treemap-fullscreen-bg, var(--treemap-bg, var(--plot-bg, transparent)));
|
|
767
|
+
box-sizing: border-box;
|
|
768
|
+
}
|
|
769
|
+
.header-controls {
|
|
770
|
+
position: absolute;
|
|
771
|
+
top: var(--ctrl-btn-top, 5pt);
|
|
772
|
+
right: var(--fullscreen-btn-right, 4px);
|
|
773
|
+
z-index: var(--fullscreen-btn-z-index, 10);
|
|
774
|
+
display: flex;
|
|
775
|
+
align-items: center;
|
|
776
|
+
gap: 8px;
|
|
777
|
+
}
|
|
778
|
+
.header-controls :global(.fullscreen-toggle) {
|
|
779
|
+
position: static;
|
|
780
|
+
opacity: 1;
|
|
781
|
+
}
|
|
782
|
+
/* plotly-pathbar look: right-pointing chevron segments with a matching left
|
|
783
|
+
notch on all but the first, slightly overlapped so they read as one bar.
|
|
784
|
+
Opaque background: the pathbar overlays arbitrarily-colored cells, and a
|
|
785
|
+
translucent one would be illegible over dark fills */
|
|
786
|
+
.breadcrumb {
|
|
787
|
+
background: var(--treemap-btn-bg, light-dark(#e3e6ea, #33383f));
|
|
788
|
+
color: inherit;
|
|
789
|
+
border: none;
|
|
790
|
+
padding: 2px 14px 2px 12px;
|
|
791
|
+
cursor: pointer;
|
|
792
|
+
font: inherit;
|
|
793
|
+
clip-path: polygon(
|
|
794
|
+
0 0,
|
|
795
|
+
calc(100% - 7px) 0,
|
|
796
|
+
100% 50%,
|
|
797
|
+
calc(100% - 7px) 100%,
|
|
798
|
+
0 100%,
|
|
799
|
+
7px 50%
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
.breadcrumb:first-child {
|
|
803
|
+
border-radius: 3pt 0 0 3pt;
|
|
804
|
+
padding-inline-start: 8px;
|
|
805
|
+
clip-path: polygon(0 0, calc(100% - 7px) 0, 100% 50%, calc(100% - 7px) 100%, 0 100%);
|
|
806
|
+
}
|
|
807
|
+
.breadcrumb:hover:not(:disabled) {
|
|
808
|
+
background: var(--treemap-btn-hover-bg, light-dark(#d0d5db, #454b54));
|
|
809
|
+
}
|
|
810
|
+
/* inset focus ring: native outlines get clipped by the chevron clip-path and
|
|
811
|
+
hidden under the next overlapped segment */
|
|
812
|
+
.breadcrumb:focus-visible {
|
|
813
|
+
position: relative;
|
|
814
|
+
z-index: 1;
|
|
815
|
+
outline: none;
|
|
816
|
+
box-shadow: inset 0 0 0 2px var(--accent-color, Highlight);
|
|
817
|
+
}
|
|
818
|
+
.breadcrumbs {
|
|
819
|
+
position: absolute;
|
|
820
|
+
top: var(--treemap-breadcrumbs-top, 5pt);
|
|
821
|
+
left: var(--treemap-breadcrumbs-left, 8px);
|
|
822
|
+
z-index: 9;
|
|
823
|
+
display: flex;
|
|
824
|
+
align-items: stretch;
|
|
825
|
+
flex-wrap: wrap;
|
|
826
|
+
max-width: 75%;
|
|
827
|
+
font-size: var(--treemap-breadcrumbs-font-size, 0.85em);
|
|
828
|
+
}
|
|
829
|
+
/* negative gap: each chevron tip tucks into the next segment's left notch */
|
|
830
|
+
.breadcrumb + .breadcrumb {
|
|
831
|
+
margin-left: -6px;
|
|
832
|
+
}
|
|
833
|
+
.breadcrumb:disabled {
|
|
834
|
+
cursor: default;
|
|
835
|
+
font-weight: bold;
|
|
836
|
+
}
|
|
837
|
+
.treemap :global(.pane-toggle),
|
|
838
|
+
.treemap .header-controls {
|
|
839
|
+
opacity: 0;
|
|
840
|
+
transition:
|
|
841
|
+
opacity 0.2s,
|
|
842
|
+
background-color 0.2s;
|
|
843
|
+
}
|
|
844
|
+
.treemap:hover :global(.pane-toggle),
|
|
845
|
+
.treemap:hover .header-controls,
|
|
846
|
+
.treemap :global(.pane-toggle:focus-visible),
|
|
847
|
+
.treemap :global(.pane-toggle[aria-expanded='true']),
|
|
848
|
+
.treemap .header-controls:has(:global([aria-expanded='true'])),
|
|
849
|
+
.treemap .header-controls:focus-within {
|
|
850
|
+
opacity: 1;
|
|
851
|
+
}
|
|
852
|
+
svg {
|
|
853
|
+
width: var(--treemap-svg-width, 100%);
|
|
854
|
+
height: var(--treemap-svg-height, 100%);
|
|
855
|
+
flex: var(--treemap-svg-flex, 1);
|
|
856
|
+
overflow: var(--treemap-svg-overflow, visible);
|
|
857
|
+
fill: var(--text-color);
|
|
858
|
+
font-size: var(--treemap-font-size, 11px);
|
|
859
|
+
}
|
|
860
|
+
.cells rect {
|
|
861
|
+
/* stroke via CSS (not presentation attributes): var() substitution in SVG
|
|
862
|
+
presentation attributes is not reliably supported across browsers.
|
|
863
|
+
Dividers matter more here than in the sunburst: sibling gaps show the
|
|
864
|
+
parent's fill (parents paint under their children), which is identical to
|
|
865
|
+
the children's inherited color - without a stroke, same-color siblings
|
|
866
|
+
blend into one shape. Not defaulted to --plot-bg because that is often
|
|
867
|
+
semi-transparent (near-invisible as a line); light-dark keeps dividers
|
|
868
|
+
paper-colored in both themes, like plotly */
|
|
869
|
+
stroke: var(--treemap-cell-stroke, light-dark(white, #16181d));
|
|
870
|
+
stroke-width: var(--treemap-cell-stroke-width, 1);
|
|
871
|
+
transition: fill-opacity 0.15s ease;
|
|
872
|
+
}
|
|
873
|
+
.cells rect:hover {
|
|
874
|
+
filter: brightness(var(--treemap-hover-brightness, 1.08));
|
|
875
|
+
}
|
|
876
|
+
/* decorative overlay: never intercepts pointer events, no hover effect */
|
|
877
|
+
.cells rect.cell-hatch {
|
|
878
|
+
stroke: none;
|
|
879
|
+
pointer-events: none;
|
|
880
|
+
}
|
|
881
|
+
/* subtle by default: thin stripes inheriting the cell border color (itself
|
|
882
|
+
defaulting to the chart bg) at low opacity, so hatching matches the gaps
|
|
883
|
+
between cells instead of reading as solid white */
|
|
884
|
+
.hatch-pattern-line {
|
|
885
|
+
stroke: var(
|
|
886
|
+
--treemap-hatch-stroke,
|
|
887
|
+
color-mix(
|
|
888
|
+
in srgb,
|
|
889
|
+
var(--treemap-cell-stroke, light-dark(white, #16181d)) 30%,
|
|
890
|
+
transparent
|
|
891
|
+
)
|
|
892
|
+
);
|
|
893
|
+
stroke-width: var(--treemap-hatch-stroke-width, 0.35);
|
|
894
|
+
}
|
|
895
|
+
.cell-label {
|
|
896
|
+
text-anchor: middle;
|
|
897
|
+
dominant-baseline: central;
|
|
898
|
+
/* selectable so labels can be copied; clicks/hover still reach the underlying
|
|
899
|
+
cell via data-treemap-node-idx + delegation on the chart group */
|
|
900
|
+
-webkit-user-select: text;
|
|
901
|
+
user-select: text;
|
|
902
|
+
}
|
|
903
|
+
.cell-label.header {
|
|
904
|
+
text-anchor: start;
|
|
905
|
+
font-weight: 600;
|
|
906
|
+
}
|
|
907
|
+
</style>
|