@honua/app-platform 0.1.9-beta.0 → 0.1.10-beta.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 (190) hide show
  1. package/control-plane/admin-client.d.ts +2 -0
  2. package/control-plane/admin-client.d.ts.map +1 -1
  3. package/control-plane/admin-client.js +32 -1
  4. package/control-plane/client.d.ts +1 -1
  5. package/control-plane/client.d.ts.map +1 -1
  6. package/control-plane/client.js +124 -8
  7. package/control-plane/commands/catalog.d.ts +7 -7
  8. package/control-plane/commands/catalog.d.ts.map +1 -1
  9. package/control-plane/commands/catalog.js +27 -15
  10. package/control-plane/commands/runtime.d.ts +6 -6
  11. package/control-plane/commands/runtime.d.ts.map +1 -1
  12. package/control-plane/commands/runtime.js +26 -14
  13. package/control-plane/commands/types.d.ts +4 -2
  14. package/control-plane/commands/types.d.ts.map +1 -1
  15. package/control-plane/generated/admin-api.d.ts +6 -4
  16. package/control-plane/generated/admin-api.d.ts.map +1 -1
  17. package/control-plane/generated/admin-api.js +2 -2
  18. package/control-plane/generated/admin-operations.d.ts +7 -7
  19. package/control-plane/generated/admin-operations.d.ts.map +1 -1
  20. package/control-plane/generated/admin-operations.js +9 -9
  21. package/control-plane/index.d.ts +1 -1
  22. package/control-plane/index.d.ts.map +1 -1
  23. package/control-plane/index.js +1 -1
  24. package/controls/qualification.d.ts.map +1 -1
  25. package/controls/qualification.js +10 -6
  26. package/core/client.d.ts.map +1 -1
  27. package/core/client.js +28 -30
  28. package/core/error-envelope.d.ts +31 -0
  29. package/core/error-envelope.d.ts.map +1 -1
  30. package/core/error-envelope.js +11 -0
  31. package/core/errors.d.ts +15 -3
  32. package/core/errors.d.ts.map +1 -1
  33. package/core/errors.js +254 -2
  34. package/core/geometry-input-sr.d.ts +3 -0
  35. package/core/geometry-input-sr.d.ts.map +1 -0
  36. package/core/geometry-input-sr.js +28 -0
  37. package/core/geoservices.d.ts.map +1 -1
  38. package/core/geoservices.js +33 -6
  39. package/core/grpc-adapter.d.ts.map +1 -1
  40. package/core/grpc-adapter.js +11 -3
  41. package/core/pbf-decoder.d.ts.map +1 -1
  42. package/core/pbf-decoder.js +16 -4
  43. package/core/protocol-transport.d.ts +6 -1
  44. package/core/protocol-transport.d.ts.map +1 -1
  45. package/core/request-pipeline.d.ts +6 -3
  46. package/core/request-pipeline.d.ts.map +1 -1
  47. package/core/request-pipeline.js +28 -11
  48. package/core/spatial-filter.d.ts +4 -4
  49. package/core/spatial-filter.d.ts.map +1 -1
  50. package/core/spatial-filter.js +7 -7
  51. package/core/types.d.ts +14 -3
  52. package/core/types.d.ts.map +1 -1
  53. package/custom-elements.json +341 -0
  54. package/esri-compat/class-breaks-renderer.d.ts +2 -0
  55. package/esri-compat/class-breaks-renderer.d.ts.map +1 -1
  56. package/esri-compat/class-breaks-renderer.js +7 -0
  57. package/esri-compat/controls.d.ts +10 -1
  58. package/esri-compat/controls.d.ts.map +1 -1
  59. package/esri-compat/controls.js +86 -2
  60. package/esri-compat/directions.d.ts +35 -0
  61. package/esri-compat/directions.d.ts.map +1 -1
  62. package/esri-compat/directions.js +153 -2
  63. package/esri-compat/expand.d.ts +1 -0
  64. package/esri-compat/expand.d.ts.map +1 -1
  65. package/esri-compat/expand.js +61 -0
  66. package/esri-compat/feature-layer.d.ts +29 -4
  67. package/esri-compat/feature-layer.d.ts.map +1 -1
  68. package/esri-compat/feature-layer.js +335 -13
  69. package/esri-compat/geometry-engine.d.ts +4 -0
  70. package/esri-compat/geometry-engine.d.ts.map +1 -1
  71. package/esri-compat/geometry-engine.js +8 -1
  72. package/esri-compat/graphic.d.ts +7 -4
  73. package/esri-compat/graphic.d.ts.map +1 -1
  74. package/esri-compat/legend.d.ts +2 -1
  75. package/esri-compat/legend.d.ts.map +1 -1
  76. package/esri-compat/legend.js +15 -0
  77. package/esri-compat/map-view-mount.d.ts +48 -0
  78. package/esri-compat/map-view-mount.d.ts.map +1 -0
  79. package/esri-compat/map-view-mount.js +344 -0
  80. package/esri-compat/map-view.d.ts +38 -6
  81. package/esri-compat/map-view.d.ts.map +1 -1
  82. package/esri-compat/map-view.js +467 -33
  83. package/esri-compat/portal.d.ts +2 -0
  84. package/esri-compat/portal.d.ts.map +1 -1
  85. package/esri-compat/portal.js +7 -2
  86. package/esri-compat/renderer-objects.d.ts +7 -2
  87. package/esri-compat/renderer-objects.d.ts.map +1 -1
  88. package/esri-compat/renderer-objects.js +16 -5
  89. package/esri-compat/route-layer.d.ts +8 -0
  90. package/esri-compat/route-layer.d.ts.map +1 -1
  91. package/esri-compat/route-layer.js +24 -4
  92. package/esri-compat/route-task.d.ts +5 -1
  93. package/esri-compat/route-task.d.ts.map +1 -1
  94. package/esri-compat/route-task.js +119 -7
  95. package/esri-compat/scene-view.d.ts.map +1 -1
  96. package/esri-compat/scene-view.js +1 -0
  97. package/esri-compat/search.d.ts +2 -1
  98. package/esri-compat/search.d.ts.map +1 -1
  99. package/esri-compat/search.js +52 -2
  100. package/esri-compat/unique-value-renderer.d.ts +2 -0
  101. package/esri-compat/unique-value-renderer.d.ts.map +1 -1
  102. package/esri-compat/unique-value-renderer.js +7 -0
  103. package/esri-compat/web-map.d.ts +10 -0
  104. package/esri-compat/web-map.d.ts.map +1 -1
  105. package/esri-compat/web-map.js +102 -0
  106. package/geocoding/index.d.ts +1 -0
  107. package/geocoding/index.d.ts.map +1 -1
  108. package/geocoding/index.js +18 -8
  109. package/geocoding/provider-http.d.ts.map +1 -1
  110. package/geocoding/provider-http.js +3 -1
  111. package/map/webmap-maplibre.d.ts +2 -1
  112. package/map/webmap-maplibre.d.ts.map +1 -1
  113. package/map/webmap-maplibre.js +3 -0
  114. package/package.json +6 -4
  115. package/query-planner/geoservices.d.ts.map +1 -1
  116. package/query-planner/geoservices.js +2 -0
  117. package/query-planner/types.d.ts +2 -0
  118. package/query-planner/types.d.ts.map +1 -1
  119. package/realtime/honua-server.d.ts +4 -0
  120. package/realtime/honua-server.d.ts.map +1 -1
  121. package/realtime/honua-server.js +10 -0
  122. package/realtime/resumable.js +9 -0
  123. package/realtime/types.d.ts +8 -0
  124. package/realtime/types.d.ts.map +1 -1
  125. package/scene-workspace/index.d.ts +2 -2
  126. package/scene-workspace/index.d.ts.map +1 -1
  127. package/scene-workspace/index.js +1 -1
  128. package/scene-workspace/maplibre-state-sync.d.ts.map +1 -1
  129. package/scene-workspace/maplibre-state-sync.js +35 -3
  130. package/scene-workspace/primitives.d.ts +37 -5
  131. package/scene-workspace/primitives.d.ts.map +1 -1
  132. package/scene-workspace/primitives.js +46 -12
  133. package/scene-workspace/state-sync-port-kit.d.ts +1 -1
  134. package/scene-workspace/state-sync-port-kit.d.ts.map +1 -1
  135. package/studio/capability-manifest.d.ts +10 -0
  136. package/studio/capability-manifest.d.ts.map +1 -1
  137. package/studio/capability-manifest.js +38 -0
  138. package/studio/command-adapter.d.ts +35 -0
  139. package/studio/command-adapter.d.ts.map +1 -0
  140. package/studio/command-adapter.js +36 -0
  141. package/studio/generated/studio-api.d.ts +1062 -0
  142. package/studio/generated/studio-api.d.ts.map +1 -0
  143. package/studio/generated/studio-api.js +4 -0
  144. package/studio/index.d.ts +8 -6
  145. package/studio/index.d.ts.map +1 -1
  146. package/studio/index.js +6 -5
  147. package/studio/lifecycle-client.d.ts +3 -3
  148. package/studio/lifecycle-client.d.ts.map +1 -1
  149. package/studio/lifecycle-client.js +41 -22
  150. package/studio/lifecycle-types.d.ts +56 -77
  151. package/studio/lifecycle-types.d.ts.map +1 -1
  152. package/studio/lifecycle-types.js +5 -12
  153. package/studio/types.d.ts +37 -7
  154. package/studio/types.d.ts.map +1 -1
  155. package/studio/types.js +5 -3
  156. package/studio/validate.d.ts.map +1 -1
  157. package/studio/validate.js +104 -7
  158. package/style/renderers.d.ts +6 -1
  159. package/style/renderers.d.ts.map +1 -1
  160. package/style/renderers.js +11 -6
  161. package/style/visual-variables.d.ts +43 -0
  162. package/style/visual-variables.d.ts.map +1 -0
  163. package/style/visual-variables.js +183 -0
  164. package/web-components/index.d.ts +2 -1
  165. package/web-components/index.d.ts.map +1 -1
  166. package/web-components/index.js +1 -0
  167. package/web-components/map-pointer-claim.d.ts +24 -0
  168. package/web-components/map-pointer-claim.d.ts.map +1 -0
  169. package/web-components/map-pointer-claim.js +40 -0
  170. package/web-components/maplibre-renderer.d.ts.map +1 -1
  171. package/web-components/maplibre-renderer.js +5 -1
  172. package/web-components/measurement-units.d.ts +88 -0
  173. package/web-components/measurement-units.d.ts.map +1 -0
  174. package/web-components/measurement-units.js +278 -0
  175. package/web-components/measurement.d.ts +75 -4
  176. package/web-components/measurement.d.ts.map +1 -1
  177. package/web-components/measurement.js +227 -28
  178. package/web-components/types.d.ts +58 -3
  179. package/web-components/types.d.ts.map +1 -1
  180. package/webmap/convert-layer.d.ts +2 -1
  181. package/webmap/convert-layer.d.ts.map +1 -1
  182. package/webmap/convert-layer.js +20 -3
  183. package/webmap/convert-renderer.d.ts +10 -3
  184. package/webmap/convert-renderer.d.ts.map +1 -1
  185. package/webmap/convert-renderer.js +190 -36
  186. package/webmap/index.d.ts +1 -0
  187. package/webmap/index.d.ts.map +1 -1
  188. package/webmap/parse.d.ts +2 -1
  189. package/webmap/parse.d.ts.map +1 -1
  190. package/webmap/parse.js +1 -1
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Unit conversion, display formatting, and planar (Euclidean, flat-earth)
3
+ * math for `<honua-measurement>` (issue #1419).
4
+ *
5
+ * All conversion and formatting here operates on the canonical SI value
6
+ * already stored on `HonuaMeasureResult` (meters / square meters) — never on
7
+ * a previously rounded display string — so switching `unit`/`areaUnit`/
8
+ * `precision` at runtime always reformats the same full-precision number.
9
+ *
10
+ * `planarLength` / `planarArea` intentionally do not depend on `proj4`
11
+ * (`@honua/geometry`'s `project`): pulling that in would add proj4 as a
12
+ * static import of every `<honua-measurement>` consumer's bundle (the
13
+ * `/web-components` and `/controls` entrypoints), well past their gzip
14
+ * budgets, for a fidelity mode most apps never enable. Instead this uses the
15
+ * same equirectangular (meters-per-degree-of-latitude/longitude) flat-earth
16
+ * approximation `MeasurementCompat` already ships in `src/esri-compat/
17
+ * measurement.ts` — accurate for the local-extent sketches this widget draws,
18
+ * and proven parity math rather than a new approach.
19
+ *
20
+ * @module
21
+ */
22
+ const METERS_PER_DISTANCE_UNIT = {
23
+ meters: 1,
24
+ kilometers: 1000,
25
+ feet: 0.3048,
26
+ yards: 0.9144,
27
+ miles: 1609.344,
28
+ nauticalmiles: 1852,
29
+ };
30
+ const SQUARE_METERS_PER_AREA_UNIT = {
31
+ "square-meters": 1,
32
+ hectares: 10_000,
33
+ "square-kilometers": 1_000_000,
34
+ "square-feet": 0.09290304,
35
+ acres: 4046.8564224,
36
+ "square-miles": 2_589_988.110336,
37
+ };
38
+ const DISTANCE_UNIT_SUFFIX = {
39
+ meters: "m",
40
+ kilometers: "km",
41
+ feet: "ft",
42
+ yards: "yd",
43
+ miles: "mi",
44
+ nauticalmiles: "nmi",
45
+ };
46
+ const AREA_UNIT_SUFFIX = {
47
+ "square-meters": "m²",
48
+ hectares: "ha",
49
+ "square-kilometers": "km²",
50
+ "square-feet": "ft²",
51
+ acres: "ac",
52
+ "square-miles": "mi²",
53
+ };
54
+ /** Converts a distance already in meters into `unit`. */
55
+ export function convertDistance(meters, unit) {
56
+ return meters / METERS_PER_DISTANCE_UNIT[unit];
57
+ }
58
+ /** Converts an area already in square meters into `unit`. */
59
+ export function convertArea(squareMeters, unit) {
60
+ return squareMeters / SQUARE_METERS_PER_AREA_UNIT[unit];
61
+ }
62
+ /** Resolves `"auto"` to a concrete unit given the magnitude, matching the pre-#1419 auto-scaling. */
63
+ function resolveDistanceUnit(meters, unit) {
64
+ if (unit !== "auto")
65
+ return unit;
66
+ return meters >= 1000 ? "kilometers" : "meters";
67
+ }
68
+ /** Resolves `"auto"` to a concrete unit given the magnitude, matching the pre-#1419 auto-scaling. */
69
+ function resolveAreaUnit(squareMeters, unit) {
70
+ if (unit !== "auto")
71
+ return unit;
72
+ if (squareMeters >= 1_000_000)
73
+ return "square-kilometers";
74
+ if (squareMeters >= 10_000)
75
+ return "hectares";
76
+ return "square-meters";
77
+ }
78
+ /** Default decimal digits per resolved unit, matching the pre-#1419 formatting. */
79
+ function defaultDistancePrecision(unit) {
80
+ return unit === "meters" ? 1 : 2;
81
+ }
82
+ /** Default decimal digits per resolved unit, matching the pre-#1419 formatting. */
83
+ function defaultAreaPrecision(unit) {
84
+ return unit === "square-meters" ? 1 : 2;
85
+ }
86
+ /**
87
+ * Formats a canonical meters value for display. `precision` overrides the
88
+ * unit's default decimal digits; `unit` overrides magnitude-based auto-scaling.
89
+ */
90
+ export function formatDistanceValue(meters, unit, precision) {
91
+ const resolved = resolveDistanceUnit(meters, unit);
92
+ const value = convertDistance(meters, resolved);
93
+ const digits = precision ?? defaultDistancePrecision(resolved);
94
+ return `${value.toFixed(digits)} ${DISTANCE_UNIT_SUFFIX[resolved]}`;
95
+ }
96
+ /**
97
+ * Formats a canonical square-meters value for display. `precision` overrides
98
+ * the unit's default decimal digits; `unit` overrides magnitude-based
99
+ * auto-scaling.
100
+ */
101
+ export function formatAreaValue(squareMeters, unit, precision) {
102
+ const resolved = resolveAreaUnit(squareMeters, unit);
103
+ const value = convertArea(squareMeters, resolved);
104
+ const digits = precision ?? defaultAreaPrecision(resolved);
105
+ return `${value.toFixed(digits)} ${AREA_UNIT_SUFFIX[resolved]}`;
106
+ }
107
+ /** Distance units `<honua-measurement>` accepts, including `"auto"`. */
108
+ export const HONUA_MEASURE_DISTANCE_UNITS = [
109
+ "auto",
110
+ ...Object.keys(METERS_PER_DISTANCE_UNIT),
111
+ ];
112
+ /** Area units `<honua-measurement>` accepts, including `"auto"`. */
113
+ export const HONUA_MEASURE_AREA_UNITS = [
114
+ "auto",
115
+ ...Object.keys(SQUARE_METERS_PER_AREA_UNIT),
116
+ ];
117
+ /** Planar frames `<honua-measurement>` accepts for `fidelity: "planar"`. */
118
+ export const HONUA_MEASURE_PLANAR_CRS = ["local", "EPSG:3857"];
119
+ /** Meters per degree of latitude (WGS84, constant to within centimeters at any latitude). */
120
+ const METERS_PER_DEGREE_LATITUDE = 111_132.92;
121
+ /** Semi-major axis EPSG:3857 (spherical Web Mercator) projects onto. */
122
+ const WEB_MERCATOR_RADIUS = 6_378_137;
123
+ /** Latitude beyond which EPSG:3857 is undefined (the square-world clamp). */
124
+ const WEB_MERCATOR_MAX_LATITUDE = 85.051_128_779_806_59;
125
+ /** Meters per degree of longitude at WGS84 latitude `latDeg`. */
126
+ function metersPerDegreeLongitude(latDeg) {
127
+ return 111_412.84 * Math.cos(toRadians(latDeg));
128
+ }
129
+ function toRadians(degrees) {
130
+ return (degrees * Math.PI) / 180;
131
+ }
132
+ function meanLatitude(positions) {
133
+ return positions.reduce((sum, [, lat]) => sum + lat, 0) / positions.length;
134
+ }
135
+ /**
136
+ * Whether a position is a usable WGS84 vertex: finite, with latitude inside
137
+ * `[-90, 90]`. Longitude may exceed ±180 — MapLibre reports clicks on a world
138
+ * copy that way — and is unwrapped before any planar math.
139
+ */
140
+ export function isValidMeasureVertex(position) {
141
+ const [lng, lat] = position;
142
+ return (typeof lng === "number" &&
143
+ typeof lat === "number" &&
144
+ Number.isFinite(lng) &&
145
+ Number.isFinite(lat) &&
146
+ lat >= -90 &&
147
+ lat <= 90);
148
+ }
149
+ /**
150
+ * Shifts each longitude by whole turns so consecutive vertices are never more
151
+ * than 180° apart. A sketch crossing the antimeridian (179° → -179°) is then
152
+ * measured the short way, matching what the geodesic ops already do, instead
153
+ * of across 358° of flat map.
154
+ */
155
+ export function unwrapLongitudes(positions) {
156
+ const unwrapped = [];
157
+ for (const [lng, lat] of positions) {
158
+ const previous = unwrapped[unwrapped.length - 1];
159
+ if (!previous) {
160
+ unwrapped.push([lng, lat]);
161
+ continue;
162
+ }
163
+ const turns = Math.round((lng - previous[0]) / 360);
164
+ unwrapped.push([lng - turns * 360, lat]);
165
+ }
166
+ return unwrapped;
167
+ }
168
+ /** Projects unwrapped lng/lat into the planar frame's meters. */
169
+ function projector(positions, crs) {
170
+ if (crs === "EPSG:3857") {
171
+ return ([lng, lat]) => {
172
+ const clamped = Math.max(-WEB_MERCATOR_MAX_LATITUDE, Math.min(WEB_MERCATOR_MAX_LATITUDE, lat));
173
+ return [
174
+ WEB_MERCATOR_RADIUS * toRadians(lng),
175
+ WEB_MERCATOR_RADIUS * Math.log(Math.tan(Math.PI / 4 + toRadians(clamped) / 2)),
176
+ ];
177
+ };
178
+ }
179
+ const metersPerDegLon = metersPerDegreeLongitude(meanLatitude(positions));
180
+ return ([lng, lat]) => [lng * metersPerDegLon, lat * METERS_PER_DEGREE_LATITUDE];
181
+ }
182
+ /**
183
+ * Euclidean length of a line, in meters of the planar frame `crs`:
184
+ *
185
+ * - `"local"` (default): a flat-earth approximation centered on the vertices'
186
+ * mean latitude, matching `MeasurementCompat`'s approximation.
187
+ * - `"EPSG:3857"`: spherical Web Mercator, the projected CRS MapLibre renders
188
+ * in. Its meters are not scale-corrected, so lengths grow by `sec(latitude)`
189
+ * away from the equator — which is what an app mirroring ArcGIS planar
190
+ * measurement on a Web Mercator view expects.
191
+ *
192
+ * Unlike the geodesic `length` op in `@honua/geometry`, this never follows
193
+ * the great circle. Longitudes are unwrapped first, so an antimeridian
194
+ * crossing is measured the short way.
195
+ */
196
+ export function planarLength(positions, crs = "local") {
197
+ if (positions.length < 2)
198
+ return 0;
199
+ const unwrapped = unwrapLongitudes(positions);
200
+ const project = projector(unwrapped, crs);
201
+ let total = 0;
202
+ for (let index = 1; index < unwrapped.length; index += 1) {
203
+ const [x0, y0] = project(unwrapped[index - 1]);
204
+ const [x1, y1] = project(unwrapped[index]);
205
+ total += Math.hypot(x1 - x0, y1 - y0);
206
+ }
207
+ return total;
208
+ }
209
+ /**
210
+ * Euclidean (shoelace) area of a ring, in square meters of the planar frame
211
+ * `crs` (see {@link planarLength}). `positions` need not be closed; the first
212
+ * vertex is implicitly repeated to close the ring.
213
+ */
214
+ export function planarArea(positions, crs = "local") {
215
+ if (positions.length < 3)
216
+ return 0;
217
+ const unwrapped = unwrapLongitudes(positions);
218
+ const project = projector(unwrapped, crs);
219
+ const closed = [...unwrapped, unwrapped[0]].map(project);
220
+ let sum = 0;
221
+ for (let index = 1; index < closed.length; index += 1) {
222
+ const [x0, y0] = closed[index - 1];
223
+ const [x1, y1] = closed[index];
224
+ sum += x0 * y1 - x1 * y0;
225
+ }
226
+ return Math.abs(sum) / 2;
227
+ }
228
+ /**
229
+ * Whether the closed ring through `positions` crosses itself (a "bow tie").
230
+ * Such a ring has no single enclosed area: the shoelace and geodesic sums
231
+ * cancel the lobes against each other, so reporting their result would be a
232
+ * confident wrong number. Touching at a shared vertex of adjacent edges is
233
+ * not a crossing; collinear overlap of non-adjacent edges is.
234
+ */
235
+ export function ringSelfIntersects(positions) {
236
+ const ring = unwrapLongitudes(positions);
237
+ const count = ring.length;
238
+ if (count < 4)
239
+ return false;
240
+ for (let first = 0; first < count; first += 1) {
241
+ const a = ring[first];
242
+ const b = ring[(first + 1) % count];
243
+ for (let second = first + 1; second < count; second += 1) {
244
+ // Skip the edge itself and the two edges that share a vertex with it.
245
+ if (second === first || (second + 1) % count === first || (first + 1) % count === second)
246
+ continue;
247
+ const c = ring[second];
248
+ const d = ring[(second + 1) % count];
249
+ if (segmentsIntersect(a, b, c, d))
250
+ return true;
251
+ }
252
+ }
253
+ return false;
254
+ }
255
+ function orientation(p, q, r) {
256
+ const value = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
257
+ if (Math.abs(value) < 1e-12)
258
+ return 0;
259
+ return value > 0 ? 1 : 2;
260
+ }
261
+ function onSegment(p, q, r) {
262
+ return (q[0] <= Math.max(p[0], r[0]) &&
263
+ q[0] >= Math.min(p[0], r[0]) &&
264
+ q[1] <= Math.max(p[1], r[1]) &&
265
+ q[1] >= Math.min(p[1], r[1]));
266
+ }
267
+ function segmentsIntersect(a, b, c, d) {
268
+ const o1 = orientation(a, b, c);
269
+ const o2 = orientation(a, b, d);
270
+ const o3 = orientation(c, d, a);
271
+ const o4 = orientation(c, d, b);
272
+ if (o1 !== o2 && o3 !== o4)
273
+ return true;
274
+ return ((o1 === 0 && onSegment(a, c, b)) ||
275
+ (o2 === 0 && onSegment(a, d, b)) ||
276
+ (o3 === 0 && onSegment(c, a, d)) ||
277
+ (o4 === 0 && onSegment(c, b, d)));
278
+ }
@@ -11,6 +11,15 @@
11
11
  * suspended while a mode is active when the map exposes the handle);
12
12
  * - **Escape** (or the Cancel button) discards the in-progress sketch.
13
13
  *
14
+ * Touch input needs nothing extra: MapLibre reports a tap as `click`, and the
15
+ * Finish button stands in for double-tap (which MapLibre does not report as
16
+ * `dblclick`).
17
+ *
18
+ * While a mode is active the element claims the map pointer
19
+ * (`./map-pointer-claim.js`), so a vertex click that lands on a feature does
20
+ * not also rewrite the shared selection `<honua-map>` feeds to tables,
21
+ * inspectors, and editors.
22
+ *
14
23
  * Distance and area are computed with the geodesic ops from the public
15
24
  * `@honua/geometry` surface (`length` / `area`), so the widget's numbers match
16
25
  * `geometryEngine` parity math everywhere else in the SDK.
@@ -25,6 +34,12 @@
25
34
  * in-progress sketch renders as a line + fill overlay in a
26
35
  * `honua-measurement` GeoJSON source; on plain stubs the overlay is skipped.
27
36
  *
37
+ * ## Units, precision, fidelity, CRS
38
+ * `unit`, `areaUnit`, `precision`, `fidelity`, and `planarCrs` are
39
+ * properties, also settable declaratively as the `unit`, `area-unit`,
40
+ * `precision`, `fidelity`, and `planar-crs` attributes. Unknown values fall
41
+ * back to the default rather than producing a malformed display.
42
+ *
28
43
  * ## Accessibility
29
44
  * Mode buttons are a `role="group"` of toggle buttons with `aria-pressed`;
30
45
  * the live result is announced through a `role="status"` region; Finish /
@@ -33,14 +48,66 @@
33
48
  *
34
49
  * @module
35
50
  */
36
- import type { HonuaMeasureMode, HonuaMeasureResult, HonuaMeasurementMap, HonuaMeasurementMessages } from "./types.js";
51
+ import type { HonuaMeasureAreaUnit, HonuaMeasureDistanceUnit, HonuaMeasureFidelity, HonuaMeasureMode, HonuaMeasurePlanarCrs, HonuaMeasureResult, HonuaMeasurementMap, HonuaMeasurementMessages } from "./types.js";
37
52
  declare const HTMLElementBase: typeof HTMLElement;
38
53
  type LngLat = readonly [number, number];
54
+ /**
55
+ * Distance and area measurement drawn directly on a MapLibre map.
56
+ *
57
+ * @attr {string} for - `id` of the `<honua-map>` (or any element exposing `.map`) to measure on.
58
+ * @attr {string} label - Heading and accessible name of the panel; `messages.label` wins when set.
59
+ * @fires {CustomEvent<HonuaMeasureChangeDetail>} honua-measure-change - A mode, vertex, result, fidelity, or planar CRS change. Bubbles and is composed.
60
+ * @csspart panel - The measurement panel.
61
+ * @csspart mode - Each mode toggle button.
62
+ * @csspart value - The live result readout (`role="status"`).
63
+ * @csspart finish - The Finish button.
64
+ * @csspart cancel - The Cancel button.
65
+ */
39
66
  export declare class HonuaMeasurementElement extends HTMLElementBase {
40
67
  #private;
41
68
  static get observedAttributes(): string[];
69
+ /** Caller-supplied labels, statuses, and ARIA text; unset entries keep the English defaults. */
42
70
  get messages(): HonuaMeasurementMessages;
43
71
  set messages(messages: HonuaMeasurementMessages | undefined);
72
+ /**
73
+ * Displayed distance unit. `"auto"` (default) keeps the metric auto-scaling
74
+ * behavior. Changing this reformats the existing full-precision result — it
75
+ * never recomputes from a rounded display value.
76
+ */
77
+ get unit(): HonuaMeasureDistanceUnit;
78
+ set unit(unit: HonuaMeasureDistanceUnit | undefined);
79
+ /**
80
+ * Displayed area unit. `"auto"` (default) keeps the metric auto-scaling
81
+ * behavior. Changing this reformats the existing full-precision result — it
82
+ * never recomputes from a rounded display value.
83
+ */
84
+ get areaUnit(): HonuaMeasureAreaUnit;
85
+ set areaUnit(unit: HonuaMeasureAreaUnit | undefined);
86
+ /** Decimal digits for the displayed value. `undefined` (default) uses a per-unit default. */
87
+ get precision(): number | undefined;
88
+ set precision(precision: number | undefined);
89
+ /**
90
+ * Which math computes `result.distance` / `result.area`: `"geodesic"`
91
+ * (default, great-circle over WGS84) or `"planar"` (Euclidean, in the
92
+ * {@link planarCrs} frame — see `./measurement-units.js`). Changing this
93
+ * recomputes from the drawn vertices, since it changes which math produces
94
+ * the canonical value.
95
+ */
96
+ get fidelity(): HonuaMeasureFidelity;
97
+ set fidelity(fidelity: HonuaMeasureFidelity | undefined);
98
+ /**
99
+ * Planar frame used when {@link fidelity} is `"planar"`: `"local"` (default,
100
+ * flat-earth meters around the sketch) or `"EPSG:3857"` (Web Mercator
101
+ * meters, not scale-corrected). Recomputes like {@link fidelity} does.
102
+ */
103
+ get planarCrs(): HonuaMeasurePlanarCrs;
104
+ set planarCrs(crs: HonuaMeasurePlanarCrs | undefined);
105
+ /**
106
+ * CRS vertices are recorded in. Always WGS84 (`"EPSG:4326"`): vertices come
107
+ * from map click events, which report geographic lng/lat regardless of the
108
+ * map's own projection. Exposed so a consumer never has to assume it.
109
+ */
110
+ get crs(): "EPSG:4326";
44
111
  /** The MapLibre map this widget draws on. */
45
112
  get map(): HonuaMeasurementMap | undefined;
46
113
  set map(map: HonuaMeasurementMap | undefined);
@@ -54,13 +121,17 @@ export declare class HonuaMeasurementElement extends HTMLElementBase {
54
121
  get vertices(): readonly LngLat[];
55
122
  /** Activates a measure mode; `"off"` cancels any in-progress sketch. */
56
123
  setMode(mode: HonuaMeasureMode): void;
57
- /** Adds a vertex programmatically (same as a map click). */
58
- addVertex(lngLat: LngLat): void;
124
+ /**
125
+ * Adds a vertex programmatically (same as a map click). Returns `false`,
126
+ * changing nothing, when no mode is active or the position is not a usable
127
+ * WGS84 vertex (non-finite, or latitude outside `[-90, 90]`).
128
+ */
129
+ addVertex(lngLat: LngLat): boolean;
59
130
  /** Finishes the in-progress sketch (same as double-click). */
60
131
  finish(): void;
61
132
  /** Cancels the in-progress sketch (same as Escape); the mode stays active. */
62
133
  cancel(): void;
63
- attributeChangedCallback(name: string): void;
134
+ attributeChangedCallback(name: string, _previous?: string | null, value?: string | null): void;
64
135
  connectedCallback(): void;
65
136
  disconnectedCallback(): void;
66
137
  protected render(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"measurement.d.ts","sourceRoot":"","sources":["../../../src/web-components/measurement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAEV,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAQpB,QAAA,MAAM,eAAe,EAAE,OAAO,WAAkF,CAAC;AAMjH,KAAK,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAExC,qBAAa,uBAAwB,SAAQ,eAAe;;IAC1D,WAAkB,kBAAkB,IAAI,MAAM,EAAE,CAE/C;IASD,IAAW,QAAQ,IAAI,wBAAwB,CAE9C;IACD,IAAW,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,GAAG,SAAS,EAGjE;IAOD,6CAA6C;IAC7C,IAAW,GAAG,IAAI,mBAAmB,GAAG,SAAS,CAEhD;IAED,IAAW,GAAG,CAAC,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAMlD;IAED,wEAAwE;IACjE,OAAO,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI;IAI9C,+BAA+B;IAC/B,IAAW,IAAI,IAAI,gBAAgB,CAElC;IAED,yDAAyD;IACzD,IAAW,MAAM,IAAI,kBAAkB,GAAG,SAAS,CAElD;IAED,4DAA4D;IAC5D,IAAW,QAAQ,IAAI,SAAS,MAAM,EAAE,CAEvC;IAED,wEAAwE;IACjE,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAY5C,4DAA4D;IACrD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAatC,8DAA8D;IACvD,MAAM,IAAI,IAAI;IASrB,8EAA8E;IACvE,MAAM,IAAI,IAAI;IAUd,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQ5C,iBAAiB,IAAI,IAAI;IAQzB,oBAAoB,IAAI,IAAI;IAsMnC,SAAS,CAAC,MAAM,IAAI,IAAI;CAwGzB;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,QAAQ,wBAA2B,GAAG,IAAI,CAKhF"}
1
+ {"version":3,"file":"measurement.d.ts","sourceRoot":"","sources":["../../../src/web-components/measurement.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAgBH,OAAO,KAAK,EACV,oBAAoB,EAEpB,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,wBAAwB,EACzB,MAAM,YAAY,CAAC;AAQpB,QAAA,MAAM,eAAe,EAAE,OAAO,WAAkF,CAAC;AAMjH,KAAK,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAIxC;;;;;;;;;;;GAWG;AACH,qBAAa,uBAAwB,SAAQ,eAAe;;IAC1D,WAAkB,kBAAkB,IAAI,MAAM,EAAE,CAE/C;IAcD,gGAAgG;IAChG,IAAW,QAAQ,IAAI,wBAAwB,CAE9C;IACD,IAAW,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,GAAG,SAAS,EAGjE;IAED;;;;OAIG;IACH,IAAW,IAAI,IAAI,wBAAwB,CAE1C;IACD,IAAW,IAAI,CAAC,IAAI,EAAE,wBAAwB,GAAG,SAAS,EAGzD;IAED;;;;OAIG;IACH,IAAW,QAAQ,IAAI,oBAAoB,CAE1C;IACD,IAAW,QAAQ,CAAC,IAAI,EAAE,oBAAoB,GAAG,SAAS,EAGzD;IAED,6FAA6F;IAC7F,IAAW,SAAS,IAAI,MAAM,GAAG,SAAS,CAEzC;IACD,IAAW,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAQjD;IAED;;;;;;OAMG;IACH,IAAW,QAAQ,IAAI,oBAAoB,CAE1C;IACD,IAAW,QAAQ,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,EAO7D;IAED;;;;OAIG;IACH,IAAW,SAAS,IAAI,qBAAqB,CAE5C;IACD,IAAW,SAAS,CAAC,GAAG,EAAE,qBAAqB,GAAG,SAAS,EAQ1D;IAED;;;;OAIG;IACH,IAAW,GAAG,IAAI,WAAW,CAE5B;IAUD,6CAA6C;IAC7C,IAAW,GAAG,IAAI,mBAAmB,GAAG,SAAS,CAEhD;IAED,IAAW,GAAG,CAAC,GAAG,EAAE,mBAAmB,GAAG,SAAS,EAMlD;IAED,wEAAwE;IACjE,OAAO,CAAC,GAAG,EAAE,mBAAmB,GAAG,IAAI;IAI9C,+BAA+B;IAC/B,IAAW,IAAI,IAAI,gBAAgB,CAElC;IAED,yDAAyD;IACzD,IAAW,MAAM,IAAI,kBAAkB,GAAG,SAAS,CAElD;IAED,4DAA4D;IAC5D,IAAW,QAAQ,IAAI,SAAS,MAAM,EAAE,CAEvC;IAED,wEAAwE;IACjE,OAAO,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI;IAY5C;;;;OAIG;IACI,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAczC,8DAA8D;IACvD,MAAM,IAAI,IAAI;IASrB,8EAA8E;IACvE,MAAM,IAAI,IAAI;IAUd,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IA2B9F,iBAAiB,IAAI,IAAI;IAczB,oBAAoB,IAAI,IAAI;IA+OnC,SAAS,CAAC,MAAM,IAAI,IAAI;CA2GzB;AAED,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,QAAQ,wBAA2B,GAAG,IAAI,CAKhF"}