@sakuzu/maplibre-gl-draw 1.0.0 → 2.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 (540) hide show
  1. package/CHANGELOG.md +1016 -2
  2. package/README.ja.md +39 -19
  3. package/README.md +41 -21
  4. package/dist/api/datasets.d.ts +258 -0
  5. package/dist/api/document.d.ts +66 -0
  6. package/dist/api/draw.d.ts +135 -0
  7. package/dist/api/draw.js +18 -0
  8. package/dist/api/drawing.d.ts +87 -0
  9. package/dist/api/errors.d.ts +35 -0
  10. package/dist/api/errors.js +35 -0
  11. package/dist/api/events.d.ts +306 -0
  12. package/dist/api/extension/context.d.ts +247 -0
  13. package/dist/api/extension/feature-type.d.ts +129 -0
  14. package/dist/api/extension/mode.d.ts +123 -0
  15. package/dist/api/extension/plugin.d.ts +51 -0
  16. package/dist/api/extension/plugin.js +3 -0
  17. package/dist/api/extension/provider.d.ts +119 -0
  18. package/dist/api/extension/provider.js +3 -0
  19. package/dist/api/extension/render.d.ts +176 -0
  20. package/dist/api/extension/render.js +3 -0
  21. package/dist/api/extension/store.d.ts +190 -0
  22. package/dist/api/extension/store.js +3 -0
  23. package/dist/api/extensions.d.ts +306 -0
  24. package/dist/api/extensions.js +3 -0
  25. package/dist/api/features.d.ts +188 -0
  26. package/dist/api/features.js +3 -0
  27. package/dist/api/groups.d.ts +111 -0
  28. package/dist/api/groups.js +3 -0
  29. package/dist/api/hidden.d.ts +45 -0
  30. package/dist/api/hidden.js +3 -0
  31. package/dist/api/impl/adapters.js +463 -0
  32. package/dist/api/impl/contexts.js +466 -0
  33. package/dist/api/impl/create-draw.js +124 -0
  34. package/dist/api/impl/datasets.js +404 -0
  35. package/dist/api/impl/destroy-guard.js +74 -0
  36. package/dist/api/impl/document.js +280 -0
  37. package/dist/api/impl/drawing.js +180 -0
  38. package/dist/api/impl/engine-context.d.ts +7 -0
  39. package/dist/api/{context.js → impl/engine-context.js} +49 -38
  40. package/dist/{maplibre-gl-draw.js → api/impl/engine.js} +145 -177
  41. package/dist/api/impl/events.js +422 -0
  42. package/dist/api/impl/extension-host.js +361 -0
  43. package/dist/api/impl/extensions.js +229 -0
  44. package/dist/api/impl/features.js +445 -0
  45. package/dist/api/impl/geometry/apply.d.ts +32 -0
  46. package/dist/api/{geometry → impl/geometry}/apply.js +10 -27
  47. package/dist/api/{geometry → impl/geometry}/buffer.d.ts +4 -3
  48. package/dist/api/{geometry → impl/geometry}/buffer.js +12 -23
  49. package/dist/api/{geometry → impl/geometry}/split.d.ts +4 -3
  50. package/dist/api/{geometry → impl/geometry}/split.js +10 -21
  51. package/dist/api/{geometry → impl/geometry}/targets.d.ts +2 -20
  52. package/dist/api/{geometry → impl/geometry}/targets.js +8 -35
  53. package/dist/api/impl/geometry/types.js +3 -0
  54. package/dist/api/impl/groups.d.ts +3 -0
  55. package/dist/api/impl/groups.js +268 -0
  56. package/dist/api/impl/hidden.js +60 -0
  57. package/dist/api/impl/import-export/constants.d.ts +22 -0
  58. package/dist/api/impl/import-export/constants.js +24 -0
  59. package/dist/api/{import-export → impl/import-export}/embedded-file.js +2 -2
  60. package/dist/api/{import-export → impl/import-export}/format-detection.d.ts +1 -1
  61. package/dist/api/{import-export → impl/import-export}/format-detection.js +2 -1
  62. package/dist/api/impl/import-export/geojson-export.d.ts +19 -0
  63. package/dist/api/{import-export → impl/import-export}/geojson-export.js +71 -104
  64. package/dist/api/{import-export → impl/import-export}/geojson-import.d.ts +11 -7
  65. package/dist/api/{import-export → impl/import-export}/geojson-import.js +139 -97
  66. package/dist/api/{import-export → impl/import-export}/geometry-validation.d.ts +14 -0
  67. package/dist/api/{import-export → impl/import-export}/geometry-validation.js +45 -0
  68. package/dist/api/impl/import-export/image-import.d.ts +16 -0
  69. package/dist/api/impl/import-export/image-import.js +73 -0
  70. package/dist/api/impl/import-export/legacy-image-style.d.ts +16 -0
  71. package/dist/api/impl/import-export/legacy-image-style.js +49 -0
  72. package/dist/api/impl/import-export/native-format.d.ts +14 -0
  73. package/dist/api/{import-export → impl/import-export}/native-format.js +32 -22
  74. package/dist/api/impl/import-export/native-upgrade.d.ts +8 -0
  75. package/dist/api/impl/import-export/native-upgrade.js +139 -0
  76. package/dist/api/{import-export → impl/import-export}/native-validation.d.ts +1 -1
  77. package/dist/api/{import-export → impl/import-export}/native-validation.js +15 -14
  78. package/dist/api/impl/import-export/style-validation.d.ts +24 -0
  79. package/dist/api/impl/import-export/style-validation.js +86 -0
  80. package/dist/api/impl/import-export/types.d.ts +52 -0
  81. package/dist/api/impl/import-export/types.js +3 -0
  82. package/dist/api/impl/input.js +180 -0
  83. package/dist/api/impl/layers.js +307 -0
  84. package/dist/api/impl/metadata.d.ts +1 -0
  85. package/dist/api/impl/metadata.js +22 -0
  86. package/dist/api/impl/options.d.ts +1 -0
  87. package/dist/api/impl/options.js +822 -0
  88. package/dist/api/impl/placement.d.ts +1 -0
  89. package/dist/api/impl/placement.js +138 -0
  90. package/dist/api/impl/render-context.d.ts +13 -0
  91. package/dist/api/impl/render-context.js +272 -0
  92. package/dist/api/impl/rows.d.ts +1 -0
  93. package/dist/api/impl/rows.js +46 -0
  94. package/dist/api/impl/selection.d.ts +1 -0
  95. package/dist/api/impl/selection.js +186 -0
  96. package/dist/api/impl/shared.d.ts +64 -0
  97. package/dist/api/impl/shared.js +178 -0
  98. package/dist/api/impl/validate-extension.d.ts +1 -0
  99. package/dist/api/impl/validate-extension.js +159 -0
  100. package/dist/api/layers.d.ts +130 -0
  101. package/dist/api/layers.js +3 -0
  102. package/dist/api/metadata.d.ts +18 -0
  103. package/dist/api/metadata.js +3 -0
  104. package/dist/api/model.d.ts +487 -0
  105. package/dist/api/model.js +47 -0
  106. package/dist/api/options.d.ts +466 -0
  107. package/dist/api/options.js +3 -0
  108. package/dist/api/selection.d.ts +94 -0
  109. package/dist/api/selection.js +3 -0
  110. package/dist/api/state.d.ts +155 -0
  111. package/dist/api/state.js +12 -0
  112. package/dist/{display → dataset}/chunk.d.ts +1 -1
  113. package/dist/{display → dataset}/chunk.js +4 -3
  114. package/dist/{display → dataset}/dataset.js +18 -21
  115. package/dist/dataset/interaction.d.ts +1 -0
  116. package/dist/{display → dataset}/interaction.js +18 -6
  117. package/dist/dataset/manager.d.ts +1 -0
  118. package/dist/dataset/provider.d.ts +1 -0
  119. package/dist/{display → dataset}/retained.d.ts +1 -1
  120. package/dist/{display → dataset}/retained.js +8 -7
  121. package/dist/dataset/source.d.ts +1 -0
  122. package/dist/{display → dataset}/source.js +17 -4
  123. package/dist/dataset/spatial.d.ts +1 -0
  124. package/dist/{display → dataset}/spatial.js +1 -1
  125. package/dist/dataset/style.d.ts +1 -0
  126. package/dist/{display → dataset}/style.js +1 -1
  127. package/dist/dataset/table-source.d.ts +1 -0
  128. package/dist/{display/columnar/source.js → dataset/table-source.js} +53 -25
  129. package/dist/{display → dataset}/thinning.d.ts +0 -10
  130. package/dist/{display → dataset}/thinning.js +3 -2
  131. package/dist/dataset/triangulation.d.ts +1 -0
  132. package/dist/{display → dataset}/triangulation.js +0 -0
  133. package/dist/{display → dataset}/types.d.ts +82 -121
  134. package/dist/dataset/types.js +61 -0
  135. package/dist/dispatcher/hit-test/box-strategies.js +13 -13
  136. package/dist/dispatcher/hit-test/box-strategy.d.ts +2 -15
  137. package/dist/dispatcher/hit-test/globe-shape.js +5 -4
  138. package/dist/dispatcher/hit-test/service.d.ts +17 -0
  139. package/dist/dispatcher/hit-test/service.js +80 -16
  140. package/dist/dispatcher/hit-test/strategies/base.d.ts +13 -19
  141. package/dist/dispatcher/hit-test/strategies/circle.js +3 -2
  142. package/dist/dispatcher/hit-test/strategies/image.js +6 -18
  143. package/dist/dispatcher/hit-test/strategies/line.d.ts +0 -6
  144. package/dist/dispatcher/hit-test/strategies/line.js +9 -2
  145. package/dist/dispatcher/hit-test/strategies/multi.d.ts +0 -8
  146. package/dist/dispatcher/hit-test/strategies/multi.js +17 -8
  147. package/dist/dispatcher/hit-test/strategies/point.d.ts +9 -7
  148. package/dist/dispatcher/hit-test/strategies/point.js +8 -4
  149. package/dist/dispatcher/hit-test/strategies/polygon.d.ts +0 -7
  150. package/dist/dispatcher/hit-test/strategies/polygon.js +11 -3
  151. package/dist/dispatcher/hit-test/topmost.d.ts +1 -1
  152. package/dist/dispatcher/input-router.js +152 -69
  153. package/dist/dispatcher/normalizer.js +6 -2
  154. package/dist/dispatcher/types.d.ts +6 -1
  155. package/dist/extension/feature-handler.d.ts +1 -182
  156. package/dist/extension/index.d.ts +4 -7
  157. package/dist/extension/renderers.d.ts +1 -208
  158. package/dist/geometry/angle.d.ts +0 -8
  159. package/dist/geometry/angle.js +0 -8
  160. package/dist/geometry/bbox.d.ts +4 -12
  161. package/dist/geometry/bbox.js +4 -12
  162. package/dist/geometry/boolean.d.ts +0 -51
  163. package/dist/geometry/boolean.js +0 -51
  164. package/dist/geometry/buffer.d.ts +0 -26
  165. package/dist/geometry/buffer.js +0 -26
  166. package/dist/geometry/circle.d.ts +0 -9
  167. package/dist/geometry/circle.js +0 -9
  168. package/dist/geometry/coords.d.ts +0 -16
  169. package/dist/geometry/coords.js +0 -16
  170. package/dist/geometry/distance.d.ts +0 -24
  171. package/dist/geometry/distance.js +0 -24
  172. package/dist/geometry/errors.d.ts +21 -36
  173. package/dist/geometry/errors.js +49 -29
  174. package/dist/geometry/geojson.d.ts +81 -0
  175. package/dist/geometry/geojson.js +164 -0
  176. package/dist/geometry/index.d.ts +38 -23
  177. package/dist/geometry/index.js +43 -31
  178. package/dist/geometry/measure.d.ts +0 -27
  179. package/dist/geometry/measure.js +0 -27
  180. package/dist/geometry/predicates.d.ts +0 -9
  181. package/dist/geometry/predicates.js +0 -9
  182. package/dist/geometry/public-bounds.d.ts +26 -0
  183. package/dist/geometry/public-bounds.js +30 -0
  184. package/dist/geometry/public-combine.d.ts +78 -0
  185. package/dist/geometry/public-combine.js +82 -0
  186. package/dist/geometry/public-create.d.ts +54 -0
  187. package/dist/geometry/public-create.js +70 -0
  188. package/dist/geometry/public-measure.d.ts +170 -0
  189. package/dist/geometry/public-measure.js +283 -0
  190. package/dist/geometry/public-predicates.d.ts +54 -0
  191. package/dist/geometry/public-predicates.js +144 -0
  192. package/dist/geometry/public-repair.d.ts +75 -0
  193. package/dist/geometry/public-repair.js +77 -0
  194. package/dist/geometry/simplify.d.ts +0 -7
  195. package/dist/geometry/simplify.js +0 -7
  196. package/dist/geometry/split.d.ts +0 -20
  197. package/dist/geometry/split.js +0 -20
  198. package/dist/geometry/units.d.ts +20 -12
  199. package/dist/geometry/units.js +20 -12
  200. package/dist/index.d.ts +52 -66
  201. package/dist/index.js +6 -18
  202. package/dist/messages.d.ts +7 -7
  203. package/dist/modes/draw/circle.js +83 -207
  204. package/dist/modes/draw/commit-layer.d.ts +5 -16
  205. package/dist/modes/draw/commit-layer.js +2 -13
  206. package/dist/modes/draw/freehand.js +108 -246
  207. package/dist/modes/draw/image.js +4 -2
  208. package/dist/modes/draw/index.d.ts +5 -5
  209. package/dist/modes/draw/index.js +5 -5
  210. package/dist/modes/draw/line.js +18 -354
  211. package/dist/modes/draw/point.js +29 -78
  212. package/dist/modes/draw/polygon.js +23 -368
  213. package/dist/modes/draw/trace-support.d.ts +43 -36
  214. package/dist/modes/draw/trace-support.js +95 -98
  215. package/dist/modes/draw/vertex-drawing.d.ts +1 -0
  216. package/dist/modes/draw/vertex-drawing.js +176 -0
  217. package/dist/modes/handler.d.ts +1 -285
  218. package/dist/modes/manager.d.ts +2 -2
  219. package/dist/modes/manager.js +3 -0
  220. package/dist/modes/select/box-selection.d.ts +3 -3
  221. package/dist/modes/select/box-selection.js +2 -1
  222. package/dist/modes/select/click-handler.d.ts +5 -5
  223. package/dist/modes/select/click-handler.js +22 -20
  224. package/dist/modes/select/cursor-handler.d.ts +2 -2
  225. package/dist/modes/select/drag/intermediate-writes.js +1 -1
  226. package/dist/modes/select/drag/move.js +3 -3
  227. package/dist/modes/select/drag/operation.d.ts +3 -3
  228. package/dist/modes/select/drag/radius.js +5 -4
  229. package/dist/modes/select/drag/transform.d.ts +2 -2
  230. package/dist/modes/select/drag/transform.js +11 -5
  231. package/dist/modes/select/drag/vertex.d.ts +2 -2
  232. package/dist/modes/select/drag/vertex.js +13 -8
  233. package/dist/modes/select/drag-handler.js +44 -25
  234. package/dist/modes/select/mode.js +17 -17
  235. package/dist/modes/select/shortcut-handler.d.ts +8 -8
  236. package/dist/modes/select/shortcut-handler.js +9 -7
  237. package/dist/operations/layer-operations.js +29 -168
  238. package/dist/operations/resize.d.ts +2 -2
  239. package/dist/operations/resize.js +5 -5
  240. package/dist/operations/rotate.js +5 -5
  241. package/dist/operations/selection-operations.d.ts +16 -1
  242. package/dist/operations/selection-operations.js +28 -13
  243. package/dist/operations/shared-vertex.js +4 -2
  244. package/dist/operations/trace-graph.d.ts +0 -18
  245. package/dist/operations/trace-graph.js +0 -18
  246. package/dist/operations/vertex.js +36 -35
  247. package/dist/shared/color.d.ts +1 -0
  248. package/dist/shared/color.js +245 -0
  249. package/dist/shared/config/constants.d.ts +1 -54
  250. package/dist/shared/config/constants.js +1 -58
  251. package/dist/shared/config/feature-style.d.ts +16 -13
  252. package/dist/shared/config/feature-style.js +9 -0
  253. package/dist/shared/config/rendering.d.ts +3 -3
  254. package/dist/shared/config/selection-highlight.d.ts +0 -15
  255. package/dist/shared/config/selection-highlight.js +4 -7
  256. package/dist/shared/config/selection.d.ts +2 -32
  257. package/dist/shared/config/selection.js +0 -18
  258. package/dist/shared/config/topology.d.ts +2 -2
  259. package/dist/shared/config/trace.d.ts +4 -4
  260. package/dist/shared/math/angle.d.ts +1 -1
  261. package/dist/shared/math/angle.js +1 -1
  262. package/dist/shared/math/circle.d.ts +1 -1
  263. package/dist/shared/math/circle.js +1 -1
  264. package/dist/shared/math/distance.d.ts +2 -1
  265. package/dist/shared/math/distance.js +3 -2
  266. package/dist/shared/math/index.d.ts +1 -1
  267. package/dist/shared/math/index.js +1 -1
  268. package/dist/shared/math/transform.d.ts +23 -0
  269. package/dist/shared/math/transform.js +47 -28
  270. package/dist/shared/properties.d.ts +18 -0
  271. package/dist/shared/properties.js +129 -0
  272. package/dist/shared/types/events.d.ts +15 -7
  273. package/dist/shared/types/model.d.ts +109 -159
  274. package/dist/shared/types/style.d.ts +1 -1
  275. package/dist/shared/utils/color.d.ts +2 -36
  276. package/dist/shared/utils/color.js +13 -70
  277. package/dist/shared/utils/coordinates.d.ts +30 -4
  278. package/dist/shared/utils/coordinates.js +56 -10
  279. package/dist/shared/utils/event-emitter.d.ts +1 -262
  280. package/dist/shared/utils/event-emitter.js +4 -3
  281. package/dist/shared/utils/feature-bbox.js +8 -7
  282. package/dist/shared/utils/feature-segments.js +5 -4
  283. package/dist/shared/utils/image.d.ts +0 -4
  284. package/dist/shared/utils/image.js +0 -6
  285. package/dist/shared/utils/name-generator.d.ts +14 -20
  286. package/dist/shared/utils/name-generator.js +20 -3
  287. package/dist/shared/utils/pixel-ratio.d.ts +9 -3
  288. package/dist/shared/utils/pixel-ratio.js +13 -4
  289. package/dist/shared/utils/property.d.ts +7 -50
  290. package/dist/shared/utils/property.js +22 -87
  291. package/dist/snapping/custom-targets.js +21 -4
  292. package/dist/snapping/indicator.js +20 -11
  293. package/dist/snapping/providers/display.d.ts +6 -1
  294. package/dist/snapping/providers/display.js +2 -1
  295. package/dist/snapping/providers/guide.d.ts +3 -43
  296. package/dist/snapping/providers/guide.js +1 -44
  297. package/dist/snapping/providers/intersection.js +1 -1
  298. package/dist/snapping/providers/store.js +3 -3
  299. package/dist/snapping/service.js +18 -7
  300. package/dist/snapping/types.d.ts +9 -35
  301. package/dist/store/draw-store.js +233 -142
  302. package/dist/store/local-visibility.d.ts +11 -6
  303. package/dist/store/local-visibility.js +38 -7
  304. package/dist/store/lock.d.ts +0 -6
  305. package/dist/store/lock.js +0 -6
  306. package/dist/store/memory/change-bus.d.ts +3 -3
  307. package/dist/store/memory/change-bus.js +12 -0
  308. package/dist/store/memory/file-store.d.ts +2 -2
  309. package/dist/store/memory/ui-state.d.ts +1 -51
  310. package/dist/store/memory/ui-state.js +122 -134
  311. package/dist/store/memory.d.ts +1 -8
  312. package/dist/store/memory.js +249 -45
  313. package/dist/store/ordering.d.ts +9 -0
  314. package/dist/store/ordering.js +17 -0
  315. package/dist/store/spatial/spatial-index.d.ts +1 -1
  316. package/dist/store/spatial/spatial-index.js +1 -1
  317. package/dist/store/spatial/store-spatial-index.d.ts +3 -1
  318. package/dist/store/spatial/store-spatial-index.js +9 -3
  319. package/dist/store/store.d.ts +66 -107
  320. package/dist/store/types.d.ts +1 -1
  321. package/dist/store/writable-layer.d.ts +1 -1
  322. package/dist/store/writable-layer.js +2 -2
  323. package/dist/table/builder.d.ts +83 -0
  324. package/dist/table/builder.js +381 -0
  325. package/dist/table/index.d.ts +37 -0
  326. package/dist/table/index.js +5 -0
  327. package/dist/table/packed-rtree.d.ts +1 -0
  328. package/dist/{display → table}/packed-rtree.js +1 -1
  329. package/dist/table/partition.d.ts +1 -0
  330. package/dist/{display → table}/partition.js +3 -3
  331. package/dist/table/prepare.d.ts +44 -0
  332. package/dist/table/prepare.js +136 -0
  333. package/dist/table/table.d.ts +1 -0
  334. package/dist/{display/columnar → table}/table.js +29 -25
  335. package/dist/{display/columnar → table}/types.d.ts +68 -72
  336. package/dist/table/types.js +3 -0
  337. package/dist/view/coordinator.js +4 -3
  338. package/dist/view/feature-companion.d.ts +13 -7
  339. package/dist/view/feature-companion.js +11 -3
  340. package/dist/view/globe-subdivision.js +3 -3
  341. package/dist/view/layer/attach.d.ts +1 -1
  342. package/dist/view/layer/attach.js +1 -1
  343. package/dist/view/layer/custom-layer.js +40 -11
  344. package/dist/view/layer/display-list.js +2 -1
  345. package/dist/view/layer/drape-planner.d.ts +2 -2
  346. package/dist/view/layer/frame-render.d.ts +3 -3
  347. package/dist/view/layer/frame-render.js +7 -2
  348. package/dist/view/layer/frame-state.d.ts +6 -6
  349. package/dist/view/layer/index.d.ts +2 -2
  350. package/dist/view/layer/index.js +1 -1
  351. package/dist/view/layer/render.d.ts +4 -4
  352. package/dist/view/layer/render.js +3 -8
  353. package/dist/view/layer/renderers.d.ts +2 -2
  354. package/dist/view/layer/renderers.js +1 -1
  355. package/dist/view/layer/slot-manager.d.ts +2 -2
  356. package/dist/view/layer/slot-manager.js +4 -4
  357. package/dist/view/layer/slots.d.ts +2 -2
  358. package/dist/view/layer/slots.js +1 -1
  359. package/dist/view/layer/store-retained-bbox.js +3 -2
  360. package/dist/view/layer/store-retained-classify.d.ts +5 -7
  361. package/dist/view/layer/store-retained-classify.js +19 -7
  362. package/dist/view/layer/store-retained-collect.js +8 -7
  363. package/dist/view/layer/store-retained-coord-patch.d.ts +0 -8
  364. package/dist/view/layer/store-retained-coord-patch.js +13 -4
  365. package/dist/view/layer/store-retained-immediate.d.ts +3 -3
  366. package/dist/view/layer/store-retained-immediate.js +3 -8
  367. package/dist/view/layer/store-retained-invalidation.d.ts +2 -2
  368. package/dist/view/layer/store-retained.d.ts +2 -2
  369. package/dist/view/layer/store-retained.js +1 -1
  370. package/dist/view/renderers/batch-manager.js +8 -7
  371. package/dist/view/renderers/drawer.js +21 -15
  372. package/dist/view/renderers/image.js +13 -39
  373. package/dist/view/renderers/line/line-types.d.ts +3 -3
  374. package/dist/view/renderers/line/sdf-line.js +3 -1
  375. package/dist/view/renderers/point/billboard-depth.js +1 -1
  376. package/dist/view/renderers/point/point-instance.js +1 -1
  377. package/dist/view/renderers/point/point-shape.js +2 -2
  378. package/dist/view/renderers/point/point-style.js +48 -4
  379. package/dist/view/renderers/polygon/batch.js +1 -2
  380. package/dist/view/renderers/polygon/fill.js +3 -1
  381. package/dist/view/renderers/polygon/sdf-polygon.js +2 -3
  382. package/dist/view/renderers/polygon/triangulator.d.ts +1 -1
  383. package/dist/view/renderers/stroke.js +3 -1
  384. package/dist/view/shaders/helpers.d.ts +2 -42
  385. package/dist/view/shaders/helpers.js +0 -6
  386. package/dist/view/shaders/projection.d.ts +15 -7
  387. package/dist/view/shaders/projection.js +23 -6
  388. package/dist/view/shaders/quad.d.ts +16 -12
  389. package/dist/view/shaders/quad.js +34 -13
  390. package/dist/view/style-rule.d.ts +5 -42
  391. package/dist/view/style-rule.js +20 -44
  392. package/dist/view/terrain/binding.d.ts +1 -0
  393. package/dist/view/terrain/binding.js +29 -0
  394. package/dist/view/terrain/context.d.ts +3 -4
  395. package/dist/view/terrain/context.js +4 -5
  396. package/dist/view/terrain/drape/geometry.js +1 -1
  397. package/dist/view/terrain/drape/pass.d.ts +1 -1
  398. package/dist/view/terrain/drape/pass.js +8 -7
  399. package/dist/view/terrain/polygon.d.ts +9 -5
  400. package/dist/view/terrain/polygon.js +16 -2
  401. package/dist/view/terrain/state.d.ts +1 -1
  402. package/dist/view/terrain/state.js +1 -1
  403. package/dist/view/terrain/tessellation.d.ts +2 -2
  404. package/dist/view/terrain/tessellation.js +1 -1
  405. package/dist/view/ui/auxiliary-handles.d.ts +6 -29
  406. package/dist/view/ui/bounds.js +8 -12
  407. package/dist/view/ui/handle-test.js +2 -2
  408. package/dist/view/ui/handle-thinning.js +17 -17
  409. package/dist/view/ui/handles.js +21 -13
  410. package/dist/view/ui/helper.d.ts +1 -1
  411. package/dist/view/ui/helper.js +1 -1
  412. package/dist/view/ui/index.d.ts +1 -1
  413. package/dist/view/ui/selection-scope.js +4 -2
  414. package/dist/view/ui/selection-ui/bounding-box.js +6 -6
  415. package/dist/view/ui/selection-ui/extension-registry.d.ts +31 -20
  416. package/dist/view/ui/selection-ui/extension-registry.js +70 -7
  417. package/dist/view/ui/selection-ui/index.d.ts +2 -2
  418. package/dist/view/ui/selection-ui/index.js +1 -1
  419. package/dist/view/ui/selection-ui/renderer.js +15 -38
  420. package/dist/view/ui/selection-ui/types.d.ts +17 -2
  421. package/dist/view/ui/selection-ui-drawer.d.ts +8 -0
  422. package/dist/view/ui/selection-ui-drawer.js +63 -2
  423. package/dist/view/ui/tentative.js +1 -1
  424. package/dist/webgl/index.d.ts +65 -0
  425. package/dist/webgl/index.js +62 -0
  426. package/package.json +20 -9
  427. package/dist/api/api.d.ts +0 -1259
  428. package/dist/api/api.js +0 -86
  429. package/dist/api/context.d.ts +0 -173
  430. package/dist/api/display-api.js +0 -23
  431. package/dist/api/event-api.d.ts +0 -13
  432. package/dist/api/event-api.js +0 -17
  433. package/dist/api/extension-api.d.ts +0 -46
  434. package/dist/api/extension-api.js +0 -85
  435. package/dist/api/feature-api.d.ts +0 -11
  436. package/dist/api/feature-api.js +0 -101
  437. package/dist/api/geometry/apply.d.ts +0 -51
  438. package/dist/api/geometry/boolean.d.ts +0 -28
  439. package/dist/api/geometry/boolean.js +0 -65
  440. package/dist/api/geometry/types.d.ts +0 -31
  441. package/dist/api/geometry-operations.d.ts +0 -162
  442. package/dist/api/geometry-operations.js +0 -94
  443. package/dist/api/group-api.d.ts +0 -10
  444. package/dist/api/group-api.js +0 -78
  445. package/dist/api/import-export/constants.d.ts +0 -29
  446. package/dist/api/import-export/constants.js +0 -40
  447. package/dist/api/import-export/file-name.d.ts +0 -10
  448. package/dist/api/import-export/file-name.js +0 -20
  449. package/dist/api/import-export/geojson-export.d.ts +0 -19
  450. package/dist/api/import-export/image-import.d.ts +0 -12
  451. package/dist/api/import-export/image-import.js +0 -53
  452. package/dist/api/import-export/index.d.ts +0 -9
  453. package/dist/api/import-export/index.js +0 -107
  454. package/dist/api/import-export/native-format.d.ts +0 -15
  455. package/dist/api/import-export/style-validation.d.ts +0 -27
  456. package/dist/api/import-export/style-validation.js +0 -49
  457. package/dist/api/import-export/types.d.ts +0 -26
  458. package/dist/api/index.d.ts +0 -15
  459. package/dist/api/index.js +0 -3
  460. package/dist/api/input-api.d.ts +0 -158
  461. package/dist/api/input-api.js +0 -144
  462. package/dist/api/instance-api.d.ts +0 -38
  463. package/dist/api/instance-api.js +0 -136
  464. package/dist/api/layer-api.d.ts +0 -12
  465. package/dist/api/layer-api.js +0 -62
  466. package/dist/api/selection-api.d.ts +0 -7
  467. package/dist/api/selection-api.js +0 -78
  468. package/dist/api/snapping-api.d.ts +0 -125
  469. package/dist/api/snapping-api.js +0 -50
  470. package/dist/api/topology-api.d.ts +0 -30
  471. package/dist/api/topology-api.js +0 -16
  472. package/dist/api/tracing-api.d.ts +0 -31
  473. package/dist/api/tracing-api.js +0 -16
  474. package/dist/dispatcher/hit-test/index.d.ts +0 -14
  475. package/dist/dispatcher/hit-test/index.js +0 -9
  476. package/dist/dispatcher/index.d.ts +0 -15
  477. package/dist/dispatcher/index.js +0 -3
  478. package/dist/display/columnar/index.d.ts +0 -12
  479. package/dist/display/columnar/index.js +0 -13
  480. package/dist/display/columnar/prepare.d.ts +0 -42
  481. package/dist/display/columnar/prepare.js +0 -116
  482. package/dist/display/index.d.ts +0 -13
  483. package/dist/display/types.js +0 -43
  484. package/dist/maplibre-gl-draw.d.ts +0 -47
  485. package/dist/modes/cursor.js +0 -72
  486. package/dist/modes/index.d.ts +0 -7
  487. package/dist/operations/index.d.ts +0 -9
  488. package/dist/operations/index.js +0 -3
  489. package/dist/plugins/index.d.ts +0 -10
  490. package/dist/plugins/mutation-hooks.d.ts +0 -28
  491. package/dist/plugins/mutation-hooks.js +0 -84
  492. package/dist/plugins/plugin-context.js +0 -367
  493. package/dist/plugins/plugin-manager.d.ts +0 -103
  494. package/dist/plugins/plugin-manager.js +0 -316
  495. package/dist/plugins/plugin.d.ts +0 -529
  496. package/dist/shared/config/index.d.ts +0 -17
  497. package/dist/shared/config/index.js +0 -8
  498. package/dist/shared/utils/index.d.ts +0 -15
  499. package/dist/shared/utils/index.js +0 -24
  500. package/dist/snapping/index.d.ts +0 -14
  501. package/dist/snapping/index.js +0 -4
  502. package/dist/store/change-merger.js +0 -102
  503. package/dist/store/event-bridge.js +0 -161
  504. package/dist/store/index.d.ts +0 -12
  505. package/dist/store/index.js +0 -4
  506. package/dist/view/index.d.ts +0 -47
  507. package/dist/view/index.js +0 -20
  508. /package/dist/api/{geometry/types.js → datasets.js} +0 -0
  509. /package/dist/api/{import-export/types.js → document.js} +0 -0
  510. /package/dist/{display/columnar/types.js → api/drawing.js} +0 -0
  511. /package/dist/{display/index.js → api/events.js} +0 -0
  512. /package/dist/{modes/index.js → api/extension/context.js} +0 -0
  513. /package/dist/{plugins/index.js → api/extension/feature-type.js} +0 -0
  514. /package/dist/{plugins/plugin.js → api/extension/mode.js} +0 -0
  515. /package/dist/api/{display-api.d.ts → impl/adapters.d.ts} +0 -0
  516. /package/dist/{display/columnar/source.d.ts → api/impl/contexts.d.ts} +0 -0
  517. /package/dist/{display/columnar/table.d.ts → api/impl/create-draw.d.ts} +0 -0
  518. /package/dist/{display/interaction.d.ts → api/impl/datasets.d.ts} +0 -0
  519. /package/dist/{display/manager.d.ts → api/impl/destroy-guard.d.ts} +0 -0
  520. /package/dist/{display/packed-rtree.d.ts → api/impl/document.d.ts} +0 -0
  521. /package/dist/{display/partition.d.ts → api/impl/drawing.d.ts} +0 -0
  522. /package/dist/{display/provider.d.ts → api/impl/engine.d.ts} +0 -0
  523. /package/dist/{display/source.d.ts → api/impl/events.d.ts} +0 -0
  524. /package/dist/{display/spatial.d.ts → api/impl/extension-host.d.ts} +0 -0
  525. /package/dist/{display/style.d.ts → api/impl/extensions.d.ts} +0 -0
  526. /package/dist/{display/triangulation.d.ts → api/impl/features.d.ts} +0 -0
  527. /package/dist/{modes/cursor.d.ts → api/impl/geometry/types.d.ts} +0 -0
  528. /package/dist/{plugins/plugin-context.d.ts → api/impl/hidden.d.ts} +0 -0
  529. /package/dist/api/{import-export → impl/import-export}/embedded-file.d.ts +0 -0
  530. /package/dist/api/{import-export → impl/import-export}/own-property.d.ts +0 -0
  531. /package/dist/api/{import-export → impl/import-export}/own-property.js +0 -0
  532. /package/dist/{store/change-merger.d.ts → api/impl/input.d.ts} +0 -0
  533. /package/dist/{store/event-bridge.d.ts → api/impl/layers.d.ts} +0 -0
  534. /package/dist/{display → dataset}/chunk-set.d.ts +0 -0
  535. /package/dist/{display → dataset}/chunk-set.js +0 -0
  536. /package/dist/{display → dataset}/dataset.d.ts +0 -0
  537. /package/dist/{display → dataset}/manager.js +0 -0
  538. /package/dist/{display → dataset}/provider.js +0 -0
  539. /package/dist/{display → dataset}/selection.d.ts +0 -0
  540. /package/dist/{display → dataset}/selection.js +0 -0
@@ -1,15 +1,13 @@
1
1
  // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
2
  // SPDX-License-Identifier: AGPL-3.0-only
3
- /**
4
- * Conversion from GeoJSON to the internal Feature format + load of a
5
- * GeoJSON FeatureCollection
6
- */
7
- import { createId } from '../../shared/utils/id.js';
8
- import { GEOJSON_PREFIX, LIBRARY_PROPERTIES } from './constants.js';
3
+ import { DRAW_PROPERTY_NAMES, DRAW_PROPERTY_PREFIX, drawPropertyKey, hasDrawProperty, setDrawProperty, } from '../../../shared/properties.js';
4
+ import { createId } from '../../../shared/utils/id.js';
5
+ import { DrawError } from '../../errors.js';
9
6
  import { normalizeEmbeddedFile } from './embedded-file.js';
10
7
  import { COORDINATE_DEPTH, describeCoordinateProblem } from './geometry-validation.js';
8
+ import { foldLegacyImageStyle } from './legacy-image-style.js';
11
9
  import { setOwnProperty } from './own-property.js';
12
- import { isHexColor, sanitizeFeatureStyle } from './style-validation.js';
10
+ import { isCssColor, sanitizeFeatureStyle } from './style-validation.js';
13
11
  /**
14
12
  * Converts a single geometry (Point/LineString/Polygon) into the Feature format
15
13
  */
@@ -28,7 +26,7 @@ function convertSingleGeometry(geometry, meta, userProperties, featureType, file
28
26
  case 'Point': {
29
27
  const type = resolveFeatureType('Point', featureType);
30
28
  return {
31
- feature: { ...base, type, coordinates: geometry.coordinates },
29
+ feature: { ...base, type, geometry },
32
30
  // The embedded image belongs only to a feature that really is an Image
33
31
  fileData: type === 'Image' ? fileData : undefined,
34
32
  };
@@ -39,19 +37,16 @@ function convertSingleGeometry(geometry, meta, userProperties, featureType, file
39
37
  // (this pairs with the default branch on export).
40
38
  const type = resolveFeatureType('LineString', featureType);
41
39
  return {
42
- feature: {
43
- ...base,
44
- type,
45
- coordinates: geometry.coordinates,
46
- },
40
+ feature: { ...base, type, geometry },
47
41
  };
48
42
  }
49
43
  case 'Polygon':
44
+ // A custom type whose geometry is an area comes back from its marker as the others do
50
45
  return {
51
46
  feature: {
52
47
  ...base,
53
- type: 'Polygon',
54
- coordinates: geometry.coordinates,
48
+ type: resolveFeatureType('Polygon', featureType),
49
+ geometry,
55
50
  },
56
51
  };
57
52
  default:
@@ -64,7 +59,7 @@ function convertSingleGeometry(geometry, meta, userProperties, featureType, file
64
59
  * The parts are kept as they are instead of being split, so that properties are not
65
60
  * duplicated.
66
61
  */
67
- function convertMultiGeometry(geometry, meta, userProperties) {
62
+ function convertMultiGeometry(geometry, meta, userProperties, featureType) {
68
63
  if (geometry.coordinates.length === 0)
69
64
  return null;
70
65
  return [
@@ -77,8 +72,8 @@ function convertMultiGeometry(geometry, meta, userProperties) {
77
72
  style: meta.style,
78
73
  locked: meta.locked,
79
74
  visible: meta.visible,
80
- type: geometry.type,
81
- coordinates: geometry.coordinates,
75
+ type: resolveFeatureType(geometry.type, featureType),
76
+ geometry,
82
77
  },
83
78
  },
84
79
  ];
@@ -164,7 +159,7 @@ function convertGeometryCollection(geometry, meta, userProperties, generateFeatu
164
159
  locked: meta.locked,
165
160
  visible: meta.visible,
166
161
  type,
167
- coordinates,
162
+ geometry: { type, coordinates },
168
163
  },
169
164
  });
170
165
  };
@@ -187,14 +182,15 @@ const GEOMETRY_TYPE_NAMES = new Set([
187
182
  'geometrycollection',
188
183
  ]);
189
184
  /**
190
- * Resolves the feature type of a Point or LineString from the featureType marker
185
+ * Resolves the feature type of a geometry from the featureType marker
191
186
  *
192
187
  * The marker restores a type that GeoJSON has no geometry for (Image, Circle, Freehand and
193
- * custom types). The export writes the type name as it is, and the marker is read as that exact
194
- * name. It is used only when it is a non-empty string, does not name a GeoJSON geometry type
195
- * (in any letter case), and names a type whose coordinates have the shape of the geometry.
196
- * Anything else is ignored and the geometry type is kept, so the marker can never pair a type
197
- * with coordinates of another shape.
188
+ * custom types, whatever their geometry). The export writes the type name as it is, and the
189
+ * marker is read as that exact name: it wins over the kind of the geometry. It is used only
190
+ * when it is a non-empty string, does not name a GeoJSON geometry type (in any letter case),
191
+ * and does not name a built-in type whose coordinates have another shape. Anything else is
192
+ * ignored and the geometry type is kept, so the marker can never pair a built-in type with
193
+ * coordinates of another shape.
198
194
  */
199
195
  function resolveFeatureType(geometryType, marker) {
200
196
  if (typeof marker !== 'string' || marker === '')
@@ -202,9 +198,13 @@ function resolveFeatureType(geometryType, marker) {
202
198
  if (GEOMETRY_TYPE_NAMES.has(marker.toLowerCase()))
203
199
  return geometryType;
204
200
  const expectedDepth = COORDINATE_DEPTH[marker];
205
- const actualDepth = geometryType === 'Point' ? 0 : 1;
201
+ const actualDepth = COORDINATE_DEPTH[geometryType];
206
202
  return expectedDepth === undefined || expectedDepth === actualDepth ? marker : geometryType;
207
203
  }
204
+ /** The keys of `properties` that hold the values of this library */
205
+ const LIBRARY_KEYS = new Set(DRAW_PROPERTY_NAMES.map((name) => drawPropertyKey(name)));
206
+ /** The values of a Circle that an earlier export wrote without the prefix */
207
+ const LEGACY_CIRCLE_PROPERTIES = ['radiusMeters', 'radiusHandleAngle'];
208
208
  /** The geometry types the import converts */
209
209
  const SUPPORTED_GEOMETRY_TYPES = new Set([
210
210
  'Point',
@@ -286,7 +286,7 @@ function simplestyleToFeatureStyle(properties) {
286
286
  let found = false;
287
287
  const copyString = (key, target) => {
288
288
  const value = properties[key];
289
- if (isHexColor(value)) {
289
+ if (isCssColor(value)) {
290
290
  style[target] = value;
291
291
  found = true;
292
292
  }
@@ -333,7 +333,7 @@ export function convertGeoJSONToFeature(geoFeature, layerId, generateFeatureId,
333
333
  // form, and anything else gets a new id. The prefixed property takes precedence, then the
334
334
  // standard id member of the Feature. Whether it collides with existing data is resolved by
335
335
  // the caller, which knows the store.
336
- const prefixedId = properties?.[`${GEOJSON_PREFIX}id`];
336
+ const prefixedId = properties?.[`${DRAW_PROPERTY_PREFIX}id`];
337
337
  const rawId = prefixedId === undefined || prefixedId === null || prefixedId === ''
338
338
  ? geoFeature.id
339
339
  : prefixedId;
@@ -342,54 +342,65 @@ export function convertGeoJSONToFeature(geoFeature, layerId, generateFeatureId,
342
342
  : typeof rawId === 'number' && Number.isFinite(rawId)
343
343
  ? String(rawId)
344
344
  : generateFeatureId();
345
- const rawLayerId = properties?.[`${GEOJSON_PREFIX}layerId`];
345
+ const rawLayerId = properties?.[`${DRAW_PROPERTY_PREFIX}layerId`];
346
346
  const featureLayerId = typeof rawLayerId === 'string' && rawLayerId !== '' ? rawLayerId : layerId;
347
- const rawGroupId = properties?.[`${GEOJSON_PREFIX}groupId`];
347
+ const rawGroupId = properties?.[`${DRAW_PROPERTY_PREFIX}groupId`];
348
348
  const groupId = typeof rawGroupId === 'string' && rawGroupId !== '' ? rawGroupId : undefined;
349
349
  // The round-trip style key takes precedence; only when it is absent is the style built
350
350
  // from simplestyle-spec (they are not merged). Either way the keys are validated.
351
- const roundTripStyle = properties?.[`${GEOJSON_PREFIX}style`];
352
- const style = roundTripStyle !== undefined && roundTripStyle !== null
351
+ const roundTripStyle = properties?.[`${DRAW_PROPERTY_PREFIX}style`];
352
+ const style = (roundTripStyle !== undefined && roundTripStyle !== null
353
353
  ? sanitizeFeatureStyle(roundTripStyle)
354
- : simplestyleToFeatureStyle(properties);
355
- const featureType = properties?.[`${GEOJSON_PREFIX}featureType`];
354
+ : simplestyleToFeatureStyle(properties)) ?? {};
355
+ const featureType = properties?.[`${DRAW_PROPERTY_PREFIX}featureType`];
356
356
  // visible is hidden only when it is explicitly false, and locked is treated as locked
357
357
  // only when it is explicitly true
358
- const visible = properties?.[`${GEOJSON_PREFIX}visible`] !== false;
359
- const locked = properties?.[`${GEOJSON_PREFIX}locked`] === true;
358
+ const visible = properties?.[`${DRAW_PROPERTY_PREFIX}visible`] !== false;
359
+ const locked = properties?.[`${DRAW_PROPERTY_PREFIX}locked`] === true;
360
360
  // Extract the embedded image data. It is taken only for a single point that really is an
361
361
  // Image.
362
- const imageData = properties?.[`${GEOJSON_PREFIX}imageData`];
363
- const imageMimeType = properties?.[`${GEOJSON_PREFIX}imageMimeType`];
362
+ const imageData = properties?.[`${DRAW_PROPERTY_PREFIX}imageData`];
363
+ const imageMimeType = properties?.[`${DRAW_PROPERTY_PREFIX}imageMimeType`];
364
364
  const embedsImage = Boolean(imageData && imageMimeType) &&
365
365
  geometry.type === 'Point' &&
366
366
  resolveFeatureType('Point', featureType) === 'Image';
367
367
  // Extract the properties
368
368
  // - without a prefix: added as is as a user-defined property
369
- // - with a prefix and one of this library's own properties: added with the prefix stripped
369
+ // - with a prefix and one of this library's own values: added as is
370
370
  // - any other prefixed key (id, layerId, style, visible, locked and so on): excluded
371
371
  // (they are handled separately)
372
372
  // Keys are defined as own properties so that a `__proto__` key stays an ordinary key.
373
373
  const userProperties = {};
374
374
  if (properties) {
375
375
  for (const [key, value] of Object.entries(properties)) {
376
- if (key.startsWith(GEOJSON_PREFIX)) {
377
- const keyWithoutPrefix = key.slice(GEOJSON_PREFIX.length);
378
- if (LIBRARY_PROPERTIES.has(keyWithoutPrefix)) {
379
- // When there is image data, imageFileId is replaced with a new ID, so it is
380
- // not added here
381
- if (keyWithoutPrefix !== 'imageFileId' || !embedsImage) {
382
- setOwnProperty(userProperties, keyWithoutPrefix, value);
383
- }
376
+ if (key.startsWith(DRAW_PROPERTY_PREFIX)) {
377
+ // When there is image data, imageFileId is replaced with a new ID, so it is not
378
+ // added here. Anything else that is not a value of this library (id, layerId, style,
379
+ // featureType, visible, locked, imageData and so on) is excluded
380
+ if (LIBRARY_KEYS.has(key) && (key !== drawPropertyKey('imageFileId') || !embedsImage)) {
381
+ setOwnProperty(userProperties, key, value);
384
382
  }
385
- // Anything else (id, layerId, style, featureType, visible, locked, imageData and
386
- // so on) is excluded
387
383
  }
388
384
  else {
389
385
  setOwnProperty(userProperties, key, value);
390
386
  }
391
387
  }
392
388
  }
389
+ // An earlier export wrote the radius of a Circle and the direction of its handle without
390
+ // the prefix; they are read as the values of this library when the prefixed ones are absent
391
+ if (geometry.type === 'Point' && resolveFeatureType('Point', featureType) === 'Circle') {
392
+ for (const name of LEGACY_CIRCLE_PROPERTIES) {
393
+ if (userProperties[name] !== undefined && !hasDrawProperty(userProperties, name)) {
394
+ setOwnProperty(userProperties, drawPropertyKey(name), userProperties[name]);
395
+ delete userProperties[name];
396
+ }
397
+ }
398
+ }
399
+ // The style of an Image written by an earlier export can carry its size, a rotation and an
400
+ // opacity of its own; they are read as the values of this library and imageOpacity
401
+ if (geometry.type === 'Point' && resolveFeatureType('Point', featureType) === 'Image') {
402
+ foldLegacyImageStyle(userProperties, style);
403
+ }
393
404
  // When there is image data on a single Image point, create the FileData and set a new
394
405
  // imageFileId
395
406
  let fileData;
@@ -400,7 +411,7 @@ export function convertGeoJSONToFeature(geoFeature, layerId, generateFeatureId,
400
411
  mimeType: imageMimeType,
401
412
  dataURL: imageData,
402
413
  };
403
- userProperties.imageFileId = newFileId;
414
+ setDrawProperty(userProperties, 'imageFileId', newFileId);
404
415
  }
405
416
  const meta = {
406
417
  id,
@@ -420,17 +431,17 @@ export function convertGeoJSONToFeature(geoFeature, layerId, generateFeatureId,
420
431
  }
421
432
  case 'MultiPoint':
422
433
  if (!flattenMulti) {
423
- return convertMultiGeometry(geometry, meta, userProperties);
434
+ return convertMultiGeometry(geometry, meta, userProperties, featureType);
424
435
  }
425
436
  return flattenMultiGeometry(geometry.coordinates, (coords) => ({ type: 'Point', coordinates: coords }), generateFeatureId, meta, userProperties, featureType, fileData);
426
437
  case 'MultiLineString':
427
438
  if (!flattenMulti) {
428
- return convertMultiGeometry(geometry, meta, userProperties);
439
+ return convertMultiGeometry(geometry, meta, userProperties, featureType);
429
440
  }
430
441
  return flattenMultiGeometry(geometry.coordinates, (coords) => ({ type: 'LineString', coordinates: coords }), generateFeatureId, meta, userProperties, undefined, undefined);
431
442
  case 'MultiPolygon':
432
443
  if (!flattenMulti) {
433
- return convertMultiGeometry(geometry, meta, userProperties);
444
+ return convertMultiGeometry(geometry, meta, userProperties, featureType);
434
445
  }
435
446
  return flattenMultiGeometry(geometry.coordinates, (coords) => ({ type: 'Polygon', coordinates: coords }), generateFeatureId, meta, userProperties, undefined, undefined);
436
447
  case 'GeometryCollection':
@@ -447,15 +458,20 @@ export function convertGeoJSONToFeature(geoFeature, layerId, generateFeatureId,
447
458
  /** How many times a colliding feature id is regenerated before the import gives up */
448
459
  const MAX_ID_ATTEMPTS = 1000;
449
460
  /**
450
- * Imports a GeoJSON FeatureCollection (adds to the existing data)
461
+ * Reads a GeoJSON FeatureCollection for a load that adds to the existing data (or replaces
462
+ * the features and groups): the features are converted and checked and the embedded images
463
+ * decoded here, and the writes are left to the transaction of the caller. The IDs and the
464
+ * references to layers and groups are resolved when the features are written, against the
465
+ * document as it is then (another load of the same transaction may have changed it).
451
466
  */
452
- export async function loadGeoJSON(data, deps, options) {
467
+ export async function prepareGeoJSON(data, deps, options) {
453
468
  const { store, autoNameGenerator, generateFeatureId, getCurrentLayerId } = deps;
454
469
  const layerId = getCurrentLayerId();
455
470
  const generateFileId = () => createId();
456
- // 1. Validate, convert and resolve everything before writing. store.transact does not roll
457
- // back, so nothing may throw once the writing has started. A feature that cannot be
458
- // imported is skipped with its reason instead of rejecting the whole load.
471
+ // 1. Validate and convert everything, and decode the embedded images, before writing.
472
+ // store.transact does not roll back, so nothing may throw once the writing has started. A
473
+ // feature that cannot be imported is skipped with its reason instead of rejecting the
474
+ // whole load.
459
475
  const results = [];
460
476
  const skipped = [];
461
477
  data.features.forEach((geoFeature, index) => {
@@ -467,33 +483,6 @@ export async function loadGeoJSON(data, deps, options) {
467
483
  results.push(...converted.results);
468
484
  }
469
485
  });
470
- // Feature and group IDs share the entries of layer.order, so an id taken by either (or by
471
- // an earlier feature of this import) is replaced with a new one. This is what makes a
472
- // GeoJSON exported from a store loadable into the same store again.
473
- const takenIds = new Set();
474
- const isTaken = (id) => takenIds.has(id) || store.getFeature(id) !== undefined || store.getGroup(id) !== undefined;
475
- const resolveId = (id) => {
476
- let resolved = id;
477
- for (let attempt = 0; isTaken(resolved); attempt++) {
478
- if (attempt >= MAX_ID_ATTEMPTS) {
479
- throw new Error('Failed to generate a unique feature id for the GeoJSON import');
480
- }
481
- resolved = generateFeatureId();
482
- }
483
- takenIds.add(resolved);
484
- return resolved;
485
- };
486
- for (const { feature } of results) {
487
- feature.id = resolveId(feature.id);
488
- // References are resolved against this store: a layer it does not have falls back to
489
- // the current layer, and a group it does not have is dropped (a feature pointing at a
490
- // missing group would belong to no layer order and never be drawn).
491
- if (!store.getLayer(feature.layerId))
492
- feature.layerId = layerId;
493
- if (feature.groupId !== undefined && !store.getGroup(feature.groupId)) {
494
- delete feature.groupId;
495
- }
496
- }
497
486
  // Embedded images are accepted only as PNG / JPEG / WebP / GIF data URLs, and an oversized
498
487
  // one is scaled down. Unlike a malformed geometry, a bad image rejects the whole load: the
499
488
  // image fields are written only by this library's export, so a bad one means the file was
@@ -503,16 +492,67 @@ export async function loadGeoJSON(data, deps, options) {
503
492
  continue;
504
493
  const content = await normalizeEmbeddedFile(result.fileData.dataURL, result.fileData.mimeType);
505
494
  if (!content) {
506
- throw new Error(`Invalid GeoJSON: the image data of feature "${result.feature.id}" is not an embedded ` +
495
+ throw new DrawError('invalid-input', `Invalid GeoJSON: the image data of feature "${result.feature.id}" is not an embedded ` +
507
496
  'PNG / JPEG / WebP / GIF data URL of its declared type');
508
497
  }
509
498
  result.fileData = { ...result.fileData, ...content };
510
499
  }
511
- // 2. Write. Written with batch: the whole import is one notification, one step for a
512
- // subscriber that records changes. Hosts that rebuild a view should subscribe to the
513
- // per-flush `features.change` event rather than the per-feature events.
514
- const featureIds = [];
515
- store.transact(() => {
500
+ const replace = options?.replace === true;
501
+ // 2. The writes, in the transaction of the caller, the deletion of a replace included: the
502
+ // whole import is one notification, one step for a subscriber that records changes
503
+ const write = () => {
504
+ const currentLayerId = getCurrentLayerId();
505
+ if (replace) {
506
+ for (const feature of store.listFeatures())
507
+ store.deleteFeature(feature.id);
508
+ for (const group of store.listGroups())
509
+ store.deleteGroup(group.id);
510
+ }
511
+ // Feature and group IDs share the entries of layer.order, so an id taken by either (or by
512
+ // an earlier feature of this import) is replaced with a new one. This is what makes a
513
+ // GeoJSON exported from a store loadable into the same store again.
514
+ // With replace, the features and groups of the document are gone by the time the new ones
515
+ // are written, so only the IDs of this import can collide
516
+ const takenIds = new Set();
517
+ const isTaken = (id) => takenIds.has(id) ||
518
+ options?.reservedIds?.has(id) === true ||
519
+ (!replace && (store.getFeature(id) !== undefined || store.getGroup(id) !== undefined));
520
+ const resolveId = (id) => {
521
+ let resolved = id;
522
+ for (let attempt = 0; isTaken(resolved); attempt++) {
523
+ if (attempt >= MAX_ID_ATTEMPTS) {
524
+ throw new DrawError('invalid-input', 'Failed to generate a unique feature id for the GeoJSON import');
525
+ }
526
+ resolved = generateFeatureId();
527
+ }
528
+ takenIds.add(resolved);
529
+ return resolved;
530
+ };
531
+ const forcedLayerId = options?.layerId;
532
+ const oneGroup = options?.oneGroup === true;
533
+ for (const { feature } of results) {
534
+ feature.id = resolveId(feature.id);
535
+ // References are resolved against this store: a layer given to the load wins over the one
536
+ // the feature names, a layer the store does not have falls back to the current layer, and a
537
+ // group it does not have (or a group of another layer, or any group when the groups are
538
+ // replaced) is dropped: a feature pointing at a missing group would belong to no layer
539
+ // order and never be drawn.
540
+ if (forcedLayerId !== undefined && store.getLayer(forcedLayerId)) {
541
+ feature.layerId = forcedLayerId;
542
+ }
543
+ else if (forcedLayerId !== undefined || oneGroup || !store.getLayer(feature.layerId)) {
544
+ feature.layerId = currentLayerId;
545
+ }
546
+ // The features of a load that makes a group of them leave the group they name
547
+ if (oneGroup)
548
+ delete feature.groupId;
549
+ if (feature.groupId !== undefined) {
550
+ const group = replace ? undefined : store.getGroup(feature.groupId);
551
+ if (!group || group.layerId !== feature.layerId)
552
+ delete feature.groupId;
553
+ }
554
+ }
555
+ const featureIds = [];
516
556
  for (const result of results) {
517
557
  // When there is image data, add the file first
518
558
  if (result.fileData) {
@@ -528,11 +568,13 @@ export async function loadGeoJSON(data, deps, options) {
528
568
  store.createFeature(result.feature);
529
569
  featureIds.push(result.feature.id);
530
570
  }
531
- }, 'batch');
532
- return {
533
- format: 'geojson',
534
- featureIds,
535
- replaced: false,
536
- skipped,
571
+ const loaded = {
572
+ format: 'geojson',
573
+ featureIds,
574
+ replaced: replace,
575
+ skipped,
576
+ };
577
+ return loaded;
537
578
  };
579
+ return { write };
538
580
  }
@@ -18,3 +18,17 @@ export declare const COORDINATE_DEPTH: Readonly<Record<string, number>>;
18
18
  * null
19
19
  */
20
20
  export declare function describeCoordinateProblem(type: string, coordinates: unknown): string | null;
21
+ /**
22
+ * Returns why a GeoJSON geometry cannot be used for a feature of the type, or null when it
23
+ * can
24
+ *
25
+ * The geometry must be an object of one of the six kinds with coordinates (a
26
+ * GeometryCollection is not a geometry of a feature), a built-in type must hold its own kind
27
+ * (a Circle and an Image a Point, a Freehand a LineString), and the coordinates must pass
28
+ * {@link describeCoordinateProblem} for the kind. A custom type may hold any of the kinds.
29
+ *
30
+ * @param type - the feature type
31
+ * @param geometry - the geometry to check
32
+ * @returns a short phrase that reads after "has", or null
33
+ */
34
+ export declare function describeGeometryProblem(type: string, geometry: unknown): string | null;
@@ -1,5 +1,13 @@
1
1
  // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
2
  // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * Validation of feature coordinates at the import boundary
5
+ *
6
+ * Both imports (the native format and GeoJSON) check coordinates with the same rules before
7
+ * anything is written, so that malformed geometry never reaches the store, the spatial index
8
+ * or the renderers. The rules follow docs/reference/data-format.md.
9
+ */
10
+ import { builtInGeometryKind } from '../../../shared/utils/coordinates.js';
3
11
  /**
4
12
  * The nesting depth of the coordinates of each built-in feature type
5
13
  * (0 = a single position, 1 = a sequence of positions, and so on).
@@ -105,3 +113,40 @@ export function describeCoordinateProblem(type, coordinates) {
105
113
  return null;
106
114
  }
107
115
  }
116
+ /** The kinds of GeoJSON geometry a feature can hold */
117
+ const GEOMETRY_KINDS = new Set([
118
+ 'Point',
119
+ 'LineString',
120
+ 'Polygon',
121
+ 'MultiPoint',
122
+ 'MultiLineString',
123
+ 'MultiPolygon',
124
+ ]);
125
+ /**
126
+ * Returns why a GeoJSON geometry cannot be used for a feature of the type, or null when it
127
+ * can
128
+ *
129
+ * The geometry must be an object of one of the six kinds with coordinates (a
130
+ * GeometryCollection is not a geometry of a feature), a built-in type must hold its own kind
131
+ * (a Circle and an Image a Point, a Freehand a LineString), and the coordinates must pass
132
+ * {@link describeCoordinateProblem} for the kind. A custom type may hold any of the kinds.
133
+ *
134
+ * @param type - the feature type
135
+ * @param geometry - the geometry to check
136
+ * @returns a short phrase that reads after "has", or null
137
+ */
138
+ export function describeGeometryProblem(type, geometry) {
139
+ if (typeof geometry !== 'object' || geometry === null || Array.isArray(geometry)) {
140
+ return 'no geometry object';
141
+ }
142
+ const { type: kind, coordinates } = geometry;
143
+ if (typeof kind !== 'string' || !GEOMETRY_KINDS.has(kind)) {
144
+ return `a geometry of the unsupported type "${String(kind)}"`;
145
+ }
146
+ const expected = builtInGeometryKind(type);
147
+ if (expected !== undefined && kind !== expected) {
148
+ return `a ${kind} geometry that does not match the type ${type}`;
149
+ }
150
+ const problem = describeCoordinateProblem(kind, coordinates);
151
+ return problem ? `a ${kind} geometry with ${problem}` : null;
152
+ }
@@ -0,0 +1,16 @@
1
+ import type { AutoNameGenerator } from '../../../shared/utils/name-generator.js';
2
+ import type { Store } from '../../../store/store.js';
3
+ import type { LoadOptions } from '../../../store/types.js';
4
+ import type { PreparedLoad } from './types.js';
5
+ /**
6
+ * Decodes an image file for a load that creates an Image feature; the writes are left to the
7
+ * transaction of the caller
8
+ *
9
+ * @param beforeWrite - Runs first when the image is written, such as the deletion of a replace
10
+ */
11
+ export declare function prepareImage(file: File, options: LoadOptions, deps: {
12
+ store: Store;
13
+ autoNameGenerator: AutoNameGenerator;
14
+ generateFeatureId: () => string;
15
+ getCurrentLayerId: () => string;
16
+ }, beforeWrite?: () => void): Promise<PreparedLoad>;
@@ -0,0 +1,73 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * Import of image files (creates an Image feature)
5
+ */
6
+ import { drawProperties } from '../../../shared/properties.js';
7
+ import { processImageFile } from '../../../shared/utils/image.js';
8
+ import { DrawError } from '../../errors.js';
9
+ /**
10
+ * Decodes an image file for a load that creates an Image feature; the writes are left to the
11
+ * transaction of the caller
12
+ *
13
+ * @param beforeWrite - Runs first when the image is written, such as the deletion of a replace
14
+ */
15
+ export async function prepareImage(file, options, deps, beforeWrite) {
16
+ const coordinate = options.coordinate;
17
+ if (!coordinate) {
18
+ throw new DrawError('invalid-input', 'Image files require coordinate option');
19
+ }
20
+ const { store, autoNameGenerator, generateFeatureId, getCurrentLayerId } = deps;
21
+ let processed;
22
+ try {
23
+ processed = await processImageFile(file);
24
+ }
25
+ catch (error) {
26
+ const message = error instanceof Error ? error.message : String(error);
27
+ throw new DrawError('unsupported-format', `The image cannot be read: ${message}`, {
28
+ cause: error,
29
+ });
30
+ }
31
+ // The IDs, the layer and the automatic name are taken when the image is written, so that a
32
+ // load that fails later takes nothing
33
+ const write = () => {
34
+ const fileId = generateFeatureId();
35
+ const fileData = {
36
+ id: fileId,
37
+ mimeType: processed.mimeType,
38
+ dataURL: processed.dataUrl,
39
+ };
40
+ const featureId = generateFeatureId();
41
+ const layerId = options.layerId && store.getLayer(options.layerId) ? options.layerId : getCurrentLayerId();
42
+ const autoName = autoNameGenerator.generateName('Image');
43
+ const feature = {
44
+ groupId: undefined,
45
+ id: featureId,
46
+ type: 'Image',
47
+ geometry: { type: 'Point', coordinates: coordinate },
48
+ layerId,
49
+ properties: {
50
+ ...drawProperties({
51
+ imageFileId: fileId,
52
+ imageWidth: processed.width,
53
+ imageHeight: processed.height,
54
+ createdZoom: options.zoom ?? 1,
55
+ }),
56
+ ...(autoName !== undefined && { name: autoName }),
57
+ },
58
+ locked: false,
59
+ visible: true,
60
+ style: {},
61
+ };
62
+ beforeWrite?.();
63
+ store.createFile(fileData);
64
+ store.createFeature(feature);
65
+ store.setSelection('feature', [featureId]);
66
+ return {
67
+ format: 'image',
68
+ featureIds: [featureId],
69
+ replaced: false,
70
+ };
71
+ };
72
+ return { write };
73
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Folds the style keys of an Image of 1.0 into its properties and its style
3
+ *
4
+ * - `width` and `height`, when they are positive, become the size the image is drawn at
5
+ * (`maplibre-gl-draw:imageWidth` and `maplibre-gl-draw:imageHeight`)
6
+ * - `rotation` is added to `maplibre-gl-draw:rotation` (1.0 drew the sum of the two)
7
+ * - `opacity` becomes `imageOpacity` when the style has no `imageOpacity` (1.0 read it only
8
+ * then)
9
+ *
10
+ * The four keys are removed from the style. The objects given are changed in place.
11
+ *
12
+ * @param properties - the properties of the feature, with the values of the library prefixed
13
+ * @param style - the style of the feature
14
+ * @returns whether anything was folded
15
+ */
16
+ export declare function foldLegacyImageStyle(properties: Record<string, unknown>, style: Record<string, unknown>): boolean;
@@ -0,0 +1,49 @@
1
+ // SPDX-FileCopyrightText: 2026 SAKAIDA Atsushi
2
+ // SPDX-License-Identifier: AGPL-3.0-only
3
+ /**
4
+ * The style keys an Image had in 1.0, folded into the model of 2.0
5
+ *
6
+ * In 1.0 the style of an Image could carry its size, a rotation and an opacity of its own. In
7
+ * 2.0 the size and the rotation are values of the library in `properties` and the opacity is
8
+ * `imageOpacity` of the style. Data written by 1.0 (native data of version 2 and GeoJSON) is
9
+ * read through this fold so that the image keeps its look.
10
+ */
11
+ import { drawPropertyKey } from '../../../shared/properties.js';
12
+ /** The style keys of an Image that 2.0 does not have */
13
+ const LEGACY_KEYS = ['width', 'height', 'rotation', 'opacity'];
14
+ function isNumber(value) {
15
+ return typeof value === 'number' && Number.isFinite(value);
16
+ }
17
+ /**
18
+ * Folds the style keys of an Image of 1.0 into its properties and its style
19
+ *
20
+ * - `width` and `height`, when they are positive, become the size the image is drawn at
21
+ * (`maplibre-gl-draw:imageWidth` and `maplibre-gl-draw:imageHeight`)
22
+ * - `rotation` is added to `maplibre-gl-draw:rotation` (1.0 drew the sum of the two)
23
+ * - `opacity` becomes `imageOpacity` when the style has no `imageOpacity` (1.0 read it only
24
+ * then)
25
+ *
26
+ * The four keys are removed from the style. The objects given are changed in place.
27
+ *
28
+ * @param properties - the properties of the feature, with the values of the library prefixed
29
+ * @param style - the style of the feature
30
+ * @returns whether anything was folded
31
+ */
32
+ export function foldLegacyImageStyle(properties, style) {
33
+ if (!LEGACY_KEYS.some((key) => key in style))
34
+ return false;
35
+ const { width, height, rotation, opacity } = style;
36
+ if (isNumber(width) && width > 0)
37
+ properties[drawPropertyKey('imageWidth')] = width;
38
+ if (isNumber(height) && height > 0)
39
+ properties[drawPropertyKey('imageHeight')] = height;
40
+ if (isNumber(rotation) && rotation !== 0) {
41
+ const current = properties[drawPropertyKey('rotation')];
42
+ properties[drawPropertyKey('rotation')] = (isNumber(current) ? current : 0) + rotation;
43
+ }
44
+ if (style.imageOpacity === undefined && isNumber(opacity))
45
+ style.imageOpacity = opacity;
46
+ for (const key of LEGACY_KEYS)
47
+ delete style[key];
48
+ return true;
49
+ }
@@ -0,0 +1,14 @@
1
+ import type { Store } from '../../../store/store.js';
2
+ import type { Data, ExportOptions } from '../../../store/types.js';
3
+ import type { PreparedLoad } from './types.js';
4
+ /**
5
+ * Exports the current data in the native format
6
+ */
7
+ export declare function exportNative(store: Store, options?: ExportOptions): Data;
8
+ /**
9
+ * Reads the native format for a load that replaces the existing data: everything is checked
10
+ * here, and the writes are left to the transaction of the caller
11
+ */
12
+ export declare function prepareNative(data: Data, deps: {
13
+ store: Store;
14
+ }): Promise<PreparedLoad>;