minerva-design 1.2.0 → 1.3.0

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 (256) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/charts/canvas.d.cts +4 -1
  3. package/dist/charts/canvas.d.ts +4 -1
  4. package/dist/charts/core.cjs +1 -1
  5. package/dist/charts/core.d.cts +5 -2
  6. package/dist/charts/core.d.ts +5 -2
  7. package/dist/charts/core.js +6 -4
  8. package/dist/charts/engine/canvas.cjs +1 -1
  9. package/dist/charts/engine/canvas.cjs.map +1 -1
  10. package/dist/charts/engine/canvas.js +65 -53
  11. package/dist/charts/engine/canvas.js.map +1 -1
  12. package/dist/charts/engine/chart.cjs +1 -2
  13. package/dist/charts/engine/chart.cjs.map +1 -1
  14. package/dist/charts/engine/chart.js +342 -323
  15. package/dist/charts/engine/chart.js.map +1 -1
  16. package/dist/charts/engine/color.cjs +1 -1
  17. package/dist/charts/engine/color.cjs.map +1 -1
  18. package/dist/charts/engine/color.d.cts +17 -0
  19. package/dist/charts/engine/color.d.ts +17 -0
  20. package/dist/charts/engine/color.js +27 -3
  21. package/dist/charts/engine/color.js.map +1 -1
  22. package/dist/charts/engine/controller.cjs +2 -2
  23. package/dist/charts/engine/controller.cjs.map +1 -1
  24. package/dist/charts/engine/controller.d.cts +6 -0
  25. package/dist/charts/engine/controller.d.ts +6 -0
  26. package/dist/charts/engine/controller.js +317 -253
  27. package/dist/charts/engine/controller.js.map +1 -1
  28. package/dist/charts/engine/curve.cjs +2 -0
  29. package/dist/charts/engine/curve.cjs.map +1 -0
  30. package/dist/charts/engine/curve.d.cts +15 -0
  31. package/dist/charts/engine/curve.d.ts +15 -0
  32. package/dist/charts/engine/curve.js +56 -0
  33. package/dist/charts/engine/curve.js.map +1 -0
  34. package/dist/charts/engine/data.cjs +1 -1
  35. package/dist/charts/engine/data.cjs.map +1 -1
  36. package/dist/charts/engine/data.d.cts +15 -2
  37. package/dist/charts/engine/data.d.ts +15 -2
  38. package/dist/charts/engine/data.js +98 -38
  39. package/dist/charts/engine/data.js.map +1 -1
  40. package/dist/charts/engine/dom.cjs +1 -1
  41. package/dist/charts/engine/dom.cjs.map +1 -1
  42. package/dist/charts/engine/dom.d.cts +5 -3
  43. package/dist/charts/engine/dom.d.ts +5 -3
  44. package/dist/charts/engine/dom.js +27 -22
  45. package/dist/charts/engine/dom.js.map +1 -1
  46. package/dist/charts/engine/items.cjs +1 -1
  47. package/dist/charts/engine/items.cjs.map +1 -1
  48. package/dist/charts/engine/items.js +132 -61
  49. package/dist/charts/engine/items.js.map +1 -1
  50. package/dist/charts/engine/model.cjs +1 -1
  51. package/dist/charts/engine/model.cjs.map +1 -1
  52. package/dist/charts/engine/model.d.cts +30 -3
  53. package/dist/charts/engine/model.d.ts +30 -3
  54. package/dist/charts/engine/model.js +225 -108
  55. package/dist/charts/engine/model.js.map +1 -1
  56. package/dist/charts/engine/overlay.cjs +1 -1
  57. package/dist/charts/engine/overlay.cjs.map +1 -1
  58. package/dist/charts/engine/overlay.d.cts +2 -0
  59. package/dist/charts/engine/overlay.d.ts +2 -0
  60. package/dist/charts/engine/overlay.js +16 -16
  61. package/dist/charts/engine/overlay.js.map +1 -1
  62. package/dist/charts/engine/presets.cjs +2 -2
  63. package/dist/charts/engine/presets.cjs.map +1 -1
  64. package/dist/charts/engine/presets.d.cts +71 -5
  65. package/dist/charts/engine/presets.d.ts +71 -5
  66. package/dist/charts/engine/presets.js +120 -33
  67. package/dist/charts/engine/presets.js.map +1 -1
  68. package/dist/charts/engine/renderers/canvas2d.cjs +1 -1
  69. package/dist/charts/engine/renderers/canvas2d.cjs.map +1 -1
  70. package/dist/charts/engine/renderers/canvas2d.js +149 -111
  71. package/dist/charts/engine/renderers/canvas2d.js.map +1 -1
  72. package/dist/charts/engine/renderers/range.cjs +1 -1
  73. package/dist/charts/engine/renderers/range.cjs.map +1 -1
  74. package/dist/charts/engine/renderers/range.js +4 -4
  75. package/dist/charts/engine/renderers/range.js.map +1 -1
  76. package/dist/charts/engine/renderers/shaders.cjs +37 -19
  77. package/dist/charts/engine/renderers/shaders.cjs.map +1 -1
  78. package/dist/charts/engine/renderers/shaders.d.cts +2 -2
  79. package/dist/charts/engine/renderers/shaders.d.ts +2 -2
  80. package/dist/charts/engine/renderers/shaders.js +37 -19
  81. package/dist/charts/engine/renderers/shaders.js.map +1 -1
  82. package/dist/charts/engine/renderers/types.cjs.map +1 -1
  83. package/dist/charts/engine/renderers/types.d.cts +11 -4
  84. package/dist/charts/engine/renderers/types.d.ts +11 -4
  85. package/dist/charts/engine/renderers/types.js.map +1 -1
  86. package/dist/charts/engine/renderers/webgl2.cjs +1 -1
  87. package/dist/charts/engine/renderers/webgl2.cjs.map +1 -1
  88. package/dist/charts/engine/renderers/webgl2.js +33 -12
  89. package/dist/charts/engine/renderers/webgl2.js.map +1 -1
  90. package/dist/charts/engine/renderers/webgpu.cjs +1 -1
  91. package/dist/charts/engine/renderers/webgpu.cjs.map +1 -1
  92. package/dist/charts/engine/renderers/webgpu.js +18 -15
  93. package/dist/charts/engine/renderers/webgpu.js.map +1 -1
  94. package/dist/charts/engine/scene.cjs +1 -1
  95. package/dist/charts/engine/scene.cjs.map +1 -1
  96. package/dist/charts/engine/scene.d.cts +19 -6
  97. package/dist/charts/engine/scene.d.ts +19 -6
  98. package/dist/charts/engine/scene.js +201 -89
  99. package/dist/charts/engine/scene.js.map +1 -1
  100. package/dist/charts/engine/shapes/canvas.cjs +2 -0
  101. package/dist/charts/engine/shapes/canvas.cjs.map +1 -0
  102. package/dist/charts/engine/shapes/canvas.d.cts +58 -0
  103. package/dist/charts/engine/shapes/canvas.d.ts +58 -0
  104. package/dist/charts/engine/shapes/canvas.js +159 -0
  105. package/dist/charts/engine/shapes/canvas.js.map +1 -0
  106. package/dist/charts/engine/shapes/chart.cjs +2 -0
  107. package/dist/charts/engine/shapes/chart.cjs.map +1 -0
  108. package/dist/charts/engine/shapes/chart.d.cts +6 -0
  109. package/dist/charts/engine/shapes/chart.d.ts +6 -0
  110. package/dist/charts/engine/shapes/chart.js +273 -0
  111. package/dist/charts/engine/shapes/chart.js.map +1 -0
  112. package/dist/charts/engine/shapes/draw.cjs +2 -0
  113. package/dist/charts/engine/shapes/draw.cjs.map +1 -0
  114. package/dist/charts/engine/shapes/draw.d.cts +20 -0
  115. package/dist/charts/engine/shapes/draw.d.ts +20 -0
  116. package/dist/charts/engine/shapes/draw.js +152 -0
  117. package/dist/charts/engine/shapes/draw.js.map +1 -0
  118. package/dist/charts/engine/shapes/funnel.cjs +2 -0
  119. package/dist/charts/engine/shapes/funnel.cjs.map +1 -0
  120. package/dist/charts/engine/shapes/funnel.d.cts +6 -0
  121. package/dist/charts/engine/shapes/funnel.d.ts +6 -0
  122. package/dist/charts/engine/shapes/funnel.js +149 -0
  123. package/dist/charts/engine/shapes/funnel.js.map +1 -0
  124. package/dist/charts/engine/shapes/gauge.cjs +2 -0
  125. package/dist/charts/engine/shapes/gauge.cjs.map +1 -0
  126. package/dist/charts/engine/shapes/gauge.d.cts +7 -0
  127. package/dist/charts/engine/shapes/gauge.d.ts +7 -0
  128. package/dist/charts/engine/shapes/gauge.js +173 -0
  129. package/dist/charts/engine/shapes/gauge.js.map +1 -0
  130. package/dist/charts/engine/shapes/hit.cjs +2 -0
  131. package/dist/charts/engine/shapes/hit.cjs.map +1 -0
  132. package/dist/charts/engine/shapes/hit.d.cts +28 -0
  133. package/dist/charts/engine/shapes/hit.d.ts +28 -0
  134. package/dist/charts/engine/shapes/hit.js +124 -0
  135. package/dist/charts/engine/shapes/hit.js.map +1 -0
  136. package/dist/charts/engine/shapes/index.d.cts +9 -0
  137. package/dist/charts/engine/shapes/index.d.ts +9 -0
  138. package/dist/charts/engine/shapes/layout.cjs +3 -0
  139. package/dist/charts/engine/shapes/layout.cjs.map +1 -0
  140. package/dist/charts/engine/shapes/layout.d.cts +88 -0
  141. package/dist/charts/engine/shapes/layout.d.ts +88 -0
  142. package/dist/charts/engine/shapes/layout.js +266 -0
  143. package/dist/charts/engine/shapes/layout.js.map +1 -0
  144. package/dist/charts/engine/shapes/pie.cjs +2 -0
  145. package/dist/charts/engine/shapes/pie.cjs.map +1 -0
  146. package/dist/charts/engine/shapes/pie.d.cts +20 -0
  147. package/dist/charts/engine/shapes/pie.d.ts +20 -0
  148. package/dist/charts/engine/shapes/pie.js +302 -0
  149. package/dist/charts/engine/shapes/pie.js.map +1 -0
  150. package/dist/charts/engine/shapes/radar.cjs +2 -0
  151. package/dist/charts/engine/shapes/radar.cjs.map +1 -0
  152. package/dist/charts/engine/shapes/radar.d.cts +8 -0
  153. package/dist/charts/engine/shapes/radar.d.ts +8 -0
  154. package/dist/charts/engine/shapes/radar.js +197 -0
  155. package/dist/charts/engine/shapes/radar.js.map +1 -0
  156. package/dist/charts/engine/shapes/runtime.cjs +2 -0
  157. package/dist/charts/engine/shapes/runtime.cjs.map +1 -0
  158. package/dist/charts/engine/shapes/runtime.d.cts +29 -0
  159. package/dist/charts/engine/shapes/runtime.d.ts +29 -0
  160. package/dist/charts/engine/shapes/runtime.js +97 -0
  161. package/dist/charts/engine/shapes/runtime.js.map +1 -0
  162. package/dist/charts/engine/shapes/scene.cjs +2 -0
  163. package/dist/charts/engine/shapes/scene.cjs.map +1 -0
  164. package/dist/charts/engine/shapes/scene.d.cts +257 -0
  165. package/dist/charts/engine/shapes/scene.d.ts +257 -0
  166. package/dist/charts/engine/shapes/scene.js +123 -0
  167. package/dist/charts/engine/shapes/scene.js.map +1 -0
  168. package/dist/charts/engine/shapes/treemap.cjs +2 -0
  169. package/dist/charts/engine/shapes/treemap.cjs.map +1 -0
  170. package/dist/charts/engine/shapes/treemap.d.cts +14 -0
  171. package/dist/charts/engine/shapes/treemap.d.ts +14 -0
  172. package/dist/charts/engine/shapes/treemap.js +213 -0
  173. package/dist/charts/engine/shapes/treemap.js.map +1 -0
  174. package/dist/charts/engine/shapes/types.d.cts +292 -0
  175. package/dist/charts/engine/shapes/types.d.ts +292 -0
  176. package/dist/charts/engine/signature.cjs +2 -0
  177. package/dist/charts/engine/signature.cjs.map +1 -0
  178. package/dist/charts/engine/signature.d.cts +9 -0
  179. package/dist/charts/engine/signature.d.ts +9 -0
  180. package/dist/charts/engine/signature.js +13 -0
  181. package/dist/charts/engine/signature.js.map +1 -0
  182. package/dist/charts/engine/theme.cjs +1 -1
  183. package/dist/charts/engine/theme.cjs.map +1 -1
  184. package/dist/charts/engine/theme.d.cts +10 -1
  185. package/dist/charts/engine/theme.d.ts +10 -1
  186. package/dist/charts/engine/theme.js +40 -16
  187. package/dist/charts/engine/theme.js.map +1 -1
  188. package/dist/charts/engine/types.d.cts +70 -9
  189. package/dist/charts/engine/types.d.ts +70 -9
  190. package/dist/charts/index.cjs +1 -1
  191. package/dist/charts/index.d.cts +4 -2
  192. package/dist/charts/index.d.ts +4 -2
  193. package/dist/charts/index.js +8 -5
  194. package/dist/charts/react/Chart.cjs +1 -1
  195. package/dist/charts/react/Chart.cjs.map +1 -1
  196. package/dist/charts/react/Chart.d.cts +8 -1
  197. package/dist/charts/react/Chart.d.ts +8 -1
  198. package/dist/charts/react/Chart.js +66 -47
  199. package/dist/charts/react/Chart.js.map +1 -1
  200. package/dist/charts/react/charts.cjs +1 -1
  201. package/dist/charts/react/charts.cjs.map +1 -1
  202. package/dist/charts/react/charts.d.cts +10 -2
  203. package/dist/charts/react/charts.d.ts +10 -2
  204. package/dist/charts/react/charts.js +174 -51
  205. package/dist/charts/react/charts.js.map +1 -1
  206. package/dist/charts/react/shapes.cjs +2 -0
  207. package/dist/charts/react/shapes.cjs.map +1 -0
  208. package/dist/charts/react/shapes.d.cts +255 -0
  209. package/dist/charts/react/shapes.d.ts +255 -0
  210. package/dist/charts/react/shapes.js +242 -0
  211. package/dist/charts/react/shapes.js.map +1 -0
  212. package/dist/charts/react/types.d.cts +73 -4
  213. package/dist/charts/react/types.d.ts +73 -4
  214. package/dist/native/charts/src/engine/color.cjs +1 -1
  215. package/dist/native/charts/src/engine/color.cjs.map +1 -1
  216. package/dist/native/charts/src/engine/color.js +12 -3
  217. package/dist/native/charts/src/engine/color.js.map +1 -1
  218. package/dist/native/charts/src/engine/controller.cjs +2 -2
  219. package/dist/native/charts/src/engine/controller.cjs.map +1 -1
  220. package/dist/native/charts/src/engine/controller.js +334 -270
  221. package/dist/native/charts/src/engine/controller.js.map +1 -1
  222. package/dist/native/charts/src/engine/curve.cjs +2 -0
  223. package/dist/native/charts/src/engine/curve.cjs.map +1 -0
  224. package/dist/native/charts/src/engine/curve.js +56 -0
  225. package/dist/native/charts/src/engine/curve.js.map +1 -0
  226. package/dist/native/charts/src/engine/data.cjs +1 -1
  227. package/dist/native/charts/src/engine/data.cjs.map +1 -1
  228. package/dist/native/charts/src/engine/data.js +98 -38
  229. package/dist/native/charts/src/engine/data.js.map +1 -1
  230. package/dist/native/charts/src/engine/model.cjs +1 -1
  231. package/dist/native/charts/src/engine/model.cjs.map +1 -1
  232. package/dist/native/charts/src/engine/model.js +229 -112
  233. package/dist/native/charts/src/engine/model.js.map +1 -1
  234. package/dist/native/charts/src/engine/overlay.cjs +1 -1
  235. package/dist/native/charts/src/engine/overlay.cjs.map +1 -1
  236. package/dist/native/charts/src/engine/overlay.js +16 -16
  237. package/dist/native/charts/src/engine/overlay.js.map +1 -1
  238. package/dist/native/charts/src/engine/presets.cjs +1 -1
  239. package/dist/native/charts/src/engine/presets.cjs.map +1 -1
  240. package/dist/native/charts/src/engine/presets.js +11 -4
  241. package/dist/native/charts/src/engine/presets.js.map +1 -1
  242. package/dist/native/charts/src/engine/scene.cjs +1 -1
  243. package/dist/native/charts/src/engine/scene.cjs.map +1 -1
  244. package/dist/native/charts/src/engine/scene.js +209 -97
  245. package/dist/native/charts/src/engine/scene.js.map +1 -1
  246. package/dist/native/charts/src/engine/theme.cjs.map +1 -1
  247. package/dist/native/charts/src/engine/theme.js.map +1 -1
  248. package/dist/native/components/Chart/scene.cjs +1 -1
  249. package/dist/native/components/Chart/scene.cjs.map +1 -1
  250. package/dist/native/components/Chart/scene.js +31 -19
  251. package/dist/native/components/Chart/scene.js.map +1 -1
  252. package/dist/native/source/components/Chart/scene.tsx +54 -20
  253. package/dist/taro/index.js +1059 -579
  254. package/dist/uni/charts-canvas.js +3 -1
  255. package/dist/weapp/controls.js +966 -225
  256. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draw.js","names":["SHADOW","BRIGHTEN","sectorPad","node","padAngleAt","r","half","sectorPath","cx","dx","cy","dy","span","a1","a0","ctx","r1","r0","TAU","edge","t","a","side","polar","po","outerSpan","pi","innerSpan","hasInner","thick","co","ci","s","c","e","c2","e2","d","m","polygonSubpath","n","points","px","reverse","i","py","radius","j","p","lenPrev","lenNext","polygonPath","roundRectPath","w","h","x","y","setDash","dash","circle","drawShapeScene","enter","scene","base","owned","active","hover","alpha","fill","focused","k","drawShapeLegend","font","theme","box","boxes","toCss","drawShapeTooltip","padding","lineHeight","left","right","line","content","row"],"sources":["../../../../../charts/src/engine/shapes/draw.ts"],"sourcesContent":["// Draws a ShapeScene on any CanvasRenderingContext2D (browser, OffscreenCanvas,\n// mini-programs). Only uses the widely available path APIs: arc, arcTo,\n// quadraticCurveTo (no roundRect, no Path2D, no fill rules).\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport type { ChartTheme } from \"../theme\";\nimport type { ShapeLegendBox, ShapeTooltipBox } from \"./layout\";\nimport {\n TAU,\n type PolygonNode,\n type SectorNode,\n type ShapeHover,\n type ShapeScene,\n} from \"./scene\";\n\nconst SHADOW = \"rgba(15, 23, 42, 0.18)\";\nconst BRIGHTEN = \"rgba(255, 255, 255, 0.14)\";\n\n/** Gap of a sector, reduced so thin slices keep most of their arc */\nexport const sectorPad = (node: SectorNode) =>\n Math.max(0, Math.min(node.pad, (node.r1 * (node.a1 - node.a0)) / 3));\n\n/** Angle offset of a point at distance `r` from a radial edge moved by `half` px */\nexport const padAngleAt = (half: number, r: number) =>\n r > 0 ? Math.asin(Math.min(1, half / r)) : Math.PI / 2;\n\n/** Annular sector with pixel gaps and rounded corners */\nexport const sectorPath = (\n ctx: CanvasRenderingContext2D,\n node: SectorNode,\n dx = 0,\n dy = 0,\n) => {\n const cx = node.cx + dx;\n const cy = node.cy + dy;\n const { r0, r1, a0, a1 } = node;\n const span = a1 - a0;\n ctx.beginPath();\n if (span <= 0 || r1 <= r0) return;\n if (span >= TAU - 1e-6) {\n ctx.moveTo(cx + r1, cy);\n ctx.arc(cx, cy, r1, 0, TAU);\n if (r0 > 0) {\n ctx.moveTo(cx + r0, cy);\n ctx.arc(cx, cy, r0, TAU, 0, true);\n }\n ctx.closePath();\n return;\n }\n const half = sectorPad(node) / 2;\n // point at distance `r` on the start (side 1) or end (side -1) edge\n const edge = (a: number, side: 1 | -1, r: number): [number, number] => {\n const t = a + side * padAngleAt(half, r);\n return [cx + r * Math.cos(t), cy + r * Math.sin(t)];\n };\n const polar = (a: number, r: number): [number, number] => [\n cx + r * Math.cos(a),\n cy + r * Math.sin(a),\n ];\n\n const po = padAngleAt(half, r1);\n const outerSpan = Math.max(0, span - 2 * po);\n const pi = r0 > 0 ? padAngleAt(half, r0) : 0;\n const innerSpan = r0 > 0 ? span - 2 * pi : 0;\n const hasInner = r0 > 0 && innerSpan > 1e-4;\n const thick = r1 - r0;\n const co = Math.max(\n 0,\n Math.min(node.corner, thick / 2, (r1 * outerSpan) / 2 - 0.01),\n );\n const ci = hasInner\n ? Math.max(0, Math.min(node.corner, thick / 2, (r0 * innerSpan) / 2 - 0.01))\n : 0;\n\n // outer edge\n if (co > 0.5) {\n const s = edge(a0, 1, r1 - co);\n ctx.moveTo(s[0], s[1]);\n const c = edge(a0, 1, r1);\n const e = polar(a0 + po + co / r1, r1);\n ctx.quadraticCurveTo(c[0], c[1], e[0], e[1]);\n ctx.arc(cx, cy, r1, a0 + po + co / r1, a1 - po - co / r1);\n const c2 = edge(a1, -1, r1);\n const e2 = edge(a1, -1, r1 - co);\n ctx.quadraticCurveTo(c2[0], c2[1], e2[0], e2[1]);\n } else {\n const s = polar(a0 + po, r1);\n ctx.moveTo(s[0], s[1]);\n ctx.arc(cx, cy, r1, a0 + po, a1 - po);\n }\n\n // inner edge (or apex)\n if (hasInner) {\n if (ci > 0.5) {\n const s = edge(a1, -1, r0 + ci);\n ctx.lineTo(s[0], s[1]);\n const c = edge(a1, -1, r0);\n const e = polar(a1 - pi - ci / r0, r0);\n ctx.quadraticCurveTo(c[0], c[1], e[0], e[1]);\n ctx.arc(cx, cy, r0, a1 - pi - ci / r0, a0 + pi + ci / r0, true);\n const c2 = edge(a0, 1, r0);\n const e2 = edge(a0, 1, r0 + ci);\n ctx.quadraticCurveTo(c2[0], c2[1], e2[0], e2[1]);\n } else {\n const s = polar(a1 - pi, r0);\n ctx.lineTo(s[0], s[1]);\n ctx.arc(cx, cy, r0, a1 - pi, a0 + pi, true);\n }\n } else if (half <= 0) {\n ctx.lineTo(cx, cy);\n } else if (span < Math.PI) {\n // the two offset edges meet on the bisector\n const d = half / Math.sin(span / 2);\n const m = (a0 + a1) / 2;\n ctx.lineTo(cx + d * Math.cos(m), cy + d * Math.sin(m));\n } else {\n ctx.lineTo(\n cx + half * Math.cos(a1 - Math.PI / 2),\n cy + half * Math.sin(a1 - Math.PI / 2),\n );\n ctx.lineTo(\n cx + half * Math.cos(a0 + Math.PI / 2),\n cy + half * Math.sin(a0 + Math.PI / 2),\n );\n }\n ctx.closePath();\n};\n\n/** Closed polygon with rounded corners (adds a subpath) */\nconst polygonSubpath = (\n ctx: CanvasRenderingContext2D,\n points: readonly number[],\n radius: number,\n reverse: boolean,\n dx: number,\n dy: number,\n) => {\n const n = points.length >> 1;\n if (n < 2) return;\n const px = (i: number) => {\n const k = reverse ? n - 1 - i : i;\n return points[k * 2] + dx;\n };\n const py = (i: number) => {\n const k = reverse ? n - 1 - i : i;\n return points[k * 2 + 1] + dy;\n };\n if (radius <= 0 || n < 3) {\n ctx.moveTo(px(0), py(0));\n for (let i = 1; i < n; i++) ctx.lineTo(px(i), py(i));\n ctx.closePath();\n return;\n }\n // start in the middle of the last edge so every corner is rounded\n ctx.moveTo((px(n - 1) + px(0)) / 2, (py(n - 1) + py(0)) / 2);\n for (let i = 0; i < n; i++) {\n const j = (i + 1) % n;\n const p = (i + n - 1) % n;\n const lenPrev = Math.hypot(px(i) - px(p), py(i) - py(p));\n const lenNext = Math.hypot(px(j) - px(i), py(j) - py(i));\n const r = Math.min(radius, lenPrev / 2, lenNext / 2);\n if (r > 0.01) ctx.arcTo(px(i), py(i), px(j), py(j), r);\n else ctx.lineTo(px(i), py(i));\n }\n ctx.closePath();\n};\n\nconst polygonPath = (\n ctx: CanvasRenderingContext2D,\n node: PolygonNode,\n dx = 0,\n dy = 0,\n) => {\n ctx.beginPath();\n polygonSubpath(ctx, node.points, node.radius ?? 0, false, dx, dy);\n // reversed winding cuts the hole with the default nonzero rule\n if (node.hole) polygonSubpath(ctx, node.hole, 0, true, dx, dy);\n};\n\n/** Rounded rectangle path (no `ctx.roundRect`) */\nexport const roundRectPath = (\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n w: number,\n h: number,\n radius: number,\n) => {\n const r = Math.max(0, Math.min(radius, w / 2, h / 2));\n ctx.beginPath();\n if (r <= 0.01) {\n ctx.moveTo(x, y);\n ctx.lineTo(x + w, y);\n ctx.lineTo(x + w, y + h);\n ctx.lineTo(x, y + h);\n ctx.closePath();\n return;\n }\n ctx.moveTo(x + r, y);\n ctx.lineTo(x + w - r, y);\n ctx.arcTo(x + w, y, x + w, y + r, r);\n ctx.lineTo(x + w, y + h - r);\n ctx.arcTo(x + w, y + h, x + w - r, y + h, r);\n ctx.lineTo(x + r, y + h);\n ctx.arcTo(x, y + h, x, y + h - r, r);\n ctx.lineTo(x, y + r);\n ctx.arcTo(x, y, x + r, y, r);\n ctx.closePath();\n};\n\nconst setDash = (ctx: CanvasRenderingContext2D, dash: number[]) => {\n if (typeof ctx.setLineDash === \"function\") ctx.setLineDash(dash);\n};\n\nconst circle = (\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n r: number,\n) => {\n ctx.beginPath();\n ctx.arc(x, y, Math.max(0, r), 0, TAU);\n};\n\n/**\n * Draws a scene in CSS pixels (the caller sets the pixel-ratio transform and\n * clears the canvas). `hover` emphasizes an item and dims the others.\n */\nexport const drawShapeScene = (\n ctx: CanvasRenderingContext2D,\n scene: ShapeScene,\n hover: ShapeHover | null,\n) => {\n ctx.save();\n const enter = scene.enter;\n const base = enter ? Math.max(0, Math.min(1, enter.alpha)) : 1;\n if (enter && enter.scale !== 1) {\n ctx.translate(enter.cx, enter.cy);\n ctx.scale(enter.scale, enter.scale);\n ctx.translate(-enter.cx, -enter.cy);\n }\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (const node of scene.nodes) {\n const owned = node.hit !== undefined;\n const active = !!hover && owned && node.hit === hover.index;\n let alpha = base * (node.alpha ?? 1);\n if (hover && owned && !active) alpha *= scene.dim;\n if (alpha <= 0.002) continue;\n ctx.globalAlpha = alpha;\n const dx = active && node.shift ? node.shift[0] : 0;\n const dy = active && node.shift ? node.shift[1] : 0;\n\n switch (node.kind) {\n case \"sector\": {\n sectorPath(ctx, node, dx, dy);\n ctx.fillStyle = node.fill;\n if (active) {\n ctx.save();\n ctx.shadowColor = SHADOW;\n ctx.shadowBlur = 14;\n ctx.shadowOffsetY = 4;\n ctx.fill();\n ctx.restore();\n } else ctx.fill();\n break;\n }\n case \"polygon\": {\n polygonPath(ctx, node, dx, dy);\n const fill = active && node.hoverFill ? node.hoverFill : node.fill;\n if (fill) {\n ctx.fillStyle = fill;\n ctx.fill();\n if (active && node.brighten) {\n ctx.fillStyle = BRIGHTEN;\n ctx.fill();\n }\n }\n if (node.stroke) {\n ctx.strokeStyle = node.stroke;\n ctx.lineWidth =\n active && node.hoverLineWidth\n ? node.hoverLineWidth\n : (node.lineWidth ?? 1);\n ctx.stroke();\n }\n break;\n }\n case \"rect\": {\n roundRectPath(\n ctx,\n node.x + dx,\n node.y + dy,\n node.width,\n node.height,\n node.radius,\n );\n ctx.fillStyle = node.fill;\n ctx.fill();\n if (active && node.brighten) {\n ctx.fillStyle = BRIGHTEN;\n ctx.fill();\n }\n break;\n }\n case \"arc\": {\n if (node.a1 - node.a0 <= 1e-6 || node.width <= 0) break;\n ctx.beginPath();\n ctx.arc(node.cx + dx, node.cy + dy, node.r, node.a0, node.a1);\n ctx.lineCap = node.cap;\n ctx.lineWidth = node.width;\n ctx.strokeStyle = node.color;\n ctx.stroke();\n ctx.lineCap = \"round\";\n break;\n }\n case \"circle\": {\n if (!node.fill && !node.stroke) break;\n const focused =\n active &&\n (node.indicator === undefined || node.indicator === hover?.indicator);\n const r = focused && node.hoverR ? node.hoverR : node.r;\n const x = node.cx + dx;\n const y = node.cy + dy;\n if (focused && node.halo) {\n circle(ctx, x, y, r + 5);\n ctx.fillStyle = node.halo;\n ctx.fill();\n }\n circle(ctx, x, y, r);\n if (node.fill) {\n ctx.fillStyle = node.fill;\n ctx.fill();\n }\n if (node.stroke) {\n ctx.strokeStyle = node.stroke;\n ctx.lineWidth = node.lineWidth ?? 1;\n ctx.stroke();\n }\n break;\n }\n case \"line\": {\n const p = node.points;\n if (p.length < 4) break;\n ctx.beginPath();\n ctx.moveTo(p[0] + dx, p[1] + dy);\n // the last point stays: leader lines bend to their fixed label\n for (let i = 2; i < p.length; i += 2)\n ctx.lineTo(\n p[i] + (i === p.length - 2 ? 0 : dx),\n p[i + 1] + (i === p.length - 2 ? 0 : dy),\n );\n ctx.strokeStyle = node.color;\n ctx.lineWidth = node.width;\n if (node.dash) setDash(ctx, node.dash);\n ctx.stroke();\n if (node.dash) setDash(ctx, []);\n break;\n }\n case \"text\": {\n const focused =\n node.indicator !== undefined && hover?.indicator === node.indicator;\n ctx.font = focused && node.hoverFont ? node.hoverFont : node.font;\n ctx.fillStyle =\n focused && node.hoverColor ? node.hoverColor : node.color;\n ctx.textAlign = node.align;\n ctx.textBaseline = node.baseline;\n ctx.fillText(node.text, node.x + dx, node.y + dy);\n break;\n }\n case \"guide\": {\n const k = hover?.indicator;\n if (k === undefined || !node.ends[k]) break;\n ctx.globalAlpha = base;\n ctx.beginPath();\n ctx.moveTo(node.cx, node.cy);\n ctx.lineTo(node.ends[k][0], node.ends[k][1]);\n ctx.strokeStyle = node.color;\n ctx.lineWidth = 1;\n setDash(ctx, [3, 3]);\n ctx.stroke();\n setDash(ctx, []);\n break;\n }\n default:\n break;\n }\n }\n ctx.restore();\n};\n\n/** Legend drawn on a canvas (dots, muted names, struck-through when hidden) */\nexport const drawShapeLegend = (\n ctx: CanvasRenderingContext2D,\n theme: ChartTheme,\n boxes: readonly ShapeLegendBox[],\n) => {\n ctx.save();\n ctx.font = font(theme, 12);\n ctx.textBaseline = \"middle\";\n ctx.textAlign = \"left\";\n for (const box of boxes) {\n const cy = box.y + box.height / 2;\n ctx.globalAlpha = box.hidden ? 0.45 : 1;\n ctx.fillStyle = box.color;\n circle(ctx, box.x + 4.5, cy, 4.5);\n ctx.fill();\n ctx.fillStyle = toCss(theme.textMuted);\n ctx.fillText(box.name, box.x + 15, cy, Math.max(1, box.width - 15));\n if (box.hidden) ctx.fillRect(box.x + 15, cy, box.width - 15, 1);\n }\n ctx.restore();\n};\n\n/** Tooltip drawn on a canvas, styled like the DOM tooltip */\nexport const drawShapeTooltip = (\n ctx: CanvasRenderingContext2D,\n theme: ChartTheme,\n box: ShapeTooltipBox,\n) => {\n const { padding, lineHeight } = box;\n ctx.save();\n ctx.globalAlpha = 1;\n ctx.save();\n ctx.shadowColor = SHADOW;\n ctx.shadowBlur = 16;\n ctx.shadowOffsetY = 6;\n roundRectPath(ctx, box.x, box.y, box.width, box.height, 8);\n ctx.fillStyle = toCss(theme.background);\n ctx.fill();\n ctx.restore();\n roundRectPath(\n ctx,\n box.x + 0.5,\n box.y + 0.5,\n box.width - 1,\n box.height - 1,\n 8,\n );\n ctx.strokeStyle = toCss(theme.axis);\n ctx.lineWidth = 1;\n ctx.stroke();\n\n ctx.textBaseline = \"middle\";\n let y = box.y + padding + lineHeight / 2;\n const left = box.x + padding + 2;\n const right = box.x + box.width - padding - 2;\n if (box.text) {\n ctx.font = font(theme, 12);\n ctx.fillStyle = toCss(theme.text);\n ctx.textAlign = \"left\";\n for (const line of box.text) {\n ctx.fillText(line, left, y);\n y += lineHeight;\n }\n } else if (box.content) {\n const { content } = box;\n let x = left;\n if (content.color) {\n ctx.fillStyle = content.color;\n circle(ctx, x + 4, y, 4);\n ctx.fill();\n x += 14;\n }\n ctx.font = font(theme, 12, 600);\n ctx.fillStyle = toCss(theme.text);\n ctx.textAlign = \"left\";\n ctx.fillText(content.title, x, y);\n y += lineHeight;\n for (const row of content.rows) {\n x = left;\n if (row.color) {\n ctx.fillStyle = row.color;\n circle(ctx, x + 4, y, 4);\n ctx.fill();\n x += 14;\n }\n ctx.font = font(theme, 12, row.strong ? 600 : 400);\n ctx.textAlign = \"left\";\n ctx.fillStyle = toCss(row.strong ? theme.text : theme.textMuted);\n ctx.fillText(row.name, x, y);\n ctx.font = font(theme, 12, 600);\n ctx.textAlign = \"right\";\n ctx.fillStyle = toCss(theme.text);\n ctx.fillText(row.value, right, y);\n y += lineHeight;\n }\n }\n ctx.restore();\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../color.cjs"),t=require("../overlay.cjs"),n=require("./scene.cjs");var r=e=>n.uniqueKeys(e.data.map(e=>e.name)),i=(e,t,i)=>{r(e).forEach((r,a)=>{i.set(r,t.has(a)?0:n.positive(e.data[a].value))})},a=(e,t)=>{let r=e.data.map((e,t)=>t).filter(e=>!t.has(e)),i=t=>n.positive(e.data[t].value);return e.sort===`descending`?r.sort((e,t)=>i(t)-i(e)):e.sort===`ascending`&&r.sort((e,t)=>i(e)-i(t)),r},o=(i,o)=>{let{theme:s,area:c,measure:l,hidden:u}=o,d=r(i),f=a(i,u),p=f.map(e=>n.positive(i.data[e].value));if(!f.length||p.every(e=>e<=0))return n.emptyLayout(o);let m=f.length,h=Math.max(0,n.finite(i.gap,4)),g=i.shape===`bar`,_=t.font(s,12,500),v=t.font(s,12),y=t.font(s,11),b=Math.max(1,(c.height-h*(m-1))/m),x=f.map((e,t)=>Math.max(0,o.value(d[e],p[t]))),S=Math.max(...x)||1,C=p[0],w=m<2||x[m-2]>=x[m-1],T=f.map(e=>i.data[e].name),E=p.map(e=>o.format(e)),D=T.map(e=>l(e,_)),O=E.map(e=>l(e,v)),k=p.map((e,t)=>t>0?p[t-1]>0?e/p[t-1]:0:1),A=i.conversion!==!1,j=k.map((e,t)=>t?`↓ ${o.percent(e)}`:``),M=j.map(e=>e?l(e,y):0),N=e=>{let t=x.map(t=>Math.max(2,e*t/S));return{tops:t,bottoms:t.map((e,n)=>g?e:n<m-1?t[n+1]:w?e*.72:e)}},P=(e,t,r)=>e.tops[t]+(e.bottoms[t]-e.tops[t])*n.clamp(r,0,b)/b,F=(e,t)=>{if(b<10)return{kind:`none`};let n=b/2,r=r=>Math.min(P(e,t,n-r/2),P(e,t,n+r/2));return b>=18&&D[t]+8+O[t]+20<=r(16)?{kind:`inline`}:b>=38&&Math.max(D[t],O[t])+20<=r(32)?{kind:`stacked`}:{kind:`outside`,half:Math.max(P(e,t,n-8),P(e,t,n+8))/2}},I=e=>D[e]+6+O[e],L=c.x+c.width,R=Math.max(20,c.width*.78),z=Math.max(20,c.width*.35),B=N(R),V=[],H=c.x+c.width/2;for(;;){B=N(R),V=f.map((e,t)=>F(B,t));let e=R/2,t=R/2;if(V.forEach((n,r)=>{if(n.kind===`outside`&&(e=Math.max(e,n.half+10+I(r))),A&&r>0){let e=g?Math.max(B.tops[r-1],B.tops[r]):B.tops[r];t=Math.max(t,e/2+10+M[r])}}),e+t<=c.width||R<=z){let r=c.x+c.width/2;H=e+t<=c.width?n.clamp(r,c.x+e,L-t):c.x+Math.max(R/2,c.width-t);break}R=Math.max(z,R*.92)}let U=B.tops,W=[],G=[],K=[];f.forEach((t,r)=>{let a=i.data[t],u=o.color(a.color,t),d=e.toCss(u),f=c.y+r*(b+h),m=U[r],x=B.bottoms[r];g?W.push({kind:`rect`,x:H-m/2,y:f,width:m,height:b,radius:Math.min(4,b/2,m/2),fill:d,hit:t,brighten:!0}):W.push({kind:`polygon`,points:[H-m/2,f,H+m/2,f,H+x/2,f+b,H-x/2,f+b],fill:d,radius:Math.min(3,b/3),hit:t,brighten:!0});let S=f+b/2,w=V[r],M=n.textOn(u),N=(e,n,r,i,a,o)=>({kind:`text`,x:e,y:n,text:r,font:i,color:a,align:o,baseline:`middle`,hit:t});if(w.kind===`inline`){let e=H-(D[r]+8+O[r])/2;G.push(N(e,S,T[r],_,M,`left`),N(e+D[r]+8,S,E[r],v,M,`left`))}else if(w.kind===`stacked`)G.push(N(H,S-8,T[r],_,M,`center`),N(H,S+8,E[r],v,M,`center`));else if(w.kind===`outside`){let t=H-w.half-10,i=t-c.x,a=O[r];if(a<=i){G.push(N(t,S,E[r],v,e.toCss(s.textMuted),`right`));let o=n.ellipsize(T[r],i-a-6,_,l);o&&G.push(N(t-a-6,S,o,_,e.toCss(s.text),`right`))}}let P=C>0?p[r]/C:0,F=[{name:`Value`,value:E[r]},{name:`Of first stage`,value:o.percent(P)}];if(r>0&&(F.push({name:`Conversion`,value:o.percent(k[r])}),A)){let t=g?Math.max(U[r-1],m):m;G.push({kind:`text`,x:H+t/2+10,y:f-h/2,text:j[r],font:y,color:e.toCss(s.textMuted),align:`left`,baseline:`middle`})}K.push({index:t,name:a.name,value:p[r],percent:P,share:o.percent(P),color:d,x:H,y:S,rows:F})}),W.push(...G);let q=n.clamp(o.enter,0,1);return{nodes:W,items:K,dim:.5,empty:!1,...q<1?{enter:{alpha:q,scale:.94+.06*q,cx:H,cy:c.y+c.height/2}}:{}}};exports.funnelOrder=a,exports.funnelValues=i,exports.layoutFunnel=o;
2
+ //# sourceMappingURL=funnel.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.cjs","names":["uniqueKeys","positive","emptyLayout","finite","font","clamp","toCss","textOn","ellipsize","require_color","require_overlay","require_scene","keysOf","o","d","funnelValues","out","key","hidden","i","funnelOrder","order","v","b","a","layoutFunnel","c","keys","targets","n","gap","bar","nameFont","theme","valueFont","smallFont","stageH","area","shown","k","vmax","first","narrowing","names","valueTexts","nameWs","measure","s","valueWs","rates","showConversion","convTexts","r","convWs","shapeOf","tops","maxW","wt","widthAt","dy","placementOf","mid","inner","h","outsideWidth","right","minW","shape","places","cx","reqL","reqR","p","boundary","center","widths","nodes","labels","items","datum","color","css","y","wb","midY","place","ink","text","ty","value","f","textColor","x0","x","room","vw","name","percent","rows","enter"],"sources":["../../../../../charts/src/engine/shapes/funnel.ts"],"sourcesContent":["// Funnel layout: centered trapezoids (or bars) narrowing to the next stage,\n// labels inside (or beside when too narrow), conversion rates between stages.\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport {\n clamp,\n ellipsize,\n emptyLayout,\n finite,\n positive,\n textOn,\n uniqueKeys,\n type LayoutContext,\n type LayoutResult,\n type ShapeItem,\n type ShapeNode,\n type ShapeTooltipRow,\n} from \"./scene\";\nimport type { FunnelChartOptions } from \"./types\";\n\nconst keysOf = (o: FunnelChartOptions) => uniqueKeys(o.data.map((d) => d.name));\n\nexport const funnelValues = (\n o: FunnelChartOptions,\n hidden: ReadonlySet<number>,\n out: Map<string, number>,\n) => {\n keysOf(o).forEach((key, i) => {\n out.set(key, hidden.has(i) ? 0 : positive(o.data[i].value));\n });\n};\n\n/** Data indexes of the visible stages, top to bottom */\nexport const funnelOrder = (\n o: FunnelChartOptions,\n hidden: ReadonlySet<number>,\n): number[] => {\n const order = o.data.map((_, i) => i).filter((i) => !hidden.has(i));\n const v = (i: number) => positive(o.data[i].value);\n if (o.sort === \"descending\") order.sort((a, b) => v(b) - v(a));\n else if (o.sort === \"ascending\") order.sort((a, b) => v(a) - v(b));\n return order;\n};\n\nexport const layoutFunnel = (\n o: FunnelChartOptions,\n c: LayoutContext,\n): LayoutResult => {\n const { theme, area, measure, hidden } = c;\n const keys = keysOf(o);\n const order = funnelOrder(o, hidden);\n const targets = order.map((i) => positive(o.data[i].value));\n if (!order.length || targets.every((v) => v <= 0)) return emptyLayout(c);\n\n const n = order.length;\n const gap = Math.max(0, finite(o.gap, 4));\n const bar = o.shape === \"bar\";\n const nameFont = font(theme, 12, 500);\n const valueFont = font(theme, 12);\n const smallFont = font(theme, 11);\n const stageH = Math.max(1, (area.height - gap * (n - 1)) / n);\n const shown = order.map((i, k) => Math.max(0, c.value(keys[i], targets[k])));\n const vmax = Math.max(...shown) || 1;\n const first = targets[0];\n const narrowing = n < 2 || shown[n - 2] >= shown[n - 1];\n\n // texts\n const names = order.map((i) => o.data[i].name);\n const valueTexts = targets.map((v) => c.format(v));\n const nameWs = names.map((s) => measure(s, nameFont));\n const valueWs = valueTexts.map((s) => measure(s, valueFont));\n const rates = targets.map((v, k) =>\n k > 0 ? (targets[k - 1] > 0 ? v / targets[k - 1] : 0) : 1,\n );\n const showConversion = o.conversion !== false;\n const convTexts = rates.map((r, k) => (k ? `↓ ${c.percent(r)}` : \"\"));\n const convWs = convTexts.map((s) => (s ? measure(s, smallFont) : 0));\n\n /** Widths of the stages (top, bottom) for a widest stage of `maxW` */\n const shapeOf = (maxW: number) => {\n const tops = shown.map((v) => Math.max(2, (maxW * v) / vmax));\n const bottoms = tops.map((wt, k) =>\n bar ? wt : k < n - 1 ? tops[k + 1] : narrowing ? wt * 0.72 : wt,\n );\n return { tops, bottoms };\n };\n /** Width of stage `k` at `dy` pixels below its top */\n const widthAt = (\n s: ReturnType<typeof shapeOf>,\n k: number,\n dy: number,\n ): number =>\n s.tops[k] + ((s.bottoms[k] - s.tops[k]) * clamp(dy, 0, stageH)) / stageH;\n\n const LINE = 16;\n const PAD = 10;\n const NAME_GAP = 8;\n type Placement =\n | { kind: \"inline\" }\n | { kind: \"stacked\" }\n | { kind: \"outside\"; half: number }\n | { kind: \"none\" };\n /** Inside on one line, on two lines, else beside the stage (left) */\n const placementOf = (s: ReturnType<typeof shapeOf>, k: number): Placement => {\n if (stageH < 10) return { kind: \"none\" };\n const mid = stageH / 2;\n // the narrowest width over the text's height (the bottom for narrowing stages)\n const inner = (h: number) =>\n Math.min(widthAt(s, k, mid - h / 2), widthAt(s, k, mid + h / 2));\n if (\n stageH >= 18 &&\n nameWs[k] + NAME_GAP + valueWs[k] + 2 * PAD <= inner(LINE)\n )\n return { kind: \"inline\" };\n if (\n stageH >= 2 * LINE + 6 &&\n Math.max(nameWs[k], valueWs[k]) + 2 * PAD <= inner(2 * LINE)\n )\n return { kind: \"stacked\" };\n const half =\n Math.max(widthAt(s, k, mid - LINE / 2), widthAt(s, k, mid + LINE / 2)) /\n 2;\n return { kind: \"outside\", half };\n };\n const outsideWidth = (k: number) => nameWs[k] + 6 + valueWs[k];\n\n // largest funnel leaving room for the outside labels (left) and the\n // conversion rates (right); centered when the margins allow it\n const right = area.x + area.width;\n let maxW = Math.max(20, area.width * 0.78);\n const minW = Math.max(20, area.width * 0.35);\n let shape = shapeOf(maxW);\n let places: Placement[] = [];\n let cx = area.x + area.width / 2;\n for (;;) {\n shape = shapeOf(maxW);\n places = order.map((_, k) => placementOf(shape, k));\n let reqL = maxW / 2;\n let reqR = maxW / 2;\n places.forEach((p, k) => {\n if (p.kind === \"outside\")\n reqL = Math.max(reqL, p.half + 10 + outsideWidth(k));\n if (showConversion && k > 0) {\n const boundary = bar\n ? Math.max(shape.tops[k - 1], shape.tops[k])\n : shape.tops[k];\n reqR = Math.max(reqR, boundary / 2 + 10 + convWs[k]);\n }\n });\n if (reqL + reqR <= area.width || maxW <= minW) {\n const center = area.x + area.width / 2;\n cx =\n reqL + reqR <= area.width\n ? clamp(center, area.x + reqL, right - reqR)\n : area.x + Math.max(maxW / 2, area.width - reqR);\n break;\n }\n maxW = Math.max(minW, maxW * 0.92);\n }\n const widths = shape.tops;\n\n const nodes: ShapeNode[] = [];\n const labels: ShapeNode[] = [];\n const items: ShapeItem[] = [];\n order.forEach((i, k) => {\n const datum = o.data[i];\n const color = c.color(datum.color, i);\n const css = toCss(color);\n const y = area.y + k * (stageH + gap);\n const wt = widths[k];\n const wb = shape.bottoms[k];\n if (bar) {\n nodes.push({\n kind: \"rect\",\n x: cx - wt / 2,\n y,\n width: wt,\n height: stageH,\n radius: Math.min(4, stageH / 2, wt / 2),\n fill: css,\n hit: i,\n brighten: true,\n });\n } else {\n nodes.push({\n kind: \"polygon\",\n points: [\n cx - wt / 2,\n y,\n cx + wt / 2,\n y,\n cx + wb / 2,\n y + stageH,\n cx - wb / 2,\n y + stageH,\n ],\n fill: css,\n radius: Math.min(3, stageH / 3),\n hit: i,\n brighten: true,\n });\n }\n\n const midY = y + stageH / 2;\n const place = places[k];\n const ink = textOn(color);\n const text = (\n x: number,\n ty: number,\n value: string,\n f: string,\n textColor: string,\n align: \"left\" | \"center\" | \"right\",\n ): ShapeNode => ({\n kind: \"text\",\n x,\n y: ty,\n text: value,\n font: f,\n color: textColor,\n align,\n baseline: \"middle\",\n hit: i,\n });\n if (place.kind === \"inline\") {\n const x0 = cx - (nameWs[k] + NAME_GAP + valueWs[k]) / 2;\n labels.push(\n text(x0, midY, names[k], nameFont, ink, \"left\"),\n text(\n x0 + nameWs[k] + NAME_GAP,\n midY,\n valueTexts[k],\n valueFont,\n ink,\n \"left\",\n ),\n );\n } else if (place.kind === \"stacked\") {\n labels.push(\n text(cx, midY - LINE / 2, names[k], nameFont, ink, \"center\"),\n text(cx, midY + LINE / 2, valueTexts[k], valueFont, ink, \"center\"),\n );\n } else if (place.kind === \"outside\") {\n // beside the stage: the value always, the name shortened if needed\n const x = cx - place.half - 10;\n const room = x - area.x;\n const vw = valueWs[k];\n if (vw <= room) {\n labels.push(\n text(\n x,\n midY,\n valueTexts[k],\n valueFont,\n toCss(theme.textMuted),\n \"right\",\n ),\n );\n const name = ellipsize(names[k], room - vw - 6, nameFont, measure);\n if (name)\n labels.push(\n text(x - vw - 6, midY, name, nameFont, toCss(theme.text), \"right\"),\n );\n }\n }\n\n const percent = first > 0 ? targets[k] / first : 0;\n const rows: ShapeTooltipRow[] = [\n { name: \"Value\", value: valueTexts[k] },\n { name: \"Of first stage\", value: c.percent(percent) },\n ];\n if (k > 0) {\n rows.push({ name: \"Conversion\", value: c.percent(rates[k]) });\n if (showConversion) {\n const boundary = bar ? Math.max(widths[k - 1], wt) : wt;\n labels.push({\n kind: \"text\",\n x: cx + boundary / 2 + 10,\n y: y - gap / 2,\n text: convTexts[k],\n font: smallFont,\n color: toCss(theme.textMuted),\n align: \"left\",\n baseline: \"middle\",\n });\n }\n }\n items.push({\n index: i,\n name: datum.name,\n value: targets[k],\n percent,\n share: c.percent(percent),\n color: css,\n x: cx,\n y: midY,\n rows,\n });\n });\n nodes.push(...labels);\n\n const enter = clamp(c.enter, 0, 1);\n return {\n nodes,\n items,\n dim: 0.5,\n empty: false,\n ...(enter < 1\n ? {\n enter: {\n alpha: enter,\n scale: 0.94 + 0.06 * enter,\n cx,\n cy: area.y + area.height / 2,\n },\n }\n : {}),\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { LayoutContext, LayoutResult } from './scene.cjs';
2
+ import { FunnelChartOptions } from './types.cjs';
3
+ export declare const funnelValues: (o: FunnelChartOptions, hidden: ReadonlySet<number>, out: Map<string, number>) => void;
4
+ /** Data indexes of the visible stages, top to bottom */
5
+ export declare const funnelOrder: (o: FunnelChartOptions, hidden: ReadonlySet<number>) => number[];
6
+ export declare const layoutFunnel: (o: FunnelChartOptions, c: LayoutContext) => LayoutResult;
@@ -0,0 +1,6 @@
1
+ import { LayoutContext, LayoutResult } from './scene.js';
2
+ import { FunnelChartOptions } from './types.js';
3
+ export declare const funnelValues: (o: FunnelChartOptions, hidden: ReadonlySet<number>, out: Map<string, number>) => void;
4
+ /** Data indexes of the visible stages, top to bottom */
5
+ export declare const funnelOrder: (o: FunnelChartOptions, hidden: ReadonlySet<number>) => number[];
6
+ export declare const layoutFunnel: (o: FunnelChartOptions, c: LayoutContext) => LayoutResult;
@@ -0,0 +1,149 @@
1
+ import { toCss as e } from "../color.js";
2
+ import { font as t } from "../overlay.js";
3
+ import { clamp as n, ellipsize as r, emptyLayout as i, finite as a, positive as o, textOn as s, uniqueKeys as c } from "./scene.js";
4
+ //#region src/engine/shapes/funnel.ts
5
+ var l = (e) => c(e.data.map((e) => e.name)), u = (e, t, n) => {
6
+ l(e).forEach((r, i) => {
7
+ n.set(r, t.has(i) ? 0 : o(e.data[i].value));
8
+ });
9
+ }, d = (e, t) => {
10
+ let n = e.data.map((e, t) => t).filter((e) => !t.has(e)), r = (t) => o(e.data[t].value);
11
+ return e.sort === "descending" ? n.sort((e, t) => r(t) - r(e)) : e.sort === "ascending" && n.sort((e, t) => r(e) - r(t)), n;
12
+ }, f = (c, u) => {
13
+ let { theme: f, area: p, measure: m, hidden: h } = u, g = l(c), _ = d(c, h), v = _.map((e) => o(c.data[e].value));
14
+ if (!_.length || v.every((e) => e <= 0)) return i(u);
15
+ let y = _.length, b = Math.max(0, a(c.gap, 4)), x = c.shape === "bar", S = t(f, 12, 500), C = t(f, 12), w = t(f, 11), T = Math.max(1, (p.height - b * (y - 1)) / y), E = _.map((e, t) => Math.max(0, u.value(g[e], v[t]))), D = Math.max(...E) || 1, O = v[0], k = y < 2 || E[y - 2] >= E[y - 1], A = _.map((e) => c.data[e].name), j = v.map((e) => u.format(e)), M = A.map((e) => m(e, S)), N = j.map((e) => m(e, C)), P = v.map((e, t) => t > 0 ? v[t - 1] > 0 ? e / v[t - 1] : 0 : 1), F = c.conversion !== !1, I = P.map((e, t) => t ? `↓ ${u.percent(e)}` : ""), L = I.map((e) => e ? m(e, w) : 0), R = (e) => {
16
+ let t = E.map((t) => Math.max(2, e * t / D));
17
+ return {
18
+ tops: t,
19
+ bottoms: t.map((e, n) => x ? e : n < y - 1 ? t[n + 1] : k ? e * .72 : e)
20
+ };
21
+ }, z = (e, t, r) => e.tops[t] + (e.bottoms[t] - e.tops[t]) * n(r, 0, T) / T, B = (e, t) => {
22
+ if (T < 10) return { kind: "none" };
23
+ let n = T / 2, r = (r) => Math.min(z(e, t, n - r / 2), z(e, t, n + r / 2));
24
+ return T >= 18 && M[t] + 8 + N[t] + 20 <= r(16) ? { kind: "inline" } : T >= 38 && Math.max(M[t], N[t]) + 20 <= r(32) ? { kind: "stacked" } : {
25
+ kind: "outside",
26
+ half: Math.max(z(e, t, n - 8), z(e, t, n + 8)) / 2
27
+ };
28
+ }, V = (e) => M[e] + 6 + N[e], H = p.x + p.width, U = Math.max(20, p.width * .78), W = Math.max(20, p.width * .35), G = R(U), K = [], q = p.x + p.width / 2;
29
+ for (;;) {
30
+ G = R(U), K = _.map((e, t) => B(G, t));
31
+ let e = U / 2, t = U / 2;
32
+ if (K.forEach((n, r) => {
33
+ if (n.kind === "outside" && (e = Math.max(e, n.half + 10 + V(r))), F && r > 0) {
34
+ let e = x ? Math.max(G.tops[r - 1], G.tops[r]) : G.tops[r];
35
+ t = Math.max(t, e / 2 + 10 + L[r]);
36
+ }
37
+ }), e + t <= p.width || U <= W) {
38
+ let r = p.x + p.width / 2;
39
+ q = e + t <= p.width ? n(r, p.x + e, H - t) : p.x + Math.max(U / 2, p.width - t);
40
+ break;
41
+ }
42
+ U = Math.max(W, U * .92);
43
+ }
44
+ let J = G.tops, Y = [], X = [], Z = [];
45
+ _.forEach((t, n) => {
46
+ let i = c.data[t], a = u.color(i.color, t), o = e(a), l = p.y + n * (T + b), d = J[n], h = G.bottoms[n];
47
+ x ? Y.push({
48
+ kind: "rect",
49
+ x: q - d / 2,
50
+ y: l,
51
+ width: d,
52
+ height: T,
53
+ radius: Math.min(4, T / 2, d / 2),
54
+ fill: o,
55
+ hit: t,
56
+ brighten: !0
57
+ }) : Y.push({
58
+ kind: "polygon",
59
+ points: [
60
+ q - d / 2,
61
+ l,
62
+ q + d / 2,
63
+ l,
64
+ q + h / 2,
65
+ l + T,
66
+ q - h / 2,
67
+ l + T
68
+ ],
69
+ fill: o,
70
+ radius: Math.min(3, T / 3),
71
+ hit: t,
72
+ brighten: !0
73
+ });
74
+ let g = l + T / 2, _ = K[n], y = s(a), E = (e, n, r, i, a, o) => ({
75
+ kind: "text",
76
+ x: e,
77
+ y: n,
78
+ text: r,
79
+ font: i,
80
+ color: a,
81
+ align: o,
82
+ baseline: "middle",
83
+ hit: t
84
+ });
85
+ if (_.kind === "inline") {
86
+ let e = q - (M[n] + 8 + N[n]) / 2;
87
+ X.push(E(e, g, A[n], S, y, "left"), E(e + M[n] + 8, g, j[n], C, y, "left"));
88
+ } else if (_.kind === "stacked") X.push(E(q, g - 8, A[n], S, y, "center"), E(q, g + 8, j[n], C, y, "center"));
89
+ else if (_.kind === "outside") {
90
+ let t = q - _.half - 10, i = t - p.x, a = N[n];
91
+ if (a <= i) {
92
+ X.push(E(t, g, j[n], C, e(f.textMuted), "right"));
93
+ let o = r(A[n], i - a - 6, S, m);
94
+ o && X.push(E(t - a - 6, g, o, S, e(f.text), "right"));
95
+ }
96
+ }
97
+ let D = O > 0 ? v[n] / O : 0, k = [{
98
+ name: "Value",
99
+ value: j[n]
100
+ }, {
101
+ name: "Of first stage",
102
+ value: u.percent(D)
103
+ }];
104
+ if (n > 0 && (k.push({
105
+ name: "Conversion",
106
+ value: u.percent(P[n])
107
+ }), F)) {
108
+ let t = x ? Math.max(J[n - 1], d) : d;
109
+ X.push({
110
+ kind: "text",
111
+ x: q + t / 2 + 10,
112
+ y: l - b / 2,
113
+ text: I[n],
114
+ font: w,
115
+ color: e(f.textMuted),
116
+ align: "left",
117
+ baseline: "middle"
118
+ });
119
+ }
120
+ Z.push({
121
+ index: t,
122
+ name: i.name,
123
+ value: v[n],
124
+ percent: D,
125
+ share: u.percent(D),
126
+ color: o,
127
+ x: q,
128
+ y: g,
129
+ rows: k
130
+ });
131
+ }), Y.push(...X);
132
+ let Q = n(u.enter, 0, 1);
133
+ return {
134
+ nodes: Y,
135
+ items: Z,
136
+ dim: .5,
137
+ empty: !1,
138
+ ...Q < 1 ? { enter: {
139
+ alpha: Q,
140
+ scale: .94 + .06 * Q,
141
+ cx: q,
142
+ cy: p.y + p.height / 2
143
+ } } : {}
144
+ };
145
+ };
146
+ //#endregion
147
+ export { d as funnelOrder, u as funnelValues, f as layoutFunnel };
148
+
149
+ //# sourceMappingURL=funnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"funnel.js","names":["keysOf","uniqueKeys","o","d","funnelValues","key","hidden","positive","funnelOrder","order","i","v","b","a","layoutFunnel","c","keys","targets","emptyLayout","n","gap","finite","bar","nameFont","font","theme","valueFont","smallFont","stageH","area","shown","k","vmax","first","narrowing","names","valueTexts","nameWs","measure","s","valueWs","rates","showConversion","convTexts","r","convWs","shapeOf","tops","maxW","wt","widthAt","clamp","dy","placementOf","mid","inner","h","outsideWidth","right","minW","shape","places","cx","reqL","reqR","p","boundary","center","widths","nodes","labels","items","datum","color","css","toCss","y","wb","midY","place","ink","textOn","text","ty","value","f","textColor","x0","x","room","vw","name","ellipsize","percent","rows","enter"],"sources":["../../../../../charts/src/engine/shapes/funnel.ts"],"sourcesContent":["// Funnel layout: centered trapezoids (or bars) narrowing to the next stage,\n// labels inside (or beside when too narrow), conversion rates between stages.\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport {\n clamp,\n ellipsize,\n emptyLayout,\n finite,\n positive,\n textOn,\n uniqueKeys,\n type LayoutContext,\n type LayoutResult,\n type ShapeItem,\n type ShapeNode,\n type ShapeTooltipRow,\n} from \"./scene\";\nimport type { FunnelChartOptions } from \"./types\";\n\nconst keysOf = (o: FunnelChartOptions) => uniqueKeys(o.data.map((d) => d.name));\n\nexport const funnelValues = (\n o: FunnelChartOptions,\n hidden: ReadonlySet<number>,\n out: Map<string, number>,\n) => {\n keysOf(o).forEach((key, i) => {\n out.set(key, hidden.has(i) ? 0 : positive(o.data[i].value));\n });\n};\n\n/** Data indexes of the visible stages, top to bottom */\nexport const funnelOrder = (\n o: FunnelChartOptions,\n hidden: ReadonlySet<number>,\n): number[] => {\n const order = o.data.map((_, i) => i).filter((i) => !hidden.has(i));\n const v = (i: number) => positive(o.data[i].value);\n if (o.sort === \"descending\") order.sort((a, b) => v(b) - v(a));\n else if (o.sort === \"ascending\") order.sort((a, b) => v(a) - v(b));\n return order;\n};\n\nexport const layoutFunnel = (\n o: FunnelChartOptions,\n c: LayoutContext,\n): LayoutResult => {\n const { theme, area, measure, hidden } = c;\n const keys = keysOf(o);\n const order = funnelOrder(o, hidden);\n const targets = order.map((i) => positive(o.data[i].value));\n if (!order.length || targets.every((v) => v <= 0)) return emptyLayout(c);\n\n const n = order.length;\n const gap = Math.max(0, finite(o.gap, 4));\n const bar = o.shape === \"bar\";\n const nameFont = font(theme, 12, 500);\n const valueFont = font(theme, 12);\n const smallFont = font(theme, 11);\n const stageH = Math.max(1, (area.height - gap * (n - 1)) / n);\n const shown = order.map((i, k) => Math.max(0, c.value(keys[i], targets[k])));\n const vmax = Math.max(...shown) || 1;\n const first = targets[0];\n const narrowing = n < 2 || shown[n - 2] >= shown[n - 1];\n\n // texts\n const names = order.map((i) => o.data[i].name);\n const valueTexts = targets.map((v) => c.format(v));\n const nameWs = names.map((s) => measure(s, nameFont));\n const valueWs = valueTexts.map((s) => measure(s, valueFont));\n const rates = targets.map((v, k) =>\n k > 0 ? (targets[k - 1] > 0 ? v / targets[k - 1] : 0) : 1,\n );\n const showConversion = o.conversion !== false;\n const convTexts = rates.map((r, k) => (k ? `↓ ${c.percent(r)}` : \"\"));\n const convWs = convTexts.map((s) => (s ? measure(s, smallFont) : 0));\n\n /** Widths of the stages (top, bottom) for a widest stage of `maxW` */\n const shapeOf = (maxW: number) => {\n const tops = shown.map((v) => Math.max(2, (maxW * v) / vmax));\n const bottoms = tops.map((wt, k) =>\n bar ? wt : k < n - 1 ? tops[k + 1] : narrowing ? wt * 0.72 : wt,\n );\n return { tops, bottoms };\n };\n /** Width of stage `k` at `dy` pixels below its top */\n const widthAt = (\n s: ReturnType<typeof shapeOf>,\n k: number,\n dy: number,\n ): number =>\n s.tops[k] + ((s.bottoms[k] - s.tops[k]) * clamp(dy, 0, stageH)) / stageH;\n\n const LINE = 16;\n const PAD = 10;\n const NAME_GAP = 8;\n type Placement =\n | { kind: \"inline\" }\n | { kind: \"stacked\" }\n | { kind: \"outside\"; half: number }\n | { kind: \"none\" };\n /** Inside on one line, on two lines, else beside the stage (left) */\n const placementOf = (s: ReturnType<typeof shapeOf>, k: number): Placement => {\n if (stageH < 10) return { kind: \"none\" };\n const mid = stageH / 2;\n // the narrowest width over the text's height (the bottom for narrowing stages)\n const inner = (h: number) =>\n Math.min(widthAt(s, k, mid - h / 2), widthAt(s, k, mid + h / 2));\n if (\n stageH >= 18 &&\n nameWs[k] + NAME_GAP + valueWs[k] + 2 * PAD <= inner(LINE)\n )\n return { kind: \"inline\" };\n if (\n stageH >= 2 * LINE + 6 &&\n Math.max(nameWs[k], valueWs[k]) + 2 * PAD <= inner(2 * LINE)\n )\n return { kind: \"stacked\" };\n const half =\n Math.max(widthAt(s, k, mid - LINE / 2), widthAt(s, k, mid + LINE / 2)) /\n 2;\n return { kind: \"outside\", half };\n };\n const outsideWidth = (k: number) => nameWs[k] + 6 + valueWs[k];\n\n // largest funnel leaving room for the outside labels (left) and the\n // conversion rates (right); centered when the margins allow it\n const right = area.x + area.width;\n let maxW = Math.max(20, area.width * 0.78);\n const minW = Math.max(20, area.width * 0.35);\n let shape = shapeOf(maxW);\n let places: Placement[] = [];\n let cx = area.x + area.width / 2;\n for (;;) {\n shape = shapeOf(maxW);\n places = order.map((_, k) => placementOf(shape, k));\n let reqL = maxW / 2;\n let reqR = maxW / 2;\n places.forEach((p, k) => {\n if (p.kind === \"outside\")\n reqL = Math.max(reqL, p.half + 10 + outsideWidth(k));\n if (showConversion && k > 0) {\n const boundary = bar\n ? Math.max(shape.tops[k - 1], shape.tops[k])\n : shape.tops[k];\n reqR = Math.max(reqR, boundary / 2 + 10 + convWs[k]);\n }\n });\n if (reqL + reqR <= area.width || maxW <= minW) {\n const center = area.x + area.width / 2;\n cx =\n reqL + reqR <= area.width\n ? clamp(center, area.x + reqL, right - reqR)\n : area.x + Math.max(maxW / 2, area.width - reqR);\n break;\n }\n maxW = Math.max(minW, maxW * 0.92);\n }\n const widths = shape.tops;\n\n const nodes: ShapeNode[] = [];\n const labels: ShapeNode[] = [];\n const items: ShapeItem[] = [];\n order.forEach((i, k) => {\n const datum = o.data[i];\n const color = c.color(datum.color, i);\n const css = toCss(color);\n const y = area.y + k * (stageH + gap);\n const wt = widths[k];\n const wb = shape.bottoms[k];\n if (bar) {\n nodes.push({\n kind: \"rect\",\n x: cx - wt / 2,\n y,\n width: wt,\n height: stageH,\n radius: Math.min(4, stageH / 2, wt / 2),\n fill: css,\n hit: i,\n brighten: true,\n });\n } else {\n nodes.push({\n kind: \"polygon\",\n points: [\n cx - wt / 2,\n y,\n cx + wt / 2,\n y,\n cx + wb / 2,\n y + stageH,\n cx - wb / 2,\n y + stageH,\n ],\n fill: css,\n radius: Math.min(3, stageH / 3),\n hit: i,\n brighten: true,\n });\n }\n\n const midY = y + stageH / 2;\n const place = places[k];\n const ink = textOn(color);\n const text = (\n x: number,\n ty: number,\n value: string,\n f: string,\n textColor: string,\n align: \"left\" | \"center\" | \"right\",\n ): ShapeNode => ({\n kind: \"text\",\n x,\n y: ty,\n text: value,\n font: f,\n color: textColor,\n align,\n baseline: \"middle\",\n hit: i,\n });\n if (place.kind === \"inline\") {\n const x0 = cx - (nameWs[k] + NAME_GAP + valueWs[k]) / 2;\n labels.push(\n text(x0, midY, names[k], nameFont, ink, \"left\"),\n text(\n x0 + nameWs[k] + NAME_GAP,\n midY,\n valueTexts[k],\n valueFont,\n ink,\n \"left\",\n ),\n );\n } else if (place.kind === \"stacked\") {\n labels.push(\n text(cx, midY - LINE / 2, names[k], nameFont, ink, \"center\"),\n text(cx, midY + LINE / 2, valueTexts[k], valueFont, ink, \"center\"),\n );\n } else if (place.kind === \"outside\") {\n // beside the stage: the value always, the name shortened if needed\n const x = cx - place.half - 10;\n const room = x - area.x;\n const vw = valueWs[k];\n if (vw <= room) {\n labels.push(\n text(\n x,\n midY,\n valueTexts[k],\n valueFont,\n toCss(theme.textMuted),\n \"right\",\n ),\n );\n const name = ellipsize(names[k], room - vw - 6, nameFont, measure);\n if (name)\n labels.push(\n text(x - vw - 6, midY, name, nameFont, toCss(theme.text), \"right\"),\n );\n }\n }\n\n const percent = first > 0 ? targets[k] / first : 0;\n const rows: ShapeTooltipRow[] = [\n { name: \"Value\", value: valueTexts[k] },\n { name: \"Of first stage\", value: c.percent(percent) },\n ];\n if (k > 0) {\n rows.push({ name: \"Conversion\", value: c.percent(rates[k]) });\n if (showConversion) {\n const boundary = bar ? Math.max(widths[k - 1], wt) : wt;\n labels.push({\n kind: \"text\",\n x: cx + boundary / 2 + 10,\n y: y - gap / 2,\n text: convTexts[k],\n font: smallFont,\n color: toCss(theme.textMuted),\n align: \"left\",\n baseline: \"middle\",\n });\n }\n }\n items.push({\n index: i,\n name: datum.name,\n value: targets[k],\n percent,\n share: c.percent(percent),\n color: css,\n x: cx,\n y: midY,\n rows,\n });\n });\n nodes.push(...labels);\n\n const enter = clamp(c.enter, 0, 1);\n return {\n nodes,\n items,\n dim: 0.5,\n empty: false,\n ...(enter < 1\n ? {\n enter: {\n alpha: enter,\n scale: 0.94 + 0.06 * enter,\n cx,\n cy: area.y + area.height / 2,\n },\n }\n : {}),\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("../color.cjs"),t=require("../overlay.cjs"),n=require("./scene.cjs");var r=e=>{let t=n.finite(e.min,0),r=n.finite(e.max,100);return r>t||(r=t+1),[t,r]},i=(e,t,i)=>{i.set(`value`,n.finite(e.value,r(e)[0]))},a=e=>(e??[]).filter(e=>Number.isFinite(e.to)).slice().sort((e,t)=>e.to-t.to),o=(e,t)=>{if(!e?.length)return-1;for(let n=0;n<e.length;n++)if(t<=e[n].to)return n;return e.length-1},s=e=>{let t=String(e),n=t.indexOf(`.`);return n<0||t.includes(`e`)?0:Math.min(4,t.length-n-1)},c=(i,c)=>{let{theme:l,area:u,measure:d}=c,[f,p]=r(i),m=n.finite(i.value,f),h=n.clamp(c.enter,0,1),g=f+(c.value(`value`,m)-f)*h,_=s(m),v=g===m?m:Number(g.toFixed(_)),y=n.clamp((g-f)/(p-f),0,1),b=n.clamp(n.finite(i.sweep,240),30,360)*Math.PI/180,x=-Math.PI/2-b/2,S=x+b,C=n.clamp(n.finite(i.thickness,.16),.04,.4),w=b<=200*Math.PI/180,T=[0],E=[i.needle?.62:w?.26:0];for(let e of[x,S]){let t=1-C/2;T.push(t*Math.cos(e)-C/2,t*Math.cos(e)+C/2),E.push(t*Math.sin(e)-C/2,t*Math.sin(e)+C/2)}for(let e=-4;e<=4;e++){let t=e*Math.PI/2;t>x&&t<S&&(T.push(Math.cos(t)),E.push(Math.sin(t)))}let D=Math.min(...T),O=Math.max(...T),k=Math.min(...E),A=Math.max(...E),j=Math.max(4,Math.min(u.width/(O-D),u.height/(A-k))),M=u.x+(u.width-(O-D)*j)/2-D*j,N=u.y+(u.height-(A-k)*j)/2-k*j,P=j*C,F=j-P/2,I=a(i.bands),L=I.map((e,t)=>n.resolveWith(l,e.color,l.palette[t%l.palette.length])),R=o(I,n.clamp(g,f,p)),z=R>=0?L[R]:c.color(i.color,0),B=e.toCss(z),V=e=>x+b*n.clamp((e-f)/(p-f),0,1),H=[{kind:`circle`,cx:M,cy:N,r:j,hit:0},{kind:`arc`,cx:M,cy:N,r:F,a0:x,a1:S,width:P,color:e.toCss(l.grid),cap:`round`}];y>5e-4&&H.push({kind:`arc`,cx:M,cy:N,r:F,a0:x,a1:x+b*y,width:P,color:B,cap:`round`,hit:0});let U=j-P-6;if(I.length&&U>12){let t=f;I.forEach((n,r)=>{let i=Math.max(t,f),a=Math.min(n.to,p);if(t=n.to,a<=i)return;let o=r?1/U:0;H.push({kind:`arc`,cx:M,cy:N,r:U,a0:V(i)+o,a1:V(a)-(a<p?1/U:0),width:3,color:e.toCss(L[r],.9),cap:`butt`})})}if(i.ticks!==!1&&j>=48){let n=(I.length&&U>12?U-1.5:j-P)-8,r=[f,...I.map(e=>e.to),p].filter((e,t,n)=>e>=f&&e<=p&&n.indexOf(e)===t&&!(b>=Math.PI*2-1e-6&&e===p)),i=t.font(l,11);for(let t of r){let r=V(t),a=Math.cos(r),o=Math.sin(r);H.push({kind:`text`,x:M+n*a,y:N+n*o,text:c.format(t),font:i,color:e.toCss(l.textMuted),align:a>.35?`right`:a<-.35?`left`:`center`,baseline:o>.35?`bottom`:o<-.35?`top`:`middle`})}}if(i.needle){let t=x+b*y,n=F,r=Math.cos(t+Math.PI/2),i=Math.sin(t+Math.PI/2),a=M+n*Math.cos(t),o=N+n*Math.sin(t);H.push({kind:`polygon`,points:[M+r*3.5,N+i*3.5,a+r*1,o+i*1,a-r*1,o-i*1,M-r*3.5,N-i*3.5],fill:e.toCss(l.text,.85),radius:1},{kind:`circle`,cx:M,cy:N,r:7,fill:e.toCss(l.text,.9)},{kind:`circle`,cx:M,cy:N,r:2.5,fill:e.toCss(l.background)})}let W=n.clamp(j*.28,16,40),G=t.font(l,W,600),K=t.font(l,12),q=F*(w?1.5:1.3),J=n.ellipsize(c.format(v),q,G,d),Y=i.label?n.ellipsize(i.label,q,K,d):``,X=W+(Y?18:0),Z=i.needle?N+Math.max(14,j*.16):w?N-W-2:N-X/2;H.push({kind:`text`,x:M,y:Z+W/2,text:J,font:G,color:e.toCss(l.text),align:`center`,baseline:`middle`}),Y&&H.push({kind:`text`,x:M,y:w&&!i.needle?N+12:Z+W+11,text:Y,font:K,color:e.toCss(l.textMuted),align:`center`,baseline:`middle`});let Q=n.clamp((m-f)/(p-f),0,1);return{nodes:H,items:[{index:0,name:i.label??`Value`,value:m,percent:Q,share:c.percent(Q),color:B,x:M+F*Math.cos(V(m)),y:N+F*Math.sin(V(m)),rows:[{name:`Value`,value:c.format(m)},{name:`Of range`,value:c.percent(Q)}]}],dim:1,empty:!1}};exports.gaugeBandIndex=o,exports.gaugeRange=r,exports.gaugeValues=i,exports.layoutGauge=c;
2
+ //# sourceMappingURL=gauge.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gauge.cjs","names":["finite","clamp","resolveWith","toCss","font","ellipsize","require_color","require_overlay","require_scene","gaugeRange","min","o","max","gaugeValues","out","sortedBands","bands","b","a","gaugeBandIndex","i","value","decimalsOf","text","v","dot","layoutGauge","raw","enter","animated","decimals","shown","frac","sweep","a0","a1","th","semi","xs","ys","r","k","minX","maxX","minY","maxY","R","area","cx","cy","lw","rc","bandColors","theme","band","color","css","angleOf","nodes","rb","from","lo","hi","gap","rt","values","all","tickFont","cos","sin","an","len","nx","ny","tx","ty","size","valueFont","labelFont","maxW","valueText","measure","label","blockH","top","percent"],"sources":["../../../../../charts/src/engine/shapes/gauge.ts"],"sourcesContent":["// Gauge layout: rounded track, value arc colored by its band, optional\n// needle, thin band scale, tick labels and the value in the middle.\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport {\n clamp,\n ellipsize,\n finite,\n resolveWith,\n type LayoutContext,\n type LayoutResult,\n type ShapeNode,\n} from \"./scene\";\nimport type { GaugeBand, GaugeChartOptions } from \"./types\";\n\nexport const gaugeRange = (o: GaugeChartOptions): [number, number] => {\n const min = finite(o.min, 0);\n let max = finite(o.max, 100);\n if (!(max > min)) max = min + 1;\n return [min, max];\n};\n\nexport const gaugeValues = (\n o: GaugeChartOptions,\n _hidden: ReadonlySet<number>,\n out: Map<string, number>,\n) => {\n out.set(\"value\", finite(o.value, gaugeRange(o)[0]));\n};\n\n/** Bands sorted by their upper bound */\nconst sortedBands = (bands: readonly GaugeBand[] | undefined) =>\n (bands ?? [])\n .filter((b) => Number.isFinite(b.to))\n .slice()\n .sort((a, b) => a.to - b.to);\n\n/** Band of a value: the first whose `to` is not below it (the last one above all bounds); -1 without bands */\nexport const gaugeBandIndex = (\n bands: readonly GaugeBand[] | undefined,\n value: number,\n): number => {\n if (!bands?.length) return -1;\n for (let i = 0; i < bands.length; i++) if (value <= bands[i].to) return i;\n return bands.length - 1;\n};\n\nconst decimalsOf = (v: number) => {\n const text = String(v);\n const dot = text.indexOf(\".\");\n return dot < 0 || text.includes(\"e\") ? 0 : Math.min(4, text.length - dot - 1);\n};\n\nexport const layoutGauge = (\n o: GaugeChartOptions,\n c: LayoutContext,\n): LayoutResult => {\n const { theme, area, measure } = c;\n const [min, max] = gaugeRange(o);\n const raw = finite(o.value, min);\n const enter = clamp(c.enter, 0, 1);\n const animated = min + (c.value(\"value\", raw) - min) * enter;\n const decimals = decimalsOf(raw);\n const shown = animated === raw ? raw : Number(animated.toFixed(decimals));\n const frac = clamp((animated - min) / (max - min), 0, 1);\n const sweep = (clamp(finite(o.sweep, 240), 30, 360) * Math.PI) / 180;\n const a0 = -Math.PI / 2 - sweep / 2;\n const a1 = a0 + sweep;\n const th = clamp(finite(o.thickness, 0.16), 0.04, 0.4);\n const semi = sweep <= (200 * Math.PI) / 180;\n\n // bounding box of the unit gauge: arc, round caps and the texts\n const xs: number[] = [0];\n const ys: number[] = [o.needle ? 0.62 : semi ? 0.26 : 0];\n for (const a of [a0, a1]) {\n const r = 1 - th / 2;\n xs.push(r * Math.cos(a) - th / 2, r * Math.cos(a) + th / 2);\n ys.push(r * Math.sin(a) - th / 2, r * Math.sin(a) + th / 2);\n }\n for (let k = -4; k <= 4; k++) {\n const a = (k * Math.PI) / 2;\n if (a > a0 && a < a1) {\n xs.push(Math.cos(a));\n ys.push(Math.sin(a));\n }\n }\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const R = Math.max(\n 4,\n Math.min(area.width / (maxX - minX), area.height / (maxY - minY)),\n );\n const cx = area.x + (area.width - (maxX - minX) * R) / 2 - minX * R;\n const cy = area.y + (area.height - (maxY - minY) * R) / 2 - minY * R;\n const lw = R * th;\n const rc = R - lw / 2;\n\n const bands = sortedBands(o.bands);\n const bandColors = bands.map((b, i) =>\n resolveWith(theme, b.color, theme.palette[i % theme.palette.length]),\n );\n const band = gaugeBandIndex(bands, clamp(animated, min, max));\n const color = band >= 0 ? bandColors[band] : c.color(o.color, 0);\n const css = toCss(color);\n const angleOf = (v: number) =>\n a0 + sweep * clamp((v - min) / (max - min), 0, 1);\n\n const nodes: ShapeNode[] = [\n { kind: \"circle\", cx, cy, r: R, hit: 0 },\n {\n kind: \"arc\",\n cx,\n cy,\n r: rc,\n a0,\n a1,\n width: lw,\n color: toCss(theme.grid),\n cap: \"round\",\n },\n ];\n if (frac > 0.0005)\n nodes.push({\n kind: \"arc\",\n cx,\n cy,\n r: rc,\n a0,\n a1: a0 + sweep * frac,\n width: lw,\n color: css,\n cap: \"round\",\n hit: 0,\n });\n\n // thin band scale inside the track\n const rb = R - lw - 6;\n if (bands.length && rb > 12) {\n let from = min;\n bands.forEach((b, i) => {\n const lo = Math.max(from, min);\n const hi = Math.min(b.to, max);\n from = b.to;\n if (hi <= lo) return;\n const gap = i ? 1 / rb : 0;\n nodes.push({\n kind: \"arc\",\n cx,\n cy,\n r: rb,\n a0: angleOf(lo) + gap,\n a1: angleOf(hi) - (hi < max ? 1 / rb : 0),\n width: 3,\n color: toCss(bandColors[i], 0.9),\n cap: \"butt\",\n });\n });\n }\n\n // tick labels at the ends and the band bounds\n if (o.ticks !== false && R >= 48) {\n const rt = (bands.length && rb > 12 ? rb - 1.5 : R - lw) - 8;\n const values = [min, ...bands.map((b) => b.to), max].filter(\n (v, i, all) =>\n v >= min &&\n v <= max &&\n all.indexOf(v) === i &&\n !(sweep >= Math.PI * 2 - 1e-6 && v === max),\n );\n const tickFont = font(theme, 11);\n for (const v of values) {\n const a = angleOf(v);\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n nodes.push({\n kind: \"text\",\n x: cx + rt * cos,\n y: cy + rt * sin,\n text: c.format(v),\n font: tickFont,\n color: toCss(theme.textMuted),\n align: cos > 0.35 ? \"right\" : cos < -0.35 ? \"left\" : \"center\",\n baseline: sin > 0.35 ? \"bottom\" : sin < -0.35 ? \"top\" : \"middle\",\n });\n }\n }\n\n // needle\n if (o.needle) {\n const an = a0 + sweep * frac;\n const len = rc;\n const nx = Math.cos(an + Math.PI / 2);\n const ny = Math.sin(an + Math.PI / 2);\n const tx = cx + len * Math.cos(an);\n const ty = cy + len * Math.sin(an);\n nodes.push(\n {\n kind: \"polygon\",\n points: [\n cx + nx * 3.5,\n cy + ny * 3.5,\n tx + nx * 1,\n ty + ny * 1,\n tx - nx * 1,\n ty - ny * 1,\n cx - nx * 3.5,\n cy - ny * 3.5,\n ],\n fill: toCss(theme.text, 0.85),\n radius: 1,\n },\n { kind: \"circle\", cx, cy, r: 7, fill: toCss(theme.text, 0.9) },\n { kind: \"circle\", cx, cy, r: 2.5, fill: toCss(theme.background) },\n );\n }\n\n // value and label\n const size = clamp(R * 0.28, 16, 40);\n const valueFont = font(theme, size, 600);\n const labelFont = font(theme, 12);\n const maxW = rc * (semi ? 1.5 : 1.3);\n const valueText = ellipsize(c.format(shown), maxW, valueFont, measure);\n const label = o.label ? ellipsize(o.label, maxW, labelFont, measure) : \"\";\n const blockH = size + (label ? 18 : 0);\n const top = o.needle\n ? cy + Math.max(14, R * 0.16)\n : semi\n ? cy - size - 2\n : cy - blockH / 2;\n nodes.push({\n kind: \"text\",\n x: cx,\n y: top + size / 2,\n text: valueText,\n font: valueFont,\n color: toCss(theme.text),\n align: \"center\",\n baseline: \"middle\",\n });\n if (label)\n nodes.push({\n kind: \"text\",\n x: cx,\n y: semi && !o.needle ? cy + 12 : top + size + 11,\n text: label,\n font: labelFont,\n color: toCss(theme.textMuted),\n align: \"center\",\n baseline: \"middle\",\n });\n\n const percent = clamp((raw - min) / (max - min), 0, 1);\n return {\n nodes,\n items: [\n {\n index: 0,\n name: o.label ?? \"Value\",\n value: raw,\n percent,\n share: c.percent(percent),\n color: css,\n x: cx + rc * Math.cos(angleOf(raw)),\n y: cy + rc * Math.sin(angleOf(raw)),\n rows: [\n { name: \"Value\", value: c.format(raw) },\n { name: \"Of range\", value: c.percent(percent) },\n ],\n },\n ],\n dim: 1,\n empty: false,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { LayoutContext, LayoutResult } from './scene.cjs';
2
+ import { GaugeBand, GaugeChartOptions } from './types.cjs';
3
+ export declare const gaugeRange: (o: GaugeChartOptions) => [number, number];
4
+ export declare const gaugeValues: (o: GaugeChartOptions, _hidden: ReadonlySet<number>, out: Map<string, number>) => void;
5
+ /** Band of a value: the first whose `to` is not below it (the last one above all bounds); -1 without bands */
6
+ export declare const gaugeBandIndex: (bands: readonly GaugeBand[] | undefined, value: number) => number;
7
+ export declare const layoutGauge: (o: GaugeChartOptions, c: LayoutContext) => LayoutResult;
@@ -0,0 +1,7 @@
1
+ import { LayoutContext, LayoutResult } from './scene.js';
2
+ import { GaugeBand, GaugeChartOptions } from './types.js';
3
+ export declare const gaugeRange: (o: GaugeChartOptions) => [number, number];
4
+ export declare const gaugeValues: (o: GaugeChartOptions, _hidden: ReadonlySet<number>, out: Map<string, number>) => void;
5
+ /** Band of a value: the first whose `to` is not below it (the last one above all bounds); -1 without bands */
6
+ export declare const gaugeBandIndex: (bands: readonly GaugeBand[] | undefined, value: number) => number;
7
+ export declare const layoutGauge: (o: GaugeChartOptions, c: LayoutContext) => LayoutResult;
@@ -0,0 +1,173 @@
1
+ import { toCss as e } from "../color.js";
2
+ import { font as t } from "../overlay.js";
3
+ import { clamp as n, ellipsize as r, finite as i, resolveWith as a } from "./scene.js";
4
+ //#region src/engine/shapes/gauge.ts
5
+ var o = (e) => {
6
+ let t = i(e.min, 0), n = i(e.max, 100);
7
+ return n > t || (n = t + 1), [t, n];
8
+ }, s = (e, t, n) => {
9
+ n.set("value", i(e.value, o(e)[0]));
10
+ }, c = (e) => (e ?? []).filter((e) => Number.isFinite(e.to)).slice().sort((e, t) => e.to - t.to), l = (e, t) => {
11
+ if (!e?.length) return -1;
12
+ for (let n = 0; n < e.length; n++) if (t <= e[n].to) return n;
13
+ return e.length - 1;
14
+ }, u = (e) => {
15
+ let t = String(e), n = t.indexOf(".");
16
+ return n < 0 || t.includes("e") ? 0 : Math.min(4, t.length - n - 1);
17
+ }, d = (s, d) => {
18
+ let { theme: f, area: p, measure: m } = d, [h, g] = o(s), _ = i(s.value, h), v = n(d.enter, 0, 1), y = h + (d.value("value", _) - h) * v, b = u(_), x = y === _ ? _ : Number(y.toFixed(b)), S = n((y - h) / (g - h), 0, 1), C = n(i(s.sweep, 240), 30, 360) * Math.PI / 180, w = -Math.PI / 2 - C / 2, T = w + C, E = n(i(s.thickness, .16), .04, .4), D = C <= 200 * Math.PI / 180, O = [0], k = [s.needle ? .62 : D ? .26 : 0];
19
+ for (let e of [w, T]) {
20
+ let t = 1 - E / 2;
21
+ O.push(t * Math.cos(e) - E / 2, t * Math.cos(e) + E / 2), k.push(t * Math.sin(e) - E / 2, t * Math.sin(e) + E / 2);
22
+ }
23
+ for (let e = -4; e <= 4; e++) {
24
+ let t = e * Math.PI / 2;
25
+ t > w && t < T && (O.push(Math.cos(t)), k.push(Math.sin(t)));
26
+ }
27
+ let A = Math.min(...O), j = Math.max(...O), M = Math.min(...k), N = Math.max(...k), P = Math.max(4, Math.min(p.width / (j - A), p.height / (N - M))), F = p.x + (p.width - (j - A) * P) / 2 - A * P, I = p.y + (p.height - (N - M) * P) / 2 - M * P, L = P * E, R = P - L / 2, z = c(s.bands), B = z.map((e, t) => a(f, e.color, f.palette[t % f.palette.length])), V = l(z, n(y, h, g)), H = V >= 0 ? B[V] : d.color(s.color, 0), U = e(H), W = (e) => w + C * n((e - h) / (g - h), 0, 1), G = [{
28
+ kind: "circle",
29
+ cx: F,
30
+ cy: I,
31
+ r: P,
32
+ hit: 0
33
+ }, {
34
+ kind: "arc",
35
+ cx: F,
36
+ cy: I,
37
+ r: R,
38
+ a0: w,
39
+ a1: T,
40
+ width: L,
41
+ color: e(f.grid),
42
+ cap: "round"
43
+ }];
44
+ S > 5e-4 && G.push({
45
+ kind: "arc",
46
+ cx: F,
47
+ cy: I,
48
+ r: R,
49
+ a0: w,
50
+ a1: w + C * S,
51
+ width: L,
52
+ color: U,
53
+ cap: "round",
54
+ hit: 0
55
+ });
56
+ let K = P - L - 6;
57
+ if (z.length && K > 12) {
58
+ let t = h;
59
+ z.forEach((n, r) => {
60
+ let i = Math.max(t, h), a = Math.min(n.to, g);
61
+ if (t = n.to, a <= i) return;
62
+ let o = r ? 1 / K : 0;
63
+ G.push({
64
+ kind: "arc",
65
+ cx: F,
66
+ cy: I,
67
+ r: K,
68
+ a0: W(i) + o,
69
+ a1: W(a) - (a < g ? 1 / K : 0),
70
+ width: 3,
71
+ color: e(B[r], .9),
72
+ cap: "butt"
73
+ });
74
+ });
75
+ }
76
+ if (s.ticks !== !1 && P >= 48) {
77
+ let n = (z.length && K > 12 ? K - 1.5 : P - L) - 8, r = [
78
+ h,
79
+ ...z.map((e) => e.to),
80
+ g
81
+ ].filter((e, t, n) => e >= h && e <= g && n.indexOf(e) === t && !(C >= Math.PI * 2 - 1e-6 && e === g)), i = t(f, 11);
82
+ for (let t of r) {
83
+ let r = W(t), a = Math.cos(r), o = Math.sin(r);
84
+ G.push({
85
+ kind: "text",
86
+ x: F + n * a,
87
+ y: I + n * o,
88
+ text: d.format(t),
89
+ font: i,
90
+ color: e(f.textMuted),
91
+ align: a > .35 ? "right" : a < -.35 ? "left" : "center",
92
+ baseline: o > .35 ? "bottom" : o < -.35 ? "top" : "middle"
93
+ });
94
+ }
95
+ }
96
+ if (s.needle) {
97
+ let t = w + C * S, n = R, r = Math.cos(t + Math.PI / 2), i = Math.sin(t + Math.PI / 2), a = F + n * Math.cos(t), o = I + n * Math.sin(t);
98
+ G.push({
99
+ kind: "polygon",
100
+ points: [
101
+ F + r * 3.5,
102
+ I + i * 3.5,
103
+ a + r * 1,
104
+ o + i * 1,
105
+ a - r * 1,
106
+ o - i * 1,
107
+ F - r * 3.5,
108
+ I - i * 3.5
109
+ ],
110
+ fill: e(f.text, .85),
111
+ radius: 1
112
+ }, {
113
+ kind: "circle",
114
+ cx: F,
115
+ cy: I,
116
+ r: 7,
117
+ fill: e(f.text, .9)
118
+ }, {
119
+ kind: "circle",
120
+ cx: F,
121
+ cy: I,
122
+ r: 2.5,
123
+ fill: e(f.background)
124
+ });
125
+ }
126
+ let q = n(P * .28, 16, 40), J = t(f, q, 600), Y = t(f, 12), X = R * (D ? 1.5 : 1.3), ee = r(d.format(x), X, J, m), Z = s.label ? r(s.label, X, Y, m) : "", te = q + (Z ? 18 : 0), Q = s.needle ? I + Math.max(14, P * .16) : D ? I - q - 2 : I - te / 2;
127
+ G.push({
128
+ kind: "text",
129
+ x: F,
130
+ y: Q + q / 2,
131
+ text: ee,
132
+ font: J,
133
+ color: e(f.text),
134
+ align: "center",
135
+ baseline: "middle"
136
+ }), Z && G.push({
137
+ kind: "text",
138
+ x: F,
139
+ y: D && !s.needle ? I + 12 : Q + q + 11,
140
+ text: Z,
141
+ font: Y,
142
+ color: e(f.textMuted),
143
+ align: "center",
144
+ baseline: "middle"
145
+ });
146
+ let $ = n((_ - h) / (g - h), 0, 1);
147
+ return {
148
+ nodes: G,
149
+ items: [{
150
+ index: 0,
151
+ name: s.label ?? "Value",
152
+ value: _,
153
+ percent: $,
154
+ share: d.percent($),
155
+ color: U,
156
+ x: F + R * Math.cos(W(_)),
157
+ y: I + R * Math.sin(W(_)),
158
+ rows: [{
159
+ name: "Value",
160
+ value: d.format(_)
161
+ }, {
162
+ name: "Of range",
163
+ value: d.percent($)
164
+ }]
165
+ }],
166
+ dim: 1,
167
+ empty: !1
168
+ };
169
+ };
170
+ //#endregion
171
+ export { l as gaugeBandIndex, o as gaugeRange, s as gaugeValues, d as layoutGauge };
172
+
173
+ //# sourceMappingURL=gauge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gauge.js","names":["gaugeRange","min","finite","o","max","gaugeValues","sortedBands","bands","b","a","gaugeBandIndex","i","value","decimalsOf","text","v","dot","layoutGauge","c","raw","enter","clamp","animated","decimals","shown","frac","sweep","a0","a1","th","semi","xs","ys","r","k","minX","maxX","minY","maxY","R","area","cx","cy","lw","rc","bandColors","resolveWith","theme","band","color","css","toCss","angleOf","nodes","rb","from","lo","hi","gap","rt","values","all","tickFont","font","cos","sin","an","len","nx","ny","tx","ty","size","valueFont","labelFont","maxW","valueText","ellipsize","measure","label","blockH","top","percent"],"sources":["../../../../../charts/src/engine/shapes/gauge.ts"],"sourcesContent":["// Gauge layout: rounded track, value arc colored by its band, optional\n// needle, thin band scale, tick labels and the value in the middle.\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport {\n clamp,\n ellipsize,\n finite,\n resolveWith,\n type LayoutContext,\n type LayoutResult,\n type ShapeNode,\n} from \"./scene\";\nimport type { GaugeBand, GaugeChartOptions } from \"./types\";\n\nexport const gaugeRange = (o: GaugeChartOptions): [number, number] => {\n const min = finite(o.min, 0);\n let max = finite(o.max, 100);\n if (!(max > min)) max = min + 1;\n return [min, max];\n};\n\nexport const gaugeValues = (\n o: GaugeChartOptions,\n _hidden: ReadonlySet<number>,\n out: Map<string, number>,\n) => {\n out.set(\"value\", finite(o.value, gaugeRange(o)[0]));\n};\n\n/** Bands sorted by their upper bound */\nconst sortedBands = (bands: readonly GaugeBand[] | undefined) =>\n (bands ?? [])\n .filter((b) => Number.isFinite(b.to))\n .slice()\n .sort((a, b) => a.to - b.to);\n\n/** Band of a value: the first whose `to` is not below it (the last one above all bounds); -1 without bands */\nexport const gaugeBandIndex = (\n bands: readonly GaugeBand[] | undefined,\n value: number,\n): number => {\n if (!bands?.length) return -1;\n for (let i = 0; i < bands.length; i++) if (value <= bands[i].to) return i;\n return bands.length - 1;\n};\n\nconst decimalsOf = (v: number) => {\n const text = String(v);\n const dot = text.indexOf(\".\");\n return dot < 0 || text.includes(\"e\") ? 0 : Math.min(4, text.length - dot - 1);\n};\n\nexport const layoutGauge = (\n o: GaugeChartOptions,\n c: LayoutContext,\n): LayoutResult => {\n const { theme, area, measure } = c;\n const [min, max] = gaugeRange(o);\n const raw = finite(o.value, min);\n const enter = clamp(c.enter, 0, 1);\n const animated = min + (c.value(\"value\", raw) - min) * enter;\n const decimals = decimalsOf(raw);\n const shown = animated === raw ? raw : Number(animated.toFixed(decimals));\n const frac = clamp((animated - min) / (max - min), 0, 1);\n const sweep = (clamp(finite(o.sweep, 240), 30, 360) * Math.PI) / 180;\n const a0 = -Math.PI / 2 - sweep / 2;\n const a1 = a0 + sweep;\n const th = clamp(finite(o.thickness, 0.16), 0.04, 0.4);\n const semi = sweep <= (200 * Math.PI) / 180;\n\n // bounding box of the unit gauge: arc, round caps and the texts\n const xs: number[] = [0];\n const ys: number[] = [o.needle ? 0.62 : semi ? 0.26 : 0];\n for (const a of [a0, a1]) {\n const r = 1 - th / 2;\n xs.push(r * Math.cos(a) - th / 2, r * Math.cos(a) + th / 2);\n ys.push(r * Math.sin(a) - th / 2, r * Math.sin(a) + th / 2);\n }\n for (let k = -4; k <= 4; k++) {\n const a = (k * Math.PI) / 2;\n if (a > a0 && a < a1) {\n xs.push(Math.cos(a));\n ys.push(Math.sin(a));\n }\n }\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const R = Math.max(\n 4,\n Math.min(area.width / (maxX - minX), area.height / (maxY - minY)),\n );\n const cx = area.x + (area.width - (maxX - minX) * R) / 2 - minX * R;\n const cy = area.y + (area.height - (maxY - minY) * R) / 2 - minY * R;\n const lw = R * th;\n const rc = R - lw / 2;\n\n const bands = sortedBands(o.bands);\n const bandColors = bands.map((b, i) =>\n resolveWith(theme, b.color, theme.palette[i % theme.palette.length]),\n );\n const band = gaugeBandIndex(bands, clamp(animated, min, max));\n const color = band >= 0 ? bandColors[band] : c.color(o.color, 0);\n const css = toCss(color);\n const angleOf = (v: number) =>\n a0 + sweep * clamp((v - min) / (max - min), 0, 1);\n\n const nodes: ShapeNode[] = [\n { kind: \"circle\", cx, cy, r: R, hit: 0 },\n {\n kind: \"arc\",\n cx,\n cy,\n r: rc,\n a0,\n a1,\n width: lw,\n color: toCss(theme.grid),\n cap: \"round\",\n },\n ];\n if (frac > 0.0005)\n nodes.push({\n kind: \"arc\",\n cx,\n cy,\n r: rc,\n a0,\n a1: a0 + sweep * frac,\n width: lw,\n color: css,\n cap: \"round\",\n hit: 0,\n });\n\n // thin band scale inside the track\n const rb = R - lw - 6;\n if (bands.length && rb > 12) {\n let from = min;\n bands.forEach((b, i) => {\n const lo = Math.max(from, min);\n const hi = Math.min(b.to, max);\n from = b.to;\n if (hi <= lo) return;\n const gap = i ? 1 / rb : 0;\n nodes.push({\n kind: \"arc\",\n cx,\n cy,\n r: rb,\n a0: angleOf(lo) + gap,\n a1: angleOf(hi) - (hi < max ? 1 / rb : 0),\n width: 3,\n color: toCss(bandColors[i], 0.9),\n cap: \"butt\",\n });\n });\n }\n\n // tick labels at the ends and the band bounds\n if (o.ticks !== false && R >= 48) {\n const rt = (bands.length && rb > 12 ? rb - 1.5 : R - lw) - 8;\n const values = [min, ...bands.map((b) => b.to), max].filter(\n (v, i, all) =>\n v >= min &&\n v <= max &&\n all.indexOf(v) === i &&\n !(sweep >= Math.PI * 2 - 1e-6 && v === max),\n );\n const tickFont = font(theme, 11);\n for (const v of values) {\n const a = angleOf(v);\n const cos = Math.cos(a);\n const sin = Math.sin(a);\n nodes.push({\n kind: \"text\",\n x: cx + rt * cos,\n y: cy + rt * sin,\n text: c.format(v),\n font: tickFont,\n color: toCss(theme.textMuted),\n align: cos > 0.35 ? \"right\" : cos < -0.35 ? \"left\" : \"center\",\n baseline: sin > 0.35 ? \"bottom\" : sin < -0.35 ? \"top\" : \"middle\",\n });\n }\n }\n\n // needle\n if (o.needle) {\n const an = a0 + sweep * frac;\n const len = rc;\n const nx = Math.cos(an + Math.PI / 2);\n const ny = Math.sin(an + Math.PI / 2);\n const tx = cx + len * Math.cos(an);\n const ty = cy + len * Math.sin(an);\n nodes.push(\n {\n kind: \"polygon\",\n points: [\n cx + nx * 3.5,\n cy + ny * 3.5,\n tx + nx * 1,\n ty + ny * 1,\n tx - nx * 1,\n ty - ny * 1,\n cx - nx * 3.5,\n cy - ny * 3.5,\n ],\n fill: toCss(theme.text, 0.85),\n radius: 1,\n },\n { kind: \"circle\", cx, cy, r: 7, fill: toCss(theme.text, 0.9) },\n { kind: \"circle\", cx, cy, r: 2.5, fill: toCss(theme.background) },\n );\n }\n\n // value and label\n const size = clamp(R * 0.28, 16, 40);\n const valueFont = font(theme, size, 600);\n const labelFont = font(theme, 12);\n const maxW = rc * (semi ? 1.5 : 1.3);\n const valueText = ellipsize(c.format(shown), maxW, valueFont, measure);\n const label = o.label ? ellipsize(o.label, maxW, labelFont, measure) : \"\";\n const blockH = size + (label ? 18 : 0);\n const top = o.needle\n ? cy + Math.max(14, R * 0.16)\n : semi\n ? cy - size - 2\n : cy - blockH / 2;\n nodes.push({\n kind: \"text\",\n x: cx,\n y: top + size / 2,\n text: valueText,\n font: valueFont,\n color: toCss(theme.text),\n align: \"center\",\n baseline: \"middle\",\n });\n if (label)\n nodes.push({\n kind: \"text\",\n x: cx,\n y: semi && !o.needle ? cy + 12 : top + size + 11,\n text: label,\n font: labelFont,\n color: toCss(theme.textMuted),\n align: \"center\",\n baseline: \"middle\",\n });\n\n const percent = clamp((raw - min) / (max - min), 0, 1);\n return {\n nodes,\n items: [\n {\n index: 0,\n name: o.label ?? \"Value\",\n value: raw,\n percent,\n share: c.percent(percent),\n color: css,\n x: cx + rc * Math.cos(angleOf(raw)),\n y: cy + rc * Math.sin(angleOf(raw)),\n rows: [\n { name: \"Value\", value: c.format(raw) },\n { name: \"Of range\", value: c.percent(percent) },\n ],\n },\n ],\n dim: 1,\n empty: false,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("./scene.cjs"),t=require("./draw.cjs");var n=12,r=(t,n)=>{let r=(t-n)%e.TAU;return r<0&&(r+=e.TAU),n+r},i=(n,i,a)=>{let o=n-a.cx,s=i-a.cy,c=Math.hypot(o,s);if(c>a.r1||c<a.r0)return!1;let l=a.a1-a.a0;if(l>=e.TAU-1e-6)return!0;if(l<=0)return!1;let u=r(Math.atan2(s,o),a.a0),d=(a.pad??0)/2,f=d>0?t.padAngleAt(d,c):0;return u>=a.a0+f&&u<=a.a1-f},a=(e,t,n)=>{let r=n.length>>1,i=!1;for(let a=0,o=r-1;a<r;o=a++){let r=n[a*2],s=n[a*2+1],c=n[o*2],l=n[o*2+1];s>t!=l>t&&e<(c-r)*(t-s)/(l-s)+r&&(i=!i)}return i},o=e=>{let t=e.length>>1,n=0;for(let r=0,i=t-1;r<t;i=r++)n+=e[i*2]*e[r*2+1]-e[r*2]*e[i*2+1];return Math.abs(n)/2},s=(n,o,s)=>{switch(n.kind){case`sector`:return i(o,s,{...n,pad:t.sectorPad(n)});case`polygon`:return a(o,s,n.points)&&!(n.hole&&a(o,s,n.hole));case`rect`:return o>=n.x&&o<=n.x+n.width&&s>=n.y&&s<=n.y+n.height;case`circle`:return Math.hypot(o-n.cx,s-n.cy)<=n.r;case`arc`:{let t=Math.hypot(o-n.cx,s-n.cy);return Math.abs(t-n.r)>n.width/2+4?!1:n.a1-n.a0>=e.TAU-1e-6||r(Math.atan2(s-n.cy,o-n.cx),n.a0)<=n.a1}default:return!1}},c=(e,t,i)=>{let s=e.radar;if(!s||!s.series.length)return null;let c=null,l=n;for(let e of s.series)for(let n=0;n<e.points.length>>1;n++){let r=Math.hypot(t-e.points[n*2],i-e.points[n*2+1]);r<=l&&(l=r,c={index:e.index,indicator:n})}if(c)return c;let u=1/0,d=-1;for(let e of s.series){if(e.points.length<6||!a(t,i,e.points))continue;let n=o(e.points);n<u&&(u=n,d=e.index)}if(d<0)return null;let f=Math.atan2(i-s.cy,t-s.cx),p=0,m=1/0;return s.angles.forEach((e,t)=>{let n=Math.abs(r(f-e+Math.PI,0)-Math.PI);n<m&&(m=n,p=t)}),{index:d,indicator:p}},l=(e,t,n,r=null)=>{if(e.empty)return null;if(e.type===`radar`)return c(e,t,n);let i=e.enter;i&&i.scale>0&&i.scale!==1&&(t=i.cx+(t-i.cx)/i.scale,n=i.cy+(n-i.cy)/i.scale);let a=new Set(e.items.map(e=>e.index));for(let i=e.nodes.length-1;i>=0;i--){let o=e.nodes[i];if(o.hit!==void 0&&a.has(o.hit)&&o.kind!==`text`&&o.kind!==`line`){if(s(o,t,n))return{index:o.hit};if(r?.index===o.hit&&o.shift){let[e,r]=o.shift;if(s(o,t-e,n-r))return{index:o.hit}}}}return null},u=(e,t)=>{let n=e.items.find(e=>e.index===t.index);if(!n)return null;let r=t.indicator===void 0?null:n.indicators?.[t.indicator];return r?{x:r.x,y:r.y}:{x:n.x,y:n.y}},d=(e,t,n)=>{let r=e.items;if(!r.length)return null;let i=t?r.findIndex(e=>e.index===t.index):-1,a=e.type===`radar`;if(i<0){let e=n===`prev`||n===`up`?r.length-1:0;return a?{index:r[e].index,indicator:0}:{index:r[e].index}}let o=n===`next`||n===`down`;if(a&&(n===`next`||n===`prev`)){let e=r[i].indicators?.length??1,n=t?.indicator??0;return{index:r[i].index,indicator:(n+(o?1:-1)+e)%e}}let s=r[(i+(o?1:-1)+r.length)%r.length];return a?{index:s.index,indicator:t?.indicator??0}:{index:s.index}};exports.hitTestShapes=l,exports.hoverAnchor=u,exports.pointInPolygon=a,exports.pointInSector=i,exports.stepHover=d;
2
+ //# sourceMappingURL=hit.cjs.map