@react-x11/components 0.1.0 → 0.2.1

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 (788) hide show
  1. package/README.md +979 -21
  2. package/dist/ansi/cast.d.ts +48 -0
  3. package/dist/ansi/cast.d.ts.map +1 -0
  4. package/dist/ansi/cast.js +135 -0
  5. package/dist/ansi/cast.js.map +1 -0
  6. package/dist/ansi/index.d.ts +10 -0
  7. package/dist/ansi/index.d.ts.map +1 -0
  8. package/dist/ansi/index.js +27 -0
  9. package/dist/ansi/index.js.map +1 -0
  10. package/dist/ansi/palette.d.ts +79 -0
  11. package/dist/ansi/palette.d.ts.map +1 -0
  12. package/dist/ansi/palette.js +155 -0
  13. package/dist/ansi/palette.js.map +1 -0
  14. package/dist/ansi/parse.d.ts +114 -0
  15. package/dist/ansi/parse.d.ts.map +1 -0
  16. package/dist/ansi/parse.js +687 -0
  17. package/dist/ansi/parse.js.map +1 -0
  18. package/dist/ansi/sgr.d.ts +87 -0
  19. package/dist/ansi/sgr.d.ts.map +1 -0
  20. package/dist/ansi/sgr.js +302 -0
  21. package/dist/ansi/sgr.js.map +1 -0
  22. package/dist/ansi/utf8.d.ts +15 -0
  23. package/dist/ansi/utf8.d.ts.map +1 -0
  24. package/dist/ansi/utf8.js +82 -0
  25. package/dist/ansi/utf8.js.map +1 -0
  26. package/dist/calendar/Calendar.d.ts +136 -0
  27. package/dist/calendar/Calendar.d.ts.map +1 -0
  28. package/dist/calendar/Calendar.js +460 -0
  29. package/dist/calendar/Calendar.js.map +1 -0
  30. package/dist/calendar/DatePicker.d.ts +52 -0
  31. package/dist/calendar/DatePicker.d.ts.map +1 -0
  32. package/dist/calendar/DatePicker.js +257 -0
  33. package/dist/calendar/DatePicker.js.map +1 -0
  34. package/dist/calendar/dates.d.ts +90 -0
  35. package/dist/calendar/dates.d.ts.map +1 -0
  36. package/dist/calendar/dates.js +236 -0
  37. package/dist/calendar/dates.js.map +1 -0
  38. package/dist/calendar/index.d.ts +8 -0
  39. package/dist/calendar/index.d.ts.map +1 -0
  40. package/dist/calendar/index.js +15 -0
  41. package/dist/calendar/index.js.map +1 -0
  42. package/dist/charts/components.d.ts +141 -0
  43. package/dist/charts/components.d.ts.map +1 -0
  44. package/dist/charts/components.js +580 -0
  45. package/dist/charts/components.js.map +1 -0
  46. package/dist/charts/data.d.ts +198 -0
  47. package/dist/charts/data.d.ts.map +1 -0
  48. package/dist/charts/data.js +616 -0
  49. package/dist/charts/data.js.map +1 -0
  50. package/dist/charts/hx.d.ts +21 -0
  51. package/dist/charts/hx.d.ts.map +1 -0
  52. package/dist/charts/hx.js +15 -0
  53. package/dist/charts/hx.js.map +1 -0
  54. package/dist/charts/index.d.ts +27 -0
  55. package/dist/charts/index.d.ts.map +1 -0
  56. package/dist/charts/index.js +38 -0
  57. package/dist/charts/index.js.map +1 -0
  58. package/dist/charts/node.d.ts +96 -0
  59. package/dist/charts/node.d.ts.map +1 -0
  60. package/dist/charts/node.js +720 -0
  61. package/dist/charts/node.js.map +1 -0
  62. package/dist/charts/render.d.ts +153 -0
  63. package/dist/charts/render.d.ts.map +1 -0
  64. package/dist/charts/render.js +762 -0
  65. package/dist/charts/render.js.map +1 -0
  66. package/dist/charts/scale.d.ts +42 -0
  67. package/dist/charts/scale.d.ts.map +1 -0
  68. package/dist/charts/scale.js +173 -0
  69. package/dist/charts/scale.js.map +1 -0
  70. package/dist/charts/spec.d.ts +91 -0
  71. package/dist/charts/spec.d.ts.map +1 -0
  72. package/dist/charts/spec.js +33 -0
  73. package/dist/charts/spec.js.map +1 -0
  74. package/dist/charts/timers.d.ts +6 -0
  75. package/dist/charts/timers.d.ts.map +1 -0
  76. package/dist/charts/timers.js +14 -0
  77. package/dist/charts/timers.js.map +1 -0
  78. package/dist/code/hx.d.ts +24 -0
  79. package/dist/code/hx.d.ts.map +1 -0
  80. package/dist/code/hx.js +25 -0
  81. package/dist/code/hx.js.map +1 -0
  82. package/dist/code/index.d.ts +45 -0
  83. package/dist/code/index.d.ts.map +1 -0
  84. package/dist/code/index.js +93 -0
  85. package/dist/code/index.js.map +1 -0
  86. package/dist/code-editor/completion.d.ts +26 -0
  87. package/dist/code-editor/completion.d.ts.map +1 -0
  88. package/dist/code-editor/completion.js +129 -0
  89. package/dist/code-editor/completion.js.map +1 -0
  90. package/dist/code-editor/doc.d.ts +35 -0
  91. package/dist/code-editor/doc.d.ts.map +1 -0
  92. package/dist/code-editor/doc.js +162 -0
  93. package/dist/code-editor/doc.js.map +1 -0
  94. package/dist/code-editor/hx.d.ts +13 -0
  95. package/dist/code-editor/hx.d.ts.map +1 -0
  96. package/dist/code-editor/hx.js +10 -0
  97. package/dist/code-editor/hx.js.map +1 -0
  98. package/dist/code-editor/index.d.ts +88 -0
  99. package/dist/code-editor/index.d.ts.map +1 -0
  100. package/dist/code-editor/index.js +401 -0
  101. package/dist/code-editor/index.js.map +1 -0
  102. package/dist/code-editor/node.d.ts +343 -0
  103. package/dist/code-editor/node.d.ts.map +1 -0
  104. package/dist/code-editor/node.js +1521 -0
  105. package/dist/code-editor/node.js.map +1 -0
  106. package/dist/code-language/hljs.d.ts +47 -0
  107. package/dist/code-language/hljs.d.ts.map +1 -0
  108. package/dist/code-language/hljs.js +211 -0
  109. package/dist/code-language/hljs.js.map +1 -0
  110. package/dist/code-language/index.d.ts +22 -0
  111. package/dist/code-language/index.d.ts.map +1 -0
  112. package/dist/code-language/index.js +20 -0
  113. package/dist/code-language/index.js.map +1 -0
  114. package/dist/code-language/languages/glsl.d.ts +4 -0
  115. package/dist/code-language/languages/glsl.d.ts.map +1 -0
  116. package/dist/code-language/languages/glsl.js +99 -0
  117. package/dist/code-language/languages/glsl.js.map +1 -0
  118. package/dist/code-language/languages/javascript.d.ts +10 -0
  119. package/dist/code-language/languages/javascript.d.ts.map +1 -0
  120. package/dist/code-language/languages/javascript.js +360 -0
  121. package/dist/code-language/languages/javascript.js.map +1 -0
  122. package/dist/code-language/languages/json.d.ts +4 -0
  123. package/dist/code-language/languages/json.d.ts.map +1 -0
  124. package/dist/code-language/languages/json.js +68 -0
  125. package/dist/code-language/languages/json.js.map +1 -0
  126. package/dist/code-language/languages/shell.d.ts +4 -0
  127. package/dist/code-language/languages/shell.d.ts.map +1 -0
  128. package/dist/code-language/languages/shell.js +189 -0
  129. package/dist/code-language/languages/shell.js.map +1 -0
  130. package/dist/code-language/languages/sql.d.ts +11 -0
  131. package/dist/code-language/languages/sql.d.ts.map +1 -0
  132. package/dist/code-language/languages/sql.js +133 -0
  133. package/dist/code-language/languages/sql.js.map +1 -0
  134. package/dist/code-language/lezer.d.ts +24 -0
  135. package/dist/code-language/lezer.d.ts.map +1 -0
  136. package/dist/code-language/lezer.js +148 -0
  137. package/dist/code-language/lezer.js.map +1 -0
  138. package/dist/code-language/registry.d.ts +19 -0
  139. package/dist/code-language/registry.d.ts.map +1 -0
  140. package/dist/code-language/registry.js +56 -0
  141. package/dist/code-language/registry.js.map +1 -0
  142. package/dist/code-language/runs.d.ts +35 -0
  143. package/dist/code-language/runs.d.ts.map +1 -0
  144. package/dist/code-language/runs.js +88 -0
  145. package/dist/code-language/runs.js.map +1 -0
  146. package/dist/code-language/stream.d.ts +70 -0
  147. package/dist/code-language/stream.d.ts.map +1 -0
  148. package/dist/code-language/stream.js +243 -0
  149. package/dist/code-language/stream.js.map +1 -0
  150. package/dist/code-language/textmate.d.ts +27 -0
  151. package/dist/code-language/textmate.d.ts.map +1 -0
  152. package/dist/code-language/textmate.js +86 -0
  153. package/dist/code-language/textmate.js.map +1 -0
  154. package/dist/code-language/theme.d.ts +26 -0
  155. package/dist/code-language/theme.d.ts.map +1 -0
  156. package/dist/code-language/theme.js +108 -0
  157. package/dist/code-language/theme.js.map +1 -0
  158. package/dist/code-language/timers.d.ts +7 -0
  159. package/dist/code-language/timers.d.ts.map +1 -0
  160. package/dist/code-language/timers.js +22 -0
  161. package/dist/code-language/timers.js.map +1 -0
  162. package/dist/code-language/types.d.ts +173 -0
  163. package/dist/code-language/types.d.ts.map +1 -0
  164. package/dist/code-language/types.js +41 -0
  165. package/dist/code-language/types.js.map +1 -0
  166. package/dist/codeblock/index.d.ts +69 -0
  167. package/dist/codeblock/index.d.ts.map +1 -0
  168. package/dist/codeblock/index.js +85 -0
  169. package/dist/codeblock/index.js.map +1 -0
  170. package/dist/color-picker/ColorField.d.ts +39 -0
  171. package/dist/color-picker/ColorField.d.ts.map +1 -0
  172. package/dist/color-picker/ColorField.js +239 -0
  173. package/dist/color-picker/ColorField.js.map +1 -0
  174. package/dist/color-picker/ColorPicker.d.ts +109 -0
  175. package/dist/color-picker/ColorPicker.d.ts.map +1 -0
  176. package/dist/color-picker/ColorPicker.js +757 -0
  177. package/dist/color-picker/ColorPicker.js.map +1 -0
  178. package/dist/color-picker/color.d.ts +105 -0
  179. package/dist/color-picker/color.d.ts.map +1 -0
  180. package/dist/color-picker/color.js +313 -0
  181. package/dist/color-picker/color.js.map +1 -0
  182. package/dist/color-picker/index.d.ts +8 -0
  183. package/dist/color-picker/index.d.ts.map +1 -0
  184. package/dist/color-picker/index.js +19 -0
  185. package/dist/color-picker/index.js.map +1 -0
  186. package/dist/desktop-calendar/eds.d.ts +102 -0
  187. package/dist/desktop-calendar/eds.d.ts.map +1 -0
  188. package/dist/desktop-calendar/eds.js +356 -0
  189. package/dist/desktop-calendar/eds.js.map +1 -0
  190. package/dist/desktop-calendar/ical.d.ts +63 -0
  191. package/dist/desktop-calendar/ical.d.ts.map +1 -0
  192. package/dist/desktop-calendar/ical.js +57 -0
  193. package/dist/desktop-calendar/ical.js.map +1 -0
  194. package/dist/desktop-calendar/index.d.ts +72 -0
  195. package/dist/desktop-calendar/index.d.ts.map +1 -0
  196. package/dist/desktop-calendar/index.js +213 -0
  197. package/dist/desktop-calendar/index.js.map +1 -0
  198. package/dist/embed/client.d.ts +121 -0
  199. package/dist/embed/client.d.ts.map +1 -0
  200. package/dist/embed/client.js +203 -0
  201. package/dist/embed/client.js.map +1 -0
  202. package/dist/embed/host.d.ts +96 -0
  203. package/dist/embed/host.d.ts.map +1 -0
  204. package/dist/embed/host.js +266 -0
  205. package/dist/embed/host.js.map +1 -0
  206. package/dist/embed/index.d.ts +5 -0
  207. package/dist/embed/index.d.ts.map +1 -0
  208. package/dist/embed/index.js +13 -0
  209. package/dist/embed/index.js.map +1 -0
  210. package/dist/embed/timers.d.ts +6 -0
  211. package/dist/embed/timers.d.ts.map +1 -0
  212. package/dist/embed/timers.js +16 -0
  213. package/dist/embed/timers.js.map +1 -0
  214. package/dist/flow/draw.d.ts +45 -0
  215. package/dist/flow/draw.d.ts.map +1 -0
  216. package/dist/flow/draw.js +295 -0
  217. package/dist/flow/draw.js.map +1 -0
  218. package/dist/flow/index.d.ts +64 -0
  219. package/dist/flow/index.d.ts.map +1 -0
  220. package/dist/flow/index.js +306 -0
  221. package/dist/flow/index.js.map +1 -0
  222. package/dist/flow/model.d.ts +158 -0
  223. package/dist/flow/model.d.ts.map +1 -0
  224. package/dist/flow/model.js +566 -0
  225. package/dist/flow/model.js.map +1 -0
  226. package/dist/flow/node.d.ts +429 -0
  227. package/dist/flow/node.d.ts.map +1 -0
  228. package/dist/flow/node.js +3025 -0
  229. package/dist/flow/node.js.map +1 -0
  230. package/dist/flow/paths.d.ts +43 -0
  231. package/dist/flow/paths.d.ts.map +1 -0
  232. package/dist/flow/paths.js +327 -0
  233. package/dist/flow/paths.js.map +1 -0
  234. package/dist/flow/types.d.ts +561 -0
  235. package/dist/flow/types.d.ts.map +1 -0
  236. package/dist/flow/types.js +2 -0
  237. package/dist/flow/types.js.map +1 -0
  238. package/dist/formula/hx.d.ts +24 -0
  239. package/dist/formula/hx.d.ts.map +1 -0
  240. package/dist/formula/hx.js +25 -0
  241. package/dist/formula/hx.js.map +1 -0
  242. package/dist/formula/index.d.ts +74 -0
  243. package/dist/formula/index.d.ts.map +1 -0
  244. package/dist/formula/index.js +155 -0
  245. package/dist/formula/index.js.map +1 -0
  246. package/dist/formula/katex.d.ts +78 -0
  247. package/dist/formula/katex.d.ts.map +1 -0
  248. package/dist/formula/katex.js +130 -0
  249. package/dist/formula/katex.js.map +1 -0
  250. package/dist/formula/layout.d.ts +103 -0
  251. package/dist/formula/layout.d.ts.map +1 -0
  252. package/dist/formula/layout.js +716 -0
  253. package/dist/formula/layout.js.map +1 -0
  254. package/dist/formula/node.d.ts +50 -0
  255. package/dist/formula/node.d.ts.map +1 -0
  256. package/dist/formula/node.js +351 -0
  257. package/dist/formula/node.js.map +1 -0
  258. package/dist/html/controls.d.ts +48 -0
  259. package/dist/html/controls.d.ts.map +1 -0
  260. package/dist/html/controls.js +195 -0
  261. package/dist/html/controls.js.map +1 -0
  262. package/dist/html/css/cascade.d.ts +51 -0
  263. package/dist/html/css/cascade.d.ts.map +1 -0
  264. package/dist/html/css/cascade.js +552 -0
  265. package/dist/html/css/cascade.js.map +1 -0
  266. package/dist/html/css/parse.d.ts +74 -0
  267. package/dist/html/css/parse.d.ts.map +1 -0
  268. package/dist/html/css/parse.js +464 -0
  269. package/dist/html/css/parse.js.map +1 -0
  270. package/dist/html/css/style.d.ts +142 -0
  271. package/dist/html/css/style.d.ts.map +1 -0
  272. package/dist/html/css/style.js +1145 -0
  273. package/dist/html/css/style.js.map +1 -0
  274. package/dist/html/css/ua.d.ts +5 -0
  275. package/dist/html/css/ua.d.ts.map +1 -0
  276. package/dist/html/css/ua.js +171 -0
  277. package/dist/html/css/ua.js.map +1 -0
  278. package/dist/html/css/values.d.ts +78 -0
  279. package/dist/html/css/values.d.ts.map +1 -0
  280. package/dist/html/css/values.js +330 -0
  281. package/dist/html/css/values.js.map +1 -0
  282. package/dist/html/dom.d.ts +112 -0
  283. package/dist/html/dom.d.ts.map +1 -0
  284. package/dist/html/dom.js +374 -0
  285. package/dist/html/dom.js.map +1 -0
  286. package/dist/html/hx.d.ts +24 -0
  287. package/dist/html/hx.d.ts.map +1 -0
  288. package/dist/html/hx.js +29 -0
  289. package/dist/html/hx.js.map +1 -0
  290. package/dist/html/index.d.ts +137 -0
  291. package/dist/html/index.d.ts.map +1 -0
  292. package/dist/html/index.js +339 -0
  293. package/dist/html/index.js.map +1 -0
  294. package/dist/html/layout/block.d.ts +58 -0
  295. package/dist/html/layout/block.d.ts.map +1 -0
  296. package/dist/html/layout/block.js +724 -0
  297. package/dist/html/layout/block.js.map +1 -0
  298. package/dist/html/layout/boxes.d.ts +261 -0
  299. package/dist/html/layout/boxes.d.ts.map +1 -0
  300. package/dist/html/layout/boxes.js +725 -0
  301. package/dist/html/layout/boxes.js.map +1 -0
  302. package/dist/html/layout/flex.d.ts +16 -0
  303. package/dist/html/layout/flex.d.ts.map +1 -0
  304. package/dist/html/layout/flex.js +242 -0
  305. package/dist/html/layout/flex.js.map +1 -0
  306. package/dist/html/layout/floats.d.ts +50 -0
  307. package/dist/html/layout/floats.d.ts.map +1 -0
  308. package/dist/html/layout/floats.js +110 -0
  309. package/dist/html/layout/floats.js.map +1 -0
  310. package/dist/html/layout/inline.d.ts +44 -0
  311. package/dist/html/layout/inline.d.ts.map +1 -0
  312. package/dist/html/layout/inline.js +700 -0
  313. package/dist/html/layout/inline.js.map +1 -0
  314. package/dist/html/layout/table.d.ts +5 -0
  315. package/dist/html/layout/table.d.ts.map +1 -0
  316. package/dist/html/layout/table.js +340 -0
  317. package/dist/html/layout/table.js.map +1 -0
  318. package/dist/html/node.d.ts +149 -0
  319. package/dist/html/node.d.ts.map +1 -0
  320. package/dist/html/node.js +861 -0
  321. package/dist/html/node.js.map +1 -0
  322. package/dist/html/paint.d.ts +48 -0
  323. package/dist/html/paint.d.ts.map +1 -0
  324. package/dist/html/paint.js +495 -0
  325. package/dist/html/paint.js.map +1 -0
  326. package/dist/html/resources.d.ts +48 -0
  327. package/dist/html/resources.d.ts.map +1 -0
  328. package/dist/html/resources.js +156 -0
  329. package/dist/html/resources.js.map +1 -0
  330. package/dist/index.d.ts +48 -0
  331. package/dist/index.d.ts.map +1 -0
  332. package/dist/index.js +92 -0
  333. package/dist/index.js.map +1 -0
  334. package/dist/internal/heights.d.ts +88 -0
  335. package/dist/internal/heights.d.ts.map +1 -0
  336. package/dist/internal/heights.js +203 -0
  337. package/dist/internal/heights.js.map +1 -0
  338. package/dist/internal/hx.d.ts +24 -0
  339. package/dist/internal/hx.d.ts.map +1 -0
  340. package/dist/internal/hx.js +27 -0
  341. package/dist/internal/hx.js.map +1 -0
  342. package/dist/internal/scroll.d.ts +62 -0
  343. package/dist/internal/scroll.d.ts.map +1 -0
  344. package/dist/internal/scroll.js +224 -0
  345. package/dist/internal/scroll.js.map +1 -0
  346. package/dist/internal/text.d.ts +6 -0
  347. package/dist/internal/text.d.ts.map +1 -0
  348. package/dist/internal/text.js +44 -0
  349. package/dist/internal/text.js.map +1 -0
  350. package/dist/internal/timers.d.ts +8 -0
  351. package/dist/internal/timers.d.ts.map +1 -0
  352. package/dist/internal/timers.js +22 -0
  353. package/dist/internal/timers.js.map +1 -0
  354. package/dist/internal/widget.d.ts +40 -0
  355. package/dist/internal/widget.d.ts.map +1 -0
  356. package/dist/internal/widget.js +44 -0
  357. package/dist/internal/widget.js.map +1 -0
  358. package/dist/markdown/ast.d.ts +126 -0
  359. package/dist/markdown/ast.d.ts.map +1 -0
  360. package/dist/markdown/ast.js +8 -0
  361. package/dist/markdown/ast.js.map +1 -0
  362. package/dist/markdown/hx.d.ts +24 -0
  363. package/dist/markdown/hx.d.ts.map +1 -0
  364. package/dist/markdown/hx.js +25 -0
  365. package/dist/markdown/hx.js.map +1 -0
  366. package/dist/markdown/index.d.ts +90 -0
  367. package/dist/markdown/index.d.ts.map +1 -0
  368. package/dist/markdown/index.js +413 -0
  369. package/dist/markdown/index.js.map +1 -0
  370. package/dist/markdown/parse.d.ts +8 -0
  371. package/dist/markdown/parse.d.ts.map +1 -0
  372. package/dist/markdown/parse.js +911 -0
  373. package/dist/markdown/parse.js.map +1 -0
  374. package/dist/markdown/spans.d.ts +20 -0
  375. package/dist/markdown/spans.d.ts.map +1 -0
  376. package/dist/markdown/spans.js +96 -0
  377. package/dist/markdown/spans.js.map +1 -0
  378. package/dist/media-player/backends.d.ts +64 -0
  379. package/dist/media-player/backends.d.ts.map +1 -0
  380. package/dist/media-player/backends.js +110 -0
  381. package/dist/media-player/backends.js.map +1 -0
  382. package/dist/media-player/control.d.ts +40 -0
  383. package/dist/media-player/control.d.ts.map +1 -0
  384. package/dist/media-player/control.js +44 -0
  385. package/dist/media-player/control.js.map +1 -0
  386. package/dist/media-player/hx.d.ts +24 -0
  387. package/dist/media-player/hx.d.ts.map +1 -0
  388. package/dist/media-player/hx.js +25 -0
  389. package/dist/media-player/hx.js.map +1 -0
  390. package/dist/media-player/index.d.ts +107 -0
  391. package/dist/media-player/index.d.ts.map +1 -0
  392. package/dist/media-player/index.js +219 -0
  393. package/dist/media-player/index.js.map +1 -0
  394. package/dist/media-player/mpv.d.ts +4 -0
  395. package/dist/media-player/mpv.d.ts.map +1 -0
  396. package/dist/media-player/mpv.js +120 -0
  397. package/dist/media-player/mpv.js.map +1 -0
  398. package/dist/media-player/vlc.d.ts +8 -0
  399. package/dist/media-player/vlc.d.ts.map +1 -0
  400. package/dist/media-player/vlc.js +83 -0
  401. package/dist/media-player/vlc.js.map +1 -0
  402. package/dist/richtext/index.d.ts +19 -0
  403. package/dist/richtext/index.d.ts.map +1 -0
  404. package/dist/richtext/index.js +4 -0
  405. package/dist/richtext/index.js.map +1 -0
  406. package/dist/richtext/links.d.ts +12 -0
  407. package/dist/richtext/links.d.ts.map +1 -0
  408. package/dist/richtext/links.js +64 -0
  409. package/dist/richtext/links.js.map +1 -0
  410. package/dist/richtext/menu.d.ts +11 -0
  411. package/dist/richtext/menu.d.ts.map +1 -0
  412. package/dist/richtext/menu.js +43 -0
  413. package/dist/richtext/menu.js.map +1 -0
  414. package/dist/richtext/node.d.ts +151 -0
  415. package/dist/richtext/node.d.ts.map +1 -0
  416. package/dist/richtext/node.js +255 -0
  417. package/dist/richtext/node.js.map +1 -0
  418. package/dist/richtext/runs.d.ts +92 -0
  419. package/dist/richtext/runs.d.ts.map +1 -0
  420. package/dist/richtext/runs.js +158 -0
  421. package/dist/richtext/runs.js.map +1 -0
  422. package/dist/table/hx.d.ts +24 -0
  423. package/dist/table/hx.d.ts.map +1 -0
  424. package/dist/table/hx.js +25 -0
  425. package/dist/table/hx.js.map +1 -0
  426. package/dist/table/index.d.ts +169 -0
  427. package/dist/table/index.d.ts.map +1 -0
  428. package/dist/table/index.js +890 -0
  429. package/dist/table/index.js.map +1 -0
  430. package/dist/table/rows.d.ts +136 -0
  431. package/dist/table/rows.d.ts.map +1 -0
  432. package/dist/table/rows.js +146 -0
  433. package/dist/table/rows.js.map +1 -0
  434. package/dist/terminal/backends.d.ts +105 -0
  435. package/dist/terminal/backends.d.ts.map +1 -0
  436. package/dist/terminal/backends.js +185 -0
  437. package/dist/terminal/backends.js.map +1 -0
  438. package/dist/terminal/hx.d.ts +24 -0
  439. package/dist/terminal/hx.d.ts.map +1 -0
  440. package/dist/terminal/hx.js +25 -0
  441. package/dist/terminal/hx.js.map +1 -0
  442. package/dist/terminal/index.d.ts +160 -0
  443. package/dist/terminal/index.d.ts.map +1 -0
  444. package/dist/terminal/index.js +344 -0
  445. package/dist/terminal/index.js.map +1 -0
  446. package/dist/terminal/title.d.ts +24 -0
  447. package/dist/terminal/title.d.ts.map +1 -0
  448. package/dist/terminal/title.js +129 -0
  449. package/dist/terminal/title.js.map +1 -0
  450. package/dist/terminal/vt/colors.d.ts +63 -0
  451. package/dist/terminal/vt/colors.d.ts.map +1 -0
  452. package/dist/terminal/vt/colors.js +203 -0
  453. package/dist/terminal/vt/colors.js.map +1 -0
  454. package/dist/terminal/vt/diff.d.ts +117 -0
  455. package/dist/terminal/vt/diff.d.ts.map +1 -0
  456. package/dist/terminal/vt/diff.js +358 -0
  457. package/dist/terminal/vt/diff.js.map +1 -0
  458. package/dist/terminal/vt/fonts.d.ts +92 -0
  459. package/dist/terminal/vt/fonts.d.ts.map +1 -0
  460. package/dist/terminal/vt/fonts.js +178 -0
  461. package/dist/terminal/vt/fonts.js.map +1 -0
  462. package/dist/terminal/vt/index.d.ts +78 -0
  463. package/dist/terminal/vt/index.d.ts.map +1 -0
  464. package/dist/terminal/vt/index.js +312 -0
  465. package/dist/terminal/vt/index.js.map +1 -0
  466. package/dist/terminal/vt/keys.d.ts +74 -0
  467. package/dist/terminal/vt/keys.d.ts.map +1 -0
  468. package/dist/terminal/vt/keys.js +309 -0
  469. package/dist/terminal/vt/keys.js.map +1 -0
  470. package/dist/terminal/vt/mouse.d.ts +44 -0
  471. package/dist/terminal/vt/mouse.d.ts.map +1 -0
  472. package/dist/terminal/vt/mouse.js +106 -0
  473. package/dist/terminal/vt/mouse.js.map +1 -0
  474. package/dist/terminal/vt/node.d.ts +246 -0
  475. package/dist/terminal/vt/node.d.ts.map +1 -0
  476. package/dist/terminal/vt/node.js +1068 -0
  477. package/dist/terminal/vt/node.js.map +1 -0
  478. package/dist/terminal/vt/pty.d.ts +81 -0
  479. package/dist/terminal/vt/pty.d.ts.map +1 -0
  480. package/dist/terminal/vt/pty.js +201 -0
  481. package/dist/terminal/vt/pty.js.map +1 -0
  482. package/dist/terminal/vt/renderer.d.ts +179 -0
  483. package/dist/terminal/vt/renderer.d.ts.map +1 -0
  484. package/dist/terminal/vt/renderer.js +357 -0
  485. package/dist/terminal/vt/renderer.js.map +1 -0
  486. package/dist/terminal/vt/timers.d.ts +6 -0
  487. package/dist/terminal/vt/timers.d.ts.map +1 -0
  488. package/dist/terminal/vt/timers.js +16 -0
  489. package/dist/terminal/vt/timers.js.map +1 -0
  490. package/dist/terminal/vt/xterm.d.ts +142 -0
  491. package/dist/terminal/vt/xterm.d.ts.map +1 -0
  492. package/dist/terminal/vt/xterm.js +32 -0
  493. package/dist/terminal/vt/xterm.js.map +1 -0
  494. package/dist/terminal-output/hx.d.ts +24 -0
  495. package/dist/terminal-output/hx.d.ts.map +1 -0
  496. package/dist/terminal-output/hx.js +25 -0
  497. package/dist/terminal-output/hx.js.map +1 -0
  498. package/dist/terminal-output/index.d.ts +92 -0
  499. package/dist/terminal-output/index.d.ts.map +1 -0
  500. package/dist/terminal-output/index.js +179 -0
  501. package/dist/terminal-output/index.js.map +1 -0
  502. package/dist/terminal-output/runs.d.ts +27 -0
  503. package/dist/terminal-output/runs.d.ts.map +1 -0
  504. package/dist/terminal-output/runs.js +66 -0
  505. package/dist/terminal-output/runs.js.map +1 -0
  506. package/dist/three/canvas.d.ts +46 -0
  507. package/dist/three/canvas.d.ts.map +1 -0
  508. package/dist/three/canvas.js +305 -0
  509. package/dist/three/canvas.js.map +1 -0
  510. package/dist/three/events.d.ts +64 -0
  511. package/dist/three/events.d.ts.map +1 -0
  512. package/dist/three/events.js +146 -0
  513. package/dist/three/events.js.map +1 -0
  514. package/dist/three/geometries.d.ts +89 -0
  515. package/dist/three/geometries.d.ts.map +1 -0
  516. package/dist/three/geometries.js +345 -0
  517. package/dist/three/geometries.js.map +1 -0
  518. package/dist/three/globals.d.ts +7 -0
  519. package/dist/three/globals.d.ts.map +1 -0
  520. package/dist/three/globals.js +20 -0
  521. package/dist/three/globals.js.map +1 -0
  522. package/dist/three/hx.d.ts +9 -0
  523. package/dist/three/hx.d.ts.map +1 -0
  524. package/dist/three/hx.js +10 -0
  525. package/dist/three/hx.js.map +1 -0
  526. package/dist/three/index.d.ts +22 -0
  527. package/dist/three/index.d.ts.map +1 -0
  528. package/dist/three/index.js +24 -0
  529. package/dist/three/index.js.map +1 -0
  530. package/dist/three/jsx-dev-runtime.d.ts +19 -0
  531. package/dist/three/jsx-dev-runtime.d.ts.map +1 -0
  532. package/dist/three/jsx-dev-runtime.js +2 -0
  533. package/dist/three/jsx-dev-runtime.js.map +1 -0
  534. package/dist/three/jsx-runtime.d.ts +19 -0
  535. package/dist/three/jsx-runtime.d.ts.map +1 -0
  536. package/dist/three/jsx-runtime.js +2 -0
  537. package/dist/three/jsx-runtime.js.map +1 -0
  538. package/dist/three/jsx.d.ts +198 -0
  539. package/dist/three/jsx.d.ts.map +1 -0
  540. package/dist/three/jsx.js +2 -0
  541. package/dist/three/jsx.js.map +1 -0
  542. package/dist/three/materials.d.ts +125 -0
  543. package/dist/three/materials.d.ts.map +1 -0
  544. package/dist/three/materials.js +229 -0
  545. package/dist/three/materials.js.map +1 -0
  546. package/dist/three/math.d.ts +146 -0
  547. package/dist/three/math.d.ts.map +1 -0
  548. package/dist/three/math.js +464 -0
  549. package/dist/three/math.js.map +1 -0
  550. package/dist/three/objects.d.ts +185 -0
  551. package/dist/three/objects.d.ts.map +1 -0
  552. package/dist/three/objects.js +309 -0
  553. package/dist/three/objects.js.map +1 -0
  554. package/dist/three/passes.d.ts +54 -0
  555. package/dist/three/passes.d.ts.map +1 -0
  556. package/dist/three/passes.js +78 -0
  557. package/dist/three/passes.js.map +1 -0
  558. package/dist/three/postprocess.d.ts +85 -0
  559. package/dist/three/postprocess.d.ts.map +1 -0
  560. package/dist/three/postprocess.js +503 -0
  561. package/dist/three/postprocess.js.map +1 -0
  562. package/dist/three/raycast.d.ts +24 -0
  563. package/dist/three/raycast.d.ts.map +1 -0
  564. package/dist/three/raycast.js +138 -0
  565. package/dist/three/raycast.js.map +1 -0
  566. package/dist/three/reconciler.d.ts +48 -0
  567. package/dist/three/reconciler.d.ts.map +1 -0
  568. package/dist/three/reconciler.js +416 -0
  569. package/dist/three/reconciler.js.map +1 -0
  570. package/dist/three/renderer-direct.d.ts +102 -0
  571. package/dist/three/renderer-direct.d.ts.map +1 -0
  572. package/dist/three/renderer-direct.js +782 -0
  573. package/dist/three/renderer-direct.js.map +1 -0
  574. package/dist/three/renderer-indirect.d.ts +68 -0
  575. package/dist/three/renderer-indirect.d.ts.map +1 -0
  576. package/dist/three/renderer-indirect.js +438 -0
  577. package/dist/three/renderer-indirect.js.map +1 -0
  578. package/dist/three/store.d.ts +81 -0
  579. package/dist/three/store.d.ts.map +1 -0
  580. package/dist/three/store.js +110 -0
  581. package/dist/three/store.js.map +1 -0
  582. package/dist/timeline/hx.d.ts +18 -0
  583. package/dist/timeline/hx.d.ts.map +1 -0
  584. package/dist/timeline/hx.js +10 -0
  585. package/dist/timeline/hx.js.map +1 -0
  586. package/dist/timeline/index.d.ts +152 -0
  587. package/dist/timeline/index.d.ts.map +1 -0
  588. package/dist/timeline/index.js +383 -0
  589. package/dist/timeline/index.js.map +1 -0
  590. package/dist/tray-host/hx.d.ts +24 -0
  591. package/dist/tray-host/hx.d.ts.map +1 -0
  592. package/dist/tray-host/hx.js +25 -0
  593. package/dist/tray-host/hx.js.map +1 -0
  594. package/dist/tray-host/index.d.ts +110 -0
  595. package/dist/tray-host/index.d.ts.map +1 -0
  596. package/dist/tray-host/index.js +191 -0
  597. package/dist/tray-host/index.js.map +1 -0
  598. package/dist/tray-host/manager.d.ts +137 -0
  599. package/dist/tray-host/manager.d.ts.map +1 -0
  600. package/dist/tray-host/manager.js +462 -0
  601. package/dist/tray-host/manager.js.map +1 -0
  602. package/dist/tray-host/notify.d.ts +22 -0
  603. package/dist/tray-host/notify.d.ts.map +1 -0
  604. package/dist/tray-host/notify.js +74 -0
  605. package/dist/tray-host/notify.js.map +1 -0
  606. package/dist/tray-host/protocol.d.ts +106 -0
  607. package/dist/tray-host/protocol.d.ts.map +1 -0
  608. package/dist/tray-host/protocol.js +191 -0
  609. package/dist/tray-host/protocol.js.map +1 -0
  610. package/dist/tree/hx.d.ts +24 -0
  611. package/dist/tree/hx.d.ts.map +1 -0
  612. package/dist/tree/hx.js +25 -0
  613. package/dist/tree/hx.js.map +1 -0
  614. package/dist/tree/index.d.ts +221 -0
  615. package/dist/tree/index.d.ts.map +1 -0
  616. package/dist/tree/index.js +751 -0
  617. package/dist/tree/index.js.map +1 -0
  618. package/dist/tree/internal.d.ts +18 -0
  619. package/dist/tree/internal.d.ts.map +1 -0
  620. package/dist/tree/internal.js +66 -0
  621. package/dist/tree/internal.js.map +1 -0
  622. package/dist/tree/rows.d.ts +177 -0
  623. package/dist/tree/rows.d.ts.map +1 -0
  624. package/dist/tree/rows.js +179 -0
  625. package/dist/tree/rows.js.map +1 -0
  626. package/package.json +166 -12
  627. package/src/ansi/cast.ts +159 -0
  628. package/src/ansi/index.ts +53 -0
  629. package/src/ansi/palette.ts +226 -0
  630. package/src/ansi/parse.ts +780 -0
  631. package/src/ansi/sgr.ts +380 -0
  632. package/src/ansi/utf8.ts +84 -0
  633. package/src/calendar/Calendar.ts +744 -0
  634. package/src/calendar/DatePicker.ts +368 -0
  635. package/src/calendar/dates.ts +307 -0
  636. package/src/calendar/index.ts +51 -0
  637. package/src/charts/components.ts +864 -0
  638. package/src/charts/data.ts +776 -0
  639. package/src/charts/hx.ts +39 -0
  640. package/src/charts/index.ts +99 -0
  641. package/src/charts/node.ts +932 -0
  642. package/src/charts/render.ts +982 -0
  643. package/src/charts/scale.ts +214 -0
  644. package/src/charts/spec.ts +122 -0
  645. package/src/charts/timers.ts +24 -0
  646. package/src/code/hx.ts +51 -0
  647. package/src/code/index.ts +174 -0
  648. package/src/code-editor/completion.ts +161 -0
  649. package/src/code-editor/doc.ts +198 -0
  650. package/src/code-editor/hx.ts +26 -0
  651. package/src/code-editor/index.ts +615 -0
  652. package/src/code-editor/node.ts +1926 -0
  653. package/src/code-language/hljs.ts +302 -0
  654. package/src/code-language/index.ts +51 -0
  655. package/src/code-language/languages/glsl.ts +120 -0
  656. package/src/code-language/languages/javascript.ts +419 -0
  657. package/src/code-language/languages/json.ts +72 -0
  658. package/src/code-language/languages/shell.ts +221 -0
  659. package/src/code-language/languages/sql.ts +165 -0
  660. package/src/code-language/lezer.ts +190 -0
  661. package/src/code-language/registry.ts +66 -0
  662. package/src/code-language/runs.ts +128 -0
  663. package/src/code-language/stream.ts +306 -0
  664. package/src/code-language/textmate.ts +134 -0
  665. package/src/code-language/theme.ts +124 -0
  666. package/src/code-language/timers.ts +36 -0
  667. package/src/code-language/types.ts +252 -0
  668. package/src/codeblock/index.ts +146 -0
  669. package/src/color-picker/ColorField.ts +333 -0
  670. package/src/color-picker/ColorPicker.ts +1069 -0
  671. package/src/color-picker/color.ts +399 -0
  672. package/src/color-picker/index.ts +50 -0
  673. package/src/desktop-calendar/eds.ts +484 -0
  674. package/src/desktop-calendar/ical.ts +119 -0
  675. package/src/desktop-calendar/index.ts +287 -0
  676. package/src/embed/client.ts +311 -0
  677. package/src/embed/host.ts +432 -0
  678. package/src/embed/index.ts +33 -0
  679. package/src/embed/timers.ts +32 -0
  680. package/src/flow/draw.ts +418 -0
  681. package/src/flow/index.ts +473 -0
  682. package/src/flow/model.ts +687 -0
  683. package/src/flow/node.ts +3694 -0
  684. package/src/flow/paths.ts +403 -0
  685. package/src/flow/types.ts +634 -0
  686. package/src/formula/hx.ts +51 -0
  687. package/src/formula/index.ts +243 -0
  688. package/src/formula/katex.ts +209 -0
  689. package/src/formula/layout.ts +876 -0
  690. package/src/formula/node.ts +467 -0
  691. package/src/html/controls.ts +244 -0
  692. package/src/html/css/cascade.ts +606 -0
  693. package/src/html/css/parse.ts +500 -0
  694. package/src/html/css/style.ts +1371 -0
  695. package/src/html/css/ua.ts +174 -0
  696. package/src/html/css/values.ts +358 -0
  697. package/src/html/dom.ts +410 -0
  698. package/src/html/hx.ts +55 -0
  699. package/src/html/index.ts +545 -0
  700. package/src/html/layout/block.ts +876 -0
  701. package/src/html/layout/boxes.ts +981 -0
  702. package/src/html/layout/flex.ts +297 -0
  703. package/src/html/layout/floats.ts +125 -0
  704. package/src/html/layout/inline.ts +870 -0
  705. package/src/html/layout/table.ts +380 -0
  706. package/src/html/node.ts +967 -0
  707. package/src/html/paint.ts +605 -0
  708. package/src/html/resources.ts +214 -0
  709. package/src/index.ts +638 -0
  710. package/src/internal/heights.ts +222 -0
  711. package/src/internal/hx.ts +53 -0
  712. package/src/internal/scroll.ts +288 -0
  713. package/src/internal/text.ts +44 -0
  714. package/src/internal/timers.ts +44 -0
  715. package/src/internal/widget.ts +92 -0
  716. package/src/markdown/ast.ts +163 -0
  717. package/src/markdown/hx.ts +51 -0
  718. package/src/markdown/index.ts +686 -0
  719. package/src/markdown/parse.ts +1037 -0
  720. package/src/markdown/spans.ts +143 -0
  721. package/src/media-player/backends.ts +155 -0
  722. package/src/media-player/control.ts +70 -0
  723. package/src/media-player/hx.ts +51 -0
  724. package/src/media-player/index.ts +378 -0
  725. package/src/media-player/mpv.ts +146 -0
  726. package/src/media-player/vlc.ts +97 -0
  727. package/src/richtext/index.ts +42 -0
  728. package/src/richtext/links.ts +78 -0
  729. package/src/richtext/menu.ts +49 -0
  730. package/src/richtext/node.ts +406 -0
  731. package/src/richtext/runs.ts +253 -0
  732. package/src/table/hx.ts +51 -0
  733. package/src/table/index.ts +1270 -0
  734. package/src/table/rows.ts +275 -0
  735. package/src/terminal/backends.ts +242 -0
  736. package/src/terminal/hx.ts +51 -0
  737. package/src/terminal/index.ts +574 -0
  738. package/src/terminal/title.ts +172 -0
  739. package/src/terminal/vt/colors.ts +247 -0
  740. package/src/terminal/vt/diff.ts +467 -0
  741. package/src/terminal/vt/fonts.ts +233 -0
  742. package/src/terminal/vt/index.ts +443 -0
  743. package/src/terminal/vt/keys.ts +369 -0
  744. package/src/terminal/vt/mouse.ts +144 -0
  745. package/src/terminal/vt/node.ts +1242 -0
  746. package/src/terminal/vt/pty.ts +334 -0
  747. package/src/terminal/vt/renderer.ts +555 -0
  748. package/src/terminal/vt/timers.ts +31 -0
  749. package/src/terminal/vt/xterm.ts +193 -0
  750. package/src/terminal-output/hx.ts +51 -0
  751. package/src/terminal-output/index.ts +340 -0
  752. package/src/terminal-output/runs.ts +79 -0
  753. package/src/three/canvas.ts +451 -0
  754. package/src/three/events.ts +197 -0
  755. package/src/three/geometries.ts +429 -0
  756. package/src/three/globals.ts +34 -0
  757. package/src/three/hx.ts +22 -0
  758. package/src/three/index.ts +98 -0
  759. package/src/three/jsx-dev-runtime.ts +27 -0
  760. package/src/three/jsx-runtime.ts +38 -0
  761. package/src/three/jsx.ts +275 -0
  762. package/src/three/materials.ts +270 -0
  763. package/src/three/math.ts +585 -0
  764. package/src/three/objects.ts +397 -0
  765. package/src/three/passes.ts +90 -0
  766. package/src/three/postprocess.ts +677 -0
  767. package/src/three/raycast.ts +189 -0
  768. package/src/three/react-reconciler.d.ts +50 -0
  769. package/src/three/reconciler.ts +624 -0
  770. package/src/three/renderer-direct.ts +1055 -0
  771. package/src/three/renderer-indirect.ts +570 -0
  772. package/src/three/store.ts +207 -0
  773. package/src/timeline/hx.ts +31 -0
  774. package/src/timeline/index.ts +603 -0
  775. package/src/tray-host/hx.ts +51 -0
  776. package/src/tray-host/index.ts +331 -0
  777. package/src/tray-host/manager.ts +639 -0
  778. package/src/tray-host/notify.ts +102 -0
  779. package/src/tray-host/protocol.ts +235 -0
  780. package/src/tree/hx.ts +51 -0
  781. package/src/tree/index.ts +1127 -0
  782. package/src/tree/internal.ts +87 -0
  783. package/src/tree/rows.ts +334 -0
  784. package/src/index.d.ts +0 -2
  785. package/src/index.js +0 -9
  786. package/src/sparkline/index.d.ts +0 -29
  787. package/src/sparkline/index.js +0 -50
  788. package/src/sparkline/node.js +0 -72
@@ -0,0 +1,982 @@
1
+ // The series renderers: data columns → drawing commands, with the mode
2
+ // decision that keeps every frame bounded by pixels.
3
+ //
4
+ // Two rules govern everything here:
5
+ //
6
+ // 1. **Cost scales with pixels, never with points.** Below DENSE_PPX points
7
+ // per pixel a series draws as a real stroked path (antialiased, curved,
8
+ // dotted); above it, each pixel column collapses to its min/max span
9
+ // through the pyramid and the whole series goes out as one `fillRects`
10
+ // batch. A million points in a 40px cell cost ~40 rectangles.
11
+ //
12
+ // 2. **Server-side commands by default, pixels when they win.** The command
13
+ // stream is bounded by the width (rule 1), so it is almost always far
14
+ // smaller than pushing the plot as an image. The one exception is a
15
+ // scatter so dense it covers most of the plot — rectangles then cost
16
+ // more bytes than the pixels do (8/cell vs 4/px), and the renderer
17
+ // flips to compositing a density image. The crossover is computed from
18
+ // those two numbers, not guessed.
19
+ //
20
+ // The renderers draw through a structural slice of ntk's context and take
21
+ // their caches through `RenderHost`, so they run identically against the
22
+ // real server, the recording mock, and the plain fakes in the tests.
23
+
24
+ import type { NumericColumn, MinMax, XIndex } from './data.js';
25
+ import {
26
+ lowerBound,
27
+ minMaxRange,
28
+ pyramidFor,
29
+ visibleIndexRange,
30
+ xIndexFor,
31
+ } from './data.js';
32
+ import type { BandScale, LinearScale } from './scale.js';
33
+ import type { ChartFrameStats, SeriesSpec } from './spec.js';
34
+
35
+ /** points per pixel above which a line/area stops stroking real segments
36
+ * and collapses to per-column spans */
37
+ export const DENSE_PPX = 2;
38
+ /** most points a sparse pass will ever stroke (DENSE_PPX × a wide plot) */
39
+ export const ROUND_JOIN_MAX = 256;
40
+ /** dots/points drawn as real circles; batched squares above, nothing once
41
+ * the grid takes over */
42
+ export const CIRCLE_MAX = 96;
43
+ export const DIRECT_SCATTER_MAX = 512;
44
+ /** bars that may keep their rounded tops — past this they go square into
45
+ * one batch */
46
+ export const BAR_RADIUS_MAX = 256;
47
+
48
+ export interface PlotRect {
49
+ x: number;
50
+ y: number;
51
+ width: number;
52
+ height: number;
53
+ }
54
+
55
+ /** The slice of ntk's 2d context the renderers need. Everything optional is
56
+ * feature-tested: the mock backend has most of it, the plain test fakes
57
+ * less, and a missing method degrades the drawing rather than throwing. */
58
+ export interface PlotContext {
59
+ fillStyle: unknown;
60
+ strokeStyle: unknown;
61
+ lineWidth: number;
62
+ globalAlpha?: number;
63
+ lineJoin?: string;
64
+ lineCap?: string;
65
+ save(): void;
66
+ restore(): void;
67
+ fillRect(x: number, y: number, w: number, h: number): void;
68
+ fillRects?(rects: number[]): void;
69
+ beginPath?(): void;
70
+ moveTo?(x: number, y: number): void;
71
+ lineTo?(x: number, y: number): void;
72
+ bezierCurveTo?(
73
+ x1: number,
74
+ y1: number,
75
+ x2: number,
76
+ y2: number,
77
+ x: number,
78
+ y: number,
79
+ ): void;
80
+ arc?(x: number, y: number, r: number, a0: number, a1: number): void;
81
+ closePath?(): void;
82
+ stroke?(): void;
83
+ fill?(): void;
84
+ rect?(x: number, y: number, w: number, h: number): void;
85
+ clip?(): void;
86
+ drawImage?(image: unknown, dx: number, dy: number): void;
87
+ roundRect?(
88
+ x: number,
89
+ y: number,
90
+ w: number,
91
+ h: number,
92
+ radii: number | number[],
93
+ ): void;
94
+ }
95
+
96
+ export const canPath = (
97
+ ctx: PlotContext,
98
+ ): ctx is PlotContext &
99
+ Required<Pick<PlotContext, 'beginPath' | 'moveTo' | 'lineTo'>> =>
100
+ typeof ctx.beginPath === 'function' &&
101
+ typeof ctx.moveTo === 'function' &&
102
+ typeof ctx.lineTo === 'function';
103
+
104
+ /** One batched fill for many rectangles, or the loop where the context has
105
+ * no batch — same pixels, more requests, which is the mock's documented
106
+ * contract too. */
107
+ function fillRects(ctx: PlotContext, rects: number[]): void {
108
+ if (typeof ctx.fillRects === 'function') {
109
+ ctx.fillRects(rects);
110
+ return;
111
+ }
112
+ for (let i = 0; i + 3 < rects.length; i += 4) {
113
+ ctx.fillRect(rects[i], rects[i + 1], rects[i + 2], rects[i + 3]);
114
+ }
115
+ }
116
+
117
+ /** Mutable accumulator behind `ChartFrameStats`. */
118
+ export interface FrameStatsSink {
119
+ pointsSpanned: number;
120
+ commands: number;
121
+ estimatedWireBytes: number;
122
+ series: ChartFrameStats['series'];
123
+ }
124
+
125
+ /** Estimated wire bytes per primitive — the numbers the mode policy
126
+ * compares. A rectangle is 8 bytes in a FillRectangles; a stroked segment
127
+ * extrudes to two triangles at 24 bytes each; an image pixel is 4. */
128
+ export const BYTES_PER_RECT = 8;
129
+ export const BYTES_PER_SEGMENT = 48;
130
+ export const BYTES_PER_PIXEL = 4;
131
+
132
+ // --- per-series input ------------------------------------------------------
133
+
134
+ /** A series' resolved geometry inputs, prepared by the node. */
135
+ export interface SeriesGeometry {
136
+ spec: SeriesSpec;
137
+ /** y values (or the stack top for this layer). */
138
+ y: NumericColumn;
139
+ /** The stack base: the layer below's tops, or a constant domain value. */
140
+ base: NumericColumn | number;
141
+ /** x column; null means "the index is the x value". */
142
+ x: NumericColumn | null;
143
+ /** Index metadata for x when there is a column. */
144
+ xIdx: XIndex | null;
145
+ /** Bars: which slot of how many this series takes within a band. */
146
+ group: { index: number; count: number };
147
+ /** Paint-ready colour (theme tokens already resolved). */
148
+ color: string;
149
+ }
150
+
151
+ export interface SeriesEnv {
152
+ ctx: PlotContext;
153
+ plot: PlotRect;
154
+ xScale: LinearScale | BandScale;
155
+ yScale: LinearScale;
156
+ stats: FrameStatsSink;
157
+ host: RenderHost;
158
+ }
159
+
160
+ /** Caches and capabilities only the retained node can provide. */
161
+ export interface RenderHost {
162
+ /** Per-series scatter occupancy grid, cached across frames. */
163
+ scatterGrid(id: string, key: string, n: number): ScatterGrid;
164
+ /**
165
+ * Composite a straight-RGBA image over the plot, preserving what is
166
+ * already painted underneath. False when this backend cannot (no
167
+ * XRender surface — the mock), in which case the caller uses rects.
168
+ * `contentKey` names what `fill` would produce: an unchanged key lets
169
+ * the host re-composite its retained surface without refilling or
170
+ * re-uploading a pixel.
171
+ */
172
+ blitImage(
173
+ x: number,
174
+ y: number,
175
+ w: number,
176
+ h: number,
177
+ fill: (data: Uint8ClampedArray) => void,
178
+ contentKey?: string,
179
+ ): boolean;
180
+ }
181
+
182
+ // --- helpers ---------------------------------------------------------------
183
+
184
+ const mm: MinMax = { min: 0, max: 0 };
185
+
186
+ function xValueAt(g: SeriesGeometry, i: number): number {
187
+ return g.x ? (g.x.values[i] as number) : i;
188
+ }
189
+
190
+ /** Pixel x for a data index — linear x maps the value, band x maps the
191
+ * index to its band center (a line over categories walks the centers). */
192
+ function pxAt(env: SeriesEnv, g: SeriesGeometry, i: number): number {
193
+ return env.xScale.kind === 'band'
194
+ ? env.xScale.center(i)
195
+ : env.xScale.scale(xValueAt(g, i));
196
+ }
197
+
198
+ /** The visible index window for this series under the current x domain. */
199
+ export function visibleRange(
200
+ env: SeriesEnv,
201
+ g: SeriesGeometry,
202
+ ): [number, number] {
203
+ const n = g.y.n;
204
+ if (env.xScale.kind === 'band') return [0, n];
205
+ if (!g.x || !g.xIdx) {
206
+ const i0 = Math.max(0, Math.floor(env.xScale.d0) - 1);
207
+ const i1 = Math.min(n, Math.ceil(env.xScale.d1) + 2);
208
+ return [i0, Math.max(i0, i1)];
209
+ }
210
+ return visibleIndexRange(
211
+ g.xIdx,
212
+ g.x.values,
213
+ Math.min(n, g.x.n),
214
+ env.xScale.d0,
215
+ env.xScale.d1,
216
+ );
217
+ }
218
+
219
+ /** Last finite y at or before `i1-1`, looking back a bounded distance —
220
+ * the M4 "close" value that bridges adjacent columns. */
221
+ function lastFinite(values: ArrayLike<number>, i0: number, i1: number): number {
222
+ const stop = Math.max(i0, i1 - 16);
223
+ for (let i = i1 - 1; i >= stop; i--) {
224
+ const v = values[i];
225
+ if (!Number.isNaN(v)) return v;
226
+ }
227
+ return NaN;
228
+ }
229
+
230
+ /**
231
+ * Walk the pixel columns of the visible range, handing each column its
232
+ * exact index window. Uniform x advances arithmetically; sorted x binary
233
+ * searches each boundary (O(width · log n), bounded); the band case is
234
+ * plain proportional slicing. `cb` returns nothing; gaps come through as
235
+ * empty windows.
236
+ */
237
+ function walkColumns(
238
+ env: SeriesEnv,
239
+ g: SeriesGeometry,
240
+ i0: number,
241
+ i1: number,
242
+ cb: (colPx: number, ia: number, ib: number) => void,
243
+ ): void {
244
+ const { plot } = env;
245
+ const cols = Math.max(1, Math.round(plot.width));
246
+ if (env.xScale.kind === 'band' || !g.x || !g.xIdx || !g.xIdx.sorted) {
247
+ // proportional index slicing: exact for bands, and the honest bounded
248
+ // fallback for unsorted x (index order is all there is to draw)
249
+ const span = i1 - i0;
250
+ let prev = i0;
251
+ for (let c = 0; c < cols; c++) {
252
+ const ib = c + 1 >= cols ? i1 : i0 + Math.floor((span * (c + 1)) / cols);
253
+ cb(plot.x + c, prev, ib);
254
+ prev = ib;
255
+ }
256
+ return;
257
+ }
258
+ const xs = g.x.values;
259
+ const n = Math.min(g.y.n, g.x.n);
260
+ const idx = g.xIdx;
261
+ const scale = env.xScale as LinearScale;
262
+ const uniform = idx.uniform && idx.dx > 0;
263
+ let prev = i0;
264
+ for (let c = 0; c < cols; c++) {
265
+ let ib: number;
266
+ if (c + 1 >= cols) {
267
+ ib = i1;
268
+ } else {
269
+ const xRight = scale.invert(plot.x + c + 1);
270
+ ib = uniform
271
+ ? Math.ceil((xRight - idx.x0) / idx.dx)
272
+ : lowerBound(xs, n, xRight);
273
+ if (ib < prev) ib = prev;
274
+ if (ib > i1) ib = i1;
275
+ }
276
+ cb(plot.x + c, prev, ib);
277
+ prev = ib;
278
+ }
279
+ }
280
+
281
+ // --- monotone curve --------------------------------------------------------
282
+
283
+ /**
284
+ * Fritsch–Carlson monotone cubic tangents — the `curve="monotone"`
285
+ * recharts draws, so a smoothed series never overshoots its own points.
286
+ */
287
+ function monotoneTangents(xs: number[], ys: number[]): number[] {
288
+ const m = xs.length;
289
+ const t = new Array<number>(m);
290
+ if (m < 2) return t.fill(0);
291
+ const s: number[] = [];
292
+ for (let i = 0; i < m - 1; i++) {
293
+ const h = xs[i + 1] - xs[i];
294
+ s.push(h === 0 ? 0 : (ys[i + 1] - ys[i]) / h);
295
+ }
296
+ t[0] = s[0];
297
+ t[m - 1] = s[m - 2];
298
+ for (let i = 1; i < m - 1; i++) {
299
+ t[i] = s[i - 1] * s[i] <= 0 ? 0 : (s[i - 1] + s[i]) / 2;
300
+ }
301
+ for (let i = 0; i < m - 1; i++) {
302
+ if (s[i] === 0) {
303
+ t[i] = 0;
304
+ t[i + 1] = 0;
305
+ continue;
306
+ }
307
+ const a = t[i] / s[i];
308
+ const b = t[i + 1] / s[i];
309
+ const len = a * a + b * b;
310
+ if (len > 9) {
311
+ const scale = 3 / Math.sqrt(len);
312
+ t[i] = scale * a * s[i];
313
+ t[i + 1] = scale * b * s[i];
314
+ }
315
+ }
316
+ return t;
317
+ }
318
+
319
+ /** Emit one already-collected run of points into the current path. */
320
+ function emitRun(
321
+ ctx: PlotContext,
322
+ xs: number[],
323
+ ys: number[],
324
+ curve: SeriesSpec['curve'],
325
+ move: boolean,
326
+ ): void {
327
+ const m = xs.length;
328
+ if (m === 0) return;
329
+ if (move) ctx.moveTo!(xs[0], ys[0]);
330
+ else ctx.lineTo!(xs[0], ys[0]);
331
+ if (curve === 'monotone' && m > 2 && ctx.bezierCurveTo) {
332
+ const t = monotoneTangents(xs, ys);
333
+ for (let i = 0; i < m - 1; i++) {
334
+ const h = (xs[i + 1] - xs[i]) / 3;
335
+ ctx.bezierCurveTo(
336
+ xs[i] + h,
337
+ ys[i] + t[i] * h,
338
+ xs[i + 1] - h,
339
+ ys[i + 1] - t[i + 1] * h,
340
+ xs[i + 1],
341
+ ys[i + 1],
342
+ );
343
+ }
344
+ return;
345
+ }
346
+ if (curve === 'step') {
347
+ for (let i = 1; i < m; i++) {
348
+ ctx.lineTo!(xs[i], ys[i - 1]);
349
+ ctx.lineTo!(xs[i], ys[i]);
350
+ }
351
+ return;
352
+ }
353
+ for (let i = 1; i < m; i++) ctx.lineTo!(xs[i], ys[i]);
354
+ }
355
+
356
+ // --- line / area -----------------------------------------------------------
357
+
358
+ /** Clamp a pixel span to the plot; null when it misses entirely. */
359
+ function clampSpan(
360
+ plot: PlotRect,
361
+ top: number,
362
+ bottom: number,
363
+ ): [number, number] | null {
364
+ const y0 = Math.max(plot.y, top);
365
+ const y1 = Math.min(plot.y + plot.height, bottom);
366
+ if (y1 <= y0 - 0.5) return null;
367
+ return [y0, Math.max(y1, y0 + 1)];
368
+ }
369
+
370
+ function baseValueAt(g: SeriesGeometry, i: number): number {
371
+ return typeof g.base === 'number' ? g.base : (g.base.values[i] as number);
372
+ }
373
+
374
+ /**
375
+ * A line or area series. Sparse: a stroked (and for areas, filled) path
376
+ * through the real points. Dense: per-column min/max spans bridged with the
377
+ * previous column's closing value, batched into one request — the M4
378
+ * rendering, which is pixel-identical to drawing every point.
379
+ */
380
+ export function renderLineArea(env: SeriesEnv, g: SeriesGeometry): void {
381
+ const { ctx, plot, yScale, stats } = env;
382
+ const [i0, i1] = visibleRange(env, g);
383
+ const count = Math.max(0, i1 - i0);
384
+ stats.pointsSpanned += count;
385
+ const isArea = g.spec.type === 'area';
386
+ if (count < 2) {
387
+ stats.series.push({ id: g.spec.id, mode: 'skipped', points: count });
388
+ return;
389
+ }
390
+
391
+ const density = count / Math.max(1, plot.width);
392
+ if (density <= DENSE_PPX && canPath(ctx) && ctx.stroke) {
393
+ // ---- sparse: real geometry. Runs split at NaN, each carrying its own
394
+ // base edge so an area's return path is collected in the same walk.
395
+ //
396
+ // Points sharing (nearly) one pixel column collapse to a single
397
+ // ordered vertical pair — the same envelope the dense branch draws, so
398
+ // the two modes agree at their boundary, and a burst-heavy stream (a
399
+ // few samples per timestamp) strokes a third of the points for
400
+ // identical pixels. History worth keeping: this collapse began as a
401
+ // correctness workaround — ntk's stroke extruder emitted NaN join
402
+ // geometry on same-x sub-pixel hairpins (ntk#259; invisible on the
403
+ // headless server, origin-wedges on a real one), fixed in ntk 7.6.1
404
+ // (ntk#260, pinned via core ceb9da5) — and it still keeps any older
405
+ // extruder in an app's tree out of that input by construction.
406
+ const runsX: number[][] = [];
407
+ const runsY: number[][] = [];
408
+ const runsB: number[][] = [];
409
+ let xs: number[] = [];
410
+ let ys: number[] = [];
411
+ let bs: number[] = [];
412
+ const yv = g.y.values;
413
+ const flush = () => {
414
+ if (xs.length) {
415
+ runsX.push(xs);
416
+ runsY.push(ys);
417
+ runsB.push(bs);
418
+ xs = [];
419
+ ys = [];
420
+ bs = [];
421
+ }
422
+ };
423
+ // one pending pixel column: px, first/min/max y, the area base
424
+ const COL_EPS = 0.5;
425
+ let colPx = NaN;
426
+ let colFirst = 0;
427
+ let colMin = 0;
428
+ let colMax = 0;
429
+ let colBase = 0;
430
+ let colCount = 0;
431
+ const emitColumn = () => {
432
+ if (colCount === 0) return;
433
+ if (colCount === 1) {
434
+ xs.push(colPx);
435
+ ys.push(colFirst);
436
+ if (isArea) bs.push(colBase);
437
+ } else {
438
+ // enter at the extreme nearer the first sample, leave at the other:
439
+ // one vertical segment, no reversal inside the column
440
+ const enterMin =
441
+ Math.abs(colFirst - colMin) <= Math.abs(colFirst - colMax);
442
+ xs.push(colPx, colPx);
443
+ ys.push(enterMin ? colMin : colMax, enterMin ? colMax : colMin);
444
+ if (isArea) bs.push(colBase, colBase);
445
+ }
446
+ colCount = 0;
447
+ colPx = NaN;
448
+ };
449
+ for (let i = i0; i < i1; i++) {
450
+ const v = yv[i] as number;
451
+ const py = yScale.scale(v);
452
+ // isFinite, not isNaN: an index past a snapshot's end reads as
453
+ // undefined, and undefined is not NaN — both are gaps, not points
454
+ if (!Number.isFinite(py)) {
455
+ emitColumn();
456
+ flush();
457
+ continue;
458
+ }
459
+ const px = pxAt(env, g, i);
460
+ if (!Number.isFinite(px)) {
461
+ emitColumn();
462
+ flush();
463
+ continue;
464
+ }
465
+ if (colCount > 0 && Math.abs(px - colPx) < COL_EPS) {
466
+ if (py < colMin) colMin = py;
467
+ if (py > colMax) colMax = py;
468
+ colCount++;
469
+ continue;
470
+ }
471
+ emitColumn();
472
+ colPx = px;
473
+ colFirst = colMin = colMax = py;
474
+ colCount = 1;
475
+ if (isArea) {
476
+ const b = baseValueAt(g, i);
477
+ colBase = yScale.scale(Number.isNaN(b) ? 0 : b);
478
+ }
479
+ }
480
+ emitColumn();
481
+ flush();
482
+
483
+ if (isArea && ctx.fill) {
484
+ // fill each run down to its base edge, walked back with the same
485
+ // curve — a stacked layer's base is the layer below's top, so the
486
+ // two paths coincide and the seam is exact
487
+ ctx.save();
488
+ if (ctx.globalAlpha !== undefined) ctx.globalAlpha = g.spec.fillOpacity;
489
+ ctx.fillStyle = g.color;
490
+ ctx.beginPath!();
491
+ for (let r = 0; r < runsX.length; r++) {
492
+ emitRun(ctx, runsX[r], runsY[r], g.spec.curve, true);
493
+ const backX = runsX[r].slice().reverse();
494
+ const backY = runsB[r].slice().reverse();
495
+ emitRun(ctx, backX, backY, g.spec.curve, false);
496
+ ctx.closePath?.();
497
+ }
498
+ ctx.fill();
499
+ ctx.restore();
500
+ stats.commands++;
501
+ stats.estimatedWireBytes += count * BYTES_PER_SEGMENT * 2;
502
+ }
503
+
504
+ ctx.save();
505
+ ctx.strokeStyle = g.color;
506
+ ctx.lineWidth = g.spec.strokeWidth;
507
+ if (count <= ROUND_JOIN_MAX) {
508
+ if (ctx.lineJoin !== undefined) ctx.lineJoin = 'round';
509
+ if (ctx.lineCap !== undefined) ctx.lineCap = 'round';
510
+ }
511
+ ctx.beginPath!();
512
+ for (let r = 0; r < runsX.length; r++) {
513
+ emitRun(ctx, runsX[r], runsY[r], g.spec.curve, true);
514
+ }
515
+ ctx.stroke();
516
+ ctx.restore();
517
+ stats.commands++;
518
+ stats.estimatedWireBytes += count * BYTES_PER_SEGMENT;
519
+
520
+ if (g.spec.dot !== false && g.spec.dot > 0) {
521
+ renderDots(env, runsX, runsY, g.spec.dot, g.color);
522
+ }
523
+ stats.series.push({ id: g.spec.id, mode: 'polyline', points: count });
524
+ return;
525
+ }
526
+
527
+ // ---- dense: per-column spans through the pyramid
528
+ const pyr = pyramidFor(g.y);
529
+ const yv = g.y.values;
530
+ const strokeRects: number[] = [];
531
+ const fillRectsArr: number[] = [];
532
+ const half = Math.max(0, (g.spec.strokeWidth - 1) / 2);
533
+ const baseConst =
534
+ typeof g.base === 'number' ? Math.round(yScale.scale(g.base)) : null;
535
+ const basePyr =
536
+ isArea && typeof g.base !== 'number' ? pyramidFor(g.base) : null;
537
+ let prevLast = NaN;
538
+ walkColumns(env, g, i0, i1, (colPx, ia, ib) => {
539
+ if (ib <= ia) {
540
+ prevLast = NaN;
541
+ return;
542
+ }
543
+ minMaxRange(pyr, yv, ia, ib, mm);
544
+ if (mm.min > mm.max) {
545
+ prevLast = NaN;
546
+ return;
547
+ }
548
+ const closing = lastFinite(yv, ia, ib);
549
+ let lo = mm.min;
550
+ let hi = mm.max;
551
+ if (!Number.isNaN(prevLast)) {
552
+ if (prevLast < lo) lo = prevLast;
553
+ if (prevLast > hi) hi = prevLast;
554
+ }
555
+ prevLast = closing;
556
+ const span = clampSpan(
557
+ env.plot,
558
+ Math.round(yScale.scale(hi) - half),
559
+ Math.round(yScale.scale(lo) + half),
560
+ );
561
+ if (span) strokeRects.push(colPx, span[0], 1, span[1] - span[0]);
562
+
563
+ if (isArea && !Number.isNaN(closing)) {
564
+ let basePx: number;
565
+ if (baseConst !== null) {
566
+ basePx = baseConst;
567
+ } else {
568
+ const baseCol = g.base as NumericColumn;
569
+ minMaxRange(basePyr!, baseCol.values, ia, ib, mm);
570
+ const baseClosing = lastFinite(baseCol.values, ia, ib);
571
+ basePx = Math.round(
572
+ yScale.scale(Number.isNaN(baseClosing) ? 0 : baseClosing),
573
+ );
574
+ }
575
+ const topPx = Math.round(yScale.scale(closing));
576
+ const fillSpan = clampSpan(
577
+ env.plot,
578
+ Math.min(topPx, basePx),
579
+ Math.max(topPx, basePx),
580
+ );
581
+ if (fillSpan) {
582
+ fillRectsArr.push(colPx, fillSpan[0], 1, fillSpan[1] - fillSpan[0]);
583
+ }
584
+ }
585
+ });
586
+
587
+ if (isArea && fillRectsArr.length) {
588
+ ctx.save();
589
+ if (ctx.globalAlpha !== undefined) ctx.globalAlpha = g.spec.fillOpacity;
590
+ ctx.fillStyle = g.color;
591
+ fillRects(ctx, fillRectsArr);
592
+ ctx.restore();
593
+ stats.commands++;
594
+ stats.estimatedWireBytes += (fillRectsArr.length / 4) * BYTES_PER_RECT;
595
+ }
596
+ if (strokeRects.length) {
597
+ ctx.save();
598
+ ctx.fillStyle = g.color;
599
+ fillRects(ctx, strokeRects);
600
+ ctx.restore();
601
+ stats.commands++;
602
+ stats.estimatedWireBytes += (strokeRects.length / 4) * BYTES_PER_RECT;
603
+ }
604
+ stats.series.push({ id: g.spec.id, mode: 'columns', points: count });
605
+ }
606
+
607
+ function renderDots(
608
+ env: SeriesEnv,
609
+ runsX: number[][],
610
+ runsY: number[][],
611
+ r: number,
612
+ color: string,
613
+ ): void {
614
+ const { ctx, stats } = env;
615
+ let total = 0;
616
+ for (const run of runsX) total += run.length;
617
+ if (total <= CIRCLE_MAX && ctx.arc && ctx.fill && ctx.beginPath) {
618
+ ctx.save();
619
+ ctx.fillStyle = color;
620
+ for (let k = 0; k < runsX.length; k++) {
621
+ for (let i = 0; i < runsX[k].length; i++) {
622
+ ctx.beginPath();
623
+ ctx.arc(runsX[k][i], runsY[k][i], r, 0, Math.PI * 2);
624
+ ctx.fill();
625
+ }
626
+ }
627
+ ctx.restore();
628
+ stats.commands += total;
629
+ stats.estimatedWireBytes += total * BYTES_PER_SEGMENT;
630
+ return;
631
+ }
632
+ const rects: number[] = [];
633
+ for (let k = 0; k < runsX.length; k++) {
634
+ for (let i = 0; i < runsX[k].length; i++) {
635
+ rects.push(
636
+ Math.round(runsX[k][i] - r),
637
+ Math.round(runsY[k][i] - r),
638
+ Math.round(2 * r),
639
+ Math.round(2 * r),
640
+ );
641
+ }
642
+ }
643
+ ctx.save();
644
+ ctx.fillStyle = color;
645
+ fillRects(ctx, rects);
646
+ ctx.restore();
647
+ stats.commands++;
648
+ stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
649
+ }
650
+
651
+ // --- bars ------------------------------------------------------------------
652
+
653
+ /**
654
+ * Bars over a band scale. The normal case is one `fillRects` batch per
655
+ * series; rounded tops keep their radius only while the count stays small
656
+ * enough that per-bar paths are cheaper than they are pretty; and a series
657
+ * with more bars than pixels collapses to the same per-column envelope a
658
+ * dense line uses — a 100k-bar histogram is a silhouette either way.
659
+ */
660
+ export function renderBars(env: SeriesEnv, g: SeriesGeometry): void {
661
+ const { ctx, yScale, stats } = env;
662
+ if (env.xScale.kind !== 'band') {
663
+ stats.series.push({ id: g.spec.id, mode: 'skipped', points: 0 });
664
+ return;
665
+ }
666
+ const band = env.xScale;
667
+ const n = Math.min(g.y.n, band.count);
668
+ stats.pointsSpanned += n;
669
+ const yv = g.y.values;
670
+
671
+ if (band.bandwidth / g.group.count < 1 || n > env.plot.width * 2) {
672
+ // envelope: per-column span from the base to the tallest bar
673
+ const pyr = pyramidFor(g.y);
674
+ const rects: number[] = [];
675
+ const cols = Math.max(1, Math.round(env.plot.width));
676
+ const basePx = Math.round(
677
+ yScale.scale(typeof g.base === 'number' ? g.base : 0),
678
+ );
679
+ let prev = 0;
680
+ for (let c = 0; c < cols; c++) {
681
+ const ib = c + 1 >= cols ? n : Math.floor((n * (c + 1)) / cols);
682
+ if (ib > prev) {
683
+ minMaxRange(pyr, yv, prev, ib, mm);
684
+ if (mm.min <= mm.max) {
685
+ const hiPx = Math.round(yScale.scale(mm.max));
686
+ const loPx = Math.round(yScale.scale(Math.min(mm.min, 0)));
687
+ const span = clampSpan(
688
+ env.plot,
689
+ Math.min(hiPx, loPx, basePx),
690
+ Math.max(hiPx, loPx, basePx),
691
+ );
692
+ if (span) rects.push(env.plot.x + c, span[0], 1, span[1] - span[0]);
693
+ }
694
+ }
695
+ prev = ib;
696
+ }
697
+ ctx.save();
698
+ ctx.fillStyle = g.color;
699
+ fillRects(ctx, rects);
700
+ ctx.restore();
701
+ stats.commands++;
702
+ stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
703
+ stats.series.push({ id: g.spec.id, mode: 'columns', points: n });
704
+ return;
705
+ }
706
+
707
+ const slot = band.bandwidth / g.group.count;
708
+ const gap = g.group.count > 1 && slot > 3 ? 1 : 0;
709
+ const w = Math.max(1, Math.round(slot - gap));
710
+ const rounded =
711
+ g.spec.barRadius > 0 &&
712
+ n <= BAR_RADIUS_MAX &&
713
+ canPath(ctx) &&
714
+ typeof ctx.roundRect === 'function' &&
715
+ typeof ctx.fill === 'function';
716
+ const rects: number[] = [];
717
+ ctx.save();
718
+ ctx.fillStyle = g.color;
719
+ for (let i = 0; i < n; i++) {
720
+ const v = yv[i] as number;
721
+ if (Number.isNaN(v)) continue;
722
+ const base = baseValueAt(g, i);
723
+ const x = Math.round(band.scale(i) + slot * g.group.index);
724
+ const y0 = yScale.scale(v);
725
+ const y1 = yScale.scale(Number.isNaN(base) ? 0 : base);
726
+ const top = Math.round(Math.min(y0, y1));
727
+ const h = Math.max(1, Math.round(Math.abs(y1 - y0)));
728
+ if (rounded) {
729
+ const r = Math.min(g.spec.barRadius, w / 2, h);
730
+ ctx.beginPath!();
731
+ // round the value end only — the stack seam and the axis stay square
732
+ const radii = y0 <= y1 ? [r, r, 0, 0] : [0, 0, r, r];
733
+ ctx.roundRect!(x, top, w, h, radii);
734
+ ctx.fill!();
735
+ stats.commands++;
736
+ stats.estimatedWireBytes += BYTES_PER_RECT * 3;
737
+ } else {
738
+ rects.push(x, top, w, h);
739
+ }
740
+ }
741
+ if (rects.length) {
742
+ fillRects(ctx, rects);
743
+ stats.commands++;
744
+ stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
745
+ }
746
+ ctx.restore();
747
+ stats.series.push({
748
+ id: g.spec.id,
749
+ mode: rounded ? 'rects' : 'bars',
750
+ points: n,
751
+ });
752
+ }
753
+
754
+ // --- scatter ---------------------------------------------------------------
755
+
756
+ /** The occupancy grid a dense scatter reduces to: point counts per
757
+ * dot-sized cell, extended incrementally as data appends. */
758
+ export interface ScatterGrid {
759
+ key: string;
760
+ cell: number;
761
+ gw: number;
762
+ gh: number;
763
+ counts: Uint32Array;
764
+ occupied: number;
765
+ maxCount: number;
766
+ /** points consumed so far — the incremental cursor */
767
+ consumedN: number;
768
+ /** rects per alpha bucket, rebuilt only when the grid changed */
769
+ buckets: number[][] | null;
770
+ }
771
+
772
+ export function makeScatterGrid(
773
+ key: string,
774
+ cell: number,
775
+ gw: number,
776
+ gh: number,
777
+ ): ScatterGrid {
778
+ return {
779
+ key,
780
+ cell,
781
+ gw,
782
+ gh,
783
+ counts: new Uint32Array(gw * gh),
784
+ occupied: 0,
785
+ maxCount: 0,
786
+ consumedN: 0,
787
+ buckets: null,
788
+ };
789
+ }
790
+
791
+ const ALPHA_LEVELS = 8;
792
+
793
+ /** #rgb/#rrggbb/#rrggbbaa → [r,g,b,a?]; null for anything fancier, which
794
+ * simply keeps the rect path. */
795
+ export function parseHexColor(
796
+ color: string,
797
+ ): [number, number, number, number] | null {
798
+ if (!color.startsWith('#')) return null;
799
+ const hex = color.slice(1);
800
+ const digit = (c: string) => parseInt(c, 16);
801
+ if (hex.length === 3) {
802
+ return [digit(hex[0]) * 17, digit(hex[1]) * 17, digit(hex[2]) * 17, 255];
803
+ }
804
+ if (hex.length === 6 || hex.length === 8) {
805
+ const r = parseInt(hex.slice(0, 2), 16);
806
+ const gg = parseInt(hex.slice(2, 4), 16);
807
+ const b = parseInt(hex.slice(4, 6), 16);
808
+ const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) : 255;
809
+ if ([r, gg, b, a].some(Number.isNaN)) return null;
810
+ return [r, gg, b, a];
811
+ }
812
+ return null;
813
+ }
814
+
815
+ /**
816
+ * A scatter series. A handful of points draw directly (circles, then one
817
+ * batch of squares); past that the series reduces to the occupancy grid —
818
+ * a million coincident points are one cell — rendered as per-alpha-level
819
+ * `fillRects` batches, or as one composited density image once rectangles
820
+ * would cost more bytes than pixels.
821
+ */
822
+ export function renderScatter(env: SeriesEnv, g: SeriesGeometry): void {
823
+ const { ctx, plot, yScale, stats } = env;
824
+ const n = g.x ? Math.min(g.y.n, g.x.n) : g.y.n;
825
+ stats.pointsSpanned += n;
826
+ const size = Math.max(1, Math.round(g.spec.size));
827
+ const yv = g.y.values;
828
+
829
+ if (n <= DIRECT_SCATTER_MAX) {
830
+ const xs: number[] = [];
831
+ const ys: number[] = [];
832
+ for (let i = 0; i < n; i++) {
833
+ const v = yv[i] as number;
834
+ if (Number.isNaN(v)) continue;
835
+ const px = pxAt(env, g, i);
836
+ const py = yScale.scale(v);
837
+ if (px < plot.x || px > plot.x + plot.width) continue;
838
+ xs.push(px);
839
+ ys.push(py);
840
+ }
841
+ renderDots(env, [xs], [ys], size / 2 + 0.5, g.color);
842
+ stats.series.push({ id: g.spec.id, mode: 'rects', points: n });
843
+ return;
844
+ }
845
+
846
+ // ---- dense: occupancy grid
847
+ const cell = size;
848
+ const gw = Math.max(1, Math.ceil(plot.width / cell));
849
+ const gh = Math.max(1, Math.ceil(plot.height / cell));
850
+ const xScale = env.xScale;
851
+ const domKey =
852
+ xScale.kind === 'band' ? `b${xScale.count}` : `${xScale.d0},${xScale.d1}`;
853
+ const key = `${cell}|${gw}|${gh}|${domKey}|${yScale.d0},${yScale.d1}|${g.y.epoch}`;
854
+ const grid = env.host.scatterGrid(g.spec.id, key, n);
855
+
856
+ if (grid.consumedN < n) {
857
+ const kx = gw / plot.width;
858
+ const ky = gh / plot.height;
859
+ for (let i = grid.consumedN; i < n; i++) {
860
+ const v = yv[i] as number;
861
+ if (Number.isNaN(v)) continue;
862
+ const px = pxAt(env, g, i) - plot.x;
863
+ const py = yScale.scale(v) - plot.y;
864
+ const cx = Math.floor(px * kx);
865
+ const cy = Math.floor(py * ky);
866
+ if (cx < 0 || cx >= gw || cy < 0 || cy >= gh) continue;
867
+ const at = cy * gw + cx;
868
+ const before = grid.counts[at]++;
869
+ if (before === 0) grid.occupied++;
870
+ if (before + 1 > grid.maxCount) grid.maxCount = before + 1;
871
+ }
872
+ grid.consumedN = n;
873
+ grid.buckets = null;
874
+ }
875
+
876
+ // rectangles vs pixels: the byte crossover, computed
877
+ const rectBytes = grid.occupied * BYTES_PER_RECT;
878
+ const imageBytes = plot.width * plot.height * BYTES_PER_PIXEL;
879
+ const rgb = parseHexColor(g.color);
880
+ if (rectBytes > imageBytes && rgb) {
881
+ const drawn = env.host.blitImage(
882
+ plot.x,
883
+ plot.y,
884
+ gw * cell,
885
+ gh * cell,
886
+ (data) => {
887
+ const [r, gg, b] = rgb;
888
+ for (let cy = 0; cy < gh; cy++) {
889
+ for (let cx = 0; cx < gw; cx++) {
890
+ const count = grid.counts[cy * gw + cx];
891
+ if (count === 0) continue;
892
+ const a = Math.round(
893
+ 255 * (0.3 + 0.7 * Math.sqrt(count / grid.maxCount)),
894
+ );
895
+ for (let dy = 0; dy < cell; dy++) {
896
+ let at = ((cy * cell + dy) * gw * cell + cx * cell) * 4;
897
+ for (let dx = 0; dx < cell; dx++) {
898
+ data[at] = r;
899
+ data[at + 1] = gg;
900
+ data[at + 2] = b;
901
+ data[at + 3] = a;
902
+ at += 4;
903
+ }
904
+ }
905
+ }
906
+ }
907
+ },
908
+ // same grid content + colour → the host recomposites its retained
909
+ // surface: no refill, no upload
910
+ `${grid.key}#${grid.consumedN}|${g.color}`,
911
+ );
912
+ if (drawn) {
913
+ stats.commands++;
914
+ stats.estimatedWireBytes += imageBytes;
915
+ stats.series.push({ id: g.spec.id, mode: 'image', points: n });
916
+ return;
917
+ }
918
+ }
919
+
920
+ if (!grid.buckets) {
921
+ // Plot-LOCAL coordinates, translated at draw time. Nothing that lives
922
+ // across frames may bake in the plot's window position: every part of
923
+ // the cache key stays equal while a scroll or a section reflow moves
924
+ // the plot rect, and window-space buckets then redraw at the old
925
+ // origin — sliced flat by the series clip, or clipped away entirely.
926
+ const buckets: number[][] = Array.from({ length: ALPHA_LEVELS }, () => []);
927
+ for (let cy = 0; cy < gh; cy++) {
928
+ for (let cx = 0; cx < gw; cx++) {
929
+ const count = grid.counts[cy * gw + cx];
930
+ if (count === 0) continue;
931
+ const level = Math.min(
932
+ ALPHA_LEVELS - 1,
933
+ Math.floor(Math.sqrt(count / grid.maxCount) * ALPHA_LEVELS),
934
+ );
935
+ buckets[level].push(cx * cell, cy * cell, cell, cell);
936
+ }
937
+ }
938
+ grid.buckets = buckets;
939
+ }
940
+ ctx.save();
941
+ ctx.fillStyle = g.color;
942
+ for (let level = 0; level < ALPHA_LEVELS; level++) {
943
+ const local = grid.buckets[level];
944
+ if (!local.length) continue;
945
+ if (ctx.globalAlpha !== undefined) {
946
+ ctx.globalAlpha = 0.3 + (0.7 * (level + 1)) / ALPHA_LEVELS;
947
+ }
948
+ // translate manually: ctx.translate would kick fillRects off ntk's
949
+ // single-FillRectangles fast path (it requires an identity transform)
950
+ const rects = new Array<number>(local.length);
951
+ for (let i = 0; i < local.length; i += 4) {
952
+ rects[i] = local[i] + plot.x;
953
+ rects[i + 1] = local[i + 1] + plot.y;
954
+ rects[i + 2] = local[i + 2];
955
+ rects[i + 3] = local[i + 3];
956
+ }
957
+ fillRects(ctx, rects);
958
+ stats.commands++;
959
+ stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
960
+ }
961
+ ctx.restore();
962
+ stats.series.push({ id: g.spec.id, mode: 'columns', points: n });
963
+ }
964
+
965
+ /** One dispatch for the node's series loop. */
966
+ export function renderSeries(env: SeriesEnv, g: SeriesGeometry): void {
967
+ switch (g.spec.type) {
968
+ case 'line':
969
+ case 'area':
970
+ renderLineArea(env, g);
971
+ break;
972
+ case 'bar':
973
+ renderBars(env, g);
974
+ break;
975
+ case 'scatter':
976
+ renderScatter(env, g);
977
+ break;
978
+ }
979
+ }
980
+
981
+ /** Re-exported for the node; keeps `data.js` out of its import list. */
982
+ export { pyramidFor, xIndexFor };