matterviz 0.4.1 → 0.4.3
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 +48 -60
- package/dist/Icon.svelte +7 -4
- package/dist/MillerIndexInput.svelte +2 -2
- package/dist/api/optimade.js +10 -7
- package/dist/app.css +68 -0
- package/dist/brillouin/BrillouinZone.svelte +90 -91
- package/dist/brillouin/BrillouinZone.svelte.d.ts +5 -7
- package/dist/brillouin/BrillouinZoneControls.svelte +3 -6
- package/dist/brillouin/BrillouinZoneExportPane.svelte +18 -14
- package/dist/brillouin/BrillouinZoneInfoPane.svelte +6 -10
- package/dist/brillouin/BrillouinZoneScene.svelte +46 -68
- package/dist/brillouin/BrillouinZoneScene.svelte.d.ts +1 -1
- package/dist/brillouin/compute.js +10 -16
- package/dist/brillouin/geometry.js +2 -2
- package/dist/chempot-diagram/ChemPotDiagram.svelte +48 -50
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte +61 -169
- package/dist/chempot-diagram/ChemPotDiagram2D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte +559 -755
- package/dist/chempot-diagram/ChemPotDiagram3D.svelte.d.ts +1 -1
- package/dist/chempot-diagram/async-compute.svelte.js +13 -14
- package/dist/chempot-diagram/color.d.ts +21 -1
- package/dist/chempot-diagram/color.js +70 -1
- package/dist/chempot-diagram/compute.d.ts +7 -0
- package/dist/chempot-diagram/compute.js +85 -26
- package/dist/chempot-diagram/controls-state.svelte.js +1 -1
- package/dist/chempot-diagram/export.js +1 -6
- package/dist/chempot-diagram/temperature.js +9 -10
- package/dist/colors/index.d.ts +0 -4
- package/dist/colors/index.js +19 -20
- package/dist/composition/BarChart.svelte +30 -26
- package/dist/composition/BubbleChart.svelte +17 -17
- package/dist/composition/Composition.svelte +10 -19
- package/dist/composition/Formula.svelte +20 -27
- package/dist/composition/FormulaFilter.svelte +115 -184
- package/dist/composition/PieChart.svelte +55 -41
- package/dist/composition/format.js +7 -9
- package/dist/composition/index.d.ts +2 -0
- package/dist/composition/index.js +14 -0
- package/dist/composition/parse.d.ts +2 -2
- package/dist/composition/parse.js +61 -115
- package/dist/constants.d.ts +0 -1
- package/dist/constants.js +17 -26
- package/dist/convex-hull/ConvexHull.svelte +12 -15
- package/dist/convex-hull/ConvexHull.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull2D.svelte +93 -94
- package/dist/convex-hull/ConvexHull2D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull3D.svelte +127 -186
- package/dist/convex-hull/ConvexHull3D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHull4D.svelte +131 -180
- package/dist/convex-hull/ConvexHull4D.svelte.d.ts +1 -1
- package/dist/convex-hull/ConvexHullChrome.svelte +36 -40
- package/dist/convex-hull/ConvexHullControls.svelte +46 -48
- package/dist/convex-hull/ConvexHullStats.svelte +193 -195
- package/dist/convex-hull/ConvexHullTooltip.svelte +5 -12
- package/dist/convex-hull/GasPressureControls.svelte +5 -12
- package/dist/convex-hull/StructurePopup.svelte +18 -22
- package/dist/convex-hull/StructurePopup.svelte.d.ts +2 -0
- package/dist/convex-hull/TemperatureSlider.svelte +4 -10
- package/dist/convex-hull/canvas-interactions.svelte.js +2 -1
- package/dist/convex-hull/gas-thermodynamics.js +21 -53
- package/dist/convex-hull/helpers.d.ts +8 -10
- package/dist/convex-hull/helpers.js +37 -43
- package/dist/convex-hull/hull-state.svelte.d.ts +1 -1
- package/dist/convex-hull/thermodynamics.js +37 -44
- package/dist/coordination/CoordinationBarPlot.svelte +49 -53
- 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 +5 -9
- 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 +44 -67
- package/dist/element/Nucleus.svelte +4 -2
- package/dist/element/data.d.ts +3 -2
- package/dist/element/data.js +5 -1
- package/dist/element/helpers.d.ts +4 -0
- package/dist/element/helpers.js +18 -0
- package/dist/element/index.d.ts +2 -5
- package/dist/element/index.js +4 -19
- package/dist/feedback/DragOverlay.svelte +5 -5
- package/dist/feedback/DragOverlay.svelte.d.ts +2 -2
- package/dist/feedback/StatusMessage.svelte +7 -4
- package/dist/fermi-surface/FermiSlice.svelte +21 -18
- package/dist/fermi-surface/FermiSurface.svelte +35 -44
- package/dist/fermi-surface/FermiSurface.svelte.d.ts +7 -13
- package/dist/fermi-surface/FermiSurfaceControls.svelte +6 -20
- package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceScene.svelte +64 -136
- package/dist/fermi-surface/FermiSurfaceScene.svelte.d.ts +1 -1
- package/dist/fermi-surface/FermiSurfaceTooltip.svelte +9 -6
- package/dist/fermi-surface/compute.js +25 -58
- package/dist/fermi-surface/parse.js +54 -88
- package/dist/file-viewer/JsonBrowser.svelte +1043 -0
- package/dist/file-viewer/JsonBrowser.svelte.d.ts +9 -0
- package/dist/file-viewer/PlotPanel.svelte +350 -0
- package/dist/file-viewer/PlotPanel.svelte.d.ts +9 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte +30 -0
- package/dist/file-viewer/TrajectoryWithDos.svelte.d.ts +10 -0
- package/dist/file-viewer/detect.d.ts +11 -0
- package/dist/file-viewer/detect.js +381 -0
- package/dist/file-viewer/eligibility.d.ts +4 -0
- package/dist/file-viewer/eligibility.js +53 -0
- package/dist/file-viewer/host-protocol.d.ts +50 -0
- package/dist/file-viewer/host-transfer.d.ts +25 -0
- package/dist/file-viewer/host-transfer.js +42 -0
- package/dist/file-viewer/index.d.ts +5 -0
- package/dist/file-viewer/index.js +5 -0
- package/dist/file-viewer/main.d.ts +44 -0
- package/dist/file-viewer/main.js +535 -0
- package/dist/file-viewer/parse.d.ts +9 -0
- package/dist/file-viewer/parse.js +170 -0
- package/dist/file-viewer/plot-utils.d.ts +24 -0
- package/dist/file-viewer/plot-utils.js +191 -0
- package/dist/file-viewer/types.d.ts +4 -0
- package/dist/file-viewer/types.js +5 -0
- package/dist/heatmap-matrix/HeatmapMatrix.svelte +153 -219
- package/dist/heatmap-matrix/HeatmapMatrix.svelte.d.ts +2 -2
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte +9 -7
- package/dist/heatmap-matrix/HeatmapMatrixControls.svelte.d.ts +1 -1
- package/dist/heatmap-matrix/index.d.ts +5 -0
- package/dist/icons.d.ts +4 -0
- package/dist/icons.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/io/ExportPane.svelte +11 -7
- package/dist/io/decompress.d.ts +4 -1
- package/dist/io/decompress.js +24 -36
- package/dist/io/export.d.ts +11 -4
- package/dist/io/export.js +75 -19
- package/dist/io/fetch.d.ts +0 -3
- package/dist/io/fetch.js +0 -11
- package/dist/io/file-drop.js +60 -35
- package/dist/io/index.d.ts +0 -1
- package/dist/io/index.js +2 -9
- package/dist/io/is-binary.d.ts +9 -0
- package/dist/io/is-binary.js +45 -1
- package/dist/io/url-drop.d.ts +2 -0
- package/dist/io/url-drop.js +40 -40
- package/dist/isosurface/Isosurface.svelte +700 -215
- package/dist/isosurface/Isosurface.svelte.d.ts +7 -1
- package/dist/isosurface/IsosurfaceControls.svelte +590 -116
- package/dist/isosurface/IsosurfaceControls.svelte.d.ts +1 -1
- package/dist/isosurface/VolumeSlice.svelte +224 -0
- package/dist/isosurface/VolumeSlice.svelte.d.ts +28 -0
- package/dist/isosurface/coloring.d.ts +20 -0
- package/dist/isosurface/coloring.js +118 -0
- package/dist/isosurface/geometry-worker-types.d.ts +38 -0
- package/dist/isosurface/geometry.worker.d.ts +1 -0
- package/dist/isosurface/geometry.worker.js +59 -0
- package/dist/isosurface/grid.d.ts +10 -0
- package/dist/isosurface/grid.js +31 -0
- package/dist/isosurface/index.d.ts +4 -0
- package/dist/isosurface/index.js +4 -0
- package/dist/isosurface/parse-vaspwave.d.ts +3 -0
- package/dist/isosurface/parse-vaspwave.js +138 -0
- package/dist/isosurface/parse.js +6 -6
- package/dist/isosurface/profile.d.ts +12 -0
- package/dist/isosurface/profile.js +19 -0
- package/dist/isosurface/sampling.d.ts +34 -0
- package/dist/isosurface/sampling.js +408 -0
- package/dist/isosurface/slice-rendering.d.ts +13 -0
- package/dist/isosurface/slice-rendering.js +79 -0
- package/dist/isosurface/slice.d.ts +22 -2
- package/dist/isosurface/slice.js +200 -116
- package/dist/isosurface/types.d.ts +24 -1
- package/dist/isosurface/types.js +120 -8
- package/dist/json-path.d.ts +4 -0
- package/dist/json-path.js +89 -0
- package/dist/labels.d.ts +6 -2
- package/dist/labels.js +44 -14
- package/dist/layout/FullscreenButton.svelte +2 -1
- package/dist/layout/FullscreenToggle.svelte +10 -4
- package/dist/layout/InfoCard.svelte +8 -21
- 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 +57 -62
- package/dist/layout/SettingsSection.svelte.d.ts +6 -7
- package/dist/layout/SubpageGrid.svelte +3 -1
- package/dist/layout/ViewerChrome.svelte +16 -11
- package/dist/layout/ViewerChrome.svelte.d.ts +2 -1
- package/dist/layout/fullscreen.js +3 -5
- package/dist/layout/fullscreen.svelte.js +1 -2
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/index.js +1 -0
- package/dist/layout/json-tree/JsonNode.svelte +22 -59
- package/dist/layout/json-tree/JsonTree.svelte +101 -172
- package/dist/layout/json-tree/JsonValue.svelte +9 -32
- package/dist/layout/json-tree/utils.d.ts +0 -3
- package/dist/layout/json-tree/utils.js +50 -188
- package/dist/marching-cubes.d.ts +8 -1
- package/dist/marching-cubes.js +115 -48
- package/dist/math.d.ts +5 -2
- package/dist/math.js +48 -38
- package/dist/overlays/ContextMenu.svelte +19 -34
- package/dist/overlays/CopyButton.svelte +11 -5
- package/dist/overlays/DragControlTab.svelte +6 -1
- package/dist/overlays/DraggablePane.svelte +110 -74
- package/dist/overlays/DraggablePane.svelte.d.ts +2 -1
- package/dist/overlays/GlassChip.svelte +32 -0
- package/dist/overlays/GlassChip.svelte.d.ts +8 -0
- package/dist/overlays/InfoPaneCards.svelte +11 -23
- package/dist/overlays/index.d.ts +7 -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 +113 -145
- package/dist/periodic-table/PeriodicTable.svelte.d.ts +5 -3
- package/dist/periodic-table/PeriodicTableControls.svelte +37 -115
- package/dist/periodic-table/TableInset.svelte +9 -4
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +68 -105
- package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +6 -8
- package/dist/phase-diagram/PhaseDiagramControls.svelte +70 -94
- package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
- package/dist/phase-diagram/PhaseDiagramEditorPane.svelte +2 -1
- package/dist/phase-diagram/PhaseDiagramExportPane.svelte +12 -12
- package/dist/phase-diagram/PhaseDiagramTooltip.svelte +54 -58
- package/dist/phase-diagram/TdbInfoPanel.svelte +21 -15
- package/dist/phase-diagram/build-diagram.js +4 -9
- package/dist/phase-diagram/diagram-input.d.ts +1 -2
- package/dist/phase-diagram/parse.js +15 -15
- package/dist/phase-diagram/svg-to-diagram.js +28 -27
- package/dist/phase-diagram/utils.js +2 -3
- package/dist/plot/bar/BarPlot.svelte +461 -426
- package/dist/plot/bar/BarPlot.svelte.d.ts +2 -0
- package/dist/plot/bar/BarPlotControls.svelte +1 -3
- package/dist/plot/bar/BarPlotControls.svelte.d.ts +4 -6
- package/dist/plot/bar/SpacegroupBarPlot.svelte +46 -77
- package/dist/plot/bar/data.d.ts +5 -4
- package/dist/plot/bar/data.js +2 -1
- package/dist/plot/box/BoxPlot.svelte +322 -226
- package/dist/plot/box/BoxPlot.svelte.d.ts +2 -0
- package/dist/plot/box/Violin.svelte.d.ts +1 -0
- package/dist/plot/box/box-plot.js +1 -1
- package/dist/plot/core/auto-place.d.ts +1 -1
- package/dist/plot/core/auto-place.js +2 -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 +101 -106
- 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 +18 -9
- package/dist/plot/core/components/Line.svelte.d.ts +2 -0
- package/dist/plot/core/components/PlotAxis.svelte +40 -17
- package/dist/plot/core/components/PlotControls.svelte +65 -41
- 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 +54 -57
- package/dist/plot/core/components/ReferencePlane.svelte +7 -8
- 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 +27 -474
- package/dist/plot/core/data-transform.d.ts +1 -2
- package/dist/plot/core/data-transform.js +9 -15
- package/dist/plot/core/fill-utils.d.ts +3 -1
- package/dist/plot/core/fill-utils.js +28 -6
- package/dist/plot/core/index.d.ts +1 -0
- package/dist/plot/core/index.js +1 -0
- package/dist/plot/core/interactions.js +0 -2
- package/dist/plot/core/layout.d.ts +15 -6
- package/dist/plot/core/layout.js +57 -38
- 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 +2 -4
- package/dist/plot/core/pan-zoom.svelte.js +34 -17
- package/dist/plot/core/placed-tween.svelte.d.ts +3 -0
- package/dist/plot/core/placed-tween.svelte.js +68 -21
- package/dist/plot/core/reference-line.js +1 -1
- package/dist/plot/core/scales.d.ts +23 -0
- package/dist/plot/core/scales.js +39 -13
- package/dist/plot/core/svg.js +0 -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 +29 -324
- package/dist/plot/core/types.js +23 -20
- package/dist/plot/core/utils/hierarchy-chart.d.ts +52 -0
- package/dist/plot/core/utils/hierarchy-chart.js +191 -0
- package/dist/plot/core/utils/hierarchy-labels.d.ts +20 -0
- package/dist/plot/core/utils/hierarchy-labels.js +100 -0
- package/dist/plot/core/utils/label-placement.js +2 -2
- package/dist/plot/histogram/Histogram.svelte +314 -340
- package/dist/plot/histogram/Histogram.svelte.d.ts +7 -7
- package/dist/plot/histogram/HistogramControls.svelte +30 -28
- 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 +78 -69
- package/dist/plot/sankey/Sankey.svelte.d.ts +2 -2
- package/dist/plot/sankey/SankeyControls.svelte +22 -16
- package/dist/plot/sankey/sankey.js +13 -9
- package/dist/plot/scatter/BinnedScatterPlot.svelte +311 -141
- package/dist/plot/scatter/BinnedScatterPlot.svelte.d.ts +7 -0
- package/dist/plot/scatter/ElementScatter.svelte +4 -1
- package/dist/plot/scatter/ScatterPlot.svelte +517 -410
- package/dist/plot/scatter/ScatterPlot.svelte.d.ts +2 -0
- 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/adaptive-density.d.ts +1 -1
- package/dist/plot/scatter/adaptive-density.js +36 -20
- package/dist/plot/scatter/binned-scatter-types.d.ts +3 -2
- package/dist/plot/scatter/binned-scatter-types.js +6 -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 +25 -34
- package/dist/plot/scatter-3d/ScatterPlot3D.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/ScatterPlot3DControls.svelte +8 -5
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte +113 -116
- package/dist/plot/scatter-3d/ScatterPlot3DScene.svelte.d.ts +2 -2
- package/dist/plot/scatter-3d/Surface3D.svelte +4 -13
- package/dist/plot/sunburst/Sunburst.svelte +269 -347
- package/dist/plot/sunburst/Sunburst.svelte.d.ts +2 -2
- 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 +10 -3
- package/dist/plot/treemap/Treemap.svelte +1022 -0
- package/dist/plot/treemap/Treemap.svelte.d.ts +90 -0
- package/dist/plot/treemap/index.d.ts +4 -0
- package/dist/plot/treemap/index.js +4 -0
- package/dist/plot/treemap/labels.d.ts +38 -0
- package/dist/plot/treemap/labels.js +80 -0
- package/dist/plot/treemap/treemap.d.ts +28 -0
- package/dist/plot/treemap/treemap.js +102 -0
- package/dist/rdf/RdfPlot.svelte +37 -59
- package/dist/rdf/RdfPlot.svelte.d.ts +1 -1
- package/dist/rdf/calc-rdf.js +63 -52
- package/dist/rdf/index.d.ts +0 -1
- package/dist/sanitize.js +85 -27
- package/dist/scene/SceneCamera.svelte +1 -1
- package/dist/scene/SceneCamera.svelte.d.ts +1 -1
- package/dist/scene/bind-renderer.svelte.js +14 -6
- package/dist/scene/index.d.ts +1 -2
- package/dist/scene/index.js +1 -1
- package/dist/scene/{props.js → props.svelte.js} +15 -1
- package/dist/settings.d.ts +19 -9
- package/dist/settings.js +229 -525
- package/dist/spectral/Bands.svelte +207 -221
- package/dist/spectral/BandsAndDos.svelte +11 -9
- package/dist/spectral/BrillouinBandsDos.svelte +19 -42
- package/dist/spectral/Dos.svelte +92 -93
- package/dist/spectral/helpers.d.ts +3 -3
- package/dist/spectral/helpers.js +65 -140
- package/dist/state.svelte.js +5 -18
- package/dist/structure/Arrow.svelte +5 -18
- package/dist/structure/ArrowInstances.svelte +160 -0
- package/dist/structure/ArrowInstances.svelte.d.ts +16 -0
- package/dist/structure/AtomLegend.svelte +120 -85
- package/dist/structure/AtomLegend.svelte.d.ts +2 -3
- package/dist/structure/Bond.svelte +31 -23
- package/dist/structure/CanvasTooltip.svelte +15 -3
- package/dist/structure/CellSelect.svelte +45 -35
- 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 +636 -504
- package/dist/structure/Structure.svelte.d.ts +4 -2
- package/dist/structure/StructureCarousel.svelte +637 -0
- package/dist/structure/StructureCarousel.svelte.d.ts +19 -0
- package/dist/structure/StructureControls.svelte +165 -425
- package/dist/structure/StructureControls.svelte.d.ts +1 -1
- package/dist/structure/StructureExportPane.svelte +17 -21
- package/dist/structure/StructureInfoPane.svelte +128 -133
- package/dist/structure/StructureInfoPane.svelte.d.ts +1 -1
- package/dist/structure/StructureScene.svelte +535 -578
- package/dist/structure/StructureScene.svelte.d.ts +6 -2
- package/dist/structure/StructureViewport.svelte +451 -0
- package/dist/structure/StructureViewport.svelte.d.ts +65 -0
- package/dist/structure/atom-label-placement.d.ts +16 -12
- package/dist/structure/atom-label-placement.js +70 -37
- package/dist/structure/atom-properties.d.ts +2 -0
- package/dist/structure/atom-properties.js +105 -38
- package/dist/structure/bond-order-perception.js +3 -8
- package/dist/structure/bonding.d.ts +9 -3
- package/dist/structure/bonding.js +95 -46
- package/dist/structure/edit-history.d.ts +6 -0
- package/dist/structure/edit-history.js +27 -0
- package/dist/structure/export.d.ts +1 -0
- package/dist/structure/export.js +89 -105
- package/dist/structure/format-detect.d.ts +1 -0
- package/dist/structure/format-detect.js +20 -0
- package/dist/structure/geometry.d.ts +9 -0
- package/dist/structure/geometry.js +27 -0
- package/dist/structure/index.d.ts +16 -1
- package/dist/structure/index.js +15 -10
- package/dist/structure/measure.d.ts +1 -1
- package/dist/structure/measure.js +6 -12
- package/dist/structure/parse.d.ts +2 -1
- package/dist/structure/parse.js +272 -313
- package/dist/structure/partial-occupancy.js +10 -5
- package/dist/structure/pbc.js +85 -107
- package/dist/structure/polyhedra.d.ts +0 -1
- package/dist/structure/polyhedra.js +7 -21
- package/dist/structure/prop-groups.d.ts +85 -0
- package/dist/structure/prop-groups.js +18 -0
- package/dist/structure/supercell.d.ts +1 -2
- package/dist/structure/supercell.js +7 -13
- package/dist/symmetry/SymmetryElements.svelte +11 -15
- package/dist/symmetry/SymmetryStats.svelte +55 -71
- package/dist/symmetry/WyckoffTable.svelte +10 -28
- package/dist/symmetry/cell-transform.js +6 -14
- package/dist/symmetry/index.d.ts +1 -0
- package/dist/symmetry/index.js +13 -10
- package/dist/symmetry/spacegroups.js +3 -2
- package/dist/table/HeatmapTable.svelte +1142 -447
- package/dist/table/HeatmapTable.svelte.d.ts +12 -2
- package/dist/table/ToggleMenu.svelte +168 -53
- package/dist/table/ToggleMenu.svelte.d.ts +1 -1
- 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/embedded.d.ts +18 -0
- package/dist/theme/embedded.js +206 -0
- package/dist/theme/index.d.ts +5 -5
- package/dist/theme/index.js +5 -12
- package/dist/theme/themes.mjs +44 -66
- package/dist/tooltip/KCoords.svelte +4 -1
- package/dist/tooltip/TooltipContent.svelte +3 -6
- package/dist/tooltip/TooltipContent.svelte.d.ts +1 -1
- package/dist/tooltip/index.d.ts +8 -1
- package/dist/trajectory/Trajectory.svelte +613 -386
- package/dist/trajectory/Trajectory.svelte.d.ts +1 -1
- package/dist/trajectory/TrajectoryError.svelte +12 -74
- package/dist/trajectory/TrajectoryExportPane.svelte +14 -32
- package/dist/trajectory/TrajectoryInfoPane.svelte +127 -164
- package/dist/trajectory/TrajectoryInfoPane.svelte.d.ts +2 -1
- package/dist/trajectory/extract.js +61 -49
- package/dist/trajectory/format-detect.d.ts +2 -0
- package/dist/trajectory/format-detect.js +17 -13
- package/dist/trajectory/frame-reader.d.ts +2 -0
- package/dist/trajectory/frame-reader.js +35 -32
- package/dist/trajectory/helpers.d.ts +2 -0
- package/dist/trajectory/helpers.js +34 -56
- package/dist/trajectory/index.d.ts +1 -0
- package/dist/trajectory/index.js +5 -8
- package/dist/trajectory/parse/ase.js +1 -1
- 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 +6 -6
- package/dist/trajectory/parse/index.js +25 -33
- package/dist/trajectory/parse/lammps.js +8 -12
- package/dist/trajectory/parse/vasp.js +10 -7
- 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 +4 -0
- package/dist/trajectory/parse/vaspout-h5.js +281 -0
- package/dist/trajectory/parse/xyz.js +59 -9
- package/dist/trajectory/plotting.d.ts +8 -9
- package/dist/trajectory/plotting.js +113 -64
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +7 -0
- package/dist/xrd/XrdPlot.svelte +79 -118
- package/dist/xrd/broadening.js +2 -1
- package/dist/xrd/calc-xrd.js +24 -62
- package/dist/xrd/parse.d.ts +0 -1
- package/dist/xrd/parse.js +69 -95
- package/package.json +94 -34
- package/readme.md +6 -5
- package/dist/api/mp.d.ts +0 -6
- package/dist/api/mp.js +0 -22
- package/dist/plot/sunburst/SunburstControls.svelte +0 -200
- package/dist/scene/types.d.ts +0 -26
- package/dist/tooltip/types.d.ts +0 -8
- package/dist/trajectory/constants.d.ts +0 -6
- package/dist/trajectory/constants.js +0 -11
- /package/dist/{scene/types.js → file-viewer/host-protocol.js} +0 -0
- /package/dist/{tooltip/types.js → isosurface/geometry-worker-types.js} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
generics="Metadata extends Record<string, unknown> = Record<string, unknown>"
|
|
4
4
|
>
|
|
5
5
|
import type { D3InterpolateName } from '../../colors'
|
|
6
|
-
import { format_value } from '../../labels'
|
|
6
|
+
import { format_value, format_value_or_num } from '../../labels'
|
|
7
7
|
import { sanitize_html } from '../../sanitize'
|
|
8
8
|
import { FullscreenToggle, set_fullscreen_bg } from '../../layout'
|
|
9
9
|
import type { Point2D, Vec2 } from '../../math'
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
Line,
|
|
41
41
|
PlotAxis,
|
|
42
42
|
PlotLegend,
|
|
43
|
+
PlotMarginals,
|
|
43
44
|
PlotTooltip,
|
|
44
45
|
ReferenceLine,
|
|
45
46
|
ScatterPlotControls,
|
|
@@ -47,20 +48,34 @@
|
|
|
47
48
|
ZeroLines,
|
|
48
49
|
ZoomRect,
|
|
49
50
|
} from '..'
|
|
51
|
+
import type { MarginalSeriesInput, MarginalsProp } from '../core/marginals'
|
|
52
|
+
import {
|
|
53
|
+
add_sides,
|
|
54
|
+
marginal_axis,
|
|
55
|
+
marginal_axis_presence,
|
|
56
|
+
normalize_marginals,
|
|
57
|
+
reserve_marginal_pad,
|
|
58
|
+
} from '../core/marginals'
|
|
50
59
|
import {
|
|
51
60
|
build_obstacles_norm,
|
|
52
61
|
has_explicit_position,
|
|
53
62
|
measured_footprint,
|
|
54
63
|
place_decorations,
|
|
64
|
+
placed_coords,
|
|
55
65
|
} from '../core/auto-place'
|
|
56
|
-
import
|
|
57
|
-
|
|
66
|
+
import {
|
|
67
|
+
AXIS_DEFAULTS,
|
|
68
|
+
type AxisChangeState,
|
|
69
|
+
create_axis_loader,
|
|
70
|
+
} from '../core/axis-utils'
|
|
58
71
|
import { get_series_color, get_series_symbol } from '../core/data-transform'
|
|
59
72
|
import { create_placed_tween } from '../core/placed-tween.svelte'
|
|
60
73
|
import {
|
|
74
|
+
COLOR_BAR_DEFAULTS,
|
|
61
75
|
DEFAULT_MARKERS,
|
|
62
76
|
get_scale_type_name,
|
|
63
77
|
is_time_scale,
|
|
78
|
+
SCALE_DEFAULTS,
|
|
64
79
|
} from '../core/types'
|
|
65
80
|
import { compute_label_positions } from '../core/utils/label-placement'
|
|
66
81
|
import { create_legend_visibility } from '../core/utils/series-visibility'
|
|
@@ -88,11 +103,12 @@
|
|
|
88
103
|
import { create_pan_zoom } from '../core/pan-zoom.svelte'
|
|
89
104
|
import type { Rect, Sides } from '../core/layout'
|
|
90
105
|
import {
|
|
106
|
+
AXIS_TITLE_OFFSET,
|
|
91
107
|
calc_auto_padding,
|
|
92
108
|
filter_padding,
|
|
109
|
+
full_footprint_or,
|
|
93
110
|
LABEL_GAP_DEFAULT,
|
|
94
111
|
y2_axis_label_x,
|
|
95
|
-
measure_full_footprint,
|
|
96
112
|
measure_max_tick_width,
|
|
97
113
|
sample_series_obstacle_points,
|
|
98
114
|
} from '../core/layout'
|
|
@@ -106,11 +122,10 @@
|
|
|
106
122
|
get_nice_data_range,
|
|
107
123
|
} from '../core/scales'
|
|
108
124
|
import { resolve_line_tween, unique_id } from '../core/utils'
|
|
109
|
-
import {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} from './scatter-data'
|
|
125
|
+
import { build_legend_data, filter_series_to_ranges, pick_tooltip_bg } from './scatter-data'
|
|
126
|
+
|
|
127
|
+
// Plots with at least this many visible markers get smaller default point radii
|
|
128
|
+
const DENSE_MARKER_COUNT = 100
|
|
114
129
|
|
|
115
130
|
let {
|
|
116
131
|
series = $bindable([]),
|
|
@@ -122,7 +137,7 @@
|
|
|
122
137
|
styles: styles_init = {},
|
|
123
138
|
controls: controls_init = {},
|
|
124
139
|
padding = {},
|
|
125
|
-
range_padding = 0
|
|
140
|
+
range_padding = 0,
|
|
126
141
|
current_x_value = null,
|
|
127
142
|
tooltip_point = $bindable(null),
|
|
128
143
|
selected_point = null,
|
|
@@ -130,13 +145,9 @@
|
|
|
130
145
|
tooltip,
|
|
131
146
|
user_content,
|
|
132
147
|
change = () => {},
|
|
133
|
-
color_scale =
|
|
134
|
-
type: `linear`,
|
|
135
|
-
scheme: `interpolateViridis`,
|
|
136
|
-
value_range: undefined,
|
|
137
|
-
},
|
|
148
|
+
color_scale = SCALE_DEFAULTS.color,
|
|
138
149
|
color_bar = {},
|
|
139
|
-
size_scale =
|
|
150
|
+
size_scale = SCALE_DEFAULTS.size,
|
|
140
151
|
label_placement_config = {},
|
|
141
152
|
hover_config = {},
|
|
142
153
|
legend = {},
|
|
@@ -163,100 +174,95 @@
|
|
|
163
174
|
on_axis_change,
|
|
164
175
|
on_error,
|
|
165
176
|
pan = {},
|
|
177
|
+
marginals = false,
|
|
166
178
|
...rest
|
|
167
|
-
}: HTMLAttributes<HTMLDivElement> &
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
[
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
) => void
|
|
225
|
-
on_error?: (error: AxisLoadError) => void
|
|
226
|
-
pan?: PanConfig
|
|
227
|
-
} = $props()
|
|
179
|
+
}: HTMLAttributes<HTMLDivElement> &
|
|
180
|
+
Omit<BasePlotProps, `change`> &
|
|
181
|
+
PlotConfig & {
|
|
182
|
+
series?: DataSeries<Metadata>[]
|
|
183
|
+
styles?: StyleOverrides
|
|
184
|
+
controls?: ControlsConfig
|
|
185
|
+
current_x_value?: number | null
|
|
186
|
+
tooltip_point?: InternalPoint<Metadata> | null
|
|
187
|
+
selected_point?: { series_idx: number; point_idx: number } | null
|
|
188
|
+
tooltip?: Snippet<[ScatterHandlerProps<Metadata>]>
|
|
189
|
+
user_content?: Snippet<[UserContentProps]>
|
|
190
|
+
header_controls?: Snippet<[{ height: number; width: number; fullscreen: boolean }]>
|
|
191
|
+
controls_extra?: Snippet<
|
|
192
|
+
[{ styles: StyleOverrides; selected_series_idx: number } & Required<PlotConfig>]
|
|
193
|
+
>
|
|
194
|
+
change?: (data: (Point<Metadata> & { series: DataSeries<Metadata> }) | null) => void
|
|
195
|
+
color_scale?: ColorScaleConfig | D3InterpolateName
|
|
196
|
+
size_scale?: SizeScaleConfig
|
|
197
|
+
color_bar?:
|
|
198
|
+
| (ComponentProps<typeof ColorBar> & {
|
|
199
|
+
margin?: number | Sides
|
|
200
|
+
tween?: TweenOptions<Point2D>
|
|
201
|
+
responsive?: boolean // Allow colorbar to reposition if density changes (default: false)
|
|
202
|
+
axis_clearance?: number // Min distance kept from plot edges/axes (default: 15)
|
|
203
|
+
})
|
|
204
|
+
| null
|
|
205
|
+
label_placement_config?: Partial<LabelPlacementConfig>
|
|
206
|
+
hover_config?: Partial<HoverConfig>
|
|
207
|
+
legend?: LegendConfig | null
|
|
208
|
+
point_tween?: TweenOptions<Point2D>
|
|
209
|
+
line_tween?: TweenOptions<string>
|
|
210
|
+
point_events?: Record<
|
|
211
|
+
string,
|
|
212
|
+
(payload: { point: InternalPoint<Metadata>; event: Event }) => void
|
|
213
|
+
>
|
|
214
|
+
on_point_click?: (data: ScatterHandlerEvent<Metadata>) => void
|
|
215
|
+
on_point_hover?: (data: ScatterHandlerEvent<Metadata> | null) => void
|
|
216
|
+
fill_regions?: FillRegion[] // Bindable for legend toggle support
|
|
217
|
+
error_bands?: ErrorBand[]
|
|
218
|
+
on_fill_click?: (event: FillHandlerEvent) => void
|
|
219
|
+
on_fill_hover?: (event: FillHandlerEvent | null) => void
|
|
220
|
+
ref_lines?: RefLine[] // Bindable for legend toggle support
|
|
221
|
+
on_ref_line_click?: (event: RefLineEvent) => void
|
|
222
|
+
on_ref_line_hover?: (event: RefLineEvent | null) => void
|
|
223
|
+
selected_series_idx?: number
|
|
224
|
+
wrapper?: HTMLDivElement
|
|
225
|
+
// Interactive axis props
|
|
226
|
+
data_loader?: DataLoaderFn<Metadata>
|
|
227
|
+
on_axis_change?: (
|
|
228
|
+
axis: `x` | `x2` | `y` | `y2`,
|
|
229
|
+
key: string,
|
|
230
|
+
new_series: DataSeries<Metadata>[],
|
|
231
|
+
) => void
|
|
232
|
+
on_error?: (error: AxisLoadError) => void
|
|
233
|
+
pan?: PanConfig
|
|
234
|
+
marginals?: MarginalsProp
|
|
235
|
+
} = $props()
|
|
228
236
|
|
|
229
237
|
// Merged axis/display values with defaults (use $derived to avoid breaking $bindable)
|
|
230
238
|
const final_x_axis = $derived({
|
|
231
239
|
...AXIS_DEFAULTS,
|
|
232
|
-
label_shift: { x: 0, y:
|
|
240
|
+
label_shift: { x: 0, y: 0 },
|
|
233
241
|
...x_axis,
|
|
234
242
|
})
|
|
235
243
|
const final_y_axis = $derived({ ...AXIS_DEFAULTS, ...y_axis })
|
|
236
244
|
const final_x2_axis = $derived({
|
|
237
245
|
...AXIS_DEFAULTS,
|
|
238
|
-
label_shift: { x: 0, y:
|
|
246
|
+
label_shift: { x: 0, y: AXIS_TITLE_OFFSET }, // x2-axis label above top edge
|
|
239
247
|
...x2_axis,
|
|
240
248
|
})
|
|
241
249
|
const final_y2_axis = $derived({ ...AXIS_DEFAULTS, ...y2_axis })
|
|
242
250
|
// Cache time-axis check — used in ~10 places for scale/tick/tooltip logic
|
|
243
|
-
let is_time_x = $derived(
|
|
244
|
-
|
|
245
|
-
)
|
|
246
|
-
let is_time_x2 = $derived(
|
|
247
|
-
is_time_scale(final_x2_axis.scale_type, final_x2_axis.format),
|
|
248
|
-
)
|
|
251
|
+
let is_time_x = $derived(is_time_scale(final_x_axis.scale_type, final_x_axis.format))
|
|
252
|
+
let is_time_x2 = $derived(is_time_scale(final_x2_axis.scale_type, final_x2_axis.format))
|
|
249
253
|
const final_display = $derived({ ...DEFAULTS.scatter.display, ...display })
|
|
250
254
|
// Local state for styles (initialized from prop, owned by this component for controls)
|
|
251
255
|
// Using $state because styles has bindings in ScatterPlotControls
|
|
252
256
|
// untrack() explicitly captures initial prop value (intentional - props provide initial config)
|
|
253
|
-
let styles = $state(
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
257
|
+
let styles = $state(
|
|
258
|
+
untrack(() => ({
|
|
259
|
+
show_points: DEFAULTS.scatter.show_points,
|
|
260
|
+
show_lines: DEFAULTS.scatter.show_lines,
|
|
261
|
+
point: { ...DEFAULTS.scatter.point, ...styles_init?.point },
|
|
262
|
+
line: { ...DEFAULTS.scatter.line, ...styles_init?.line },
|
|
263
|
+
...styles_init,
|
|
264
|
+
})),
|
|
265
|
+
)
|
|
260
266
|
let controls = $derived({ show: true, open: false, ...controls_init })
|
|
261
267
|
|
|
262
268
|
let [width, height] = $state([0, 0])
|
|
@@ -287,7 +293,10 @@
|
|
|
287
293
|
initial: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
|
|
288
294
|
current: { x: [0, 1], x2: [0, 1], y: [0, 1], y2: [0, 1] },
|
|
289
295
|
})
|
|
290
|
-
const legend_vis = create_legend_visibility(
|
|
296
|
+
const legend_vis = create_legend_visibility(
|
|
297
|
+
() => series,
|
|
298
|
+
(next) => (series = next),
|
|
299
|
+
)
|
|
291
300
|
|
|
292
301
|
// Y2 axis sync configuration
|
|
293
302
|
let y2_sync_config = $derived(normalize_y2_sync(y2_axis?.sync))
|
|
@@ -350,8 +359,13 @@
|
|
|
350
359
|
|
|
351
360
|
for (const srs of series_with_ids) {
|
|
352
361
|
if (!srs) continue
|
|
353
|
-
const {
|
|
354
|
-
|
|
362
|
+
const {
|
|
363
|
+
x: xs,
|
|
364
|
+
y: ys,
|
|
365
|
+
visible = true,
|
|
366
|
+
y_axis: series_y_axis = `y1`,
|
|
367
|
+
x_axis: x_ax = `x1`,
|
|
368
|
+
} = srs as DataSeries
|
|
355
369
|
for (let idx = 0; idx < xs.length; idx++) {
|
|
356
370
|
const point = { x: xs[idx], y: ys[idx] }
|
|
357
371
|
all.push(point)
|
|
@@ -376,37 +390,53 @@
|
|
|
376
390
|
|
|
377
391
|
// Update padding when format or ticks change
|
|
378
392
|
$effect(() => {
|
|
379
|
-
const new_pad =
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
393
|
+
const new_pad =
|
|
394
|
+
width &&
|
|
395
|
+
height &&
|
|
396
|
+
(y_tick_values.length > 0 || y2_tick_values.length > 0 || x2_tick_values.length > 0)
|
|
397
|
+
? calc_auto_padding({
|
|
398
|
+
padding,
|
|
399
|
+
default_padding,
|
|
400
|
+
x2_axis: { ...final_x2_axis, tick_values: x2_tick_values },
|
|
401
|
+
y_axis: { ...final_y_axis, tick_values: y_tick_values },
|
|
402
|
+
y2_axis: { ...final_y2_axis, tick_values: y2_tick_values },
|
|
403
|
+
})
|
|
404
|
+
: filter_padding(padding, default_padding)
|
|
389
405
|
|
|
390
406
|
if (
|
|
391
407
|
base_pad.t !== new_pad.t ||
|
|
392
408
|
base_pad.b !== new_pad.b ||
|
|
393
409
|
base_pad.l !== new_pad.l ||
|
|
394
410
|
base_pad.r !== new_pad.r
|
|
395
|
-
)
|
|
411
|
+
)
|
|
412
|
+
base_pad = new_pad
|
|
396
413
|
})
|
|
397
414
|
|
|
398
415
|
// === Auto-move legend/colorbar outside the plot when interior overlap is unavoidable ===
|
|
399
416
|
// (shared logic lives in auto-place.ts so every 2D plot reuses it)
|
|
400
417
|
// ColorBar's orientation prop defaults to horizontal, so treat unset as horizontal too
|
|
401
|
-
const colorbar_is_horizontal = $derived(
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
418
|
+
const colorbar_is_horizontal = $derived(
|
|
419
|
+
(color_bar?.orientation ?? `horizontal`) === `horizontal`,
|
|
420
|
+
)
|
|
421
|
+
// Fallback estimate (with room for tick labels) used before the colorbar first
|
|
422
|
+
// renders; compute_element_placement measures the real footprint once it's laid out
|
|
423
|
+
const colorbar_fallback_size = $derived(
|
|
424
|
+
colorbar_is_horizontal
|
|
425
|
+
? COLOR_BAR_DEFAULTS.horizontal_footprint
|
|
426
|
+
: COLOR_BAR_DEFAULTS.vertical_footprint,
|
|
408
427
|
)
|
|
409
|
-
|
|
428
|
+
// full footprint (not the offset box): colorbar tick labels are absolutely
|
|
429
|
+
// positioned outside the bar and must count toward reserved margins
|
|
430
|
+
let colorbar_size_revision = $state(0)
|
|
431
|
+
let legend_size_revision = $state(0)
|
|
432
|
+
const colorbar_footprint = $derived.by(() => {
|
|
433
|
+
void colorbar_size_revision
|
|
434
|
+
return full_footprint_or(colorbar_element, colorbar_fallback_size)
|
|
435
|
+
})
|
|
436
|
+
const legend_footprint = $derived.by(() => {
|
|
437
|
+
void legend_size_revision
|
|
438
|
+
return measured_footprint(legend_element, { width: 120, height: 80 })
|
|
439
|
+
})
|
|
410
440
|
const legend_has_explicit_pos = $derived(has_explicit_position(legend?.style))
|
|
411
441
|
|
|
412
442
|
// Plot-specific obstacle field: series points/lines normalized to [0,1] (y=0 at top)
|
|
@@ -416,7 +446,9 @@
|
|
|
416
446
|
const base_h = height - base_pad.t - base_pad.b
|
|
417
447
|
if (base_w <= 0 || base_h <= 0) return []
|
|
418
448
|
const norm_x = is_time_x
|
|
419
|
-
? scaleTime()
|
|
449
|
+
? scaleTime()
|
|
450
|
+
.domain([new Date(x_min), new Date(x_max)])
|
|
451
|
+
.range([0, 1])
|
|
420
452
|
: create_scale(final_x_axis.scale_type ?? `linear`, [x_min, x_max], [0, 1])
|
|
421
453
|
const norm_y = create_scale(final_y_axis.scale_type ?? `linear`, [y_min, y_max], [0, 1])
|
|
422
454
|
return build_obstacles_norm(
|
|
@@ -442,23 +474,58 @@
|
|
|
442
474
|
obstacles_norm,
|
|
443
475
|
// gate on legend_element (the actual render signal) not legend_data, whose fill entries read
|
|
444
476
|
// computed_fills -> pad and would make this derived reference itself
|
|
445
|
-
legend:
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
477
|
+
legend:
|
|
478
|
+
legend != null &&
|
|
479
|
+
legend_element != null &&
|
|
480
|
+
!legend_has_explicit_pos &&
|
|
481
|
+
!legend_is_dragging &&
|
|
482
|
+
!legend_manual_position
|
|
483
|
+
? { footprint: legend_footprint, clearance: legend?.axis_clearance }
|
|
484
|
+
: null,
|
|
449
485
|
// gate on a measured colorbar: its outside style stretches it to full width, so deciding from
|
|
450
486
|
// the (wide) pre-measure fallback would flip-flop placement between interior and outside
|
|
451
|
-
colorbar:
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
487
|
+
colorbar:
|
|
488
|
+
Boolean(color_bar) &&
|
|
489
|
+
all_color_values.length > 0 &&
|
|
490
|
+
!color_bar?.wrapper_style &&
|
|
491
|
+
(colorbar_element?.offsetWidth ?? 0) > 0 &&
|
|
492
|
+
(colorbar_element?.offsetHeight ?? 0) > 0
|
|
493
|
+
? {
|
|
494
|
+
footprint: colorbar_footprint,
|
|
495
|
+
horizontal: colorbar_is_horizontal,
|
|
496
|
+
clearance: color_bar?.axis_clearance,
|
|
497
|
+
}
|
|
498
|
+
: null,
|
|
499
|
+
}),
|
|
500
|
+
)
|
|
501
|
+
// Resolve marginals and reserve outer-band padding so the plot shrinks to make room
|
|
502
|
+
const resolved_marginals = $derived(
|
|
503
|
+
normalize_marginals(marginals, { top: true, right: true }),
|
|
504
|
+
)
|
|
505
|
+
const pad = $derived(add_sides(decor.pad, reserve_marginal_pad(resolved_marginals)))
|
|
506
|
+
// Map series to the generic marginal input, reusing the line/legend color fallback
|
|
507
|
+
const marginal_series = $derived<MarginalSeriesInput[]>(
|
|
508
|
+
series_with_ids.map((srs, idx) => {
|
|
509
|
+
const point_fill = Array.isArray(srs?.point_style)
|
|
510
|
+
? srs.point_style[0]?.fill
|
|
511
|
+
: srs?.point_style?.fill
|
|
512
|
+
return {
|
|
513
|
+
x: srs?.x ?? [],
|
|
514
|
+
y: srs?.y ?? [],
|
|
515
|
+
color:
|
|
516
|
+
srs?.line_style?.stroke ??
|
|
517
|
+
point_fill ??
|
|
518
|
+
get_series_color(srs?.orig_series_idx ?? idx),
|
|
519
|
+
label: srs?.label,
|
|
520
|
+
visible: srs?.visible ?? true,
|
|
521
|
+
x_axis: srs?.x_axis,
|
|
522
|
+
y_axis: srs?.y_axis,
|
|
523
|
+
}
|
|
524
|
+
}),
|
|
525
|
+
)
|
|
526
|
+
const marginal_has_axis = $derived(
|
|
527
|
+
marginal_axis_presence(x2_points.length > 0, y2_points.length > 0),
|
|
460
528
|
)
|
|
461
|
-
const pad = $derived(decor.pad)
|
|
462
529
|
const legend_auto_outside = $derived(decor.legend_outside)
|
|
463
530
|
const legend_outside_x = $derived(decor.legend_pos.x)
|
|
464
531
|
const legend_outside_y = $derived(decor.legend_pos.y)
|
|
@@ -471,9 +538,7 @@
|
|
|
471
538
|
x: pad.l || 0,
|
|
472
539
|
y: pad.t || 0,
|
|
473
540
|
width: isFinite(width - pad.l - pad.r) ? Math.max(1, width - pad.l - pad.r) : 1,
|
|
474
|
-
height: isFinite(height - pad.t - pad.b)
|
|
475
|
-
? Math.max(1, height - pad.t - pad.b)
|
|
476
|
-
: 1,
|
|
541
|
+
height: isFinite(height - pad.t - pad.b) ? Math.max(1, height - pad.t - pad.b) : 1,
|
|
477
542
|
})
|
|
478
543
|
|
|
479
544
|
// Calculate plot area center coordinates
|
|
@@ -487,8 +552,12 @@
|
|
|
487
552
|
for (const srs of series_with_ids) {
|
|
488
553
|
if (!srs) continue
|
|
489
554
|
const { color_values: cvs, size_values: svs } = srs as DataSeries
|
|
490
|
-
if (cvs) {
|
|
491
|
-
|
|
555
|
+
if (cvs) {
|
|
556
|
+
for (const val of cvs) if (val != null) color_values.push(val)
|
|
557
|
+
}
|
|
558
|
+
if (svs) {
|
|
559
|
+
for (const val of svs) if (val != null) size_values.push(val)
|
|
560
|
+
}
|
|
492
561
|
}
|
|
493
562
|
return { color_values, size_values }
|
|
494
563
|
})
|
|
@@ -567,7 +636,10 @@
|
|
|
567
636
|
if (explicit) {
|
|
568
637
|
ranges.current[axis] = range
|
|
569
638
|
} else {
|
|
570
|
-
const result = expand_range_if_needed(
|
|
639
|
+
const result = expand_range_if_needed(
|
|
640
|
+
untrack(() => ranges.initial[axis]),
|
|
641
|
+
range,
|
|
642
|
+
)
|
|
571
643
|
if (result.changed) {
|
|
572
644
|
ranges.initial[axis] = result.range
|
|
573
645
|
ranges.current[axis] = result.range
|
|
@@ -579,7 +651,10 @@
|
|
|
579
651
|
if (resolved.y2.explicit) {
|
|
580
652
|
ranges.current.y2 = resolved.y2.range
|
|
581
653
|
} else {
|
|
582
|
-
const result = expand_range_if_needed(
|
|
654
|
+
const result = expand_range_if_needed(
|
|
655
|
+
untrack(() => ranges.initial.y2),
|
|
656
|
+
resolved.y2.range,
|
|
657
|
+
)
|
|
583
658
|
if (result.changed) ranges.initial.y2 = result.range
|
|
584
659
|
// Apply sync if enabled, otherwise use expanded range (or keep current if unchanged)
|
|
585
660
|
if (y2_sync_config.mode !== `none`) {
|
|
@@ -605,10 +680,10 @@
|
|
|
605
680
|
// Ensure we only calculate extent on actual numbers, filtering out nulls/undefined
|
|
606
681
|
all_color_values.length > 0
|
|
607
682
|
? extent(
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
683
|
+
all_color_values.filter(
|
|
684
|
+
(color_val: number | null): color_val is number => typeof color_val === `number`,
|
|
685
|
+
),
|
|
686
|
+
)
|
|
612
687
|
: [0, 1],
|
|
613
688
|
) as Vec2
|
|
614
689
|
|
|
@@ -617,37 +692,37 @@
|
|
|
617
692
|
let x_scale_fn = $derived(
|
|
618
693
|
is_time_x
|
|
619
694
|
? scaleTime()
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
: create_scale(
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
695
|
+
.domain([new Date(x_min), new Date(x_max)])
|
|
696
|
+
.range([pad.l, width - pad.r])
|
|
697
|
+
: create_scale(
|
|
698
|
+
final_x_axis.scale_type ?? `linear`,
|
|
699
|
+
[x_min, x_max],
|
|
700
|
+
[pad.l, width - pad.r],
|
|
701
|
+
),
|
|
626
702
|
)
|
|
627
703
|
|
|
628
704
|
let x2_scale_fn = $derived(
|
|
629
705
|
is_time_x2
|
|
630
706
|
? scaleTime()
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
: create_scale(
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
707
|
+
.domain([new Date(x2_min), new Date(x2_max)])
|
|
708
|
+
.range([pad.l, width - pad.r])
|
|
709
|
+
: create_scale(
|
|
710
|
+
final_x2_axis.scale_type ?? `linear`,
|
|
711
|
+
[x2_min, x2_max],
|
|
712
|
+
[pad.l, width - pad.r],
|
|
713
|
+
),
|
|
637
714
|
)
|
|
638
715
|
|
|
639
716
|
let y_scale_fn = $derived(
|
|
640
|
-
create_scale(final_y_axis.scale_type ?? `linear`, [y_min, y_max], [
|
|
641
|
-
height - pad.b,
|
|
642
|
-
pad.t,
|
|
643
|
-
]),
|
|
717
|
+
create_scale(final_y_axis.scale_type ?? `linear`, [y_min, y_max], [height - pad.b, pad.t]),
|
|
644
718
|
)
|
|
645
719
|
|
|
646
720
|
let y2_scale_fn = $derived(
|
|
647
|
-
create_scale(
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
721
|
+
create_scale(
|
|
722
|
+
final_y2_axis.scale_type ?? `linear`,
|
|
723
|
+
[y2_min, y2_max],
|
|
724
|
+
[height - pad.b, pad.t],
|
|
725
|
+
),
|
|
651
726
|
)
|
|
652
727
|
|
|
653
728
|
// All size values from series (for size scale) - extracted in series_value_arrays
|
|
@@ -684,6 +759,22 @@
|
|
|
684
759
|
})
|
|
685
760
|
let effective_line_tween = $derived(resolve_line_tween(line_tween, line_tween_load))
|
|
686
761
|
|
|
762
|
+
let visible_marker_count = $derived.by(() => {
|
|
763
|
+
if (!styles.show_points) return 0
|
|
764
|
+
let count = 0
|
|
765
|
+
for (const series_data of filtered_series ?? []) {
|
|
766
|
+
if ((series_data.markers ?? DEFAULT_MARKERS).includes(`points`)) {
|
|
767
|
+
count += series_data.filtered_data.length
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
return count
|
|
771
|
+
})
|
|
772
|
+
|
|
773
|
+
const default_point_radius = (markers: string): number => {
|
|
774
|
+
const [sparse_radius, dense_radius] = markers.includes(`line`) ? [2.5, 2] : [3, 2.5]
|
|
775
|
+
return visible_marker_count >= DENSE_MARKER_COUNT ? dense_radius : sparse_radius
|
|
776
|
+
}
|
|
777
|
+
|
|
687
778
|
// Obstacle field for legend/colorbar auto-placement. Sampling only data points lets the
|
|
688
779
|
// legend land on top of a steep connecting line whose markers are sparse (e.g. y=x^2), so
|
|
689
780
|
// sample_series_obstacle_points also walks each drawn segment at a fixed pixel cadence.
|
|
@@ -699,14 +790,16 @@
|
|
|
699
790
|
const active_x_scale = use_x2_scale ? x2_scale_fn : x_scale_fn
|
|
700
791
|
const active_is_time_x = use_x2_scale ? is_time_x2 : is_time_x
|
|
701
792
|
const active_y_scale = series_data.y_axis === `y2` ? y2_scale_fn : y_scale_fn
|
|
702
|
-
const draws_line =
|
|
703
|
-
(series_data.markers ?? DEFAULT_MARKERS).includes(`line`)
|
|
793
|
+
const draws_line =
|
|
794
|
+
styles.show_lines && (series_data.markers ?? DEFAULT_MARKERS).includes(`line`)
|
|
704
795
|
|
|
705
796
|
const pixel_points = series_data.filtered_data.map((point) => ({
|
|
706
797
|
x: active_is_time_x ? active_x_scale(new Date(point.x)) : active_x_scale(point.x),
|
|
707
798
|
y: active_y_scale(point.y),
|
|
708
799
|
}))
|
|
709
|
-
points.push(
|
|
800
|
+
points.push(
|
|
801
|
+
...sample_series_obstacle_points(pixel_points, draws_line, SEGMENT_SAMPLE_STEP),
|
|
802
|
+
)
|
|
710
803
|
}
|
|
711
804
|
return points
|
|
712
805
|
})
|
|
@@ -791,14 +884,16 @@
|
|
|
791
884
|
}
|
|
792
885
|
|
|
793
886
|
return all_regions
|
|
794
|
-
.filter(
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
887
|
+
.filter(
|
|
888
|
+
(
|
|
889
|
+
entry,
|
|
890
|
+
): entry is {
|
|
891
|
+
region: FillRegion
|
|
892
|
+
source_type: `fill_region` | `error_band`
|
|
893
|
+
source_idx: number
|
|
894
|
+
hover_key: string
|
|
895
|
+
} => entry.region !== null,
|
|
896
|
+
)
|
|
802
897
|
.map(({ region, source_type, source_idx, hover_key }, idx) => {
|
|
803
898
|
// Hidden fills keep their entry (with empty path_segments -> nothing renders) so the
|
|
804
899
|
// legend item persists greyed-out and can be toggled back on.
|
|
@@ -806,15 +901,15 @@
|
|
|
806
901
|
const path_segments = hidden
|
|
807
902
|
? []
|
|
808
903
|
: compute_fill_segments(region, series_with_ids, domains)
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
904
|
+
.map((seg) =>
|
|
905
|
+
generate_fill_path(
|
|
906
|
+
seg.upper.map(to_px),
|
|
907
|
+
seg.lower.map(to_px),
|
|
908
|
+
seg.upper_curve,
|
|
909
|
+
seg.lower_curve,
|
|
910
|
+
),
|
|
815
911
|
)
|
|
816
|
-
|
|
817
|
-
.filter((path) => path.length > 0)
|
|
912
|
+
.filter((path) => path.length > 0)
|
|
818
913
|
|
|
819
914
|
// Drop only visible fills with no geometry; keep hidden ones for the legend
|
|
820
915
|
if (!hidden && path_segments.length === 0) return null
|
|
@@ -848,13 +943,12 @@
|
|
|
848
943
|
})
|
|
849
944
|
|
|
850
945
|
// Compute ref_lines with index and group by z-index (using shared utilities)
|
|
851
|
-
let
|
|
852
|
-
let ref_lines_by_z = $derived(group_ref_lines_by_z(indexed_ref_lines))
|
|
946
|
+
let ref_lines_by_z = $derived(group_ref_lines_by_z(index_ref_lines(ref_lines)))
|
|
853
947
|
|
|
854
948
|
// Calculate best legend placement using continuous grid sampling
|
|
855
|
-
|
|
856
|
-
const should_place =
|
|
857
|
-
(legend_data.length > 1 || Object.keys(legend ?? {}).length > 0)
|
|
949
|
+
const get_legend_placement = () => {
|
|
950
|
+
const should_place =
|
|
951
|
+
legend != null && (legend_data.length > 1 || Object.keys(legend ?? {}).length > 0)
|
|
858
952
|
|
|
859
953
|
if (!should_place || !width || !height) return null
|
|
860
954
|
|
|
@@ -871,24 +965,27 @@
|
|
|
871
965
|
}
|
|
872
966
|
|
|
873
967
|
return compute_element_placement(placement_config)
|
|
874
|
-
}
|
|
968
|
+
}
|
|
875
969
|
|
|
876
970
|
// Calculate color bar placement (coordinates with legend to avoid overlap)
|
|
877
|
-
|
|
971
|
+
const get_color_bar_placement = () => {
|
|
878
972
|
if (!color_bar || all_color_values.length === 0 || !width || !height) return null
|
|
879
973
|
|
|
880
974
|
const plot_width = width - pad.l - pad.r
|
|
881
975
|
const plot_height = height - pad.t - pad.b
|
|
882
976
|
|
|
883
|
-
// Fallback estimate (with room for tick labels) used before the colorbar first
|
|
884
|
-
// renders; compute_element_placement measures the real footprint once it's laid out
|
|
885
|
-
const is_horizontal = (color_bar.orientation ?? `horizontal`) === `horizontal`
|
|
886
|
-
const colorbar_size = is_horizontal
|
|
887
|
-
? { width: 220, height: 56 }
|
|
888
|
-
: { width: 56, height: 100 }
|
|
889
|
-
|
|
890
977
|
// Build exclusion rects (avoid legend if it's placed)
|
|
891
978
|
const exclude_rects: Rect[] = []
|
|
979
|
+
const legend_placement =
|
|
980
|
+
legend_is_dragging && legend_manual_position
|
|
981
|
+
? legend_manual_position
|
|
982
|
+
: legend_has_explicit_pos && legend_element
|
|
983
|
+
? { x: legend_element.offsetLeft, y: legend_element.offsetTop }
|
|
984
|
+
: legend_auto_outside
|
|
985
|
+
? { x: legend_outside_x, y: legend_outside_y }
|
|
986
|
+
: legend_tween.placed()
|
|
987
|
+
? legend_tween.coords.target
|
|
988
|
+
: get_legend_placement()
|
|
892
989
|
if (legend_element && legend_placement) {
|
|
893
990
|
exclude_rects.push({
|
|
894
991
|
x: legend_placement.x,
|
|
@@ -901,48 +998,44 @@
|
|
|
901
998
|
return compute_element_placement({
|
|
902
999
|
plot_bounds: { x: pad.l, y: pad.t, width: plot_width, height: plot_height },
|
|
903
1000
|
element: colorbar_element,
|
|
904
|
-
element_size:
|
|
1001
|
+
element_size: colorbar_fallback_size,
|
|
905
1002
|
// Small gap from the corner; the full-footprint measurement reserves the tick
|
|
906
1003
|
// labels, so this alone keeps the colorbar off the axes
|
|
907
1004
|
axis_clearance: color_bar?.axis_clearance ?? 15,
|
|
908
1005
|
exclude_rects,
|
|
909
1006
|
points: plot_points_for_placement,
|
|
910
1007
|
})
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
// Active legend placement (null if user set explicit position)
|
|
914
|
-
let active_legend_placement = $derived.by(() => {
|
|
915
|
-
if (!legend_placement) return null
|
|
1008
|
+
}
|
|
916
1009
|
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
/(^|[;{]\s*)(top|bottom|left|right)\s*:|position\s*:\s*absolute/.test(
|
|
921
|
-
legend_style,
|
|
922
|
-
)
|
|
923
|
-
) return null
|
|
924
|
-
|
|
925
|
-
return legend_placement
|
|
926
|
-
})
|
|
1010
|
+
// Active legend placement (null if user set explicit position in style)
|
|
1011
|
+
const get_active_legend_placement = () =>
|
|
1012
|
+
legend_has_explicit_pos ? null : get_legend_placement()
|
|
927
1013
|
|
|
928
1014
|
// Tweened colorbar/legend coordinates with shared placement stability gating
|
|
929
|
-
const colorbar_tween = create_placed_tween({
|
|
930
|
-
placement: () => color_bar_placement,
|
|
931
|
-
dims: () => ({ width, height }),
|
|
932
|
-
responsive: () => color_bar?.responsive ?? false,
|
|
933
|
-
element: () => colorbar_element,
|
|
934
|
-
tween: () => color_bar?.tween,
|
|
935
|
-
})
|
|
936
1015
|
const legend_tween = create_placed_tween({
|
|
937
|
-
placement:
|
|
1016
|
+
placement: get_active_legend_placement,
|
|
938
1017
|
dims: () => ({ width, height }),
|
|
939
1018
|
responsive: () => legend?.responsive ?? false,
|
|
940
1019
|
element: () => legend_element,
|
|
941
1020
|
tween: () => legend?.tween,
|
|
1021
|
+
on_element_resize: () => (legend_size_revision += 1),
|
|
1022
|
+
placement_revision: () => colorbar_size_revision,
|
|
942
1023
|
// Leave coords alone mid-drag; once dragged, the manual position wins permanently
|
|
943
1024
|
suspended: () => legend_is_dragging,
|
|
944
1025
|
manual_position: () => legend_manual_position,
|
|
945
1026
|
})
|
|
1027
|
+
const colorbar_tween = create_placed_tween({
|
|
1028
|
+
placement: get_color_bar_placement,
|
|
1029
|
+
dims: () => ({ width, height }),
|
|
1030
|
+
responsive: () => color_bar?.responsive ?? false,
|
|
1031
|
+
element: () => colorbar_element,
|
|
1032
|
+
tween: () => color_bar?.tween,
|
|
1033
|
+
on_element_resize: () => (colorbar_size_revision += 1),
|
|
1034
|
+
placement_revision: () =>
|
|
1035
|
+
`${legend_size_revision}:${legend_tween.coords.target.x}:${legend_tween.coords.target.y}:${
|
|
1036
|
+
legend_auto_outside ? `${legend_outside_x}:${legend_outside_y}` : `inside`
|
|
1037
|
+
}:${legend?.style ?? ``}`,
|
|
1038
|
+
})
|
|
946
1039
|
|
|
947
1040
|
// Generate axis ticks - consolidated into single derived for efficiency
|
|
948
1041
|
let axis_ticks = $derived.by(() => {
|
|
@@ -966,15 +1059,16 @@
|
|
|
966
1059
|
x_scale_for_ticks,
|
|
967
1060
|
{ format: final_x_axis.format },
|
|
968
1061
|
),
|
|
969
|
-
x2:
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1062
|
+
x2:
|
|
1063
|
+
x2_points.length > 0
|
|
1064
|
+
? generate_ticks(
|
|
1065
|
+
[x2_min, x2_max],
|
|
1066
|
+
final_x2_axis.scale_type ?? `linear`,
|
|
1067
|
+
final_x2_axis.ticks,
|
|
1068
|
+
x2_scale_for_ticks,
|
|
1069
|
+
{ format: final_x2_axis.format },
|
|
1070
|
+
)
|
|
1071
|
+
: [],
|
|
978
1072
|
y: generate_ticks(
|
|
979
1073
|
[y_min, y_max],
|
|
980
1074
|
final_y_axis.scale_type ?? `linear`,
|
|
@@ -982,15 +1076,16 @@
|
|
|
982
1076
|
y_scale_fn,
|
|
983
1077
|
{ default_count: 5 },
|
|
984
1078
|
),
|
|
985
|
-
y2:
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1079
|
+
y2:
|
|
1080
|
+
y2_points.length > 0
|
|
1081
|
+
? generate_ticks(
|
|
1082
|
+
[y2_min, y2_max],
|
|
1083
|
+
final_y2_axis.scale_type ?? `linear`,
|
|
1084
|
+
final_y2_axis.ticks,
|
|
1085
|
+
y2_scale_fn,
|
|
1086
|
+
{ default_count: 5 },
|
|
1087
|
+
)
|
|
1088
|
+
: [],
|
|
994
1089
|
}
|
|
995
1090
|
})
|
|
996
1091
|
|
|
@@ -1016,7 +1111,9 @@
|
|
|
1016
1111
|
({ x: final_x_axis, x2: final_x2_axis, y: final_y_axis, y2: final_y2_axis })[axis]
|
|
1017
1112
|
.scale_type,
|
|
1018
1113
|
// Clamp to at least 1 to avoid Infinity deltas when padding equals container size
|
|
1019
|
-
|
|
1114
|
+
plot_bounds: () => ({
|
|
1115
|
+
x: pad.l,
|
|
1116
|
+
y: pad.t,
|
|
1020
1117
|
width: Math.max(1, width - pad.l - pad.r),
|
|
1021
1118
|
height: Math.max(1, height - pad.t - pad.b),
|
|
1022
1119
|
}),
|
|
@@ -1036,16 +1133,16 @@
|
|
|
1036
1133
|
y_axis = { ...y_axis, range: next_y }
|
|
1037
1134
|
|
|
1038
1135
|
// X2 axis: invert screen coords using x2 scale
|
|
1039
|
-
const next_x2 =
|
|
1040
|
-
? invert_rect_range(x2_scale_fn, start.x, current.x)
|
|
1041
|
-
: null
|
|
1136
|
+
const next_x2 =
|
|
1137
|
+
x2_points.length > 0 ? invert_rect_range(x2_scale_fn, start.x, current.x) : null
|
|
1042
1138
|
if (next_x2) x2_axis = { ...x2_axis, range: next_x2 }
|
|
1043
1139
|
|
|
1044
1140
|
// Y2 axis: when sync is enabled the y_axis effect derives y2; with sync 'none'
|
|
1045
1141
|
// y2 must zoom from the rect directly (parity with BarPlot/Histogram/BoxPlot)
|
|
1046
|
-
const next_y2 =
|
|
1047
|
-
|
|
1048
|
-
|
|
1142
|
+
const next_y2 =
|
|
1143
|
+
y2_points.length > 0 && y2_sync_config.mode === `none`
|
|
1144
|
+
? invert_rect_range(y2_scale_fn, start.y, current.y)
|
|
1145
|
+
: null
|
|
1049
1146
|
if (next_y2) y2_axis = { ...y2_axis, range: next_y2 }
|
|
1050
1147
|
},
|
|
1051
1148
|
on_reset: () => {
|
|
@@ -1100,9 +1197,7 @@
|
|
|
1100
1197
|
const point_cx = tooltip_is_time_x
|
|
1101
1198
|
? tooltip_x_scale(new Date(point.x))
|
|
1102
1199
|
: tooltip_x_scale(point.x)
|
|
1103
|
-
const point_cy = (series_data.y_axis === `y2` ? y2_scale_fn : y_scale_fn)(
|
|
1104
|
-
point.y,
|
|
1105
|
-
)
|
|
1200
|
+
const point_cy = (series_data.y_axis === `y2` ? y2_scale_fn : y_scale_fn)(point.y)
|
|
1106
1201
|
|
|
1107
1202
|
// Calculate squared screen distance between mouse and point
|
|
1108
1203
|
const screen_dx = x_rel - point_cx
|
|
@@ -1119,11 +1214,7 @@
|
|
|
1119
1214
|
}
|
|
1120
1215
|
|
|
1121
1216
|
// Check if the closest point is within the hover threshold
|
|
1122
|
-
if (
|
|
1123
|
-
closest_point &&
|
|
1124
|
-
closest_series &&
|
|
1125
|
-
min_screen_dist_sq <= hover_threshold_px_sq
|
|
1126
|
-
) {
|
|
1217
|
+
if (closest_point && closest_series && min_screen_dist_sq <= hover_threshold_px_sq) {
|
|
1127
1218
|
// Construct handler props synchronously to avoid stale derived reads
|
|
1128
1219
|
const props = construct_handler_props(closest_point)
|
|
1129
1220
|
tooltip_point = closest_point
|
|
@@ -1198,8 +1289,8 @@
|
|
|
1198
1289
|
const new_y = event.clientY - svg_rect.top - legend_drag_offset.y
|
|
1199
1290
|
|
|
1200
1291
|
// Get actual legend dimensions for accurate bounds checking using the bound element reference
|
|
1201
|
-
const { width: legend_width, height: legend_height } =
|
|
1202
|
-
.getBoundingClientRect()
|
|
1292
|
+
const { width: legend_width, height: legend_height } =
|
|
1293
|
+
legend_element.getBoundingClientRect()
|
|
1203
1294
|
|
|
1204
1295
|
// Constrain to plot bounds using measured legend size
|
|
1205
1296
|
const constrained_x = Math.max(0, Math.min(width - legend_width, new_x))
|
|
@@ -1245,9 +1336,7 @@
|
|
|
1245
1336
|
const cx = handler_is_time_x ? handler_x_scale(new Date(x)) : handler_x_scale(x)
|
|
1246
1337
|
const cy = (hovered_series.y_axis === `y2` ? y2_scale_fn : y_scale_fn)(y)
|
|
1247
1338
|
const active_x_config = handler_use_x2 ? final_x2_axis : final_x_axis
|
|
1248
|
-
const active_y_config = hovered_series.y_axis === `y2`
|
|
1249
|
-
? final_y2_axis
|
|
1250
|
-
: final_y_axis
|
|
1339
|
+
const active_y_config = hovered_series.y_axis === `y2` ? final_y2_axis : final_y_axis
|
|
1251
1340
|
const coords = {
|
|
1252
1341
|
x,
|
|
1253
1342
|
y,
|
|
@@ -1264,8 +1353,8 @@
|
|
|
1264
1353
|
metadata,
|
|
1265
1354
|
label: hovered_series.label ?? null,
|
|
1266
1355
|
series_idx,
|
|
1267
|
-
x_formatted:
|
|
1268
|
-
y_formatted:
|
|
1356
|
+
x_formatted: format_value_or_num(x, active_x_config.format),
|
|
1357
|
+
y_formatted: format_value_or_num(y, active_y_config.format),
|
|
1269
1358
|
color_value: color_value ?? null,
|
|
1270
1359
|
colorbar: {
|
|
1271
1360
|
value: color_value ?? null,
|
|
@@ -1287,9 +1376,7 @@
|
|
|
1287
1376
|
// Precompute non-click event names from point_events so we don't rebuild
|
|
1288
1377
|
// the entries array on every point render.
|
|
1289
1378
|
let point_event_names = $derived(
|
|
1290
|
-
point_events
|
|
1291
|
-
? Object.keys(point_events).filter((name) => name !== `onclick`)
|
|
1292
|
-
: [],
|
|
1379
|
+
point_events ? Object.keys(point_events).filter((name) => name !== `onclick`) : [],
|
|
1293
1380
|
)
|
|
1294
1381
|
|
|
1295
1382
|
// Set theme-aware background when entering fullscreen
|
|
@@ -1298,41 +1385,30 @@
|
|
|
1298
1385
|
})
|
|
1299
1386
|
|
|
1300
1387
|
// State accessors for shared axis change handler
|
|
1388
|
+
// Spread into existing state in each setter to preserve merged type structure
|
|
1301
1389
|
const axis_state: AxisChangeState<DataSeries<Metadata>> = {
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1390
|
+
axes: {
|
|
1391
|
+
x: { get: () => x_axis, set: (config) => (x_axis = { ...x_axis, ...config }) },
|
|
1392
|
+
x2: { get: () => x2_axis, set: (config) => (x2_axis = { ...x2_axis, ...config }) },
|
|
1393
|
+
y: { get: () => y_axis, set: (config) => (y_axis = { ...y_axis, ...config }) },
|
|
1394
|
+
y2: { get: () => y2_axis, set: (config) => (y2_axis = { ...y2_axis, ...config }) },
|
|
1307
1395
|
},
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
if (axis === `x`) x_axis = { ...x_axis, ...config }
|
|
1311
|
-
else if (axis === `x2`) x2_axis = { ...x2_axis, ...config }
|
|
1312
|
-
else if (axis === `y`) y_axis = { ...y_axis, ...config }
|
|
1313
|
-
else y2_axis = { ...y2_axis, ...config }
|
|
1314
|
-
},
|
|
1315
|
-
get_series: () => series,
|
|
1316
|
-
set_series: (new_series) => (series = new_series),
|
|
1317
|
-
get_loading: () => axis_loading,
|
|
1318
|
-
set_loading: (axis) => (axis_loading = axis),
|
|
1396
|
+
series: { get: () => series, set: (next) => (series = next) },
|
|
1397
|
+
loading: { get: () => axis_loading, set: (axis) => (axis_loading = axis) },
|
|
1319
1398
|
}
|
|
1320
1399
|
|
|
1321
1400
|
// Shared handler + one-shot auto-load bound to this component's state
|
|
1322
|
-
const { handle_axis_change, try_auto_load } = create_axis_loader(
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1401
|
+
const { handle_axis_change, try_auto_load } = create_axis_loader(axis_state, () => ({
|
|
1402
|
+
data_loader,
|
|
1403
|
+
on_axis_change,
|
|
1404
|
+
on_error,
|
|
1405
|
+
}))
|
|
1326
1406
|
$effect(try_auto_load)
|
|
1327
1407
|
</script>
|
|
1328
1408
|
|
|
1329
1409
|
{#snippet fill_regions_layer(fills: typeof computed_fills)}
|
|
1330
1410
|
{#each fills as fill (fill.hover_key)}
|
|
1331
|
-
{#each fill.path_segments as
|
|
1332
|
-
path_d,
|
|
1333
|
-
segment_idx
|
|
1334
|
-
(`${fill.id ?? fill.idx}-${segment_idx}`)
|
|
1335
|
-
}
|
|
1411
|
+
{#each fill.path_segments as path_d, segment_idx (`${fill.id ?? fill.idx}-${segment_idx}`)}
|
|
1336
1412
|
<FillArea
|
|
1337
1413
|
region={fill}
|
|
1338
1414
|
region_idx={fill.idx}
|
|
@@ -1399,7 +1475,7 @@
|
|
|
1399
1475
|
bind:clientWidth={width}
|
|
1400
1476
|
bind:clientHeight={height}
|
|
1401
1477
|
{...rest}
|
|
1402
|
-
class=
|
|
1478
|
+
class={[`scatter`, rest.class]}
|
|
1403
1479
|
class:fullscreen
|
|
1404
1480
|
>
|
|
1405
1481
|
{#if width && height}
|
|
@@ -1415,8 +1491,8 @@
|
|
|
1415
1491
|
bind:this={svg_element}
|
|
1416
1492
|
role="application"
|
|
1417
1493
|
aria-label={rest[`aria-label`] ??
|
|
1418
|
-
|
|
1419
|
-
|
|
1494
|
+
([final_x_axis.label, final_y_axis.label].filter(Boolean).join(` vs `) ||
|
|
1495
|
+
`Scatter plot`)}
|
|
1420
1496
|
tabindex="0"
|
|
1421
1497
|
onfocusin={() => pan_zoom.set_focused(true)}
|
|
1422
1498
|
onfocusout={() => pan_zoom.set_focused(false)}
|
|
@@ -1473,7 +1549,7 @@
|
|
|
1473
1549
|
domain={[x_min, x_max]}
|
|
1474
1550
|
tick_label={(tick) => get_tick_label(tick, final_x_axis.ticks)}
|
|
1475
1551
|
label_x={width / 2 + (final_x_axis.label_shift?.x ?? 0)}
|
|
1476
|
-
label_y={height - pad.b
|
|
1552
|
+
label_y={height - pad.b + AXIS_TITLE_OFFSET + (final_x_axis.label_shift?.y ?? 0)}
|
|
1477
1553
|
axis_loading={axis_loading === `x`}
|
|
1478
1554
|
on_axis_change={(key) => handle_axis_change(`x`, key)}
|
|
1479
1555
|
/>
|
|
@@ -1481,8 +1557,8 @@
|
|
|
1481
1557
|
<!-- Current frame indicator -->
|
|
1482
1558
|
{#if current_x_value != null}
|
|
1483
1559
|
{@const current_pos_raw = is_time_x
|
|
1484
|
-
|
|
1485
|
-
|
|
1560
|
+
? x_scale_fn(new Date(current_x_value))
|
|
1561
|
+
: x_scale_fn(current_x_value)}
|
|
1486
1562
|
{#if isFinite(current_pos_raw)}
|
|
1487
1563
|
{@const current_pos = current_pos_raw}
|
|
1488
1564
|
{#if current_pos >= pad.l && current_pos <= width - pad.r}
|
|
@@ -1516,7 +1592,8 @@
|
|
|
1516
1592
|
tick_label={(tick) => get_tick_label(tick, final_y_axis.ticks)}
|
|
1517
1593
|
label_x={Math.max(
|
|
1518
1594
|
12,
|
|
1519
|
-
pad.l -
|
|
1595
|
+
pad.l -
|
|
1596
|
+
(final_y_axis.tick?.label?.inside ? 0 : tick_label_widths.y_max) -
|
|
1520
1597
|
LABEL_GAP_DEFAULT,
|
|
1521
1598
|
) + (final_y_axis.label_shift?.x ?? 0)}
|
|
1522
1599
|
label_y={pad.t + (height - pad.t - pad.b) / 2 + (final_y_axis.label_shift?.y ?? 0)}
|
|
@@ -1561,7 +1638,7 @@
|
|
|
1561
1638
|
domain={[x2_min, x2_max]}
|
|
1562
1639
|
tick_label={(tick) => get_tick_label(tick, final_x2_axis.ticks)}
|
|
1563
1640
|
label_x={width / 2 + (final_x2_axis.label_shift?.x ?? 0)}
|
|
1564
|
-
label_y={Math.max(12, pad.t - (final_x2_axis.label_shift?.y ??
|
|
1641
|
+
label_y={Math.max(12, pad.t - (final_x2_axis.label_shift?.y ?? AXIS_TITLE_OFFSET))}
|
|
1565
1642
|
axis_loading={axis_loading === `x2`}
|
|
1566
1643
|
on_axis_change={(key) => handle_axis_change(`x2`, key)}
|
|
1567
1644
|
/>
|
|
@@ -1619,30 +1696,32 @@
|
|
|
1619
1696
|
data-series-id={series_data._id}
|
|
1620
1697
|
clip-path="url(#{clip_path_id})"
|
|
1621
1698
|
opacity={hovered_legend_series_idx !== null &&
|
|
1622
|
-
|
|
1699
|
+
hovered_legend_series_idx !== series_data.orig_series_idx
|
|
1623
1700
|
? 0.25
|
|
1624
1701
|
: 1}
|
|
1625
1702
|
>
|
|
1626
|
-
{#if series_markers
|
|
1703
|
+
{#if series_markers.includes(`line`)}
|
|
1627
1704
|
{@const all_line_points = series_data.x.map((x, idx) => ({
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1705
|
+
x,
|
|
1706
|
+
y: series_data.y[idx],
|
|
1707
|
+
}))}
|
|
1631
1708
|
{@const finite_screen_points = all_line_points
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
{@const apply_line_controls =
|
|
1635
|
-
|
|
1636
|
-
|
|
1709
|
+
.map((point) => get_screen_coords(point, series_data))
|
|
1710
|
+
.filter(([sx, sy]) => isFinite(sx) && isFinite(sy))}
|
|
1711
|
+
{@const apply_line_controls =
|
|
1712
|
+
controls.show &&
|
|
1713
|
+
(!has_multiple_series ||
|
|
1714
|
+
series_data._id === series_with_ids[selected_series_idx]?._id)}
|
|
1637
1715
|
{@const ls = series_data.line_style}
|
|
1638
1716
|
{@const tc = (key: string) => apply_line_controls && touched.has(key)}
|
|
1639
|
-
{@const color_fallback =
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1717
|
+
{@const color_fallback =
|
|
1718
|
+
ls?.stroke ??
|
|
1719
|
+
(Array.isArray(series_data.point_style)
|
|
1720
|
+
? series_data.point_style[0]?.fill
|
|
1721
|
+
: series_data.point_style?.fill) ??
|
|
1722
|
+
(series_data.color_values?.[0] != null
|
|
1723
|
+
? color_scale_fn(series_data.color_values[0])
|
|
1724
|
+
: series_default_color)}
|
|
1646
1725
|
<Line
|
|
1647
1726
|
points={finite_screen_points}
|
|
1648
1727
|
origin={[
|
|
@@ -1650,8 +1729,11 @@
|
|
|
1650
1729
|
series_data.y_axis === `y2` ? y2_scale_fn(y2_min) : y_scale_fn(y_min),
|
|
1651
1730
|
]}
|
|
1652
1731
|
line_color={(tc(`line.color`) ? styles.line?.color : null) ?? color_fallback}
|
|
1653
|
-
line_width={(tc(`line.width`) ? styles.line?.width : null) ??
|
|
1732
|
+
line_width={(tc(`line.width`) ? styles.line?.width : null) ??
|
|
1733
|
+
ls?.stroke_width ??
|
|
1734
|
+
2}
|
|
1654
1735
|
line_dash={(tc(`line.dash`) ? styles.line?.dash : null) ?? ls?.line_dash}
|
|
1736
|
+
curve={ls?.curve}
|
|
1655
1737
|
area_color="transparent"
|
|
1656
1738
|
line_tween={effective_line_tween}
|
|
1657
1739
|
/>
|
|
@@ -1672,53 +1754,60 @@
|
|
|
1672
1754
|
{@const series_default_color = get_series_color(series_data.orig_series_idx ?? 0)}
|
|
1673
1755
|
{@const series_default_symbol = get_series_symbol(series_data.orig_series_idx ?? 0)}
|
|
1674
1756
|
<g data-series-id={series_data._id}>
|
|
1675
|
-
{#if series_markers
|
|
1676
|
-
{#each series_data.filtered_data as
|
|
1677
|
-
point
|
|
1678
|
-
(`${point.series_idx}-${point.point_idx}`)
|
|
1679
|
-
}
|
|
1757
|
+
{#if series_markers.includes(`points`)}
|
|
1758
|
+
{#each series_data.filtered_data as point (`${point.series_idx}-${point.point_idx}`)}
|
|
1680
1759
|
{@const label_id = `${point.series_idx}-${point.point_idx}`}
|
|
1681
1760
|
{@const calculated_label_pos = label_positions[label_id]}
|
|
1682
1761
|
{@const point_label = point.point_label ?? {}}
|
|
1683
|
-
{@const label_style =
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1762
|
+
{@const label_style =
|
|
1763
|
+
point_label.auto_placement &&
|
|
1764
|
+
actual_label_config.max_neighbors &&
|
|
1765
|
+
!calculated_label_pos
|
|
1766
|
+
? {}
|
|
1767
|
+
: point_label}
|
|
1688
1768
|
{@const final_label = calculated_label_pos
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1769
|
+
? {
|
|
1770
|
+
...label_style,
|
|
1771
|
+
offset: {
|
|
1772
|
+
x:
|
|
1773
|
+
calculated_label_pos.x -
|
|
1774
|
+
(is_time_x ? x_scale_fn(new Date(point.x)) : x_scale_fn(point.x)),
|
|
1775
|
+
y:
|
|
1776
|
+
calculated_label_pos.y -
|
|
1777
|
+
(series_data.y_axis === `y2`
|
|
1778
|
+
? y2_scale_fn(point.y)
|
|
1779
|
+
: y_scale_fn(point.y)),
|
|
1780
|
+
},
|
|
1781
|
+
}
|
|
1782
|
+
: label_style}
|
|
1700
1783
|
{@const [raw_screen_x, raw_screen_y] = get_screen_coords(point, series_data)}
|
|
1701
|
-
{@const screen_x = isFinite(raw_screen_x)
|
|
1784
|
+
{@const screen_x = isFinite(raw_screen_x)
|
|
1785
|
+
? raw_screen_x
|
|
1786
|
+
: x_scale_fn.range()[0]}
|
|
1702
1787
|
{@const screen_y = isFinite(raw_screen_y)
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
{@const apply_controls =
|
|
1706
|
-
|
|
1707
|
-
|
|
1788
|
+
? raw_screen_y
|
|
1789
|
+
: (series_data.y_axis === `y2` ? y2_scale_fn : y_scale_fn).range()[0]}
|
|
1790
|
+
{@const apply_controls =
|
|
1791
|
+
controls.show &&
|
|
1792
|
+
(!has_multiple_series ||
|
|
1793
|
+
series_data._id === series_with_ids[selected_series_idx]?._id)}
|
|
1708
1794
|
{@const pt = point.point_style}
|
|
1709
1795
|
{@const tc = (key: string) => apply_controls && touched.has(key)}
|
|
1710
|
-
{@const computed_radius =
|
|
1711
|
-
|
|
1712
|
-
|
|
1796
|
+
{@const computed_radius =
|
|
1797
|
+
point.size_value != null
|
|
1798
|
+
? size_scale_fn(point.size_value)
|
|
1799
|
+
: ((tc(`point.size`) ? styles.point?.size : null) ??
|
|
1800
|
+
pt?.radius ??
|
|
1801
|
+
default_point_radius(series_markers))}
|
|
1713
1802
|
<ScatterPoint
|
|
1714
1803
|
x={screen_x}
|
|
1715
1804
|
y={screen_y}
|
|
1716
1805
|
is_dimmed={hovered_legend_series_idx !== null &&
|
|
1717
1806
|
hovered_legend_series_idx !== point.series_idx}
|
|
1718
1807
|
is_hovered={tooltip_point?.series_idx === point.series_idx &&
|
|
1719
|
-
|
|
1808
|
+
tooltip_point?.point_idx === point.point_idx}
|
|
1720
1809
|
is_selected={selected_point?.series_idx === point.series_idx &&
|
|
1721
|
-
|
|
1810
|
+
selected_point?.point_idx === point.point_idx}
|
|
1722
1811
|
leader_line_threshold={actual_label_config.leader_line_threshold}
|
|
1723
1812
|
style={{
|
|
1724
1813
|
symbol_type: pt?.symbol_type ?? series_default_symbol,
|
|
@@ -1726,18 +1815,21 @@
|
|
|
1726
1815
|
radius: computed_radius,
|
|
1727
1816
|
stroke_width:
|
|
1728
1817
|
(tc(`point.stroke_width`) ? styles.point?.stroke_width : null) ??
|
|
1729
|
-
|
|
1818
|
+
pt?.stroke_width ??
|
|
1819
|
+
1,
|
|
1730
1820
|
stroke:
|
|
1731
1821
|
(tc(`point.stroke_color`) ? styles.point?.stroke_color : null) ??
|
|
1732
|
-
|
|
1822
|
+
pt?.stroke ??
|
|
1823
|
+
`#000`,
|
|
1733
1824
|
stroke_opacity:
|
|
1734
1825
|
(tc(`point.stroke_opacity`) ? styles.point?.stroke_opacity : null) ??
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1826
|
+
pt?.stroke_opacity ??
|
|
1827
|
+
1,
|
|
1828
|
+
fill_opacity:
|
|
1829
|
+
(tc(`point.opacity`) ? styles.point?.opacity : null) ??
|
|
1830
|
+
pt?.fill_opacity ??
|
|
1831
|
+
1,
|
|
1832
|
+
cursor: on_point_click || point_events?.onclick ? `pointer` : undefined,
|
|
1741
1833
|
}}
|
|
1742
1834
|
hover={point.point_hover ?? {}}
|
|
1743
1835
|
label={final_label}
|
|
@@ -1745,15 +1837,17 @@
|
|
|
1745
1837
|
{point_tween}
|
|
1746
1838
|
origin={{ x: plot_center_x, y: plot_center_y }}
|
|
1747
1839
|
--point-fill-color={point.color_value != null
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1840
|
+
? color_scale_fn(point.color_value)
|
|
1841
|
+
: ((tc(`point.color`) ? styles.point?.color : null) ??
|
|
1842
|
+
pt?.fill ??
|
|
1843
|
+
series_default_color)}
|
|
1751
1844
|
{...point_events &&
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1845
|
+
Object.fromEntries(
|
|
1846
|
+
point_event_names.map((name) => [
|
|
1847
|
+
name,
|
|
1848
|
+
(event: Event) => point_events?.[name]?.({ point, event }),
|
|
1849
|
+
]),
|
|
1850
|
+
)}
|
|
1757
1851
|
onclick={(event: MouseEvent) => {
|
|
1758
1852
|
// Call user-provided onclick handler first if it exists
|
|
1759
1853
|
point_events?.onclick?.({ point, event })
|
|
@@ -1773,16 +1867,33 @@
|
|
|
1773
1867
|
{@render fill_regions_layer(fills_by_z.above_all)}
|
|
1774
1868
|
<!-- Reference lines: above all -->
|
|
1775
1869
|
{@render ref_lines_layer(ref_lines_by_z.above_all)}
|
|
1870
|
+
|
|
1871
|
+
<!-- Marginal distribution strips -->
|
|
1872
|
+
<PlotMarginals
|
|
1873
|
+
marginals={resolved_marginals}
|
|
1874
|
+
series={marginal_series}
|
|
1875
|
+
{width}
|
|
1876
|
+
{height}
|
|
1877
|
+
{pad}
|
|
1878
|
+
has_axis={marginal_has_axis}
|
|
1879
|
+
axes={{
|
|
1880
|
+
x1: marginal_axis(x_scale_fn, [x_min, x_max], final_x_axis),
|
|
1881
|
+
x2: marginal_axis(x2_scale_fn, [x2_min, x2_max], final_x2_axis),
|
|
1882
|
+
y1: marginal_axis(y_scale_fn, [y_min, y_max], final_y_axis),
|
|
1883
|
+
y2: marginal_axis(y2_scale_fn, [y2_min, y2_max], final_y2_axis),
|
|
1884
|
+
}}
|
|
1885
|
+
id={component_id}
|
|
1886
|
+
/>
|
|
1776
1887
|
</svg>
|
|
1777
1888
|
|
|
1778
1889
|
<!-- Tooltip overlay above all plot overlays (legend, colorbar) -->
|
|
1779
1890
|
{#if handler_props && hovered && tooltip_point}
|
|
1780
1891
|
{@const { point_label, series_idx } = tooltip_point}
|
|
1781
1892
|
{@const tooltip_bg_color = pick_tooltip_bg(
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1893
|
+
tooltip_point,
|
|
1894
|
+
series_with_ids[series_idx],
|
|
1895
|
+
color_scale_fn,
|
|
1896
|
+
)}
|
|
1786
1897
|
<PlotTooltip
|
|
1787
1898
|
x={handler_props.cx}
|
|
1788
1899
|
y={handler_props.cy}
|
|
@@ -1800,9 +1911,10 @@
|
|
|
1800
1911
|
{@html sanitize_html(hp.x_axis.label || `x`)}: {hp.x_formatted}<br />
|
|
1801
1912
|
{@html sanitize_html(hp.y_axis.label || `y`)}: {hp.y_formatted}
|
|
1802
1913
|
{#if hp.colorbar?.value != null}
|
|
1803
|
-
<br />{@html sanitize_html(hp.colorbar.title || `Color`)}: {
|
|
1804
|
-
|
|
1805
|
-
|
|
1914
|
+
<br />{@html sanitize_html(hp.colorbar.title || `Color`)}: {format_value(
|
|
1915
|
+
hp.colorbar.value,
|
|
1916
|
+
hp.colorbar.tick_format || `.3~g`,
|
|
1917
|
+
)}
|
|
1806
1918
|
{/if}
|
|
1807
1919
|
{/if}
|
|
1808
1920
|
</PlotTooltip>
|
|
@@ -1813,10 +1925,9 @@
|
|
|
1813
1925
|
<ScatterPlotControls
|
|
1814
1926
|
toggle_props={{
|
|
1815
1927
|
...controls.toggle_props,
|
|
1816
|
-
style:
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
}`,
|
|
1928
|
+
style: `--ctrl-btn-right: var(--fullscreen-btn-offset, 30px); top: var(--ctrl-btn-top, 5pt); ${
|
|
1929
|
+
controls.toggle_props?.style ?? ``
|
|
1930
|
+
}`,
|
|
1820
1931
|
}}
|
|
1821
1932
|
pane_props={controls.pane_props}
|
|
1822
1933
|
bind:x_axis
|
|
@@ -1839,13 +1950,13 @@
|
|
|
1839
1950
|
{/if}
|
|
1840
1951
|
|
|
1841
1952
|
<!-- Color Bar -->
|
|
1842
|
-
{#if color_bar && all_color_values.length > 0
|
|
1953
|
+
{#if width > 0 && height > 0 && color_bar && all_color_values.length > 0}
|
|
1843
1954
|
{@const color_domain = [
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1955
|
+
(typeof color_scale === `string` ? undefined : color_scale.value_range)?.[0] ??
|
|
1956
|
+
auto_color_range[0],
|
|
1957
|
+
(typeof color_scale === `string` ? undefined : color_scale.value_range)?.[1] ??
|
|
1958
|
+
auto_color_range[1],
|
|
1959
|
+
] as Vec2}
|
|
1849
1960
|
<div
|
|
1850
1961
|
bind:this={colorbar_element}
|
|
1851
1962
|
onmouseenter={() => colorbar_tween.set_locked(true)}
|
|
@@ -1854,9 +1965,10 @@
|
|
|
1854
1965
|
role="img"
|
|
1855
1966
|
aria-label="Color scale legend"
|
|
1856
1967
|
style={`${
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
`position: absolute; left: ${colorbar_tween.coords.current.x}px; top: ${colorbar_tween.coords.current.y}px`
|
|
1968
|
+
// explicit wrapper_style or auto-outside places the colorbar; else auto-placement coords
|
|
1969
|
+
effective_cbar_wrapper_style ??
|
|
1970
|
+
`position: absolute; left: ${colorbar_tween.coords.current.x}px; top: ${colorbar_tween.coords.current.y}px`
|
|
1971
|
+
}; pointer-events: auto;`}
|
|
1860
1972
|
>
|
|
1861
1973
|
<ColorBar
|
|
1862
1974
|
tick_labels={4}
|
|
@@ -1865,7 +1977,8 @@
|
|
|
1865
1977
|
color_scale_domain={color_domain}
|
|
1866
1978
|
scale_type={typeof color_scale === `string` ? undefined : color_scale.type}
|
|
1867
1979
|
range={color_domain?.every((val) => val != null) ? color_domain : undefined}
|
|
1868
|
-
bar_style="width:
|
|
1980
|
+
bar_style="width: {COLOR_BAR_DEFAULTS.width}px; height: {COLOR_BAR_DEFAULTS.horizontal_bar_height}px; {color_bar?.style ??
|
|
1981
|
+
``}"
|
|
1869
1982
|
{...color_bar}
|
|
1870
1983
|
wrapper_style={effective_cbar_wrapper_style ? `height: 100%; width: 100%;` : ``}
|
|
1871
1984
|
/>
|
|
@@ -1874,24 +1987,18 @@
|
|
|
1874
1987
|
|
|
1875
1988
|
<!-- Legend -->
|
|
1876
1989
|
<!-- Only render if multiple series or if legend prop was explicitly provided by user (even if empty object) -->
|
|
1877
|
-
{#if legend != null && legend_data.length > 0 &&
|
|
1878
|
-
(legend_data.length > 1 || Object.keys(legend ?? {}).length > 0)}
|
|
1990
|
+
{#if legend != null && legend_data.length > 0 && (legend_data.length > 1 || Object.keys(legend ?? {}).length > 0)}
|
|
1879
1991
|
{@const default_x = pad.l + 10}
|
|
1880
1992
|
{@const default_y = pad.t + 10}
|
|
1881
|
-
{@const
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
{@const
|
|
1889
|
-
|
|
1890
|
-
: legend_auto_outside
|
|
1891
|
-
? legend_outside_y
|
|
1892
|
-
: legend_placement
|
|
1893
|
-
? legend_tween.coords.current.y
|
|
1894
|
-
: default_y}
|
|
1993
|
+
{@const auto_position = placed_coords(
|
|
1994
|
+
legend_auto_outside,
|
|
1995
|
+
{ x: legend_outside_x, y: legend_outside_y },
|
|
1996
|
+
legend_tween.placed(),
|
|
1997
|
+
legend_tween.coords.current,
|
|
1998
|
+
{ x: default_x, y: default_y },
|
|
1999
|
+
)}
|
|
2000
|
+
{@const current_position =
|
|
2001
|
+
legend_is_dragging && legend_manual_position ? legend_manual_position : auto_position}
|
|
1895
2002
|
<PlotLegend
|
|
1896
2003
|
bind:root_element={legend_element}
|
|
1897
2004
|
series_data={legend_data}
|
|
@@ -1907,15 +2014,14 @@
|
|
|
1907
2014
|
hovered_fill_key = fill && fill.visible !== false ? fill.hover_key : null
|
|
1908
2015
|
hovered_legend_series_idx = null
|
|
1909
2016
|
} else {
|
|
1910
|
-
hovered_legend_series_idx =
|
|
1911
|
-
? item.series_idx
|
|
1912
|
-
: null
|
|
2017
|
+
hovered_legend_series_idx =
|
|
2018
|
+
item != null && item.series_idx >= 0 ? item.series_idx : null
|
|
1913
2019
|
hovered_fill_key = null
|
|
1914
2020
|
}
|
|
1915
2021
|
}}
|
|
1916
2022
|
active_series_idx={tooltip_point?.series_idx ?? hovered_legend_series_idx}
|
|
1917
|
-
active_fill_idx={computed_fills.find((fill) => fill.hover_key === hovered_fill_key)
|
|
1918
|
-
null}
|
|
2023
|
+
active_fill_idx={computed_fills.find((fill) => fill.hover_key === hovered_fill_key)
|
|
2024
|
+
?.idx ?? null}
|
|
1919
2025
|
draggable={legend?.draggable ?? true}
|
|
1920
2026
|
{...legend}
|
|
1921
2027
|
on_toggle={legend?.on_toggle ?? legend_vis.on_toggle}
|
|
@@ -1927,7 +2033,7 @@
|
|
|
1927
2033
|
fill_regions = fill_regions.map((region, idx) =>
|
|
1928
2034
|
idx === source_idx
|
|
1929
2035
|
? { ...region, visible: !(region.visible !== false) }
|
|
1930
|
-
: region
|
|
2036
|
+
: region,
|
|
1931
2037
|
)
|
|
1932
2038
|
}
|
|
1933
2039
|
}}
|
|
@@ -1938,7 +2044,9 @@
|
|
|
1938
2044
|
// Only fill_regions can be toggled (error_bands are not bindable)
|
|
1939
2045
|
if (source_type !== `fill_region`) return
|
|
1940
2046
|
// Toggle: if only this fill is visible, show all; otherwise show only this one
|
|
1941
|
-
const visible_count = fill_regions.filter(
|
|
2047
|
+
const visible_count = fill_regions.filter(
|
|
2048
|
+
(region) => region.visible !== false,
|
|
2049
|
+
).length
|
|
1942
2050
|
const this_visible = fill_regions[source_idx]?.visible !== false
|
|
1943
2051
|
if (visible_count === 1 && this_visible) {
|
|
1944
2052
|
// Show all fills
|
|
@@ -1953,8 +2061,8 @@
|
|
|
1953
2061
|
}}
|
|
1954
2062
|
style={`
|
|
1955
2063
|
position: absolute;
|
|
1956
|
-
left: ${
|
|
1957
|
-
top: ${
|
|
2064
|
+
left: ${current_position.x}px;
|
|
2065
|
+
top: ${current_position.y}px;
|
|
1958
2066
|
pointer-events: auto;
|
|
1959
2067
|
${legend?.style ?? ``}
|
|
1960
2068
|
`}
|
|
@@ -2024,7 +2132,9 @@
|
|
|
2024
2132
|
div.scatter :global(.pane-toggle),
|
|
2025
2133
|
div.scatter .header-controls {
|
|
2026
2134
|
opacity: 0;
|
|
2027
|
-
transition:
|
|
2135
|
+
transition:
|
|
2136
|
+
opacity 0.2s,
|
|
2137
|
+
background-color 0.2s;
|
|
2028
2138
|
}
|
|
2029
2139
|
div.scatter:hover :global(.pane-toggle),
|
|
2030
2140
|
div.scatter:hover .header-controls,
|
|
@@ -2051,10 +2161,7 @@
|
|
|
2051
2161
|
color: var(--text-color);
|
|
2052
2162
|
white-space: nowrap;
|
|
2053
2163
|
/* Use line-height to center text vertically without flexbox */
|
|
2054
|
-
line-height: var(
|
|
2055
|
-
--scatter-axis-label-line-height,
|
|
2056
|
-
20px
|
|
2057
|
-
); /* Match foreignObject height */
|
|
2164
|
+
line-height: var(--scatter-axis-label-line-height, 20px); /* Match foreignObject height */
|
|
2058
2165
|
display: block;
|
|
2059
2166
|
}
|
|
2060
2167
|
.current-frame-indicator {
|