@oicl/openbridge-webcomponents 2.0.0-next.161 → 2.0.0-next.163

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 (33) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +439 -327
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +96 -29
  4. package/dist/components/keyboard-numeric/keyboard-numeric.css.js +2 -3
  5. package/dist/components/keyboard-numeric/keyboard-numeric.css.js.map +1 -1
  6. package/dist/navigation-instruments/compass-sector/compass-sector.css.js +20 -11
  7. package/dist/navigation-instruments/compass-sector/compass-sector.css.js.map +1 -1
  8. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts +18 -17
  9. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
  10. package/dist/navigation-instruments/compass-sector/compass-sector.js +85 -52
  11. package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
  12. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js +2 -6
  13. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -1
  14. package/dist/navigation-instruments/rudder/rudder.css.js +40 -0
  15. package/dist/navigation-instruments/rudder/rudder.css.js.map +1 -0
  16. package/dist/navigation-instruments/rudder/rudder.d.ts +9 -0
  17. package/dist/navigation-instruments/rudder/rudder.d.ts.map +1 -1
  18. package/dist/navigation-instruments/rudder/rudder.js +40 -23
  19. package/dist/navigation-instruments/rudder/rudder.js.map +1 -1
  20. package/dist/navigation-instruments/watch/watch.css.js +6 -0
  21. package/dist/navigation-instruments/watch/watch.css.js.map +1 -1
  22. package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
  23. package/dist/navigation-instruments/watch/watch.js +11 -1
  24. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  25. package/dist/svghelpers/arc-frame.d.ts +8 -0
  26. package/dist/svghelpers/arc-frame.d.ts.map +1 -1
  27. package/dist/svghelpers/arc-frame.js +16 -6
  28. package/dist/svghelpers/arc-frame.js.map +1 -1
  29. package/dist/svghelpers/radial-frame.d.ts +14 -1
  30. package/dist/svghelpers/radial-frame.d.ts.map +1 -1
  31. package/dist/svghelpers/radial-frame.js +3 -1
  32. package/dist/svghelpers/radial-frame.js.map +1 -1
  33. package/package.json +1 -1
@@ -93140,56 +93140,54 @@
93140
93140
  },
93141
93141
  {
93142
93142
  "kind": "field",
93143
- "name": "_radiusOffset",
93143
+ "name": "_cachedAreas",
93144
93144
  "type": {
93145
- "text": "number"
93145
+ "text": "WatchArea[]"
93146
93146
  },
93147
93147
  "privacy": "private",
93148
- "default": "0"
93148
+ "default": "[]"
93149
93149
  },
93150
93150
  {
93151
93151
  "kind": "field",
93152
- "name": "_cachedViewBox",
93152
+ "name": "_cachedTickmarks",
93153
93153
  "type": {
93154
- "text": "string"
93154
+ "text": "Tickmark[]"
93155
93155
  },
93156
93156
  "privacy": "private",
93157
- "default": "''"
93157
+ "default": "[]"
93158
93158
  },
93159
93159
  {
93160
93160
  "kind": "field",
93161
- "name": "_cachedArcFrame",
93161
+ "name": "_cachedAdvices",
93162
93162
  "type": {
93163
- "text": "ZoomToFitArcFrame | undefined"
93163
+ "text": "AngleAdviceRaw[]"
93164
93164
  },
93165
- "privacy": "private"
93165
+ "privacy": "private",
93166
+ "default": "[]"
93166
93167
  },
93167
93168
  {
93168
93169
  "kind": "field",
93169
- "name": "_cachedAreas",
93170
- "type": {
93171
- "text": "WatchArea[]"
93172
- },
93170
+ "name": "_resizeController",
93173
93171
  "privacy": "private",
93174
- "default": "[]"
93172
+ "default": "new ResizeController(this, {})"
93175
93173
  },
93176
93174
  {
93177
93175
  "kind": "field",
93178
- "name": "_cachedTickmarks",
93176
+ "name": "_aspectWidth",
93179
93177
  "type": {
93180
- "text": "Tickmark[]"
93178
+ "text": "number"
93181
93179
  },
93182
93180
  "privacy": "private",
93183
- "default": "[]"
93181
+ "default": "448"
93184
93182
  },
93185
93183
  {
93186
93184
  "kind": "field",
93187
- "name": "_cachedAdvices",
93185
+ "name": "_aspectHeight",
93188
93186
  "type": {
93189
- "text": "AngleAdviceRaw[]"
93187
+ "text": "number"
93190
93188
  },
93191
93189
  "privacy": "private",
93192
- "default": "[]"
93190
+ "default": "217.28"
93193
93191
  },
93194
93192
  {
93195
93193
  "kind": "method",
@@ -93221,13 +93219,25 @@
93221
93219
  },
93222
93220
  {
93223
93221
  "kind": "method",
93224
- "name": "_computeViewBox",
93222
+ "name": "_clipBottom",
93225
93223
  "privacy": "private",
93226
93224
  "return": {
93227
93225
  "type": {
93228
- "text": "void"
93226
+ "text": "number"
93229
93227
  }
93230
- }
93228
+ },
93229
+ "description": "Deepest crop the active features need, so none of them is shaved."
93230
+ },
93231
+ {
93232
+ "kind": "method",
93233
+ "name": "_buildFrame",
93234
+ "privacy": "private",
93235
+ "return": {
93236
+ "type": {
93237
+ "text": "RadialFrame"
93238
+ }
93239
+ },
93240
+ "description": "One frame per render, feeding both layers: the shared sector box cropped\nto the arc. Zoom enlarges the arc rather than the window, so the window\nonly slides outward by the radius offset and the canvas holds still."
93231
93241
  },
93232
93242
  {
93233
93243
  "kind": "method",
@@ -93319,14 +93329,23 @@
93319
93329
  ]
93320
93330
  },
93321
93331
  {
93322
- "kind": "field",
93332
+ "kind": "method",
93323
93333
  "name": "_readoutTopPercent",
93324
- "type": {
93325
- "text": "number"
93326
- },
93327
93334
  "privacy": "private",
93328
- "description": "Vertical placement of the readout as a percentage of the host height.\n\nWith `zoomToFitArc` the arc is reframed by `computeZoomToFitArcFrame`, whose\n`radiusOffset`/`viewBox` depend on the arc's *absolute* orientation (which\ncardinal axes its bounding box crosses), not just its bend. The arc itself\nis always rotated back to the top, so it stays put on screen — but a\nframe-derived offset would swing wildly as `heading` rotates the bbox around\nthe circle. So in zoom we use a fixed offset, which keeps the readout steady\nunder the (stationary) arc regardless of heading.\n\nWithout zoom the viewBox is the fixed, origin-symmetric 120° framing, so the\ngeometry is orientation-independent: place the readout halfway down the inner\nradius from the watch center toward the arc's inner edge.",
93329
- "readonly": true
93335
+ "return": {
93336
+ "type": {
93337
+ "text": "number"
93338
+ }
93339
+ },
93340
+ "parameters": [
93341
+ {
93342
+ "name": "frame",
93343
+ "type": {
93344
+ "text": "RadialFrame"
93345
+ }
93346
+ }
93347
+ ],
93348
+ "description": "Vertical placement of the readout as a percentage of the frame height.\n\nThe anchor sits halfway down the inner radius, below the arc's inner edge.\nZoom pushes that edge out by the radius offset, so the anchor follows it\nand the gap under the arc reads the same in both modes."
93330
93349
  }
93331
93350
  ],
93332
93351
  "attributes": [
@@ -115568,6 +115587,54 @@
115568
115587
  "privacy": "private",
115569
115588
  "default": "new ResizeController(this, {})"
115570
115589
  },
115590
+ {
115591
+ "kind": "field",
115592
+ "name": "NEEDLE_INNER_RADIUS",
115593
+ "type": {
115594
+ "text": "number"
115595
+ },
115596
+ "privacy": "private",
115597
+ "static": true,
115598
+ "readonly": true,
115599
+ "default": "-16.5",
115600
+ "description": "Radial reach of the needle path about the watch centre, and its half\nwidth — the zoomed arc's own box stops short of the inner end."
115601
+ },
115602
+ {
115603
+ "kind": "field",
115604
+ "name": "NEEDLE_OUTER_RADIUS",
115605
+ "type": {
115606
+ "text": "number"
115607
+ },
115608
+ "privacy": "private",
115609
+ "static": true,
115610
+ "readonly": true,
115611
+ "default": "160.65"
115612
+ },
115613
+ {
115614
+ "kind": "field",
115615
+ "name": "NEEDLE_HALF_WIDTH",
115616
+ "type": {
115617
+ "text": "number"
115618
+ },
115619
+ "privacy": "private",
115620
+ "static": true,
115621
+ "readonly": true,
115622
+ "default": "16.5"
115623
+ },
115624
+ {
115625
+ "kind": "method",
115626
+ "name": "_needleIncludeBox",
115627
+ "privacy": "private",
115628
+ "parameters": [
115629
+ {
115630
+ "name": "radiusOffset",
115631
+ "type": {
115632
+ "text": "number"
115633
+ }
115634
+ }
115635
+ ],
115636
+ "description": "Box the zoomed frame must keep visible, in SVG units."
115637
+ },
115571
115638
  {
115572
115639
  "kind": "field",
115573
115640
  "name": "_needleTransform",
@@ -8,7 +8,6 @@ const componentStyle = css`* {
8
8
  width: fit-content;
9
9
  height: fit-content;
10
10
  min-width: var(--ui-components-keyboard-numeric-component-width-min);
11
- min-height: var(--ui-components-keyboard-numeric-component-height-min);
12
11
  flex-direction: column;
13
12
  align-items: flex-start;
14
13
  border-radius: var(--ui-components-keyboard-numeric-border-radius);
@@ -132,7 +131,7 @@ obc-icon-button.calculation-button::part(visible-wrapper) {
132
131
 
133
132
  .key-button {
134
133
  flex: 1 0 0;
135
- min-width: var(--ui-components-keyboard-numeric-touch-target-size);
134
+ min-width: var(--ui-components-keyboard-numeric-button-size-min);
136
135
  min-height: var(--ui-components-keyboard-numeric-button-size-min);
137
136
  height: var(--ui-components-keyboard-numeric-button-size-min);
138
137
  }
@@ -141,7 +140,7 @@ obc-button.key-button::part(visible-wrapper) {
141
140
  box-sizing: border-box;
142
141
  display: flex;
143
142
  flex: 1 0 0;
144
- min-width: var(--ui-components-keyboard-numeric-touch-target-size);
143
+ min-width: var(--ui-components-keyboard-numeric-button-size-min);
145
144
  min-height: var(--ui-components-keyboard-numeric-button-size-min);
146
145
  height: 100%;
147
146
  align-items: center;
@@ -1 +1 @@
1
- {"version":3,"file":"keyboard-numeric.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"keyboard-numeric.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -21,6 +21,13 @@ const componentStyle = css`* {
21
21
  height: 100%;
22
22
  }
23
23
 
24
+ .container > svg {
25
+ /* The arc is drawn where it points and rotated into the window, so it paints
26
+ outside the cropped viewBox; \`transform-origin\` (set inline) keeps that
27
+ rotation on the compass centre. */
28
+ overflow: visible;
29
+ }
30
+
24
31
  .container > .readout {
25
32
  left: 50%;
26
33
  width: auto;
@@ -30,17 +37,19 @@ const componentStyle = css`* {
30
37
 
31
38
  :host {
32
39
  display: block;
33
- width: 100%;
34
- height: 100%;
35
- /* Clips the rotated overlay <svg transform="rotate(...)">, whose corners
36
- swing outside the host and leak arc pixels in wide layouts (same
37
- protection obc-watch has had since #994). Known trade-off: the HDG/COG
38
- arrow apexes previously painted 1-2px past the host's top edge and are
39
- now shaved flat at the box edge — imperceptible at normal viewing.
40
- TODO(designer): if the shave is unwanted, the frame needs headroom so
41
- the arrow tips fit inside the box — see "Host clipping & the arrow-apex
42
- shave" in docs/agents/watch-radial-instruments.md before changing
43
- (interacts with the #1021/#1049 label-reserve geometry). */
40
+ /* The element is the cropped canvas, not a square holding one, so the
41
+ aspect comes from the frame each render — the crop and the label reserve
42
+ both move it. 448 / 217 is the default crop's box (448 wide × 448·(1 −
43
+ 51.5%) tall); keep in sync with \`SECTOR_CLIP_BOTTOM\` in
44
+ compass-sector.ts. */
45
+ width: auto;
46
+ height: auto;
47
+ max-width: 100%;
48
+ max-height: 100%;
49
+ aspect-ratio: var(--obc-compass-sector-aspect, 448 / 217);
50
+
51
+ /* Both layers paint past their viewBox so the rotation can carry the arc in;
52
+ this is the edge that bounds the component. */
44
53
  overflow: hidden;
45
54
  }
46
55
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"compass-sector.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"compass-sector.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -165,17 +165,26 @@ export declare class ObcCompassSector extends LitElement {
165
165
  private _halfFOV;
166
166
  private _arcHalfExtent;
167
167
  private _scale;
168
- private _radiusOffset;
169
- private _cachedViewBox;
170
- private _cachedArcFrame;
171
168
  private _cachedAreas;
172
169
  private _cachedTickmarks;
173
170
  private _cachedAdvices;
171
+ private _resizeController;
172
+ private _aspectWidth;
173
+ private _aspectHeight;
174
+ firstUpdated(changed: PropertyValues): void;
174
175
  willUpdate(changed: PropertyValues): void;
176
+ updated(changed: PropertyValues): void;
175
177
  disconnectedCallback(): void;
176
178
  private _mapAngle;
177
179
  private _buildTickmarks;
178
- private _computeViewBox;
180
+ /** Deepest crop the active features need, so none of them is shaved. */
181
+ private _clipBottom;
182
+ /**
183
+ * One frame per render, feeding both layers: the shared sector box cropped
184
+ * to the arc. Zoom enlarges the arc rather than the window, so the window
185
+ * only slides outward by the radius offset and the canvas holds still.
186
+ */
187
+ private _buildFrame;
179
188
  private _renderNorthArrow;
180
189
  private _angleInRange;
181
190
  private _buildAdvices;
@@ -183,21 +192,13 @@ export declare class ObcCompassSector extends LitElement {
183
192
  private get _rotEndAngle();
184
193
  private priorityFor;
185
194
  /**
186
- * Vertical placement of the readout as a percentage of the host height.
187
- *
188
- * With `zoomToFitArc` the arc is reframed by `computeZoomToFitArcFrame`, whose
189
- * `radiusOffset`/`viewBox` depend on the arc's *absolute* orientation (which
190
- * cardinal axes its bounding box crosses), not just its bend. The arc itself
191
- * is always rotated back to the top, so it stays put on screen — but a
192
- * frame-derived offset would swing wildly as `heading` rotates the bbox around
193
- * the circle. So in zoom we use a fixed offset, which keeps the readout steady
194
- * under the (stationary) arc regardless of heading.
195
+ * Vertical placement of the readout as a percentage of the frame height.
195
196
  *
196
- * Without zoom the viewBox is the fixed, origin-symmetric 120° framing, so the
197
- * geometry is orientation-independent: place the readout halfway down the inner
198
- * radius from the watch center toward the arc's inner edge.
197
+ * The anchor sits halfway down the inner radius, below the arc's inner edge.
198
+ * Zoom pushes that edge out by the radius offset, so the anchor follows it
199
+ * and the gap under the arc reads the same in both modes.
199
200
  */
200
- private get _readoutTopPercent();
201
+ private _readoutTopPercent;
201
202
  render(): import('lit-html').TemplateResult<1>;
202
203
  static styles: import('lit').CSSResult[];
203
204
  }
@@ -1 +1 @@
1
- {"version":3,"file":"compass-sector.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/compass-sector/compass-sector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAgC,MAAM,KAAK,CAAC;AAG9E,OAAO,mBAAmB,CAAC;AAS3B,OAAO,EAAc,WAAW,EAAiB,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAKL,OAAO,EACP,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAS3B,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AACtD,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,CAAC;AAE9B,oBAAY,4BAA4B;IACtC,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,GAAG,QAAQ;CACZ;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuEG;AACH,qBACa,gBAAiB,SAAQ,UAAU;IACpB,OAAO,SAAK;IACZ,gBAAgB,SAAK;IAErB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAQ;IACtC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iBAAiB,EAAE,OAAO,CAAS;IACpC,6BAA6B,EAAE,MAAM,CAAO;IAC3C,uBAAuB,EAAE,OAAO,CAAS;IACvB,qBAAqB,UAAQ;IAChD,6BAA6B,EAAE,MAAM,CAAK;IACzC,eAAe,EAAE,OAAO,CAAS;IACjC,QAAQ,EAAE,OAAO,CAAS;IACV,cAAc,EAAE,WAAW,EAAE,CAAM;IAEpD,MAAM,EAAE,MAAM,CAAM;IAEpB,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,WAAW,CAA2B;IACnD,0BAA0B,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,qBAAqB,EAAE,MAAM,CAAM;IAC7D;;;;;OAKG;IACuB,kBAAkB,EAAE,MAAM,CAAK;IAC/B,WAAW,EAAE,MAAM,CAAM;IACxB,gBAAgB,EAAE,OAAO,CAAS;IACnC,iBAAiB,EAAE,MAAM,CAAyB;IAElD,KAAK,EAAE,eAAe,CAA0B;IAChD,QAAQ,EAAE,QAAQ,CAAoB;IAEhE,gBAAgB,EAAE,4BAA4B,EAAE,CAE9C;IACyB,eAAe,EAAE,OAAO,CAAS;IACjC,YAAY,EAAE,OAAO,CAAS;IAC9B,UAAU,EAAE,OAAO,CAAS;IAC7B,KAAK,SAAS;IACd,IAAI,SAAS;IACb,cAAc,SAAK;IAE7C,OAAO,CAAC,UAAU,CAGf;IAGH,OAAO,CAAC,QAAQ,CAAM;IACtB,OAAO,CAAC,cAAc,CAAmB;IACzC,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,aAAa,CAAK;IAC1B,OAAO,CAAC,cAAc,CAAM;IAC5B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,YAAY,CAAmB;IACvC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,cAAc,CAAwB;IAErC,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA8DzC,oBAAoB,IAAI,IAAI;IASrC,OAAO,CAAC,SAAS;IAejB,OAAO,CAAC,eAAe;IAmDvB,OAAO,CAAC,eAAe;IAyBvB,OAAO,CAAC,iBAAiB;IAqBzB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IAgBrB,OAAO,KAAK,sBAAsB,GAEjC;IAED,OAAO,KAAK,YAAY,GAKvB;IAED,OAAO,CAAC,WAAW;IAOnB;;;;;;;;;;;;;;OAcG;IACH,OAAO,KAAK,kBAAkB,GAU7B;IAMQ,MAAM;IAwGf,OAAgB,MAAM,4BAIpB;CACH;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,oBAAoB,EAAE,gBAAgB,CAAC;KACxC;CACF"}
1
+ {"version":3,"file":"compass-sector.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/compass-sector/compass-sector.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { unsafeCSS, LitElement, nothing, svg, html } from "lit";
2
2
  import { property } from "lit/decorators.js";
3
+ import { ResizeController } from "@lit-labs/observers/resize-controller.js";
3
4
  import componentStyle from "./compass-sector.css.js";
4
5
  import { WatchCircleType, innerRingRadiusFor, OUTER_RING_RADIUS } from "../watch/watch.js";
5
6
  import { centerReadoutStyles, renderCenterReadouts } from "../readout/center-readout.js";
@@ -9,11 +10,11 @@ import { TickmarkType, TickmarkStyle } from "../watch/tickmark.js";
9
10
  import { arrow, ArrowStyle } from "../compass/arrow.js";
10
11
  import { AdviceState } from "../watch/advice.js";
11
12
  import { SetpointBundle } from "../../svghelpers/setpoint-bundle.js";
12
- import { computeZoomToFitArcFrame } from "../../svghelpers/arc-frame.js";
13
+ import { observeInnerBox, computeRadialFrame, measureContainerPx, estimateLabelWidthPx } from "../../svghelpers/radial-frame.js";
13
14
  import { RotPosition, ROT_ZERO_DEADBAND_DEG } from "../rate-of-turn/rot-renderer.js";
14
15
  import { RotType } from "../rate-of-turn/rot-renderer.js";
15
16
  import { customElement } from "../../decorator.js";
16
- import { normalizeAngle } from "../../svghelpers/math.js";
17
+ import { degToRad, normalizeAngle } from "../../svghelpers/math.js";
17
18
  import { InstrumentState, Priority } from "../types.js";
18
19
  var __defProp = Object.defineProperty;
19
20
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -31,7 +32,12 @@ var CompassSectorPriorityElement = /* @__PURE__ */ ((CompassSectorPriorityElemen
31
32
  CompassSectorPriorityElement2["rot"] = "rot";
32
33
  return CompassSectorPriorityElement2;
33
34
  })(CompassSectorPriorityElement || {});
34
- const PADDING = 72;
35
+ const BASE_PADDING = 48;
36
+ const SECTOR_CLIP_BOTTOM = 51.5;
37
+ const SECTOR_CLIP_BOTTOM_ROT = 50.4;
38
+ const SECTOR_CLIP_BOTTOM_INSIDE_LABELS = 47.3;
39
+ const SECTOR_CLIP_BOTTOM_READOUT = 44;
40
+ const SECTOR_SIDE_MARGIN = 0;
35
41
  const WATCH_TYPE = WatchCircleType.triple;
36
42
  const INNER_RADIUS = innerRingRadiusFor(WATCH_TYPE);
37
43
  const ARC_HALF_EXTENT = 60;
@@ -87,11 +93,16 @@ let ObcCompassSector = class extends LitElement {
87
93
  this._halfFOV = 30;
88
94
  this._arcHalfExtent = ARC_HALF_EXTENT;
89
95
  this._scale = 1;
90
- this._radiusOffset = 0;
91
- this._cachedViewBox = "";
92
96
  this._cachedAreas = [];
93
97
  this._cachedTickmarks = [];
94
98
  this._cachedAdvices = [];
99
+ this._resizeController = new ResizeController(this, {});
100
+ this._aspectWidth = 448;
101
+ this._aspectHeight = 217.28;
102
+ }
103
+ firstUpdated(changed) {
104
+ super.firstUpdated(changed);
105
+ observeInnerBox(this._resizeController, this.renderRoot);
95
106
  }
96
107
  willUpdate(changed) {
97
108
  super.willUpdate(changed);
@@ -137,13 +148,19 @@ let ObcCompassSector = class extends LitElement {
137
148
  roundOutsideCut: true
138
149
  }
139
150
  ];
140
- this._computeViewBox();
141
151
  this._cachedTickmarks = this._buildTickmarks();
142
152
  }
143
153
  if (arcInputsChanged || changed.has("headingAdvices")) {
144
154
  this._cachedAdvices = this._buildAdvices();
145
155
  }
146
156
  }
157
+ updated(changed) {
158
+ super.updated(changed);
159
+ this.style.setProperty(
160
+ "--obc-compass-sector-aspect",
161
+ `${this._aspectWidth} / ${this._aspectHeight}`
162
+ );
163
+ }
147
164
  disconnectedCallback() {
148
165
  super.disconnectedCallback();
149
166
  this._headingSp.dispose();
@@ -197,25 +214,45 @@ let ObcCompassSector = class extends LitElement {
197
214
  // ---------------------------------------------------------------------------
198
215
  // ViewBox
199
216
  // ---------------------------------------------------------------------------
200
- _computeViewBox() {
201
- if (this.zoomToFitArc) {
202
- const targetSize = (176 + PADDING) * 2;
203
- const frame = computeZoomToFitArcFrame({
204
- areas: this._cachedAreas,
205
- outerRadius: OUTER_RING_RADIUS,
206
- innerRadius: INNER_RADIUS,
207
- extension: PADDING,
208
- targetSize
209
- });
210
- this._radiusOffset = frame.radiusOffset;
211
- this._cachedViewBox = frame.viewBox;
212
- this._cachedArcFrame = frame;
213
- } else {
214
- this._radiusOffset = 0;
215
- const width = (176 + PADDING) * 2;
216
- this._cachedViewBox = `-${width / 2} -${width / 2} ${width} ${width}`;
217
- this._cachedArcFrame = void 0;
217
+ /** Deepest crop the active features need, so none of them is shaved. */
218
+ _clipBottom() {
219
+ const clips = [SECTOR_CLIP_BOTTOM];
220
+ if (this.rotType !== void 0 && this.rotPosition === RotPosition.innerCircle) {
221
+ clips.push(SECTOR_CLIP_BOTTOM_ROT);
222
+ }
223
+ if (this.tickmarksInside) {
224
+ clips.push(SECTOR_CLIP_BOTTOM_INSIDE_LABELS);
225
+ }
226
+ if (this.hasReadout) {
227
+ clips.push(SECTOR_CLIP_BOTTOM_READOUT);
218
228
  }
229
+ return Math.min(...clips);
230
+ }
231
+ /**
232
+ * One frame per render, feeding both layers: the shared sector box cropped
233
+ * to the arc. Zoom enlarges the arc rather than the window, so the window
234
+ * only slides outward by the radius offset and the canvas holds still.
235
+ */
236
+ _buildFrame() {
237
+ const frame = computeRadialFrame({
238
+ basePadding: BASE_PADDING,
239
+ labelWidthPx: this.tickmarksInside ? 0 : estimateLabelWidthPx(this._cachedTickmarks.map((t) => t.text)),
240
+ clips: { top: 0, bottom: this._clipBottom(), left: 0, right: 0 },
241
+ containerPx: measureContainerPx(this)
242
+ });
243
+ if (!this.zoomToFitArc) {
244
+ return frame;
245
+ }
246
+ const halfWidth = frame.width / 2 - SECTOR_SIDE_MARGIN;
247
+ const sin = Math.sin(degToRad(this._arcHalfExtent));
248
+ const radiusOffset = Math.max(0, halfWidth / sin - OUTER_RING_RADIUS);
249
+ const y = frame.y - radiusOffset;
250
+ return {
251
+ ...frame,
252
+ y,
253
+ radiusOffset,
254
+ viewBox: `${frame.x} ${y} ${frame.width} ${frame.height}`
255
+ };
219
256
  }
220
257
  // ---------------------------------------------------------------------------
221
258
  // North arrow — rendered in overlay at mapped 0° position
@@ -268,38 +305,32 @@ let ObcCompassSector = class extends LitElement {
268
305
  return selected.includes(element) ? this.priority : Priority.regular;
269
306
  }
270
307
  /**
271
- * Vertical placement of the readout as a percentage of the host height.
308
+ * Vertical placement of the readout as a percentage of the frame height.
272
309
  *
273
- * With `zoomToFitArc` the arc is reframed by `computeZoomToFitArcFrame`, whose
274
- * `radiusOffset`/`viewBox` depend on the arc's *absolute* orientation (which
275
- * cardinal axes its bounding box crosses), not just its bend. The arc itself
276
- * is always rotated back to the top, so it stays put on screen — but a
277
- * frame-derived offset would swing wildly as `heading` rotates the bbox around
278
- * the circle. So in zoom we use a fixed offset, which keeps the readout steady
279
- * under the (stationary) arc regardless of heading.
280
- *
281
- * Without zoom the viewBox is the fixed, origin-symmetric 120° framing, so the
282
- * geometry is orientation-independent: place the readout halfway down the inner
283
- * radius from the watch center toward the arc's inner edge.
310
+ * The anchor sits halfway down the inner radius, below the arc's inner edge.
311
+ * Zoom pushes that edge out by the radius offset, so the anchor follows it
312
+ * and the gap under the arc reads the same in both modes.
284
313
  */
285
- get _readoutTopPercent() {
286
- if (this.zoomToFitArc) {
287
- return 70;
288
- }
289
- const [, vy, , vh] = this._cachedViewBox.split(" ").map(Number);
290
- if (!vh || Number.isNaN(vy)) {
314
+ _readoutTopPercent(frame) {
315
+ if (!frame.height) {
291
316
  return 50;
292
317
  }
293
- const anchorY = -INNER_RADIUS * 0.5;
294
- return Math.round((anchorY - vy) / vh * 1e3) / 10;
318
+ const anchorY = -INNER_RADIUS * 0.5 - frame.radiusOffset;
319
+ return Math.round((anchorY - frame.y) / frame.height * 1e3) / 10;
295
320
  }
296
321
  // ---------------------------------------------------------------------------
297
322
  // Render
298
323
  // ---------------------------------------------------------------------------
299
324
  render() {
300
325
  const rotation = -this.heading;
301
- const viewBox = this._cachedViewBox;
302
- const rOff = this._radiusOffset;
326
+ const frame = this._buildFrame();
327
+ const viewBox = frame.viewBox;
328
+ const rOff = frame.radiusOffset;
329
+ const pivotX = -frame.x / frame.width * 100;
330
+ const pivotY = -frame.y / frame.height * 100;
331
+ this._aspectWidth = frame.width;
332
+ this._aspectHeight = frame.height;
333
+ const tickmarks = frame.labelsHidden ? this._cachedTickmarks.map((t) => ({ ...t, text: void 0 })) : this._cachedTickmarks;
303
334
  const mappedCOG = this._mapAngle(this.courseOverGround);
304
335
  const mappedSetpoint = this.headingSetpoint != null ? this._mapAngle(this.headingSetpoint) : void 0;
305
336
  const mappedNewSetpoint = this.newHeadingSetpoint != null ? this._mapAngle(this.newHeadingSetpoint) : void 0;
@@ -307,17 +338,15 @@ let ObcCompassSector = class extends LitElement {
307
338
  <div class="container">
308
339
  <obc-watch
309
340
  .touching=${this.touching}
310
- .padding=${PADDING}
311
341
  .advices=${this._cachedAdvices}
312
- .tickmarks=${this._cachedTickmarks}
342
+ .tickmarks=${tickmarks}
313
343
  .tickmarkStyle=${TickmarkStyle.regular}
314
344
  .tickmarksInside=${this.tickmarksInside}
315
345
  .state=${this.state}
316
346
  .watchCircleType=${WATCH_TYPE}
317
347
  .northArrow=${false}
318
348
  .areas=${this._cachedAreas}
319
- .arcFrame=${this._cachedArcFrame}
320
- .zoomToFitArc=${this.zoomToFitArc}
349
+ .arcFrame=${frame}
321
350
  .tickFadeAngle=${this._arcHalfExtent * 0.2}
322
351
  .rotation=${rotation}
323
352
  .angleSetpoint=${mappedSetpoint}
@@ -342,7 +371,11 @@ let ObcCompassSector = class extends LitElement {
342
371
  .rotationsPerMinute=${this.rotationsPerMinute}
343
372
  >
344
373
  </obc-watch>
345
- <svg viewBox="${viewBox}" transform="rotate(${rotation})">
374
+ <svg
375
+ viewBox="${viewBox}"
376
+ transform="rotate(${rotation})"
377
+ style="transform-origin: ${pivotX}% ${pivotY}%"
378
+ >
346
379
  <g transform="rotate(${this.heading})">
347
380
  <line
348
381
  x1="0"
@@ -376,7 +409,7 @@ let ObcCompassSector = class extends LitElement {
376
409
  </svg>
377
410
  ${this.hasReadout ? html`<div
378
411
  class="readout"
379
- style="top: ${this._readoutTopPercent}%"
412
+ style="top: ${this._readoutTopPercent(frame)}%"
380
413
  >
381
414
  ${renderCenterReadouts([
382
415
  {