@pibbl/core 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) hide show
  1. package/README.md +1 -1
  2. package/dist/features/machines/animation.d.ts +64 -0
  3. package/dist/features/machines/animation.js +55 -0
  4. package/dist/features/machines/animation.js.map +7 -0
  5. package/dist/features/machines/animation.mjs +1 -0
  6. package/dist/features/machines/assign.d.ts +16 -0
  7. package/dist/features/machines/assign.js +15 -0
  8. package/dist/features/machines/assign.js.map +7 -0
  9. package/dist/features/machines/callback.d.ts +9 -0
  10. package/dist/features/machines/callback.js +7 -0
  11. package/dist/features/machines/callback.js.map +7 -0
  12. package/dist/features/machines/hook.d.ts +30 -0
  13. package/dist/features/machines/hook.js +37 -0
  14. package/dist/features/machines/hook.js.map +7 -0
  15. package/dist/features/machines/index.d.ts +6 -0
  16. package/dist/features/machines/index.js +12 -0
  17. package/dist/features/machines/index.js.map +7 -0
  18. package/dist/features/machines/index.mjs +1 -0
  19. package/dist/features/machines/runtime.d.ts +18 -0
  20. package/dist/features/machines/runtime.js +363 -0
  21. package/dist/features/machines/runtime.js.map +7 -0
  22. package/dist/features/machines/types.d.ts +164 -0
  23. package/dist/features/physics/2d-geometry.d.ts +3 -3
  24. package/dist/features/physics/2d-geometry.js.map +1 -1
  25. package/dist/features/physics/2d.d.ts +115 -62
  26. package/dist/features/physics/2d.js +59 -28
  27. package/dist/features/physics/2d.js.map +2 -2
  28. package/dist/features/physics/lib/2d/query-types.d.ts +6 -0
  29. package/dist/features/physics/lib/2d/runtime/controller.d.ts +7 -6
  30. package/dist/features/physics/lib/2d/runtime/controller.js.map +2 -2
  31. package/dist/features/physics/lib/2d/types.d.ts +8 -30
  32. package/dist/features/physics/lib/2d/world/queries.d.ts +7 -6
  33. package/dist/features/physics/lib/2d/world/queries.js.map +2 -2
  34. package/dist/features/sprites/formats/aseprite.d.ts +5 -0
  35. package/dist/features/sprites/formats/texture-packer.d.ts +5 -0
  36. package/dist/features/sprites/index.d.ts +6 -0
  37. package/dist/features/sprites/loader.d.ts +25 -0
  38. package/dist/features/sprites/model.d.ts +75 -0
  39. package/dist/features/sprites/sprite.d.ts +22 -0
  40. package/dist/features/viz/index.d.ts +28 -3
  41. package/dist/features/viz/index.js +40 -4
  42. package/dist/features/viz/index.js.map +2 -2
  43. package/dist/features/viz/lib/axis-labels.d.ts +2 -0
  44. package/dist/features/viz/lib/axis-labels.js +41 -0
  45. package/dist/features/viz/lib/axis-labels.js.map +7 -0
  46. package/dist/features/viz/lib/axis-title.d.ts +23 -0
  47. package/dist/features/viz/lib/axis-title.js +23 -0
  48. package/dist/features/viz/lib/axis-title.js.map +7 -0
  49. package/dist/features/viz/lib/axis.d.ts +1 -1
  50. package/dist/features/viz/lib/axis.js +50 -50
  51. package/dist/features/viz/lib/axis.js.map +2 -2
  52. package/dist/features/viz/lib/bar-scale.d.ts +7 -0
  53. package/dist/features/viz/lib/bar-scale.js +34 -0
  54. package/dist/features/viz/lib/bar-scale.js.map +7 -0
  55. package/dist/features/viz/lib/bar-series.js +5 -4
  56. package/dist/features/viz/lib/bar-series.js.map +2 -2
  57. package/dist/features/viz/lib/chart-lines.d.ts +41 -0
  58. package/dist/features/viz/lib/chart-lines.js +32 -0
  59. package/dist/features/viz/lib/chart-lines.js.map +7 -0
  60. package/dist/features/viz/lib/hover-data.js +2 -2
  61. package/dist/features/viz/lib/hover-data.js.map +2 -2
  62. package/dist/features/viz/lib/hover-types.d.ts +5 -5
  63. package/dist/features/viz/lib/line-series.js +3 -3
  64. package/dist/features/viz/lib/line-series.js.map +2 -2
  65. package/dist/features/viz/lib/linear-scale-component.d.ts +7 -0
  66. package/dist/features/viz/lib/linear-scale-component.js +18 -0
  67. package/dist/features/viz/lib/linear-scale-component.js.map +7 -0
  68. package/dist/features/viz/lib/linear-scale.js +1 -1
  69. package/dist/features/viz/lib/linear-scale.js.map +2 -2
  70. package/dist/features/viz/lib/log-scale-component.d.ts +7 -0
  71. package/dist/features/viz/lib/log-scale-component.js +19 -0
  72. package/dist/features/viz/lib/log-scale-component.js.map +7 -0
  73. package/dist/features/viz/lib/log-scale.d.ts +2 -0
  74. package/dist/features/viz/lib/log-scale.js +53 -0
  75. package/dist/features/viz/lib/log-scale.js.map +7 -0
  76. package/dist/features/viz/lib/nearest.d.ts +9 -9
  77. package/dist/features/viz/lib/nearest.js.map +1 -1
  78. package/dist/features/viz/lib/numeric-ticks.d.ts +38 -0
  79. package/dist/features/viz/lib/numeric-ticks.js +54 -0
  80. package/dist/features/viz/lib/numeric-ticks.js.map +7 -0
  81. package/dist/features/viz/lib/plot-series.js +2 -2
  82. package/dist/features/viz/lib/plot-series.js.map +2 -2
  83. package/dist/features/viz/lib/point-scale-component.d.ts +7 -0
  84. package/dist/features/viz/lib/point-scale-component.js +19 -0
  85. package/dist/features/viz/lib/point-scale-component.js.map +7 -0
  86. package/dist/features/viz/lib/point-scale.d.ts +2 -0
  87. package/dist/features/viz/lib/point-scale.js +45 -0
  88. package/dist/features/viz/lib/point-scale.js.map +7 -0
  89. package/dist/features/viz/lib/point-series.js +2 -2
  90. package/dist/features/viz/lib/point-series.js.map +2 -2
  91. package/dist/features/viz/lib/reference-band.d.ts +16 -0
  92. package/dist/features/viz/lib/reference-band.js +27 -0
  93. package/dist/features/viz/lib/reference-band.js.map +7 -0
  94. package/dist/features/viz/lib/scale-adjust.js +9 -4
  95. package/dist/features/viz/lib/scale-adjust.js.map +2 -2
  96. package/dist/features/viz/lib/scale-context.d.ts +5 -4
  97. package/dist/features/viz/lib/scale-context.js +15 -11
  98. package/dist/features/viz/lib/scale-context.js.map +2 -2
  99. package/dist/features/viz/lib/scale-provider.d.ts +2 -0
  100. package/dist/features/viz/lib/scale-provider.js +13 -0
  101. package/dist/features/viz/lib/scale-provider.js.map +7 -0
  102. package/dist/features/viz/lib/scale-ticks.d.ts +5 -0
  103. package/dist/features/viz/lib/scale-ticks.js +49 -0
  104. package/dist/features/viz/lib/scale-ticks.js.map +7 -0
  105. package/dist/features/viz/lib/scale-view.d.ts +4 -0
  106. package/dist/features/viz/lib/scale-view.js +21 -0
  107. package/dist/features/viz/lib/scale-view.js.map +7 -0
  108. package/dist/features/viz/lib/symlog-scale-component.d.ts +7 -0
  109. package/dist/features/viz/lib/symlog-scale-component.js +19 -0
  110. package/dist/features/viz/lib/symlog-scale-component.js.map +7 -0
  111. package/dist/features/viz/lib/symlog-scale.d.ts +2 -0
  112. package/dist/features/viz/lib/symlog-scale.js +38 -0
  113. package/dist/features/viz/lib/symlog-scale.js.map +7 -0
  114. package/dist/features/viz/lib/types.d.ts +95 -18
  115. package/dist/features/viz/lib/use-bar-scale.d.ts +8 -0
  116. package/dist/features/viz/lib/use-bar-scale.js +9 -0
  117. package/dist/features/viz/lib/use-bar-scale.js.map +7 -0
  118. package/dist/features/viz/lib/use-continuous-scale.d.ts +8 -0
  119. package/dist/features/viz/lib/use-continuous-scale.js +9 -0
  120. package/dist/features/viz/lib/use-continuous-scale.js.map +7 -0
  121. package/dist/features/viz/lib/use-linear-scale.d.ts +8 -0
  122. package/dist/features/viz/lib/use-linear-scale.js +9 -0
  123. package/dist/features/viz/lib/use-linear-scale.js.map +7 -0
  124. package/dist/features/viz/lib/use-log-scale.d.ts +8 -0
  125. package/dist/features/viz/lib/use-log-scale.js +9 -0
  126. package/dist/features/viz/lib/use-log-scale.js.map +7 -0
  127. package/dist/features/viz/lib/use-point-scale.d.ts +8 -0
  128. package/dist/features/viz/lib/use-point-scale.js +9 -0
  129. package/dist/features/viz/lib/use-point-scale.js.map +7 -0
  130. package/dist/features/viz/lib/use-symlog-scale.d.ts +8 -0
  131. package/dist/features/viz/lib/use-symlog-scale.js +9 -0
  132. package/dist/features/viz/lib/use-symlog-scale.js.map +7 -0
  133. package/dist/features/viz/lib/use-utc-scale.d.ts +8 -0
  134. package/dist/features/viz/lib/use-utc-scale.js +9 -0
  135. package/dist/features/viz/lib/use-utc-scale.js.map +7 -0
  136. package/dist/features/viz/lib/utc-labels.d.ts +12 -0
  137. package/dist/features/viz/lib/utc-labels.js +27 -0
  138. package/dist/features/viz/lib/utc-labels.js.map +7 -0
  139. package/dist/features/viz/lib/utc-scale-component.d.ts +7 -0
  140. package/dist/features/viz/lib/utc-scale-component.js +18 -0
  141. package/dist/features/viz/lib/utc-scale-component.js.map +7 -0
  142. package/dist/features/viz/lib/utc-scale.d.ts +21 -0
  143. package/dist/features/viz/lib/utc-scale.js +123 -0
  144. package/dist/features/viz/lib/utc-scale.js.map +7 -0
  145. package/dist/index.d.ts +1 -1
  146. package/dist/index.js.map +1 -1
  147. package/dist/lib/animation/definition.d.ts +5 -3
  148. package/dist/lib/animation/definition.js +29 -4
  149. package/dist/lib/animation/definition.js.map +2 -2
  150. package/dist/lib/animation/playback.d.ts +8 -0
  151. package/dist/lib/animation/playback.js +33 -11
  152. package/dist/lib/animation/playback.js.map +2 -2
  153. package/dist/lib/animation/spring.d.ts +3 -1
  154. package/dist/lib/animation/spring.js.map +2 -2
  155. package/dist/lib/animation/types.d.ts +29 -73
  156. package/dist/lib/hooks/use-animated-value.d.ts +11 -21
  157. package/dist/lib/hooks/use-animated-value.js +23 -70
  158. package/dist/lib/hooks/use-animated-value.js.map +3 -3
  159. package/dist/lib/hooks/use-playback.js +1 -0
  160. package/dist/lib/hooks/use-playback.js.map +2 -2
  161. package/package.json +18 -4
  162. package/dist/features/viz/lib/scale.d.ts +0 -11
  163. package/dist/features/viz/lib/scale.js +0 -80
  164. package/dist/features/viz/lib/scale.js.map +0 -7
  165. package/dist/features/viz/lib/use-scale.d.ts +0 -20
  166. package/dist/features/viz/lib/use-scale.js +0 -10
  167. package/dist/features/viz/lib/use-scale.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/point-series.tsx"],
4
- "sourcesContent": ["import { resolveTexturePaint } from '@pibbl/core/internal';\nimport {\n Path,\n isSignal,\n resolveSignalValue,\n useCanvasContext,\n} from \"@pibbl/core\";\nimport type { FillStyle, StrokeStyle } from \"@pibbl/core\";\nimport type {\n PointMarkStyle,\n PointSeriesProps,\n PointSeriesStyle,\n} from \"./point-types.js\";\nimport { useScale } from \"./use-scale.js\";\nimport { finiteCoordinate, pointAccessor, pointData } from \"./point-data.js\";\nimport { appendPointTarget, pointPath } from \"./point-geometry.js\";\nimport { opacity, width } from \"./paint.js\";\nconst fields = [\"radius\", \"fill\", \"stroke\", \"strokeWidth\", \"opacity\", \"cursor\"];\nfunction paint(\n value: unknown,\n name: string,\n): FillStyle | StrokeStyle | undefined {\n if (\n value === undefined ||\n typeof value === \"string\" ||\n value instanceof CanvasGradient ||\n value instanceof CanvasPattern\n )\n return value;\n throw new TypeError(`PointSeries: invalid ${name}.`);\n}\nfunction styleObject(input: unknown, callback: boolean): PointSeriesStyle {\n if (input === null || typeof input !== \"object\" || Array.isArray(input))\n throw new TypeError(\"PointSeries: style must be an object.\");\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n if (!fields.includes(key) || (callback && key === \"cursor\"))\n throw new TypeError(`PointSeries: unsupported style field ${key}.`);\n const value = (input as Record<string, unknown>)[key];\n if (callback && isSignal(value))\n throw new TypeError(\n \"PointSeries: datum styles must contain plain values; read signals explicitly.\",\n );\n result[key] = callback ? value : resolveSignalValue(value);\n }\n return result as PointSeriesStyle;\n}\nfunction normalized(style: PointSeriesStyle) {\n const radius = width(style.radius ?? 3, \"PointSeries radius\");\n if (style.cursor !== undefined && typeof style.cursor !== \"string\")\n throw new TypeError(\"PointSeries: cursor must be a string.\");\n return {\n radius,\n fill: paint(style.fill ?? \"#2563eb\", \"fill\"),\n stroke: paint(style.stroke, \"stroke\"),\n strokeWidth: width(style.strokeWidth ?? 1, \"PointSeries\"),\n opacity: opacity(style.opacity ?? 1, \"PointSeries\"),\n cursor: style.cursor,\n };\n}\n/**\n * Batched circles in source paint order with one ordinary Pibbl target.\n *\n * @param props - Data, coordinate accessors, scales, and point styling. See\n * {@link PointSeriesProps} .\n * @returns Pibbl nodes drawing the point marks.\n *\n * @see {@link PointSeriesProps}\n */\nexport function PointSeries<D>({\n data: input,\n x: xInput,\n y: yInput,\n xScale: xId,\n yScale: yId,\n defined,\n style: styleInput,\n ...events\n}: PointSeriesProps<D>) {\n const xs = useScale(xId).get(),\n ys = useScale(yId).get();\n const data = pointData(resolveSignalValue(input), \"PointSeries\");\n const x = pointAccessor(xInput),\n y = pointAccessor(yInput);\n const specified = resolveSignalValue(styleInput);\n const shared =\n typeof specified === \"function\"\n ? undefined\n : normalized(styleObject(specified ?? {}, false));\n const ctx = useCanvasContext();\n const target = new Path2D();\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (defined && !defined(datum, i, data)) continue;\n const xv = x(datum, i, data),\n yv = y(datum, i, data);\n if (!finiteCoordinate(xv) || !finiteCoordinate(yv)) continue;\n const px = xs.map(xv),\n py = ys.map(yv);\n const style =\n shared ??\n normalized(\n styleObject(\n (specified as (d: D, i: number, a: readonly D[]) => PointMarkStyle)(\n datum,\n i,\n data,\n ),\n true,\n ),\n );\n if (style.radius === 0) continue;\n appendPointTarget(\n target,\n px,\n py,\n style.radius,\n !!style.fill,\n style.stroke ? style.strokeWidth : 0,\n );\n const path = pointPath(px, py, style.radius);\n ctx.save();\n try {\n ctx.globalAlpha *= style.opacity;\n if (style.fill) {\n ctx.fillStyle = resolveTexturePaint(style.fill, ctx, { x: px - style.radius, y: py - style.radius, width: style.radius * 2, height: style.radius * 2 });\n ctx.fill(path);\n }\n if (style.stroke && style.strokeWidth > 0) {\n ctx.strokeStyle = resolveTexturePaint(style.stroke, ctx, { x: px - style.radius, y: py - style.radius, width: style.radius * 2, height: style.radius * 2 });\n ctx.lineWidth = style.strokeWidth;\n ctx.stroke(path);\n }\n } finally {\n ctx.restore();\n }\n }\n return (\n <Path\n {...events}\n style={{ d: target, fill: \"transparent\", cursor: shared?.cursor }}\n />\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { resolveTexturePaint } from '@pibbl/core/internal';\nimport {\n Path,\n isSignal,\n resolveSignalValue,\n useCanvasContext,\n} from \"@pibbl/core\";\nimport type { FillStyle, StrokeStyle } from \"@pibbl/core\";\nimport type {\n PointMarkStyle,\n PointSeriesProps,\n PointSeriesStyle,\n} from \"./point-types.js\";\nimport { useContinuousScale } from \"./use-continuous-scale.js\";\nimport { finiteCoordinate, pointAccessor, pointData } from \"./point-data.js\";\nimport { appendPointTarget, pointPath } from \"./point-geometry.js\";\nimport { opacity, width } from \"./paint.js\";\nconst fields = [\"radius\", \"fill\", \"stroke\", \"strokeWidth\", \"opacity\", \"cursor\"];\nfunction paint(\n value: unknown,\n name: string,\n): FillStyle | StrokeStyle | undefined {\n if (\n value === undefined ||\n typeof value === \"string\" ||\n value instanceof CanvasGradient ||\n value instanceof CanvasPattern\n )\n return value;\n throw new TypeError(`PointSeries: invalid ${name}.`);\n}\nfunction styleObject(input: unknown, callback: boolean): PointSeriesStyle {\n if (input === null || typeof input !== \"object\" || Array.isArray(input))\n throw new TypeError(\"PointSeries: style must be an object.\");\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(input)) {\n if (!fields.includes(key) || (callback && key === \"cursor\"))\n throw new TypeError(`PointSeries: unsupported style field ${key}.`);\n const value = (input as Record<string, unknown>)[key];\n if (callback && isSignal(value))\n throw new TypeError(\n \"PointSeries: datum styles must contain plain values; read signals explicitly.\",\n );\n result[key] = callback ? value : resolveSignalValue(value);\n }\n return result as PointSeriesStyle;\n}\nfunction normalized(style: PointSeriesStyle) {\n const radius = width(style.radius ?? 3, \"PointSeries radius\");\n if (style.cursor !== undefined && typeof style.cursor !== \"string\")\n throw new TypeError(\"PointSeries: cursor must be a string.\");\n return {\n radius,\n fill: paint(style.fill ?? \"#2563eb\", \"fill\"),\n stroke: paint(style.stroke, \"stroke\"),\n strokeWidth: width(style.strokeWidth ?? 1, \"PointSeries\"),\n opacity: opacity(style.opacity ?? 1, \"PointSeries\"),\n cursor: style.cursor,\n };\n}\n/**\n * Batched circles in source paint order with one ordinary Pibbl target.\n *\n * @param props - Data, coordinate accessors, scales, and point styling. See\n * {@link PointSeriesProps} .\n * @returns Pibbl nodes drawing the point marks.\n *\n * @see {@link PointSeriesProps}\n */\nexport function PointSeries<D>({\n data: input,\n x: xInput,\n y: yInput,\n xScale: xId,\n yScale: yId,\n defined,\n style: styleInput,\n ...events\n}: PointSeriesProps<D>) {\n const xs = useContinuousScale(xId).get(),\n ys = useContinuousScale(yId).get();\n const data = pointData(resolveSignalValue(input), \"PointSeries\");\n const x = pointAccessor(xInput),\n y = pointAccessor(yInput);\n const specified = resolveSignalValue(styleInput);\n const shared =\n typeof specified === \"function\"\n ? undefined\n : normalized(styleObject(specified ?? {}, false));\n const ctx = useCanvasContext();\n const target = new Path2D();\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (defined && !defined(datum, i, data)) continue;\n const xv = x(datum, i, data),\n yv = y(datum, i, data);\n if (!finiteCoordinate(xv) || !finiteCoordinate(yv)) continue;\n const px = xs.map(xv),\n py = ys.map(yv);\n const style =\n shared ??\n normalized(\n styleObject(\n (specified as (d: D, i: number, a: readonly D[]) => PointMarkStyle)(\n datum,\n i,\n data,\n ),\n true,\n ),\n );\n if (style.radius === 0) continue;\n appendPointTarget(\n target,\n px,\n py,\n style.radius,\n !!style.fill,\n style.stroke ? style.strokeWidth : 0,\n );\n const path = pointPath(px, py, style.radius);\n ctx.save();\n try {\n ctx.globalAlpha *= style.opacity;\n if (style.fill) {\n ctx.fillStyle = resolveTexturePaint(style.fill, ctx, { x: px - style.radius, y: py - style.radius, width: style.radius * 2, height: style.radius * 2 });\n ctx.fill(path);\n }\n if (style.stroke && style.strokeWidth > 0) {\n ctx.strokeStyle = resolveTexturePaint(style.stroke, ctx, { x: px - style.radius, y: py - style.radius, width: style.radius * 2, height: style.radius * 2 });\n ctx.lineWidth = style.strokeWidth;\n ctx.stroke(path);\n }\n } finally {\n ctx.restore();\n }\n }\n return (\n <Path\n {...events}\n style={{ d: target, fill: \"transparent\", cursor: shared?.cursor }}\n />\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,16 @@
1
+ import { type SignalValue } from "@pibbl/core";
2
+ import type { SignalStyle } from "@pibbl/core/internal";
3
+ import type { AxisStyle } from "./types.js";
4
+ import type { ChartLineProps } from "./chart-lines.js";
5
+ /** A continuous domain interval painted across an explicit local pixel span. See {@link ReferenceBand}. */
6
+ export interface ReferenceBandProps extends Omit<ChartLineProps, "style"> {
7
+ /** Two finite in-domain numeric endpoints; either order, including equal values. */
8
+ readonly values: SignalValue<readonly [number, number]>;
9
+ /** Fill defaults to #dce5e8; opacity defaults to 0.35. */
10
+ readonly style?: SignalValue<SignalStyle<Pick<AxisStyle, "fill" | "opacity">>>;
11
+ }
12
+ /** Paint a decorative interval without owning layout, labels, or hit geometry.
13
+ * @param props - Scale geometry and presentation. See {@link ReferenceBandProps}.
14
+ * @returns Decorative chart content in the caller's coordinate space.
15
+ */
16
+ export declare function ReferenceBand(props: ReferenceBandProps): import("../../../jsx-runtime.js").JSX.Element;
@@ -0,0 +1,27 @@
1
+ import { jsx } from "@pibbl/core/jsx-runtime";
2
+ import { Path, resolveSignalValue } from "@pibbl/core";
3
+ import { lookupScale } from "./scale-context.js";
4
+ import { opacity } from "./paint.js";
5
+ function ReferenceBand(props) {
6
+ if (props.direction !== "horizontal" && props.direction !== "vertical") throw new TypeError("ReferenceBand direction must be horizontal or vertical.");
7
+ const source = lookupScale(props.scale, "ReferenceBand");
8
+ if (!source) throw new TypeError("ReferenceBand requires a scale ID.");
9
+ const scale = source.get();
10
+ if (scale.type === "point" || scale.type === "band") throw new TypeError("ReferenceBand requires a continuous scale.");
11
+ const values = resolveSignalValue(props.values), span = resolveSignalValue(props.span);
12
+ for (const pair of [values, span]) if (!Array.isArray(pair) || pair.length !== 2 || !pair.every((value) => typeof value === "number" && Number.isFinite(value))) throw new RangeError("ReferenceBand values and span require two finite endpoints.");
13
+ const lo = Math.min(...scale.domain), hi = Math.max(...scale.domain);
14
+ if (values.some((value) => value < lo || value > hi)) throw new RangeError("ReferenceBand values must be within the scale domain.");
15
+ const a = scale.map(values[0]), b = scale.map(values[1]);
16
+ const start = Math.min(...span), length = Math.abs(span[1] - span[0]);
17
+ if (!Number.isFinite(length)) throw new RangeError("ReferenceBand span length must be finite.");
18
+ const path = new Path2D();
19
+ if (props.direction === "horizontal") path.rect(start, Math.min(a, b), length, Math.abs(b - a));
20
+ else path.rect(Math.min(a, b), start, Math.abs(b - a), length);
21
+ const style = resolveSignalValue(props.style) ?? {};
22
+ return /* @__PURE__ */ jsx(Path, { pointerEvents: "none", style: { d: path, fill: resolveSignalValue(style.fill) ?? "#dce5e8", opacity: opacity(resolveSignalValue(style.opacity) ?? 0.35, "ReferenceBand") } });
23
+ }
24
+ export {
25
+ ReferenceBand
26
+ };
27
+ //# sourceMappingURL=reference-band.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/reference-band.tsx"],
4
+ "sourcesContent": ["import { Path, resolveSignalValue, type SignalValue } from \"@pibbl/core\";\nimport type { SignalStyle } from \"@pibbl/core/internal\";\nimport type { AxisStyle } from \"./types.js\";\nimport type { ChartLineProps } from \"./chart-lines.js\";\nimport { lookupScale } from \"./scale-context.js\";\nimport { opacity } from \"./paint.js\";\n/** A continuous domain interval painted across an explicit local pixel span. See {@link ReferenceBand}. */\nexport interface ReferenceBandProps extends Omit<ChartLineProps, \"style\"> {\n /** Two finite in-domain numeric endpoints; either order, including equal values. */\n readonly values: SignalValue<readonly [number, number]>;\n /** Fill defaults to #dce5e8; opacity defaults to 0.35. */\n readonly style?: SignalValue<SignalStyle<Pick<AxisStyle, \"fill\" | \"opacity\">>>;\n}\n/** Paint a decorative interval without owning layout, labels, or hit geometry.\n * @param props - Scale geometry and presentation. See {@link ReferenceBandProps}.\n * @returns Decorative chart content in the caller's coordinate space.\n */\nexport function ReferenceBand(props: ReferenceBandProps) {\n if (props.direction !== \"horizontal\" && props.direction !== \"vertical\") throw new TypeError(\"ReferenceBand direction must be horizontal or vertical.\");\n const source = lookupScale(props.scale, \"ReferenceBand\");\n if (!source) throw new TypeError(\"ReferenceBand requires a scale ID.\");\n const scale = source.get();\n if (scale.type === \"point\" || scale.type === \"band\") throw new TypeError(\"ReferenceBand requires a continuous scale.\");\n const values = resolveSignalValue(props.values), span = resolveSignalValue(props.span);\n for (const pair of [values, span]) if (!Array.isArray(pair) || pair.length !== 2 || !pair.every(value => typeof value === \"number\" && Number.isFinite(value))) throw new RangeError(\"ReferenceBand values and span require two finite endpoints.\");\n const lo = Math.min(...scale.domain), hi = Math.max(...scale.domain);\n if (values.some(value => value < lo || value > hi)) throw new RangeError(\"ReferenceBand values must be within the scale domain.\");\n const a = scale.map(values[0]), b = scale.map(values[1]);\n const start = Math.min(...span), length = Math.abs(span[1] - span[0]);\n if (!Number.isFinite(length)) throw new RangeError(\"ReferenceBand span length must be finite.\");\n const path = new Path2D();\n if (props.direction === \"horizontal\") path.rect(start, Math.min(a, b), length, Math.abs(b - a));\n else path.rect(Math.min(a, b), start, Math.abs(b - a), length);\n const style = resolveSignalValue(props.style) ?? {};\n return <Path pointerEvents=\"none\" style={{ d: path, fill: resolveSignalValue(style.fill) ?? \"#dce5e8\", opacity: opacity(resolveSignalValue(style.opacity) ?? 0.35, \"ReferenceBand\") }} />;\n}\n"],
5
+ "mappings": "AAkCS;AAlCT,SAAS,MAAM,0BAA4C;AAI3D,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AAYjB,SAAS,cAAc,OAA2B;AACvD,MAAI,MAAM,cAAc,gBAAgB,MAAM,cAAc,WAAY,OAAM,IAAI,UAAU,yDAAyD;AACrJ,QAAM,SAAS,YAAY,MAAM,OAAO,eAAe;AACvD,MAAI,CAAC,OAAQ,OAAM,IAAI,UAAU,oCAAoC;AACrE,QAAM,QAAQ,OAAO,IAAI;AACzB,MAAI,MAAM,SAAS,WAAW,MAAM,SAAS,OAAQ,OAAM,IAAI,UAAU,4CAA4C;AACrH,QAAM,SAAS,mBAAmB,MAAM,MAAM,GAAG,OAAO,mBAAmB,MAAM,IAAI;AACrF,aAAW,QAAQ,CAAC,QAAQ,IAAI,EAAG,KAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,KAAK,CAAC,KAAK,MAAM,WAAS,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,CAAC,EAAG,OAAM,IAAI,WAAW,6DAA6D;AACjP,QAAM,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM,GAAG,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM;AACnE,MAAI,OAAO,KAAK,WAAS,QAAQ,MAAM,QAAQ,EAAE,EAAG,OAAM,IAAI,WAAW,uDAAuD;AAChI,QAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,GAAG,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC;AACvD,QAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,GAAG,SAAS,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC;AACpE,MAAI,CAAC,OAAO,SAAS,MAAM,EAAG,OAAM,IAAI,WAAW,2CAA2C;AAC9F,QAAM,OAAO,IAAI,OAAO;AACxB,MAAI,MAAM,cAAc,aAAc,MAAK,KAAK,OAAO,KAAK,IAAI,GAAG,CAAC,GAAG,QAAQ,KAAK,IAAI,IAAI,CAAC,CAAC;AAAA,MACzF,MAAK,KAAK,KAAK,IAAI,GAAG,CAAC,GAAG,OAAO,KAAK,IAAI,IAAI,CAAC,GAAG,MAAM;AAC7D,QAAM,QAAQ,mBAAmB,MAAM,KAAK,KAAK,CAAC;AAClD,SAAO,oBAAC,QAAK,eAAc,QAAO,OAAO,EAAE,GAAG,MAAM,MAAM,mBAAmB,MAAM,IAAI,KAAK,WAAW,SAAS,QAAQ,mBAAmB,MAAM,OAAO,KAAK,MAAM,eAAe,EAAE,GAAG;AACzL;",
6
+ "names": []
7
+ }
@@ -6,14 +6,19 @@ function ScaleAdjust(props) {
6
6
  const y = lookupScale(props.yScale, "ScaleAdjust");
7
7
  if (props.x === void 0 !== (props.xScale === void 0) || props.y === void 0 !== (props.yScale === void 0))
8
8
  throw new TypeError("ScaleAdjust coordinates require matching scale IDs.");
9
- if (x && x.get().type !== "linear" || y && y.get().type !== "linear")
10
- throw new TypeError("ScaleAdjust requires linear scales.");
9
+ const coordinate = (scale, value) => {
10
+ if (scale.type === "band") throw new TypeError("ScaleAdjust requires continuous or point scales.");
11
+ if (scale.type !== "point" && typeof value !== "number") throw new TypeError("ScaleAdjust continuous coordinates must be numbers.");
12
+ const result = scale.type === "point" ? scale.map(value) : scale.map(value);
13
+ if (result === void 0) throw new RangeError("ScaleAdjust point category is not in the domain.");
14
+ return result;
15
+ };
11
16
  return /* @__PURE__ */ jsx(
12
17
  Group,
13
18
  {
14
19
  style: {
15
- translateX: x ? x.get().map(resolveSignalValue(props.x)) : 0,
16
- translateY: y ? y.get().map(resolveSignalValue(props.y)) : 0
20
+ translateX: x ? coordinate(x.get(), resolveSignalValue(props.x)) : 0,
21
+ translateY: y ? coordinate(y.get(), resolveSignalValue(props.y)) : 0
17
22
  },
18
23
  children: props.children
19
24
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/scale-adjust.tsx"],
4
- "sourcesContent": ["import { Group, resolveSignalValue } from \"@pibbl/core\";\nimport type { ScaleAdjustProps } from \"./types.js\";\nimport { lookupScale } from \"./scale-context.js\";\n/**\n * Adjusts descendant placement using configured x and y scales.\n *\n * @param props - Scale identity and domain or range adjustments for descendants. See\n * {@link ScaleAdjustProps} .\n * @returns Child content evaluated with the adjusted scale.\n *\n * @see {@link ScaleAdjustProps}\n */\nexport function ScaleAdjust(props: ScaleAdjustProps) {\n const x = lookupScale(props.xScale, \"ScaleAdjust\");\n const y = lookupScale(props.yScale, \"ScaleAdjust\");\n if (\n (props.x === undefined) !== (props.xScale === undefined) ||\n (props.y === undefined) !== (props.yScale === undefined)\n )\n throw new TypeError(\"ScaleAdjust coordinates require matching scale IDs.\");\n if ((x && x.get().type !== \"linear\") || (y && y.get().type !== \"linear\"))\n throw new TypeError(\"ScaleAdjust requires linear scales.\");\n return (\n <Group\n style={{\n translateX: x ? x.get().map(resolveSignalValue(props.x!)) : 0,\n translateY: y ? y.get().map(resolveSignalValue(props.y!)) : 0,\n }}\n >\n {props.children}\n </Group>\n );\n}\n"],
5
- "mappings": "AAuBI;AAvBJ,SAAS,OAAO,0BAA0B;AAE1C,SAAS,mBAAmB;AAUrB,SAAS,YAAY,OAAyB;AACnD,QAAM,IAAI,YAAY,MAAM,QAAQ,aAAa;AACjD,QAAM,IAAI,YAAY,MAAM,QAAQ,aAAa;AACjD,MACG,MAAM,MAAM,YAAgB,MAAM,WAAW,WAC7C,MAAM,MAAM,YAAgB,MAAM,WAAW;AAE9C,UAAM,IAAI,UAAU,qDAAqD;AAC3E,MAAK,KAAK,EAAE,IAAI,EAAE,SAAS,YAAc,KAAK,EAAE,IAAI,EAAE,SAAS;AAC7D,UAAM,IAAI,UAAU,qCAAqC;AAC3D,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,YAAY,IAAI,EAAE,IAAI,EAAE,IAAI,mBAAmB,MAAM,CAAE,CAAC,IAAI;AAAA,QAC5D,YAAY,IAAI,EAAE,IAAI,EAAE,IAAI,mBAAmB,MAAM,CAAE,CAAC,IAAI;AAAA,MAC9D;AAAA,MAEC,gBAAM;AAAA;AAAA,EACT;AAEJ;",
4
+ "sourcesContent": ["import { Group, resolveSignalValue } from \"@pibbl/core\";\nimport type { ScaleAdjustProps, ResolvedScale, BandCategory } from \"./types.js\";\nimport { lookupScale } from \"./scale-context.js\";\n/**\n * Adjusts descendant placement using configured x and y scales.\n *\n * @param props - Scale identity and domain or range adjustments for descendants. See\n * {@link ScaleAdjustProps} .\n * @returns Child content evaluated with the adjusted scale.\n *\n * @see {@link ScaleAdjustProps}\n */\nexport function ScaleAdjust(props: ScaleAdjustProps) {\n const x = lookupScale(props.xScale, \"ScaleAdjust\");\n const y = lookupScale(props.yScale, \"ScaleAdjust\");\n if (\n (props.x === undefined) !== (props.xScale === undefined) ||\n (props.y === undefined) !== (props.yScale === undefined)\n )\n throw new TypeError(\"ScaleAdjust coordinates require matching scale IDs.\");\n const coordinate = (scale: ResolvedScale, value: BandCategory) => {\n if (scale.type === \"band\") throw new TypeError(\"ScaleAdjust requires continuous or point scales.\");\n if (scale.type !== \"point\" && typeof value !== \"number\") throw new TypeError(\"ScaleAdjust continuous coordinates must be numbers.\");\n const result = scale.type === \"point\" ? scale.map(value) : scale.map(value as number);\n if (result === undefined) throw new RangeError(\"ScaleAdjust point category is not in the domain.\");\n return result;\n };\n return (\n <Group\n style={{\n translateX: x ? coordinate(x.get(), resolveSignalValue(props.x!)) : 0,\n translateY: y ? coordinate(y.get(), resolveSignalValue(props.y!)) : 0,\n }}\n >\n {props.children}\n </Group>\n );\n}\n"],
5
+ "mappings": "AA4BI;AA5BJ,SAAS,OAAO,0BAA0B;AAE1C,SAAS,mBAAmB;AAUrB,SAAS,YAAY,OAAyB;AACnD,QAAM,IAAI,YAAY,MAAM,QAAQ,aAAa;AACjD,QAAM,IAAI,YAAY,MAAM,QAAQ,aAAa;AACjD,MACG,MAAM,MAAM,YAAgB,MAAM,WAAW,WAC7C,MAAM,MAAM,YAAgB,MAAM,WAAW;AAE9C,UAAM,IAAI,UAAU,qDAAqD;AAC3E,QAAM,aAAa,CAAC,OAAsB,UAAwB;AAChE,QAAI,MAAM,SAAS,OAAQ,OAAM,IAAI,UAAU,kDAAkD;AACjG,QAAI,MAAM,SAAS,WAAW,OAAO,UAAU,SAAU,OAAM,IAAI,UAAU,qDAAqD;AAClI,UAAM,SAAS,MAAM,SAAS,UAAU,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAe;AACpF,QAAI,WAAW,OAAW,OAAM,IAAI,WAAW,kDAAkD;AACjG,WAAO;AAAA,EACT;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,YAAY,IAAI,WAAW,EAAE,IAAI,GAAG,mBAAmB,MAAM,CAAE,CAAC,IAAI;AAAA,QACpE,YAAY,IAAI,WAAW,EAAE,IAAI,GAAG,mBAAmB,MAAM,CAAE,CAAC,IAAI;AAAA,MACtE;AAAA,MAEC,gBAAM;AAAA;AAAA,EACT;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,9 @@
1
1
  import type { Signal } from "@pibbl/core";
2
2
  import type { ResolvedScale, ScaleId } from "./types.js";
3
- export declare function provideScale(id: ScaleId, value: Signal<ResolvedScale>, linear: Signal<ResolvedScale>, band: Signal<ResolvedScale>): void;
4
- export declare function lookupScale(id: ScaleId | undefined, receiver: string, type?: "linear" | "band"): Signal<ResolvedScale> | undefined;
3
+ export declare function scaleKind(value: Signal<ResolvedScale>): "band" | "linear" | "log" | "point" | "symlog" | "utc" | undefined;
4
+ export declare function provideScale(id: ScaleId, value: Signal<ResolvedScale>, kind: ResolvedScale["type"]): void;
5
+ export declare function lookupScale(id: ScaleId | undefined, receiver: string): Signal<ResolvedScale> | undefined;
5
6
  /** Invocation-scoped lookup for official viz receivers; does not allocate a hook. */
6
- export declare function readScale(id: ScaleId | undefined, receiver: string, type?: "linear" | "band"): Signal<ResolvedScale> | undefined;
7
+ export declare function readScale(id: ScaleId | undefined, receiver: string): Signal<ResolvedScale> | undefined;
7
8
  /** Captures visible ancestors so reactive formulas can resolve IDs outside traversal. */
8
- export declare function captureScaleLookup(receiver: string): (id: ScaleId | undefined, type?: "linear" | "band") => Signal<ResolvedScale> | undefined;
9
+ export declare function captureScaleLookup(receiver: string): (id: ScaleId | undefined) => Signal<ResolvedScale> | undefined;
@@ -4,13 +4,16 @@ import {
4
4
  useInternalHookSlot
5
5
  } from "@pibbl/core/internal";
6
6
  let current;
7
- function provideScale(id, value, linear, band) {
7
+ const kinds = /* @__PURE__ */ new WeakMap();
8
+ function scaleKind(value) {
9
+ return kinds.get(value);
10
+ }
11
+ function provideScale(id, value, kind) {
12
+ kinds.set(value, kind);
8
13
  const parent = current;
9
14
  const scope = {
10
15
  id,
11
16
  value,
12
- linear,
13
- band,
14
17
  canvas: getCurrentBackendHostCanvas(),
15
18
  parent
16
19
  };
@@ -25,20 +28,20 @@ function provideScale(id, value, linear, band) {
25
28
  throw error;
26
29
  }
27
30
  }
28
- function lookupScale(id, receiver, type) {
31
+ function lookupScale(id, receiver) {
29
32
  useInternalHookSlot("vizScaleLookup", () => void 0);
30
- return readScale(id, receiver, type);
33
+ return readScale(id, receiver);
31
34
  }
32
- function readScale(id, receiver, type) {
33
- return findScale(current, getCurrentBackendHostCanvas(), id, receiver, type);
35
+ function readScale(id, receiver) {
36
+ return findScale(current, getCurrentBackendHostCanvas(), id, receiver);
34
37
  }
35
38
  function captureScaleLookup(receiver) {
36
39
  useInternalHookSlot("vizScaleLookup", () => void 0);
37
40
  const parent = current;
38
41
  const canvas = getCurrentBackendHostCanvas();
39
- return (id, type) => findScale(parent, canvas, id, receiver, type);
42
+ return (id) => findScale(parent, canvas, id, receiver);
40
43
  }
41
- function findScale(parent, canvas, id, receiver, type) {
44
+ function findScale(parent, canvas, id, receiver) {
42
45
  if (id === void 0) return void 0;
43
46
  for (let scope = parent; scope; scope = scope.parent) {
44
47
  if (scope.id !== id) continue;
@@ -46,7 +49,7 @@ function findScale(parent, canvas, id, receiver, type) {
46
49
  throw new Error(
47
50
  `${receiver}: scale ${String(id)} crosses a Layer boundary; place Scale inside the Layer.`
48
51
  );
49
- return type ? scope[type] : scope.value;
52
+ return scope.value;
50
53
  }
51
54
  throw new Error(
52
55
  `${receiver}: unknown scale ${String(id)}; add an ancestor Scale with this ID.`
@@ -56,6 +59,7 @@ export {
56
59
  captureScaleLookup,
57
60
  lookupScale,
58
61
  provideScale,
59
- readScale
62
+ readScale,
63
+ scaleKind
60
64
  };
61
65
  //# sourceMappingURL=scale-context.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/scale-context.ts"],
4
- "sourcesContent": ["import type { Canvas, Signal } from \"@pibbl/core\";\nimport {\n getCurrentBackendHostCanvas,\n setCurrentComponentAfterRender,\n useInternalHookSlot,\n} from \"@pibbl/core/internal\";\nimport type { ResolvedScale, ScaleId } from \"./types.js\";\ninterface Scope {\n id: ScaleId;\n value: Signal<ResolvedScale>;\n linear: Signal<ResolvedScale>;\n band: Signal<ResolvedScale>;\n canvas: Canvas;\n parent: Scope | undefined;\n}\nlet current: Scope | undefined;\nexport function provideScale(\n id: ScaleId,\n value: Signal<ResolvedScale>,\n linear: Signal<ResolvedScale>,\n band: Signal<ResolvedScale>,\n): void {\n const parent = current;\n const scope: Scope = {\n id,\n value,\n linear,\n band,\n canvas: getCurrentBackendHostCanvas(),\n parent,\n };\n current = scope;\n const restore = () => {\n current = parent;\n };\n try {\n setCurrentComponentAfterRender(restore);\n } catch (error) {\n restore();\n throw error;\n }\n}\nexport function lookupScale(\n id: ScaleId | undefined,\n receiver: string,\n type?: \"linear\" | \"band\",\n): Signal<ResolvedScale> | undefined {\n useInternalHookSlot(\"vizScaleLookup\", () => undefined);\n return readScale(id, receiver, type);\n}\n/** Invocation-scoped lookup for official viz receivers; does not allocate a hook. */\nexport function readScale(\n id: ScaleId | undefined,\n receiver: string,\n type?: \"linear\" | \"band\",\n): Signal<ResolvedScale> | undefined {\n return findScale(current, getCurrentBackendHostCanvas(), id, receiver, type);\n}\n/** Captures visible ancestors so reactive formulas can resolve IDs outside traversal. */\nexport function captureScaleLookup(receiver: string) {\n useInternalHookSlot(\"vizScaleLookup\", () => undefined);\n const parent = current;\n const canvas = getCurrentBackendHostCanvas();\n return (id: ScaleId | undefined, type?: \"linear\" | \"band\") =>\n findScale(parent, canvas, id, receiver, type);\n}\nfunction findScale(\n parent: Scope | undefined,\n canvas: Canvas,\n id: ScaleId | undefined,\n receiver: string,\n type?: \"linear\" | \"band\",\n): Signal<ResolvedScale> | undefined {\n if (id === undefined) return undefined;\n for (let scope = parent; scope; scope = scope.parent) {\n if (scope.id !== id) continue;\n if (scope.canvas !== canvas)\n throw new Error(\n `${receiver}: scale ${String(id)} crosses a Layer boundary; place Scale inside the Layer.`,\n );\n return type ? scope[type] : scope.value;\n }\n throw new Error(\n `${receiver}: unknown scale ${String(id)}; add an ancestor Scale with this ID.`,\n );\n}\n"],
5
- "mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUP,IAAI;AACG,SAAS,aACd,IACA,OACA,QACA,MACM;AACN,QAAM,SAAS;AACf,QAAM,QAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,4BAA4B;AAAA,IACpC;AAAA,EACF;AACA,YAAU;AACV,QAAM,UAAU,MAAM;AACpB,cAAU;AAAA,EACZ;AACA,MAAI;AACF,mCAA+B,OAAO;AAAA,EACxC,SAAS,OAAO;AACd,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AACO,SAAS,YACd,IACA,UACA,MACmC;AACnC,sBAAoB,kBAAkB,MAAM,MAAS;AACrD,SAAO,UAAU,IAAI,UAAU,IAAI;AACrC;AAEO,SAAS,UACd,IACA,UACA,MACmC;AACnC,SAAO,UAAU,SAAS,4BAA4B,GAAG,IAAI,UAAU,IAAI;AAC7E;AAEO,SAAS,mBAAmB,UAAkB;AACnD,sBAAoB,kBAAkB,MAAM,MAAS;AACrD,QAAM,SAAS;AACf,QAAM,SAAS,4BAA4B;AAC3C,SAAO,CAAC,IAAyB,SAC/B,UAAU,QAAQ,QAAQ,IAAI,UAAU,IAAI;AAChD;AACA,SAAS,UACP,QACA,QACA,IACA,UACA,MACmC;AACnC,MAAI,OAAO,OAAW,QAAO;AAC7B,WAAS,QAAQ,QAAQ,OAAO,QAAQ,MAAM,QAAQ;AACpD,QAAI,MAAM,OAAO,GAAI;AACrB,QAAI,MAAM,WAAW;AACnB,YAAM,IAAI;AAAA,QACR,GAAG,QAAQ,WAAW,OAAO,EAAE,CAAC;AAAA,MAClC;AACF,WAAO,OAAO,MAAM,IAAI,IAAI,MAAM;AAAA,EACpC;AACA,QAAM,IAAI;AAAA,IACR,GAAG,QAAQ,mBAAmB,OAAO,EAAE,CAAC;AAAA,EAC1C;AACF;",
4
+ "sourcesContent": ["import type { Canvas, Signal } from \"@pibbl/core\";\nimport {\n getCurrentBackendHostCanvas,\n setCurrentComponentAfterRender,\n useInternalHookSlot,\n} from \"@pibbl/core/internal\";\nimport type { ResolvedScale, ScaleId } from \"./types.js\";\ninterface Scope {\n id: ScaleId;\n value: Signal<ResolvedScale>;\n canvas: Canvas;\n parent: Scope | undefined;\n}\nlet current: Scope | undefined;\nconst kinds = new WeakMap<Signal<ResolvedScale>, ResolvedScale[\"type\"]>();\nexport function scaleKind(value: Signal<ResolvedScale>) { return kinds.get(value); }\nexport function provideScale(\n id: ScaleId,\n value: Signal<ResolvedScale>,\n kind: ResolvedScale[\"type\"],\n): void {\n kinds.set(value, kind);\n const parent = current;\n const scope: Scope = {\n id,\n value,\n canvas: getCurrentBackendHostCanvas(),\n parent,\n };\n current = scope;\n const restore = () => {\n current = parent;\n };\n try {\n setCurrentComponentAfterRender(restore);\n } catch (error) {\n restore();\n throw error;\n }\n}\nexport function lookupScale(\n id: ScaleId | undefined,\n receiver: string,\n): Signal<ResolvedScale> | undefined {\n useInternalHookSlot(\"vizScaleLookup\", () => undefined);\n return readScale(id, receiver);\n}\n/** Invocation-scoped lookup for official viz receivers; does not allocate a hook. */\nexport function readScale(\n id: ScaleId | undefined,\n receiver: string,\n): Signal<ResolvedScale> | undefined {\n return findScale(current, getCurrentBackendHostCanvas(), id, receiver);\n}\n/** Captures visible ancestors so reactive formulas can resolve IDs outside traversal. */\nexport function captureScaleLookup(receiver: string) {\n useInternalHookSlot(\"vizScaleLookup\", () => undefined);\n const parent = current;\n const canvas = getCurrentBackendHostCanvas();\n return (id: ScaleId | undefined) =>\n findScale(parent, canvas, id, receiver);\n}\nfunction findScale(\n parent: Scope | undefined,\n canvas: Canvas,\n id: ScaleId | undefined,\n receiver: string,\n): Signal<ResolvedScale> | undefined {\n if (id === undefined) return undefined;\n for (let scope = parent; scope; scope = scope.parent) {\n if (scope.id !== id) continue;\n if (scope.canvas !== canvas)\n throw new Error(\n `${receiver}: scale ${String(id)} crosses a Layer boundary; place Scale inside the Layer.`,\n );\n return scope.value;\n }\n throw new Error(\n `${receiver}: unknown scale ${String(id)}; add an ancestor Scale with this ID.`,\n );\n}\n"],
5
+ "mappings": "AACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP,IAAI;AACJ,MAAM,QAAQ,oBAAI,QAAsD;AACjE,SAAS,UAAU,OAA8B;AAAE,SAAO,MAAM,IAAI,KAAK;AAAG;AAC5E,SAAS,aACd,IACA,OACA,MACM;AACN,QAAM,IAAI,OAAO,IAAI;AACrB,QAAM,SAAS;AACf,QAAM,QAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA,QAAQ,4BAA4B;AAAA,IACpC;AAAA,EACF;AACA,YAAU;AACV,QAAM,UAAU,MAAM;AACpB,cAAU;AAAA,EACZ;AACA,MAAI;AACF,mCAA+B,OAAO;AAAA,EACxC,SAAS,OAAO;AACd,YAAQ;AACR,UAAM;AAAA,EACR;AACF;AACO,SAAS,YACd,IACA,UACmC;AACnC,sBAAoB,kBAAkB,MAAM,MAAS;AACrD,SAAO,UAAU,IAAI,QAAQ;AAC/B;AAEO,SAAS,UACd,IACA,UACmC;AACnC,SAAO,UAAU,SAAS,4BAA4B,GAAG,IAAI,QAAQ;AACvE;AAEO,SAAS,mBAAmB,UAAkB;AACnD,sBAAoB,kBAAkB,MAAM,MAAS;AACrD,QAAM,SAAS;AACf,QAAM,SAAS,4BAA4B;AAC3C,SAAO,CAAC,OACN,UAAU,QAAQ,QAAQ,IAAI,QAAQ;AAC1C;AACA,SAAS,UACP,QACA,QACA,IACA,UACmC;AACnC,MAAI,OAAO,OAAW,QAAO;AAC7B,WAAS,QAAQ,QAAQ,OAAO,QAAQ,MAAM,QAAQ;AACpD,QAAI,MAAM,OAAO,GAAI;AACrB,QAAI,MAAM,WAAW;AACnB,YAAM,IAAI;AAAA,QACR,GAAG,QAAQ,WAAW,OAAO,EAAE,CAAC;AAAA,MAClC;AACF,WAAO,MAAM;AAAA,EACf;AACA,QAAM,IAAI;AAAA,IACR,GAAG,QAAQ,mBAAmB,OAAO,EAAE,CAAC;AAAA,EAC1C;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,2 @@
1
+ import type { ResolvedScale, ScaleId } from "./types.js";
2
+ export declare function useScaleProvider(id: ScaleId, kind: ResolvedScale["type"], resolve: () => ResolvedScale, dependencies: readonly unknown[]): void;
@@ -0,0 +1,13 @@
1
+ import { useComputed } from "@pibbl/core";
2
+ import { equalScale } from "./linear-scale.js";
3
+ import { provideScale } from "./scale-context.js";
4
+ function useScaleProvider(id, kind, resolve, dependencies) {
5
+ if ((typeof id !== "string" || id.length === 0) && typeof id !== "symbol")
6
+ throw new TypeError("Scale id requires a nonempty string or symbol.");
7
+ const value = useComputed(resolve, dependencies, { equals: equalScale });
8
+ provideScale(id, value, kind);
9
+ }
10
+ export {
11
+ useScaleProvider
12
+ };
13
+ //# sourceMappingURL=scale-provider.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/scale-provider.ts"],
4
+ "sourcesContent": ["import { useComputed } from \"@pibbl/core\";\nimport { equalScale } from \"./linear-scale.js\";\nimport { provideScale } from \"./scale-context.js\";\nimport type { ResolvedScale, ScaleId } from \"./types.js\";\nexport function useScaleProvider(id: ScaleId, kind: ResolvedScale[\"type\"], resolve: () => ResolvedScale, dependencies: readonly unknown[]): void {\n if ((typeof id !== \"string\" || id.length === 0) && typeof id !== \"symbol\")\n throw new TypeError(\"Scale id requires a nonempty string or symbol.\");\n const value = useComputed(resolve, dependencies, { equals: equalScale });\n provideScale(id, value, kind);\n}\n"],
5
+ "mappings": "AAAA,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAC3B,SAAS,oBAAoB;AAEtB,SAAS,iBAAiB,IAAa,MAA6B,SAA8B,cAAwC;AAC/I,OAAK,OAAO,OAAO,YAAY,GAAG,WAAW,MAAM,OAAO,OAAO;AAC/D,UAAM,IAAI,UAAU,gDAAgD;AACtE,QAAM,QAAQ,YAAY,SAAS,cAAc,EAAE,QAAQ,WAAW,CAAC;AACvE,eAAa,IAAI,OAAO,IAAI;AAC9B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,5 @@
1
+ import type { AxisProps, ResolvedScale } from "./types.js";
2
+ type Tick = number | string;
3
+ export declare function ticks(scale: ResolvedScale, props: Pick<AxisProps, "tickValues" | "tickCount">): readonly Tick[];
4
+ export declare function position(scale: ResolvedScale, value: Tick): number;
5
+ export {};
@@ -0,0 +1,49 @@
1
+ import { resolveSignalValue } from "@pibbl/core";
2
+ function ticks(scale, props) {
3
+ if (props.tickValues !== void 0 && props.tickCount !== void 0)
4
+ throw new TypeError("Axis tickValues and tickCount are mutually exclusive.");
5
+ const explicit = props.tickValues === void 0 ? void 0 : resolveSignalValue(props.tickValues);
6
+ if (explicit !== void 0) {
7
+ if (!Array.isArray(explicit) || explicit.length > 100)
8
+ throw new RangeError("Axis tickValues must be an array with at most 100 values.");
9
+ const seen = /* @__PURE__ */ new Set();
10
+ for (const value of explicit) {
11
+ if (seen.has(value)) throw new RangeError("Axis tickValues must not contain duplicates.");
12
+ seen.add(value);
13
+ if (scale.type !== "band" && scale.type !== "point") {
14
+ if (typeof value !== "number" || !Number.isFinite(value))
15
+ throw new TypeError("Axis tickValues for a continuous scale must be finite numbers.");
16
+ const [a, b] = scale.domain;
17
+ if (value < Math.min(a, b) || value > Math.max(a, b))
18
+ throw new RangeError("Axis tickValues must be within the scale domain.");
19
+ } else if (typeof value !== "string" && (typeof value !== "number" || !Number.isFinite(value)) || scale.map(value) === void 0) {
20
+ throw new RangeError("Axis tickValues must be known band categories.");
21
+ }
22
+ }
23
+ return explicit;
24
+ }
25
+ const count = resolveSignalValue(props.tickCount ?? 5);
26
+ if (!Number.isInteger(count) || count < 0 || count > 100)
27
+ throw new RangeError("Axis tickCount must be an integer from 0 to 100.");
28
+ if (count === 0) return [];
29
+ if (scale.type !== "band" && scale.type !== "point")
30
+ return count === 1 ? [scale.domain[0]] : scale.ticks(count);
31
+ const n = scale.domain.length;
32
+ if (n === 0) return [];
33
+ if (count === 1) return [scale.domain[0]];
34
+ const m = Math.min(count, n);
35
+ if (m === 1) return [scale.domain[0]];
36
+ return Array.from(
37
+ { length: m },
38
+ (_, index) => scale.domain[Math.round(index * (n - 1) / (m - 1))]
39
+ );
40
+ }
41
+ function position(scale, value) {
42
+ if (scale.type === "point") return scale.map(value);
43
+ return scale.type === "band" ? scale.map(value) + scale.bandwidth / 2 : scale.map(value);
44
+ }
45
+ export {
46
+ position,
47
+ ticks
48
+ };
49
+ //# sourceMappingURL=scale-ticks.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/scale-ticks.ts"],
4
+ "sourcesContent": ["import { resolveSignalValue } from \"@pibbl/core\";\nimport type { AxisProps, BandCategory, ResolvedScale } from \"./types.js\";\ntype Tick = number | string;\n\nexport function ticks(scale: ResolvedScale, props: Pick<AxisProps, \"tickValues\" | \"tickCount\">): readonly Tick[] {\n if (props.tickValues !== undefined && props.tickCount !== undefined)\n throw new TypeError(\"Axis tickValues and tickCount are mutually exclusive.\");\n const explicit = props.tickValues === undefined\n ? undefined\n : resolveSignalValue(props.tickValues);\n if (explicit !== undefined) {\n if (!Array.isArray(explicit) || explicit.length > 100)\n throw new RangeError(\"Axis tickValues must be an array with at most 100 values.\");\n const seen = new Set<Tick>();\n for (const value of explicit) {\n if (seen.has(value)) throw new RangeError(\"Axis tickValues must not contain duplicates.\");\n seen.add(value);\n if (scale.type !== \"band\" && scale.type !== \"point\") {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new TypeError(\"Axis tickValues for a continuous scale must be finite numbers.\");\n const [a, b] = scale.domain;\n if (value < Math.min(a, b) || value > Math.max(a, b))\n throw new RangeError(\"Axis tickValues must be within the scale domain.\");\n } else if (\n (typeof value !== \"string\" &&\n (typeof value !== \"number\" || !Number.isFinite(value))) ||\n scale.map(value as BandCategory) === undefined\n ) {\n throw new RangeError(\"Axis tickValues must be known band categories.\");\n }\n }\n return explicit;\n }\n const count = resolveSignalValue(props.tickCount ?? 5);\n if (!Number.isInteger(count) || count < 0 || count > 100)\n throw new RangeError(\"Axis tickCount must be an integer from 0 to 100.\");\n if (count === 0) return [];\n if (scale.type !== \"band\" && scale.type !== \"point\")\n return count === 1 ? [scale.domain[0]] : scale.ticks(count);\n const n = scale.domain.length;\n if (n === 0) return [];\n if (count === 1) return [scale.domain[0]];\n const m = Math.min(count, n);\n if (m === 1) return [scale.domain[0]];\n return Array.from(\n { length: m },\n (_, index) => scale.domain[Math.round((index * (n - 1)) / (m - 1))]!,\n );\n}\n\nexport function position(scale: ResolvedScale, value: Tick): number {\n if (scale.type === \"point\") return scale.map(value as BandCategory)!;\n return scale.type === \"band\"\n ? scale.map(value as BandCategory)! + scale.bandwidth / 2\n : scale.map(value as number);\n}\n\n"],
5
+ "mappings": "AAAA,SAAS,0BAA0B;AAI5B,SAAS,MAAM,OAAsB,OAAqE;AAC/G,MAAI,MAAM,eAAe,UAAa,MAAM,cAAc;AACxD,UAAM,IAAI,UAAU,uDAAuD;AAC7E,QAAM,WAAW,MAAM,eAAe,SAClC,SACA,mBAAmB,MAAM,UAAU;AACvC,MAAI,aAAa,QAAW;AAC1B,QAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,SAAS,SAAS;AAChD,YAAM,IAAI,WAAW,2DAA2D;AAClF,UAAM,OAAO,oBAAI,IAAU;AAC3B,eAAW,SAAS,UAAU;AAC5B,UAAI,KAAK,IAAI,KAAK,EAAG,OAAM,IAAI,WAAW,8CAA8C;AACxF,WAAK,IAAI,KAAK;AACd,UAAI,MAAM,SAAS,UAAU,MAAM,SAAS,SAAS;AACnD,YAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK;AACrD,gBAAM,IAAI,UAAU,gEAAgE;AACtF,cAAM,CAAC,GAAG,CAAC,IAAI,MAAM;AACrB,YAAI,QAAQ,KAAK,IAAI,GAAG,CAAC,KAAK,QAAQ,KAAK,IAAI,GAAG,CAAC;AACjD,gBAAM,IAAI,WAAW,kDAAkD;AAAA,MAC3E,WACG,OAAO,UAAU,aACf,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,MACtD,MAAM,IAAI,KAAqB,MAAM,QACrC;AACA,cAAM,IAAI,WAAW,gDAAgD;AAAA,MACvE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,mBAAmB,MAAM,aAAa,CAAC;AACrD,MAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ;AACnD,UAAM,IAAI,WAAW,kDAAkD;AACzE,MAAI,UAAU,EAAG,QAAO,CAAC;AACzB,MAAI,MAAM,SAAS,UAAU,MAAM,SAAS;AAC1C,WAAO,UAAU,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,MAAM,MAAM,KAAK;AAC5D,QAAM,IAAI,MAAM,OAAO;AACvB,MAAI,MAAM,EAAG,QAAO,CAAC;AACrB,MAAI,UAAU,EAAG,QAAO,CAAC,MAAM,OAAO,CAAC,CAAC;AACxC,QAAM,IAAI,KAAK,IAAI,OAAO,CAAC;AAC3B,MAAI,MAAM,EAAG,QAAO,CAAC,MAAM,OAAO,CAAC,CAAC;AACpC,SAAO,MAAM;AAAA,IACX,EAAE,QAAQ,EAAE;AAAA,IACZ,CAAC,GAAG,UAAU,MAAM,OAAO,KAAK,MAAO,SAAS,IAAI,MAAO,IAAI,EAAE,CAAC;AAAA,EACpE;AACF;AAEO,SAAS,SAAS,OAAsB,OAAqB;AAClE,MAAI,MAAM,SAAS,QAAS,QAAO,MAAM,IAAI,KAAqB;AAClE,SAAO,MAAM,SAAS,SAClB,MAAM,IAAI,KAAqB,IAAK,MAAM,YAAY,IACtD,MAAM,IAAI,KAAe;AAC/B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,4 @@
1
+ import { type Signal } from "@pibbl/core";
2
+ import type { ResolvedScale, ScaleId } from "./types.js";
3
+ /** A lazy shared view: one readonly signal per provider and supported hook. */
4
+ export declare function scaleView<T extends ResolvedScale>(cache: WeakMap<Signal<ResolvedScale>, Signal<T>>, id: ScaleId, receiver: string, accepts: (kind: ResolvedScale["type"] | undefined) => boolean): Signal<T>;
@@ -0,0 +1,21 @@
1
+ import { computed } from "@pibbl/core";
2
+ import { lookupScale, scaleKind } from "./scale-context.js";
3
+ function scaleView(cache, id, receiver, accepts) {
4
+ const source = lookupScale(id, receiver);
5
+ if (!source) throw new TypeError(`${receiver} requires a scale ID.`);
6
+ if (accepts(scaleKind(source))) return source;
7
+ let view = cache.get(source);
8
+ if (!view) {
9
+ view = computed(() => {
10
+ const value = source.get();
11
+ if (!accepts(value.type)) throw new TypeError(`${receiver} cannot read a ${value.type} scale.`);
12
+ return value;
13
+ });
14
+ cache.set(source, view);
15
+ }
16
+ return view;
17
+ }
18
+ export {
19
+ scaleView
20
+ };
21
+ //# sourceMappingURL=scale-view.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/scale-view.ts"],
4
+ "sourcesContent": ["import { computed, type Signal } from \"@pibbl/core\";\nimport { lookupScale, scaleKind } from \"./scale-context.js\";\nimport type { ResolvedScale, ScaleId } from \"./types.js\";\n/** A lazy shared view: one readonly signal per provider and supported hook. */\nexport function scaleView<T extends ResolvedScale>(\n cache: WeakMap<Signal<ResolvedScale>, Signal<T>>,\n id: ScaleId,\n receiver: string,\n accepts: (kind: ResolvedScale[\"type\"] | undefined) => boolean,\n): Signal<T> {\n const source = lookupScale(id, receiver);\n if (!source) throw new TypeError(`${receiver} requires a scale ID.`);\n // Return the provider transaction directly; an extra computed cache would hide\n // candidate formulas during layout/reflow until the render commits.\n if (accepts(scaleKind(source))) return source as Signal<T>;\n let view = cache.get(source);\n if (!view) {\n view = computed(() => {\n const value = source.get();\n if (!accepts(value.type)) throw new TypeError(`${receiver} cannot read a ${value.type} scale.`);\n return value as T;\n });\n cache.set(source, view);\n }\n return view;\n}\n"],
5
+ "mappings": "AAAA,SAAS,gBAA6B;AACtC,SAAS,aAAa,iBAAiB;AAGhC,SAAS,UACd,OACA,IACA,UACA,SACW;AACX,QAAM,SAAS,YAAY,IAAI,QAAQ;AACvC,MAAI,CAAC,OAAQ,OAAM,IAAI,UAAU,GAAG,QAAQ,uBAAuB;AAGnE,MAAI,QAAQ,UAAU,MAAM,CAAC,EAAG,QAAO;AACvC,MAAI,OAAO,MAAM,IAAI,MAAM;AAC3B,MAAI,CAAC,MAAM;AACT,WAAO,SAAS,MAAM;AACpB,YAAM,QAAQ,OAAO,IAAI;AACzB,UAAI,CAAC,QAAQ,MAAM,IAAI,EAAG,OAAM,IAAI,UAAU,GAAG,QAAQ,kBAAkB,MAAM,IAAI,SAAS;AAC9F,aAAO;AAAA,IACT,CAAC;AACD,UAAM,IAAI,QAAQ,IAAI;AAAA,EACxB;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { SymlogScaleProps } from "./types.js";
2
+ /**
3
+ * Provides a named symlog mapping to descendant visualization components.
4
+ * @param props - Identity, domain, range, and constant. See {@link SymlogScaleProps}.
5
+ * @returns Descendant content within the scale scope.
6
+ */
7
+ export declare function SymlogScale(props: SymlogScaleProps): import("@pibbl/core").PibblNode;
@@ -0,0 +1,19 @@
1
+ import { resolveSignalValue, useLayoutBox } from "@pibbl/core";
2
+ import { resolveSymlogScale } from "./symlog-scale.js";
3
+ import { useScaleProvider } from "./scale-provider.js";
4
+ function SymlogScale(props) {
5
+ const { width, height } = useLayoutBox();
6
+ useScaleProvider(props.id, "symlog", () => resolveSymlogScale(
7
+ resolveSignalValue(props.domain),
8
+ resolveSignalValue(props.range),
9
+ resolveSignalValue(props.reverse ?? false),
10
+ width,
11
+ height,
12
+ resolveSignalValue(props.constant ?? 1)
13
+ ), [props.domain, props.range, props.reverse, props.constant, width, height]);
14
+ return props.children;
15
+ }
16
+ export {
17
+ SymlogScale
18
+ };
19
+ //# sourceMappingURL=symlog-scale-component.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/symlog-scale-component.ts"],
4
+ "sourcesContent": ["import { resolveSignalValue, useLayoutBox } from \"@pibbl/core\";\nimport type { SymlogScaleProps } from \"./types.js\";\nimport { resolveSymlogScale } from \"./symlog-scale.js\";\nimport { useScaleProvider } from \"./scale-provider.js\";\n/**\n * Provides a named symlog mapping to descendant visualization components.\n * @param props - Identity, domain, range, and constant. See {@link SymlogScaleProps}.\n * @returns Descendant content within the scale scope.\n */\nexport function SymlogScale(props: SymlogScaleProps) {\n const { width, height } = useLayoutBox();\n useScaleProvider(props.id, \"symlog\", () => resolveSymlogScale(\n resolveSignalValue(props.domain), resolveSignalValue(props.range),\n resolveSignalValue(props.reverse ?? false), width, height, resolveSignalValue(props.constant ?? 1),\n ), [props.domain, props.range, props.reverse, props.constant, width, height]);\n return props.children;\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB,oBAAoB;AAEjD,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AAM1B,SAAS,YAAY,OAAyB;AACnD,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa;AACvC,mBAAiB,MAAM,IAAI,UAAU,MAAM;AAAA,IACzC,mBAAmB,MAAM,MAAM;AAAA,IAAG,mBAAmB,MAAM,KAAK;AAAA,IAChE,mBAAmB,MAAM,WAAW,KAAK;AAAA,IAAG;AAAA,IAAO;AAAA,IAAQ,mBAAmB,MAAM,YAAY,CAAC;AAAA,EACnG,GAAG,CAAC,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,MAAM,UAAU,OAAO,MAAM,CAAC;AAC5E,SAAO,MAAM;AACf;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { LinearDomain, ResolvedSymlogScale, ScaleRange } from "./types.js";
2
+ export declare function resolveSymlogScale(domain: LinearDomain, range: ScaleRange, reverse: boolean, width: number, height: number, constant: number): ResolvedSymlogScale;
@@ -0,0 +1,38 @@
1
+ import { resolveLinearScale } from "./linear-scale.js";
2
+ import { linearTicks } from "./numeric-ticks.js";
3
+ function resolveSymlogScale(domain, range, reverse, width, height, constant) {
4
+ if (typeof constant !== "number" || !Number.isFinite(constant) || constant <= 0)
5
+ throw new RangeError("SymlogScale constant must be finite and positive.");
6
+ const original = resolveLinearScale(domain, range, reverse, width, height);
7
+ const transform = (value) => {
8
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new RangeError("SymlogScale map input must be finite.");
9
+ const ratio = Math.abs(value) / constant;
10
+ return Math.sign(value) * (Number.isFinite(ratio) ? Math.log1p(ratio) : Math.log(Math.abs(value)) - Math.log(constant));
11
+ };
12
+ const mapping = resolveLinearScale([transform(domain[0]), transform(domain[1])], original.range, false, width, height);
13
+ return Object.freeze({
14
+ ...original,
15
+ type: "symlog",
16
+ constant,
17
+ map(value) {
18
+ return mapping.map(transform(value));
19
+ },
20
+ invert(pixel) {
21
+ if (mapping.range[0] !== mapping.range[1]) {
22
+ if (pixel === mapping.range[0]) return original.domain[0];
23
+ if (pixel === mapping.range[1]) return original.domain[1];
24
+ }
25
+ const t = mapping.invert(pixel), magnitude = Math.abs(t);
26
+ const value = Math.sign(t) * (magnitude < 700 ? constant * Math.expm1(magnitude) : Math.exp(magnitude + Math.log(constant)) - constant);
27
+ if (!Number.isFinite(value)) throw new RangeError("SymlogScale inverted output must be finite.");
28
+ return value || 0;
29
+ },
30
+ ticks(count = 5) {
31
+ return linearTicks(original.domain, { count });
32
+ }
33
+ });
34
+ }
35
+ export {
36
+ resolveSymlogScale
37
+ };
38
+ //# sourceMappingURL=symlog-scale.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/symlog-scale.ts"],
4
+ "sourcesContent": ["import type { LinearDomain, ResolvedSymlogScale, ScaleRange } from \"./types.js\";\nimport { resolveLinearScale } from \"./linear-scale.js\";\nimport { linearTicks } from \"./numeric-ticks.js\";\nexport function resolveSymlogScale(domain: LinearDomain, range: ScaleRange, reverse: boolean, width: number, height: number, constant: number): ResolvedSymlogScale {\n if (typeof constant !== \"number\" || !Number.isFinite(constant) || constant <= 0)\n throw new RangeError(\"SymlogScale constant must be finite and positive.\");\n const original = resolveLinearScale(domain, range, reverse, width, height);\n const transform = (value: number) => {\n if (typeof value !== \"number\" || !Number.isFinite(value)) throw new RangeError(\"SymlogScale map input must be finite.\");\n const ratio = Math.abs(value) / constant;\n return Math.sign(value) * (Number.isFinite(ratio) ? Math.log1p(ratio) : Math.log(Math.abs(value)) - Math.log(constant));\n };\n const mapping = resolveLinearScale([transform(domain[0]), transform(domain[1])], original.range, false, width, height);\n return Object.freeze({\n ...original, type: \"symlog\", constant,\n map(value: number) { return mapping.map(transform(value)); },\n invert(pixel: number) {\n if (mapping.range[0] !== mapping.range[1]) {\n if (pixel === mapping.range[0]) return original.domain[0];\n if (pixel === mapping.range[1]) return original.domain[1];\n }\n const t = mapping.invert(pixel), magnitude = Math.abs(t);\n const value = Math.sign(t) * (magnitude < 700 ? constant * Math.expm1(magnitude) : Math.exp(magnitude + Math.log(constant)) - constant);\n if (!Number.isFinite(value)) throw new RangeError(\"SymlogScale inverted output must be finite.\");\n return value || 0;\n },\n ticks(count = 5) { return linearTicks(original.domain, { count }); },\n });\n}\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AACrB,SAAS,mBAAmB,QAAsB,OAAmB,SAAkB,OAAe,QAAgB,UAAuC;AAClK,MAAI,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,QAAQ,KAAK,YAAY;AAC5E,UAAM,IAAI,WAAW,mDAAmD;AAC1E,QAAM,WAAW,mBAAmB,QAAQ,OAAO,SAAS,OAAO,MAAM;AACzE,QAAM,YAAY,CAAC,UAAkB;AACnC,QAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,OAAM,IAAI,WAAW,uCAAuC;AACtH,UAAM,QAAQ,KAAK,IAAI,KAAK,IAAI;AAChC,WAAO,KAAK,KAAK,KAAK,KAAK,OAAO,SAAS,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,QAAQ;AAAA,EACvH;AACA,QAAM,UAAU,mBAAmB,CAAC,UAAU,OAAO,CAAC,CAAC,GAAG,UAAU,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,OAAO,OAAO,OAAO,MAAM;AACrH,SAAO,OAAO,OAAO;AAAA,IACnB,GAAG;AAAA,IAAU,MAAM;AAAA,IAAU;AAAA,IAC7B,IAAI,OAAe;AAAE,aAAO,QAAQ,IAAI,UAAU,KAAK,CAAC;AAAA,IAAG;AAAA,IAC3D,OAAO,OAAe;AACpB,UAAI,QAAQ,MAAM,CAAC,MAAM,QAAQ,MAAM,CAAC,GAAG;AACzC,YAAI,UAAU,QAAQ,MAAM,CAAC,EAAG,QAAO,SAAS,OAAO,CAAC;AACxD,YAAI,UAAU,QAAQ,MAAM,CAAC,EAAG,QAAO,SAAS,OAAO,CAAC;AAAA,MAC1D;AACA,YAAM,IAAI,QAAQ,OAAO,KAAK,GAAG,YAAY,KAAK,IAAI,CAAC;AACvD,YAAM,QAAQ,KAAK,KAAK,CAAC,KAAK,YAAY,MAAM,WAAW,KAAK,MAAM,SAAS,IAAI,KAAK,IAAI,YAAY,KAAK,IAAI,QAAQ,CAAC,IAAI;AAC9H,UAAI,CAAC,OAAO,SAAS,KAAK,EAAG,OAAM,IAAI,WAAW,6CAA6C;AAC/F,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,MAAM,QAAQ,GAAG;AAAE,aAAO,YAAY,SAAS,QAAQ,EAAE,MAAM,CAAC;AAAA,IAAG;AAAA,EACrE,CAAC;AACH;",
6
+ "names": []
7
+ }