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":"radar.js","names":["radarRanges","o","min","finite","ind","max","s","v","k","radarValues","ranges","on","hidden","si","out","seriesName","layoutRadar","c","n","emptyLayout","levels","clamp","circle","angles","TAU","labelFont","font","theme","strongFont","halfW","area","halfH","radius","cos","sin","w","measure","half","cx","cy","at","r","ring","points","nodes","band","toCss","line","l","rIn","color","ends","x","y","enter","items","dots","geometry","isHidden","visibility","css","opacity","target","frac","indicators","value","labelBoxes","room","text","ellipsize","align","baseline"],"sources":["../../../../../charts/src/engine/shapes/radar.ts"],"sourcesContent":["// Radar (spider) layout: concentric grid with alternate bands, spokes,\n// indicator labels placed by angle, series polygons with dots.\n\nimport { toCss } from \"../color\";\nimport { font } from \"../overlay\";\nimport {\n clamp,\n ellipsize,\n emptyLayout,\n finite,\n TAU,\n type LayoutContext,\n type LayoutResult,\n type ShapeItem,\n type ShapeNode,\n type ShapeRect,\n} from \"./scene\";\nimport type { RadarChartOptions } from \"./types\";\n\n/** Value range of every indicator (center, rim) */\nexport const radarRanges = (o: RadarChartOptions): [number, number][] =>\n o.indicators.map((ind, k) => {\n const min = finite(ind.min);\n let max = ind.max;\n if (max === undefined || !Number.isFinite(max)) {\n max = -Infinity;\n for (const s of o.series) {\n const v = s.values[k];\n if (Number.isFinite(v)) max = Math.max(max, v);\n }\n }\n if (!(max > min)) max = min + 1;\n return [min, max];\n });\n\n/** Target values: hidden series shrink to the center */\nexport const radarValues = (\n o: RadarChartOptions,\n hidden: ReadonlySet<number>,\n out: Map<string, number>,\n) => {\n const ranges = radarRanges(o);\n o.series.forEach((s, si) => {\n const on = !hidden.has(si);\n out.set(`~${si}`, on ? 1 : 0);\n ranges.forEach(([min], k) => {\n out.set(`${si}:${k}`, on ? finite(s.values[k], min) : min);\n });\n });\n};\n\nexport const seriesName = (o: RadarChartOptions, si: number) =>\n o.series[si]?.name ?? `Series ${si + 1}`;\n\nexport const layoutRadar = (\n o: RadarChartOptions,\n c: LayoutContext,\n): LayoutResult => {\n const { theme, area, measure, hidden } = c;\n const n = o.indicators.length;\n if (!n) return emptyLayout(c);\n const ranges = radarRanges(o);\n const levels = Math.round(clamp(finite(o.levels, 4), 1, 12));\n const circle = o.shape === \"circle\";\n const angles = o.indicators.map((_, k) => -Math.PI / 2 + (TAU * k) / n);\n const labelFont = font(theme, 12);\n const strongFont = font(theme, 12, 600);\n\n // largest radius leaving room for every label, given its direction\n const LABEL_GAP = 10;\n const LABEL_H = 16;\n const halfW = area.width / 2;\n const halfH = area.height / 2;\n let radius = Math.min(halfW, halfH) - 4;\n o.indicators.forEach((ind, k) => {\n const cos = Math.abs(Math.cos(angles[k]));\n const sin = Math.abs(Math.sin(angles[k]));\n const w = measure(ind.name, strongFont);\n if (cos > 0.15)\n radius = Math.min(radius, (halfW - w - 4) / cos - LABEL_GAP);\n else radius = Math.min(radius, halfW - w / 2 - 4);\n if (sin > 0.3)\n radius = Math.min(radius, (halfH - LABEL_H - 2) / sin - LABEL_GAP);\n else radius = Math.min(radius, halfH - LABEL_H / 2 - 2);\n });\n const half = Math.min(area.width, area.height) / 2;\n radius = Math.max(radius, half * 0.45, 4);\n const cx = area.x + area.width / 2;\n const cy = area.y + area.height / 2;\n const at = (k: number, r: number): [number, number] => [\n cx + r * Math.cos(angles[k]),\n cy + r * Math.sin(angles[k]),\n ];\n const ring = (r: number) => {\n const points: number[] = [];\n for (let k = 0; k < n; k++) points.push(...at(k, r));\n return points;\n };\n\n const nodes: ShapeNode[] = [];\n const band = toCss(theme.grid, 0.45);\n const line = toCss(theme.grid);\n\n // grid: alternate bands from the rim, ring outlines, spokes\n for (let l = levels; l >= 1; l--) {\n const r = (radius * l) / levels;\n const rIn = (radius * (l - 1)) / levels;\n if ((levels - l) % 2 === 0) {\n if (circle)\n nodes.push({\n kind: \"sector\",\n cx,\n cy,\n r0: rIn,\n r1: r,\n a0: 0,\n a1: TAU,\n pad: 0,\n corner: 0,\n fill: band,\n });\n else if (n >= 3)\n nodes.push({\n kind: \"polygon\",\n points: ring(r),\n ...(l > 1 ? { hole: ring(rIn) } : {}),\n fill: band,\n });\n }\n }\n for (let l = 1; l <= levels; l++) {\n const r = (radius * l) / levels;\n const color = l === levels ? toCss(theme.axis, 0.9) : line;\n if (circle || n < 3)\n nodes.push({\n kind: \"arc\",\n cx,\n cy,\n r,\n a0: 0,\n a1: TAU,\n width: 1,\n color,\n cap: \"butt\",\n });\n else\n nodes.push({\n kind: \"polygon\",\n points: ring(r),\n stroke: color,\n lineWidth: 1,\n });\n }\n const ends = angles.map((_, k) => at(k, radius));\n for (const [x, y] of ends)\n nodes.push({ kind: \"line\", points: [cx, cy, x, y], color: line, width: 1 });\n nodes.push({\n kind: \"guide\",\n cx,\n cy,\n ends,\n color: toCss(theme.textMuted, 0.55),\n });\n\n // series\n const enter = clamp(c.enter, 0, 1);\n const items: ShapeItem[] = [];\n const dots: ShapeNode[] = [];\n const geometry: { index: number; points: number[] }[] = [];\n o.series.forEach((s, si) => {\n const isHidden = hidden.has(si);\n const visibility = clamp(c.value(`~${si}`, isHidden ? 0 : 1), 0, 1);\n if (isHidden && visibility <= 0.001) return;\n const color = c.color(s.color, si);\n const css = toCss(color);\n const opacity = clamp(finite(s.opacity, 0.18), 0, 1);\n const points: number[] = [];\n ranges.forEach(([min, max], k) => {\n const target = isHidden ? min : finite(s.values[k], min);\n const v = c.value(`${si}:${k}`, target);\n const frac = clamp((v - min) / (max - min), 0, 1);\n points.push(...at(k, radius * frac * enter));\n });\n nodes.push({\n kind: \"polygon\",\n points,\n fill: toCss(color, opacity),\n stroke: css,\n lineWidth: 2,\n hit: si,\n hoverFill: toCss(color, Math.min(0.5, opacity * 2 + 0.06)),\n hoverLineWidth: 3,\n });\n if (o.dots !== false) {\n for (let k = 0; k < n; k++)\n dots.push({\n kind: \"circle\",\n cx: points[k * 2],\n cy: points[k * 2 + 1],\n r: 3,\n fill: css,\n stroke: toCss(theme.background),\n lineWidth: 1.5,\n hit: si,\n indicator: k,\n hoverR: 5,\n halo: toCss(color, 0.2),\n });\n }\n if (isHidden) return;\n geometry.push({ index: si, points });\n const indicators = ranges.map(([min, max], k) => {\n const value = finite(s.values[k]);\n return {\n name: o.indicators[k].name,\n value,\n percent: clamp((value - min) / (max - min), 0, 1),\n x: points[k * 2],\n y: points[k * 2 + 1],\n };\n });\n items.push({\n index: si,\n name: seriesName(o, si),\n value: indicators[0].value,\n percent: indicators[0].percent,\n color: css,\n x: indicators[0].x,\n y: indicators[0].y,\n rows: indicators.map((ind) => ({\n name: ind.name,\n value: c.format(ind.value),\n })),\n indicators,\n });\n });\n nodes.push(...dots);\n\n // indicator labels\n const labelBoxes: ShapeRect[] = [];\n o.indicators.forEach((ind, k) => {\n const cos = Math.cos(angles[k]);\n const sin = Math.sin(angles[k]);\n const [x, y] = at(k, radius + LABEL_GAP);\n const room =\n Math.abs(cos) < 0.15\n ? area.width\n : halfW - Math.abs(cos) * (radius + LABEL_GAP) - 2;\n const text = ellipsize(ind.name, Math.max(0, room), strongFont, measure);\n if (!text) return;\n const align = cos > 0.15 ? \"left\" : cos < -0.15 ? \"right\" : \"center\";\n const baseline = sin < -0.3 ? \"bottom\" : sin > 0.3 ? \"top\" : \"middle\";\n const w = measure(text, strongFont);\n labelBoxes.push({\n x: align === \"left\" ? x : align === \"right\" ? x - w : x - w / 2,\n y:\n baseline === \"top\"\n ? y\n : baseline === \"bottom\"\n ? y - LABEL_H\n : y - LABEL_H / 2,\n width: w,\n height: LABEL_H,\n });\n nodes.push({\n kind: \"text\",\n x,\n y,\n text,\n font: labelFont,\n color: toCss(theme.textMuted),\n align,\n baseline,\n indicator: k,\n hoverColor: toCss(theme.text),\n hoverFont: strongFont,\n });\n });\n\n return {\n nodes,\n items,\n dim: 0.35,\n empty: false,\n radar: { cx, cy, radius, angles, series: geometry, labels: labelBoxes },\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ const e=require("./scene.cjs"),t=require("./layout.cjs");var n=()=>typeof performance<`u`&&typeof performance.now==`function`?performance.now():Date.now(),r=()=>{let e=globalThis;try{return!!e.matchMedia?.(`(prefers-reduced-motion: reduce)`)?.matches}catch{return!1}},i=(n,i=r)=>{let a=n,o=new Set,s=()=>{let e=t.toggleCount(a);if(a.hidden){o.clear();for(let t of a.hidden)Number.isInteger(t)&&t>=0&&t<e&&o.add(t)}else for(let t of[...o])t>=e&&o.delete(t)};s();let c=e=>[...e].sort((e,t)=>e-t),l=!1,u=null,d=null,f=1,p=()=>a.animation!==!1&&!i(),m=()=>{let e=t.shapeValues(a,o);return d&&f<1?t.blendValues(d.from,e,f):e},h=e=>{let n=m();if(e(),!p()){d=null,l=!0;return}t.sameValues(n,t.shapeValues(a,o))||(d={from:n,start:null},f=0)};return{get options(){return a},hidden:o,setOptions(e){if(e.type!==a.type){a=e,o.clear(),s(),l=!1,u=null,d=null,f=1;return}h(()=>{a=e,s()})},toggle(e){if(!(Number.isInteger(e)&&e>=0)||e>=t.toggleCount(a))return null;let n=new Set(o),r=!n.has(e);return r?n.add(e):n.delete(e),a.hidden||h(()=>{r?o.add(e):o.delete(e)}),{index:e,hidden:r,hiddenIndexes:c(n)}},hiddenIndexes:()=>c(o),frame(n,r){let i=1;if(!l){if(!p())l=!0;else{u===null&&(u=n);let t=(n-u)/600;i=e.easeOutCubic(t),t>=1&&(l=!0,i=1)}}let s=1;if(d){if(!p())d=null;else{d.start===null&&(d.start=n);let t=(n-d.start)/400;s=t>=1?1:e.easeOutCubic(t)}}f=s;let c=t.layoutShapeScene({...r,options:a,hidden:o,enter:i,from:d?.from??null,t:s});return d&&s>=1&&(d=null),{scene:c,animating:!l||d!==null}}}};exports.createShapeRuntime=i,exports.now=n,exports.prefersReducedMotion=r;
2
+ //# sourceMappingURL=runtime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.cjs","names":["toggleCount","shapeValues","blendValues","sameValues","easeOutCubic","layoutShapeScene","require_scene","require_layout","now","prefersReducedMotion","g","createShapeRuntime","options","initial","hidden","syncHidden","count","i","sorted","set","a","b","entered","entryStart","update","lastT","animated","reducedMotion","displayed","targets","transition","from","mutate","next","index","proposed","nowHidden","enter","time","p","t","scene","input"],"sources":["../../../../../charts/src/engine/shapes/runtime.ts"],"sourcesContent":["// Animation and visibility state shared by the DOM and canvas hosts: entry\n// animation, interpolation from the displayed values on updates / toggles.\n\nimport {\n blendValues,\n layoutShapeScene,\n sameValues,\n shapeValues,\n toggleCount,\n type ShapeLayoutInput,\n} from \"./layout\";\nimport { easeOutCubic, type ShapeScene } from \"./scene\";\nimport type { ShapeChartOptions, ShapeToggleEvent } from \"./types\";\n\n/** Duration of the entry animation, ms */\nexport const ENTER_MS = 600;\n/** Duration of the update animation, ms */\nexport const UPDATE_MS = 400;\n\nexport const now = () =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n\n/** Whether the user prefers reduced motion (false without `matchMedia`) */\nexport const prefersReducedMotion = () => {\n const g = globalThis as {\n matchMedia?: (query: string) => { matches: boolean } | null;\n };\n try {\n return !!g.matchMedia?.(\"(prefers-reduced-motion: reduce)\")?.matches;\n } catch {\n return false;\n }\n};\n\nexport type ShapeFrameInput = Omit<\n ShapeLayoutInput,\n \"options\" | \"hidden\" | \"enter\" | \"from\" | \"t\"\n>;\n\nexport interface ShapeRuntime {\n readonly options: ShapeChartOptions;\n readonly hidden: ReadonlySet<number>;\n setOptions(options: ShapeChartOptions): void;\n /**\n * Hides / shows an entry (only proposes it when `options.hidden` controls\n * the state); null when the index is out of range\n */\n toggle(index: number): ShapeToggleEvent | null;\n /** Hidden indexes, ascending */\n hiddenIndexes(): number[];\n /** Lays the scene out at time `time`; `animating` asks for another frame */\n frame(\n time: number,\n input: ShapeFrameInput,\n ): { scene: ShapeScene; animating: boolean };\n}\n\nexport const createShapeRuntime = (\n initial: ShapeChartOptions,\n reducedMotion: () => boolean = prefersReducedMotion,\n): ShapeRuntime => {\n let options = initial;\n const hidden = new Set<number>();\n /** Replaces the hidden set by the controlled `hidden` option (if any) */\n const syncHidden = () => {\n const count = toggleCount(options);\n if (options.hidden) {\n hidden.clear();\n for (const i of options.hidden)\n if (Number.isInteger(i) && i >= 0 && i < count) hidden.add(i);\n } else for (const i of [...hidden]) if (i >= count) hidden.delete(i);\n };\n syncHidden();\n const sorted = (set: ReadonlySet<number>) => [...set].sort((a, b) => a - b);\n let entered = false;\n let entryStart: number | null = null;\n let update: { from: Map<string, number>; start: number | null } | null = null;\n let lastT = 1;\n\n const animated = () => options.animation !== false && !reducedMotion();\n\n /** Values currently on screen */\n const displayed = () => {\n const targets = shapeValues(options, hidden);\n return update && lastT < 1\n ? blendValues(update.from, targets, lastT)\n : targets;\n };\n\n const transition = (mutate: () => void) => {\n const from = displayed();\n mutate();\n if (!animated()) {\n update = null;\n entered = true;\n return;\n }\n if (!sameValues(from, shapeValues(options, hidden))) {\n update = { from, start: null };\n lastT = 0;\n }\n };\n\n return {\n get options() {\n return options;\n },\n hidden,\n setOptions(next) {\n if (next.type !== options.type) {\n options = next;\n hidden.clear();\n syncHidden();\n entered = false;\n entryStart = null;\n update = null;\n lastT = 1;\n return;\n }\n transition(() => {\n options = next;\n syncHidden();\n });\n },\n toggle(index) {\n if (!(Number.isInteger(index) && index >= 0)) return null;\n if (index >= toggleCount(options)) return null;\n const proposed = new Set(hidden);\n const nowHidden = !proposed.has(index);\n if (nowHidden) proposed.add(index);\n else proposed.delete(index);\n if (!options.hidden)\n transition(() => {\n if (nowHidden) hidden.add(index);\n else hidden.delete(index);\n });\n return { index, hidden: nowHidden, hiddenIndexes: sorted(proposed) };\n },\n hiddenIndexes: () => sorted(hidden),\n frame(time, input) {\n let enter = 1;\n if (!entered) {\n if (!animated()) entered = true;\n else {\n if (entryStart === null) entryStart = time;\n const p = (time - entryStart) / ENTER_MS;\n enter = easeOutCubic(p);\n if (p >= 1) {\n entered = true;\n enter = 1;\n }\n }\n }\n let t = 1;\n if (update) {\n if (!animated()) update = null;\n else {\n if (update.start === null) update.start = time;\n const p = (time - update.start) / UPDATE_MS;\n t = p >= 1 ? 1 : easeOutCubic(p);\n }\n }\n lastT = t;\n const scene = layoutShapeScene({\n ...input,\n options,\n hidden,\n enter,\n from: update?.from ?? null,\n t,\n });\n if (update && t >= 1) update = null;\n return { scene, animating: !entered || update !== null };\n },\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { ShapeLayoutInput } from './layout.cjs';
2
+ import { ShapeScene } from './scene.cjs';
3
+ import { ShapeChartOptions, ShapeToggleEvent } from './types.cjs';
4
+ /** Duration of the entry animation, ms */
5
+ export declare const ENTER_MS = 600;
6
+ /** Duration of the update animation, ms */
7
+ export declare const UPDATE_MS = 400;
8
+ export declare const now: () => number;
9
+ /** Whether the user prefers reduced motion (false without `matchMedia`) */
10
+ export declare const prefersReducedMotion: () => boolean;
11
+ export type ShapeFrameInput = Omit<ShapeLayoutInput, "options" | "hidden" | "enter" | "from" | "t">;
12
+ export interface ShapeRuntime {
13
+ readonly options: ShapeChartOptions;
14
+ readonly hidden: ReadonlySet<number>;
15
+ setOptions(options: ShapeChartOptions): void;
16
+ /**
17
+ * Hides / shows an entry (only proposes it when `options.hidden` controls
18
+ * the state); null when the index is out of range
19
+ */
20
+ toggle(index: number): ShapeToggleEvent | null;
21
+ /** Hidden indexes, ascending */
22
+ hiddenIndexes(): number[];
23
+ /** Lays the scene out at time `time`; `animating` asks for another frame */
24
+ frame(time: number, input: ShapeFrameInput): {
25
+ scene: ShapeScene;
26
+ animating: boolean;
27
+ };
28
+ }
29
+ export declare const createShapeRuntime: (initial: ShapeChartOptions, reducedMotion?: () => boolean) => ShapeRuntime;
@@ -0,0 +1,29 @@
1
+ import { ShapeLayoutInput } from './layout.js';
2
+ import { ShapeScene } from './scene.js';
3
+ import { ShapeChartOptions, ShapeToggleEvent } from './types.js';
4
+ /** Duration of the entry animation, ms */
5
+ export declare const ENTER_MS = 600;
6
+ /** Duration of the update animation, ms */
7
+ export declare const UPDATE_MS = 400;
8
+ export declare const now: () => number;
9
+ /** Whether the user prefers reduced motion (false without `matchMedia`) */
10
+ export declare const prefersReducedMotion: () => boolean;
11
+ export type ShapeFrameInput = Omit<ShapeLayoutInput, "options" | "hidden" | "enter" | "from" | "t">;
12
+ export interface ShapeRuntime {
13
+ readonly options: ShapeChartOptions;
14
+ readonly hidden: ReadonlySet<number>;
15
+ setOptions(options: ShapeChartOptions): void;
16
+ /**
17
+ * Hides / shows an entry (only proposes it when `options.hidden` controls
18
+ * the state); null when the index is out of range
19
+ */
20
+ toggle(index: number): ShapeToggleEvent | null;
21
+ /** Hidden indexes, ascending */
22
+ hiddenIndexes(): number[];
23
+ /** Lays the scene out at time `time`; `animating` asks for another frame */
24
+ frame(time: number, input: ShapeFrameInput): {
25
+ scene: ShapeScene;
26
+ animating: boolean;
27
+ };
28
+ }
29
+ export declare const createShapeRuntime: (initial: ShapeChartOptions, reducedMotion?: () => boolean) => ShapeRuntime;
@@ -0,0 +1,97 @@
1
+ import { easeOutCubic as e } from "./scene.js";
2
+ import { blendValues as t, layoutShapeScene as n, sameValues as r, shapeValues as i, toggleCount as a } from "./layout.js";
3
+ var o = () => typeof performance < "u" && typeof performance.now == "function" ? performance.now() : Date.now(), s = () => {
4
+ let e = globalThis;
5
+ try {
6
+ return !!e.matchMedia?.("(prefers-reduced-motion: reduce)")?.matches;
7
+ } catch {
8
+ return !1;
9
+ }
10
+ }, c = (o, c = s) => {
11
+ let l = o, u = /* @__PURE__ */ new Set(), d = () => {
12
+ let e = a(l);
13
+ if (l.hidden) {
14
+ u.clear();
15
+ for (let t of l.hidden) Number.isInteger(t) && t >= 0 && t < e && u.add(t);
16
+ } else for (let t of [...u]) t >= e && u.delete(t);
17
+ };
18
+ d();
19
+ let f = (e) => [...e].sort((e, t) => e - t), p = !1, m = null, h = null, g = 1, _ = () => l.animation !== !1 && !c(), v = () => {
20
+ let e = i(l, u);
21
+ return h && g < 1 ? t(h.from, e, g) : e;
22
+ }, y = (e) => {
23
+ let t = v();
24
+ if (e(), !_()) {
25
+ h = null, p = !0;
26
+ return;
27
+ }
28
+ r(t, i(l, u)) || (h = {
29
+ from: t,
30
+ start: null
31
+ }, g = 0);
32
+ };
33
+ return {
34
+ get options() {
35
+ return l;
36
+ },
37
+ hidden: u,
38
+ setOptions(e) {
39
+ if (e.type !== l.type) {
40
+ l = e, u.clear(), d(), p = !1, m = null, h = null, g = 1;
41
+ return;
42
+ }
43
+ y(() => {
44
+ l = e, d();
45
+ });
46
+ },
47
+ toggle(e) {
48
+ if (!(Number.isInteger(e) && e >= 0) || e >= a(l)) return null;
49
+ let t = new Set(u), n = !t.has(e);
50
+ return n ? t.add(e) : t.delete(e), l.hidden || y(() => {
51
+ n ? u.add(e) : u.delete(e);
52
+ }), {
53
+ index: e,
54
+ hidden: n,
55
+ hiddenIndexes: f(t)
56
+ };
57
+ },
58
+ hiddenIndexes: () => f(u),
59
+ frame(t, r) {
60
+ let i = 1;
61
+ if (!p) {
62
+ if (!_()) p = !0;
63
+ else {
64
+ m === null && (m = t);
65
+ let n = (t - m) / 600;
66
+ i = e(n), n >= 1 && (p = !0, i = 1);
67
+ }
68
+ }
69
+ let a = 1;
70
+ if (h) {
71
+ if (!_()) h = null;
72
+ else {
73
+ h.start === null && (h.start = t);
74
+ let n = (t - h.start) / 400;
75
+ a = n >= 1 ? 1 : e(n);
76
+ }
77
+ }
78
+ g = a;
79
+ let o = n({
80
+ ...r,
81
+ options: l,
82
+ hidden: u,
83
+ enter: i,
84
+ from: h?.from ?? null,
85
+ t: a
86
+ });
87
+ return h && a >= 1 && (h = null), {
88
+ scene: o,
89
+ animating: !p || h !== null
90
+ };
91
+ }
92
+ };
93
+ };
94
+ //#endregion
95
+ export { c as createShapeRuntime, o as now, s as prefersReducedMotion };
96
+
97
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","names":["now","prefersReducedMotion","g","createShapeRuntime","options","initial","hidden","syncHidden","count","toggleCount","i","sorted","set","a","b","entered","entryStart","update","lastT","animated","reducedMotion","displayed","targets","shapeValues","blendValues","transition","from","mutate","sameValues","next","index","proposed","nowHidden","enter","time","p","easeOutCubic","t","scene","layoutShapeScene","input"],"sources":["../../../../../charts/src/engine/shapes/runtime.ts"],"sourcesContent":["// Animation and visibility state shared by the DOM and canvas hosts: entry\n// animation, interpolation from the displayed values on updates / toggles.\n\nimport {\n blendValues,\n layoutShapeScene,\n sameValues,\n shapeValues,\n toggleCount,\n type ShapeLayoutInput,\n} from \"./layout\";\nimport { easeOutCubic, type ShapeScene } from \"./scene\";\nimport type { ShapeChartOptions, ShapeToggleEvent } from \"./types\";\n\n/** Duration of the entry animation, ms */\nexport const ENTER_MS = 600;\n/** Duration of the update animation, ms */\nexport const UPDATE_MS = 400;\n\nexport const now = () =>\n typeof performance !== \"undefined\" && typeof performance.now === \"function\"\n ? performance.now()\n : Date.now();\n\n/** Whether the user prefers reduced motion (false without `matchMedia`) */\nexport const prefersReducedMotion = () => {\n const g = globalThis as {\n matchMedia?: (query: string) => { matches: boolean } | null;\n };\n try {\n return !!g.matchMedia?.(\"(prefers-reduced-motion: reduce)\")?.matches;\n } catch {\n return false;\n }\n};\n\nexport type ShapeFrameInput = Omit<\n ShapeLayoutInput,\n \"options\" | \"hidden\" | \"enter\" | \"from\" | \"t\"\n>;\n\nexport interface ShapeRuntime {\n readonly options: ShapeChartOptions;\n readonly hidden: ReadonlySet<number>;\n setOptions(options: ShapeChartOptions): void;\n /**\n * Hides / shows an entry (only proposes it when `options.hidden` controls\n * the state); null when the index is out of range\n */\n toggle(index: number): ShapeToggleEvent | null;\n /** Hidden indexes, ascending */\n hiddenIndexes(): number[];\n /** Lays the scene out at time `time`; `animating` asks for another frame */\n frame(\n time: number,\n input: ShapeFrameInput,\n ): { scene: ShapeScene; animating: boolean };\n}\n\nexport const createShapeRuntime = (\n initial: ShapeChartOptions,\n reducedMotion: () => boolean = prefersReducedMotion,\n): ShapeRuntime => {\n let options = initial;\n const hidden = new Set<number>();\n /** Replaces the hidden set by the controlled `hidden` option (if any) */\n const syncHidden = () => {\n const count = toggleCount(options);\n if (options.hidden) {\n hidden.clear();\n for (const i of options.hidden)\n if (Number.isInteger(i) && i >= 0 && i < count) hidden.add(i);\n } else for (const i of [...hidden]) if (i >= count) hidden.delete(i);\n };\n syncHidden();\n const sorted = (set: ReadonlySet<number>) => [...set].sort((a, b) => a - b);\n let entered = false;\n let entryStart: number | null = null;\n let update: { from: Map<string, number>; start: number | null } | null = null;\n let lastT = 1;\n\n const animated = () => options.animation !== false && !reducedMotion();\n\n /** Values currently on screen */\n const displayed = () => {\n const targets = shapeValues(options, hidden);\n return update && lastT < 1\n ? blendValues(update.from, targets, lastT)\n : targets;\n };\n\n const transition = (mutate: () => void) => {\n const from = displayed();\n mutate();\n if (!animated()) {\n update = null;\n entered = true;\n return;\n }\n if (!sameValues(from, shapeValues(options, hidden))) {\n update = { from, start: null };\n lastT = 0;\n }\n };\n\n return {\n get options() {\n return options;\n },\n hidden,\n setOptions(next) {\n if (next.type !== options.type) {\n options = next;\n hidden.clear();\n syncHidden();\n entered = false;\n entryStart = null;\n update = null;\n lastT = 1;\n return;\n }\n transition(() => {\n options = next;\n syncHidden();\n });\n },\n toggle(index) {\n if (!(Number.isInteger(index) && index >= 0)) return null;\n if (index >= toggleCount(options)) return null;\n const proposed = new Set(hidden);\n const nowHidden = !proposed.has(index);\n if (nowHidden) proposed.add(index);\n else proposed.delete(index);\n if (!options.hidden)\n transition(() => {\n if (nowHidden) hidden.add(index);\n else hidden.delete(index);\n });\n return { index, hidden: nowHidden, hiddenIndexes: sorted(proposed) };\n },\n hiddenIndexes: () => sorted(hidden),\n frame(time, input) {\n let enter = 1;\n if (!entered) {\n if (!animated()) entered = true;\n else {\n if (entryStart === null) entryStart = time;\n const p = (time - entryStart) / ENTER_MS;\n enter = easeOutCubic(p);\n if (p >= 1) {\n entered = true;\n enter = 1;\n }\n }\n }\n let t = 1;\n if (update) {\n if (!animated()) update = null;\n else {\n if (update.start === null) update.start = time;\n const p = (time - update.start) / UPDATE_MS;\n t = p >= 1 ? 1 : easeOutCubic(p);\n }\n }\n lastT = t;\n const scene = layoutShapeScene({\n ...input,\n options,\n hidden,\n enter,\n from: update?.from ?? null,\n t,\n });\n if (update && t >= 1) update = null;\n return { scene, animating: !entered || update !== null };\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("../format.cjs");var r=Math.PI*2,i=(e,t)=>{let n=/(\d+(?:\.\d+)?)px/.exec(t);return e.length*(n?Number(n[1]):12)*.6},a=(e,t,n)=>e<t?t:e>n?n:e,o=e=>typeof e==`number`&&Number.isFinite(e)&&e>0?e:0,s=(e,t=0)=>typeof e==`number`&&Number.isFinite(e)?e:t,c=e=>{let t=0;for(let n of e)t+=n;return t},l=e=>1-(1-a(e,0,1))**3,u=e=>n.formatCompact(e),d=e=>Number.isFinite(e)?`${(e*100).toFixed(1)}%`:`–`,f=(e,t)=>{let n=t?.top??8,r=t?.right??8,i=t?.bottom??8,a=t?.left??8;return{x:e.x+a,y:e.y+n,width:Math.max(0,e.width-a-r),height:Math.max(0,e.height-n-i)}},p=(e,t,n,r)=>{if(r(e,n)<=t)return e;if(r(`…`,n)>t)return``;let i=0,a=e.length;for(;i<a;){let o=i+a+1>>1;r(e.slice(0,o)+`…`,n)<=t?i=o:a=o-1}return i?e.slice(0,i).trimEnd()+`…`:``},m=e=>{let t=new Map;return e.map(e=>{let n=(t.get(e)??0)+1;return t.set(e,n),n===1?e:`${e}#${n}`})},h=[1,1,1,.96],g=[15/255,23/255,42/255,.88],_=e=>e<=.04045?e/12.92:((e+.055)/1.055)**2.4,v=e=>.2126*_(e[0])+.7152*_(e[1])+.0722*_(e[2]),y=(e,t)=>{let n=a(e[3],0,1);return[e[0]*n+t[0]*(1-n),e[1]*n+t[1]*(1-n),e[2]*n+t[2]*(1-n),1]},b=(e,t)=>{let n=v(y(e,t)),r=v(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)},x=[1,1,1,1],S=(t,n=x)=>{let r=y(t,y(n,x)),i=b(h,r),a=b(g,r);return i>=a?{ink:h,css:e.toCss(h),contrast:i}:{ink:g,css:e.toCss(g),contrast:a}},C=(e,t)=>S(e,t).css,w=(t,n=4.5,r=.3)=>{let i=S(t);if(i.contrast>=n)return t;let a=i.ink===h?[0,0,0,t[3]]:[1,1,1,t[3]];for(let o=.04;o<=r+1e-9;o+=.04){let r=e.mix(t,a,o);if(i=S(r),i.contrast>=n)return r}return e.mix(t,a,r)},T=(t,n,r)=>n?t.resolve?t.resolve(n,r):e.parseColor(n)??r:r,E=n=>{let{area:i,theme:a}=n,o=i.x+i.width/2,s=i.y+i.height/2,c=Math.max(0,Math.min(i.width,i.height)/2-6);return{nodes:[{kind:`sector`,cx:o,cy:s,r0:c*.66,r1:c,a0:0,a1:r,pad:0,corner:0,fill:e.toCss(a.grid,.8)},{kind:`text`,x:o,y:s,text:`No data`,font:t.font(a,12),color:e.toCss(a.textMuted),align:`center`,baseline:`middle`}],items:[],dim:1,empty:!0}};exports.TAU=r,exports.clamp=a,exports.contrastRatio=b,exports.defaultFormat=u,exports.easeOutCubic=l,exports.ellipsize=p,exports.emptyLayout=E,exports.estimateText=i,exports.finite=s,exports.formatPercent=d,exports.inkOn=S,exports.inset=f,exports.over=y,exports.positive=o,exports.readableFill=w,exports.relativeLuminance=v,exports.resolveWith=T,exports.sum=c,exports.textOn=C,exports.uniqueKeys=m;
2
+ //# sourceMappingURL=scene.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.cjs","names":["formatCompact","toCss","mix","parseColor","font","require_color","require_overlay","require_format","TAU","estimateText","size","f","text","clamp","v","lo","hi","positive","finite","fallback","sum","s","values","easeOutCubic","t","defaultFormat","value","formatPercent","p","inset","top","padding","right","bottom","left","rect","ellipsize","measure","font","max","mid","uniqueKeys","seen","names","name","LIGHT_INK","DARK_INK","channel","relativeLuminance","c","over","a","contrastRatio","ink","fill","b","WHITE","inkOn","solid","backdrop","light","dark","textOn","readableFill","best","target","toward","limit","next","resolveWith","css","theme","emptyLayout","cx","area","cy","r1"],"sources":["../../../../../charts/src/engine/shapes/scene.ts"],"sourcesContent":["// Drawable scene of a shape chart: resolved geometry, colors and texts,\n// produced by the (DOM-free) layouts and consumed by draw / hit testing.\n\nimport { mix, parseColor, toCss, type Rgba } from \"../color\";\nimport { formatCompact } from \"../format\";\nimport { font } from \"../overlay\";\nimport type { ChartTheme } from \"../theme\";\nimport type { ChartPadding } from \"../types\";\nimport type { ShapeChartType } from \"./types\";\n\nexport const TAU = Math.PI * 2;\n\n/** Rectangle in CSS pixels */\nexport interface ShapeRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface NodeBase {\n /** Index of the item the node belongs to (hover, dimming); none for decorations */\n hit?: number;\n /** Opacity multiplier */\n alpha?: number;\n /** Offset applied while the node's item is hovered (pie slices pop out) */\n shift?: [number, number];\n}\n\n/** Annular sector (pie slice, donut segment, ring) */\nexport interface SectorNode extends NodeBase {\n kind: \"sector\";\n cx: number;\n cy: number;\n r0: number;\n r1: number;\n /** Canvas angles (radians, clockwise from 3 o'clock) */\n a0: number;\n a1: number;\n /** Gap with the neighbours, in pixels */\n pad: number;\n /** Corner radius, in pixels */\n corner: number;\n fill: string;\n}\n\n/** Polygon (radar grid / series, funnel stage); `hole` is cut out */\nexport interface PolygonNode extends NodeBase {\n kind: \"polygon\";\n /** Flat x, y list */\n points: number[];\n hole?: number[];\n fill?: string;\n stroke?: string;\n lineWidth?: number;\n /** Corner radius, in pixels */\n radius?: number;\n /** Fill / stroke width when hovered */\n hoverFill?: string;\n hoverLineWidth?: number;\n /** Lightens the shape when hovered */\n brighten?: boolean;\n}\n\nexport interface RectNode extends NodeBase {\n kind: \"rect\";\n x: number;\n y: number;\n width: number;\n height: number;\n radius: number;\n fill: string;\n brighten?: boolean;\n}\n\n/** Stroked arc (gauge track / value) */\nexport interface ArcNode extends NodeBase {\n kind: \"arc\";\n cx: number;\n cy: number;\n r: number;\n a0: number;\n a1: number;\n width: number;\n color: string;\n cap: \"round\" | \"butt\";\n}\n\n/** Dot; without fill nor stroke it is only a hit area */\nexport interface CircleNode extends NodeBase {\n kind: \"circle\";\n cx: number;\n cy: number;\n r: number;\n fill?: string;\n stroke?: string;\n lineWidth?: number;\n /** Radar: indicator of the vertex */\n indicator?: number;\n /** Radius and halo color when the vertex is hovered */\n hoverR?: number;\n halo?: string;\n}\n\nexport interface LineNode extends NodeBase {\n kind: \"line\";\n points: number[];\n color: string;\n width: number;\n dash?: number[];\n}\n\nexport interface TextNode extends NodeBase {\n kind: \"text\";\n x: number;\n y: number;\n text: string;\n font: string;\n color: string;\n align: \"left\" | \"center\" | \"right\";\n baseline: \"top\" | \"middle\" | \"bottom\" | \"alphabetic\";\n /** Radar: indicator of the label */\n indicator?: number;\n hoverColor?: string;\n hoverFont?: string;\n}\n\n/** Radar: dashed guide from the center to the hovered indicator */\nexport interface GuideNode extends NodeBase {\n kind: \"guide\";\n cx: number;\n cy: number;\n /** End of each spoke */\n ends: [number, number][];\n color: string;\n}\n\nexport type ShapeNode =\n | SectorNode\n | PolygonNode\n | RectNode\n | ArcNode\n | CircleNode\n | LineNode\n | TextNode\n | GuideNode;\n\n/** A row of the default tooltip */\nexport interface ShapeTooltipRow {\n name: string;\n value: string;\n color?: string;\n strong?: boolean;\n}\n\n/** Something the pointer / keyboard can focus */\nexport interface ShapeItem {\n index: number;\n name: string;\n value: number;\n percent: number;\n /** `percent` formatted for screen readers (`percentFormat`) */\n share?: string;\n color: string;\n path?: string[];\n /** Anchor of the tooltip when focused with the keyboard */\n x: number;\n y: number;\n /** Rows of the default tooltip */\n rows: ShapeTooltipRow[];\n /** Radar: one entry per indicator */\n indicators?: {\n name: string;\n value: number;\n percent: number;\n x: number;\n y: number;\n }[];\n}\n\n/** What is hovered: an item (and a radar indicator) */\nexport interface ShapeHover {\n index: number;\n indicator?: number;\n}\n\nexport interface ShapeLegendEntry {\n /** Index passed to `toggle` */\n index: number;\n name: string;\n color: string;\n hidden: boolean;\n}\n\nexport interface ShapeScene {\n type: ShapeChartType;\n /** Size of the whole drawing */\n width: number;\n height: number;\n nodes: ShapeNode[];\n /** Focusable items, in keyboard order */\n items: ShapeItem[];\n /** Opacity of the other marks while one is hovered */\n dim: number;\n /** Entry animation of funnels / treemaps: fade and scale around a point */\n enter?: { alpha: number; scale: number; cx: number; cy: number };\n /** Radar geometry used by hit testing (and to keep the tooltip off the labels) */\n radar?: {\n cx: number;\n cy: number;\n radius: number;\n angles: number[];\n series: { index: number; points: number[] }[];\n /** Boxes of the indicator labels */\n labels?: ShapeRect[];\n };\n /** No data to draw (placeholder shown) */\n empty: boolean;\n}\n\n/** Measures a text in a CSS font */\nexport type MeasureText = (text: string, font: string) => number;\n\n/** Approximate width of a text without a canvas (tests, SSR) */\nexport const estimateText: MeasureText = (text, f) => {\n const size = /(\\d+(?:\\.\\d+)?)px/.exec(f);\n return text.length * (size ? Number(size[1]) : 12) * 0.6;\n};\n\n/** What the layouts of every type get */\nexport interface LayoutContext {\n theme: ChartTheme;\n measure: MeasureText;\n hidden: ReadonlySet<number>;\n /** Entry progress, eased (1 when done) */\n enter: number;\n /** Displayed (animated) value of a key */\n value(key: string, target: number): number;\n format(value: number): string;\n /** Formats a share (0-1): `percentFormat` or one decimal */\n percent(share: number): string;\n /** Color of the `i`-th mark (custom `color` or the palette) */\n color(css: string | undefined, i: number): Rgba;\n /** Drawing area, padding excluded */\n area: ShapeRect;\n}\n\nexport type LayoutResult = Omit<ShapeScene, \"type\" | \"width\" | \"height\">;\n\nexport const clamp = (v: number, lo: number, hi: number) =>\n v < lo ? lo : v > hi ? hi : v;\n\n/** Non-negative finite number */\nexport const positive = (v: number | undefined) =>\n typeof v === \"number\" && Number.isFinite(v) && v > 0 ? v : 0;\n\nexport const finite = (v: number | undefined, fallback = 0) =>\n typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n\nexport const sum = (values: readonly number[]) => {\n let s = 0;\n for (const v of values) s += v;\n return s;\n};\n\nexport const easeOutCubic = (t: number) => 1 - Math.pow(1 - clamp(t, 0, 1), 3);\n\nexport const defaultFormat = (value: number) => formatCompact(value);\n\n/** Share 0-1 as a percent with one decimal: `0.4` -> `40.0%` */\nexport const formatPercent = (p: number) =>\n Number.isFinite(p) ? `${(p * 100).toFixed(1)}%` : \"–\";\n\nexport const inset = (rect: ShapeRect, padding?: ChartPadding): ShapeRect => {\n const top = padding?.top ?? 8;\n const right = padding?.right ?? 8;\n const bottom = padding?.bottom ?? 8;\n const left = padding?.left ?? 8;\n return {\n x: rect.x + left,\n y: rect.y + top,\n width: Math.max(0, rect.width - left - right),\n height: Math.max(0, rect.height - top - bottom),\n };\n};\n\n/** Shortens a text with an ellipsis so it fits in `max` pixels (\"\" if nothing fits) */\nexport const ellipsize = (\n text: string,\n max: number,\n font: string,\n measure: MeasureText,\n): string => {\n if (measure(text, font) <= max) return text;\n if (measure(\"…\", font) > max) return \"\";\n let lo = 0;\n let hi = text.length;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (measure(text.slice(0, mid) + \"…\", font) <= max) lo = mid;\n else hi = mid - 1;\n }\n return lo ? text.slice(0, lo).trimEnd() + \"…\" : \"\";\n};\n\n/** Stable keys of named values: the name, `name#2` for duplicates */\nexport const uniqueKeys = (names: readonly string[]) => {\n const seen = new Map<string, number>();\n return names.map((name) => {\n const n = (seen.get(name) ?? 0) + 1;\n seen.set(name, n);\n return n === 1 ? name : `${name}#${n}`;\n });\n};\n\nconst LIGHT_INK: Rgba = [1, 1, 1, 0.96];\nconst DARK_INK: Rgba = [15 / 255, 23 / 255, 42 / 255, 0.88];\n\nconst channel = (v: number) =>\n v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);\n\n/** WCAG relative luminance of an opaque color */\nexport const relativeLuminance = (c: Rgba) =>\n 0.2126 * channel(c[0]) + 0.7152 * channel(c[1]) + 0.0722 * channel(c[2]);\n\n/** `top` composited over the opaque `bottom` */\nexport const over = (top: Rgba, bottom: Rgba): Rgba => {\n const a = clamp(top[3], 0, 1);\n return [\n top[0] * a + bottom[0] * (1 - a),\n top[1] * a + bottom[1] * (1 - a),\n top[2] * a + bottom[2] * (1 - a),\n 1,\n ];\n};\n\n/** WCAG contrast ratio (1-21) of `ink` drawn on the opaque `fill` */\nexport const contrastRatio = (ink: Rgba, fill: Rgba) => {\n const a = relativeLuminance(over(ink, fill));\n const b = relativeLuminance(fill);\n return (Math.max(a, b) + 0.05) / (Math.min(a, b) + 0.05);\n};\n\nconst WHITE: Rgba = [1, 1, 1, 1];\n\n/** Light or dark ink, whichever contrasts more with the fill, and its contrast */\nexport const inkOn = (\n fill: Rgba,\n backdrop: Rgba = WHITE,\n): { ink: Rgba; css: string; contrast: number } => {\n const solid = over(fill, over(backdrop, WHITE));\n const light = contrastRatio(LIGHT_INK, solid);\n const dark = contrastRatio(DARK_INK, solid);\n return light >= dark\n ? { ink: LIGHT_INK, css: toCss(LIGHT_INK), contrast: light }\n : { ink: DARK_INK, css: toCss(DARK_INK), contrast: dark };\n};\n\n/** Readable text color on a fill (WCAG contrast) */\nexport const textOn = (fill: Rgba, backdrop?: Rgba) =>\n inkOn(fill, backdrop).css;\n\n/**\n * Fill adjusted so that its best ink reaches `target` contrast: darkened\n * under white text, lightened under dark text (at most `limit` of the way)\n */\nexport const readableFill = (fill: Rgba, target = 4.5, limit = 0.3): Rgba => {\n let best = inkOn(fill);\n if (best.contrast >= target) return fill;\n const toward: Rgba =\n best.ink === LIGHT_INK ? [0, 0, 0, fill[3]] : [1, 1, 1, fill[3]];\n for (let t = 0.04; t <= limit + 1e-9; t += 0.04) {\n const next = mix(fill, toward, t);\n best = inkOn(next);\n if (best.contrast >= target) return next;\n }\n return mix(fill, toward, limit);\n};\n\n/** Resolves a custom color with the theme resolver (static parsing otherwise) */\nexport const resolveWith = (\n theme: ChartTheme,\n css: string | undefined,\n fallback: Rgba,\n): Rgba => {\n if (!css) return fallback;\n return theme.resolve\n ? theme.resolve(css, fallback)\n : (parseColor(css) ?? fallback);\n};\n\n/** Placeholder of a chart without data: a muted ring and \"No data\" */\nexport const emptyLayout = (c: LayoutContext): LayoutResult => {\n const { area, theme } = c;\n const cx = area.x + area.width / 2;\n const cy = area.y + area.height / 2;\n const r1 = Math.max(0, Math.min(area.width, area.height) / 2 - 6);\n return {\n nodes: [\n {\n kind: \"sector\",\n cx,\n cy,\n r0: r1 * 0.66,\n r1,\n a0: 0,\n a1: TAU,\n pad: 0,\n corner: 0,\n fill: toCss(theme.grid, 0.8),\n },\n {\n kind: \"text\",\n x: cx,\n y: cy,\n text: \"No data\",\n font: font(theme, 12),\n color: toCss(theme.textMuted),\n align: \"center\",\n baseline: \"middle\",\n },\n ],\n items: [],\n dim: 1,\n empty: true,\n };\n};\n"],"mappings":"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"}
@@ -0,0 +1,257 @@
1
+ import { Rgba } from '../color.cjs';
2
+ import { ChartTheme } from '../theme.cjs';
3
+ import { ChartPadding } from '../types.cjs';
4
+ import { ShapeChartType } from './types.cjs';
5
+ export declare const TAU: number;
6
+ /** Rectangle in CSS pixels */
7
+ export interface ShapeRect {
8
+ x: number;
9
+ y: number;
10
+ width: number;
11
+ height: number;
12
+ }
13
+ interface NodeBase {
14
+ /** Index of the item the node belongs to (hover, dimming); none for decorations */
15
+ hit?: number;
16
+ /** Opacity multiplier */
17
+ alpha?: number;
18
+ /** Offset applied while the node's item is hovered (pie slices pop out) */
19
+ shift?: [number, number];
20
+ }
21
+ /** Annular sector (pie slice, donut segment, ring) */
22
+ export interface SectorNode extends NodeBase {
23
+ kind: "sector";
24
+ cx: number;
25
+ cy: number;
26
+ r0: number;
27
+ r1: number;
28
+ /** Canvas angles (radians, clockwise from 3 o'clock) */
29
+ a0: number;
30
+ a1: number;
31
+ /** Gap with the neighbours, in pixels */
32
+ pad: number;
33
+ /** Corner radius, in pixels */
34
+ corner: number;
35
+ fill: string;
36
+ }
37
+ /** Polygon (radar grid / series, funnel stage); `hole` is cut out */
38
+ export interface PolygonNode extends NodeBase {
39
+ kind: "polygon";
40
+ /** Flat x, y list */
41
+ points: number[];
42
+ hole?: number[];
43
+ fill?: string;
44
+ stroke?: string;
45
+ lineWidth?: number;
46
+ /** Corner radius, in pixels */
47
+ radius?: number;
48
+ /** Fill / stroke width when hovered */
49
+ hoverFill?: string;
50
+ hoverLineWidth?: number;
51
+ /** Lightens the shape when hovered */
52
+ brighten?: boolean;
53
+ }
54
+ export interface RectNode extends NodeBase {
55
+ kind: "rect";
56
+ x: number;
57
+ y: number;
58
+ width: number;
59
+ height: number;
60
+ radius: number;
61
+ fill: string;
62
+ brighten?: boolean;
63
+ }
64
+ /** Stroked arc (gauge track / value) */
65
+ export interface ArcNode extends NodeBase {
66
+ kind: "arc";
67
+ cx: number;
68
+ cy: number;
69
+ r: number;
70
+ a0: number;
71
+ a1: number;
72
+ width: number;
73
+ color: string;
74
+ cap: "round" | "butt";
75
+ }
76
+ /** Dot; without fill nor stroke it is only a hit area */
77
+ export interface CircleNode extends NodeBase {
78
+ kind: "circle";
79
+ cx: number;
80
+ cy: number;
81
+ r: number;
82
+ fill?: string;
83
+ stroke?: string;
84
+ lineWidth?: number;
85
+ /** Radar: indicator of the vertex */
86
+ indicator?: number;
87
+ /** Radius and halo color when the vertex is hovered */
88
+ hoverR?: number;
89
+ halo?: string;
90
+ }
91
+ export interface LineNode extends NodeBase {
92
+ kind: "line";
93
+ points: number[];
94
+ color: string;
95
+ width: number;
96
+ dash?: number[];
97
+ }
98
+ export interface TextNode extends NodeBase {
99
+ kind: "text";
100
+ x: number;
101
+ y: number;
102
+ text: string;
103
+ font: string;
104
+ color: string;
105
+ align: "left" | "center" | "right";
106
+ baseline: "top" | "middle" | "bottom" | "alphabetic";
107
+ /** Radar: indicator of the label */
108
+ indicator?: number;
109
+ hoverColor?: string;
110
+ hoverFont?: string;
111
+ }
112
+ /** Radar: dashed guide from the center to the hovered indicator */
113
+ export interface GuideNode extends NodeBase {
114
+ kind: "guide";
115
+ cx: number;
116
+ cy: number;
117
+ /** End of each spoke */
118
+ ends: [number, number][];
119
+ color: string;
120
+ }
121
+ export type ShapeNode = SectorNode | PolygonNode | RectNode | ArcNode | CircleNode | LineNode | TextNode | GuideNode;
122
+ /** A row of the default tooltip */
123
+ export interface ShapeTooltipRow {
124
+ name: string;
125
+ value: string;
126
+ color?: string;
127
+ strong?: boolean;
128
+ }
129
+ /** Something the pointer / keyboard can focus */
130
+ export interface ShapeItem {
131
+ index: number;
132
+ name: string;
133
+ value: number;
134
+ percent: number;
135
+ /** `percent` formatted for screen readers (`percentFormat`) */
136
+ share?: string;
137
+ color: string;
138
+ path?: string[];
139
+ /** Anchor of the tooltip when focused with the keyboard */
140
+ x: number;
141
+ y: number;
142
+ /** Rows of the default tooltip */
143
+ rows: ShapeTooltipRow[];
144
+ /** Radar: one entry per indicator */
145
+ indicators?: {
146
+ name: string;
147
+ value: number;
148
+ percent: number;
149
+ x: number;
150
+ y: number;
151
+ }[];
152
+ }
153
+ /** What is hovered: an item (and a radar indicator) */
154
+ export interface ShapeHover {
155
+ index: number;
156
+ indicator?: number;
157
+ }
158
+ export interface ShapeLegendEntry {
159
+ /** Index passed to `toggle` */
160
+ index: number;
161
+ name: string;
162
+ color: string;
163
+ hidden: boolean;
164
+ }
165
+ export interface ShapeScene {
166
+ type: ShapeChartType;
167
+ /** Size of the whole drawing */
168
+ width: number;
169
+ height: number;
170
+ nodes: ShapeNode[];
171
+ /** Focusable items, in keyboard order */
172
+ items: ShapeItem[];
173
+ /** Opacity of the other marks while one is hovered */
174
+ dim: number;
175
+ /** Entry animation of funnels / treemaps: fade and scale around a point */
176
+ enter?: {
177
+ alpha: number;
178
+ scale: number;
179
+ cx: number;
180
+ cy: number;
181
+ };
182
+ /** Radar geometry used by hit testing (and to keep the tooltip off the labels) */
183
+ radar?: {
184
+ cx: number;
185
+ cy: number;
186
+ radius: number;
187
+ angles: number[];
188
+ series: {
189
+ index: number;
190
+ points: number[];
191
+ }[];
192
+ /** Boxes of the indicator labels */
193
+ labels?: ShapeRect[];
194
+ };
195
+ /** No data to draw (placeholder shown) */
196
+ empty: boolean;
197
+ }
198
+ /** Measures a text in a CSS font */
199
+ export type MeasureText = (text: string, font: string) => number;
200
+ /** Approximate width of a text without a canvas (tests, SSR) */
201
+ export declare const estimateText: MeasureText;
202
+ /** What the layouts of every type get */
203
+ export interface LayoutContext {
204
+ theme: ChartTheme;
205
+ measure: MeasureText;
206
+ hidden: ReadonlySet<number>;
207
+ /** Entry progress, eased (1 when done) */
208
+ enter: number;
209
+ /** Displayed (animated) value of a key */
210
+ value(key: string, target: number): number;
211
+ format(value: number): string;
212
+ /** Formats a share (0-1): `percentFormat` or one decimal */
213
+ percent(share: number): string;
214
+ /** Color of the `i`-th mark (custom `color` or the palette) */
215
+ color(css: string | undefined, i: number): Rgba;
216
+ /** Drawing area, padding excluded */
217
+ area: ShapeRect;
218
+ }
219
+ export type LayoutResult = Omit<ShapeScene, "type" | "width" | "height">;
220
+ export declare const clamp: (v: number, lo: number, hi: number) => number;
221
+ /** Non-negative finite number */
222
+ export declare const positive: (v: number | undefined) => number;
223
+ export declare const finite: (v: number | undefined, fallback?: number) => number;
224
+ export declare const sum: (values: readonly number[]) => number;
225
+ export declare const easeOutCubic: (t: number) => number;
226
+ export declare const defaultFormat: (value: number) => string;
227
+ /** Share 0-1 as a percent with one decimal: `0.4` -> `40.0%` */
228
+ export declare const formatPercent: (p: number) => string;
229
+ export declare const inset: (rect: ShapeRect, padding?: ChartPadding) => ShapeRect;
230
+ /** Shortens a text with an ellipsis so it fits in `max` pixels ("" if nothing fits) */
231
+ export declare const ellipsize: (text: string, max: number, font: string, measure: MeasureText) => string;
232
+ /** Stable keys of named values: the name, `name#2` for duplicates */
233
+ export declare const uniqueKeys: (names: readonly string[]) => string[];
234
+ /** WCAG relative luminance of an opaque color */
235
+ export declare const relativeLuminance: (c: Rgba) => number;
236
+ /** `top` composited over the opaque `bottom` */
237
+ export declare const over: (top: Rgba, bottom: Rgba) => Rgba;
238
+ /** WCAG contrast ratio (1-21) of `ink` drawn on the opaque `fill` */
239
+ export declare const contrastRatio: (ink: Rgba, fill: Rgba) => number;
240
+ /** Light or dark ink, whichever contrasts more with the fill, and its contrast */
241
+ export declare const inkOn: (fill: Rgba, backdrop?: Rgba) => {
242
+ ink: Rgba;
243
+ css: string;
244
+ contrast: number;
245
+ };
246
+ /** Readable text color on a fill (WCAG contrast) */
247
+ export declare const textOn: (fill: Rgba, backdrop?: Rgba) => string;
248
+ /**
249
+ * Fill adjusted so that its best ink reaches `target` contrast: darkened
250
+ * under white text, lightened under dark text (at most `limit` of the way)
251
+ */
252
+ export declare const readableFill: (fill: Rgba, target?: number, limit?: number) => Rgba;
253
+ /** Resolves a custom color with the theme resolver (static parsing otherwise) */
254
+ export declare const resolveWith: (theme: ChartTheme, css: string | undefined, fallback: Rgba) => Rgba;
255
+ /** Placeholder of a chart without data: a muted ring and "No data" */
256
+ export declare const emptyLayout: (c: LayoutContext) => LayoutResult;
257
+ export {};