@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
@@ -0,0 +1,7 @@
1
+ import type { LinearScaleProps } from "./types.js";
2
+ /**
3
+ * Provides a named linear mapping to descendant visualization components.
4
+ * @param props - Identity, domain, range, and children. See {@link LinearScaleProps}.
5
+ * @returns Descendant content within the scale scope.
6
+ */
7
+ export declare function LinearScale(props: LinearScaleProps): import("@pibbl/core").PibblNode;
@@ -0,0 +1,18 @@
1
+ import { resolveSignalValue, useLayoutBox } from "@pibbl/core";
2
+ import { resolveLinearScale } from "./linear-scale.js";
3
+ import { useScaleProvider } from "./scale-provider.js";
4
+ function LinearScale(props) {
5
+ const { width, height } = useLayoutBox();
6
+ useScaleProvider(props.id, "linear", () => resolveLinearScale(
7
+ resolveSignalValue(props.domain),
8
+ resolveSignalValue(props.range),
9
+ resolveSignalValue(props.reverse ?? false),
10
+ width,
11
+ height
12
+ ), [props.domain, props.range, props.reverse, width, height]);
13
+ return props.children;
14
+ }
15
+ export {
16
+ LinearScale
17
+ };
18
+ //# sourceMappingURL=linear-scale-component.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/linear-scale-component.ts"],
4
+ "sourcesContent": ["import { resolveSignalValue, useLayoutBox } from \"@pibbl/core\";\nimport type { LinearScaleProps } from \"./types.js\";\nimport { resolveLinearScale } from \"./linear-scale.js\";\nimport { useScaleProvider } from \"./scale-provider.js\";\n/**\n * Provides a named linear mapping to descendant visualization components.\n * @param props - Identity, domain, range, and children. See {@link LinearScaleProps}.\n * @returns Descendant content within the scale scope.\n */\nexport function LinearScale(props: LinearScaleProps) {\n const { width, height } = useLayoutBox();\n useScaleProvider(props.id, \"linear\", () => resolveLinearScale(\n resolveSignalValue(props.domain), resolveSignalValue(props.range),\n resolveSignalValue(props.reverse ?? false), width, height,\n ), [props.domain, props.range, props.reverse, 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,EACrD,GAAG,CAAC,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,OAAO,MAAM,CAAC;AAC5D,SAAO,MAAM;AACf;",
6
+ "names": []
7
+ }
@@ -61,7 +61,7 @@ function resolveLinearScale(domainInput, rangeInput, reverse, width, height) {
61
61
  });
62
62
  }
63
63
  function equalScale(a, b) {
64
- return a.type === b.type && a.domain.length === b.domain.length && a.domain.every((value, index) => Object.is(value, b.domain[index])) && (a.type !== "band" || b.type === "band" && a.bandwidth === b.bandwidth && a.step === b.step) && Object.is(a.range[0], b.range[0]) && Object.is(a.range[1], b.range[1]) && Object.is(a.frame.width, b.frame.width) && Object.is(a.frame.height, b.frame.height);
64
+ return a.type === b.type && (a.type !== "symlog" || b.type === "symlog" && a.constant === b.constant) && (a.type !== "point" || b.type === "point" && a.padding === b.padding) && (a.type !== "log" || b.type === "log" && a.base === b.base) && a.domain.length === b.domain.length && a.domain.every((value, index) => Object.is(value, b.domain[index])) && (a.type !== "band" || b.type === "band" && a.bandwidth === b.bandwidth && a.step === b.step) && Object.is(a.range[0], b.range[0]) && Object.is(a.range[1], b.range[1]) && Object.is(a.frame.width, b.frame.width) && Object.is(a.frame.height, b.frame.height);
65
65
  }
66
66
  export {
67
67
  equalScale,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/linear-scale.ts"],
4
- "sourcesContent": ["import type {\n LinearDomain,\n ResolvedLinearScale,\n ResolvedScale,\n ScaleRange,\n} from \"./types.js\";\nfunction finite(value: number, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new RangeError(`Scale ${field} must be finite.`);\n return value;\n}\nfunction pair(\n value: readonly number[],\n field: string,\n): readonly [number, number] {\n if (!Array.isArray(value) || value.length !== 2)\n throw new RangeError(`Scale ${field} requires two finite endpoints.`);\n return Object.freeze([finite(value[0], field), finite(value[1], field)]);\n}\nexport function resolveLinearScale(\n domainInput: LinearDomain,\n rangeInput: ScaleRange,\n reverse: boolean,\n width: number,\n height: number,\n): ResolvedLinearScale {\n finite(width, \"frame.width\");\n finite(height, \"frame.height\");\n if (width < 0 || height < 0)\n throw new RangeError(\"Scale allocation must be nonnegative.\");\n if (typeof reverse !== \"boolean\")\n throw new TypeError(\"Scale reverse must be boolean.\");\n const domain = pair(domainInput, \"domain\");\n if (domain[0] === domain[1])\n throw new RangeError(\"Scale domain endpoints must differ.\");\n const original = pair(\n rangeInput === \"width\"\n ? [0, width]\n : rangeInput === \"height\"\n ? [0, height]\n : (rangeInput as readonly number[]),\n \"range\",\n );\n const range = reverse ? pair([original[1], original[0]], \"range\") : original;\n const domainSpan = finite(domain[1] - domain[0], \"domain span\");\n const rangeSpan = finite(range[1] - range[0], \"range span\");\n return Object.freeze({\n type: \"linear\",\n domain,\n range,\n frame: Object.freeze({ x: 0, y: 0, width, height }),\n map(value: number) {\n return finite(\n range[0] +\n ((finite(value, \"map input\") - domain[0]) / domainSpan) * rangeSpan,\n \"mapped output\",\n );\n },\n invert(pixel: number) {\n if (rangeSpan === 0)\n throw new RangeError(\n \"Scale cannot invert a collapsed range; supply a nonzero extent.\",\n );\n return finite(\n domain[0] +\n ((finite(pixel, \"invert input\") - range[0]) / rangeSpan) * domainSpan,\n \"inverted output\",\n );\n },\n ticks(count = 5) {\n if (!Number.isInteger(count) || count < 2 || count > 100)\n throw new RangeError(\n \"Scale ticks count must be an integer from 2 to 100.\",\n );\n return Object.freeze(\n Array.from({ length: count }, (_, i) =>\n i === count - 1\n ? domain[1]\n : finite(domain[0] + (domainSpan * i) / (count - 1), \"tick\"),\n ),\n );\n },\n });\n}\nexport function equalScale(a: ResolvedScale, b: ResolvedScale): boolean {\n return (\n a.type === b.type &&\n a.domain.length === b.domain.length &&\n a.domain.every((value, index) => Object.is(value, b.domain[index])) &&\n (a.type !== \"band\" ||\n (b.type === \"band\" &&\n a.bandwidth === b.bandwidth &&\n a.step === b.step)) &&\n Object.is(a.range[0], b.range[0]) &&\n Object.is(a.range[1], b.range[1]) &&\n Object.is(a.frame.width, b.frame.width) &&\n Object.is(a.frame.height, b.frame.height)\n );\n}\n"],
5
- "mappings": "AAMA,SAAS,OAAO,OAAe,OAAuB;AACpD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK;AACrD,UAAM,IAAI,WAAW,SAAS,KAAK,kBAAkB;AACvD,SAAO;AACT;AACA,SAAS,KACP,OACA,OAC2B;AAC3B,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW;AAC5C,UAAM,IAAI,WAAW,SAAS,KAAK,iCAAiC;AACtE,SAAO,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,GAAG,KAAK,GAAG,OAAO,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC;AACzE;AACO,SAAS,mBACd,aACA,YACA,SACA,OACA,QACqB;AACrB,SAAO,OAAO,aAAa;AAC3B,SAAO,QAAQ,cAAc;AAC7B,MAAI,QAAQ,KAAK,SAAS;AACxB,UAAM,IAAI,WAAW,uCAAuC;AAC9D,MAAI,OAAO,YAAY;AACrB,UAAM,IAAI,UAAU,gCAAgC;AACtD,QAAM,SAAS,KAAK,aAAa,QAAQ;AACzC,MAAI,OAAO,CAAC,MAAM,OAAO,CAAC;AACxB,UAAM,IAAI,WAAW,qCAAqC;AAC5D,QAAM,WAAW;AAAA,IACf,eAAe,UACX,CAAC,GAAG,KAAK,IACT,eAAe,WACb,CAAC,GAAG,MAAM,IACT;AAAA,IACP;AAAA,EACF;AACA,QAAM,QAAQ,UAAU,KAAK,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,GAAG,OAAO,IAAI;AACpE,QAAM,aAAa,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC,GAAG,aAAa;AAC9D,QAAM,YAAY,OAAO,MAAM,CAAC,IAAI,MAAM,CAAC,GAAG,YAAY;AAC1D,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,OAAO,OAAO,OAAO,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,OAAO,CAAC;AAAA,IAClD,IAAI,OAAe;AACjB,aAAO;AAAA,QACL,MAAM,CAAC,KACH,OAAO,OAAO,WAAW,IAAI,OAAO,CAAC,KAAK,aAAc;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,OAAe;AACpB,UAAI,cAAc;AAChB,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AACF,aAAO;AAAA,QACL,OAAO,CAAC,KACJ,OAAO,OAAO,cAAc,IAAI,MAAM,CAAC,KAAK,YAAa;AAAA,QAC7D;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,QAAQ,GAAG;AACf,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ;AACnD,cAAM,IAAI;AAAA,UACR;AAAA,QACF;AACF,aAAO,OAAO;AAAA,QACZ,MAAM;AAAA,UAAK,EAAE,QAAQ,MAAM;AAAA,UAAG,CAAC,GAAG,MAChC,MAAM,QAAQ,IACV,OAAO,CAAC,IACR,OAAO,OAAO,CAAC,IAAK,aAAa,KAAM,QAAQ,IAAI,MAAM;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AACO,SAAS,WAAW,GAAkB,GAA2B;AACtE,SACE,EAAE,SAAS,EAAE,QACb,EAAE,OAAO,WAAW,EAAE,OAAO,UAC7B,EAAE,OAAO,MAAM,CAAC,OAAO,UAAU,OAAO,GAAG,OAAO,EAAE,OAAO,KAAK,CAAC,CAAC,MACjE,EAAE,SAAS,UACT,EAAE,SAAS,UACV,EAAE,cAAc,EAAE,aAClB,EAAE,SAAS,EAAE,SACjB,OAAO,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,KAChC,OAAO,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,KAChC,OAAO,GAAG,EAAE,MAAM,OAAO,EAAE,MAAM,KAAK,KACtC,OAAO,GAAG,EAAE,MAAM,QAAQ,EAAE,MAAM,MAAM;AAE5C;",
4
+ "sourcesContent": ["import type {\n LinearDomain,\n ResolvedLinearScale,\n ResolvedScale,\n ScaleRange,\n} from \"./types.js\";\nfunction finite(value: number, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value))\n throw new RangeError(`Scale ${field} must be finite.`);\n return value;\n}\nfunction pair(\n value: readonly number[],\n field: string,\n): readonly [number, number] {\n if (!Array.isArray(value) || value.length !== 2)\n throw new RangeError(`Scale ${field} requires two finite endpoints.`);\n return Object.freeze([finite(value[0], field), finite(value[1], field)]);\n}\nexport function resolveLinearScale(\n domainInput: LinearDomain,\n rangeInput: ScaleRange,\n reverse: boolean,\n width: number,\n height: number,\n): ResolvedLinearScale {\n finite(width, \"frame.width\");\n finite(height, \"frame.height\");\n if (width < 0 || height < 0)\n throw new RangeError(\"Scale allocation must be nonnegative.\");\n if (typeof reverse !== \"boolean\")\n throw new TypeError(\"Scale reverse must be boolean.\");\n const domain = pair(domainInput, \"domain\");\n if (domain[0] === domain[1])\n throw new RangeError(\"Scale domain endpoints must differ.\");\n const original = pair(\n rangeInput === \"width\"\n ? [0, width]\n : rangeInput === \"height\"\n ? [0, height]\n : (rangeInput as readonly number[]),\n \"range\",\n );\n const range = reverse ? pair([original[1], original[0]], \"range\") : original;\n const domainSpan = finite(domain[1] - domain[0], \"domain span\");\n const rangeSpan = finite(range[1] - range[0], \"range span\");\n return Object.freeze({\n type: \"linear\",\n domain,\n range,\n frame: Object.freeze({ x: 0, y: 0, width, height }),\n map(value: number) {\n return finite(\n range[0] +\n ((finite(value, \"map input\") - domain[0]) / domainSpan) * rangeSpan,\n \"mapped output\",\n );\n },\n invert(pixel: number) {\n if (rangeSpan === 0)\n throw new RangeError(\n \"Scale cannot invert a collapsed range; supply a nonzero extent.\",\n );\n return finite(\n domain[0] +\n ((finite(pixel, \"invert input\") - range[0]) / rangeSpan) * domainSpan,\n \"inverted output\",\n );\n },\n ticks(count = 5) {\n if (!Number.isInteger(count) || count < 2 || count > 100)\n throw new RangeError(\n \"Scale ticks count must be an integer from 2 to 100.\",\n );\n return Object.freeze(\n Array.from({ length: count }, (_, i) =>\n i === count - 1\n ? domain[1]\n : finite(domain[0] + (domainSpan * i) / (count - 1), \"tick\"),\n ),\n );\n },\n });\n}\nexport function equalScale(a: ResolvedScale, b: ResolvedScale): boolean {\n return (\n a.type === b.type &&\n (a.type !== \"symlog\" || (b.type === \"symlog\" && a.constant === b.constant)) &&\n (a.type !== \"point\" || (b.type === \"point\" && a.padding === b.padding)) &&\n (a.type !== \"log\" || (b.type === \"log\" && a.base === b.base)) &&\n a.domain.length === b.domain.length &&\n a.domain.every((value, index) => Object.is(value, b.domain[index])) &&\n (a.type !== \"band\" ||\n (b.type === \"band\" &&\n a.bandwidth === b.bandwidth &&\n a.step === b.step)) &&\n Object.is(a.range[0], b.range[0]) &&\n Object.is(a.range[1], b.range[1]) &&\n Object.is(a.frame.width, b.frame.width) &&\n Object.is(a.frame.height, b.frame.height)\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,7 @@
1
+ import type { LogScaleProps } from "./types.js";
2
+ /**
3
+ * Provides a named positive logarithmic mapping to descendant marks and axes.
4
+ * @param props - Identity, positive domain, range, and optional tick base. See {@link LogScaleProps}.
5
+ * @returns Descendant content within the logarithmic scale scope.
6
+ */
7
+ export declare function LogScale(props: LogScaleProps): import("@pibbl/core").PibblNode;
@@ -0,0 +1,19 @@
1
+ import { resolveSignalValue, useLayoutBox } from "@pibbl/core";
2
+ import { resolveLogScale } from "./log-scale.js";
3
+ import { useScaleProvider } from "./scale-provider.js";
4
+ function LogScale(props) {
5
+ const { width, height } = useLayoutBox();
6
+ useScaleProvider(props.id, "log", () => resolveLogScale(
7
+ resolveSignalValue(props.domain),
8
+ resolveSignalValue(props.range),
9
+ resolveSignalValue(props.reverse ?? false),
10
+ width,
11
+ height,
12
+ resolveSignalValue(props.base ?? 10)
13
+ ), [props.domain, props.range, props.reverse, props.base, width, height]);
14
+ return props.children;
15
+ }
16
+ export {
17
+ LogScale
18
+ };
19
+ //# sourceMappingURL=log-scale-component.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/log-scale-component.ts"],
4
+ "sourcesContent": ["import { resolveSignalValue, useLayoutBox } from \"@pibbl/core\";\nimport type { LogScaleProps } from \"./types.js\";\nimport { resolveLogScale } from \"./log-scale.js\";\nimport { useScaleProvider } from \"./scale-provider.js\";\n/**\n * Provides a named positive logarithmic mapping to descendant marks and axes.\n * @param props - Identity, positive domain, range, and optional tick base. See {@link LogScaleProps}.\n * @returns Descendant content within the logarithmic scale scope.\n */\nexport function LogScale(props: LogScaleProps) {\n const { width, height } = useLayoutBox();\n useScaleProvider(props.id, \"log\", () => resolveLogScale(\n resolveSignalValue(props.domain), resolveSignalValue(props.range),\n resolveSignalValue(props.reverse ?? false), width, height, resolveSignalValue(props.base ?? 10),\n ), [props.domain, props.range, props.reverse, props.base, width, height]);\n return props.children;\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB,oBAAoB;AAEjD,SAAS,uBAAuB;AAChC,SAAS,wBAAwB;AAM1B,SAAS,SAAS,OAAsB;AAC7C,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa;AACvC,mBAAiB,MAAM,IAAI,OAAO,MAAM;AAAA,IACtC,mBAAmB,MAAM,MAAM;AAAA,IAAG,mBAAmB,MAAM,KAAK;AAAA,IAChE,mBAAmB,MAAM,WAAW,KAAK;AAAA,IAAG;AAAA,IAAO;AAAA,IAAQ,mBAAmB,MAAM,QAAQ,EAAE;AAAA,EAChG,GAAG,CAAC,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,MAAM,MAAM,OAAO,MAAM,CAAC;AACxE,SAAO,MAAM;AACf;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { LinearDomain, ResolvedLogScale, ScaleRange } from "./types.js";
2
+ export declare function resolveLogScale(domainInput: LinearDomain, range: ScaleRange, reverse: boolean, width: number, height: number, base: number): ResolvedLogScale;
@@ -0,0 +1,53 @@
1
+ import { resolveLinearScale } from "./linear-scale.js";
2
+ function positive(value, field) {
3
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
4
+ throw new RangeError(`LogScale ${field} must be finite and positive.`);
5
+ return value;
6
+ }
7
+ function resolveLogScale(domainInput, range, reverse, width, height, base) {
8
+ if (typeof base !== "number" || !Number.isFinite(base) || base <= 1)
9
+ throw new RangeError("LogScale base must be finite and greater than one.");
10
+ if (!Array.isArray(domainInput) || domainInput.length !== 2)
11
+ throw new RangeError("LogScale domain requires two positive endpoints.");
12
+ const domain = Object.freeze([positive(domainInput[0], "domain"), positive(domainInput[1], "domain")]);
13
+ const logarithm = (value) => Math.log(positive(value, "map input"));
14
+ const mapping = resolveLinearScale([logarithm(domain[0]), logarithm(domain[1])], range, reverse, width, height);
15
+ return Object.freeze({
16
+ ...mapping,
17
+ type: "log",
18
+ domain,
19
+ base,
20
+ map(value) {
21
+ return mapping.map(logarithm(value));
22
+ },
23
+ invert(pixel) {
24
+ if (pixel === mapping.range[0] && mapping.range[0] !== mapping.range[1]) return domain[0];
25
+ if (pixel === mapping.range[1] && mapping.range[0] !== mapping.range[1]) return domain[1];
26
+ return positive(Math.exp(mapping.invert(pixel)), "inverted output");
27
+ },
28
+ ticks(count = 5) {
29
+ if (!Number.isInteger(count) || count < 2 || count > 100)
30
+ throw new RangeError("LogScale ticks count must be an integer from 2 to 100.");
31
+ if (count === 2) return Object.freeze([...domain]);
32
+ const lo = Math.min(...domain), hi = Math.max(...domain);
33
+ const first = Math.floor(Math.log(lo) / Math.log(base)) + 1;
34
+ const last = Math.ceil(Math.log(hi) / Math.log(base)) - 1;
35
+ if (!Number.isSafeInteger(first) || !Number.isSafeInteger(last))
36
+ throw new RangeError("LogScale tick exponents exceed numeric precision; choose a larger base.");
37
+ const stride = Math.max(1, Math.ceil((last - first + 1) / (count - 2)));
38
+ const ticks = [lo];
39
+ for (let i = 0; i < count - 2; i++) {
40
+ const exponent = first + i * stride;
41
+ if (exponent > last) break;
42
+ const value = base ** exponent;
43
+ if (Number.isFinite(value) && value > ticks[ticks.length - 1] && value < hi) ticks.push(value);
44
+ }
45
+ ticks.push(hi);
46
+ return Object.freeze(domain[0] > domain[1] ? ticks.reverse() : ticks);
47
+ }
48
+ });
49
+ }
50
+ export {
51
+ resolveLogScale
52
+ };
53
+ //# sourceMappingURL=log-scale.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/log-scale.ts"],
4
+ "sourcesContent": ["import type { LinearDomain, ResolvedLogScale, ScaleRange } from \"./types.js\";\nimport { resolveLinearScale } from \"./linear-scale.js\";\nfunction positive(value: number, field: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0)\n throw new RangeError(`LogScale ${field} must be finite and positive.`);\n return value;\n}\nexport function resolveLogScale(domainInput: LinearDomain, range: ScaleRange, reverse: boolean, width: number, height: number, base: number): ResolvedLogScale {\n if (typeof base !== \"number\" || !Number.isFinite(base) || base <= 1)\n throw new RangeError(\"LogScale base must be finite and greater than one.\");\n if (!Array.isArray(domainInput) || domainInput.length !== 2)\n throw new RangeError(\"LogScale domain requires two positive endpoints.\");\n const domain = Object.freeze([positive(domainInput[0], \"domain\"), positive(domainInput[1], \"domain\")] as const);\n const logarithm = (value: number) => Math.log(positive(value, \"map input\"));\n const mapping = resolveLinearScale([logarithm(domain[0]), logarithm(domain[1])], range, reverse, width, height);\n return Object.freeze({\n ...mapping, type: \"log\", domain, base,\n map(value: number) { return mapping.map(logarithm(value)); },\n invert(pixel: number) {\n if (pixel === mapping.range[0] && mapping.range[0] !== mapping.range[1]) return domain[0];\n if (pixel === mapping.range[1] && mapping.range[0] !== mapping.range[1]) return domain[1];\n return positive(Math.exp(mapping.invert(pixel)), \"inverted output\");\n },\n ticks(count = 5) {\n if (!Number.isInteger(count) || count < 2 || count > 100)\n throw new RangeError(\"LogScale ticks count must be an integer from 2 to 100.\");\n if (count === 2) return Object.freeze([...domain]);\n const lo = Math.min(...domain), hi = Math.max(...domain);\n const first = Math.floor(Math.log(lo) / Math.log(base)) + 1;\n const last = Math.ceil(Math.log(hi) / Math.log(base)) - 1;\n if (!Number.isSafeInteger(first) || !Number.isSafeInteger(last))\n throw new RangeError(\"LogScale tick exponents exceed numeric precision; choose a larger base.\");\n const stride = Math.max(1, Math.ceil((last - first + 1) / (count - 2)));\n const ticks: number[] = [lo];\n for (let i = 0; i < count - 2; i++) {\n const exponent = first + i * stride;\n if (exponent > last) break;\n const value = base ** exponent;\n if (Number.isFinite(value) && value > ticks[ticks.length - 1] && value < hi) ticks.push(value);\n }\n ticks.push(hi);\n return Object.freeze(domain[0] > domain[1] ? ticks.reverse() : ticks);\n },\n });\n}\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,SAAS,OAAe,OAAuB;AACtD,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS;AACnE,UAAM,IAAI,WAAW,YAAY,KAAK,+BAA+B;AACvE,SAAO;AACT;AACO,SAAS,gBAAgB,aAA2B,OAAmB,SAAkB,OAAe,QAAgB,MAAgC;AAC7J,MAAI,OAAO,SAAS,YAAY,CAAC,OAAO,SAAS,IAAI,KAAK,QAAQ;AAChE,UAAM,IAAI,WAAW,oDAAoD;AAC3E,MAAI,CAAC,MAAM,QAAQ,WAAW,KAAK,YAAY,WAAW;AACxD,UAAM,IAAI,WAAW,kDAAkD;AACzE,QAAM,SAAS,OAAO,OAAO,CAAC,SAAS,YAAY,CAAC,GAAG,QAAQ,GAAG,SAAS,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAU;AAC9G,QAAM,YAAY,CAAC,UAAkB,KAAK,IAAI,SAAS,OAAO,WAAW,CAAC;AAC1E,QAAM,UAAU,mBAAmB,CAAC,UAAU,OAAO,CAAC,CAAC,GAAG,UAAU,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,SAAS,OAAO,MAAM;AAC9G,SAAO,OAAO,OAAO;AAAA,IACnB,GAAG;AAAA,IAAS,MAAM;AAAA,IAAO;AAAA,IAAQ;AAAA,IACjC,IAAI,OAAe;AAAE,aAAO,QAAQ,IAAI,UAAU,KAAK,CAAC;AAAA,IAAG;AAAA,IAC3D,OAAO,OAAe;AACpB,UAAI,UAAU,QAAQ,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,MAAM,QAAQ,MAAM,CAAC,EAAG,QAAO,OAAO,CAAC;AACxF,UAAI,UAAU,QAAQ,MAAM,CAAC,KAAK,QAAQ,MAAM,CAAC,MAAM,QAAQ,MAAM,CAAC,EAAG,QAAO,OAAO,CAAC;AACxF,aAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,CAAC,GAAG,iBAAiB;AAAA,IACpE;AAAA,IACA,MAAM,QAAQ,GAAG;AACf,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ;AACnD,cAAM,IAAI,WAAW,wDAAwD;AAC/E,UAAI,UAAU,EAAG,QAAO,OAAO,OAAO,CAAC,GAAG,MAAM,CAAC;AACjD,YAAM,KAAK,KAAK,IAAI,GAAG,MAAM,GAAG,KAAK,KAAK,IAAI,GAAG,MAAM;AACvD,YAAM,QAAQ,KAAK,MAAM,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI;AAC1D,YAAM,OAAO,KAAK,KAAK,KAAK,IAAI,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI;AACxD,UAAI,CAAC,OAAO,cAAc,KAAK,KAAK,CAAC,OAAO,cAAc,IAAI;AAC5D,cAAM,IAAI,WAAW,yEAAyE;AAChG,YAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM,OAAO,QAAQ,MAAM,QAAQ,EAAE,CAAC;AACtE,YAAM,QAAkB,CAAC,EAAE;AAC3B,eAAS,IAAI,GAAG,IAAI,QAAQ,GAAG,KAAK;AAClC,cAAM,WAAW,QAAQ,IAAI;AAC7B,YAAI,WAAW,KAAM;AACrB,cAAM,QAAQ,QAAQ;AACtB,YAAI,OAAO,SAAS,KAAK,KAAK,QAAQ,MAAM,MAAM,SAAS,CAAC,KAAK,QAAQ,GAAI,OAAM,KAAK,KAAK;AAAA,MAC/F;AACA,YAAM,KAAK,EAAE;AACb,aAAO,OAAO,OAAO,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,MAAM,QAAQ,IAAI,KAAK;AAAA,IACtE;AAAA,EACF,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -1,10 +1,10 @@
1
- import type { ResolvedLinearScale } from "./types.js";
1
+ import type { ResolvedContinuousScale } from "./types.js";
2
2
  import type { PointAccessor } from "./point-types.js";
3
3
  /**
4
4
  * Coordinate accessors, resolved scales, and candidate filtering for a nearest-point search.
5
5
  *
6
6
  * @see {@link PointAccessor}
7
- * @see {@link ResolvedLinearScale}
7
+ * @see {@link ResolvedContinuousScale}
8
8
  * @see {@link nearestPoint}
9
9
  */
10
10
  export interface NearestPointOptions<D> {
@@ -12,10 +12,10 @@ export interface NearestPointOptions<D> {
12
12
  readonly x: PointAccessor<D>;
13
13
  /** Property key or callback extracting the vertical domain coordinate. See {@link PointAccessor}. */
14
14
  readonly y: PointAccessor<D>;
15
- /** The scale used to map horizontal data coordinates. See {@link ResolvedLinearScale}. */
16
- readonly xScale: ResolvedLinearScale;
17
- /** The scale used to map vertical data coordinates. See {@link ResolvedLinearScale}. */
18
- readonly yScale: ResolvedLinearScale;
15
+ /** The scale used to map horizontal data coordinates. See {@link ResolvedContinuousScale}. */
16
+ readonly xScale: ResolvedContinuousScale;
17
+ /** The scale used to map vertical data coordinates. See {@link ResolvedContinuousScale}. */
18
+ readonly yScale: ResolvedContinuousScale;
19
19
  /**
20
20
  * Returns whether a datum contributes drawable or queryable coordinates. See
21
21
  * {@link NearestPointOptions}.
@@ -57,12 +57,12 @@ export interface NearestPoint<D> {
57
57
  *
58
58
  * @param values - Candidate domain values.
59
59
  * @param rangeValue - Pointer coordinate in the scale's range.
60
- * @param scale - Scale mapping candidates into range coordinates. See {@link ResolvedLinearScale}.
60
+ * @param scale - Scale mapping candidates into range coordinates. See {@link ResolvedContinuousScale}.
61
61
  * @returns The nearest domain value, or undefined when no candidate can be selected.
62
62
  *
63
- * @see {@link ResolvedLinearScale}
63
+ * @see {@link ResolvedContinuousScale}
64
64
  */
65
- export declare function nearestDomainValue(values: readonly number[], rangeValue: number, scale: ResolvedLinearScale): number | undefined;
65
+ export declare function nearestDomainValue(values: readonly number[], rangeValue: number, scale: ResolvedContinuousScale): number | undefined;
66
66
  /**
67
67
  * Finds the nearest defined datum in scaled coordinates, subject to an optional maximum distance.
68
68
  *
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/nearest.ts"],
4
- "sourcesContent": ["import type { ResolvedLinearScale } from \"./types.js\";\nimport type { PointAccessor } from \"./point-types.js\";\nimport { finiteCoordinate, pointAccessor, pointData } from \"./point-data.js\";\n/**\n * Coordinate accessors, resolved scales, and candidate filtering for a nearest-point search.\n *\n * @see {@link PointAccessor}\n * @see {@link ResolvedLinearScale}\n * @see {@link nearestPoint}\n */\nexport interface NearestPointOptions<D> {\n /** Property key or callback extracting the horizontal domain coordinate. See {@link PointAccessor}. */\n readonly x: PointAccessor<D>;\n /** Property key or callback extracting the vertical domain coordinate. See {@link PointAccessor}. */\n readonly y: PointAccessor<D>;\n /** The scale used to map horizontal data coordinates. See {@link ResolvedLinearScale}. */\n readonly xScale: ResolvedLinearScale;\n /** The scale used to map vertical data coordinates. See {@link ResolvedLinearScale}. */\n readonly yScale: ResolvedLinearScale;\n /**\n * Returns whether a datum contributes drawable or queryable coordinates. See\n * {@link NearestPointOptions}.\n * @param datum - Datum to test.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns Whether this datum should participate in the series or query.\n */\n readonly defined?: (datum: D, index: number, data: readonly D[]) => boolean;\n /** Maximum distance accepted by the query. See {@link NearestPointOptions}. */\n readonly maxDistance?: number;\n}\n/**\n * The selected datum, source index, mapped coordinates, and distance from the query point.\n *\n * @see {@link nearestPoint}\n */\nexport interface NearestPoint<D> {\n /** The original data item selected by this result. See {@link NearestPoint}. */\n readonly datum: D;\n /** Index of the selected datum in its source data. See {@link NearestPoint}. */\n readonly index: number;\n /**\n * Horizontal coordinate or displacement in the containing coordinate system. See\n * {@link NearestPoint}.\n */\n readonly x: number;\n /**\n * Vertical coordinate or displacement in the containing coordinate system. See\n * {@link NearestPoint}.\n */\n readonly y: number;\n /** Distance measured in this query or guide's coordinate system. See {@link NearestPoint}. */\n readonly distance: number;\n}\nfunction finite(value: unknown, name: string): asserts value is number {\n if (!finiteCoordinate(value)) throw new RangeError(`${name} must be finite.`);\n}\n/**\n * Finds the domain value nearest to a logical range coordinate; returns undefined for no\n * candidate.\n *\n * @param values - Candidate domain values.\n * @param rangeValue - Pointer coordinate in the scale's range.\n * @param scale - Scale mapping candidates into range coordinates. See {@link ResolvedLinearScale}.\n * @returns The nearest domain value, or undefined when no candidate can be selected.\n *\n * @see {@link ResolvedLinearScale}\n */\nexport function nearestDomainValue(\n values: readonly number[],\n rangeValue: number,\n scale: ResolvedLinearScale,\n): number | undefined {\n pointData(values, \"nearestDomainValue\");\n finite(rangeValue, \"nearestDomainValue rangeValue\");\n let best: number | undefined,\n distance = Infinity;\n for (const value of values) {\n if (!finiteCoordinate(value)) continue;\n const next = Math.abs(scale.map(value) - rangeValue);\n finite(next, \"nearestDomainValue distance\");\n if (next < distance) {\n best = value;\n distance = next;\n }\n }\n return best;\n}\n/**\n * Finds the nearest defined datum in scaled coordinates, subject to an optional maximum distance.\n *\n * @param data - Candidate data records.\n * @param point - Query point in plotted range coordinates.\n * @param options - Accessors, scales, eligibility, and distance settings. See\n * {@link NearestPointOptions} .\n * @returns The nearest matching point, or undefined when no candidate qualifies. See\n * {@link NearestPoint} .\n *\n * @see {@link NearestPointOptions}\n * @see {@link NearestPoint}\n */\nexport function nearestPoint<D>(\n data: readonly D[],\n point: Readonly<{ x: number; y: number }>,\n options: NearestPointOptions<D>,\n): NearestPoint<D> | undefined {\n pointData(data, \"nearestPoint\");\n finite(point.x, \"nearestPoint x\");\n finite(point.y, \"nearestPoint y\");\n const max = options.maxDistance;\n if (max !== undefined) {\n finite(max, \"nearestPoint maxDistance\");\n if (max < 0)\n throw new RangeError(\"nearestPoint maxDistance must be nonnegative.\");\n }\n const x = pointAccessor(options.x),\n y = pointAccessor(options.y);\n let best: NearestPoint<D> | undefined,\n distance = Infinity;\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (options.defined && !options.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 = options.xScale.map(xv),\n py = options.yScale.map(yv);\n const next = Math.hypot(px - point.x, py - point.y);\n finite(next, \"nearestPoint distance\");\n if (next < distance && (max === undefined || next <= max)) {\n distance = next;\n best = { datum, index: i, x: px, y: py, distance: next };\n }\n }\n return best;\n}\n"],
4
+ "sourcesContent": ["import type { ResolvedContinuousScale } from \"./types.js\";\nimport type { PointAccessor } from \"./point-types.js\";\nimport { finiteCoordinate, pointAccessor, pointData } from \"./point-data.js\";\n/**\n * Coordinate accessors, resolved scales, and candidate filtering for a nearest-point search.\n *\n * @see {@link PointAccessor}\n * @see {@link ResolvedContinuousScale}\n * @see {@link nearestPoint}\n */\nexport interface NearestPointOptions<D> {\n /** Property key or callback extracting the horizontal domain coordinate. See {@link PointAccessor}. */\n readonly x: PointAccessor<D>;\n /** Property key or callback extracting the vertical domain coordinate. See {@link PointAccessor}. */\n readonly y: PointAccessor<D>;\n /** The scale used to map horizontal data coordinates. See {@link ResolvedContinuousScale}. */\n readonly xScale: ResolvedContinuousScale;\n /** The scale used to map vertical data coordinates. See {@link ResolvedContinuousScale}. */\n readonly yScale: ResolvedContinuousScale;\n /**\n * Returns whether a datum contributes drawable or queryable coordinates. See\n * {@link NearestPointOptions}.\n * @param datum - Datum to test.\n * @param index - Zero-based index in the source data.\n * @param data - Complete source data array.\n * @returns Whether this datum should participate in the series or query.\n */\n readonly defined?: (datum: D, index: number, data: readonly D[]) => boolean;\n /** Maximum distance accepted by the query. See {@link NearestPointOptions}. */\n readonly maxDistance?: number;\n}\n/**\n * The selected datum, source index, mapped coordinates, and distance from the query point.\n *\n * @see {@link nearestPoint}\n */\nexport interface NearestPoint<D> {\n /** The original data item selected by this result. See {@link NearestPoint}. */\n readonly datum: D;\n /** Index of the selected datum in its source data. See {@link NearestPoint}. */\n readonly index: number;\n /**\n * Horizontal coordinate or displacement in the containing coordinate system. See\n * {@link NearestPoint}.\n */\n readonly x: number;\n /**\n * Vertical coordinate or displacement in the containing coordinate system. See\n * {@link NearestPoint}.\n */\n readonly y: number;\n /** Distance measured in this query or guide's coordinate system. See {@link NearestPoint}. */\n readonly distance: number;\n}\nfunction finite(value: unknown, name: string): asserts value is number {\n if (!finiteCoordinate(value)) throw new RangeError(`${name} must be finite.`);\n}\n/**\n * Finds the domain value nearest to a logical range coordinate; returns undefined for no\n * candidate.\n *\n * @param values - Candidate domain values.\n * @param rangeValue - Pointer coordinate in the scale's range.\n * @param scale - Scale mapping candidates into range coordinates. See {@link ResolvedContinuousScale}.\n * @returns The nearest domain value, or undefined when no candidate can be selected.\n *\n * @see {@link ResolvedContinuousScale}\n */\nexport function nearestDomainValue(\n values: readonly number[],\n rangeValue: number,\n scale: ResolvedContinuousScale,\n): number | undefined {\n pointData(values, \"nearestDomainValue\");\n finite(rangeValue, \"nearestDomainValue rangeValue\");\n let best: number | undefined,\n distance = Infinity;\n for (const value of values) {\n if (!finiteCoordinate(value)) continue;\n const next = Math.abs(scale.map(value) - rangeValue);\n finite(next, \"nearestDomainValue distance\");\n if (next < distance) {\n best = value;\n distance = next;\n }\n }\n return best;\n}\n/**\n * Finds the nearest defined datum in scaled coordinates, subject to an optional maximum distance.\n *\n * @param data - Candidate data records.\n * @param point - Query point in plotted range coordinates.\n * @param options - Accessors, scales, eligibility, and distance settings. See\n * {@link NearestPointOptions} .\n * @returns The nearest matching point, or undefined when no candidate qualifies. See\n * {@link NearestPoint} .\n *\n * @see {@link NearestPointOptions}\n * @see {@link NearestPoint}\n */\nexport function nearestPoint<D>(\n data: readonly D[],\n point: Readonly<{ x: number; y: number }>,\n options: NearestPointOptions<D>,\n): NearestPoint<D> | undefined {\n pointData(data, \"nearestPoint\");\n finite(point.x, \"nearestPoint x\");\n finite(point.y, \"nearestPoint y\");\n const max = options.maxDistance;\n if (max !== undefined) {\n finite(max, \"nearestPoint maxDistance\");\n if (max < 0)\n throw new RangeError(\"nearestPoint maxDistance must be nonnegative.\");\n }\n const x = pointAccessor(options.x),\n y = pointAccessor(options.y);\n let best: NearestPoint<D> | undefined,\n distance = Infinity;\n for (let i = 0; i < data.length; i++) {\n const datum = data[i];\n if (options.defined && !options.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 = options.xScale.map(xv),\n py = options.yScale.map(yv);\n const next = Math.hypot(px - point.x, py - point.y);\n finite(next, \"nearestPoint distance\");\n if (next < distance && (max === undefined || next <= max)) {\n distance = next;\n best = { datum, index: i, x: px, y: py, distance: next };\n }\n }\n return best;\n}\n"],
5
5
  "mappings": "AAEA,SAAS,kBAAkB,eAAe,iBAAiB;AAoD3D,SAAS,OAAO,OAAgB,MAAuC;AACrE,MAAI,CAAC,iBAAiB,KAAK,EAAG,OAAM,IAAI,WAAW,GAAG,IAAI,kBAAkB;AAC9E;AAYO,SAAS,mBACd,QACA,YACA,OACoB;AACpB,YAAU,QAAQ,oBAAoB;AACtC,SAAO,YAAY,+BAA+B;AAClD,MAAI,MACF,WAAW;AACb,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,iBAAiB,KAAK,EAAG;AAC9B,UAAM,OAAO,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,UAAU;AACnD,WAAO,MAAM,6BAA6B;AAC1C,QAAI,OAAO,UAAU;AACnB,aAAO;AACP,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAcO,SAAS,aACd,MACA,OACA,SAC6B;AAC7B,YAAU,MAAM,cAAc;AAC9B,SAAO,MAAM,GAAG,gBAAgB;AAChC,SAAO,MAAM,GAAG,gBAAgB;AAChC,QAAM,MAAM,QAAQ;AACpB,MAAI,QAAQ,QAAW;AACrB,WAAO,KAAK,0BAA0B;AACtC,QAAI,MAAM;AACR,YAAM,IAAI,WAAW,+CAA+C;AAAA,EACxE;AACA,QAAM,IAAI,cAAc,QAAQ,CAAC,GAC/B,IAAI,cAAc,QAAQ,CAAC;AAC7B,MAAI,MACF,WAAW;AACb,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,QAAQ,WAAW,CAAC,QAAQ,QAAQ,OAAO,GAAG,IAAI,EAAG;AACzD,UAAM,KAAK,EAAE,OAAO,GAAG,IAAI,GACzB,KAAK,EAAE,OAAO,GAAG,IAAI;AACvB,QAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAG;AACpD,UAAM,KAAK,QAAQ,OAAO,IAAI,EAAE,GAC9B,KAAK,QAAQ,OAAO,IAAI,EAAE;AAC5B,UAAM,OAAO,KAAK,MAAM,KAAK,MAAM,GAAG,KAAK,MAAM,CAAC;AAClD,WAAO,MAAM,uBAAuB;AACpC,QAAI,OAAO,aAAa,QAAQ,UAAa,QAAQ,MAAM;AACzD,iBAAW;AACX,aAAO,EAAE,OAAO,OAAO,GAAG,GAAG,IAAI,GAAG,IAAI,UAAU,KAAK;AAAA,IACzD;AAAA,EACF;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,38 @@
1
+ import type { NumericDomain } from "./types.js";
2
+ /** Readable linear tick density. See {@link linearTicks}. */
3
+ export interface LinearTickOptions {
4
+ /** Target number of intervals, from 2 to 100; defaults to 5. */
5
+ readonly count?: number;
6
+ }
7
+ /**
8
+ * Generates bounded ticks at readable 1, 2, or 5 × powers-of-ten intervals.
9
+ * Endpoints are included only when aligned. Does not change scale geometry.
10
+ * @param domain - Distinct finite endpoints, ascending or descending.
11
+ * @param options - Target density; defaults to five intervals.
12
+ * @returns Frozen ticks in domain order. See {@link niceLinearDomain}.
13
+ */
14
+ export declare function linearTicks(domain: NumericDomain, options?: LinearTickOptions): readonly number[];
15
+ /**
16
+ * Expands a linear domain to readable tick boundaries, preserving direction.
17
+ * @param domain - Distinct finite numeric endpoints; never mutated.
18
+ * @param options - Target density; defaults to five intervals.
19
+ * @returns Frozen expanded endpoints. See {@link linearTicks}.
20
+ */
21
+ export declare function niceLinearDomain(domain: NumericDomain, options?: LinearTickOptions): NumericDomain;
22
+ /** Number formatting with explicit locale and literal unit affixes. See {@link formatNumber}. */
23
+ export interface NumberFormatOptions extends Intl.NumberFormatOptions {
24
+ /** Locale for formatting; defaults to en-US. */
25
+ readonly locale?: string;
26
+ /** Literal prefix; defaults to empty. */
27
+ readonly prefix?: string;
28
+ /** Literal suffix, including any desired space; defaults to empty. */
29
+ readonly suffix?: string;
30
+ }
31
+ /**
32
+ * Formats a finite number with Intl precision, currency, percent, or unit options.
33
+ * Rounded negative zero is displayed as positive zero.
34
+ * @param value - Finite numeric value.
35
+ * @param options - Intl options plus locale and literal affixes; default maximum fraction digits is 3.
36
+ * @returns Formatted text. Invalid Intl options retain native errors. See {@link NumberFormatOptions}.
37
+ */
38
+ export declare function formatNumber(value: number, options?: NumberFormatOptions): string;
@@ -0,0 +1,54 @@
1
+ function parameters(domain, options) {
2
+ const count = options.count ?? 5;
3
+ if (!Number.isInteger(count) || count < 2 || count > 100)
4
+ throw new RangeError("Linear tick count must be an integer from 2 to 100.");
5
+ if (!Array.isArray(domain) || domain.length !== 2 || !domain.every(Number.isFinite))
6
+ throw new RangeError("Linear tick domain requires two finite endpoints.");
7
+ const lo = Math.min(...domain), hi = Math.max(...domain);
8
+ const span = hi - lo;
9
+ if (!Number.isFinite(span) || span === 0)
10
+ throw new RangeError("Linear tick domain must have a finite nonzero span.");
11
+ const raw = span / count;
12
+ const power = 10 ** Math.floor(Math.log10(raw));
13
+ const error = raw / power;
14
+ let step = power * (error >= Math.sqrt(50) ? 10 : error >= Math.sqrt(10) ? 5 : error >= Math.sqrt(2) ? 2 : 1);
15
+ if (!Number.isFinite(step) || step === 0 || !Number.isSafeInteger(Math.floor(lo / step)) || !Number.isSafeInteger(Math.ceil(hi / step)))
16
+ throw new RangeError("Linear tick spacing exceeds numeric precision.");
17
+ if (Math.floor(hi / step) - Math.ceil(lo / step) + 1 > 100) {
18
+ const magnitude = 10 ** Math.floor(Math.log10(step));
19
+ const factor = step / magnitude;
20
+ step = magnitude * (factor < 1.5 ? 2 : factor < 3 ? 5 : 10);
21
+ }
22
+ return { lo, hi, step };
23
+ }
24
+ function clean(value) {
25
+ return Number(value.toPrecision(15)) || 0;
26
+ }
27
+ function linearTicks(domain, options = {}) {
28
+ const { lo, hi, step } = parameters(domain, options);
29
+ const start = Math.ceil(lo / step), end = Math.floor(hi / step);
30
+ const values = Array.from({ length: Math.max(0, end - start + 1) }, (_, i) => clean((start + i) * step)).filter((v) => v >= lo && v <= hi);
31
+ return Object.freeze(domain[0] > domain[1] ? values.reverse() : values);
32
+ }
33
+ function niceLinearDomain(domain, options = {}) {
34
+ const { lo, hi, step } = parameters(domain, options);
35
+ const a = clean(Math.floor(lo / step) * step), b = clean(Math.ceil(hi / step) * step);
36
+ if (!Number.isFinite(a) || !Number.isFinite(b)) throw new RangeError("Nice linear domain exceeds finite numeric bounds.");
37
+ return Object.freeze(domain[0] > domain[1] ? [b, a] : [a, b]);
38
+ }
39
+ function formatNumber(value, options = {}) {
40
+ if (!Number.isFinite(value)) throw new RangeError("formatNumber value must be finite.");
41
+ const { locale = "en-US", prefix = "", suffix = "", ...intl } = options;
42
+ const formatter = new Intl.NumberFormat(locale, intl);
43
+ const parts = formatter.formatToParts(value);
44
+ const zeroDigit = Array.from(formatter.formatToParts(0).find((p) => p.type === "integer").value).at(-1);
45
+ const digits = parts.filter((p) => p.type === "integer" || p.type === "fraction");
46
+ const zero = digits.length > 0 && digits.every((p) => Array.from(p.value).every((digit) => digit === zeroDigit));
47
+ return prefix + formatter.format(zero ? 0 : value) + suffix;
48
+ }
49
+ export {
50
+ formatNumber,
51
+ linearTicks,
52
+ niceLinearDomain
53
+ };
54
+ //# sourceMappingURL=numeric-ticks.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/numeric-ticks.ts"],
4
+ "sourcesContent": ["import type { NumericDomain } from \"./types.js\";\n\n/** Readable linear tick density. See {@link linearTicks}. */\nexport interface LinearTickOptions {\n /** Target number of intervals, from 2 to 100; defaults to 5. */\n readonly count?: number;\n}\nfunction parameters(domain: NumericDomain, options: LinearTickOptions) {\n const count = options.count ?? 5;\n if (!Number.isInteger(count) || count < 2 || count > 100)\n throw new RangeError(\"Linear tick count must be an integer from 2 to 100.\");\n if (!Array.isArray(domain) || domain.length !== 2 || !domain.every(Number.isFinite))\n throw new RangeError(\"Linear tick domain requires two finite endpoints.\");\n const lo = Math.min(...domain), hi = Math.max(...domain);\n const span = hi - lo;\n if (!Number.isFinite(span) || span === 0)\n throw new RangeError(\"Linear tick domain must have a finite nonzero span.\");\n const raw = span / count;\n const power = 10 ** Math.floor(Math.log10(raw));\n const error = raw / power;\n let step = power * (error >= Math.sqrt(50) ? 10 : error >= Math.sqrt(10) ? 5 : error >= Math.sqrt(2) ? 2 : 1);\n if (!Number.isFinite(step) || step === 0 || !Number.isSafeInteger(Math.floor(lo / step)) || !Number.isSafeInteger(Math.ceil(hi / step)))\n throw new RangeError(\"Linear tick spacing exceeds numeric precision.\");\n if (Math.floor(hi / step) - Math.ceil(lo / step) + 1 > 100) {\n const magnitude = 10 ** Math.floor(Math.log10(step));\n const factor = step / magnitude;\n step = magnitude * (factor < 1.5 ? 2 : factor < 3 ? 5 : 10);\n }\n return { lo, hi, step };\n}\nfunction clean(value: number) { return Number(value.toPrecision(15)) || 0; }\n/**\n * Generates bounded ticks at readable 1, 2, or 5 \u00D7 powers-of-ten intervals.\n * Endpoints are included only when aligned. Does not change scale geometry.\n * @param domain - Distinct finite endpoints, ascending or descending.\n * @param options - Target density; defaults to five intervals.\n * @returns Frozen ticks in domain order. See {@link niceLinearDomain}.\n */\nexport function linearTicks(domain: NumericDomain, options: LinearTickOptions = {}): readonly number[] {\n const { lo, hi, step } = parameters(domain, options);\n const start = Math.ceil(lo / step), end = Math.floor(hi / step);\n const values = Array.from({ length: Math.max(0, end - start + 1) }, (_, i) => clean((start + i) * step)).filter(v => v >= lo && v <= hi);\n return Object.freeze(domain[0] > domain[1] ? values.reverse() : values);\n}\n/**\n * Expands a linear domain to readable tick boundaries, preserving direction.\n * @param domain - Distinct finite numeric endpoints; never mutated.\n * @param options - Target density; defaults to five intervals.\n * @returns Frozen expanded endpoints. See {@link linearTicks}.\n */\nexport function niceLinearDomain(domain: NumericDomain, options: LinearTickOptions = {}): NumericDomain {\n const { lo, hi, step } = parameters(domain, options);\n const a = clean(Math.floor(lo / step) * step), b = clean(Math.ceil(hi / step) * step);\n if (!Number.isFinite(a) || !Number.isFinite(b)) throw new RangeError(\"Nice linear domain exceeds finite numeric bounds.\");\n return Object.freeze(domain[0] > domain[1] ? [b, a] : [a, b]);\n}\n/** Number formatting with explicit locale and literal unit affixes. See {@link formatNumber}. */\nexport interface NumberFormatOptions extends Intl.NumberFormatOptions {\n /** Locale for formatting; defaults to en-US. */\n readonly locale?: string;\n /** Literal prefix; defaults to empty. */\n readonly prefix?: string;\n /** Literal suffix, including any desired space; defaults to empty. */\n readonly suffix?: string;\n}\n/**\n * Formats a finite number with Intl precision, currency, percent, or unit options.\n * Rounded negative zero is displayed as positive zero.\n * @param value - Finite numeric value.\n * @param options - Intl options plus locale and literal affixes; default maximum fraction digits is 3.\n * @returns Formatted text. Invalid Intl options retain native errors. See {@link NumberFormatOptions}.\n */\nexport function formatNumber(value: number, options: NumberFormatOptions = {}): string {\n if (!Number.isFinite(value)) throw new RangeError(\"formatNumber value must be finite.\");\n const { locale = \"en-US\", prefix = \"\", suffix = \"\", ...intl } = options;\n const formatter = new Intl.NumberFormat(locale, intl);\n const parts = formatter.formatToParts(value);\n const zeroDigit = Array.from(formatter.formatToParts(0).find(p => p.type === \"integer\")!.value).at(-1)!;\n const digits = parts.filter(p => p.type === \"integer\" || p.type === \"fraction\");\n const zero = digits.length > 0 && digits.every(p => Array.from(p.value).every(digit => digit === zeroDigit));\n return prefix + formatter.format(zero ? 0 : value) + suffix;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,7 +1,7 @@
1
1
  import { jsx } from "@pibbl/core/jsx-runtime";
2
2
  import { Group, resolveSignalValue } from "@pibbl/core";
3
3
  import { pointAccessor, pointData, finiteCoordinate } from "./point-data.js";
4
- import { useScale } from "./use-scale.js";
4
+ import { useContinuousScale } from "./use-continuous-scale.js";
5
5
  function PlotRow({
6
6
  datum,
7
7
  index,
@@ -21,7 +21,7 @@ function PlotSeries({
21
21
  render,
22
22
  ...events
23
23
  }) {
24
- const xs = useScale(xId).get(), ys = useScale(yId).get();
24
+ const xs = useContinuousScale(xId).get(), ys = useContinuousScale(yId).get();
25
25
  const data = pointData(resolveSignalValue(input), "PlotSeries");
26
26
  if (typeof render !== "function")
27
27
  throw new TypeError("PlotSeries: render must be a synchronous function.");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/features/viz/lib/plot-series.tsx"],
4
- "sourcesContent": ["import { Group, resolveSignalValue } from \"@pibbl/core\";\nimport type { PibblNode } from \"@pibbl/core\";\nimport type { PlotSeriesProps } from \"./plot-types.js\";\nimport { pointAccessor, pointData, finiteCoordinate } from \"./point-data.js\";\nimport { useScale } from \"./use-scale.js\";\nfunction PlotRow<D>({\n datum,\n index,\n data,\n render,\n}: {\n datum: D;\n index: number;\n data: readonly D[];\n render: PlotSeriesProps<D>[\"render\"];\n}): PibblNode {\n return render(datum, index, data);\n}\n/**\n * Places keyed custom Pibbl subtrees at local data coordinates.\n *\n * @param props - Data, coordinate accessors, scales, keys, and per-datum renderer. See\n * {@link PlotSeriesProps} .\n * @returns Pibbl nodes placing each rendered datum at its mapped coordinates. See {@link PibblNode}.\n *\n * @see {@link PlotSeriesProps}\n * @see {@link PibblNode}\n */\nexport function PlotSeries<D>({\n data: input,\n x: xInput,\n y: yInput,\n xScale: xId,\n yScale: yId,\n defined,\n keyBy,\n render,\n ...events\n}: PlotSeriesProps<D>): PibblNode {\n const xs = useScale(xId).get(),\n ys = useScale(yId).get();\n const data = pointData(resolveSignalValue(input), \"PlotSeries\");\n if (typeof render !== \"function\")\n throw new TypeError(\"PlotSeries: render must be a synchronous function.\");\n const x = pointAccessor(xInput),\n y = pointAccessor(yInput);\n const keys = new Set<string>();\n const nodes: PibblNode[] = [];\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 key =\n keyBy === undefined\n ? i\n : typeof keyBy === \"function\"\n ? keyBy(datum, i, data)\n : datum[keyBy];\n if (typeof key !== \"string\" && typeof key !== \"number\")\n throw new TypeError(\"PlotSeries: keyBy must return a string or number.\");\n const normalized = String(key);\n if (keys.has(normalized))\n throw new Error(`PlotSeries: duplicate key \"${normalized}\".`);\n keys.add(normalized);\n nodes.push(\n <Group key={normalized} style={{ translateX: px, translateY: py }}>\n <PlotRow datum={datum} index={i} data={data} render={render} />\n </Group>,\n );\n }\n return <Group {...events}>{nodes}</Group>;\n}\n"],
5
- "mappings": "AAsEQ;AAtER,SAAS,OAAO,0BAA0B;AAG1C,SAAS,eAAe,WAAW,wBAAwB;AAC3D,SAAS,gBAAgB;AACzB,SAAS,QAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKc;AACZ,SAAO,OAAO,OAAO,OAAO,IAAI;AAClC;AAWO,SAAS,WAAc;AAAA,EAC5B,MAAM;AAAA,EACN,GAAG;AAAA,EACH,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,QAAM,KAAK,SAAS,GAAG,EAAE,IAAI,GAC3B,KAAK,SAAS,GAAG,EAAE,IAAI;AACzB,QAAM,OAAO,UAAU,mBAAmB,KAAK,GAAG,YAAY;AAC9D,MAAI,OAAO,WAAW;AACpB,UAAM,IAAI,UAAU,oDAAoD;AAC1E,QAAM,IAAI,cAAc,MAAM,GAC5B,IAAI,cAAc,MAAM;AAC1B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAqB,CAAC;AAC5B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,WAAW,CAAC,QAAQ,OAAO,GAAG,IAAI,EAAG;AACzC,UAAM,KAAK,EAAE,OAAO,GAAG,IAAI,GACzB,KAAK,EAAE,OAAO,GAAG,IAAI;AACvB,QAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAG;AACpD,UAAM,KAAK,GAAG,IAAI,EAAE,GAClB,KAAK,GAAG,IAAI,EAAE;AAChB,UAAM,MACJ,UAAU,SACN,IACA,OAAO,UAAU,aACf,MAAM,OAAO,GAAG,IAAI,IACpB,MAAM,KAAK;AACnB,QAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ;AAC5C,YAAM,IAAI,UAAU,mDAAmD;AACzE,UAAM,aAAa,OAAO,GAAG;AAC7B,QAAI,KAAK,IAAI,UAAU;AACrB,YAAM,IAAI,MAAM,8BAA8B,UAAU,IAAI;AAC9D,SAAK,IAAI,UAAU;AACnB,UAAM;AAAA,MACJ,oBAAC,SAAuB,OAAO,EAAE,YAAY,IAAI,YAAY,GAAG,GAC9D,8BAAC,WAAQ,OAAc,OAAO,GAAG,MAAY,QAAgB,KADnD,UAEZ;AAAA,IACF;AAAA,EACF;AACA,SAAO,oBAAC,SAAO,GAAG,QAAS,iBAAM;AACnC;",
4
+ "sourcesContent": ["import { Group, resolveSignalValue } from \"@pibbl/core\";\nimport type { PibblNode } from \"@pibbl/core\";\nimport type { PlotSeriesProps } from \"./plot-types.js\";\nimport { pointAccessor, pointData, finiteCoordinate } from \"./point-data.js\";\nimport { useContinuousScale } from \"./use-continuous-scale.js\";\nfunction PlotRow<D>({\n datum,\n index,\n data,\n render,\n}: {\n datum: D;\n index: number;\n data: readonly D[];\n render: PlotSeriesProps<D>[\"render\"];\n}): PibblNode {\n return render(datum, index, data);\n}\n/**\n * Places keyed custom Pibbl subtrees at local data coordinates.\n *\n * @param props - Data, coordinate accessors, scales, keys, and per-datum renderer. See\n * {@link PlotSeriesProps} .\n * @returns Pibbl nodes placing each rendered datum at its mapped coordinates. See {@link PibblNode}.\n *\n * @see {@link PlotSeriesProps}\n * @see {@link PibblNode}\n */\nexport function PlotSeries<D>({\n data: input,\n x: xInput,\n y: yInput,\n xScale: xId,\n yScale: yId,\n defined,\n keyBy,\n render,\n ...events\n}: PlotSeriesProps<D>): PibblNode {\n const xs = useContinuousScale(xId).get(),\n ys = useContinuousScale(yId).get();\n const data = pointData(resolveSignalValue(input), \"PlotSeries\");\n if (typeof render !== \"function\")\n throw new TypeError(\"PlotSeries: render must be a synchronous function.\");\n const x = pointAccessor(xInput),\n y = pointAccessor(yInput);\n const keys = new Set<string>();\n const nodes: PibblNode[] = [];\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 key =\n keyBy === undefined\n ? i\n : typeof keyBy === \"function\"\n ? keyBy(datum, i, data)\n : datum[keyBy];\n if (typeof key !== \"string\" && typeof key !== \"number\")\n throw new TypeError(\"PlotSeries: keyBy must return a string or number.\");\n const normalized = String(key);\n if (keys.has(normalized))\n throw new Error(`PlotSeries: duplicate key \"${normalized}\".`);\n keys.add(normalized);\n nodes.push(\n <Group key={normalized} style={{ translateX: px, translateY: py }}>\n <PlotRow datum={datum} index={i} data={data} render={render} />\n </Group>,\n );\n }\n return <Group {...events}>{nodes}</Group>;\n}\n"],
5
+ "mappings": "AAsEQ;AAtER,SAAS,OAAO,0BAA0B;AAG1C,SAAS,eAAe,WAAW,wBAAwB;AAC3D,SAAS,0BAA0B;AACnC,SAAS,QAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKc;AACZ,SAAO,OAAO,OAAO,OAAO,IAAI;AAClC;AAWO,SAAS,WAAc;AAAA,EAC5B,MAAM;AAAA,EACN,GAAG;AAAA,EACH,GAAG;AAAA,EACH,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,QAAM,KAAK,mBAAmB,GAAG,EAAE,IAAI,GACrC,KAAK,mBAAmB,GAAG,EAAE,IAAI;AACnC,QAAM,OAAO,UAAU,mBAAmB,KAAK,GAAG,YAAY;AAC9D,MAAI,OAAO,WAAW;AACpB,UAAM,IAAI,UAAU,oDAAoD;AAC1E,QAAM,IAAI,cAAc,MAAM,GAC5B,IAAI,cAAc,MAAM;AAC1B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,QAAqB,CAAC;AAC5B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,QAAQ,KAAK,CAAC;AACpB,QAAI,WAAW,CAAC,QAAQ,OAAO,GAAG,IAAI,EAAG;AACzC,UAAM,KAAK,EAAE,OAAO,GAAG,IAAI,GACzB,KAAK,EAAE,OAAO,GAAG,IAAI;AACvB,QAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB,EAAE,EAAG;AACpD,UAAM,KAAK,GAAG,IAAI,EAAE,GAClB,KAAK,GAAG,IAAI,EAAE;AAChB,UAAM,MACJ,UAAU,SACN,IACA,OAAO,UAAU,aACf,MAAM,OAAO,GAAG,IAAI,IACpB,MAAM,KAAK;AACnB,QAAI,OAAO,QAAQ,YAAY,OAAO,QAAQ;AAC5C,YAAM,IAAI,UAAU,mDAAmD;AACzE,UAAM,aAAa,OAAO,GAAG;AAC7B,QAAI,KAAK,IAAI,UAAU;AACrB,YAAM,IAAI,MAAM,8BAA8B,UAAU,IAAI;AAC9D,SAAK,IAAI,UAAU;AACnB,UAAM;AAAA,MACJ,oBAAC,SAAuB,OAAO,EAAE,YAAY,IAAI,YAAY,GAAG,GAC9D,8BAAC,WAAQ,OAAc,OAAO,GAAG,MAAY,QAAgB,KADnD,UAEZ;AAAA,IACF;AAAA,EACF;AACA,SAAO,oBAAC,SAAO,GAAG,QAAS,iBAAM;AACnC;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,7 @@
1
+ import type { PointScaleProps } from "./types.js";
2
+ /**
3
+ * Provides a named point mapping to descendant visualization components.
4
+ * @param props - Identity, domain, range, and padding. See {@link PointScaleProps}.
5
+ * @returns Descendant content within the scale scope.
6
+ */
7
+ export declare function PointScale(props: PointScaleProps): import("@pibbl/core").PibblNode;
@@ -0,0 +1,19 @@
1
+ import { resolveSignalValue, useLayoutBox } from "@pibbl/core";
2
+ import { resolvePointScale } from "./point-scale.js";
3
+ import { useScaleProvider } from "./scale-provider.js";
4
+ function PointScale(props) {
5
+ const { width, height } = useLayoutBox();
6
+ useScaleProvider(props.id, "point", () => resolvePointScale(
7
+ resolveSignalValue(props.domain),
8
+ resolveSignalValue(props.range),
9
+ resolveSignalValue(props.reverse ?? false),
10
+ width,
11
+ height,
12
+ resolveSignalValue(props.padding ?? 0)
13
+ ), [props.domain, props.range, props.reverse, props.padding, width, height]);
14
+ return props.children;
15
+ }
16
+ export {
17
+ PointScale
18
+ };
19
+ //# sourceMappingURL=point-scale-component.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/point-scale-component.ts"],
4
+ "sourcesContent": ["import { resolveSignalValue, useLayoutBox } from \"@pibbl/core\";\nimport type { PointScaleProps } from \"./types.js\";\nimport { resolvePointScale } from \"./point-scale.js\";\nimport { useScaleProvider } from \"./scale-provider.js\";\n/**\n * Provides a named point mapping to descendant visualization components.\n * @param props - Identity, domain, range, and padding. See {@link PointScaleProps}.\n * @returns Descendant content within the scale scope.\n */\nexport function PointScale(props: PointScaleProps) {\n const { width, height } = useLayoutBox();\n useScaleProvider(props.id, \"point\", () => resolvePointScale(\n resolveSignalValue(props.domain), resolveSignalValue(props.range),\n resolveSignalValue(props.reverse ?? false), width, height, resolveSignalValue(props.padding ?? 0),\n ), [props.domain, props.range, props.reverse, props.padding, width, height]);\n return props.children;\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB,oBAAoB;AAEjD,SAAS,yBAAyB;AAClC,SAAS,wBAAwB;AAM1B,SAAS,WAAW,OAAwB;AACjD,QAAM,EAAE,OAAO,OAAO,IAAI,aAAa;AACvC,mBAAiB,MAAM,IAAI,SAAS,MAAM;AAAA,IACxC,mBAAmB,MAAM,MAAM;AAAA,IAAG,mBAAmB,MAAM,KAAK;AAAA,IAChE,mBAAmB,MAAM,WAAW,KAAK;AAAA,IAAG;AAAA,IAAO;AAAA,IAAQ,mBAAmB,MAAM,WAAW,CAAC;AAAA,EAClG,GAAG,CAAC,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,MAAM,SAAS,OAAO,MAAM,CAAC;AAC3E,SAAO,MAAM;AACf;",
6
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { BandDomain, ResolvedPointScale, ScaleRange } from "./types.js";
2
+ export declare function resolvePointScale(input: BandDomain, rangeInput: ScaleRange, reverse: boolean, width: number, height: number, padding: number): ResolvedPointScale;
@@ -0,0 +1,45 @@
1
+ import { resolveLinearScale } from "./linear-scale.js";
2
+ function resolvePointScale(input, rangeInput, reverse, width, height, padding) {
3
+ if (!Array.isArray(input)) throw new TypeError("PointScale domain must be an array.");
4
+ const indices = /* @__PURE__ */ new Map();
5
+ for (const category of input) {
6
+ if (typeof category !== "string" && (typeof category !== "number" || !Number.isFinite(category))) throw new TypeError("PointScale categories must be strings or finite numbers.");
7
+ if (indices.has(category)) throw new TypeError("PointScale domain must not contain duplicate categories.");
8
+ indices.set(category, indices.size);
9
+ }
10
+ if (typeof padding !== "number" || !Number.isFinite(padding) || padding < 0 || !Number.isFinite(2 * padding)) throw new RangeError("PointScale padding must be finite and nonnegative with finite arithmetic.");
11
+ const { range, frame } = resolveLinearScale([0, 1], rangeInput, reverse, width, height);
12
+ const domain = Object.freeze([...input]), span = range[1] - range[0];
13
+ const step = domain.length < 2 ? 0 : span / Math.max(1, domain.length - 1 + 2 * padding);
14
+ const start = range[0] + (span - step * (domain.length - 1)) / 2;
15
+ const map = (value) => {
16
+ const index = indices.get(value);
17
+ return index === void 0 ? void 0 : start + index * step;
18
+ };
19
+ return Object.freeze({
20
+ type: "point",
21
+ domain,
22
+ range,
23
+ frame,
24
+ padding,
25
+ step: Math.abs(step),
26
+ map,
27
+ invert(pixel) {
28
+ if (typeof pixel !== "number" || !Number.isFinite(pixel)) throw new RangeError("PointScale invert input must be finite.");
29
+ if (!domain.length) return void 0;
30
+ if (!step) return domain[0];
31
+ const position = (pixel - start) / step;
32
+ const index = Math.max(0, Math.min(domain.length - 1, Math.ceil(position - 0.5)));
33
+ return domain[index];
34
+ },
35
+ ticks(count = 5) {
36
+ if (!Number.isInteger(count) || count < 0 || count > 100) throw new RangeError("PointScale ticks count must be an integer from 0 to 100.");
37
+ const size = Math.min(count, domain.length);
38
+ return Object.freeze(size === 0 ? [] : size === 1 ? [domain[0]] : Array.from({ length: size }, (_, i) => domain[Math.round(i * (domain.length - 1) / (size - 1))]));
39
+ }
40
+ });
41
+ }
42
+ export {
43
+ resolvePointScale
44
+ };
45
+ //# sourceMappingURL=point-scale.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/features/viz/lib/point-scale.ts"],
4
+ "sourcesContent": ["import type { BandCategory, BandDomain, ResolvedPointScale, ScaleRange } from \"./types.js\";\nimport { resolveLinearScale } from \"./linear-scale.js\";\nexport function resolvePointScale(input: BandDomain, rangeInput: ScaleRange, reverse: boolean, width: number, height: number, padding: number): ResolvedPointScale {\n if (!Array.isArray(input)) throw new TypeError(\"PointScale domain must be an array.\");\n const indices = new Map<BandCategory, number>();\n for (const category of input) {\n if (typeof category !== \"string\" && (typeof category !== \"number\" || !Number.isFinite(category))) throw new TypeError(\"PointScale categories must be strings or finite numbers.\");\n if (indices.has(category)) throw new TypeError(\"PointScale domain must not contain duplicate categories.\");\n indices.set(category, indices.size);\n }\n if (typeof padding !== \"number\" || !Number.isFinite(padding) || padding < 0 || !Number.isFinite(2 * padding)) throw new RangeError(\"PointScale padding must be finite and nonnegative with finite arithmetic.\");\n const { range, frame } = resolveLinearScale([0, 1], rangeInput, reverse, width, height);\n const domain = Object.freeze([...input]), span = range[1] - range[0];\n const step = domain.length < 2 ? 0 : span / Math.max(1, domain.length - 1 + 2 * padding);\n const start = range[0] + (span - step * (domain.length - 1)) / 2;\n const map = (value: BandCategory) => { const index = indices.get(value); return index === undefined ? undefined : start + index * step; };\n return Object.freeze({\n type: \"point\", domain, range, frame, padding, step: Math.abs(step), map,\n invert(pixel: number) {\n if (typeof pixel !== \"number\" || !Number.isFinite(pixel)) throw new RangeError(\"PointScale invert input must be finite.\");\n if (!domain.length) return undefined;\n if (!step) return domain[0];\n const position = (pixel - start) / step;\n const index = Math.max(0, Math.min(domain.length - 1, Math.ceil(position - 0.5)));\n return domain[index];\n },\n ticks(count = 5) {\n if (!Number.isInteger(count) || count < 0 || count > 100) throw new RangeError(\"PointScale ticks count must be an integer from 0 to 100.\");\n const size = Math.min(count, domain.length);\n return Object.freeze(size === 0 ? [] : size === 1 ? [domain[0]] : Array.from({ length: size }, (_, i) => domain[Math.round(i * (domain.length - 1) / (size - 1))]));\n },\n });\n}\n"],
5
+ "mappings": "AACA,SAAS,0BAA0B;AAC5B,SAAS,kBAAkB,OAAmB,YAAwB,SAAkB,OAAe,QAAgB,SAAqC;AACjK,MAAI,CAAC,MAAM,QAAQ,KAAK,EAAG,OAAM,IAAI,UAAU,qCAAqC;AACpF,QAAM,UAAU,oBAAI,IAA0B;AAC9C,aAAW,YAAY,OAAO;AAC5B,QAAI,OAAO,aAAa,aAAa,OAAO,aAAa,YAAY,CAAC,OAAO,SAAS,QAAQ,GAAI,OAAM,IAAI,UAAU,0DAA0D;AAChL,QAAI,QAAQ,IAAI,QAAQ,EAAG,OAAM,IAAI,UAAU,0DAA0D;AACzG,YAAQ,IAAI,UAAU,QAAQ,IAAI;AAAA,EACpC;AACA,MAAI,OAAO,YAAY,YAAY,CAAC,OAAO,SAAS,OAAO,KAAK,UAAU,KAAK,CAAC,OAAO,SAAS,IAAI,OAAO,EAAG,OAAM,IAAI,WAAW,2EAA2E;AAC9M,QAAM,EAAE,OAAO,MAAM,IAAI,mBAAmB,CAAC,GAAG,CAAC,GAAG,YAAY,SAAS,OAAO,MAAM;AACtF,QAAM,SAAS,OAAO,OAAO,CAAC,GAAG,KAAK,CAAC,GAAG,OAAO,MAAM,CAAC,IAAI,MAAM,CAAC;AACnE,QAAM,OAAO,OAAO,SAAS,IAAI,IAAI,OAAO,KAAK,IAAI,GAAG,OAAO,SAAS,IAAI,IAAI,OAAO;AACvF,QAAM,QAAQ,MAAM,CAAC,KAAK,OAAO,QAAQ,OAAO,SAAS,MAAM;AAC/D,QAAM,MAAM,CAAC,UAAwB;AAAE,UAAM,QAAQ,QAAQ,IAAI,KAAK;AAAG,WAAO,UAAU,SAAY,SAAY,QAAQ,QAAQ;AAAA,EAAM;AACxI,SAAO,OAAO,OAAO;AAAA,IACnB,MAAM;AAAA,IAAS;AAAA,IAAQ;AAAA,IAAO;AAAA,IAAO;AAAA,IAAS,MAAM,KAAK,IAAI,IAAI;AAAA,IAAG;AAAA,IACpE,OAAO,OAAe;AACpB,UAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,OAAM,IAAI,WAAW,yCAAyC;AACxH,UAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,UAAI,CAAC,KAAM,QAAO,OAAO,CAAC;AAC1B,YAAM,YAAY,QAAQ,SAAS;AACnC,YAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,SAAS,GAAG,KAAK,KAAK,WAAW,GAAG,CAAC,CAAC;AAChF,aAAO,OAAO,KAAK;AAAA,IACrB;AAAA,IACA,MAAM,QAAQ,GAAG;AACf,UAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,IAAK,OAAM,IAAI,WAAW,0DAA0D;AACzI,YAAM,OAAO,KAAK,IAAI,OAAO,OAAO,MAAM;AAC1C,aAAO,OAAO,OAAO,SAAS,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,MAAM,KAAK,EAAE,QAAQ,KAAK,GAAG,CAAC,GAAG,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,SAAS,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC;AAAA,IACpK;AAAA,EACF,CAAC;AACH;",
6
+ "names": []
7
+ }
@@ -6,7 +6,7 @@ import {
6
6
  resolveSignalValue,
7
7
  useCanvasContext
8
8
  } from "@pibbl/core";
9
- import { useScale } from "./use-scale.js";
9
+ import { useContinuousScale } from "./use-continuous-scale.js";
10
10
  import { finiteCoordinate, pointAccessor, pointData } from "./point-data.js";
11
11
  import { appendPointTarget, pointPath } from "./point-geometry.js";
12
12
  import { opacity, width } from "./paint.js";
@@ -55,7 +55,7 @@ function PointSeries({
55
55
  style: styleInput,
56
56
  ...events
57
57
  }) {
58
- const xs = useScale(xId).get(), ys = useScale(yId).get();
58
+ const xs = useContinuousScale(xId).get(), ys = useContinuousScale(yId).get();
59
59
  const data = pointData(resolveSignalValue(input), "PointSeries");
60
60
  const x = pointAccessor(xInput), y = pointAccessor(yInput);
61
61
  const specified = resolveSignalValue(styleInput);