@react-x11/components 0.8.0 → 0.10.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 (721) hide show
  1. package/README.md +105 -38
  2. package/dist/charts/node.d.ts +12 -2
  3. package/dist/charts/node.d.ts.map +1 -1
  4. package/dist/charts/node.js +50 -16
  5. package/dist/charts/node.js.map +1 -1
  6. package/dist/charts/render.d.ts +12 -3
  7. package/dist/charts/render.d.ts.map +1 -1
  8. package/dist/charts/render.js +94 -25
  9. package/dist/charts/render.js.map +1 -1
  10. package/dist/code/index.d.ts.map +1 -1
  11. package/dist/code/index.js +3 -1
  12. package/dist/code/index.js.map +1 -1
  13. package/dist/code-editor/completion.d.ts.map +1 -1
  14. package/dist/code-editor/completion.js +3 -2
  15. package/dist/code-editor/completion.js.map +1 -1
  16. package/dist/code-editor/index.d.ts.map +1 -1
  17. package/dist/code-editor/index.js +19 -0
  18. package/dist/code-editor/index.js.map +1 -1
  19. package/dist/code-editor/node.d.ts +177 -7
  20. package/dist/code-editor/node.d.ts.map +1 -1
  21. package/dist/code-editor/node.js +1329 -164
  22. package/dist/code-editor/node.js.map +1 -1
  23. package/dist/code-language/languages/glsl.d.ts.map +1 -1
  24. package/dist/code-language/languages/glsl.js +10 -2
  25. package/dist/code-language/languages/glsl.js.map +1 -1
  26. package/dist/code-language/languages/javascript.d.ts.map +1 -1
  27. package/dist/code-language/languages/javascript.js +18 -3
  28. package/dist/code-language/languages/javascript.js.map +1 -1
  29. package/dist/code-language/languages/json.d.ts.map +1 -1
  30. package/dist/code-language/languages/json.js +10 -2
  31. package/dist/code-language/languages/json.js.map +1 -1
  32. package/dist/code-language/languages/shell.d.ts.map +1 -1
  33. package/dist/code-language/languages/shell.js +10 -2
  34. package/dist/code-language/languages/shell.js.map +1 -1
  35. package/dist/code-language/languages/sql.d.ts.map +1 -1
  36. package/dist/code-language/languages/sql.js +20 -2
  37. package/dist/code-language/languages/sql.js.map +1 -1
  38. package/dist/code-language/stream.d.ts +22 -0
  39. package/dist/code-language/stream.d.ts.map +1 -1
  40. package/dist/code-language/stream.js +259 -9
  41. package/dist/code-language/stream.js.map +1 -1
  42. package/dist/code-language/types.d.ts +5 -4
  43. package/dist/code-language/types.d.ts.map +1 -1
  44. package/dist/codeblock/index.d.ts +13 -2
  45. package/dist/codeblock/index.d.ts.map +1 -1
  46. package/dist/codeblock/index.js +20 -3
  47. package/dist/codeblock/index.js.map +1 -1
  48. package/dist/embed/client.d.ts +48 -3
  49. package/dist/embed/client.d.ts.map +1 -1
  50. package/dist/embed/client.js +79 -5
  51. package/dist/embed/client.js.map +1 -1
  52. package/dist/embed/index.d.ts +1 -1
  53. package/dist/embed/index.d.ts.map +1 -1
  54. package/dist/embed/index.js +1 -1
  55. package/dist/embed/index.js.map +1 -1
  56. package/dist/flow/draw.d.ts +50 -0
  57. package/dist/flow/draw.d.ts.map +1 -1
  58. package/dist/flow/draw.js +132 -33
  59. package/dist/flow/draw.js.map +1 -1
  60. package/dist/flow/gl/color.d.ts +13 -0
  61. package/dist/flow/gl/color.d.ts.map +1 -0
  62. package/dist/flow/gl/color.js +82 -0
  63. package/dist/flow/gl/color.js.map +1 -0
  64. package/dist/flow/gl/index.d.ts +60 -0
  65. package/dist/flow/gl/index.d.ts.map +1 -0
  66. package/dist/flow/gl/index.js +283 -0
  67. package/dist/flow/gl/index.js.map +1 -0
  68. package/dist/flow/gl/pack.d.ts +133 -0
  69. package/dist/flow/gl/pack.d.ts.map +1 -0
  70. package/dist/flow/gl/pack.js +408 -0
  71. package/dist/flow/gl/pack.js.map +1 -0
  72. package/dist/flow/gl/renderer.d.ts +95 -0
  73. package/dist/flow/gl/renderer.d.ts.map +1 -0
  74. package/dist/flow/gl/renderer.js +459 -0
  75. package/dist/flow/gl/renderer.js.map +1 -0
  76. package/dist/flow/gl/shaders.d.ts +79 -0
  77. package/dist/flow/gl/shaders.d.ts.map +1 -0
  78. package/dist/flow/gl/shaders.js +346 -0
  79. package/dist/flow/gl/shaders.js.map +1 -0
  80. package/dist/flow/gl/text.d.ts +318 -0
  81. package/dist/flow/gl/text.d.ts.map +1 -0
  82. package/dist/flow/gl/text.js +1103 -0
  83. package/dist/flow/gl/text.js.map +1 -0
  84. package/dist/flow/index.d.ts +1 -1
  85. package/dist/flow/index.d.ts.map +1 -1
  86. package/dist/flow/index.js +619 -64
  87. package/dist/flow/index.js.map +1 -1
  88. package/dist/flow/node.d.ts +621 -72
  89. package/dist/flow/node.d.ts.map +1 -1
  90. package/dist/flow/node.js +2253 -1018
  91. package/dist/flow/node.js.map +1 -1
  92. package/dist/flow/paint.d.ts +35 -0
  93. package/dist/flow/paint.d.ts.map +1 -0
  94. package/dist/flow/paint.js +393 -0
  95. package/dist/flow/paint.js.map +1 -0
  96. package/dist/flow/paths.d.ts +14 -0
  97. package/dist/flow/paths.d.ts.map +1 -1
  98. package/dist/flow/paths.js +45 -19
  99. package/dist/flow/paths.js.map +1 -1
  100. package/dist/flow/scene.d.ts +584 -0
  101. package/dist/flow/scene.d.ts.map +1 -0
  102. package/dist/flow/scene.js +1453 -0
  103. package/dist/flow/scene.js.map +1 -0
  104. package/dist/flow/types.d.ts +111 -1
  105. package/dist/flow/types.d.ts.map +1 -1
  106. package/dist/html/controls.d.ts +28 -0
  107. package/dist/html/controls.d.ts.map +1 -1
  108. package/dist/html/controls.js +52 -2
  109. package/dist/html/controls.js.map +1 -1
  110. package/dist/html/css/calc.d.ts +14 -0
  111. package/dist/html/css/calc.d.ts.map +1 -0
  112. package/dist/html/css/calc.js +344 -0
  113. package/dist/html/css/calc.js.map +1 -0
  114. package/dist/html/css/cascade.d.ts +240 -6
  115. package/dist/html/css/cascade.d.ts.map +1 -1
  116. package/dist/html/css/cascade.js +1327 -66
  117. package/dist/html/css/cascade.js.map +1 -1
  118. package/dist/html/css/color.d.ts +23 -0
  119. package/dist/html/css/color.d.ts.map +1 -0
  120. package/dist/html/css/color.js +740 -0
  121. package/dist/html/css/color.js.map +1 -0
  122. package/dist/html/css/content.d.ts +92 -0
  123. package/dist/html/css/content.d.ts.map +1 -0
  124. package/dist/html/css/content.js +388 -0
  125. package/dist/html/css/content.js.map +1 -0
  126. package/dist/html/css/counter-styles.d.ts +76 -0
  127. package/dist/html/css/counter-styles.d.ts.map +1 -0
  128. package/dist/html/css/counter-styles.js +893 -0
  129. package/dist/html/css/counter-styles.js.map +1 -0
  130. package/dist/html/css/decode.d.ts +12 -0
  131. package/dist/html/css/decode.d.ts.map +1 -0
  132. package/dist/html/css/decode.js +116 -0
  133. package/dist/html/css/decode.js.map +1 -0
  134. package/dist/html/css/parse.d.ts +110 -10
  135. package/dist/html/css/parse.d.ts.map +1 -1
  136. package/dist/html/css/parse.js +1473 -180
  137. package/dist/html/css/parse.js.map +1 -1
  138. package/dist/html/css/style.d.ts +498 -15
  139. package/dist/html/css/style.d.ts.map +1 -1
  140. package/dist/html/css/style.js +3698 -206
  141. package/dist/html/css/style.js.map +1 -1
  142. package/dist/html/css/ua.d.ts.map +1 -1
  143. package/dist/html/css/ua.js +57 -11
  144. package/dist/html/css/ua.js.map +1 -1
  145. package/dist/html/css/values.d.ts +37 -3
  146. package/dist/html/css/values.d.ts.map +1 -1
  147. package/dist/html/css/values.js +122 -48
  148. package/dist/html/css/values.js.map +1 -1
  149. package/dist/html/css/vars.d.ts +52 -0
  150. package/dist/html/css/vars.d.ts.map +1 -0
  151. package/dist/html/css/vars.js +358 -0
  152. package/dist/html/css/vars.js.map +1 -0
  153. package/dist/html/dom.d.ts +30 -4
  154. package/dist/html/dom.d.ts.map +1 -1
  155. package/dist/html/dom.js +278 -17
  156. package/dist/html/dom.js.map +1 -1
  157. package/dist/html/fonts.d.ts +106 -0
  158. package/dist/html/fonts.d.ts.map +1 -0
  159. package/dist/html/fonts.js +565 -0
  160. package/dist/html/fonts.js.map +1 -0
  161. package/dist/html/gif.d.ts +15 -0
  162. package/dist/html/gif.d.ts.map +1 -0
  163. package/dist/html/gif.js +229 -0
  164. package/dist/html/gif.js.map +1 -0
  165. package/dist/html/index.d.ts +50 -11
  166. package/dist/html/index.d.ts.map +1 -1
  167. package/dist/html/index.js +115 -9
  168. package/dist/html/index.js.map +1 -1
  169. package/dist/html/layout/block.d.ts +226 -3
  170. package/dist/html/layout/block.d.ts.map +1 -1
  171. package/dist/html/layout/block.js +2937 -197
  172. package/dist/html/layout/block.js.map +1 -1
  173. package/dist/html/layout/boxes.d.ts +340 -17
  174. package/dist/html/layout/boxes.d.ts.map +1 -1
  175. package/dist/html/layout/boxes.js +1714 -182
  176. package/dist/html/layout/boxes.js.map +1 -1
  177. package/dist/html/layout/cache.d.ts +58 -0
  178. package/dist/html/layout/cache.d.ts.map +1 -0
  179. package/dist/html/layout/cache.js +224 -0
  180. package/dist/html/layout/cache.js.map +1 -0
  181. package/dist/html/layout/collapse.d.ts +45 -0
  182. package/dist/html/layout/collapse.d.ts.map +1 -0
  183. package/dist/html/layout/collapse.js +246 -0
  184. package/dist/html/layout/collapse.js.map +1 -0
  185. package/dist/html/layout/css-grid.d.ts +7 -0
  186. package/dist/html/layout/css-grid.d.ts.map +1 -0
  187. package/dist/html/layout/css-grid.js +900 -0
  188. package/dist/html/layout/css-grid.js.map +1 -0
  189. package/dist/html/layout/flex.d.ts.map +1 -1
  190. package/dist/html/layout/flex.js +1025 -89
  191. package/dist/html/layout/flex.js.map +1 -1
  192. package/dist/html/layout/floats.d.ts +45 -6
  193. package/dist/html/layout/floats.d.ts.map +1 -1
  194. package/dist/html/layout/floats.js +113 -14
  195. package/dist/html/layout/floats.js.map +1 -1
  196. package/dist/html/layout/grid-lines.d.ts +39 -0
  197. package/dist/html/layout/grid-lines.d.ts.map +1 -0
  198. package/dist/html/layout/grid-lines.js +119 -0
  199. package/dist/html/layout/grid-lines.js.map +1 -0
  200. package/dist/html/layout/grid.d.ts +53 -0
  201. package/dist/html/layout/grid.d.ts.map +1 -0
  202. package/dist/html/layout/grid.js +153 -0
  203. package/dist/html/layout/grid.js.map +1 -0
  204. package/dist/html/layout/inline.d.ts +151 -1
  205. package/dist/html/layout/inline.d.ts.map +1 -1
  206. package/dist/html/layout/inline.js +3375 -174
  207. package/dist/html/layout/inline.js.map +1 -1
  208. package/dist/html/layout/shaping.d.ts +6 -0
  209. package/dist/html/layout/shaping.d.ts.map +1 -0
  210. package/dist/html/layout/shaping.js +100 -0
  211. package/dist/html/layout/shaping.js.map +1 -0
  212. package/dist/html/layout/table.d.ts +3 -0
  213. package/dist/html/layout/table.d.ts.map +1 -1
  214. package/dist/html/layout/table.js +681 -175
  215. package/dist/html/layout/table.js.map +1 -1
  216. package/dist/html/layout/tracks.d.ts +44 -0
  217. package/dist/html/layout/tracks.d.ts.map +1 -0
  218. package/dist/html/layout/tracks.js +349 -0
  219. package/dist/html/layout/tracks.js.map +1 -0
  220. package/dist/html/node.d.ts +172 -5
  221. package/dist/html/node.d.ts.map +1 -1
  222. package/dist/html/node.js +1336 -103
  223. package/dist/html/node.js.map +1 -1
  224. package/dist/html/paint.d.ts +92 -3
  225. package/dist/html/paint.d.ts.map +1 -1
  226. package/dist/html/paint.js +3503 -141
  227. package/dist/html/paint.js.map +1 -1
  228. package/dist/html/resources.d.ts +60 -14
  229. package/dist/html/resources.d.ts.map +1 -1
  230. package/dist/html/resources.js +122 -36
  231. package/dist/html/resources.js.map +1 -1
  232. package/dist/html/surfaces.d.ts +23 -0
  233. package/dist/html/surfaces.d.ts.map +1 -0
  234. package/dist/html/surfaces.js +68 -0
  235. package/dist/html/surfaces.js.map +1 -0
  236. package/dist/html/svg.d.ts +80 -0
  237. package/dist/html/svg.d.ts.map +1 -0
  238. package/dist/html/svg.js +435 -0
  239. package/dist/html/svg.js.map +1 -0
  240. package/dist/html/url.d.ts +23 -0
  241. package/dist/html/url.d.ts.map +1 -0
  242. package/dist/html/url.js +80 -0
  243. package/dist/html/url.js.map +1 -0
  244. package/dist/index.d.ts +2 -2
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +1 -1
  247. package/dist/index.js.map +1 -1
  248. package/dist/internal/collate.d.ts +3 -0
  249. package/dist/internal/collate.d.ts.map +1 -0
  250. package/dist/internal/collate.js +11 -0
  251. package/dist/internal/collate.js.map +1 -0
  252. package/dist/{markdown → internal/markdown}/ast.d.ts +23 -0
  253. package/dist/internal/markdown/ast.d.ts.map +1 -0
  254. package/dist/internal/markdown/ast.js +22 -0
  255. package/dist/internal/markdown/ast.js.map +1 -0
  256. package/dist/internal/markdown/parse.d.ts.map +1 -0
  257. package/dist/{markdown → internal/markdown}/parse.js +221 -30
  258. package/dist/internal/markdown/parse.js.map +1 -0
  259. package/dist/internal/markdown/stringify.d.ts +4 -0
  260. package/dist/internal/markdown/stringify.d.ts.map +1 -0
  261. package/dist/internal/markdown/stringify.js +684 -0
  262. package/dist/internal/markdown/stringify.js.map +1 -0
  263. package/dist/internal/markdown/tags.d.ts.map +1 -0
  264. package/dist/internal/markdown/tags.js.map +1 -0
  265. package/dist/internal/prewarm.d.ts +18 -0
  266. package/dist/internal/prewarm.d.ts.map +1 -0
  267. package/dist/internal/prewarm.js +42 -0
  268. package/dist/internal/prewarm.js.map +1 -0
  269. package/dist/internal/scroll.d.ts +3 -2
  270. package/dist/internal/scroll.d.ts.map +1 -1
  271. package/dist/internal/scroll.js +1 -0
  272. package/dist/internal/scroll.js.map +1 -1
  273. package/dist/internal/sdf.d.ts +20 -0
  274. package/dist/internal/sdf.d.ts.map +1 -0
  275. package/dist/internal/sdf.js +216 -0
  276. package/dist/internal/sdf.js.map +1 -0
  277. package/dist/internal/splice.d.ts +12 -0
  278. package/dist/internal/splice.d.ts.map +1 -0
  279. package/dist/internal/splice.js +23 -0
  280. package/dist/internal/splice.js.map +1 -0
  281. package/dist/internal/window.d.ts +12 -0
  282. package/dist/internal/window.d.ts.map +1 -1
  283. package/dist/internal/window.js +23 -6
  284. package/dist/internal/window.js.map +1 -1
  285. package/dist/maps/anchors.d.ts +103 -0
  286. package/dist/maps/anchors.d.ts.map +1 -0
  287. package/dist/maps/anchors.js +790 -0
  288. package/dist/maps/anchors.js.map +1 -0
  289. package/dist/maps/controller.d.ts +340 -0
  290. package/dist/maps/controller.d.ts.map +1 -0
  291. package/dist/maps/controller.js +822 -0
  292. package/dist/maps/controller.js.map +1 -0
  293. package/dist/maps/gl/buckets.d.ts +99 -0
  294. package/dist/maps/gl/buckets.d.ts.map +1 -0
  295. package/dist/maps/gl/buckets.js +365 -0
  296. package/dist/maps/gl/buckets.js.map +1 -0
  297. package/dist/maps/gl/build-worker.d.ts +15 -0
  298. package/dist/maps/gl/build-worker.d.ts.map +1 -0
  299. package/dist/maps/gl/build-worker.js +44 -0
  300. package/dist/maps/gl/build-worker.js.map +1 -0
  301. package/dist/maps/gl/color.d.ts +8 -0
  302. package/dist/maps/gl/color.d.ts.map +1 -0
  303. package/dist/maps/gl/color.js +57 -0
  304. package/dist/maps/gl/color.js.map +1 -0
  305. package/dist/maps/gl/cover.d.ts +70 -0
  306. package/dist/maps/gl/cover.d.ts.map +1 -0
  307. package/dist/maps/gl/cover.js +137 -0
  308. package/dist/maps/gl/cover.js.map +1 -0
  309. package/dist/maps/gl/index.d.ts +3 -0
  310. package/dist/maps/gl/index.d.ts.map +1 -0
  311. package/dist/maps/gl/index.js +20 -0
  312. package/dist/maps/gl/index.js.map +1 -0
  313. package/dist/maps/gl/markers.d.ts +28 -0
  314. package/dist/maps/gl/markers.d.ts.map +1 -0
  315. package/dist/maps/gl/markers.js +60 -0
  316. package/dist/maps/gl/markers.js.map +1 -0
  317. package/dist/maps/gl/overlays.d.ts +68 -0
  318. package/dist/maps/gl/overlays.d.ts.map +1 -0
  319. package/dist/maps/gl/overlays.js +300 -0
  320. package/dist/maps/gl/overlays.js.map +1 -0
  321. package/dist/maps/gl/pane.d.ts +12 -0
  322. package/dist/maps/gl/pane.d.ts.map +1 -0
  323. package/dist/maps/gl/pane.js +37 -0
  324. package/dist/maps/gl/pane.js.map +1 -0
  325. package/dist/maps/gl/placement.d.ts +124 -0
  326. package/dist/maps/gl/placement.d.ts.map +1 -0
  327. package/dist/maps/gl/placement.js +642 -0
  328. package/dist/maps/gl/placement.js.map +1 -0
  329. package/dist/maps/gl/renderer.d.ts +384 -0
  330. package/dist/maps/gl/renderer.d.ts.map +1 -0
  331. package/dist/maps/gl/renderer.js +1184 -0
  332. package/dist/maps/gl/renderer.js.map +1 -0
  333. package/dist/maps/gl/shaders.d.ts +121 -0
  334. package/dist/maps/gl/shaders.d.ts.map +1 -0
  335. package/dist/maps/gl/shaders.js +453 -0
  336. package/dist/maps/gl/shaders.js.map +1 -0
  337. package/dist/maps/gl/store.d.ts +125 -0
  338. package/dist/maps/gl/store.d.ts.map +1 -0
  339. package/dist/maps/gl/store.js +512 -0
  340. package/dist/maps/gl/store.js.map +1 -0
  341. package/dist/maps/gl/text.d.ts +283 -0
  342. package/dist/maps/gl/text.d.ts.map +1 -0
  343. package/dist/maps/gl/text.js +698 -0
  344. package/dist/maps/gl/text.js.map +1 -0
  345. package/dist/maps/gl/view.d.ts +345 -0
  346. package/dist/maps/gl/view.d.ts.map +1 -0
  347. package/dist/maps/gl/view.js +1209 -0
  348. package/dist/maps/gl/view.js.map +1 -0
  349. package/dist/maps/icons.d.ts +32 -0
  350. package/dist/maps/icons.d.ts.map +1 -0
  351. package/dist/maps/icons.js +151 -0
  352. package/dist/maps/icons.js.map +1 -0
  353. package/dist/maps/index.d.ts +3 -1
  354. package/dist/maps/index.d.ts.map +1 -1
  355. package/dist/maps/index.js +218 -52
  356. package/dist/maps/index.js.map +1 -1
  357. package/dist/maps/labels.d.ts +91 -18
  358. package/dist/maps/labels.d.ts.map +1 -1
  359. package/dist/maps/labels.js +376 -140
  360. package/dist/maps/labels.js.map +1 -1
  361. package/dist/maps/node.d.ts +179 -56
  362. package/dist/maps/node.d.ts.map +1 -1
  363. package/dist/maps/node.js +663 -537
  364. package/dist/maps/node.js.map +1 -1
  365. package/dist/maps/overlay.d.ts +72 -9
  366. package/dist/maps/overlay.d.ts.map +1 -1
  367. package/dist/maps/overlay.js +108 -28
  368. package/dist/maps/overlay.js.map +1 -1
  369. package/dist/maps/paint.d.ts +3 -0
  370. package/dist/maps/paint.d.ts.map +1 -1
  371. package/dist/maps/paint.js.map +1 -1
  372. package/dist/maps/proj.d.ts +62 -0
  373. package/dist/maps/proj.d.ts.map +1 -1
  374. package/dist/maps/proj.js +101 -0
  375. package/dist/maps/proj.js.map +1 -1
  376. package/dist/maps/renderer.d.ts +69 -0
  377. package/dist/maps/renderer.d.ts.map +1 -0
  378. package/dist/maps/renderer.js +66 -0
  379. package/dist/maps/renderer.js.map +1 -0
  380. package/dist/maps/sources.d.ts +30 -6
  381. package/dist/maps/sources.d.ts.map +1 -1
  382. package/dist/maps/sources.js +22 -3
  383. package/dist/maps/sources.js.map +1 -1
  384. package/dist/maps/style.d.ts +35 -0
  385. package/dist/maps/style.d.ts.map +1 -1
  386. package/dist/maps/style.js.map +1 -1
  387. package/dist/maps/styles.d.ts +12 -0
  388. package/dist/maps/styles.d.ts.map +1 -1
  389. package/dist/maps/styles.js +120 -6
  390. package/dist/maps/styles.js.map +1 -1
  391. package/dist/maps/theme.d.ts +19 -0
  392. package/dist/maps/theme.d.ts.map +1 -0
  393. package/dist/maps/theme.js +44 -0
  394. package/dist/maps/theme.js.map +1 -0
  395. package/dist/maps/tiles.d.ts +147 -27
  396. package/dist/maps/tiles.d.ts.map +1 -1
  397. package/dist/maps/tiles.js +221 -54
  398. package/dist/maps/tiles.js.map +1 -1
  399. package/dist/maps/types.d.ts +213 -21
  400. package/dist/maps/types.d.ts.map +1 -1
  401. package/dist/markdown/expressions.d.ts +1 -1
  402. package/dist/markdown/expressions.d.ts.map +1 -1
  403. package/dist/markdown/expressions.js.map +1 -1
  404. package/dist/markdown/index.d.ts +7 -6
  405. package/dist/markdown/index.d.ts.map +1 -1
  406. package/dist/markdown/index.js +121 -50
  407. package/dist/markdown/index.js.map +1 -1
  408. package/dist/markdown/spans.d.ts +1 -1
  409. package/dist/markdown/spans.d.ts.map +1 -1
  410. package/dist/markdown/spans.js +6 -0
  411. package/dist/markdown/spans.js.map +1 -1
  412. package/dist/media-player/index.d.ts +11 -3
  413. package/dist/media-player/index.d.ts.map +1 -1
  414. package/dist/media-player/index.js +13 -2
  415. package/dist/media-player/index.js.map +1 -1
  416. package/dist/qml/containers.d.ts.map +1 -1
  417. package/dist/qml/containers.js +6 -1
  418. package/dist/qml/containers.js.map +1 -1
  419. package/dist/qml/interaction.d.ts.map +1 -1
  420. package/dist/qml/interaction.js +38 -5
  421. package/dist/qml/interaction.js.map +1 -1
  422. package/dist/qml/layouts.d.ts.map +1 -1
  423. package/dist/qml/layouts.js +21 -6
  424. package/dist/qml/layouts.js.map +1 -1
  425. package/dist/qml/qtquick.d.ts.map +1 -1
  426. package/dist/qml/qtquick.js +9 -2
  427. package/dist/qml/qtquick.js.map +1 -1
  428. package/dist/qml/react.d.ts.map +1 -1
  429. package/dist/qml/react.js +9 -7
  430. package/dist/qml/react.js.map +1 -1
  431. package/dist/reorder/clock.d.ts +7 -0
  432. package/dist/reorder/clock.d.ts.map +1 -0
  433. package/dist/reorder/clock.js +26 -0
  434. package/dist/reorder/clock.js.map +1 -0
  435. package/dist/reorder/index.d.ts +25 -3
  436. package/dist/reorder/index.d.ts.map +1 -1
  437. package/dist/reorder/index.js +64 -19
  438. package/dist/reorder/index.js.map +1 -1
  439. package/dist/rich-text-editor/clipboard.d.ts +23 -0
  440. package/dist/rich-text-editor/clipboard.d.ts.map +1 -0
  441. package/dist/rich-text-editor/clipboard.js +307 -0
  442. package/dist/rich-text-editor/clipboard.js.map +1 -0
  443. package/dist/rich-text-editor/collab.d.ts +32 -0
  444. package/dist/rich-text-editor/collab.d.ts.map +1 -0
  445. package/dist/rich-text-editor/collab.js +55 -0
  446. package/dist/rich-text-editor/collab.js.map +1 -0
  447. package/dist/rich-text-editor/commands.d.ts +50 -0
  448. package/dist/rich-text-editor/commands.d.ts.map +1 -0
  449. package/dist/rich-text-editor/commands.js +376 -0
  450. package/dist/rich-text-editor/commands.js.map +1 -0
  451. package/dist/rich-text-editor/drag.d.ts +68 -0
  452. package/dist/rich-text-editor/drag.d.ts.map +1 -0
  453. package/dist/rich-text-editor/drag.js +148 -0
  454. package/dist/rich-text-editor/drag.js.map +1 -0
  455. package/dist/rich-text-editor/html.d.ts +145 -0
  456. package/dist/rich-text-editor/html.d.ts.map +1 -0
  457. package/dist/rich-text-editor/html.js +516 -0
  458. package/dist/rich-text-editor/html.js.map +1 -0
  459. package/dist/rich-text-editor/index.d.ts +252 -0
  460. package/dist/rich-text-editor/index.d.ts.map +1 -0
  461. package/dist/rich-text-editor/index.js +856 -0
  462. package/dist/rich-text-editor/index.js.map +1 -0
  463. package/dist/rich-text-editor/inline.d.ts +94 -0
  464. package/dist/rich-text-editor/inline.d.ts.map +1 -0
  465. package/dist/rich-text-editor/inline.js +252 -0
  466. package/dist/rich-text-editor/inline.js.map +1 -0
  467. package/dist/rich-text-editor/keymap.d.ts +71 -0
  468. package/dist/rich-text-editor/keymap.d.ts.map +1 -0
  469. package/dist/rich-text-editor/keymap.js +394 -0
  470. package/dist/rich-text-editor/keymap.js.map +1 -0
  471. package/dist/rich-text-editor/keys.d.ts +40 -0
  472. package/dist/rich-text-editor/keys.d.ts.map +1 -0
  473. package/dist/rich-text-editor/keys.js +202 -0
  474. package/dist/rich-text-editor/keys.js.map +1 -0
  475. package/dist/rich-text-editor/look.d.ts +71 -0
  476. package/dist/rich-text-editor/look.d.ts.map +1 -0
  477. package/dist/rich-text-editor/look.js +342 -0
  478. package/dist/rich-text-editor/look.js.map +1 -0
  479. package/dist/rich-text-editor/markdown.d.ts +18 -0
  480. package/dist/rich-text-editor/markdown.d.ts.map +1 -0
  481. package/dist/rich-text-editor/markdown.js +496 -0
  482. package/dist/rich-text-editor/markdown.js.map +1 -0
  483. package/dist/rich-text-editor/marks.d.ts +9 -0
  484. package/dist/rich-text-editor/marks.d.ts.map +1 -0
  485. package/dist/rich-text-editor/marks.js +83 -0
  486. package/dist/rich-text-editor/marks.js.map +1 -0
  487. package/dist/rich-text-editor/nodes.d.ts +135 -0
  488. package/dist/rich-text-editor/nodes.d.ts.map +1 -0
  489. package/dist/rich-text-editor/nodes.js +397 -0
  490. package/dist/rich-text-editor/nodes.js.map +1 -0
  491. package/dist/rich-text-editor/render.d.ts +68 -0
  492. package/dist/rich-text-editor/render.d.ts.map +1 -0
  493. package/dist/rich-text-editor/render.js +518 -0
  494. package/dist/rich-text-editor/render.js.map +1 -0
  495. package/dist/rich-text-editor/schema.d.ts +16 -0
  496. package/dist/rich-text-editor/schema.d.ts.map +1 -0
  497. package/dist/rich-text-editor/schema.js +386 -0
  498. package/dist/rich-text-editor/schema.js.map +1 -0
  499. package/dist/rich-text-editor/store.d.ts +11 -0
  500. package/dist/rich-text-editor/store.d.ts.map +1 -0
  501. package/dist/rich-text-editor/store.js +43 -0
  502. package/dist/rich-text-editor/store.js.map +1 -0
  503. package/dist/rich-text-editor/suggest.d.ts +127 -0
  504. package/dist/rich-text-editor/suggest.d.ts.map +1 -0
  505. package/dist/rich-text-editor/suggest.js +0 -0
  506. package/dist/rich-text-editor/suggest.js.map +1 -0
  507. package/dist/rich-text-editor/tables.d.ts +41 -0
  508. package/dist/rich-text-editor/tables.d.ts.map +1 -0
  509. package/dist/rich-text-editor/tables.js +204 -0
  510. package/dist/rich-text-editor/tables.js.map +1 -0
  511. package/dist/rich-text-editor/toolbar.d.ts +58 -0
  512. package/dist/rich-text-editor/toolbar.d.ts.map +1 -0
  513. package/dist/rich-text-editor/toolbar.js +548 -0
  514. package/dist/rich-text-editor/toolbar.js.map +1 -0
  515. package/dist/rich-text-editor/view.d.ts +368 -0
  516. package/dist/rich-text-editor/view.d.ts.map +1 -0
  517. package/dist/rich-text-editor/view.js +1968 -0
  518. package/dist/rich-text-editor/view.js.map +1 -0
  519. package/dist/rich-text-editor/virtual.d.ts +54 -0
  520. package/dist/rich-text-editor/virtual.d.ts.map +1 -0
  521. package/dist/rich-text-editor/virtual.js +279 -0
  522. package/dist/rich-text-editor/virtual.js.map +1 -0
  523. package/dist/richtext/node.d.ts +71 -4
  524. package/dist/richtext/node.d.ts.map +1 -1
  525. package/dist/richtext/node.js +233 -28
  526. package/dist/richtext/node.js.map +1 -1
  527. package/dist/richtext/runs.d.ts +13 -8
  528. package/dist/richtext/runs.d.ts.map +1 -1
  529. package/dist/richtext/runs.js +18 -8
  530. package/dist/richtext/runs.js.map +1 -1
  531. package/dist/table/index.d.ts.map +1 -1
  532. package/dist/table/index.js +23 -0
  533. package/dist/table/index.js.map +1 -1
  534. package/dist/table/rows.d.ts +3 -2
  535. package/dist/table/rows.d.ts.map +1 -1
  536. package/dist/table/rows.js +20 -6
  537. package/dist/table/rows.js.map +1 -1
  538. package/dist/terminal/backends.d.ts +4 -1
  539. package/dist/terminal/backends.d.ts.map +1 -1
  540. package/dist/terminal/backends.js.map +1 -1
  541. package/dist/terminal/index.d.ts +18 -7
  542. package/dist/terminal/index.d.ts.map +1 -1
  543. package/dist/terminal/index.js +32 -11
  544. package/dist/terminal/index.js.map +1 -1
  545. package/dist/terminal/vt/pty.d.ts +13 -2
  546. package/dist/terminal/vt/pty.d.ts.map +1 -1
  547. package/dist/terminal/vt/pty.js +18 -3
  548. package/dist/terminal/vt/pty.js.map +1 -1
  549. package/dist/terminal-output/index.d.ts.map +1 -1
  550. package/dist/terminal-output/index.js +6 -1
  551. package/dist/terminal-output/index.js.map +1 -1
  552. package/dist/three/canvas.d.ts.map +1 -1
  553. package/dist/three/canvas.js +85 -7
  554. package/dist/three/canvas.js.map +1 -1
  555. package/dist/three/events.d.ts +22 -4
  556. package/dist/three/events.d.ts.map +1 -1
  557. package/dist/three/events.js +34 -4
  558. package/dist/three/events.js.map +1 -1
  559. package/dist/tree/index.d.ts.map +1 -1
  560. package/dist/tree/index.js +17 -0
  561. package/dist/tree/index.js.map +1 -1
  562. package/package.json +59 -31
  563. package/src/charts/node.ts +68 -28
  564. package/src/charts/render.ts +120 -30
  565. package/src/code/index.ts +3 -1
  566. package/src/code-editor/completion.ts +3 -2
  567. package/src/code-editor/index.ts +19 -0
  568. package/src/code-editor/node.ts +1574 -184
  569. package/src/code-language/languages/glsl.ts +12 -2
  570. package/src/code-language/languages/javascript.ts +21 -4
  571. package/src/code-language/languages/json.ts +12 -2
  572. package/src/code-language/languages/shell.ts +12 -2
  573. package/src/code-language/languages/sql.ts +22 -2
  574. package/src/code-language/stream.ts +257 -17
  575. package/src/code-language/types.ts +5 -4
  576. package/src/codeblock/index.ts +20 -3
  577. package/src/embed/client.ts +102 -8
  578. package/src/embed/index.ts +2 -0
  579. package/src/flow/draw.ts +167 -41
  580. package/src/flow/gl/color.ts +85 -0
  581. package/src/flow/gl/index.ts +342 -0
  582. package/src/flow/gl/pack.ts +585 -0
  583. package/src/flow/gl/renderer.ts +679 -0
  584. package/src/flow/gl/shaders.ts +371 -0
  585. package/src/flow/gl/text.ts +1295 -0
  586. package/src/flow/index.ts +794 -67
  587. package/src/flow/node.ts +2496 -1256
  588. package/src/flow/paint.ts +511 -0
  589. package/src/flow/paths.ts +80 -15
  590. package/src/flow/scene.ts +2199 -0
  591. package/src/flow/types.ts +113 -1
  592. package/src/html/controls.ts +73 -2
  593. package/src/html/css/calc.ts +385 -0
  594. package/src/html/css/cascade.ts +1403 -62
  595. package/src/html/css/color.ts +755 -0
  596. package/src/html/css/content.ts +417 -0
  597. package/src/html/css/counter-styles.ts +973 -0
  598. package/src/html/css/decode.ts +130 -0
  599. package/src/html/css/parse.ts +1514 -160
  600. package/src/html/css/style.ts +4102 -222
  601. package/src/html/css/ua.ts +58 -12
  602. package/src/html/css/values.ts +150 -50
  603. package/src/html/css/vars.ts +348 -0
  604. package/src/html/dom.ts +284 -17
  605. package/src/html/fonts.ts +641 -0
  606. package/src/html/gif.ts +233 -0
  607. package/src/html/index.ts +180 -20
  608. package/src/html/layout/block.ts +3456 -230
  609. package/src/html/layout/boxes.ts +2100 -190
  610. package/src/html/layout/cache.ts +289 -0
  611. package/src/html/layout/collapse.ts +317 -0
  612. package/src/html/layout/css-grid.ts +1063 -0
  613. package/src/html/layout/flex.ts +1115 -106
  614. package/src/html/layout/floats.ts +128 -14
  615. package/src/html/layout/grid-lines.ts +141 -0
  616. package/src/html/layout/grid.ts +181 -0
  617. package/src/html/layout/inline.ts +3943 -192
  618. package/src/html/layout/shaping.ts +140 -0
  619. package/src/html/layout/table.ts +696 -186
  620. package/src/html/layout/tracks.ts +437 -0
  621. package/src/html/node.ts +1486 -121
  622. package/src/html/paint.ts +4293 -169
  623. package/src/html/resources.ts +161 -50
  624. package/src/html/surfaces.ts +81 -0
  625. package/src/html/svg.ts +493 -0
  626. package/src/html/url.ts +86 -0
  627. package/src/index.ts +4 -0
  628. package/src/internal/collate.ts +12 -0
  629. package/src/{markdown → internal/markdown}/ast.ts +35 -7
  630. package/src/{markdown → internal/markdown}/parse.ts +288 -35
  631. package/src/internal/markdown/stringify.ts +772 -0
  632. package/src/internal/prewarm.ts +45 -0
  633. package/src/internal/scroll.ts +5 -3
  634. package/src/internal/sdf.ts +227 -0
  635. package/src/internal/splice.ts +25 -0
  636. package/src/internal/window.ts +36 -5
  637. package/src/maps/anchors.ts +913 -0
  638. package/src/maps/controller.ts +1084 -0
  639. package/src/maps/gl/buckets.ts +461 -0
  640. package/src/maps/gl/build-worker.ts +66 -0
  641. package/src/maps/gl/color.ts +62 -0
  642. package/src/maps/gl/cover.ts +205 -0
  643. package/src/maps/gl/index.ts +23 -0
  644. package/src/maps/gl/markers.ts +83 -0
  645. package/src/maps/gl/overlays.ts +379 -0
  646. package/src/maps/gl/pane.ts +42 -0
  647. package/src/maps/gl/placement.ts +968 -0
  648. package/src/maps/gl/renderer.ts +1660 -0
  649. package/src/maps/gl/shaders.ts +489 -0
  650. package/src/maps/gl/store.ts +615 -0
  651. package/src/maps/gl/text.ts +868 -0
  652. package/src/maps/gl/view.ts +1489 -0
  653. package/src/maps/icons.ts +183 -0
  654. package/src/maps/index.ts +274 -81
  655. package/src/maps/labels.ts +457 -144
  656. package/src/maps/node.ts +832 -665
  657. package/src/maps/overlay.ts +148 -43
  658. package/src/maps/paint.ts +3 -0
  659. package/src/maps/proj.ts +118 -0
  660. package/src/maps/renderer.ts +155 -0
  661. package/src/maps/sources.ts +43 -6
  662. package/src/maps/style.ts +32 -0
  663. package/src/maps/styles.ts +215 -4
  664. package/src/maps/theme.ts +51 -0
  665. package/src/maps/tiles.ts +253 -62
  666. package/src/maps/types.ts +213 -21
  667. package/src/markdown/expressions.ts +5 -1
  668. package/src/markdown/index.ts +163 -78
  669. package/src/markdown/spans.ts +6 -1
  670. package/src/media-player/index.ts +18 -4
  671. package/src/qml/containers.tsx +6 -1
  672. package/src/qml/interaction.tsx +42 -5
  673. package/src/qml/layouts.tsx +21 -6
  674. package/src/qml/qtquick.tsx +9 -2
  675. package/src/qml/react.tsx +7 -5
  676. package/src/reorder/clock.ts +27 -0
  677. package/src/reorder/index.ts +100 -27
  678. package/src/rich-text-editor/clipboard.ts +439 -0
  679. package/src/rich-text-editor/collab.ts +91 -0
  680. package/src/rich-text-editor/commands.ts +448 -0
  681. package/src/rich-text-editor/dom-globals.d.ts +23 -0
  682. package/src/rich-text-editor/drag.ts +211 -0
  683. package/src/rich-text-editor/html.ts +619 -0
  684. package/src/rich-text-editor/index.ts +1364 -0
  685. package/src/rich-text-editor/inline.ts +345 -0
  686. package/src/rich-text-editor/keymap.ts +510 -0
  687. package/src/rich-text-editor/keys.ts +228 -0
  688. package/src/rich-text-editor/look.ts +427 -0
  689. package/src/rich-text-editor/markdown.ts +653 -0
  690. package/src/rich-text-editor/marks.ts +101 -0
  691. package/src/rich-text-editor/nodes.ts +497 -0
  692. package/src/rich-text-editor/render.ts +837 -0
  693. package/src/rich-text-editor/schema.ts +431 -0
  694. package/src/rich-text-editor/store.ts +39 -0
  695. package/src/rich-text-editor/suggest.ts +597 -0
  696. package/src/rich-text-editor/tables.ts +272 -0
  697. package/src/rich-text-editor/toolbar.ts +724 -0
  698. package/src/rich-text-editor/view.ts +2287 -0
  699. package/src/rich-text-editor/virtual.ts +372 -0
  700. package/src/richtext/node.ts +294 -44
  701. package/src/richtext/runs.ts +23 -12
  702. package/src/table/index.ts +29 -0
  703. package/src/table/rows.ts +18 -8
  704. package/src/terminal/backends.ts +4 -1
  705. package/src/terminal/index.ts +47 -15
  706. package/src/terminal/vt/pty.ts +16 -2
  707. package/src/terminal-output/index.ts +6 -1
  708. package/src/three/canvas.ts +102 -8
  709. package/src/three/events.ts +49 -9
  710. package/src/tree/index.ts +19 -0
  711. package/dist/markdown/ast.d.ts.map +0 -1
  712. package/dist/markdown/ast.js +0 -17
  713. package/dist/markdown/ast.js.map +0 -1
  714. package/dist/markdown/parse.d.ts.map +0 -1
  715. package/dist/markdown/parse.js.map +0 -1
  716. package/dist/markdown/tags.d.ts.map +0 -1
  717. package/dist/markdown/tags.js.map +0 -1
  718. /package/dist/{markdown → internal/markdown}/parse.d.ts +0 -0
  719. /package/dist/{markdown → internal/markdown}/tags.d.ts +0 -0
  720. /package/dist/{markdown → internal/markdown}/tags.js +0 -0
  721. /package/src/{markdown → internal/markdown}/tags.ts +0 -0
@@ -9,6 +9,12 @@
9
9
  // is the one thing on a map nobody accepts blurred. And a tile's labels
10
10
  // would be **clipped at its edge**, which is where half of them sit.
11
11
  //
12
+ // **Where a label can go is the GL renderer's answer too**: both renderers
13
+ // take their anchors from `./anchors.ts` — a place name at its point, a
14
+ // street's name on a straight stretch of the street, its pieces merged
15
+ // first — so a map switched from one renderer to the other names the same
16
+ // streets in the same places, at the same angles.
17
+ //
12
18
  // The placement itself is done in **world pixels** rather than screen
13
19
  // pixels, and that is the load-bearing decision in this file. A placement
14
20
  // computed against the viewport changes whenever the viewport does, so a
@@ -17,12 +23,31 @@
17
23
  // scrolled away. Placed in world pixels, whether a label wins depends only
18
24
  // on the labels near it and the zoom, so a pan is a translation of a
19
25
  // placement that is already correct, and the blit stands.
26
+ import {
27
+ LABEL_STRIDE,
28
+ LEVEL_SNAP,
29
+ LINE_MARGIN,
30
+ LabelField,
31
+ STRAIGHT_FRACTION,
32
+ buildTileLabels,
33
+ estimateWidth,
34
+ } from './anchors.js';
35
+ import type { GlLabelData } from './anchors.js';
20
36
  import type { MapCanvas } from './paint.js';
21
- import { GeomType, GeometryBuffer } from './mvt.js';
22
37
  import type { VectorTile } from './mvt.js';
23
38
  import type { PreparedStyle, PreparedLayer } from './paint.js';
39
+ import {
40
+ DEFAULT_ICON_COLOR,
41
+ DEFAULT_ICON_GLYPH_COLOR,
42
+ DEFAULT_ICON_SIZE,
43
+ ICON_GAP,
44
+ isMapIcon,
45
+ traceGlyph,
46
+ tracePlate,
47
+ } from './icons.js';
48
+ import type { MapIcon } from './icons.js';
24
49
  import { resolveZoomed } from './style.js';
25
- import type { SymbolLayer, Zoomed } from './style.js';
50
+ import type { MapStyleLayer, SymbolLayer, Zoomed } from './style.js';
26
51
  import type { TileId, Transform } from './proj.js';
27
52
  import { tileCountAt, tileKey } from './proj.js';
28
53
 
@@ -53,7 +78,7 @@ export interface ShapedLabel {
53
78
  *
54
79
  * `mx`/`my` are normalized mercator, so a candidate outlives every camera
55
80
  * move — it is a property of the data, and collected once per tile per
56
- * zoom.
81
+ * zoom. So are the lengths a name along a street is fitted with.
57
82
  */
58
83
  export interface LabelCandidate {
59
84
  /** Stable for the life of the tile, which is what lets a placement be
@@ -66,8 +91,23 @@ export interface LabelCandidate {
66
91
  text: string;
67
92
  mx: number;
68
93
  my: number;
94
+ /** The baseline's direction, radians, y down: `0` for a point label, and
95
+ * along its street — always upright — for a street name. */
96
+ angle: number;
97
+ /** A street name's room: the straight run either side of the anchor, the
98
+ * distance to the nearest junction, the run's length and how far it
99
+ * bends from straight — normalized mercator, so a placement at any zoom
100
+ * reads them in its own pixels. `Infinity`, `Infinity`, `0`, `0` for a
101
+ * point label, which fits anywhere. */
102
+ avail: number;
103
+ clear: number;
104
+ length: number;
105
+ dev: number;
69
106
  /** Layer-wide priority; higher wins a collision. */
70
107
  rank: number;
108
+ /** Importance within the layer — a road's class, a place's population —
109
+ * which breaks a tie in rank. */
110
+ priority: number;
71
111
  /** Logical pixels. */
72
112
  size: number;
73
113
  color: string;
@@ -75,17 +115,32 @@ export interface LabelCandidate {
75
115
  haloWidth: number;
76
116
  /** Pixels within which this text may not repeat. */
77
117
  repeat: number;
118
+ /** The icon on the point, where the layer sets one — absent, or null, for
119
+ * a label that is text alone and for every name along a street. */
120
+ icon?: LabelIcon | null;
121
+ }
122
+
123
+ /** A point label's icon at a zoom: logical pixels across, and colours. */
124
+ export interface LabelIcon {
125
+ name: MapIcon;
126
+ size: number;
127
+ color: string;
128
+ glyph: string;
78
129
  }
79
130
 
80
131
  /** A candidate that won its place, with the box it occupies in world
81
- * pixels at the zoom it was placed for. */
132
+ * pixels at the zoom it was placed for — its turned text's bounding box.
133
+ * Not shaped: the placement covers every tile loaded, most of it outside
134
+ * the pane, and a label is shaped when it is first drawn. */
82
135
  export interface PlacedLabel extends LabelCandidate {
83
136
  /** World pixels: `mercator × worldSize`. */
84
137
  wx: number;
85
138
  wy: number;
86
139
  width: number;
87
140
  height: number;
88
- shaped: ShapedLabel;
141
+ /** How far right of the anchor the box's centre is, in world pixels: half
142
+ * the icon and the gap, for a name set beside an icon; 0 otherwise. */
143
+ ox?: number;
89
144
  }
90
145
 
91
146
  function num<T extends number>(
@@ -96,118 +151,211 @@ function num<T extends number>(
96
151
  return value === undefined ? fallback : resolveZoomed(value, zoom);
97
152
  }
98
153
 
154
+ /** The tile units anchors are worked out in: the GL buckets', so the two
155
+ * renderers' anchors are the same numbers. */
156
+ const EXTENT = 4096;
157
+
99
158
  /**
100
- * The label candidates one tile contributes.
101
- *
102
- * Point geometry anchors at the point. Line and polygon geometry anchor at
103
- * the **midpoint of the longest part** — which is not a true label
104
- * placement (a street name should follow its street, and a country name
105
- * should sit at the pole of inaccessibility of its border) but is the
106
- * anchor those two would start from, and is right often enough to be worth
107
- * having while line placement is unwritten. See `docs/prd-maps.md`.
159
+ * Anchors, per tile and style. They depend on neither the zoom nor the
160
+ * camera, and merging a tile's street pieces is the one costly step, so a
161
+ * zoom that collects a tile's candidates again does not work them out
162
+ * again.
163
+ */
164
+ const anchorCache = new WeakMap<
165
+ VectorTile,
166
+ { prepared: PreparedStyle; data: GlLabelData }
167
+ >();
168
+
169
+ function anchorsOf(
170
+ tile: VectorTile,
171
+ prepared: PreparedStyle,
172
+ id: TileId,
173
+ ): GlLabelData {
174
+ const hit = anchorCache.get(tile);
175
+ if (hit && hit.prepared === prepared) return hit.data;
176
+ const data = buildTileLabels(tile, prepared, EXTENT, id);
177
+ anchorCache.set(tile, { prepared, data });
178
+ return data;
179
+ }
180
+
181
+ /** A symbol layer's labelling at a zoom, or null where it does not label. */
182
+ interface LayerPaint {
183
+ id: string;
184
+ size: number;
185
+ color: string;
186
+ halo: string | undefined;
187
+ haloWidth: number;
188
+ rank: number;
189
+ repeat: number;
190
+ icon: LabelIcon | null;
191
+ }
192
+
193
+ function paintAt(
194
+ layer: MapStyleLayer | undefined,
195
+ zoom: number,
196
+ ): LayerPaint | null {
197
+ if (!layer || layer.type !== 'symbol' || layer.visible === false) {
198
+ return null;
199
+ }
200
+ if (layer.minZoom !== undefined && zoom < layer.minZoom) return null;
201
+ if (layer.maxZoom !== undefined && zoom >= layer.maxZoom) return null;
202
+ const symbol = layer as SymbolLayer;
203
+ return {
204
+ id: layer.id,
205
+ size: num(symbol.textSize, zoom, 12),
206
+ color: symbol.textColor ? resolveZoomed(symbol.textColor, zoom) : '#000000',
207
+ halo: symbol.textHaloColor
208
+ ? resolveZoomed(symbol.textHaloColor, zoom)
209
+ : undefined,
210
+ haloWidth: num(symbol.textHaloWidth, zoom, 1),
211
+ rank: symbol.rank ?? 0,
212
+ repeat: symbol.repeatDistance ?? 250,
213
+ icon: isMapIcon(symbol.icon)
214
+ ? {
215
+ name: symbol.icon,
216
+ size: num(symbol.iconSize, zoom, DEFAULT_ICON_SIZE),
217
+ color: symbol.iconColor
218
+ ? resolveZoomed(symbol.iconColor, zoom)
219
+ : DEFAULT_ICON_COLOR,
220
+ glyph: symbol.iconGlyphColor
221
+ ? resolveZoomed(symbol.iconGlyphColor, zoom)
222
+ : DEFAULT_ICON_GLYPH_COLOR,
223
+ }
224
+ : null,
225
+ };
226
+ }
227
+
228
+ /**
229
+ * The label candidates one tile contributes: its anchors (`./anchors.ts`),
230
+ * with this zoom's size and colours. A point label anchors at its point,
231
+ * an area's at the middle of its largest ring, and a street's name at the
232
+ * middle of a straight stretch of the street — or of a block of it —
233
+ * turned to lie along it.
108
234
  */
109
235
  export function collectLabels(
110
236
  tile: VectorTile,
111
237
  id: TileId,
112
238
  prepared: PreparedStyle,
113
239
  zoom: number,
114
- buffer: GeometryBuffer,
115
240
  ): LabelCandidate[] {
116
241
  const out: LabelCandidate[] = [];
242
+ const data = anchorsOf(tile, prepared, id);
117
243
  const n = tileCountAt(id.z);
118
244
  const key = tileKey(id);
119
- for (let i = 0; i < prepared.layers.length; i++) {
120
- const { layer, filter } = prepared.layers[i];
121
- if (layer.type !== 'symbol' || layer.visible === false) continue;
122
- if (layer.minZoom !== undefined && zoom < layer.minZoom) continue;
123
- if (layer.maxZoom !== undefined && zoom >= layer.maxZoom) continue;
124
- const source = tile.layers.get(layer.sourceLayer);
125
- if (!source || source.length === 0) continue;
126
- const symbol = layer as SymbolLayer;
127
- const size = num(symbol.textSize, zoom, 12);
128
- const color = symbol.textColor
129
- ? resolveZoomed(symbol.textColor, zoom)
130
- : '#000000';
131
- const halo = symbol.textHaloColor
132
- ? resolveZoomed(symbol.textHaloColor, zoom)
133
- : undefined;
134
- const haloWidth = num(symbol.textHaloWidth, zoom, 1);
135
- const rank = symbol.rank ?? 0;
136
- const repeat = symbol.repeatDistance ?? 250;
137
- const extent = source.extent;
138
- const cursor = source.feature(0);
139
- for (let f = 0; f < source.length; f++) {
140
- source.seek(f, cursor);
141
- if (!filter(cursor)) continue;
142
- const raw = cursor.get(symbol.textField);
143
- // The schema's fallback: a translated name field is absent for most
144
- // features, and the local `name` is what a map without a translation
145
- // shows rather than nothing.
146
- const text =
147
- typeof raw === 'string' && raw.length > 0
148
- ? raw
149
- : symbol.textField !== 'name'
150
- ? typeof cursor.get('name') === 'string'
151
- ? String(cursor.get('name'))
152
- : ''
153
- : '';
154
- if (text.length === 0) continue;
155
- cursor.readGeometry(buffer);
156
- const anchor = anchorOf(buffer, cursor.type);
157
- if (!anchor) continue;
158
- out.push({
159
- id: `${key}:${layer.id}:${f}`,
160
- key: `${layer.id}|${text}`,
161
- text,
162
- // Tile-local to normalized mercator, the same arithmetic the
163
- // rasterizer's transform does and for the same precision reason.
164
- mx: (id.x + anchor.x / extent) / n,
165
- my: (id.y + anchor.y / extent) / n,
166
- rank,
167
- size,
168
- color,
169
- halo,
170
- haloWidth,
171
- repeat,
172
- });
245
+ // Tile units to normalized mercator.
246
+ const unit = 1 / (EXTENT * n);
247
+ const paints = new Map<number, LayerPaint | null>();
248
+ const a = data.anchors;
249
+ for (let r = 0; r < data.count; r++) {
250
+ const at = r * LABEL_STRIDE;
251
+ const index = a[at + LabelField.layer];
252
+ let paint = paints.get(index);
253
+ if (paint === undefined) {
254
+ paint = paintAt(prepared.layers[index]?.layer, zoom);
255
+ paints.set(index, paint);
173
256
  }
257
+ if (!paint) continue;
258
+ const text = data.texts[a[at + LabelField.text]];
259
+ const point = a[at + LabelField.avail] < 0;
260
+ out.push({
261
+ id: `${key}:${paint.id}:${r}`,
262
+ key: `${paint.id}|${text}`,
263
+ text,
264
+ // Tile-local to normalized mercator, the same arithmetic the
265
+ // rasterizer's transform does and for the same precision reason.
266
+ mx: (id.x + a[at + LabelField.x] / EXTENT) / n,
267
+ my: (id.y + a[at + LabelField.y] / EXTENT) / n,
268
+ angle: point ? 0 : a[at + LabelField.angle],
269
+ avail: point ? Infinity : a[at + LabelField.avail] * unit,
270
+ clear: point ? Infinity : a[at + LabelField.clear] * unit,
271
+ length: a[at + LabelField.length] * unit,
272
+ dev: a[at + LabelField.dev] * unit,
273
+ rank: paint.rank,
274
+ priority: a[at + LabelField.priority],
275
+ size: paint.size,
276
+ color: paint.color,
277
+ halo: paint.halo,
278
+ haloWidth: paint.haloWidth,
279
+ repeat: paint.repeat,
280
+ icon: point ? paint.icon : null,
281
+ });
174
282
  }
175
283
  return out;
176
284
  }
177
285
 
178
- function anchorOf(
179
- buffer: GeometryBuffer,
180
- type: GeomType,
181
- ): { x: number; y: number } | null {
182
- if (buffer.points === 0) return null;
183
- if (type === GeomType.Point) {
184
- return { x: buffer.coords[0], y: buffer.coords[1] };
286
+ /** What a string measures, in logical pixels — all placement needs of it. */
287
+ interface LabelMetrics {
288
+ width: number;
289
+ height: number;
290
+ }
291
+
292
+ /**
293
+ * A cache bounded in **two generations** rather than by clearing: what was
294
+ * stored since the last turn is the young one, a lookup that finds an entry
295
+ * in the old one brings it back, and a full young generation becomes the
296
+ * old one as the old one is dropped. So what is in use survives the turn,
297
+ * and the bound is twice a generation.
298
+ */
299
+ class Generations<V> {
300
+ private _young = new Map<string, V>();
301
+ private _old = new Map<string, V>();
302
+ constructor(private readonly _size: number) {}
303
+
304
+ get(key: string): V | undefined {
305
+ const hit = this._young.get(key);
306
+ if (hit !== undefined) return hit;
307
+ const kept = this._old.get(key);
308
+ if (kept !== undefined) this.set(key, kept);
309
+ return kept;
185
310
  }
186
- // The longest part, by its box — a cheap stand-in for arc length that
187
- // does not need a second pass over the vertices.
188
- let best = 0;
189
- let bestSpan = -1;
190
- for (let part = 0; part < buffer.parts; part++) {
191
- const at = part * 4;
192
- const span =
193
- buffer.partBounds[at + 2] -
194
- buffer.partBounds[at] +
195
- (buffer.partBounds[at + 3] - buffer.partBounds[at + 1]);
196
- if (span > bestSpan) {
197
- bestSpan = span;
198
- best = part;
311
+
312
+ set(key: string, value: V): void {
313
+ if (this._young.size >= this._size) {
314
+ this._old = this._young;
315
+ this._young = new Map();
199
316
  }
317
+ this._young.set(key, value);
318
+ }
319
+
320
+ clear(): void {
321
+ this._young = new Map();
322
+ this._old = new Map();
200
323
  }
201
- const from = buffer.starts[best];
202
- const to = buffer.starts[best + 1];
203
- if (to <= from) return null;
204
- const mid = from + ((to - from) >> 1);
205
- return { x: buffer.coords[mid * 2], y: buffer.coords[mid * 2 + 1] };
206
324
  }
207
325
 
208
- /** Cache of shaped strings, owned by the element. */
326
+ /** Shaped strings a generation holds. Each is a layout the text engine
327
+ * keeps — a native one under CoreText — so this is the bound that
328
+ * matters, and it is the one the cache always had. */
329
+ const SHAPED_GENERATION = 2000;
330
+ /** Measurements a generation holds: two numbers each, so many more of
331
+ * them, enough for every label of a zoom across the levels. */
332
+ const MEASURED_GENERATION = 8000;
333
+
334
+ /**
335
+ * Cache of shaped strings, owned by the element — and of what they
336
+ * measure, which is kept apart and far longer.
337
+ *
338
+ * Placement asks the size of every candidate on the map, most of which
339
+ * are never drawn, and it asks again at every step of a zoom; drawing
340
+ * needs the layouts of the few hundred that won their place. With one
341
+ * cache for both, bounded by clearing it, a wheel zoom through six levels —
342
+ * some 8,000 strings, every label of every level at its own size and in
343
+ * its halo's colour — crossed the bound every few hundred milliseconds and
344
+ * threw away what the next placement needed: 43,000 strings shaped in four
345
+ * seconds, the worst frames of the zoom spent on text it had shaped
346
+ * already. Measurements now outlive the layouts they were read from, and
347
+ * both caches turn over in generations (`Generations`).
348
+ */
209
349
  export class LabelShaper {
210
- private readonly _cache = new Map<string, ShapedLabel>();
350
+ private readonly _shaped = new Generations<ShapedLabel>(SHAPED_GENERATION);
351
+ private readonly _measured = new Generations<LabelMetrics>(
352
+ MEASURED_GENERATION,
353
+ );
354
+ /** What each placed label was drawn with, text and halo: kept with the
355
+ * placement, so a pan's frames, which draw one placement over and over,
356
+ * look nothing up. */
357
+ private _drawn = new WeakMap<PlacedLabel, ShapedLabel>();
358
+ private _haloed = new WeakMap<PlacedLabel, ShapedLabel>();
211
359
  private _fonts: FontsLike | null;
212
360
  private _family: string;
213
361
  /** Device pixels per logical pixel. Text is shaped at the device size the
@@ -234,7 +382,41 @@ export class LabelShaper {
234
382
  this._fonts = fonts;
235
383
  this._family = family;
236
384
  this._scale = scale;
237
- this._cache.clear();
385
+ this._shaped.clear();
386
+ this._measured.clear();
387
+ this._drawn = new WeakMap();
388
+ this._haloed = new WeakMap();
389
+ }
390
+
391
+ /** The layout a placed label's text is drawn with — or, with `halo`, its
392
+ * halo's — or null on a backend with no font manager. */
393
+ drawn(label: PlacedLabel, halo = false): ShapedLabel | null {
394
+ const kept = halo ? this._haloed : this._drawn;
395
+ const hit = kept.get(label);
396
+ if (hit) return hit;
397
+ const color = halo ? label.halo : label.color;
398
+ if (color === undefined) return null;
399
+ const shaped = this.shape(label.text, label.size, color);
400
+ if (shaped) kept.set(label, shaped);
401
+ return shaped;
402
+ }
403
+
404
+ /** What one label measures, logical pixels, or null on a backend with no
405
+ * font manager — shaped only when it has never been measured. A string
406
+ * measures the same in any colour, so a name and its halo share it.
407
+ *
408
+ * The layout it was measured from is not kept: most candidates never
409
+ * win a place, and theirs would push the layouts of the ones that did
410
+ * out of the cache drawing reads from. */
411
+ measure(text: string, size: number, color: string): LabelMetrics | null {
412
+ const key = `${this._family}|${size}|${text}`;
413
+ const hit = this._measured.get(key);
414
+ if (hit) return hit;
415
+ const shaped = this._shapeNow(text, size, color);
416
+ if (!shaped) return null;
417
+ const metrics = { width: shaped.width, height: shaped.height };
418
+ this._measured.set(key, metrics);
419
+ return metrics;
238
420
  }
239
421
 
240
422
  /** Shape one label, or null on a backend with no font manager. Widths
@@ -243,13 +425,20 @@ export class LabelShaper {
243
425
  const fonts = this._fonts;
244
426
  if (!fonts) return null;
245
427
  const key = `${this._family}|${size}|${color}|${text}`;
246
- const hit = this._cache.get(key);
428
+ const hit = this._shaped.get(key);
247
429
  if (hit) return hit;
248
- // Bounded, so a map panned across a continent cannot turn the cache
249
- // into a leak. Cleared wholesale rather than evicted one at a time: the
250
- // labels on screen are re-shaped on the next frame and the cost of that
251
- // is a few hundred strings once.
252
- if (this._cache.size > 4000) this._cache.clear();
430
+ const shaped = this._shapeNow(text, size, color);
431
+ if (shaped) this._shaped.set(key, shaped);
432
+ return shaped;
433
+ }
434
+
435
+ private _shapeNow(
436
+ text: string,
437
+ size: number,
438
+ color: string,
439
+ ): ShapedLabel | null {
440
+ const fonts = this._fonts;
441
+ if (!fonts) return null;
253
442
  const layout = fonts.layout(text, {
254
443
  family: this._family,
255
444
  size: size * this._scale,
@@ -257,23 +446,33 @@ export class LabelShaper {
257
446
  style: 'normal',
258
447
  color,
259
448
  });
260
- const shaped: ShapedLabel = {
449
+ return {
261
450
  width: layout.width / this._scale,
262
451
  height: layout.height / this._scale,
263
452
  layout,
264
453
  };
265
- this._cache.set(key, shaped);
266
- return shaped;
267
454
  }
268
455
  }
269
456
 
457
+ /** A street name is set level — on whole pixels, which is sharper — when
458
+ * its street is this close to level. */
459
+ function levelled(angle: number): number {
460
+ return Math.abs(angle) < LEVEL_SNAP ? 0 : angle;
461
+ }
462
+
270
463
  /**
271
464
  * Place candidates against each other, in world pixels.
272
465
  *
273
- * Greedy by rank, which is what every map does: sort, and take a label if
274
- * nothing already taken overlaps it. The order has to be **total and
275
- * stable** — rank, then the candidate's id — because a tie broken by array
276
- * order would flicker as tiles arrived in a different order.
466
+ * Greedy, which is what every map does: sort, and take a label if it fits
467
+ * where it is and nothing already taken overlaps it. The order is the GL
468
+ * renderer's, less what depends on the view: rank, then importance within
469
+ * the layer, then a street name that clears its junctions over one that
470
+ * would cover a crossing street, then the longer straight run. It has to be
471
+ * **total and stable** — the candidate's id last — because a tie broken by
472
+ * array order would flicker as tiles arrived in a different order.
473
+ *
474
+ * A street name fits where the GL renderer says one does: on a stretch
475
+ * straight enough for its size, and long enough for all of it.
277
476
  */
278
477
  export function placeLabels(
279
478
  candidates: readonly LabelCandidate[],
@@ -282,9 +481,19 @@ export function placeLabels(
282
481
  options?: { padding?: number },
283
482
  ): PlacedLabel[] {
284
483
  const padding = options?.padding ?? 2;
285
- const sorted = [...candidates].sort(
286
- (a, b) => b.rank - a.rank || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0),
287
- );
484
+ const clean = (c: LabelCandidate): number =>
485
+ c.clear * worldSize >= estimateWidth(c.text, c.size) / 2 ? 1 : 0;
486
+ const sorted = [...candidates]
487
+ .map((c) => ({ c, clean: clean(c) }))
488
+ .sort(
489
+ (a, b) =>
490
+ b.c.rank - a.c.rank ||
491
+ b.c.priority - a.c.priority ||
492
+ b.clean - a.clean ||
493
+ b.c.length - a.c.length ||
494
+ (a.c.id < b.c.id ? -1 : a.c.id > b.c.id ? 1 : 0),
495
+ )
496
+ .map((entry) => entry.c);
288
497
  const placed: PlacedLabel[] = [];
289
498
  // A sparse grid over world pixels. The cell is sized for the labels
290
499
  // themselves, so a box touches one or two cells and a collision test is a
@@ -297,18 +506,18 @@ export function placeLabels(
297
506
  const byText = new Map<string, { wx: number; wy: number }[]>();
298
507
 
299
508
  for (const candidate of sorted) {
300
- const shaped = shaper.shape(
301
- candidate.text,
302
- candidate.size,
303
- candidate.color,
304
- );
305
- if (!shaped) return placed; // no font manager: nothing can be measured
509
+ // Bent under its size at this zoom: not a stretch to set a name on.
510
+ if (candidate.dev * worldSize > candidate.size * STRAIGHT_FRACTION) {
511
+ continue;
512
+ }
306
513
  const wx = candidate.mx * worldSize;
307
514
  const wy = candidate.my * worldSize;
308
- // The repeat test before the overlap test, because it is the cheaper
309
- // one and because it is what rejects most of a street layer: a street
310
- // is one feature per segment, so the same name arrives a dozen times
311
- // strung out along the road, none of them overlapping any other.
515
+ // The repeat test first, because it is the cheapest one and because it
516
+ // is what rejects most of a street layer: a long street offers its name
517
+ // every block, none of them overlapping. Ahead of the shaping, which it
518
+ // does not need — a street's every block shaped its name, and a wheel
519
+ // zoom re-places at every step, so that was thousands of strings a
520
+ // frame asked of the cache.
312
521
  if (candidate.repeat > 0) {
313
522
  const already = byText.get(candidate.key);
314
523
  if (already) {
@@ -325,9 +534,37 @@ export function placeLabels(
325
534
  if (tooClose) continue;
326
535
  }
327
536
  }
328
- const width = shaped.width + padding * 2;
329
- const height = shaped.height + padding * 2;
330
- const left = wx - width / 2;
537
+ const measured = shaper.measure(
538
+ candidate.text,
539
+ candidate.size,
540
+ candidate.color,
541
+ );
542
+ if (!measured) return placed; // no font manager: nothing can be measured
543
+ // Longer than the straight stretch it would sit on, with a margin past
544
+ // each end: it would hang off the street, over whatever the street
545
+ // turns into.
546
+ const need = measured.width / 2 + measured.height * LINE_MARGIN;
547
+ if (candidate.avail * worldSize < need) continue;
548
+ // The turned text's bounding box: what it covers, as far as another
549
+ // label can tell. With an icon, the box around the icon on the point
550
+ // and the text beside it — the two give way as one, or a stop's name
551
+ // would be set with nothing to say it is a stop.
552
+ const angle = levelled(candidate.angle);
553
+ const icon = candidate.icon ?? null;
554
+ let w = measured.width + padding * 2;
555
+ let h = measured.height + padding * 2;
556
+ let ox = 0;
557
+ if (icon) {
558
+ const full = icon.size + ICON_GAP + measured.width;
559
+ ox = (full - icon.size) / 2;
560
+ w = full + padding * 2;
561
+ h = Math.max(icon.size, measured.height) + padding * 2;
562
+ }
563
+ const cos = Math.abs(Math.cos(angle));
564
+ const sin = Math.abs(Math.sin(angle));
565
+ const width = w * cos + h * sin;
566
+ const height = w * sin + h * cos;
567
+ const left = wx + ox - width / 2;
331
568
  const top = wy - height / 2;
332
569
  const x0 = Math.floor(left / CELL);
333
570
  const x1 = Math.floor((left + width) / CELL);
@@ -339,11 +576,13 @@ export function placeLabels(
339
576
  const bucket = grid.get(cellKey(cx, cy));
340
577
  if (!bucket) continue;
341
578
  for (const other of bucket) {
579
+ const otherLeft = other.wx + (other.ox ?? 0) - other.width / 2;
580
+ const otherTop = other.wy - other.height / 2;
342
581
  if (
343
- left < other.wx - other.width / 2 + other.width &&
344
- left + width > other.wx - other.width / 2 &&
345
- top < other.wy - other.height / 2 + other.height &&
346
- top + height > other.wy - other.height / 2
582
+ left < otherLeft + other.width &&
583
+ left + width > otherLeft &&
584
+ top < otherTop + other.height &&
585
+ top + height > otherTop
347
586
  ) {
348
587
  free = false;
349
588
  break;
@@ -354,11 +593,12 @@ export function placeLabels(
354
593
  if (!free) continue;
355
594
  const entry: PlacedLabel = {
356
595
  ...candidate,
596
+ angle,
357
597
  wx,
358
598
  wy,
599
+ ox,
359
600
  width,
360
601
  height,
361
- shaped,
362
602
  };
363
603
  placed.push(entry);
364
604
  if (candidate.repeat > 0) {
@@ -387,6 +627,10 @@ export function placeLabels(
387
627
  * composites of two shaped runs. That is cheap for the few dozen labels a
388
628
  * pane holds and it is the difference between a place name that is
389
629
  * readable over a motorway and one that is not.
630
+ *
631
+ * A level label is drawn on whole device pixels. A street name along its
632
+ * street is drawn turned about its centre, where the context can turn —
633
+ * and level where it cannot, on a context with no transform.
390
634
  */
391
635
  export function drawLabels(
392
636
  ctx: MapCanvas,
@@ -401,30 +645,66 @@ export function drawLabels(
401
645
  const world = transform.world;
402
646
  const originX = pane.x + transform.paneX - transform.centerX * world;
403
647
  const originY = pane.y + transform.paneY - transform.centerY * world;
648
+ const turns = typeof ctx.rotate === 'function' && !!ctx.translate;
404
649
  for (const label of placed) {
405
- const x = originX + label.wx - label.shaped.width / 2;
406
- const y = originY + label.wy - label.shaped.height / 2;
650
+ const cx = originX + label.wx;
651
+ const cy = originY + label.wy;
652
+ // The box's centre, which is right of the point where an icon is on it.
653
+ const bx = cx + (label.ox ?? 0);
654
+ const halfW = label.width / 2;
655
+ const halfH = label.height / 2;
407
656
  if (
408
- x + label.shaped.width < pane.x ||
409
- y + label.shaped.height < pane.y ||
410
- x > pane.x + pane.width ||
411
- y > pane.y + pane.height
657
+ bx + halfW < pane.x ||
658
+ cy + halfH < pane.y ||
659
+ bx - halfW > pane.x + pane.width ||
660
+ cy - halfH > pane.y + pane.height
412
661
  ) {
413
662
  continue;
414
663
  }
415
664
  if (
416
665
  clip &&
417
- (x + label.shaped.width < clip.x ||
418
- y + label.shaped.height < clip.y ||
419
- x > clip.x + clip.width ||
420
- y > clip.y + clip.height)
666
+ (bx + halfW < clip.x ||
667
+ cy + halfH < clip.y ||
668
+ bx - halfW > clip.x + clip.width ||
669
+ cy - halfH > clip.y + clip.height)
421
670
  ) {
422
671
  continue;
423
672
  }
424
- const dx = Math.round(x * scale);
425
- const dy = Math.round(y * scale);
673
+ // Shaped here, for the labels in the pane: the few hundred a frame
674
+ // draws, where the placement holds every name on the tiles loaded.
675
+ const shaped = shaper.drawn(label);
676
+ if (!shaped) continue;
677
+ const { width, height } = shaped;
678
+ const icon = label.icon ?? null;
679
+ const turned = !icon && label.angle !== 0 && turns;
680
+ const haloed = label.halo !== undefined && label.haloWidth > 0;
681
+ let dx: number;
682
+ let dy: number;
683
+ if (icon) {
684
+ // The icon on the point, and the name level beside it.
685
+ drawIcon(
686
+ ctx,
687
+ icon,
688
+ Math.round(cx * scale),
689
+ Math.round(cy * scale),
690
+ icon.size * scale,
691
+ haloed ? label.halo : undefined,
692
+ Math.max(1, Math.round(label.haloWidth * scale)),
693
+ );
694
+ dx = Math.round((cx + icon.size / 2 + ICON_GAP) * scale);
695
+ dy = Math.round((cy - height / 2) * scale);
696
+ } else if (turned) {
697
+ ctx.save();
698
+ ctx.translate!(cx * scale, cy * scale);
699
+ ctx.rotate!(label.angle);
700
+ dx = (-width * scale) / 2;
701
+ dy = (-height * scale) / 2;
702
+ } else {
703
+ dx = Math.round((cx - width / 2) * scale);
704
+ dy = Math.round((cy - height / 2) * scale);
705
+ }
426
706
  if (label.halo !== undefined && label.haloWidth > 0) {
427
- const halo = shaper.shape(label.text, label.size, label.halo);
707
+ const halo = shaper.drawn(label, true);
428
708
  if (halo) {
429
709
  const offset = Math.max(1, Math.round(label.haloWidth * scale));
430
710
  halo.layout.draw(ctx, dx - offset, dy);
@@ -433,10 +713,43 @@ export function drawLabels(
433
713
  halo.layout.draw(ctx, dx, dy + offset);
434
714
  }
435
715
  }
436
- label.shaped.layout.draw(ctx, dx, dy);
716
+ shaped.layout.draw(ctx, dx, dy);
717
+ if (turned) ctx.restore();
437
718
  drawn++;
438
719
  }
439
720
  return drawn;
440
721
  }
441
722
 
723
+ /**
724
+ * An icon on its point, in device pixels: the plate, over a plate of the
725
+ * halo's colour a halo wider where the layer has one — the same ground a
726
+ * name's halo gives it over a road — and the glyph on the plate.
727
+ */
728
+ function drawIcon(
729
+ ctx: MapCanvas,
730
+ icon: LabelIcon,
731
+ x: number,
732
+ y: number,
733
+ size: number,
734
+ halo: string | undefined,
735
+ reach: number,
736
+ ): void {
737
+ ctx.save();
738
+ if (halo !== undefined) {
739
+ ctx.fillStyle = halo;
740
+ ctx.beginPath();
741
+ tracePlate(ctx, x, y, size + reach * 2);
742
+ ctx.fill();
743
+ }
744
+ ctx.fillStyle = icon.color;
745
+ ctx.beginPath();
746
+ tracePlate(ctx, x, y, size);
747
+ ctx.fill();
748
+ ctx.fillStyle = icon.glyph;
749
+ ctx.beginPath();
750
+ traceGlyph(ctx, icon.name, x, y, size);
751
+ ctx.fill();
752
+ ctx.restore();
753
+ }
754
+
442
755
  export type { PreparedLayer };