matterviz 0.3.5 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/dist/MillerIndexInput.svelte +5 -5
  2. package/dist/api/optimade.js +3 -3
  3. package/dist/brillouin/BrillouinZone.svelte +5 -2
  4. package/dist/brillouin/BrillouinZone.svelte.d.ts +1 -1
  5. package/dist/brillouin/BrillouinZoneExportPane.svelte +1 -3
  6. package/dist/brillouin/BrillouinZoneInfoPane.svelte +1 -1
  7. package/dist/brillouin/BrillouinZoneScene.svelte +5 -5
  8. package/dist/brillouin/compute.js +21 -21
  9. package/dist/brillouin/index.d.ts +1 -1
  10. package/dist/brillouin/index.js +0 -1
  11. package/dist/brillouin/types.d.ts +8 -13
  12. package/dist/chempot-diagram/ChemPotDiagram.svelte +3 -3
  13. package/dist/chempot-diagram/ChemPotDiagram2D.svelte +3 -4
  14. package/dist/chempot-diagram/ChemPotDiagram3D.svelte +33 -34
  15. package/dist/chempot-diagram/compute.js +1 -7
  16. package/dist/chempot-diagram/temperature.d.ts +1 -1
  17. package/dist/chempot-diagram/temperature.js +1 -3
  18. package/dist/chempot-diagram/types.d.ts +4 -9
  19. package/dist/colors/index.js +5 -5
  20. package/dist/composition/Composition.svelte +2 -1
  21. package/dist/composition/Formula.svelte +7 -4
  22. package/dist/composition/FormulaFilter.svelte +1 -3
  23. package/dist/composition/format.js +4 -4
  24. package/dist/composition/parse.d.ts +2 -1
  25. package/dist/composition/parse.js +61 -46
  26. package/dist/convex-hull/ConvexHull2D.svelte +62 -51
  27. package/dist/convex-hull/ConvexHull3D.svelte +101 -90
  28. package/dist/convex-hull/ConvexHull4D.svelte +70 -58
  29. package/dist/convex-hull/ConvexHullControls.svelte +24 -35
  30. package/dist/convex-hull/ConvexHullInfoPane.svelte +8 -5
  31. package/dist/convex-hull/ConvexHullInfoPane.svelte.d.ts +2 -0
  32. package/dist/convex-hull/ConvexHullStats.svelte +9 -2
  33. package/dist/convex-hull/ConvexHullStats.svelte.d.ts +2 -0
  34. package/dist/convex-hull/GasPressureControls.svelte +7 -7
  35. package/dist/convex-hull/StructurePopup.svelte +65 -30
  36. package/dist/convex-hull/StructurePopup.svelte.d.ts +6 -6
  37. package/dist/convex-hull/TemperatureSlider.svelte +8 -5
  38. package/dist/convex-hull/barycentric-coords.d.ts +2 -2
  39. package/dist/convex-hull/barycentric-coords.js +2 -2
  40. package/dist/convex-hull/gas-thermodynamics.js +2 -4
  41. package/dist/convex-hull/helpers.d.ts +13 -2
  42. package/dist/convex-hull/helpers.js +37 -16
  43. package/dist/convex-hull/index.d.ts +1 -0
  44. package/dist/convex-hull/index.js +1 -0
  45. package/dist/convex-hull/thermodynamics.d.ts +2 -1
  46. package/dist/convex-hull/thermodynamics.js +7 -7
  47. package/dist/convex-hull/types.d.ts +15 -15
  48. package/dist/effects.svelte.d.ts +12 -0
  49. package/dist/effects.svelte.js +37 -0
  50. package/dist/element/BohrAtom.svelte +4 -4
  51. package/dist/element/data.json.gz.d.ts +3 -1
  52. package/dist/element/index.d.ts +1 -1
  53. package/dist/element/index.js +0 -1
  54. package/dist/fermi-surface/FermiSurface.svelte +4 -4
  55. package/dist/fermi-surface/FermiSurface.svelte.d.ts +1 -1
  56. package/dist/fermi-surface/FermiSurfaceControls.svelte +15 -19
  57. package/dist/fermi-surface/FermiSurfaceControls.svelte.d.ts +1 -1
  58. package/dist/fermi-surface/FermiSurfaceScene.svelte +8 -6
  59. package/dist/fermi-surface/compute.js +2 -2
  60. package/dist/fermi-surface/export.js +13 -26
  61. package/dist/fermi-surface/parse.js +8 -12
  62. package/dist/fermi-surface/types.d.ts +2 -5
  63. package/dist/heatmap-matrix/HeatmapMatrix.svelte +21 -3
  64. package/dist/heatmap-matrix/index.js +6 -6
  65. package/dist/io/decompress.d.ts +2 -1
  66. package/dist/io/decompress.js +1 -1
  67. package/dist/io/export.js +1 -1
  68. package/dist/io/index.d.ts +1 -1
  69. package/dist/io/index.js +0 -1
  70. package/dist/io/url-drop.js +7 -1
  71. package/dist/isosurface/IsosurfaceControls.svelte +11 -25
  72. package/dist/isosurface/slice.js +1 -1
  73. package/dist/isosurface/types.js +12 -12
  74. package/dist/labels.d.ts +1 -1
  75. package/dist/labels.js +14 -11
  76. package/dist/layout/InfoTag.svelte +6 -4
  77. package/dist/layout/PropertyFilter.svelte +4 -2
  78. package/dist/layout/json-tree/JsonTree.svelte +22 -14
  79. package/dist/layout/json-tree/JsonValue.svelte +2 -2
  80. package/dist/layout/json-tree/types.d.ts +3 -2
  81. package/dist/layout/json-tree/types.js +0 -1
  82. package/dist/layout/json-tree/utils.d.ts +4 -4
  83. package/dist/layout/json-tree/utils.js +12 -20
  84. package/dist/marching-cubes.js +13 -15
  85. package/dist/math.d.ts +11 -1
  86. package/dist/math.js +15 -6
  87. package/dist/overlays/DragControlTab.svelte +98 -0
  88. package/dist/overlays/DragControlTab.svelte.d.ts +8 -0
  89. package/dist/overlays/DraggablePane.svelte +7 -84
  90. package/dist/overlays/index.d.ts +1 -0
  91. package/dist/overlays/index.js +1 -0
  92. package/dist/periodic-table/PeriodicTable.svelte +11 -11
  93. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte +4 -2
  94. package/dist/phase-diagram/IsobaricBinaryPhaseDiagram.svelte.d.ts +1 -1
  95. package/dist/phase-diagram/PhaseDiagramControls.svelte +4 -9
  96. package/dist/phase-diagram/PhaseDiagramControls.svelte.d.ts +1 -1
  97. package/dist/phase-diagram/PhaseDiagramExportPane.svelte +2 -10
  98. package/dist/phase-diagram/PhaseDiagramTooltip.svelte +2 -3
  99. package/dist/phase-diagram/TdbInfoPanel.svelte +3 -3
  100. package/dist/phase-diagram/build-diagram.js +11 -18
  101. package/dist/phase-diagram/diagram-input.d.ts +5 -9
  102. package/dist/phase-diagram/index.d.ts +2 -2
  103. package/dist/phase-diagram/index.js +0 -2
  104. package/dist/phase-diagram/parse.d.ts +2 -2
  105. package/dist/phase-diagram/parse.js +6 -10
  106. package/dist/phase-diagram/svg-to-diagram.js +15 -15
  107. package/dist/phase-diagram/types.d.ts +5 -11
  108. package/dist/phase-diagram/utils.d.ts +2 -2
  109. package/dist/phase-diagram/utils.js +9 -11
  110. package/dist/plot/BarPlot.svelte +162 -314
  111. package/dist/plot/BarPlot.svelte.d.ts +5 -4
  112. package/dist/plot/BarPlotControls.svelte.d.ts +1 -1
  113. package/dist/plot/BinnedScatterPlot.svelte +1114 -0
  114. package/dist/plot/BinnedScatterPlot.svelte.d.ts +66 -0
  115. package/dist/plot/ColorBar.svelte +19 -17
  116. package/dist/plot/ColorBar.svelte.d.ts +1 -1
  117. package/dist/plot/FillArea.svelte +2 -4
  118. package/dist/plot/FillArea.svelte.d.ts +1 -1
  119. package/dist/plot/Histogram.svelte +167 -281
  120. package/dist/plot/Histogram.svelte.d.ts +1 -1
  121. package/dist/plot/HistogramControls.svelte.d.ts +1 -1
  122. package/dist/plot/InteractiveAxisLabel.svelte +5 -3
  123. package/dist/plot/InteractiveAxisLabel.svelte.d.ts +1 -1
  124. package/dist/plot/PlotAxis.svelte +169 -0
  125. package/dist/plot/PlotAxis.svelte.d.ts +24 -0
  126. package/dist/plot/PlotControls.svelte.d.ts +1 -1
  127. package/dist/plot/ReferenceLine3D.svelte +53 -51
  128. package/dist/plot/ReferencePlane.svelte +39 -42
  129. package/dist/plot/ScatterPlot.svelte +300 -367
  130. package/dist/plot/ScatterPlot.svelte.d.ts +8 -5
  131. package/dist/plot/ScatterPlot3D.svelte +33 -6
  132. package/dist/plot/ScatterPlot3D.svelte.d.ts +3 -2
  133. package/dist/plot/ScatterPlot3DControls.svelte +9 -9
  134. package/dist/plot/ScatterPlotControls.svelte +3 -4
  135. package/dist/plot/ScatterPoint.svelte +18 -27
  136. package/dist/plot/ScatterPoint.svelte.d.ts +4 -3
  137. package/dist/plot/Surface3D.svelte +4 -7
  138. package/dist/plot/ZeroLines.svelte +2 -1
  139. package/dist/plot/ZeroLines.svelte.d.ts +2 -1
  140. package/dist/plot/ZoomRect.svelte +2 -2
  141. package/dist/plot/ZoomRect.svelte.d.ts +3 -3
  142. package/dist/plot/adaptive-density.d.ts +69 -0
  143. package/dist/plot/adaptive-density.js +191 -0
  144. package/dist/plot/auto-place.d.ts +43 -0
  145. package/dist/plot/auto-place.js +122 -0
  146. package/dist/plot/axis-utils.js +3 -5
  147. package/dist/plot/binned-scatter-types.d.ts +59 -0
  148. package/dist/plot/binned-scatter-types.js +1 -0
  149. package/dist/plot/data-cleaning.js +1 -1
  150. package/dist/plot/data-transform.js +1 -1
  151. package/dist/plot/fill-utils.d.ts +4 -9
  152. package/dist/plot/fill-utils.js +29 -44
  153. package/dist/plot/index.d.ts +4 -0
  154. package/dist/plot/index.js +2 -0
  155. package/dist/plot/interactions.d.ts +4 -4
  156. package/dist/plot/interactions.js +4 -3
  157. package/dist/plot/layout.d.ts +20 -2
  158. package/dist/plot/layout.js +59 -16
  159. package/dist/plot/reference-line.d.ts +1 -1
  160. package/dist/plot/reference-line.js +9 -11
  161. package/dist/plot/scales.d.ts +1 -1
  162. package/dist/plot/scales.js +20 -23
  163. package/dist/plot/types.d.ts +30 -58
  164. package/dist/plot/types.js +2 -6
  165. package/dist/plot/utils/label-placement.d.ts +24 -3
  166. package/dist/plot/utils/label-placement.js +82 -12
  167. package/dist/plot/utils/series-visibility.d.ts +8 -2
  168. package/dist/plot/utils/series-visibility.js +23 -5
  169. package/dist/rdf/RdfPlot.svelte +5 -5
  170. package/dist/rdf/calc-rdf.js +3 -3
  171. package/dist/sanitize.d.ts +2 -0
  172. package/dist/sanitize.js +2 -0
  173. package/dist/spectral/Bands.svelte +1 -1
  174. package/dist/spectral/BandsAndDos.svelte +22 -16
  175. package/dist/spectral/BrillouinBandsDos.svelte +20 -16
  176. package/dist/spectral/Dos.svelte +1 -1
  177. package/dist/spectral/helpers.d.ts +4 -2
  178. package/dist/spectral/helpers.js +44 -35
  179. package/dist/spectral/index.d.ts +1 -1
  180. package/dist/spectral/index.js +0 -1
  181. package/dist/structure/AtomLegend.svelte +23 -6
  182. package/dist/structure/AtomLegend.svelte.d.ts +1 -0
  183. package/dist/structure/CanvasTooltip.svelte +9 -9
  184. package/dist/structure/CanvasTooltip.svelte.d.ts +1 -1
  185. package/dist/structure/CellSelect.svelte +14 -16
  186. package/dist/structure/Structure.svelte +317 -68
  187. package/dist/structure/Structure.svelte.d.ts +4 -2
  188. package/dist/structure/StructureControls.svelte +20 -45
  189. package/dist/structure/StructureExportPane.svelte +2 -1
  190. package/dist/structure/StructureInfoPane.svelte +10 -8
  191. package/dist/structure/StructureScene.svelte +527 -177
  192. package/dist/structure/StructureScene.svelte.d.ts +5 -2
  193. package/dist/structure/atom-properties.js +4 -4
  194. package/dist/structure/bond-order-perception.js +115 -98
  195. package/dist/structure/bonding.d.ts +27 -1
  196. package/dist/structure/bonding.js +187 -16
  197. package/dist/structure/export.js +1 -1
  198. package/dist/structure/index.d.ts +3 -2
  199. package/dist/structure/index.js +0 -2
  200. package/dist/structure/parse.js +88 -59
  201. package/dist/symmetry/WyckoffTable.svelte +7 -0
  202. package/dist/symmetry/index.js +13 -14
  203. package/dist/table/HeatmapTable.svelte +45 -66
  204. package/dist/table/HeatmapTable.svelte.d.ts +1 -1
  205. package/dist/table/ToggleMenu.svelte +19 -10
  206. package/dist/theme/themes.mjs +12 -0
  207. package/dist/tooltip/index.d.ts +1 -1
  208. package/dist/tooltip/index.js +0 -1
  209. package/dist/trajectory/Trajectory.svelte +43 -15
  210. package/dist/trajectory/TrajectoryInfoPane.svelte +2 -2
  211. package/dist/trajectory/extract.js +1 -1
  212. package/dist/trajectory/frame-reader.js +4 -4
  213. package/dist/trajectory/helpers.d.ts +5 -4
  214. package/dist/trajectory/helpers.js +9 -17
  215. package/dist/trajectory/index.d.ts +2 -2
  216. package/dist/trajectory/index.js +2 -2
  217. package/dist/trajectory/parse/ase.js +4 -4
  218. package/dist/trajectory/parse/hdf5.js +1 -1
  219. package/dist/trajectory/parse/index.js +2 -3
  220. package/dist/trajectory/parse/lammps.js +1 -1
  221. package/dist/trajectory/parse/vasp.js +1 -1
  222. package/dist/trajectory/plotting.d.ts +1 -1
  223. package/dist/trajectory/plotting.js +38 -38
  224. package/dist/trajectory/types.d.ts +1 -1
  225. package/dist/utils.d.ts +1 -0
  226. package/dist/utils.js +9 -0
  227. package/dist/xrd/calc-xrd.js +3 -4
  228. package/dist/xrd/parse.js +1 -1
  229. package/package.json +42 -22
@@ -6,6 +6,7 @@
6
6
  import { format_value } from '../labels'
7
7
  import { sanitize_html } from '../sanitize'
8
8
  import { FullscreenToggle, set_fullscreen_bg } from '../layout'
9
+ import type { Point2D, Vec2 } from '../math'
9
10
  import type {
10
11
  AxisLoadError,
11
12
  BarHandlerProps,
@@ -26,12 +27,11 @@
26
27
  RefLineEvent,
27
28
  ScaleType,
28
29
  UserContentProps,
29
- XyObj,
30
30
  } from './'
31
31
  import {
32
- AxisLabel,
33
32
  BarPlotControls,
34
33
  compute_element_placement,
34
+ PlotAxis,
35
35
  PlotLegend,
36
36
  ReferenceLine,
37
37
  ScatterPoint,
@@ -59,11 +59,7 @@
59
59
  get_nice_data_range,
60
60
  get_tick_label,
61
61
  } from './scales'
62
- import {
63
- DEFAULT_GRID_STYLE,
64
- DEFAULT_MARKERS,
65
- get_scale_type_name,
66
- } from './types'
62
+ import { DEFAULT_MARKERS, get_scale_type_name } from './types'
67
63
  import { DEFAULTS } from '../settings'
68
64
  import { extent } from 'd3-array'
69
65
  import type { Snippet } from 'svelte'
@@ -71,7 +67,13 @@
71
67
  import type { HTMLAttributes } from 'svelte/elements'
72
68
  import { Tween, type TweenOptions } from 'svelte/motion'
73
69
  import { SvelteMap } from 'svelte/reactivity'
74
- import type { Vec2 } from '../math'
70
+ import {
71
+ build_obstacles_norm,
72
+ clip_bar,
73
+ has_explicit_position,
74
+ measured_footprint,
75
+ place_decorations,
76
+ } from './auto-place'
75
77
  import {
76
78
  calc_auto_padding,
77
79
  constrain_tooltip_position,
@@ -192,7 +194,7 @@
192
194
  radius_range?: [number, number]
193
195
  value_range?: [number, number]
194
196
  }
195
- point_tween?: TweenOptions<XyObj>
197
+ point_tween?: TweenOptions<Point2D>
196
198
  on_point_click?: (
197
199
  data: LineMarkerHandlerProps & { event: MouseEvent | KeyboardEvent },
198
200
  ) => void
@@ -487,7 +489,8 @@
487
489
 
488
490
  // Layout: dynamic padding based on tick label widths
489
491
  const default_padding = { t: 20, b: 60, l: 60, r: 20 }
490
- let pad = $derived(filter_padding(padding, default_padding))
492
+ // base_pad reserves space for tick labels/axis titles; pad (below) adds decoration reservations
493
+ let base_pad = $derived(filter_padding(padding, default_padding))
491
494
 
492
495
  // Update padding when format or ticks change
493
496
  $effect(() => {
@@ -530,10 +533,68 @@
530
533
 
531
534
  // Only update if padding actually changed (prevents infinite loop)
532
535
  if (
533
- pad.t !== new_pad.t || pad.b !== new_pad.b || pad.l !== new_pad.l ||
534
- pad.r !== new_pad.r
535
- ) pad = new_pad
536
+ base_pad.t !== new_pad.t || base_pad.b !== new_pad.b ||
537
+ base_pad.l !== new_pad.l || base_pad.r !== new_pad.r
538
+ ) base_pad = new_pad
536
539
  })
540
+
541
+ let legend_element = $state<HTMLDivElement | undefined>()
542
+ const legend_footprint = $derived(measured_footprint(legend_element, { width: 120, height: 60 }))
543
+ const legend_has_explicit_pos = $derived(has_explicit_position(legend?.style))
544
+
545
+ // Obstacle field in normalized [0,1] plot coords (y=0 at top). Each bar is modeled as a segment
546
+ // from baseline to its tip so the legend can't hide inside a tall bar. Built from internal_series
547
+ // (pad-independent) + ranges so the crowding decision can't see its own reservation.
548
+ const obstacles_norm = $derived.by(() => {
549
+ if (!width || !height || !visible_series.length) return []
550
+ const base_w = width - base_pad.l - base_pad.r
551
+ const base_h = height - base_pad.t - base_pad.b
552
+ if (base_w <= 0 || base_h <= 0) return []
553
+ const bars: { points: { x: number; y: number }[]; draws_line: boolean }[] = []
554
+ const vertical = orientation === `vertical`
555
+ internal_series.forEach((srs, series_idx) => {
556
+ if (!(srs?.visible ?? true)) return
557
+ const is_line = srs.render_mode === `line`
558
+ const series_offsets = stacked_offsets[series_idx] ?? []
559
+ const [ax0, ax1] = srs.x_axis === `x2` ? ranges.current.x2 : ranges.current.x
560
+ const [vy0, vy1] = srs.y_axis === `y2` ? ranges.current.y2 : ranges.current.y
561
+ const [cy0, cy1] = ranges.current.y
562
+ const x_span = ax1 - ax0
563
+ const y_span = vy1 - vy0
564
+ const cy_span = cy1 - cy0
565
+ if (!(x_span > 0) || !((vertical ? y_span : cy_span) > 0)) return
566
+ srs.x.forEach((x_val, bar_idx) => {
567
+ const base = !is_line && mode === `stacked` ? (series_offsets[bar_idx] ?? 0) : 0
568
+ const value = base + srs.y[bar_idx]
569
+ // vertical: category on x, value rises on y (inverted). horizontal: category on y, value on x
570
+ const seg = vertical
571
+ ? clip_bar(true, (x_val - ax0) / x_span, 1 - (value - vy0) / y_span, 1 - (base - vy0) / y_span)
572
+ : clip_bar(false, 1 - (x_val - cy0) / cy_span, (value - ax0) / x_span, (base - ax0) / x_span)
573
+ if (seg) bars.push(seg)
574
+ })
575
+ })
576
+ return build_obstacles_norm(bars, base_w, base_h)
577
+ })
578
+
579
+ // Move the legend to the bottom margin when no interior spot avoids the bars
580
+ const decor = $derived.by(() =>
581
+ place_decorations({
582
+ base_pad,
583
+ width,
584
+ height,
585
+ obstacles_norm,
586
+ // gate on legend_element (the render signal) not legend_data, whose entries can read pad
587
+ legend: legend != null &&
588
+ (show_legend !== undefined ? show_legend : series.length > 1) &&
589
+ legend_element != null && !legend_has_explicit_pos
590
+ ? { footprint: legend_footprint, clearance: legend?.axis_clearance }
591
+ : null,
592
+ })
593
+ )
594
+ const pad = $derived(decor.pad)
595
+ const legend_auto_outside = $derived(decor.legend_outside)
596
+ const legend_outside_x = $derived(decor.legend_pos.x)
597
+ const legend_outside_y = $derived(decor.legend_pos.y)
537
598
  const chart_width = $derived(Math.max(1, width - pad.l - pad.r))
538
599
  const chart_height = $derived(Math.max(1, height - pad.t - pad.b))
539
600
 
@@ -1067,8 +1128,7 @@
1067
1128
  })
1068
1129
  })
1069
1130
 
1070
- // Legend placement stability state
1071
- let legend_element = $state<HTMLDivElement | undefined>()
1131
+ // Legend placement stability state (legend_element declared above for the auto-place block)
1072
1132
  let hovered_legend_series_idx = $state<number | null>(null)
1073
1133
  const legend_hover = create_hover_lock()
1074
1134
  const dim_tracker = create_dimension_tracker()
@@ -1082,14 +1142,10 @@
1082
1142
  const should_show = show_legend !== undefined ? show_legend : series.length > 1
1083
1143
  if (!should_show || !width || !height) return null
1084
1144
 
1085
- // Use measured size if available, otherwise estimate
1086
- const legend_size = legend_element
1087
- ? { width: legend_element.offsetWidth, height: legend_element.offsetHeight }
1088
- : { width: 120, height: 60 }
1089
-
1090
1145
  const result = compute_element_placement({
1091
1146
  plot_bounds: { x: pad.l, y: pad.t, width: chart_width, height: chart_height },
1092
- element_size: legend_size,
1147
+ element: legend_element,
1148
+ element_size: { width: 120, height: 60 }, // fallback before first render
1093
1149
  axis_clearance: legend?.axis_clearance,
1094
1150
  exclude_rects: [],
1095
1151
  points: bar_points_for_placement,
@@ -1178,7 +1234,9 @@
1178
1234
  evt: MouseEvent,
1179
1235
  points: LineSeriesPoint[],
1180
1236
  ): LineSeriesPoint | null {
1181
- const svg_el = (evt.target as Element).closest(`svg`)
1237
+ const target = evt.target
1238
+ if (!(target instanceof Element)) return null
1239
+ const svg_el = target.closest(`svg`)
1182
1240
  if (!svg_el) return null
1183
1241
  const rect = svg_el.getBoundingClientRect()
1184
1242
  const mx = evt.clientX - rect.left
@@ -1424,304 +1482,87 @@
1424
1482
  {@render ref_lines_layer(ref_lines_by_z.below_grid)}
1425
1483
 
1426
1484
  <!-- X-axis -->
1427
- <g class="x-axis">
1428
- <line
1429
- x1={pad.l}
1430
- x2={width - pad.r}
1431
- y1={height - pad.b}
1432
- y2={height - pad.b}
1433
- stroke={x_axis.color || `var(--border-color, gray)`}
1434
- stroke-width="1"
1435
- />
1436
- {#each ticks.x as tick (tick)}
1437
- {@const tick_x = scales.x(tick as number)}
1438
- {#if isFinite(tick_x)}
1439
- {@const rotation = x_axis.tick?.label?.rotation ?? 0}
1440
- {@const shift_x = x_axis.tick?.label?.shift?.x ?? 0}
1441
- {@const shift_y = x_axis.tick?.label?.shift?.y ?? 0}
1442
- {@const inside = x_axis.tick?.label?.inside ?? false}
1443
- {@const base_y = inside ? -8 : (rotation !== 0 ? 8 : 18)}
1444
- {@const text_y = base_y + shift_y}
1445
- {@const text_anchor = rotation !== 0 ? (inside ? `end` : `start`) : `middle`}
1446
- {@const dominant_baseline = inside ? `auto` : `hanging`}
1447
- <g class="tick" transform="translate({tick_x}, {height - pad.b})">
1448
- {#if display.x_grid}
1449
- <line
1450
- y1={-(height - pad.b - pad.t)}
1451
- y2="0"
1452
- {...DEFAULT_GRID_STYLE}
1453
- {...x_axis.grid_style}
1454
- />
1455
- {/if}
1456
- <line
1457
- y1="0"
1458
- y2={inside ? -5 : 5}
1459
- stroke={x_axis.color || `var(--border-color, gray)`}
1460
- stroke-width="1"
1461
- />
1462
- <text
1463
- x={shift_x}
1464
- y={text_y}
1465
- text-anchor={text_anchor}
1466
- dominant-baseline={dominant_baseline}
1467
- fill={x_axis.color || `var(--text-color)`}
1468
- transform={rotation !== 0
1469
- ? `rotate(${rotation}, ${shift_x}, ${text_y})`
1470
- : undefined}
1471
- >
1472
- {
1473
- get_tick_label(
1474
- tick as number,
1475
- cat_axis === `x` ? effective_cat_ticks : x_axis.ticks,
1476
- ) ??
1477
- format_value(tick, x_axis.format)
1478
- }
1479
- </text>
1480
- </g>
1481
- {/if}
1482
- {/each}
1483
- {#if x_axis.label || x_axis.options?.length}
1484
- {@const { label_shift, label = ``, options, selected_key, color } = x_axis}
1485
- <AxisLabel
1486
- x={pad.l + chart_width / 2 + (label_shift?.x ?? 0)}
1487
- y={height - (pad.b / 3) + (label_shift?.y ?? 0)}
1488
- {label}
1489
- {options}
1490
- {selected_key}
1491
- loading={axis_loading === `x`}
1492
- axis_type="x"
1493
- {color}
1494
- on_select={(key) => handle_axis_change(`x`, key)}
1495
- />
1496
- {/if}
1497
- </g>
1485
+ <PlotAxis
1486
+ side="x"
1487
+ ticks={ticks.x as number[]}
1488
+ place={scales.x}
1489
+ axis={x_axis}
1490
+ {pad}
1491
+ {width}
1492
+ {height}
1493
+ show_grid={display.x_grid}
1494
+ tick_label={(tick) =>
1495
+ get_tick_label(tick, cat_axis === `x` ? effective_cat_ticks : x_axis.ticks)}
1496
+ label_x={pad.l + chart_width / 2 + (x_axis.label_shift?.x ?? 0)}
1497
+ label_y={height - pad.b / 3 + (x_axis.label_shift?.y ?? 0)}
1498
+ axis_loading={axis_loading === `x`}
1499
+ on_axis_change={(key) => handle_axis_change(`x`, key)}
1500
+ />
1498
1501
 
1499
1502
  <!-- X2-axis (Top) -->
1500
1503
  <!-- Note: x2 axis is only supported for vertical orientation -->
1501
1504
  {#if x2_series.length > 0 && orientation === `vertical`}
1502
- <g class="x2-axis">
1503
- <line
1504
- x1={pad.l}
1505
- x2={width - pad.r}
1506
- y1={pad.t}
1507
- y2={pad.t}
1508
- stroke={x2_axis.color || `var(--border-color, gray)`}
1509
- stroke-width="1"
1510
- />
1511
- {#each ticks.x2 as tick (tick)}
1512
- {@const tick_x = scales.x2(tick as number)}
1513
- {#if isFinite(tick_x)}
1514
- {@const rotation = x2_axis.tick?.label?.rotation ?? 0}
1515
- {@const shift_x = x2_axis.tick?.label?.shift?.x ?? 0}
1516
- {@const shift_y = x2_axis.tick?.label?.shift?.y ?? 0}
1517
- {@const inside = x2_axis.tick?.label?.inside ?? false}
1518
- {@const base_y = inside ? 8 : (rotation !== 0 ? -8 : -18)}
1519
- {@const text_y = base_y + shift_y}
1520
- {@const text_anchor = rotation !== 0 ? (inside ? `start` : `end`) : `middle`}
1521
- {@const dominant_baseline = inside ? `hanging` : `auto`}
1522
- <g class="tick" transform="translate({tick_x}, {pad.t})">
1523
- {#if display.x2_grid}
1524
- <line
1525
- y1="0"
1526
- y2={height - pad.b - pad.t}
1527
- {...DEFAULT_GRID_STYLE}
1528
- {...x2_axis.grid_style}
1529
- />
1530
- {/if}
1531
- <line
1532
- y1={inside ? 5 : 0}
1533
- y2={inside ? 0 : -5}
1534
- stroke={x2_axis.color || `var(--border-color, gray)`}
1535
- stroke-width="1"
1536
- />
1537
- <text
1538
- x={shift_x}
1539
- y={text_y}
1540
- text-anchor={text_anchor}
1541
- dominant-baseline={dominant_baseline}
1542
- fill={x2_axis.color || `var(--text-color)`}
1543
- transform={rotation !== 0
1544
- ? `rotate(${rotation}, ${shift_x}, ${text_y})`
1545
- : undefined}
1546
- >
1547
- {
1548
- get_tick_label(tick as number, x2_axis.ticks) ??
1549
- format_value(tick, x2_axis.format)
1550
- }
1551
- </text>
1552
- </g>
1553
- {/if}
1554
- {/each}
1555
- {#if x2_axis.label || x2_axis.options?.length}
1556
- {@const { label_shift, label = ``, options, selected_key, color } = x2_axis}
1557
- <AxisLabel
1558
- x={pad.l + chart_width / 2 + (label_shift?.x ?? 0)}
1559
- y={Math.max(12, pad.t - (label_shift?.y ?? 40))}
1560
- {label}
1561
- {options}
1562
- {selected_key}
1563
- loading={axis_loading === `x2`}
1564
- axis_type="x2"
1565
- {color}
1566
- on_select={(key) => handle_axis_change(`x2`, key)}
1567
- />
1568
- {/if}
1569
- </g>
1505
+ <PlotAxis
1506
+ side="x2"
1507
+ ticks={ticks.x2 as number[]}
1508
+ place={scales.x2}
1509
+ axis={x2_axis}
1510
+ {pad}
1511
+ {width}
1512
+ {height}
1513
+ show_grid={display.x2_grid}
1514
+ tick_label={(tick) => get_tick_label(tick, x2_axis.ticks)}
1515
+ label_x={pad.l + chart_width / 2 + (x2_axis.label_shift?.x ?? 0)}
1516
+ label_y={Math.max(12, pad.t - (x2_axis.label_shift?.y ?? 40))}
1517
+ axis_loading={axis_loading === `x2`}
1518
+ on_axis_change={(key) => handle_axis_change(`x2`, key)}
1519
+ />
1570
1520
  {/if}
1571
1521
 
1572
1522
  <!-- Y-axis -->
1573
- <g class="y-axis">
1574
- <line
1575
- x1={pad.l}
1576
- x2={pad.l}
1577
- y1={pad.t}
1578
- y2={height - pad.b}
1579
- stroke={y_axis.color || `var(--border-color, gray)`}
1580
- stroke-width="1"
1581
- />
1582
- {#each ticks.y as tick (tick)}
1583
- {@const tick_y = scales.y(tick as number)}
1584
- {#if isFinite(tick_y)}
1585
- {@const rotation = y_axis.tick?.label?.rotation ?? 0}
1586
- {@const shift_x = y_axis.tick?.label?.shift?.x ?? 0}
1587
- {@const shift_y = y_axis.tick?.label?.shift?.y ?? 0}
1588
- {@const inside = y_axis.tick?.label?.inside ?? false}
1589
- {@const base_x = inside ? 8 : -10}
1590
- {@const text_x = base_x + shift_x}
1591
- {@const text_anchor = inside ? `start` : `end`}
1592
- <g class="tick" transform="translate({pad.l}, {tick_y})">
1593
- {#if display.y_grid}
1594
- <line
1595
- x1="0"
1596
- x2={width - pad.l - pad.r}
1597
- {...DEFAULT_GRID_STYLE}
1598
- {...y_axis.grid_style}
1599
- />
1600
- {/if}
1601
- <line
1602
- x1={inside ? 0 : -5}
1603
- x2={inside ? 5 : 0}
1604
- stroke={y_axis.color || `var(--border-color, gray)`}
1605
- stroke-width="1"
1606
- />
1607
- <text
1608
- x={text_x}
1609
- y={shift_y}
1610
- text-anchor={text_anchor}
1611
- dominant-baseline="central"
1612
- fill={y_axis.color || `var(--text-color)`}
1613
- transform={rotation !== 0
1614
- ? `rotate(${rotation}, ${text_x}, ${shift_y})`
1615
- : undefined}
1616
- >
1617
- {
1618
- get_tick_label(
1619
- tick as number,
1620
- cat_axis === `y` ? effective_cat_ticks : y_axis.ticks,
1621
- ) ??
1622
- format_value(tick, y_axis.format)
1623
- }
1624
- </text>
1625
- </g>
1626
- {/if}
1627
- {/each}
1628
- {#if y_axis.label || y_axis.options?.length}
1629
- {@const { label_shift, label = ``, options, selected_key, color, tick } = y_axis}
1630
- {@const y_inside = tick?.label?.inside ?? false}
1631
- <AxisLabel
1632
- x={Math.max(
1633
- 12,
1634
- pad.l - (y_inside ? 0 : tick_label_widths.y_max) - LABEL_GAP_DEFAULT,
1635
- ) +
1636
- (label_shift?.x ?? 0)}
1637
- y={pad.t + chart_height / 2 + (label_shift?.y ?? 0)}
1638
- rotate
1639
- {label}
1640
- {options}
1641
- {selected_key}
1642
- loading={axis_loading === `y`}
1643
- axis_type="y"
1644
- {color}
1645
- on_select={(key) => handle_axis_change(`y`, key)}
1646
- />
1647
- {/if}
1648
- </g>
1523
+ <PlotAxis
1524
+ side="y"
1525
+ ticks={ticks.y as number[]}
1526
+ place={scales.y}
1527
+ axis={y_axis}
1528
+ {pad}
1529
+ {width}
1530
+ {height}
1531
+ show_grid={display.y_grid}
1532
+ tick_label={(tick) =>
1533
+ get_tick_label(tick, cat_axis === `y` ? effective_cat_ticks : y_axis.ticks)}
1534
+ label_x={Math.max(
1535
+ 12,
1536
+ pad.l - (y_axis.tick?.label?.inside ? 0 : tick_label_widths.y_max) -
1537
+ LABEL_GAP_DEFAULT,
1538
+ ) + (y_axis.label_shift?.x ?? 0)}
1539
+ label_y={pad.t + chart_height / 2 + (y_axis.label_shift?.y ?? 0)}
1540
+ axis_loading={axis_loading === `y`}
1541
+ on_axis_change={(key) => handle_axis_change(`y`, key)}
1542
+ />
1649
1543
 
1650
1544
  <!-- Y2-axis (Right) -->
1651
1545
  <!-- Note: y2 axis is only supported for vertical orientation. Implementing x2 for horizontal mode requires additional complexity. -->
1652
1546
  {#if y2_series.length > 0 && orientation === `vertical`}
1653
- <g class="y2-axis">
1654
- <line
1655
- x1={width - pad.r}
1656
- x2={width - pad.r}
1657
- y1={pad.t}
1658
- y2={height - pad.b}
1659
- stroke={y2_axis.color || `var(--border-color, gray)`}
1660
- stroke-width="1"
1661
- />
1662
- {#each ticks.y2 as tick (tick)}
1663
- {@const tick_y = scales.y2(tick as number)}
1664
- {#if isFinite(tick_y)}
1665
- {@const rotation = y2_axis.tick?.label?.rotation ?? 0}
1666
- {@const inside = y2_axis.tick?.label?.inside ?? false}
1667
- {@const base_x = inside ? -8 : 8}
1668
- {@const shift_x = (y2_axis.tick?.label?.shift?.x ?? 0) + base_x}
1669
- {@const shift_y = y2_axis.tick?.label?.shift?.y ?? 0}
1670
- {@const text_anchor = inside ? `end` : `start`}
1671
- <g class="tick" transform="translate({width - pad.r}, {tick_y})">
1672
- {#if display.y2_grid}
1673
- <line
1674
- x1={-(width - pad.l - pad.r)}
1675
- x2="0"
1676
- {...DEFAULT_GRID_STYLE}
1677
- {...y2_axis.grid_style}
1678
- />
1679
- {/if}
1680
- <line
1681
- x1={inside ? -5 : 0}
1682
- x2={inside ? 0 : 5}
1683
- stroke={y2_axis.color || `var(--border-color, gray)`}
1684
- stroke-width="1"
1685
- />
1686
- <text
1687
- x={shift_x}
1688
- y={shift_y}
1689
- text-anchor={text_anchor}
1690
- dominant-baseline="central"
1691
- fill={y2_axis.color || `var(--text-color)`}
1692
- transform={rotation !== 0
1693
- ? `rotate(${rotation}, ${shift_x}, ${shift_y})`
1694
- : undefined}
1695
- >
1696
- {
1697
- get_tick_label(tick as number, y2_axis.ticks) ??
1698
- format_value(tick, y2_axis.format)
1699
- }
1700
- </text>
1701
- </g>
1702
- {/if}
1703
- {/each}
1704
- {#if y2_axis.label || y2_axis.options?.length}
1705
- {@const { label_shift, label = ``, options, selected_key, color, tick } =
1706
- y2_axis}
1707
- {@const inside = tick?.label?.inside ?? false}
1708
- {@const tick_shift = inside ? 0 : (tick?.label?.shift?.x ?? 0) + 8}
1709
- {@const tick_width_contribution = inside ? 0 : tick_label_widths.y2_max}
1710
- <AxisLabel
1711
- x={width - pad.r + tick_shift + tick_width_contribution +
1712
- LABEL_GAP_DEFAULT + (label_shift?.x ?? 0)}
1713
- y={pad.t + chart_height / 2 + (label_shift?.y ?? 0)}
1714
- rotate
1715
- {label}
1716
- {options}
1717
- {selected_key}
1718
- loading={axis_loading === `y2`}
1719
- axis_type="y2"
1720
- {color}
1721
- on_select={(key) => handle_axis_change(`y2`, key)}
1722
- />
1723
- {/if}
1724
- </g>
1547
+ {@const y2_inside = y2_axis.tick?.label?.inside ?? false}
1548
+ {@const y2_tick_shift = y2_inside ? 0 : (y2_axis.tick?.label?.shift?.x ?? 0) + 8}
1549
+ {@const y2_tick_width = y2_inside ? 0 : tick_label_widths.y2_max}
1550
+ <PlotAxis
1551
+ side="y2"
1552
+ ticks={ticks.y2 as number[]}
1553
+ place={scales.y2}
1554
+ axis={y2_axis}
1555
+ {pad}
1556
+ {width}
1557
+ {height}
1558
+ show_grid={display.y2_grid}
1559
+ tick_label={(tick) => get_tick_label(tick, y2_axis.ticks)}
1560
+ label_x={width - pad.r + y2_tick_shift + y2_tick_width + LABEL_GAP_DEFAULT +
1561
+ (y2_axis.label_shift?.x ?? 0)}
1562
+ label_y={pad.t + chart_height / 2 + (y2_axis.label_shift?.y ?? 0)}
1563
+ axis_loading={axis_loading === `y2`}
1564
+ on_axis_change={(key) => handle_axis_change(`y2`, key)}
1565
+ />
1725
1566
  {/if}
1726
1567
 
1727
1568
  <!-- Define clip path for chart area -->
@@ -2084,6 +1925,16 @@
2084
1925
 
2085
1926
  <!-- Legend -->
2086
1927
  {#if legend && (show_legend !== undefined ? show_legend : series.length > 1)}
1928
+ {@const legend_left = legend_auto_outside
1929
+ ? legend_outside_x
1930
+ : legend_placement
1931
+ ? tweened_legend_coords.current.x
1932
+ : pad.l + 10}
1933
+ {@const legend_top = legend_auto_outside
1934
+ ? legend_outside_y
1935
+ : legend_placement
1936
+ ? tweened_legend_coords.current.y
1937
+ : pad.t + 10}
2087
1938
  <PlotLegend
2088
1939
  bind:root_element={legend_element}
2089
1940
  {...legend}
@@ -2098,8 +1949,8 @@
2098
1949
  active_series_idx={hover_info?.series_idx ?? hovered_legend_series_idx}
2099
1950
  style={`
2100
1951
  position: absolute;
2101
- left: ${legend_placement ? tweened_legend_coords.current.x : pad.l + 10}px;
2102
- top: ${legend_placement ? tweened_legend_coords.current.y : pad.t + 10}px;
1952
+ left: ${legend_left}px;
1953
+ top: ${legend_top}px;
2103
1954
  pointer-events: auto;
2104
1955
  ${legend?.style || ``}
2105
1956
  `}
@@ -2255,9 +2106,6 @@
2255
2106
  border: var(--barplot-dragover-border, var(--dragover-border));
2256
2107
  background-color: var(--barplot-dragover-bg, var(--dragover-bg));
2257
2108
  }
2258
- g:is(.x-axis, .x2-axis, .y-axis, .y2-axis) .tick text {
2259
- font-size: var(--tick-font-size, 0.8em);
2260
- }
2261
2109
  .bar-label {
2262
2110
  fill: var(--text-color);
2263
2111
  font-size: 11px;
@@ -1,5 +1,6 @@
1
1
  import type { D3ColorSchemeName, D3InterpolateName } from '../colors';
2
- import type { AxisLoadError, BarHandlerProps, BarMode, BarSeries, BarStyle, BasePlotProps, DataLoaderFn, InternalPoint, LegendConfig, LineStyle, Orientation, PanConfig, PlotConfig, RefLine, RefLineEvent, ScaleType, UserContentProps, XyObj } from './';
2
+ import type { Point2D } from '../math';
3
+ import type { AxisLoadError, BarHandlerProps, BarMode, BarSeries, BarStyle, BasePlotProps, DataLoaderFn, InternalPoint, LegendConfig, LineStyle, Orientation, PanConfig, PlotConfig, RefLine, RefLineEvent, ScaleType, UserContentProps } from './';
3
4
  import type { Snippet } from 'svelte';
4
5
  import type { HTMLAttributes } from 'svelte/elements';
5
6
  import { type TweenOptions } from 'svelte/motion';
@@ -40,7 +41,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
40
41
  radius_range?: [number, number];
41
42
  value_range?: [number, number];
42
43
  };
43
- point_tween?: TweenOptions<XyObj>;
44
+ point_tween?: TweenOptions<Point2D>;
44
45
  on_point_click?: (data: (BarHandlerProps<Metadata> & {
45
46
  point: InternalPoint<Metadata>;
46
47
  }) & {
@@ -60,7 +61,7 @@ declare function $$render<Metadata extends Record<string, unknown> = Record<stri
60
61
  pan?: PanConfig;
61
62
  };
62
63
  exports: {};
63
- bindings: "orientation" | "display" | "mode" | "fullscreen" | "series" | "hovered" | "ref_lines" | "show_controls" | "controls_open" | "x_axis" | "y_axis" | "x2_axis" | "y2_axis";
64
+ bindings: "orientation" | "display" | "mode" | "show_controls" | "x_axis" | "y_axis" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x2_axis" | "y2_axis";
64
65
  slots: {};
65
66
  events: {};
66
67
  };
@@ -68,7 +69,7 @@ declare class __sveltets_Render<Metadata extends Record<string, unknown> = Recor
68
69
  props(): ReturnType<typeof $$render<Metadata>>['props'];
69
70
  events(): ReturnType<typeof $$render<Metadata>>['events'];
70
71
  slots(): ReturnType<typeof $$render<Metadata>>['slots'];
71
- bindings(): "orientation" | "display" | "mode" | "fullscreen" | "series" | "hovered" | "ref_lines" | "show_controls" | "controls_open" | "x_axis" | "y_axis" | "x2_axis" | "y2_axis";
72
+ bindings(): "orientation" | "display" | "mode" | "show_controls" | "x_axis" | "y_axis" | "fullscreen" | "series" | "hovered" | "ref_lines" | "controls_open" | "x2_axis" | "y2_axis";
72
73
  exports(): {};
73
74
  }
74
75
  interface $$IsomorphicComponent {
@@ -13,6 +13,6 @@ type $$ComponentProps = Omit<PlotControlsProps, `children` | `post_children`> &
13
13
  } & Required<PlotConfig>
14
14
  ]>;
15
15
  };
16
- declare const BarPlotControls: import("svelte").Component<$$ComponentProps, {}, "orientation" | "display" | "mode" | "show_controls" | "controls_open" | "x_axis" | "y_axis" | "x2_axis" | "y2_axis">;
16
+ declare const BarPlotControls: import("svelte").Component<$$ComponentProps, {}, "orientation" | "display" | "mode" | "show_controls" | "x_axis" | "y_axis" | "controls_open" | "x2_axis" | "y2_axis">;
17
17
  type BarPlotControls = ReturnType<typeof BarPlotControls>;
18
18
  export default BarPlotControls;