@sakuzu/maplibre-gl-draw 1.0.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 (636) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/LICENSE +661 -0
  3. package/README.ja.md +248 -0
  4. package/README.md +255 -0
  5. package/THIRD_PARTY_NOTICES.md +275 -0
  6. package/dist/api/api.d.ts +1259 -0
  7. package/dist/api/api.js +86 -0
  8. package/dist/api/context.d.ts +173 -0
  9. package/dist/api/context.js +193 -0
  10. package/dist/api/display-api.d.ts +1 -0
  11. package/dist/api/display-api.js +23 -0
  12. package/dist/api/event-api.d.ts +13 -0
  13. package/dist/api/event-api.js +17 -0
  14. package/dist/api/extension-api.d.ts +46 -0
  15. package/dist/api/extension-api.js +85 -0
  16. package/dist/api/feature-api.d.ts +11 -0
  17. package/dist/api/feature-api.js +101 -0
  18. package/dist/api/geometry/apply.d.ts +51 -0
  19. package/dist/api/geometry/apply.js +114 -0
  20. package/dist/api/geometry/boolean.d.ts +28 -0
  21. package/dist/api/geometry/boolean.js +65 -0
  22. package/dist/api/geometry/buffer.d.ts +11 -0
  23. package/dist/api/geometry/buffer.js +105 -0
  24. package/dist/api/geometry/split.d.ts +16 -0
  25. package/dist/api/geometry/split.js +75 -0
  26. package/dist/api/geometry/targets.d.ts +76 -0
  27. package/dist/api/geometry/targets.js +158 -0
  28. package/dist/api/geometry/types.d.ts +31 -0
  29. package/dist/api/geometry/types.js +3 -0
  30. package/dist/api/geometry-operations.d.ts +162 -0
  31. package/dist/api/geometry-operations.js +94 -0
  32. package/dist/api/group-api.d.ts +10 -0
  33. package/dist/api/group-api.js +78 -0
  34. package/dist/api/import-export/constants.d.ts +29 -0
  35. package/dist/api/import-export/constants.js +40 -0
  36. package/dist/api/import-export/embedded-file.d.ts +13 -0
  37. package/dist/api/import-export/embedded-file.js +31 -0
  38. package/dist/api/import-export/file-name.d.ts +10 -0
  39. package/dist/api/import-export/file-name.js +20 -0
  40. package/dist/api/import-export/format-detection.d.ts +12 -0
  41. package/dist/api/import-export/format-detection.js +29 -0
  42. package/dist/api/import-export/geojson-export.d.ts +19 -0
  43. package/dist/api/import-export/geojson-export.js +262 -0
  44. package/dist/api/import-export/geojson-import.d.ts +34 -0
  45. package/dist/api/import-export/geojson-import.js +538 -0
  46. package/dist/api/import-export/geometry-validation.d.ts +20 -0
  47. package/dist/api/import-export/geometry-validation.js +107 -0
  48. package/dist/api/import-export/image-import.d.ts +12 -0
  49. package/dist/api/import-export/image-import.js +53 -0
  50. package/dist/api/import-export/index.d.ts +9 -0
  51. package/dist/api/import-export/index.js +107 -0
  52. package/dist/api/import-export/native-format.d.ts +15 -0
  53. package/dist/api/import-export/native-format.js +126 -0
  54. package/dist/api/import-export/native-validation.d.ts +28 -0
  55. package/dist/api/import-export/native-validation.js +212 -0
  56. package/dist/api/import-export/own-property.d.ts +10 -0
  57. package/dist/api/import-export/own-property.js +19 -0
  58. package/dist/api/import-export/style-validation.d.ts +27 -0
  59. package/dist/api/import-export/style-validation.js +49 -0
  60. package/dist/api/import-export/types.d.ts +26 -0
  61. package/dist/api/import-export/types.js +3 -0
  62. package/dist/api/index.d.ts +15 -0
  63. package/dist/api/index.js +3 -0
  64. package/dist/api/input-api.d.ts +158 -0
  65. package/dist/api/input-api.js +144 -0
  66. package/dist/api/instance-api.d.ts +38 -0
  67. package/dist/api/instance-api.js +136 -0
  68. package/dist/api/layer-api.d.ts +12 -0
  69. package/dist/api/layer-api.js +62 -0
  70. package/dist/api/selection-api.d.ts +7 -0
  71. package/dist/api/selection-api.js +78 -0
  72. package/dist/api/snapping-api.d.ts +125 -0
  73. package/dist/api/snapping-api.js +50 -0
  74. package/dist/api/topology-api.d.ts +30 -0
  75. package/dist/api/topology-api.js +16 -0
  76. package/dist/api/tracing-api.d.ts +31 -0
  77. package/dist/api/tracing-api.js +16 -0
  78. package/dist/dispatcher/hit-test/box-strategies.d.ts +19 -0
  79. package/dist/dispatcher/hit-test/box-strategies.js +275 -0
  80. package/dist/dispatcher/hit-test/box-strategy.d.ts +59 -0
  81. package/dist/dispatcher/hit-test/box-strategy.js +37 -0
  82. package/dist/dispatcher/hit-test/globe-shape.d.ts +46 -0
  83. package/dist/dispatcher/hit-test/globe-shape.js +70 -0
  84. package/dist/dispatcher/hit-test/index.d.ts +14 -0
  85. package/dist/dispatcher/hit-test/index.js +9 -0
  86. package/dist/dispatcher/hit-test/local-frame.d.ts +77 -0
  87. package/dist/dispatcher/hit-test/local-frame.js +112 -0
  88. package/dist/dispatcher/hit-test/segment-grid.d.ts +32 -0
  89. package/dist/dispatcher/hit-test/segment-grid.js +79 -0
  90. package/dist/dispatcher/hit-test/service.d.ts +120 -0
  91. package/dist/dispatcher/hit-test/service.js +333 -0
  92. package/dist/dispatcher/hit-test/strategies/base.d.ts +136 -0
  93. package/dist/dispatcher/hit-test/strategies/base.js +66 -0
  94. package/dist/dispatcher/hit-test/strategies/circle.d.ts +10 -0
  95. package/dist/dispatcher/hit-test/strategies/circle.js +56 -0
  96. package/dist/dispatcher/hit-test/strategies/image.d.ts +22 -0
  97. package/dist/dispatcher/hit-test/strategies/image.js +115 -0
  98. package/dist/dispatcher/hit-test/strategies/index.d.ts +11 -0
  99. package/dist/dispatcher/hit-test/strategies/index.js +10 -0
  100. package/dist/dispatcher/hit-test/strategies/line.d.ts +17 -0
  101. package/dist/dispatcher/hit-test/strategies/line.js +30 -0
  102. package/dist/dispatcher/hit-test/strategies/multi.d.ts +44 -0
  103. package/dist/dispatcher/hit-test/strategies/multi.js +141 -0
  104. package/dist/dispatcher/hit-test/strategies/point.d.ts +20 -0
  105. package/dist/dispatcher/hit-test/strategies/point.js +29 -0
  106. package/dist/dispatcher/hit-test/strategies/polygon.d.ts +52 -0
  107. package/dist/dispatcher/hit-test/strategies/polygon.js +138 -0
  108. package/dist/dispatcher/hit-test/topmost.d.ts +48 -0
  109. package/dist/dispatcher/hit-test/topmost.js +157 -0
  110. package/dist/dispatcher/hit-test/visibility-lookup.d.ts +23 -0
  111. package/dist/dispatcher/hit-test/visibility-lookup.js +40 -0
  112. package/dist/dispatcher/index.d.ts +15 -0
  113. package/dist/dispatcher/index.js +3 -0
  114. package/dist/dispatcher/input-router.d.ts +1 -0
  115. package/dist/dispatcher/input-router.js +288 -0
  116. package/dist/dispatcher/normalizer.d.ts +1 -0
  117. package/dist/dispatcher/normalizer.js +513 -0
  118. package/dist/dispatcher/types.d.ts +144 -0
  119. package/dist/dispatcher/types.js +15 -0
  120. package/dist/display/chunk-set.d.ts +24 -0
  121. package/dist/display/chunk-set.js +533 -0
  122. package/dist/display/chunk.d.ts +1 -0
  123. package/dist/display/chunk.js +104 -0
  124. package/dist/display/columnar/index.d.ts +12 -0
  125. package/dist/display/columnar/index.js +13 -0
  126. package/dist/display/columnar/prepare.d.ts +42 -0
  127. package/dist/display/columnar/prepare.js +116 -0
  128. package/dist/display/columnar/source.d.ts +1 -0
  129. package/dist/display/columnar/source.js +531 -0
  130. package/dist/display/columnar/table.d.ts +1 -0
  131. package/dist/display/columnar/table.js +471 -0
  132. package/dist/display/columnar/types.d.ts +223 -0
  133. package/dist/display/columnar/types.js +3 -0
  134. package/dist/display/dataset.d.ts +2 -0
  135. package/dist/display/dataset.js +891 -0
  136. package/dist/display/index.d.ts +13 -0
  137. package/dist/display/index.js +3 -0
  138. package/dist/display/interaction.d.ts +1 -0
  139. package/dist/display/interaction.js +90 -0
  140. package/dist/display/manager.d.ts +1 -0
  141. package/dist/display/manager.js +440 -0
  142. package/dist/display/packed-rtree.d.ts +1 -0
  143. package/dist/display/packed-rtree.js +244 -0
  144. package/dist/display/partition.d.ts +1 -0
  145. package/dist/display/partition.js +226 -0
  146. package/dist/display/provider.d.ts +1 -0
  147. package/dist/display/provider.js +342 -0
  148. package/dist/display/retained.d.ts +40 -0
  149. package/dist/display/retained.js +898 -0
  150. package/dist/display/selection.d.ts +13 -0
  151. package/dist/display/selection.js +226 -0
  152. package/dist/display/source.d.ts +1 -0
  153. package/dist/display/source.js +119 -0
  154. package/dist/display/spatial.d.ts +1 -0
  155. package/dist/display/spatial.js +71 -0
  156. package/dist/display/style.d.ts +1 -0
  157. package/dist/display/style.js +126 -0
  158. package/dist/display/thinning.d.ts +65 -0
  159. package/dist/display/thinning.js +910 -0
  160. package/dist/display/triangulation.d.ts +1 -0
  161. package/dist/display/triangulation.js +0 -0
  162. package/dist/display/types.d.ts +561 -0
  163. package/dist/display/types.js +43 -0
  164. package/dist/extension/feature-handler.d.ts +182 -0
  165. package/dist/extension/feature-handler.js +3 -0
  166. package/dist/extension/index.d.ts +9 -0
  167. package/dist/extension/index.js +3 -0
  168. package/dist/extension/renderers.d.ts +208 -0
  169. package/dist/extension/renderers.js +3 -0
  170. package/dist/geometry/angle.d.ts +47 -0
  171. package/dist/geometry/angle.js +44 -0
  172. package/dist/geometry/bbox.d.ts +48 -0
  173. package/dist/geometry/bbox.js +83 -0
  174. package/dist/geometry/boolean.d.ts +162 -0
  175. package/dist/geometry/boolean.js +331 -0
  176. package/dist/geometry/buffer.d.ts +72 -0
  177. package/dist/geometry/buffer.js +218 -0
  178. package/dist/geometry/circle.d.ts +55 -0
  179. package/dist/geometry/circle.js +107 -0
  180. package/dist/geometry/coords.d.ts +97 -0
  181. package/dist/geometry/coords.js +149 -0
  182. package/dist/geometry/distance.d.ts +79 -0
  183. package/dist/geometry/distance.js +111 -0
  184. package/dist/geometry/errors.d.ts +74 -0
  185. package/dist/geometry/errors.js +104 -0
  186. package/dist/geometry/index.d.ts +28 -0
  187. package/dist/geometry/index.js +38 -0
  188. package/dist/geometry/measure.d.ts +81 -0
  189. package/dist/geometry/measure.js +236 -0
  190. package/dist/geometry/predicates.d.ts +62 -0
  191. package/dist/geometry/predicates.js +132 -0
  192. package/dist/geometry/simplify.d.ts +74 -0
  193. package/dist/geometry/simplify.js +159 -0
  194. package/dist/geometry/split.d.ts +68 -0
  195. package/dist/geometry/split.js +430 -0
  196. package/dist/geometry/types.d.ts +95 -0
  197. package/dist/geometry/types.js +3 -0
  198. package/dist/geometry/units.d.ts +35 -0
  199. package/dist/geometry/units.js +41 -0
  200. package/dist/index.d.ts +72 -0
  201. package/dist/index.js +20 -0
  202. package/dist/maplibre-gl-draw.d.ts +47 -0
  203. package/dist/maplibre-gl-draw.js +407 -0
  204. package/dist/messages.d.ts +64 -0
  205. package/dist/messages.js +36 -0
  206. package/dist/modes/cursor.d.ts +1 -0
  207. package/dist/modes/cursor.js +72 -0
  208. package/dist/modes/draw/circle.d.ts +1 -0
  209. package/dist/modes/draw/circle.js +222 -0
  210. package/dist/modes/draw/commit-layer.d.ts +26 -0
  211. package/dist/modes/draw/commit-layer.js +31 -0
  212. package/dist/modes/draw/freehand.d.ts +1 -0
  213. package/dist/modes/draw/freehand.js +264 -0
  214. package/dist/modes/draw/image.d.ts +1 -0
  215. package/dist/modes/draw/image.js +60 -0
  216. package/dist/modes/draw/index.d.ts +9 -0
  217. package/dist/modes/draw/index.js +11 -0
  218. package/dist/modes/draw/line.d.ts +1 -0
  219. package/dist/modes/draw/line.js +363 -0
  220. package/dist/modes/draw/point.d.ts +1 -0
  221. package/dist/modes/draw/point.js +87 -0
  222. package/dist/modes/draw/polygon.d.ts +1 -0
  223. package/dist/modes/draw/polygon.js +378 -0
  224. package/dist/modes/draw/trace-support.d.ts +79 -0
  225. package/dist/modes/draw/trace-support.js +161 -0
  226. package/dist/modes/handler.d.ts +285 -0
  227. package/dist/modes/handler.js +3 -0
  228. package/dist/modes/index.d.ts +7 -0
  229. package/dist/modes/index.js +3 -0
  230. package/dist/modes/manager.d.ts +15 -0
  231. package/dist/modes/manager.js +196 -0
  232. package/dist/modes/select/box-selection.d.ts +52 -0
  233. package/dist/modes/select/box-selection.js +140 -0
  234. package/dist/modes/select/click-handler.d.ts +32 -0
  235. package/dist/modes/select/click-handler.js +166 -0
  236. package/dist/modes/select/cursor-handler.d.ts +15 -0
  237. package/dist/modes/select/cursor-handler.js +59 -0
  238. package/dist/modes/select/drag/auxiliary.d.ts +26 -0
  239. package/dist/modes/select/drag/auxiliary.js +56 -0
  240. package/dist/modes/select/drag/intermediate-writes.d.ts +1 -0
  241. package/dist/modes/select/drag/intermediate-writes.js +171 -0
  242. package/dist/modes/select/drag/move.d.ts +24 -0
  243. package/dist/modes/select/drag/move.js +59 -0
  244. package/dist/modes/select/drag/operation.d.ts +30 -0
  245. package/dist/modes/select/drag/operation.js +18 -0
  246. package/dist/modes/select/drag/radius.d.ts +15 -0
  247. package/dist/modes/select/drag/radius.js +49 -0
  248. package/dist/modes/select/drag/transform.d.ts +17 -0
  249. package/dist/modes/select/drag/transform.js +155 -0
  250. package/dist/modes/select/drag/vertex.d.ts +17 -0
  251. package/dist/modes/select/drag/vertex.js +163 -0
  252. package/dist/modes/select/drag-handler.d.ts +1 -0
  253. package/dist/modes/select/drag-handler.js +254 -0
  254. package/dist/modes/select/hit-helpers.d.ts +40 -0
  255. package/dist/modes/select/hit-helpers.js +51 -0
  256. package/dist/modes/select/mode.d.ts +1 -0
  257. package/dist/modes/select/mode.js +397 -0
  258. package/dist/modes/select/shortcut-handler.d.ts +40 -0
  259. package/dist/modes/select/shortcut-handler.js +128 -0
  260. package/dist/operations/index.d.ts +9 -0
  261. package/dist/operations/index.js +3 -0
  262. package/dist/operations/layer-operations.d.ts +1 -0
  263. package/dist/operations/layer-operations.js +350 -0
  264. package/dist/operations/resize.d.ts +71 -0
  265. package/dist/operations/resize.js +252 -0
  266. package/dist/operations/rotate.d.ts +17 -0
  267. package/dist/operations/rotate.js +166 -0
  268. package/dist/operations/selection-operations.d.ts +20 -0
  269. package/dist/operations/selection-operations.js +159 -0
  270. package/dist/operations/shared-vertex.d.ts +1 -0
  271. package/dist/operations/shared-vertex.js +210 -0
  272. package/dist/operations/trace-graph.d.ts +96 -0
  273. package/dist/operations/trace-graph.js +283 -0
  274. package/dist/operations/vertex.d.ts +1 -0
  275. package/dist/operations/vertex.js +538 -0
  276. package/dist/plugins/index.d.ts +10 -0
  277. package/dist/plugins/index.js +3 -0
  278. package/dist/plugins/mutation-hooks.d.ts +28 -0
  279. package/dist/plugins/mutation-hooks.js +84 -0
  280. package/dist/plugins/plugin-context.d.ts +1 -0
  281. package/dist/plugins/plugin-context.js +367 -0
  282. package/dist/plugins/plugin-manager.d.ts +103 -0
  283. package/dist/plugins/plugin-manager.js +316 -0
  284. package/dist/plugins/plugin.d.ts +529 -0
  285. package/dist/plugins/plugin.js +3 -0
  286. package/dist/shared/config/constants.d.ts +66 -0
  287. package/dist/shared/config/constants.js +60 -0
  288. package/dist/shared/config/feature-style.d.ts +155 -0
  289. package/dist/shared/config/feature-style.js +154 -0
  290. package/dist/shared/config/index.d.ts +17 -0
  291. package/dist/shared/config/index.js +8 -0
  292. package/dist/shared/config/rendering.d.ts +107 -0
  293. package/dist/shared/config/rendering.js +33 -0
  294. package/dist/shared/config/selection-highlight.d.ts +29 -0
  295. package/dist/shared/config/selection-highlight.js +35 -0
  296. package/dist/shared/config/selection.d.ts +273 -0
  297. package/dist/shared/config/selection.js +266 -0
  298. package/dist/shared/config/topology.d.ts +33 -0
  299. package/dist/shared/config/topology.js +17 -0
  300. package/dist/shared/config/trace.d.ts +40 -0
  301. package/dist/shared/config/trace.js +17 -0
  302. package/dist/shared/math/angle.d.ts +21 -0
  303. package/dist/shared/math/angle.js +34 -0
  304. package/dist/shared/math/circle.d.ts +6 -0
  305. package/dist/shared/math/circle.js +10 -0
  306. package/dist/shared/math/constants.d.ts +48 -0
  307. package/dist/shared/math/constants.js +59 -0
  308. package/dist/shared/math/distance.d.ts +78 -0
  309. package/dist/shared/math/distance.js +147 -0
  310. package/dist/shared/math/globe-subdivision.d.ts +62 -0
  311. package/dist/shared/math/globe-subdivision.js +99 -0
  312. package/dist/shared/math/index.d.ts +17 -0
  313. package/dist/shared/math/index.js +21 -0
  314. package/dist/shared/math/intersection.d.ts +63 -0
  315. package/dist/shared/math/intersection.js +236 -0
  316. package/dist/shared/math/longitude.d.ts +20 -0
  317. package/dist/shared/math/longitude.js +31 -0
  318. package/dist/shared/math/mercator-plane.d.ts +27 -0
  319. package/dist/shared/math/mercator-plane.js +26 -0
  320. package/dist/shared/math/obb.d.ts +65 -0
  321. package/dist/shared/math/obb.js +107 -0
  322. package/dist/shared/math/rotation.d.ts +93 -0
  323. package/dist/shared/math/rotation.js +186 -0
  324. package/dist/shared/math/segment-grid.d.ts +69 -0
  325. package/dist/shared/math/segment-grid.js +159 -0
  326. package/dist/shared/math/transform.d.ts +140 -0
  327. package/dist/shared/math/transform.js +189 -0
  328. package/dist/shared/types/events.d.ts +128 -0
  329. package/dist/shared/types/events.js +3 -0
  330. package/dist/shared/types/model.d.ts +950 -0
  331. package/dist/shared/types/model.js +3 -0
  332. package/dist/shared/types/selection-box.d.ts +23 -0
  333. package/dist/shared/types/selection-box.js +3 -0
  334. package/dist/shared/types/style.d.ts +68 -0
  335. package/dist/shared/types/style.js +3 -0
  336. package/dist/shared/utils/color.d.ts +49 -0
  337. package/dist/shared/utils/color.js +180 -0
  338. package/dist/shared/utils/coordinates.d.ts +52 -0
  339. package/dist/shared/utils/coordinates.js +75 -0
  340. package/dist/shared/utils/embedded-image.d.ts +34 -0
  341. package/dist/shared/utils/embedded-image.js +161 -0
  342. package/dist/shared/utils/event-emitter.d.ts +262 -0
  343. package/dist/shared/utils/event-emitter.js +44 -0
  344. package/dist/shared/utils/feature-bbox.d.ts +8 -0
  345. package/dist/shared/utils/feature-bbox.js +207 -0
  346. package/dist/shared/utils/feature-segments.d.ts +23 -0
  347. package/dist/shared/utils/feature-segments.js +179 -0
  348. package/dist/shared/utils/id.d.ts +1 -0
  349. package/dist/shared/utils/id.js +35 -0
  350. package/dist/shared/utils/image.d.ts +34 -0
  351. package/dist/shared/utils/image.js +106 -0
  352. package/dist/shared/utils/index.d.ts +15 -0
  353. package/dist/shared/utils/index.js +24 -0
  354. package/dist/shared/utils/map.d.ts +26 -0
  355. package/dist/shared/utils/map.js +35 -0
  356. package/dist/shared/utils/name-generator.d.ts +197 -0
  357. package/dist/shared/utils/name-generator.js +337 -0
  358. package/dist/shared/utils/pixel-ratio.d.ts +111 -0
  359. package/dist/shared/utils/pixel-ratio.js +85 -0
  360. package/dist/shared/utils/property.d.ts +88 -0
  361. package/dist/shared/utils/property.js +140 -0
  362. package/dist/shared/utils/vertex-ref.d.ts +23 -0
  363. package/dist/shared/utils/vertex-ref.js +20 -0
  364. package/dist/snapping/custom-targets.d.ts +1 -0
  365. package/dist/snapping/custom-targets.js +21 -0
  366. package/dist/snapping/geometry.d.ts +1 -0
  367. package/dist/snapping/geometry.js +61 -0
  368. package/dist/snapping/index.d.ts +14 -0
  369. package/dist/snapping/index.js +4 -0
  370. package/dist/snapping/indicator.d.ts +19 -0
  371. package/dist/snapping/indicator.js +145 -0
  372. package/dist/snapping/providers/display.d.ts +72 -0
  373. package/dist/snapping/providers/display.js +268 -0
  374. package/dist/snapping/providers/guide.d.ts +69 -0
  375. package/dist/snapping/providers/guide.js +187 -0
  376. package/dist/snapping/providers/intersection.d.ts +1 -0
  377. package/dist/snapping/providers/intersection.js +92 -0
  378. package/dist/snapping/providers/shared.d.ts +39 -0
  379. package/dist/snapping/providers/shared.js +146 -0
  380. package/dist/snapping/providers/store.d.ts +1 -0
  381. package/dist/snapping/providers/store.js +132 -0
  382. package/dist/snapping/service.d.ts +1 -0
  383. package/dist/snapping/service.js +272 -0
  384. package/dist/snapping/types.d.ts +267 -0
  385. package/dist/snapping/types.js +66 -0
  386. package/dist/store/change-merger.d.ts +1 -0
  387. package/dist/store/change-merger.js +102 -0
  388. package/dist/store/draw-store.d.ts +1 -0
  389. package/dist/store/draw-store.js +396 -0
  390. package/dist/store/event-bridge.d.ts +1 -0
  391. package/dist/store/event-bridge.js +161 -0
  392. package/dist/store/index.d.ts +12 -0
  393. package/dist/store/index.js +4 -0
  394. package/dist/store/local-visibility.d.ts +21 -0
  395. package/dist/store/local-visibility.js +27 -0
  396. package/dist/store/lock.d.ts +67 -0
  397. package/dist/store/lock.js +54 -0
  398. package/dist/store/memory/change-bus.d.ts +60 -0
  399. package/dist/store/memory/change-bus.js +232 -0
  400. package/dist/store/memory/file-store.d.ts +15 -0
  401. package/dist/store/memory/file-store.js +33 -0
  402. package/dist/store/memory/frozen.d.ts +21 -0
  403. package/dist/store/memory/frozen.js +51 -0
  404. package/dist/store/memory/ui-state.d.ts +51 -0
  405. package/dist/store/memory/ui-state.js +223 -0
  406. package/dist/store/memory.d.ts +26 -0
  407. package/dist/store/memory.js +708 -0
  408. package/dist/store/spatial/index.d.ts +6 -0
  409. package/dist/store/spatial/index.js +4 -0
  410. package/dist/store/spatial/spatial-index.d.ts +90 -0
  411. package/dist/store/spatial/spatial-index.js +148 -0
  412. package/dist/store/spatial/store-spatial-index.d.ts +60 -0
  413. package/dist/store/spatial/store-spatial-index.js +125 -0
  414. package/dist/store/store.d.ts +417 -0
  415. package/dist/store/store.js +3 -0
  416. package/dist/store/types.d.ts +8 -0
  417. package/dist/store/types.js +3 -0
  418. package/dist/store/writable-layer.d.ts +35 -0
  419. package/dist/store/writable-layer.js +20 -0
  420. package/dist/view/cache/buffer.d.ts +28 -0
  421. package/dist/view/cache/buffer.js +176 -0
  422. package/dist/view/cache/earcut.d.ts +1 -0
  423. package/dist/view/cache/earcut.js +122 -0
  424. package/dist/view/cache/style-rule.d.ts +1 -0
  425. package/dist/view/cache/style-rule.js +97 -0
  426. package/dist/view/cache/terrain-fill.d.ts +30 -0
  427. package/dist/view/cache/terrain-fill.js +60 -0
  428. package/dist/view/cache/texture.d.ts +14 -0
  429. package/dist/view/cache/texture.js +292 -0
  430. package/dist/view/coordinator.d.ts +27 -0
  431. package/dist/view/coordinator.js +72 -0
  432. package/dist/view/feature-companion.d.ts +173 -0
  433. package/dist/view/feature-companion.js +108 -0
  434. package/dist/view/globe-subdivision.d.ts +78 -0
  435. package/dist/view/globe-subdivision.js +128 -0
  436. package/dist/view/index.d.ts +47 -0
  437. package/dist/view/index.js +20 -0
  438. package/dist/view/layer/attach.d.ts +20 -0
  439. package/dist/view/layer/attach.js +47 -0
  440. package/dist/view/layer/blend.d.ts +57 -0
  441. package/dist/view/layer/blend.js +14 -0
  442. package/dist/view/layer/custom-layer.d.ts +1 -0
  443. package/dist/view/layer/custom-layer.js +509 -0
  444. package/dist/view/layer/depth-state.d.ts +14 -0
  445. package/dist/view/layer/depth-state.js +44 -0
  446. package/dist/view/layer/display-list.d.ts +1 -0
  447. package/dist/view/layer/display-list.js +111 -0
  448. package/dist/view/layer/drape-planner.d.ts +139 -0
  449. package/dist/view/layer/drape-planner.js +726 -0
  450. package/dist/view/layer/frame-render.d.ts +57 -0
  451. package/dist/view/layer/frame-render.js +209 -0
  452. package/dist/view/layer/frame-state.d.ts +147 -0
  453. package/dist/view/layer/frame-state.js +484 -0
  454. package/dist/view/layer/gl-state.d.ts +77 -0
  455. package/dist/view/layer/gl-state.js +132 -0
  456. package/dist/view/layer/index.d.ts +6 -0
  457. package/dist/view/layer/index.js +5 -0
  458. package/dist/view/layer/render-scope.d.ts +30 -0
  459. package/dist/view/layer/render-scope.js +28 -0
  460. package/dist/view/layer/render.d.ts +87 -0
  461. package/dist/view/layer/render.js +187 -0
  462. package/dist/view/layer/renderers.d.ts +81 -0
  463. package/dist/view/layer/renderers.js +142 -0
  464. package/dist/view/layer/slot-manager.d.ts +26 -0
  465. package/dist/view/layer/slot-manager.js +133 -0
  466. package/dist/view/layer/slots.d.ts +33 -0
  467. package/dist/view/layer/slots.js +50 -0
  468. package/dist/view/layer/store-retained-bbox.d.ts +36 -0
  469. package/dist/view/layer/store-retained-bbox.js +188 -0
  470. package/dist/view/layer/store-retained-chunk.d.ts +97 -0
  471. package/dist/view/layer/store-retained-chunk.js +94 -0
  472. package/dist/view/layer/store-retained-classify.d.ts +34 -0
  473. package/dist/view/layer/store-retained-classify.js +88 -0
  474. package/dist/view/layer/store-retained-collect.d.ts +24 -0
  475. package/dist/view/layer/store-retained-collect.js +121 -0
  476. package/dist/view/layer/store-retained-coord-patch.d.ts +119 -0
  477. package/dist/view/layer/store-retained-coord-patch.js +168 -0
  478. package/dist/view/layer/store-retained-immediate.d.ts +63 -0
  479. package/dist/view/layer/store-retained-immediate.js +49 -0
  480. package/dist/view/layer/store-retained-invalidation.d.ts +96 -0
  481. package/dist/view/layer/store-retained-invalidation.js +192 -0
  482. package/dist/view/layer/store-retained.d.ts +198 -0
  483. package/dist/view/layer/store-retained.js +430 -0
  484. package/dist/view/layer/terrain-resolver.d.ts +1 -0
  485. package/dist/view/layer/terrain-resolver.js +174 -0
  486. package/dist/view/renderers/batch-manager.d.ts +61 -0
  487. package/dist/view/renderers/batch-manager.js +718 -0
  488. package/dist/view/renderers/draw-factors.d.ts +60 -0
  489. package/dist/view/renderers/draw-factors.js +35 -0
  490. package/dist/view/renderers/drawer.d.ts +1 -0
  491. package/dist/view/renderers/drawer.js +346 -0
  492. package/dist/view/renderers/image.d.ts +1 -0
  493. package/dist/view/renderers/image.js +255 -0
  494. package/dist/view/renderers/line/dash.d.ts +31 -0
  495. package/dist/view/renderers/line/dash.js +152 -0
  496. package/dist/view/renderers/line/line-geometry.d.ts +39 -0
  497. package/dist/view/renderers/line/line-geometry.js +460 -0
  498. package/dist/view/renderers/line/line-gl.d.ts +1 -0
  499. package/dist/view/renderers/line/line-gl.js +236 -0
  500. package/dist/view/renderers/line/line-shader.d.ts +1 -0
  501. package/dist/view/renderers/line/line-shader.js +364 -0
  502. package/dist/view/renderers/line/line-types.d.ts +43 -0
  503. package/dist/view/renderers/line/line-types.js +3 -0
  504. package/dist/view/renderers/line/line-uniforms.d.ts +1 -0
  505. package/dist/view/renderers/line/line-uniforms.js +390 -0
  506. package/dist/view/renderers/line/sdf-line.d.ts +92 -0
  507. package/dist/view/renderers/line/sdf-line.js +567 -0
  508. package/dist/view/renderers/point/billboard-depth.d.ts +10 -0
  509. package/dist/view/renderers/point/billboard-depth.js +56 -0
  510. package/dist/view/renderers/point/point-instance.d.ts +124 -0
  511. package/dist/view/renderers/point/point-instance.js +738 -0
  512. package/dist/view/renderers/point/point-sdf.d.ts +58 -0
  513. package/dist/view/renderers/point/point-sdf.js +170 -0
  514. package/dist/view/renderers/point/point-shape.d.ts +99 -0
  515. package/dist/view/renderers/point/point-shape.js +504 -0
  516. package/dist/view/renderers/point/point-style.d.ts +1 -0
  517. package/dist/view/renderers/point/point-style.js +46 -0
  518. package/dist/view/renderers/polygon/batch.d.ts +26 -0
  519. package/dist/view/renderers/polygon/batch.js +336 -0
  520. package/dist/view/renderers/polygon/earcut-input.d.ts +37 -0
  521. package/dist/view/renderers/polygon/earcut-input.js +55 -0
  522. package/dist/view/renderers/polygon/earcut-sliced.d.ts +69 -0
  523. package/dist/view/renderers/polygon/earcut-sliced.js +960 -0
  524. package/dist/view/renderers/polygon/fill.d.ts +74 -0
  525. package/dist/view/renderers/polygon/fill.js +251 -0
  526. package/dist/view/renderers/polygon/sdf-polygon.d.ts +62 -0
  527. package/dist/view/renderers/polygon/sdf-polygon.js +919 -0
  528. package/dist/view/renderers/polygon/terrain-cull.d.ts +3 -0
  529. package/dist/view/renderers/polygon/terrain-cull.js +14 -0
  530. package/dist/view/renderers/polygon/triangulator.d.ts +41 -0
  531. package/dist/view/renderers/polygon/triangulator.js +3 -0
  532. package/dist/view/renderers/retained.d.ts +43 -0
  533. package/dist/view/renderers/retained.js +3 -0
  534. package/dist/view/renderers/stroke.d.ts +121 -0
  535. package/dist/view/renderers/stroke.js +621 -0
  536. package/dist/view/shaders/frame.d.ts +8 -0
  537. package/dist/view/shaders/frame.js +37 -0
  538. package/dist/view/shaders/helpers.d.ts +238 -0
  539. package/dist/view/shaders/helpers.js +611 -0
  540. package/dist/view/shaders/initializer.d.ts +27 -0
  541. package/dist/view/shaders/initializer.js +125 -0
  542. package/dist/view/shaders/projection.d.ts +123 -0
  543. package/dist/view/shaders/projection.js +299 -0
  544. package/dist/view/shaders/quad-grid.d.ts +77 -0
  545. package/dist/view/shaders/quad-grid.js +128 -0
  546. package/dist/view/shaders/quad.d.ts +189 -0
  547. package/dist/view/shaders/quad.js +582 -0
  548. package/dist/view/shaders/retained-origin.d.ts +50 -0
  549. package/dist/view/shaders/retained-origin.js +67 -0
  550. package/dist/view/shaders/terrain-shade.d.ts +23 -0
  551. package/dist/view/shaders/terrain-shade.js +93 -0
  552. package/dist/view/style-rule.d.ts +166 -0
  553. package/dist/view/style-rule.js +300 -0
  554. package/dist/view/terrain/anchor.d.ts +135 -0
  555. package/dist/view/terrain/anchor.js +226 -0
  556. package/dist/view/terrain/context.d.ts +132 -0
  557. package/dist/view/terrain/context.js +437 -0
  558. package/dist/view/terrain/dem-atlas.d.ts +97 -0
  559. package/dist/view/terrain/dem-atlas.js +534 -0
  560. package/dist/view/terrain/detect.d.ts +126 -0
  561. package/dist/view/terrain/detect.js +198 -0
  562. package/dist/view/terrain/drape/bin-store.d.ts +179 -0
  563. package/dist/view/terrain/drape/bin-store.js +529 -0
  564. package/dist/view/terrain/drape/binning.d.ts +259 -0
  565. package/dist/view/terrain/drape/binning.js +604 -0
  566. package/dist/view/terrain/drape/edge-constrain.d.ts +37 -0
  567. package/dist/view/terrain/drape/edge-constrain.js +175 -0
  568. package/dist/view/terrain/drape/geometry.d.ts +95 -0
  569. package/dist/view/terrain/drape/geometry.js +260 -0
  570. package/dist/view/terrain/drape/mesh.d.ts +50 -0
  571. package/dist/view/terrain/drape/mesh.js +86 -0
  572. package/dist/view/terrain/drape/pass.d.ts +122 -0
  573. package/dist/view/terrain/drape/pass.js +379 -0
  574. package/dist/view/terrain/drape/quad-glyphs.d.ts +64 -0
  575. package/dist/view/terrain/drape/quad-glyphs.js +117 -0
  576. package/dist/view/terrain/drape/quad.d.ts +249 -0
  577. package/dist/view/terrain/drape/quad.js +835 -0
  578. package/dist/view/terrain/drape/renderer.d.ts +184 -0
  579. package/dist/view/terrain/drape/renderer.js +706 -0
  580. package/dist/view/terrain/drape/shared.d.ts +80 -0
  581. package/dist/view/terrain/drape/shared.js +173 -0
  582. package/dist/view/terrain/drape/stitch.d.ts +155 -0
  583. package/dist/view/terrain/drape/stitch.js +228 -0
  584. package/dist/view/terrain/ground.d.ts +72 -0
  585. package/dist/view/terrain/ground.js +151 -0
  586. package/dist/view/terrain/metrics.d.ts +180 -0
  587. package/dist/view/terrain/metrics.js +231 -0
  588. package/dist/view/terrain/occlusion.d.ts +11 -0
  589. package/dist/view/terrain/occlusion.js +129 -0
  590. package/dist/view/terrain/polygon.d.ts +86 -0
  591. package/dist/view/terrain/polygon.js +301 -0
  592. package/dist/view/terrain/shade.d.ts +48 -0
  593. package/dist/view/terrain/shade.js +45 -0
  594. package/dist/view/terrain/state.d.ts +99 -0
  595. package/dist/view/terrain/state.js +186 -0
  596. package/dist/view/terrain/tessellation.d.ts +265 -0
  597. package/dist/view/terrain/tessellation.js +924 -0
  598. package/dist/view/terrain/tiling.d.ts +56 -0
  599. package/dist/view/terrain/tiling.js +155 -0
  600. package/dist/view/terrain/upstream-terrain.d.ts +82 -0
  601. package/dist/view/terrain/upstream-terrain.js +116 -0
  602. package/dist/view/ui/auxiliary-handles.d.ts +151 -0
  603. package/dist/view/ui/auxiliary-handles.js +22 -0
  604. package/dist/view/ui/bounds.d.ts +53 -0
  605. package/dist/view/ui/bounds.js +149 -0
  606. package/dist/view/ui/box-selection.d.ts +1 -0
  607. package/dist/view/ui/box-selection.js +83 -0
  608. package/dist/view/ui/handle-test.d.ts +1 -0
  609. package/dist/view/ui/handle-test.js +437 -0
  610. package/dist/view/ui/handle-thinning.d.ts +122 -0
  611. package/dist/view/ui/handle-thinning.js +430 -0
  612. package/dist/view/ui/handles.d.ts +25 -0
  613. package/dist/view/ui/handles.js +673 -0
  614. package/dist/view/ui/helper.d.ts +19 -0
  615. package/dist/view/ui/helper.js +76 -0
  616. package/dist/view/ui/index.d.ts +15 -0
  617. package/dist/view/ui/index.js +15 -0
  618. package/dist/view/ui/selection-scope.d.ts +25 -0
  619. package/dist/view/ui/selection-scope.js +34 -0
  620. package/dist/view/ui/selection-ui/bounding-box.d.ts +44 -0
  621. package/dist/view/ui/selection-ui/bounding-box.js +240 -0
  622. package/dist/view/ui/selection-ui/extension-registry.d.ts +76 -0
  623. package/dist/view/ui/selection-ui/extension-registry.js +78 -0
  624. package/dist/view/ui/selection-ui/index.d.ts +12 -0
  625. package/dist/view/ui/selection-ui/index.js +12 -0
  626. package/dist/view/ui/selection-ui/renderer.d.ts +29 -0
  627. package/dist/view/ui/selection-ui/renderer.js +227 -0
  628. package/dist/view/ui/selection-ui/types.d.ts +55 -0
  629. package/dist/view/ui/selection-ui/types.js +3 -0
  630. package/dist/view/ui/selection-ui-drawer.d.ts +52 -0
  631. package/dist/view/ui/selection-ui-drawer.js +329 -0
  632. package/dist/view/ui/tentative.d.ts +1 -0
  633. package/dist/view/ui/tentative.js +320 -0
  634. package/dist/view/viewport.d.ts +119 -0
  635. package/dist/view/viewport.js +254 -0
  636. package/package.json +113 -0
@@ -0,0 +1,910 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * The zoom at which the thinning stops (default). At or above it every feature is drawn
5
+ *
6
+ * @internal
7
+ */
8
+ export const DEFAULT_FULL_DISPLAY_ZOOM = 17;
9
+ /**
10
+ * Margin added to a footprint (px, default)
11
+ *
12
+ * @internal
13
+ */
14
+ export const DEFAULT_THINNING_MARGIN_PX = 2;
15
+ /**
16
+ * How many bands of winners a dataset keeps (one byte per row each). A zoom gesture crosses a few
17
+ * bands; going back and forth over them costs no selection
18
+ */
19
+ const MAX_CACHED_BANDS = 6;
20
+ /** Upper limit of the zoom bands (22 steps, the same as the tile coordinates) */
21
+ const MAX_ZOOM_BAND = 22;
22
+ /** Screen pixels of one tile of the mercator world coordinates (512px tiles) */
23
+ const TILE_SIZE_PX = 512;
24
+ /** Upper limit of the latitude that Web Mercator can express */
25
+ const MAX_MERCATOR_LAT = 85.0511287798066;
26
+ /**
27
+ * Resolves the settings (an unspecified item takes its default)
28
+ *
29
+ * fullDisplayZoom and marginPx fall back to their defaults for an invalid value (NaN, negative).
30
+ *
31
+ * @internal
32
+ */
33
+ export function resolveCollisionThinning(input) {
34
+ return {
35
+ enabled: input?.enabled ?? false,
36
+ fullDisplayZoom: input?.fullDisplayZoom !== undefined && Number.isFinite(input.fullDisplayZoom)
37
+ ? input.fullDisplayZoom
38
+ : DEFAULT_FULL_DISPLAY_ZOOM,
39
+ marginPx: input?.marginPx !== undefined && Number.isFinite(input.marginPx) && input.marginPx >= 0
40
+ ? input.marginPx
41
+ : DEFAULT_THINNING_MARGIN_PX,
42
+ };
43
+ }
44
+ /**
45
+ * Whether two settings are the same
46
+ *
47
+ * @internal
48
+ */
49
+ export function sameCollisionThinning(a, b) {
50
+ if (a === null || b === null)
51
+ return a === b;
52
+ return (a.enabled === b.enabled && a.fullDisplayZoom === b.fullDisplayZoom && a.marginPx === b.marginPx);
53
+ }
54
+ /**
55
+ * Computes the integer band from a zoom (clamped into 0..22)
56
+ *
57
+ * @internal
58
+ */
59
+ export function zoomBandFor(zoom) {
60
+ if (!Number.isFinite(zoom))
61
+ return 0;
62
+ return Math.min(MAX_ZOOM_BAND, Math.max(0, Math.floor(zoom)));
63
+ }
64
+ /**
65
+ * The length in mercator world coordinates that corresponds to one screen pixel in band b
66
+ *
67
+ * The whole world is `512 * 2^b` px on a side, so it is the reciprocal of that. It works not
68
+ * only for an integer band but also for a fractional zoom such as an effective zoom.
69
+ *
70
+ * @internal
71
+ */
72
+ export function worldUnitsPerPixel(band) {
73
+ return 1 / (TILE_SIZE_PX * 2 ** band);
74
+ }
75
+ /**
76
+ * Upper limit of the drop of the effective zoom allowed by the pitch correction
77
+ *
78
+ * When the pitch is large and the horizon enters the screen, the top edge goes to infinity and
79
+ * the ratio diverges. The cap keeps the band from falling to 0 and tipping into "almost nothing
80
+ * is drawn". At the default maximum pitch of 60 degrees the drop is about 3.2, so it normally
81
+ * has no effect.
82
+ *
83
+ * @internal
84
+ */
85
+ export const MAX_PITCH_ZOOM_DROP = 8;
86
+ /**
87
+ * Computes the shallowest effective zoom on screen (a pure function)
88
+ *
89
+ * With a pitch, the higher part of the screen is farther away and only there the effective scale
90
+ * gets shallower. Deciding the band with the zoom of the camera would let everything flow into
91
+ * the distance and get squashed. So the ratio "how many pixels the distance from the center of
92
+ * the screen to the top center would correspond to on a plane (pitch 0)" is measured, and the
93
+ * zoom is lowered by that much.
94
+ *
95
+ * - On a plane, the distance in mercator world coordinates from the center to the top edge
96
+ * matches `pixelDistance / (512 * 2^zoom)` exactly (ratio = 1), so at pitch 0 the result is
97
+ * exactly the zoom
98
+ * - The same camera state always returns the same value (it is deterministic)
99
+ * - The drop is capped by `MAX_PITCH_ZOOM_DROP`
100
+ *
101
+ * @param zoom The zoom of the camera
102
+ * @param center The map coordinate of the center of the screen
103
+ * @param topCenter The map coordinate of the top center of the screen
104
+ * @param pixelDistance The screen pixels from the center to the top edge (half the height)
105
+ *
106
+ * @internal
107
+ */
108
+ export function effectiveZoomForPitch(input) {
109
+ const { zoom, center, topCenter, pixelDistance } = input;
110
+ if (!Number.isFinite(zoom))
111
+ return zoom;
112
+ if (!Number.isFinite(pixelDistance) || pixelDistance <= 0)
113
+ return zoom;
114
+ const dx = lngToWorldX(topCenter[0]) - lngToWorldX(center[0]);
115
+ const dy = latToWorldY(topCenter[1]) - latToWorldY(center[1]);
116
+ const measured = Math.sqrt(dx * dx + dy * dy);
117
+ const flat = pixelDistance * worldUnitsPerPixel(zoom);
118
+ if (!Number.isFinite(measured) || measured <= 0 || flat <= 0)
119
+ return zoom;
120
+ const ratio = measured / flat;
121
+ // When the ratio is at most 1 (pitch 0, rounding error) the zoom of the camera is used as before
122
+ if (!Number.isFinite(ratio) || ratio <= 1)
123
+ return zoom;
124
+ return Math.max(zoom - MAX_PITCH_ZOOM_DROP, zoom - Math.log2(ratio));
125
+ }
126
+ /**
127
+ * Computes the effective zoom from the camera
128
+ *
129
+ * When the pitch is 0 it returns the zoom of the camera without measuring anything (so even with
130
+ * a projection that cannot be measured on a plane, such as globe, the result is exactly the same
131
+ * as before as long as there is no pitch).
132
+ *
133
+ * @internal
134
+ */
135
+ export function effectiveZoomForCamera(camera) {
136
+ const zoom = camera.getZoom();
137
+ const pitch = camera.getPitch();
138
+ if (!Number.isFinite(pitch) || pitch <= 0)
139
+ return zoom;
140
+ const canvas = camera.getCanvas();
141
+ const width = canvas.clientWidth;
142
+ const height = canvas.clientHeight;
143
+ if (!(width > 0) || !(height > 0))
144
+ return zoom;
145
+ const centerX = width / 2;
146
+ const centerY = height / 2;
147
+ const center = camera.unproject([centerX, centerY]);
148
+ const topCenter = camera.unproject([centerX, 0]);
149
+ return effectiveZoomForPitch({
150
+ zoom,
151
+ center: [center.lng, center.lat],
152
+ topCenter: [topCenter.lng, topCenter.lat],
153
+ pixelDistance: centerY,
154
+ });
155
+ }
156
+ /**
157
+ * Longitude into the mercator world coordinate X (0..1)
158
+ *
159
+ * @internal
160
+ */
161
+ export function lngToWorldX(lng) {
162
+ return (Math.min(180, Math.max(-180, lng)) + 180) / 360;
163
+ }
164
+ /**
165
+ * Latitude into the mercator world coordinate Y (0..1)
166
+ *
167
+ * @internal
168
+ */
169
+ export function latToWorldY(lat) {
170
+ const clamped = Math.min(MAX_MERCATOR_LAT, Math.max(-MAX_MERCATOR_LAT, lat));
171
+ const rad = (clamped * Math.PI) / 180;
172
+ return (1 - Math.log(Math.tan(rad) + 1 / Math.cos(rad)) / Math.PI) / 2;
173
+ }
174
+ /**
175
+ * Computes the radius (px) at which a point marker is drawn
176
+ *
177
+ * It is "the size that appears on screen": the radius of the fill plus the width of the white
178
+ * outline, multiplied by the zoom-dependent factor. The radius is resolved in the same order as
179
+ * on the rendering side (FeatureDrawer.getPointStyle): "the individual style > the base style >
180
+ * the core default". The outline width of a point cannot be changed by an individual style, so
181
+ * the default value is used as it is.
182
+ *
183
+ * Both the footprint of the thinning (with the margin added) and the hit radius of the hit
184
+ * testing (grabbable exactly as it looks) go through this single place.
185
+ *
186
+ * @param styleRadius The radius of the individual style (undefined when there is none)
187
+ * @param baseStyle The base style of the dataset
188
+ * @param defaults The default point style of core
189
+ * @param scale The zoom-dependent size factor (the scale of zoomScale)
190
+ *
191
+ * @internal
192
+ */
193
+ export function pointMarkerRadiusPx(styleRadius, baseStyle, defaults, scale) {
194
+ const radius = styleRadius ?? baseStyle?.point?.pointRadius ?? defaults.size / 2;
195
+ const stroke = defaults.strokeOpacity > 0 ? defaults.strokeWidth : 0;
196
+ return Math.max(0, (radius + stroke) * scale);
197
+ }
198
+ /**
199
+ * Computes the footprint radius (px) of a point
200
+ *
201
+ * The decision uses the size actually drawn, so the margin is added to the radius that is drawn
202
+ * (`pointMarkerRadiusPx`).
203
+ *
204
+ * @param feature The target (a Point)
205
+ * @param baseStyle The base style of the dataset
206
+ * @param defaults The default point style of core
207
+ * @param scale The zoom-dependent size factor (the scale of zoomScale)
208
+ * @param marginPx The margin (px)
209
+ *
210
+ * @internal
211
+ */
212
+ export function pointFootprintPx(feature, baseStyle, defaults, scale, marginPx) {
213
+ return pointMarkerRadiusPx(feature.style?.pointRadius, baseStyle, defaults, scale) + marginPx;
214
+ }
215
+ /**
216
+ * The number of rows handled between two looks at the clock by a selection advanced in slices
217
+ *
218
+ * @internal
219
+ */
220
+ export const SELECTION_SLICE_ROWS = 4096;
221
+ /**
222
+ * The selection of the winners of one band, advanced in slices (`step`)
223
+ *
224
+ * The work is the same as `selectCollisionWinnerRows`, in two phases that both stop at a deadline:
225
+ * the rows are read into arrays of points in world coordinates, then the points are taken
226
+ * greedily from the front. Whatever the slicing, the result is the same as a selection run in one
227
+ * go (the greedy order and the grid do not depend on where it stopped).
228
+ *
229
+ * @internal
230
+ */
231
+ export class CollisionSelection {
232
+ /**
233
+ * @param radiusPx The footprint radius of a row (px, including the outline and the margin)
234
+ */
235
+ constructor(rows, band, radiusPx) {
236
+ Object.defineProperty(this, "rows", {
237
+ enumerable: true,
238
+ configurable: true,
239
+ writable: true,
240
+ value: rows
241
+ });
242
+ Object.defineProperty(this, "radiusPx", {
243
+ enumerable: true,
244
+ configurable: true,
245
+ writable: true,
246
+ value: radiusPx
247
+ });
248
+ Object.defineProperty(this, "winners", {
249
+ enumerable: true,
250
+ configurable: true,
251
+ writable: true,
252
+ value: void 0
253
+ });
254
+ Object.defineProperty(this, "xs", {
255
+ enumerable: true,
256
+ configurable: true,
257
+ writable: true,
258
+ value: void 0
259
+ });
260
+ Object.defineProperty(this, "ys", {
261
+ enumerable: true,
262
+ configurable: true,
263
+ writable: true,
264
+ value: void 0
265
+ });
266
+ Object.defineProperty(this, "rs", {
267
+ enumerable: true,
268
+ configurable: true,
269
+ writable: true,
270
+ value: void 0
271
+ });
272
+ Object.defineProperty(this, "pointRows", {
273
+ enumerable: true,
274
+ configurable: true,
275
+ writable: true,
276
+ value: void 0
277
+ });
278
+ Object.defineProperty(this, "perPixel", {
279
+ enumerable: true,
280
+ configurable: true,
281
+ writable: true,
282
+ value: void 0
283
+ });
284
+ /** The next row to read (the first phase) */
285
+ Object.defineProperty(this, "nextRow", {
286
+ enumerable: true,
287
+ configurable: true,
288
+ writable: true,
289
+ value: 0
290
+ });
291
+ Object.defineProperty(this, "pointCount", {
292
+ enumerable: true,
293
+ configurable: true,
294
+ writable: true,
295
+ value: 0
296
+ });
297
+ Object.defineProperty(this, "maxRadius", {
298
+ enumerable: true,
299
+ configurable: true,
300
+ writable: true,
301
+ value: 0
302
+ });
303
+ /** The grid of the winners (null until the rows are read) */
304
+ Object.defineProperty(this, "grid", {
305
+ enumerable: true,
306
+ configurable: true,
307
+ writable: true,
308
+ value: null
309
+ });
310
+ /** The next point to decide, from the front (the second phase) */
311
+ Object.defineProperty(this, "nextPoint", {
312
+ enumerable: true,
313
+ configurable: true,
314
+ writable: true,
315
+ value: -1
316
+ });
317
+ Object.defineProperty(this, "finished", {
318
+ enumerable: true,
319
+ configurable: true,
320
+ writable: true,
321
+ value: false
322
+ });
323
+ const count = rows.length;
324
+ this.winners = new Uint8Array(count);
325
+ this.xs = new Float64Array(count);
326
+ this.ys = new Float64Array(count);
327
+ this.rs = new Float64Array(count);
328
+ this.pointRows = new Int32Array(count);
329
+ this.perPixel = worldUnitsPerPixel(band);
330
+ }
331
+ /** Whether the selection is finished */
332
+ get done() {
333
+ return this.finished;
334
+ }
335
+ /**
336
+ * Advances until the deadline or the end
337
+ *
338
+ * At least one slice of rows is handled per call (otherwise it would never end).
339
+ *
340
+ * @returns Whether it is finished
341
+ */
342
+ step(deadline, now) {
343
+ while (!this.finished) {
344
+ if (this.grid === null)
345
+ this.readRows();
346
+ else
347
+ this.decidePoints();
348
+ if (this.finished || now() >= deadline)
349
+ break;
350
+ }
351
+ return this.finished;
352
+ }
353
+ /** 1 for each row that may be drawn, 0 otherwise (complete once `done`) */
354
+ result() {
355
+ return this.winners;
356
+ }
357
+ /** Reads one slice of rows into the arrays of points (the first phase) */
358
+ readRows() {
359
+ const rows = this.rows;
360
+ const winners = this.winners;
361
+ const xs = this.xs;
362
+ const ys = this.ys;
363
+ const rs = this.rs;
364
+ const pointRows = this.pointRows;
365
+ const count = rows.length;
366
+ const end = Math.min(count, this.nextRow + SELECTION_SLICE_ROWS);
367
+ for (let row = this.nextRow; row < end; row++) {
368
+ const role = rows.thinningRole(row);
369
+ if (role === 'skip')
370
+ continue;
371
+ if (role === 'winner') {
372
+ // A line, a polygon, a MultiPoint and so on are not thinned (they win unconditionally)
373
+ winners[row] = 1;
374
+ continue;
375
+ }
376
+ const coord = rows.pointOf(row);
377
+ const radius = this.radiusPx(row) * this.perPixel;
378
+ const k = this.pointCount++;
379
+ xs[k] = lngToWorldX(coord[0]);
380
+ ys[k] = latToWorldY(coord[1]);
381
+ rs[k] = radius;
382
+ pointRows[k] = row;
383
+ if (radius > this.maxRadius)
384
+ this.maxRadius = radius;
385
+ }
386
+ this.nextRow = end;
387
+ if (end < count)
388
+ return;
389
+ if (this.pointCount === 0) {
390
+ this.finished = true;
391
+ return;
392
+ }
393
+ // With no footprint (radius 0) nobody collides
394
+ if (this.maxRadius <= 0) {
395
+ for (let k = 0; k < this.pointCount; k++)
396
+ winners[pointRows[k]] = 1;
397
+ this.finished = true;
398
+ return;
399
+ }
400
+ this.grid = createHashGrid(xs, ys, this.pointCount, this.maxRadius);
401
+ this.nextPoint = this.pointCount - 1;
402
+ }
403
+ /** Decides one slice of points, from the front (the second phase) */
404
+ decidePoints() {
405
+ const xs = this.xs;
406
+ const ys = this.ys;
407
+ const rs = this.rs;
408
+ const pointRows = this.pointRows;
409
+ const winners = this.winners;
410
+ const { cell, minX, minY, stride, buckets, keyDeltas } = this.grid;
411
+ const end = Math.max(-1, this.nextPoint - SELECTION_SLICE_ROWS);
412
+ // Taken greedily in the reverse of the draw order (from the frontmost)
413
+ for (let k = this.nextPoint; k > end; k--) {
414
+ const x = xs[k];
415
+ const y = ys[k];
416
+ const r = rs[k];
417
+ const key = (Math.floor((y - minY) / cell) + 1) * stride + (Math.floor((x - minX) / cell) + 1);
418
+ let blocked = false;
419
+ // From its own cell outwards, decided by the real distance to the winners (not by occupancy)
420
+ for (let d = 0; d < keyDeltas.length; d++) {
421
+ const bucket = buckets.get(key + keyDeltas[d]);
422
+ if (bucket === undefined)
423
+ continue;
424
+ for (let i = 0; i < bucket.length; i++) {
425
+ const j = bucket[i];
426
+ const ddx = xs[j] - x;
427
+ const ddy = ys[j] - y;
428
+ const sum = rs[j] + r;
429
+ if (ddx * ddx + ddy * ddy < sum * sum) {
430
+ blocked = true;
431
+ break;
432
+ }
433
+ }
434
+ if (blocked)
435
+ break;
436
+ }
437
+ if (blocked)
438
+ continue;
439
+ const bucket = buckets.get(key);
440
+ if (bucket)
441
+ bucket.push(k);
442
+ else
443
+ buckets.set(key, [k]);
444
+ winners[pointRows[k]] = 1;
445
+ }
446
+ this.nextPoint = end;
447
+ if (end < 0)
448
+ this.finished = true;
449
+ }
450
+ }
451
+ /**
452
+ * Picks the winners among the rows (a `CollisionSelection` run in one go)
453
+ *
454
+ * The result also marks what is out of scope for the thinning (anything but a Point, and so on).
455
+ * A row that is not drawn (`skip`) becomes neither a winner nor an obstacle.
456
+ *
457
+ * @param radiusPx The footprint radius of a row (px, including the outline and the margin)
458
+ * @returns 1 for each row that may be drawn, 0 otherwise
459
+ *
460
+ * @internal
461
+ */
462
+ export function selectCollisionWinnerRows(rows, band, radiusPx) {
463
+ const selection = new CollisionSelection(rows, band, radiusPx);
464
+ selection.step(Number.POSITIVE_INFINITY, () => 0);
465
+ return selection.result();
466
+ }
467
+ /**
468
+ * Picks the set of winners among features (`selectCollisionWinnerRows` over an array)
469
+ *
470
+ * @returns The set of ids of the features that may be drawn
471
+ *
472
+ * @internal
473
+ */
474
+ export function selectCollisionWinners(input) {
475
+ const { features, band, radiusPx } = input;
476
+ const rows = {
477
+ length: features.length,
478
+ thinningRole: (row) => featureThinningRole(features[row]),
479
+ pointOf: (row) => features[row].coordinates,
480
+ styleRadiusOf: (row) => features[row].style?.pointRadius,
481
+ idOf: (row) => features[row].id,
482
+ };
483
+ const mask = selectCollisionWinnerRows(rows, band, (row) => radiusPx(features[row]));
484
+ const winners = new Set();
485
+ for (let row = 0; row < mask.length; row++) {
486
+ if (mask[row] === 1)
487
+ winners.add(features[row].id);
488
+ }
489
+ return winners;
490
+ }
491
+ /**
492
+ * What a feature is to the collision thinning
493
+ *
494
+ * @internal
495
+ */
496
+ export function featureThinningRole(feature) {
497
+ if (!feature.visible)
498
+ return 'skip';
499
+ if (feature.type !== 'Point')
500
+ return 'winner';
501
+ const coord = feature.coordinates;
502
+ if (!Array.isArray(coord) || typeof coord[0] !== 'number' || typeof coord[1] !== 'number') {
503
+ return 'winner';
504
+ }
505
+ return 'point';
506
+ }
507
+ /**
508
+ * Prepares the grid
509
+ *
510
+ * The cell side is "the diameter of the largest footprint of that band". Two colliding points
511
+ * always fall within a displacement of one cell, so looking only at its own cell and the 8 cells
512
+ * around it misses nothing.
513
+ *
514
+ * The key is an integer built from the row and the column, but when the range is so wide that it
515
+ * would leave the safe integers, the cells are made coarser (this only adds candidates; the
516
+ * decision uses the real distance, so the result does not change).
517
+ */
518
+ function createHashGrid(xs, ys, count, maxRadius) {
519
+ let minX = Number.POSITIVE_INFINITY;
520
+ let minY = Number.POSITIVE_INFINITY;
521
+ let maxX = Number.NEGATIVE_INFINITY;
522
+ let maxY = Number.NEGATIVE_INFINITY;
523
+ for (let i = 0; i < count; i++) {
524
+ if (xs[i] < minX)
525
+ minX = xs[i];
526
+ if (xs[i] > maxX)
527
+ maxX = xs[i];
528
+ if (ys[i] < minY)
529
+ minY = ys[i];
530
+ if (ys[i] > maxY)
531
+ maxY = ys[i];
532
+ }
533
+ let cell = maxRadius * 2;
534
+ let cols = Math.floor((maxX - minX) / cell) + 1;
535
+ let rows = Math.floor((maxY - minY) / cell) + 1;
536
+ // Make them coarser until they fit in the safe integers even with the room to subtract one
537
+ // surrounding cell (+2)
538
+ while ((cols + 2) * (rows + 2) > Number.MAX_SAFE_INTEGER) {
539
+ cell *= 2;
540
+ cols = Math.floor((maxX - minX) / cell) + 1;
541
+ rows = Math.floor((maxY - minY) / cell) + 1;
542
+ }
543
+ const stride = cols + 2;
544
+ return {
545
+ cell,
546
+ minX,
547
+ minY,
548
+ stride,
549
+ buckets: new Map(),
550
+ // Its own cell is looked at first, so that the denser it is, the sooner it is rejected
551
+ keyDeltas: [0, -1, 1, -stride, stride, -stride - 1, -stride + 1, stride - 1, stride + 1],
552
+ };
553
+ }
554
+ /**
555
+ * The collision thinning state of one dataset
556
+ *
557
+ * It holds the settings and the rows that are drawn (`mask`). There is one way to bring the
558
+ * drawn rows up to date, `sync(zoom)`: it picks the winners of the band of `zoom` for the current
559
+ * contents, style and settings, and does nothing when they are already those. The winners of
560
+ * each band are kept for the current contents and style, so going back to a band costs nothing,
561
+ * and the bands next to the current one can be picked ahead in slices while the page is idle
562
+ * (`prefetch`). Every change of the drawn rows advances `revision`.
563
+ *
564
+ * @internal
565
+ */
566
+ export class CollisionThinningState {
567
+ constructor(host, options) {
568
+ Object.defineProperty(this, "host", {
569
+ enumerable: true,
570
+ configurable: true,
571
+ writable: true,
572
+ value: host
573
+ });
574
+ /** Settings of the collision thinning (null = not set = disabled) */
575
+ Object.defineProperty(this, "settings", {
576
+ enumerable: true,
577
+ configurable: true,
578
+ writable: true,
579
+ value: void 0
580
+ });
581
+ /** What the drawn rows were picked for (null = nothing picked: every row is drawn) */
582
+ Object.defineProperty(this, "picked", {
583
+ enumerable: true,
584
+ configurable: true,
585
+ writable: true,
586
+ value: null
587
+ });
588
+ /** The drawn rows */
589
+ Object.defineProperty(this, "drawnRows", {
590
+ enumerable: true,
591
+ configurable: true,
592
+ writable: true,
593
+ value: null
594
+ });
595
+ /** The number of rows that are drawn */
596
+ Object.defineProperty(this, "drawnCount", {
597
+ enumerable: true,
598
+ configurable: true,
599
+ writable: true,
600
+ value: 0
601
+ });
602
+ /** The ids of the drawn rows, built on the first request */
603
+ Object.defineProperty(this, "drawnIds", {
604
+ enumerable: true,
605
+ configurable: true,
606
+ writable: true,
607
+ value: null
608
+ });
609
+ /** Advances whenever the drawn rows change */
610
+ Object.defineProperty(this, "drawnRevision", {
611
+ enumerable: true,
612
+ configurable: true,
613
+ writable: true,
614
+ value: 0
615
+ });
616
+ /**
617
+ * The winners already picked for each band, for the key in `cacheKey` (null = every row).
618
+ * Going back to a band seen before costs nothing
619
+ */
620
+ Object.defineProperty(this, "bandCache", {
621
+ enumerable: true,
622
+ configurable: true,
623
+ writable: true,
624
+ value: new Map()
625
+ });
626
+ /** The contents and the style the bands in `bandCache` were picked for */
627
+ Object.defineProperty(this, "cacheKey", {
628
+ enumerable: true,
629
+ configurable: true,
630
+ writable: true,
631
+ value: null
632
+ });
633
+ /** The band being picked ahead, a slice at a time (null = none) */
634
+ Object.defineProperty(this, "ahead", {
635
+ enumerable: true,
636
+ configurable: true,
637
+ writable: true,
638
+ value: null
639
+ });
640
+ this.settings = options ? resolveCollisionThinning(options) : null;
641
+ }
642
+ /** The settings (null when not set) */
643
+ get options() {
644
+ return this.settings;
645
+ }
646
+ /** Whether the thinning is enabled */
647
+ get enabled() {
648
+ return this.settings?.enabled ?? false;
649
+ }
650
+ /** Whether some rows are thinned away (false: every row is drawn) */
651
+ get active() {
652
+ return this.drawnRows !== null;
653
+ }
654
+ /** The drawn rows (null = every row) */
655
+ get mask() {
656
+ return this.drawnRows;
657
+ }
658
+ /** A number that advances whenever the drawn rows change */
659
+ get revision() {
660
+ return this.drawnRevision;
661
+ }
662
+ /** The ids of the rows that are drawn (null = every row) */
663
+ get drawable() {
664
+ const mask = this.drawnRows;
665
+ if (!mask)
666
+ return null;
667
+ if (!this.drawnIds) {
668
+ const rows = this.host.rows();
669
+ const ids = new Set();
670
+ for (let row = 0; row < mask.length; row++) {
671
+ if (mask[row] === 1)
672
+ ids.add(rows.idOf(row));
673
+ }
674
+ this.drawnIds = ids;
675
+ }
676
+ return this.drawnIds;
677
+ }
678
+ /**
679
+ * Replaces the settings and brings the drawn rows up to date for `zoom`
680
+ *
681
+ * @param zoom The zoom the band is decided from (with the pitch correction applied)
682
+ * @returns null when the settings are the same; otherwise whether the drawn rows changed
683
+ */
684
+ setOptions(options, zoom) {
685
+ const next = options ? resolveCollisionThinning(options) : null;
686
+ if (sameCollisionThinning(this.settings, next))
687
+ return null;
688
+ this.settings = next;
689
+ this.picked = null;
690
+ this.forgetBands();
691
+ return { drawnChanged: this.sync(zoom) };
692
+ }
693
+ /** Whether a row is drawn (it survived the thinning, or nothing is thinned) */
694
+ isDrawnRow(row) {
695
+ return this.drawnRows === null || this.drawnRows[row] === 1;
696
+ }
697
+ /** The statistics of the thinning for `total` features */
698
+ stats(total) {
699
+ const thinning = this.drawnRows !== null;
700
+ return {
701
+ enabled: this.enabled,
702
+ active: thinning,
703
+ total,
704
+ visible: thinning ? this.drawnCount : total,
705
+ band: thinning ? (this.picked?.band ?? null) : null,
706
+ };
707
+ }
708
+ /**
709
+ * Brings the drawn rows up to date: the winners of the band of `zoom` for the current contents,
710
+ * style and settings (every row while the thinning is disabled)
711
+ *
712
+ * It is the only way the drawn rows change. Nothing is picked when they are already those; a
713
+ * band kept from before (or picked ahead) is reused, and a band being picked ahead is
714
+ * finished rather than started again.
715
+ *
716
+ * @param zoom The zoom the band is decided from (with the pitch correction applied)
717
+ * @returns Whether the drawn rows changed
718
+ */
719
+ sync(zoom) {
720
+ const settings = this.settings;
721
+ if (!settings?.enabled) {
722
+ this.picked = null;
723
+ return this.setDrawn(null);
724
+ }
725
+ const key = this.currentKey();
726
+ const band = zoomBandFor(zoom);
727
+ const picked = this.picked;
728
+ if (picked && sameKey(picked, key) && picked.band === band)
729
+ return false;
730
+ if (!this.cacheKey || !sameKey(this.cacheKey, key)) {
731
+ this.forgetBands();
732
+ this.cacheKey = key;
733
+ }
734
+ let mask = this.bandCache.get(band);
735
+ if (mask === undefined)
736
+ mask = this.finishAhead(band, key) ?? this.pickWinners(band, settings);
737
+ this.keepBand(band, mask);
738
+ this.picked = { ...key, band };
739
+ return this.setDrawn(mask);
740
+ }
741
+ /**
742
+ * Picks the winners of the bands next to the current one ahead of time, until the deadline
743
+ *
744
+ * Called while the page is idle, so that crossing into one of those bands during a gesture
745
+ * costs no selection in the middle of a frame. The selection of a band is advanced in slices
746
+ * (`CollisionSelection`), so an idle period is never overrun by more than one slice.
747
+ *
748
+ * @returns Whether a band next to the current one is still missing
749
+ */
750
+ prefetch(deadline, now) {
751
+ const settings = this.settings;
752
+ const picked = this.picked;
753
+ const key = this.currentKey();
754
+ if (!settings?.enabled || !picked || !sameKey(picked, key)) {
755
+ this.ahead = null;
756
+ return false;
757
+ }
758
+ for (;;) {
759
+ let ahead = this.ahead;
760
+ if (ahead && !sameKey(ahead, key))
761
+ ahead = null;
762
+ if (!ahead) {
763
+ const band = this.missingNeighbors(picked.band)[0];
764
+ if (band === undefined)
765
+ return false;
766
+ if (band >= settings.fullDisplayZoom) {
767
+ // Nothing is thinned there; there is nothing to pick
768
+ this.keepBand(band, null);
769
+ continue;
770
+ }
771
+ ahead = { ...key, band, selection: this.selectionFor(band, settings) };
772
+ this.ahead = ahead;
773
+ }
774
+ if (!ahead.selection.step(deadline, now))
775
+ return true;
776
+ this.keepBand(ahead.band, ahead.selection.result());
777
+ this.ahead = null;
778
+ if (now() >= deadline)
779
+ return this.missingNeighbors(picked.band).length > 0;
780
+ }
781
+ }
782
+ /** Forgets the winners (the settings are kept) */
783
+ clear() {
784
+ this.picked = null;
785
+ this.setDrawn(null);
786
+ this.forgetBands();
787
+ }
788
+ /**
789
+ * The bands near `band` (two on each side) whose winners are not kept yet, the nearest and the
790
+ * lower first. A fast zoom gesture crosses two bands before the page is idle again
791
+ */
792
+ missingNeighbors(band) {
793
+ const missing = [];
794
+ for (const next of [band - 1, band + 1, band - 2, band + 2]) {
795
+ if (next < 0 || next > MAX_ZOOM_BAND)
796
+ continue;
797
+ const kept = this.bandCache.get(next);
798
+ // A band still kept is marked as used, so that picking the missing ones does not drop it
799
+ if (kept === undefined)
800
+ missing.push(next);
801
+ else
802
+ this.keepBand(next, kept);
803
+ }
804
+ return missing;
805
+ }
806
+ /** The contents and the style of now */
807
+ currentKey() {
808
+ return { generation: this.host.featuresGeneration(), revision: this.host.styleRevision() };
809
+ }
810
+ /** Discards the winners kept per band and the band being picked ahead */
811
+ forgetBands() {
812
+ this.bandCache.clear();
813
+ this.cacheKey = null;
814
+ this.ahead = null;
815
+ }
816
+ /**
817
+ * Replaces the drawn rows (null = every row)
818
+ *
819
+ * A mask with the same rows as the current one keeps the current one, so nothing that depends
820
+ * on the drawn rows is redone.
821
+ *
822
+ * @returns Whether the drawn rows changed
823
+ */
824
+ setDrawn(mask) {
825
+ if (sameMask(this.drawnRows, mask))
826
+ return false;
827
+ this.drawnRows = mask;
828
+ this.drawnIds = null;
829
+ let count = 0;
830
+ if (mask)
831
+ for (let row = 0; row < mask.length; row++)
832
+ count += mask[row];
833
+ this.drawnCount = count;
834
+ this.drawnRevision++;
835
+ return true;
836
+ }
837
+ /**
838
+ * Keeps the winners of a band as the most recently used one (the least recently used band is
839
+ * dropped first; a Map keeps the order of insertion)
840
+ */
841
+ keepBand(band, mask) {
842
+ this.bandCache.delete(band);
843
+ if (this.bandCache.size >= MAX_CACHED_BANDS) {
844
+ const oldest = this.bandCache.keys().next().value;
845
+ if (oldest !== undefined)
846
+ this.bandCache.delete(oldest);
847
+ }
848
+ this.bandCache.set(band, mask);
849
+ }
850
+ /** Finishes the band being picked ahead when it is `band` (undefined otherwise) */
851
+ finishAhead(band, key) {
852
+ const ahead = this.ahead;
853
+ if (!ahead || ahead.band !== band || !sameKey(ahead, key))
854
+ return undefined;
855
+ this.ahead = null;
856
+ ahead.selection.step(Number.POSITIVE_INFINITY, () => 0);
857
+ return ahead.selection.result();
858
+ }
859
+ /** The winners of the band `band` (null = every row) */
860
+ pickWinners(band, settings) {
861
+ if (band >= settings.fullDisplayZoom)
862
+ return null;
863
+ const selection = this.selectionFor(band, settings);
864
+ selection.step(Number.POSITIVE_INFINITY, () => 0);
865
+ return selection.result();
866
+ }
867
+ /** A selection of the winners of the band `band`, not started yet */
868
+ selectionFor(band, settings) {
869
+ const rows = this.host.rows();
870
+ const footprint = this.host.footprintPx(band, settings.marginPx);
871
+ return new CollisionSelection(rows, band, (row) => footprint(rows.styleRadiusOf(row)));
872
+ }
873
+ }
874
+ /** Whether two keys name the same contents and style */
875
+ function sameKey(a, b) {
876
+ return a.generation === b.generation && a.revision === b.revision;
877
+ }
878
+ /**
879
+ * Whether two masks of drawn rows are the same (null = every row)
880
+ *
881
+ * @internal
882
+ */
883
+ export function sameMask(a, b) {
884
+ if (a === b)
885
+ return true;
886
+ if (a === null || b === null)
887
+ return false;
888
+ if (a.length !== b.length)
889
+ return false;
890
+ for (let i = 0; i < a.length; i++) {
891
+ if (a[i] !== b[i])
892
+ return false;
893
+ }
894
+ return true;
895
+ }
896
+ /**
897
+ * Whether the rows `rows` are drawn alike in two masks (null = every row)
898
+ *
899
+ * @internal
900
+ */
901
+ export function sameRowsInMasks(a, b, rows) {
902
+ if (a === b)
903
+ return true;
904
+ for (let i = 0; i < rows.length; i++) {
905
+ const row = rows[i];
906
+ if ((a === null ? 1 : a[row]) !== (b === null ? 1 : b[row]))
907
+ return false;
908
+ }
909
+ return true;
910
+ }