layerchart 2.0.0-next.44 → 2.0.0-next.46

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 (179) hide show
  1. package/LICENSE +1 -1
  2. package/dist/components/AnnotationLine.svelte +1 -1
  3. package/dist/components/AnnotationPoint.svelte +1 -1
  4. package/dist/components/AnnotationRange.svelte +16 -15
  5. package/dist/components/Arc.svelte +10 -10
  6. package/dist/components/Arc.svelte.d.ts +4 -4
  7. package/dist/components/Arc.svelte.test.d.ts +1 -0
  8. package/dist/components/Arc.svelte.test.js +868 -0
  9. package/dist/components/Area.svelte +9 -7
  10. package/dist/components/Axis.svelte +2 -1
  11. package/dist/components/Axis.svelte.d.ts +1 -0
  12. package/dist/components/Bar.svelte +3 -3
  13. package/dist/components/Bars.svelte +1 -1
  14. package/dist/components/Blur.svelte +3 -3
  15. package/dist/components/Bounds.svelte +1 -1
  16. package/dist/components/BrushContext.svelte +1 -1
  17. package/dist/components/Calendar.svelte +2 -2
  18. package/dist/components/Calendar.svelte.d.ts +1 -1
  19. package/dist/components/Chart.svelte +63 -137
  20. package/dist/components/Chart.svelte.d.ts +23 -88
  21. package/dist/components/ChartClipPath.svelte +1 -1
  22. package/dist/components/Circle.svelte +17 -8
  23. package/dist/components/Circle.svelte.d.ts +3 -0
  24. package/dist/components/ClipPath.svelte +4 -4
  25. package/dist/components/Connector.svelte +4 -4
  26. package/dist/components/Connector.svelte.d.ts +3 -3
  27. package/dist/components/Ellipse.svelte +7 -7
  28. package/dist/components/Frame.svelte +1 -1
  29. package/dist/components/GeoContext.svelte +4 -20
  30. package/dist/components/GeoContext.svelte.d.ts +2 -6
  31. package/dist/components/GeoEdgeFade.svelte +1 -1
  32. package/dist/components/GeoPath.svelte +42 -107
  33. package/dist/components/GeoPath.svelte.d.ts +5 -4
  34. package/dist/components/GeoPoint.svelte +5 -5
  35. package/dist/components/GeoSpline.svelte +2 -14
  36. package/dist/components/GeoSpline.svelte.d.ts +1 -1
  37. package/dist/components/GeoTile.svelte +7 -6
  38. package/dist/components/GeoVisible.svelte +1 -1
  39. package/dist/components/Graticule.svelte +4 -7
  40. package/dist/components/Graticule.svelte.d.ts +2 -1
  41. package/dist/components/Grid.svelte +1 -1
  42. package/dist/components/Group.svelte +8 -8
  43. package/dist/components/Highlight.svelte +18 -16
  44. package/dist/components/Hull.svelte +2 -2
  45. package/dist/components/Labels.svelte +1 -1
  46. package/dist/components/Legend.svelte +1 -1
  47. package/dist/components/Line.svelte +9 -7
  48. package/dist/components/LinearGradient.svelte +8 -7
  49. package/dist/components/MonthPath.svelte +5 -11
  50. package/dist/components/MonthPath.svelte.d.ts +2 -2
  51. package/dist/components/Pack.svelte +4 -6
  52. package/dist/components/Pack.svelte.d.ts +2 -4
  53. package/dist/components/Partition.svelte +4 -3
  54. package/dist/components/Partition.svelte.d.ts +2 -1
  55. package/dist/components/Path.svelte +344 -0
  56. package/dist/components/Path.svelte.d.ts +72 -0
  57. package/dist/components/Pattern.svelte +6 -6
  58. package/dist/components/Pie.svelte +2 -2
  59. package/dist/components/Pie.svelte.d.ts +1 -1
  60. package/dist/components/Point.svelte +1 -1
  61. package/dist/components/Points.svelte +1 -1
  62. package/dist/components/Polygon.svelte +8 -6
  63. package/dist/components/RadialGradient.svelte +7 -7
  64. package/dist/components/Rect.svelte +32 -10
  65. package/dist/components/Rect.svelte.d.ts +4 -1
  66. package/dist/components/Rule.svelte +1 -1
  67. package/dist/components/Sankey.svelte +1 -1
  68. package/dist/components/Spline.svelte +13 -337
  69. package/dist/components/Spline.svelte.d.ts +10 -73
  70. package/dist/components/Text.svelte +9 -7
  71. package/dist/components/Threshold.svelte +3 -3
  72. package/dist/components/TransformContext.svelte +10 -143
  73. package/dist/components/TransformControls.svelte +2 -2
  74. package/dist/components/TransformControls.svelte.d.ts +1 -1
  75. package/dist/components/Tree.svelte +4 -3
  76. package/dist/components/Tree.svelte.d.ts +2 -1
  77. package/dist/components/Treemap.svelte +4 -3
  78. package/dist/components/Treemap.svelte.d.ts +2 -1
  79. package/dist/components/Voronoi.svelte +5 -5
  80. package/dist/components/charts/ArcChart.svelte +14 -6
  81. package/dist/components/charts/ArcChart.svelte.d.ts +1 -1
  82. package/dist/components/charts/AreaChart.svelte +12 -6
  83. package/dist/components/charts/BarChart.svelte +12 -6
  84. package/dist/components/charts/DefaultTooltip.svelte +1 -1
  85. package/dist/components/charts/LineChart.svelte +12 -6
  86. package/dist/components/charts/PieChart.svelte +14 -6
  87. package/dist/components/charts/PieChart.svelte.d.ts +1 -1
  88. package/dist/components/charts/ScatterChart.svelte +11 -9
  89. package/dist/components/charts/types.d.ts +7 -6
  90. package/dist/components/index.d.ts +14 -12
  91. package/dist/components/index.js +14 -12
  92. package/dist/components/{layout → layers}/Canvas.svelte +13 -60
  93. package/dist/components/{layout → layers}/Canvas.svelte.d.ts +2 -32
  94. package/dist/components/{layout → layers}/Html.svelte +18 -3
  95. package/dist/components/{layout → layers}/Html.svelte.d.ts +7 -0
  96. package/dist/components/layers/Layer.svelte +85 -0
  97. package/dist/components/{layout → layers}/Layer.svelte.d.ts +7 -3
  98. package/dist/components/{layout → layers}/Svg.svelte +18 -3
  99. package/dist/components/{layout → layers}/Svg.svelte.d.ts +7 -0
  100. package/dist/components/{layout → layers}/WebGL.svelte +1 -1
  101. package/dist/components/{layout → layers}/WebGL.svelte.d.ts +3 -3
  102. package/dist/components/tests/TestHarness.svelte +76 -0
  103. package/dist/components/tests/TestHarness.svelte.d.ts +19 -0
  104. package/dist/components/tooltip/Tooltip.svelte +3 -3
  105. package/dist/components/tooltip/Tooltip.svelte.d.ts +1 -1
  106. package/dist/components/tooltip/TooltipContext.svelte +13 -45
  107. package/dist/components/tooltip/TooltipContext.svelte.d.ts +2 -14
  108. package/dist/components/tooltip/tooltipMetaContext.d.ts +2 -2
  109. package/dist/components/tooltip/tooltipMetaContext.js +2 -2
  110. package/dist/contexts/canvas.d.ts +33 -0
  111. package/dist/contexts/canvas.js +14 -0
  112. package/dist/contexts/chart.d.ts +84 -0
  113. package/dist/contexts/chart.js +10 -0
  114. package/dist/contexts/geo.d.ts +6 -0
  115. package/dist/contexts/geo.js +12 -0
  116. package/dist/contexts/index.d.ts +6 -0
  117. package/dist/contexts/index.js +6 -0
  118. package/dist/contexts/layer.d.ts +3 -0
  119. package/dist/contexts/layer.js +8 -0
  120. package/dist/contexts/settings.d.ts +4 -0
  121. package/dist/contexts/settings.js +10 -0
  122. package/dist/contexts/tooltip.d.ts +15 -0
  123. package/dist/contexts/tooltip.js +8 -0
  124. package/dist/contexts/transform.d.ts +95 -0
  125. package/dist/contexts/transform.js +10 -0
  126. package/dist/index.d.ts +1 -0
  127. package/dist/index.js +1 -0
  128. package/dist/states/settings.svelte.d.ts +12 -0
  129. package/dist/states/settings.svelte.js +10 -0
  130. package/dist/states/transform.svelte.d.ts +9 -0
  131. package/dist/states/transform.svelte.js +31 -0
  132. package/dist/utils/arcText.svelte.d.ts +1 -1
  133. package/dist/utils/canvas.d.ts +7 -3
  134. package/dist/utils/canvas.js +78 -11
  135. package/dist/utils/common.d.ts +8 -1
  136. package/dist/utils/common.js +9 -10
  137. package/dist/utils/index.d.ts +2 -0
  138. package/dist/utils/index.js +2 -0
  139. package/dist/utils/motion.svelte.js +0 -1
  140. package/dist/utils/rect.svelte.d.ts +1 -1
  141. package/dist/utils/rect.svelte.js +17 -9
  142. package/dist/utils/scales.svelte.js +2 -2
  143. package/dist/utils/string.d.ts +3 -1
  144. package/package.json +32 -54
  145. package/README.md +0 -41
  146. package/dist/components/layout/Layer.svelte +0 -41
  147. package/dist/docs/Blockquote.svelte +0 -17
  148. package/dist/docs/Blockquote.svelte.d.ts +0 -5
  149. package/dist/docs/Code.svelte +0 -80
  150. package/dist/docs/Code.svelte.d.ts +0 -14
  151. package/dist/docs/ConnectorSweepMenuField.svelte +0 -17
  152. package/dist/docs/ConnectorSweepMenuField.svelte.d.ts +0 -7
  153. package/dist/docs/ConnectorTypeMenuField.svelte +0 -17
  154. package/dist/docs/ConnectorTypeMenuField.svelte.d.ts +0 -7
  155. package/dist/docs/CurveMenuField.svelte +0 -44
  156. package/dist/docs/CurveMenuField.svelte.d.ts +0 -9
  157. package/dist/docs/GeoDebug.svelte +0 -60
  158. package/dist/docs/GeoDebug.svelte.d.ts +0 -4
  159. package/dist/docs/Header1.svelte +0 -16
  160. package/dist/docs/Header1.svelte.d.ts +0 -5
  161. package/dist/docs/Json.svelte +0 -36
  162. package/dist/docs/Json.svelte.d.ts +0 -10
  163. package/dist/docs/Layout.svelte +0 -21
  164. package/dist/docs/Layout.svelte.d.ts +0 -8
  165. package/dist/docs/Link.svelte +0 -9
  166. package/dist/docs/Link.svelte.d.ts +0 -5
  167. package/dist/docs/PathDataMenuField.svelte +0 -78
  168. package/dist/docs/PathDataMenuField.svelte.d.ts +0 -9
  169. package/dist/docs/Preview.svelte +0 -104
  170. package/dist/docs/Preview.svelte.d.ts +0 -13
  171. package/dist/docs/TilesetField.svelte +0 -136
  172. package/dist/docs/TilesetField.svelte.d.ts +0 -6
  173. package/dist/docs/TransformDebug.svelte +0 -22
  174. package/dist/docs/TransformDebug.svelte.d.ts +0 -20
  175. package/dist/docs/ViewSourceButton.svelte +0 -53
  176. package/dist/docs/ViewSourceButton.svelte.d.ts +0 -11
  177. package/dist/utils/graph/dagre.d.ts +0 -34
  178. /package/dist/{utils → contexts}/legendPayload.d.ts +0 -0
  179. /package/dist/{utils → contexts}/legendPayload.js +0 -0
@@ -0,0 +1,95 @@
1
+ import { type TransformMode, type TransformScrollMode } from '../states/transform.svelte.js';
2
+ import type { MotionProp } from '../utils/motion.svelte.js';
3
+ export type TransformContextValue = {
4
+ /**
5
+ * The current transform mode.
6
+ *
7
+ * - `canvas`: The transform is applied to the canvas element.
8
+ * - `manual`: The transform is applied manually.
9
+ * - `none`: No transform is applied.
10
+ */
11
+ mode: TransformMode;
12
+ /**
13
+ * The current scale of the transform.
14
+ */
15
+ scale: number;
16
+ /**
17
+ * Set the scale of the transform
18
+ * @param value - the scale value to set
19
+ * @param options - motion options to apply to the transform (defaults to the motion options passed to the component)
20
+ */
21
+ setScale(value: number, options?: MotionProp): void;
22
+ /**
23
+ * The current translate of the transform.
24
+ */
25
+ translate: {
26
+ x: number;
27
+ y: number;
28
+ };
29
+ /**
30
+ * Set the translate of the transform
31
+ * @param point - the point to translate to
32
+ * @param options - motion options to apply to the transform (defaults to the motion options passed to the component)
33
+ */
34
+ setTranslate(point: {
35
+ x: number;
36
+ y: number;
37
+ }, options?: MotionProp): void;
38
+ /**
39
+ * Whether the transform is currently being moved
40
+ */
41
+ moving: boolean;
42
+ /**
43
+ * Whether the transform is currently being dragged
44
+ */
45
+ dragging: boolean;
46
+ /**
47
+ * The scroll mode of the transform.
48
+ *
49
+ * - `scale`: Scrolling will zoom in/out the canvas.
50
+ * - `translate`: Scrolling will pan the canvas.
51
+ * - `none`: No scroll mode is applied.
52
+ */
53
+ scrollMode: TransformScrollMode;
54
+ /**
55
+ * Set the scroll mode of the transform
56
+ *
57
+ * @param mode - the scroll mode to set
58
+ */
59
+ setScrollMode(mode: TransformScrollMode): void;
60
+ /**
61
+ * Reset the transform to its initial state
62
+ */
63
+ reset(): void;
64
+ /**
65
+ * Zoom in the transform
66
+ */
67
+ zoomIn(): void;
68
+ /**
69
+ * Zoom out the transform
70
+ *
71
+ */
72
+ zoomOut(): void;
73
+ /**
74
+ * Translate the transform to the center of the canvas
75
+ */
76
+ translateCenter(): void;
77
+ /**
78
+ * Zoom to a specific point in the canvas
79
+ *
80
+ * @param center - The point (in chart coordinates) that should become the new
81
+ * center of the view after zooming.
82
+ *
83
+ * @param rect - A rectangular region (in chart coordinates) that the view should scale to fit.
84
+ * If omitted, the scale defaults to 1 (no zoom).
85
+ */
86
+ zoomTo(center: {
87
+ x: number;
88
+ y: number;
89
+ }, rect?: {
90
+ width: number;
91
+ height: number;
92
+ }): void;
93
+ };
94
+ export declare function getTransformContext(): TransformContextValue;
95
+ export declare function setTransformContext(transform: TransformContextValue): TransformContextValue;
@@ -0,0 +1,10 @@
1
+ import { Context } from 'runed';
2
+ import {} from '../components/TransformContext.svelte';
3
+ import { createDefaultTransformContext, } from '../states/transform.svelte.js';
4
+ const _TransformContext = new Context('TransformContext');
5
+ export function getTransformContext() {
6
+ return _TransformContext.getOr(createDefaultTransformContext());
7
+ }
8
+ export function setTransformContext(transform) {
9
+ return _TransformContext.set(transform);
10
+ }
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './components/index.js';
2
+ export * from './contexts/index.js';
2
3
  export * from './utils/index.js';
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './components/index.js';
2
+ export * from './contexts/index.js';
2
3
  export * from './utils/index.js';
@@ -0,0 +1,12 @@
1
+ import type { LayerContext } from '../contexts/layer.js';
2
+ export type SettingsOptions = {
3
+ layer?: LayerContext;
4
+ debug?: boolean;
5
+ };
6
+ /** Global settings context for charts */
7
+ export declare class Settings {
8
+ layer: LayerContext;
9
+ debug: boolean;
10
+ constructor(options?: SettingsOptions);
11
+ }
12
+ export declare const defaultSettings: Settings;
@@ -0,0 +1,10 @@
1
+ /** Global settings context for charts */
2
+ export class Settings {
3
+ layer;
4
+ debug;
5
+ constructor(options = {}) {
6
+ this.layer = $state(options.layer ?? 'svg');
7
+ this.debug = $state(options.debug ?? false);
8
+ }
9
+ }
10
+ export const defaultSettings = new Settings();
@@ -0,0 +1,9 @@
1
+ import type { TransformContextValue } from '../contexts/transform.js';
2
+ export type TransformMode = 'canvas' | 'manual' | 'none';
3
+ export type TransformScrollMode = 'scale' | 'translate' | 'none';
4
+ export declare const DEFAULT_TRANSLATE: {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ export declare const DEFAULT_SCALE = 1;
9
+ export declare function createDefaultTransformContext(): TransformContextValue;
@@ -0,0 +1,31 @@
1
+ export const DEFAULT_TRANSLATE = { x: 0, y: 0 };
2
+ export const DEFAULT_SCALE = 1;
3
+ export function createDefaultTransformContext() {
4
+ let defaultTranslate = $state(DEFAULT_TRANSLATE);
5
+ let defaultScale = $state(DEFAULT_SCALE);
6
+ const defaultContext = {
7
+ mode: 'none',
8
+ get scale() {
9
+ return defaultScale;
10
+ },
11
+ setScale: (value) => {
12
+ defaultScale = value;
13
+ },
14
+ get translate() {
15
+ return defaultTranslate;
16
+ },
17
+ setTranslate: (value) => {
18
+ defaultTranslate = value;
19
+ },
20
+ moving: false,
21
+ dragging: false,
22
+ scrollMode: 'none',
23
+ setScrollMode: () => { },
24
+ reset: () => { },
25
+ zoomIn: () => { },
26
+ zoomOut: () => { },
27
+ translateCenter: () => { },
28
+ zoomTo: () => { },
29
+ };
30
+ return defaultContext;
31
+ }
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import type { Getter, GetterValues } from './types.js';
8
8
  import type { ComponentProps } from 'svelte';
9
- import type { Text } from '../components/index.js';
9
+ import type Text from '../components/Text.svelte';
10
10
  export type ArcTextProps = GetterValues<{
11
11
  innerRadius: number;
12
12
  outerRadius: number;
@@ -9,12 +9,14 @@ type StyleOptions = Partial<Omit<CSSStyleDeclaration, 'fillOpacity' | 'strokeWid
9
9
  export type ComputedStylesOptions = {
10
10
  styles?: StyleOptions;
11
11
  classes?: ClassValue | null;
12
+ /** Inline style string (e.g., 'stroke-dasharray: 6 4') - will be parsed and merged with styles */
13
+ style?: string | null;
12
14
  };
13
15
  /**
14
16
  * Appends or reuses `<svg>` element below `<canvas>` to resolve CSS variables and classes (ex. `stroke: var(--color-primary)` => `stroke: rgb(...)` )
15
17
  */
16
18
  export declare function _getComputedStyles(canvas: HTMLCanvasElement, { styles, classes }?: ComputedStylesOptions): CSSStyleDeclaration;
17
- export declare const getComputedStyles: any;
19
+ export declare const getComputedStyles: typeof _getComputedStyles;
18
20
  /** Render SVG path data onto canvas context. Supports CSS variables and classes by tranferring to hidden `<svg>` element before retrieval) */
19
21
  export declare function renderPathData(ctx: CanvasRenderingContext2D, pathData: string | null | undefined, styleOptions?: ComputedStylesOptions): void;
20
22
  export declare function renderText(ctx: CanvasRenderingContext2D, text: string | number | null | undefined, coords: {
@@ -26,6 +28,8 @@ export declare function renderRect(ctx: CanvasRenderingContext2D, coords: {
26
28
  y: number;
27
29
  width: number;
28
30
  height: number;
31
+ rx?: number;
32
+ ry?: number;
29
33
  }, styleOptions?: ComputedStylesOptions): void;
30
34
  export declare function renderCircle(ctx: CanvasRenderingContext2D, coords: {
31
35
  cx: number;
@@ -70,8 +74,8 @@ export declare function _createLinearGradient(ctx: CanvasRenderingContext2D, x0:
70
74
  color: string;
71
75
  }[]): CanvasGradient;
72
76
  /** Create linear gradient and memoize result to fix reactivity */
73
- export declare const createLinearGradient: any;
77
+ export declare const createLinearGradient: typeof _createLinearGradient;
74
78
  export declare function _createPattern(ctx: CanvasRenderingContext2D, width: number, height: number, shapes: PatternShape[], background?: string): CanvasPattern | null;
75
79
  /** Create pattern and memoize result to fix reactivity */
76
- export declare const createPattern: any;
80
+ export declare const createPattern: typeof _createPattern;
77
81
  export {};
@@ -2,11 +2,36 @@ import memoize from 'memoize';
2
2
  import { cls } from '@layerstack/tailwind';
3
3
  export const DEFAULT_FILL = 'rgb(0, 0, 0)';
4
4
  const CANVAS_STYLES_ELEMENT_ID = '__layerchart_canvas_styles_id';
5
+ /**
6
+ * Parse an inline CSS style string into a StyleOptions object.
7
+ * Converts kebab-case properties to camelCase (e.g., 'stroke-dasharray' -> 'strokeDasharray')
8
+ */
9
+ function parseStyleString(styleString) {
10
+ if (!styleString)
11
+ return {};
12
+ const styles = {};
13
+ // Split by semicolons and process each declaration
14
+ const declarations = styleString.split(';').filter((s) => s.trim());
15
+ for (const declaration of declarations) {
16
+ const colonIndex = declaration.indexOf(':');
17
+ if (colonIndex === -1)
18
+ continue;
19
+ const property = declaration.slice(0, colonIndex).trim();
20
+ const value = declaration.slice(colonIndex + 1).trim();
21
+ if (!property || !value)
22
+ continue;
23
+ // Convert kebab-case to camelCase (e.g., 'stroke-dasharray' -> 'strokeDasharray')
24
+ const camelProperty = property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
25
+ styles[camelProperty] = value;
26
+ }
27
+ return styles;
28
+ }
5
29
  const supportedStyles = [
6
30
  'fill',
7
31
  'fillOpacity',
8
32
  'stroke',
9
33
  'strokeWidth',
34
+ 'strokeDasharray',
10
35
  'opacity',
11
36
  'fontWeight',
12
37
  'fontSize',
@@ -69,16 +94,19 @@ export const getComputedStyles = memoize(_getComputedStyles, {
69
94
  /** Render onto canvas context. Supports CSS variables and classes by tranferring to hidden `<svg>` element before retrieval) */
70
95
  function render(ctx, render, styleOptions = {}, { applyText, } = {}) {
71
96
  // console.count('render');
97
+ // Parse inline style string and merge with styles object
98
+ const parsedInlineStyles = parseStyleString(styleOptions.style);
99
+ const mergedStyles = { ...styleOptions.styles, ...parsedInlineStyles };
72
100
  // TODO: Consider memoizing? How about reactiving to CSS variable changes (light/dark mode toggle)
73
101
  let resolvedStyles;
74
102
  if (styleOptions.classes == null &&
75
- !Object.values(styleOptions.styles ?? {}).some((v) => typeof v === 'string' && v.includes('var('))) {
103
+ !Object.values(mergedStyles).some((v) => typeof v === 'string' && v.includes('var('))) {
76
104
  // Skip resolving styles if no classes are provided and no styles are using CSS variables
77
- resolvedStyles = styleOptions.styles ?? {};
105
+ resolvedStyles = mergedStyles;
78
106
  }
79
107
  else {
80
108
  // Remove constant non-css variable properties (ex. `strokeWidth: 0.5`, `fill: #123456`) as not needed and improves memoization cache hit
81
- const { constantStyles, variableStyles } = Object.entries(styleOptions.styles ?? {}).reduce((acc, [key, value]) => {
109
+ const { constantStyles, variableStyles } = Object.entries(mergedStyles).reduce((acc, [key, value]) => {
82
110
  if (typeof value === 'number' || (typeof value === 'string' && !value.includes('var('))) {
83
111
  acc.constantStyles[key] = value;
84
112
  }
@@ -120,12 +148,15 @@ function render(ctx, render, styleOptions = {}, { applyText, } = {}) {
120
148
  // ctx.textBaseline = 'hanging';
121
149
  // ctx.textBaseline = 'ideographic';
122
150
  }
123
- // Dashed lines
124
- if (resolvedStyles.strokeDasharray?.includes(',')) {
151
+ // Dashed lines (supports both comma and space separators, e.g., "2,2" or "2 2")
152
+ if (resolvedStyles.strokeDasharray && resolvedStyles.strokeDasharray !== 'none') {
125
153
  const dashArray = resolvedStyles.strokeDasharray
126
- .split(',')
154
+ .split(/[\s,]+/)
155
+ .filter((s) => s.length > 0)
127
156
  .map((s) => Number(s.replace('px', '')));
128
- ctx.setLineDash(dashArray);
157
+ if (dashArray.length > 0 && dashArray.every((n) => !isNaN(n))) {
158
+ ctx.setLineDash(dashArray);
159
+ }
129
160
  }
130
161
  for (const attr of paintOrder) {
131
162
  if (attr === 'fill') {
@@ -180,10 +211,46 @@ export function renderText(ctx, text, coords, styleOptions = {}) {
180
211
  }
181
212
  }
182
213
  export function renderRect(ctx, coords, styleOptions = {}) {
183
- render(ctx, {
184
- fill: (ctx) => ctx.fillRect(coords.x, coords.y, coords.width, coords.height),
185
- stroke: (ctx) => ctx.strokeRect(coords.x, coords.y, coords.width, coords.height),
186
- }, styleOptions);
214
+ const { x, y, width, height } = coords;
215
+ const rx = coords.rx ?? 0;
216
+ const ry = coords.ry ?? rx; // Default ry to rx if not provided (SVG behavior)
217
+ // No rounding - use simple rect methods
218
+ if (rx === 0 && ry === 0) {
219
+ render(ctx, {
220
+ fill: (ctx) => ctx.fillRect(x, y, width, height),
221
+ stroke: (ctx) => ctx.strokeRect(x, y, width, height),
222
+ }, styleOptions);
223
+ return;
224
+ }
225
+ // Try native roundRect if available (modern browsers)
226
+ if (typeof ctx.roundRect === 'function') {
227
+ ctx.beginPath();
228
+ ctx.roundRect(x, y, width, height, [rx, ry]);
229
+ render(ctx, {
230
+ fill: (ctx) => ctx.fill(),
231
+ stroke: (ctx) => ctx.stroke(),
232
+ }, styleOptions);
233
+ ctx.closePath();
234
+ return;
235
+ }
236
+ // Fallback: use path rendering for rounded corners
237
+ // Clamp radii to half the width/height
238
+ const clampedRx = Math.min(rx, width / 2);
239
+ const clampedRy = Math.min(ry, height / 2);
240
+ // Build rounded rect path: start at top-left (after corner), go clockwise
241
+ const pathData = [
242
+ `M${x + clampedRx},${y}`, // Move to top-left (after corner)
243
+ `h${width - 2 * clampedRx}`, // Top edge
244
+ `a${clampedRx},${clampedRy} 0 0 1 ${clampedRx},${clampedRy}`, // Top-right corner
245
+ `v${height - 2 * clampedRy}`, // Right edge
246
+ `a${clampedRx},${clampedRy} 0 0 1 ${-clampedRx},${clampedRy}`, // Bottom-right corner
247
+ `h${2 * clampedRx - width}`, // Bottom edge
248
+ `a${clampedRx},${clampedRy} 0 0 1 ${-clampedRx},${-clampedRy}`, // Bottom-left corner
249
+ `v${2 * clampedRy - height}`, // Left edge
250
+ `a${clampedRx},${clampedRy} 0 0 1 ${clampedRx},${-clampedRy}`, // Top-left corner
251
+ 'z', // Close path
252
+ ].join(' ');
253
+ renderPathData(ctx, pathData, styleOptions);
187
254
  }
188
255
  export function renderCircle(ctx, coords, styleOptions = {}) {
189
256
  ctx.beginPath();
@@ -5,7 +5,14 @@ export type Accessor<TData = any> = number | string | ((d: TData) => any) | unde
5
5
  export declare function accessor<TData = any>(prop: Accessor<TData>): (d: TData) => any;
6
6
  /** Guarantee chart data is an array */
7
7
  export declare function chartDataArray<TData = any>(data: ComponentProps<Chart<TData>>['data']): any[];
8
- export declare function defaultChartPadding<TData, SeriesComponent extends Component, TSnippetProps>(axis?: SimplifiedChartProps<TData, SeriesComponent, TSnippetProps>['axis'], legend?: SimplifiedChartProps<TData, SeriesComponent, TSnippetProps>['legend']): {
8
+ export declare function defaultChartPadding<TData, SeriesComponent extends Component, TSnippetProps>(options?: {
9
+ axis?: SimplifiedChartProps<TData, SeriesComponent, TSnippetProps>['axis'];
10
+ legend?: SimplifiedChartProps<TData, SeriesComponent, TSnippetProps>['legend'];
11
+ top?: number;
12
+ left?: number;
13
+ bottom?: number;
14
+ right?: number;
15
+ } | undefined): {
9
16
  top: number;
10
17
  left: number;
11
18
  bottom: number;
@@ -1,4 +1,4 @@
1
- import { get } from 'lodash-es';
1
+ import { get } from '@layerstack/utils';
2
2
  export function accessor(prop) {
3
3
  if (Array.isArray(prop)) {
4
4
  return (d) => prop.map((p) => accessor(p)(d));
@@ -32,18 +32,17 @@ export function chartDataArray(data) {
32
32
  }
33
33
  return [];
34
34
  }
35
- export function defaultChartPadding(axis = true, legend = false) {
35
+ export function defaultChartPadding(options = {}) {
36
+ const { axis = true, legend = false, top, left, bottom, right } = options;
36
37
  if (axis === false) {
37
38
  return undefined;
38
39
  }
39
- else {
40
- return {
41
- top: axis === true || axis === 'y' ? 4 : 0,
42
- left: axis === true || axis === 'y' ? 20 : 0,
43
- bottom: (axis === true || axis === 'x' ? 20 : 0) + (legend ? 32 : 0),
44
- right: axis === true || axis === 'x' ? 4 : 0,
45
- };
46
- }
40
+ return {
41
+ top: top ?? (axis === true || axis === 'y' ? 4 : 0),
42
+ left: left ?? (axis === true || axis === 'y' ? 20 : 0),
43
+ bottom: (bottom ?? (axis === true || axis === 'x' ? 20 : 0)) + (legend ? 32 : 0),
44
+ right: right ?? (axis === true || axis === 'x' ? 4 : 0),
45
+ };
47
46
  }
48
47
  /**
49
48
  * Find the first instance within `data` with the same value as `original` using prop accessor.
@@ -6,8 +6,10 @@ export * from './hierarchy.js';
6
6
  export * from './math.js';
7
7
  export * from './path.js';
8
8
  export * from './pivot.js';
9
+ export * from './scales.svelte.js';
9
10
  export * from './stack.js';
10
11
  export * from './ticks.js';
12
+ export * from './treemap.js';
11
13
  export * from './threshold.js';
12
14
  export * from './types.js';
13
15
  export * from './graph/dagre.js';
@@ -6,8 +6,10 @@ export * from './hierarchy.js';
6
6
  export * from './math.js';
7
7
  export * from './path.js';
8
8
  export * from './pivot.js';
9
+ export * from './scales.svelte.js';
9
10
  export * from './stack.js';
10
11
  export * from './ticks.js';
12
+ export * from './treemap.js';
11
13
  export * from './threshold.js';
12
14
  export * from './types.js';
13
15
  export * from './graph/dagre.js';
@@ -1,5 +1,4 @@
1
1
  import { Spring, Tween } from 'svelte/motion';
2
- import { afterTick } from './afterTick.js';
3
2
  /**
4
3
  * Extended Spring class that adds a type discriminator to help with
5
4
  * type narrowing in our motion system
@@ -1,4 +1,4 @@
1
- import type { ChartContextValue } from '../components/Chart.svelte';
1
+ import type { ChartContextValue } from '../contexts/chart.js';
2
2
  import { type Accessor } from './common.js';
3
3
  /**
4
4
  * A set of inset distances, applied to a rectangle to shrink or expand
@@ -1,6 +1,6 @@
1
+ import { max, min } from 'd3-array';
1
2
  import { accessor } from './common.js';
2
3
  import { isScaleBand } from './scales.svelte.js';
3
- import { max, min } from 'd3-array';
4
4
  function resolveInsets(insets) {
5
5
  const all = insets?.all ?? 0;
6
6
  const x = insets?.x ?? all;
@@ -22,13 +22,15 @@ export function createDimensionGetter(ctx, getOptions) {
22
22
  const _y = accessor(options?.y ?? ctx.y);
23
23
  const _x1 = accessor(options?.x1 ?? ctx.x1);
24
24
  const _y1 = accessor(options?.y1 ?? ctx.y1);
25
+ const hasX1 = (options?.x1 ?? ctx.config.x1) != null;
26
+ const hasY1 = (options?.y1 ?? ctx.config.y1) != null;
25
27
  if (isScaleBand(ctx.yScale)) {
26
28
  // Horizontal band
27
29
  const y = firstValue(ctx.yScale(_y(item)) ?? 0) +
28
- (ctx.y1Scale ? ctx.y1Scale(_y1(item)) : 0) +
30
+ (hasY1 && ctx.y1Scale ? ctx.y1Scale(_y1(item)) : 0) +
29
31
  insets.top;
30
32
  const height = Math.max(0, ctx.yScale.bandwidth
31
- ? (ctx.y1Scale ? (ctx.y1Scale.bandwidth?.() ?? 0) : ctx.yScale.bandwidth()) -
33
+ ? (hasY1 && ctx.y1Scale ? (ctx.y1Scale.bandwidth?.() ?? 0) : ctx.yScale.bandwidth()) -
32
34
  insets.bottom -
33
35
  insets.top
34
36
  : 0);
@@ -61,9 +63,11 @@ export function createDimensionGetter(ctx, getOptions) {
61
63
  }
62
64
  else if (isScaleBand(ctx.xScale)) {
63
65
  // Vertical band or linear
64
- const x = firstValue(ctx.xScale(_x(item))) + (ctx.x1Scale ? ctx.x1Scale(_x1(item)) : 0) + insets.left;
66
+ const x = firstValue(ctx.xScale(_x(item))) +
67
+ (hasX1 && ctx.x1Scale ? ctx.x1Scale(_x1(item)) : 0) +
68
+ insets.left;
65
69
  const width = Math.max(0, ctx.xScale.bandwidth
66
- ? (ctx.x1Scale ? (ctx.x1Scale.bandwidth?.() ?? 0) : ctx.xScale.bandwidth()) -
70
+ ? (hasX1 && ctx.x1Scale ? (ctx.x1Scale.bandwidth?.() ?? 0) : ctx.xScale.bandwidth()) -
67
71
  insets.left -
68
72
  insets.right
69
73
  : 0);
@@ -103,8 +107,10 @@ export function createDimensionGetter(ctx, getOptions) {
103
107
  const xValue = _x(item);
104
108
  const start = ctx.xInterval.floor(xValue);
105
109
  const end = ctx.xInterval.offset(start);
106
- const x = ctx.xScale(start) + insets.left;
107
- const width = ctx.xScale(end) - x - insets.right;
110
+ const xStart = ctx.xScale(start);
111
+ const xEnd = ctx.xScale(end);
112
+ const x = Math.min(xStart, xEnd) + insets.left;
113
+ const width = Math.abs(xEnd - xStart) - insets.left - insets.right;
108
114
  const yValue = _y(item);
109
115
  let top = 0;
110
116
  let bottom = 0;
@@ -137,8 +143,10 @@ export function createDimensionGetter(ctx, getOptions) {
137
143
  const yValue = _y(item);
138
144
  const start = ctx.yInterval.floor(yValue);
139
145
  const end = ctx.yInterval.offset(start);
140
- const y = ctx.yScale(start) + insets.top;
141
- const height = ctx.yScale(end) - y - insets.bottom;
146
+ const yStart = ctx.yScale(start);
147
+ const yEnd = ctx.yScale(end);
148
+ const y = Math.min(yStart, yEnd) + insets.top;
149
+ const height = Math.abs(yEnd - yStart) - insets.top - insets.bottom;
142
150
  const xValue = _x(item);
143
151
  let left = 0;
144
152
  let right = 0;
@@ -150,7 +150,7 @@ export function groupScaleBand(scale, flatData, groupBy, padding) {
150
150
  export function tweenedScale(scale, tweenedOptions = {}) {
151
151
  const tweenedDomain = new Tween(undefined, tweenedOptions);
152
152
  const tweenedRange = new Tween(undefined, tweenedOptions);
153
- const tweenedScale = $derived.by(() => {
153
+ const _tweenedScale = $derived.by(() => {
154
154
  const scaledInstance = scale.domain ? scale : scale();
155
155
  if (tweenedDomain.current) {
156
156
  scaledInstance.domain(tweenedDomain.current);
@@ -162,7 +162,7 @@ export function tweenedScale(scale, tweenedOptions = {}) {
162
162
  });
163
163
  return {
164
164
  get current() {
165
- return tweenedScale;
165
+ return _tweenedScale;
166
166
  },
167
167
  domain: (values) => tweenedDomain.set(values),
168
168
  range: (values) => tweenedRange.set(values),
@@ -1,4 +1,5 @@
1
- export declare const getStringWidth: any;
1
+ declare function _getStringWidth(str: string, style?: CSSStyleDeclaration): number | null;
2
+ export declare const getStringWidth: typeof _getStringWidth;
2
3
  export type RasterizeTextOptions = {
3
4
  fontSize?: string;
4
5
  fontWeight?: number;
@@ -47,3 +48,4 @@ export type TruncateTextOptions = {
47
48
  * The ellipsis can be placed at the start, middle, or end of the string.
48
49
  */
49
50
  export declare function truncateText(text: string, { position, ellipsis, maxWidth, style, maxChars }: TruncateTextOptions): string;
51
+ export {};