@oicl/openbridge-webcomponents 2.0.0-next.102 → 2.0.0-next.104

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 (46) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +583 -145
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +338 -8
  4. package/dist/building-blocks/instrument-radial/instrument-radial.d.ts +22 -2
  5. package/dist/building-blocks/instrument-radial/instrument-radial.d.ts.map +1 -1
  6. package/dist/building-blocks/instrument-radial/instrument-radial.js +61 -37
  7. package/dist/building-blocks/instrument-radial/instrument-radial.js.map +1 -1
  8. package/dist/components/modal-window/modal-window.css.js +4 -2
  9. package/dist/components/modal-window/modal-window.css.js.map +1 -1
  10. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts +14 -0
  11. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.d.ts.map +1 -1
  12. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js +30 -11
  13. package/dist/navigation-instruments/azimuth-thruster/azimuth-thruster.js.map +1 -1
  14. package/dist/navigation-instruments/compass/compass.d.ts +21 -1
  15. package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
  16. package/dist/navigation-instruments/compass/compass.js +36 -16
  17. package/dist/navigation-instruments/compass/compass.js.map +1 -1
  18. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
  19. package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
  20. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js +34 -2
  21. package/dist/navigation-instruments/gauge-radial/gauge-radial.css.js.map +1 -1
  22. package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts +15 -0
  23. package/dist/navigation-instruments/gauge-radial/gauge-radial.d.ts.map +1 -1
  24. package/dist/navigation-instruments/gauge-radial/gauge-radial.js +35 -1
  25. package/dist/navigation-instruments/gauge-radial/gauge-radial.js.map +1 -1
  26. package/dist/navigation-instruments/heading/heading.d.ts +19 -1
  27. package/dist/navigation-instruments/heading/heading.d.ts.map +1 -1
  28. package/dist/navigation-instruments/heading/heading.js +34 -16
  29. package/dist/navigation-instruments/heading/heading.js.map +1 -1
  30. package/dist/navigation-instruments/rudder/rudder.d.ts +15 -2
  31. package/dist/navigation-instruments/rudder/rudder.d.ts.map +1 -1
  32. package/dist/navigation-instruments/rudder/rudder.js +36 -26
  33. package/dist/navigation-instruments/rudder/rudder.js.map +1 -1
  34. package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts +15 -1
  35. package/dist/navigation-instruments/speed-gauge/speed-gauge.d.ts.map +1 -1
  36. package/dist/navigation-instruments/speed-gauge/speed-gauge.js +31 -3
  37. package/dist/navigation-instruments/speed-gauge/speed-gauge.js.map +1 -1
  38. package/dist/navigation-instruments/watch/watch.d.ts +29 -1
  39. package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
  40. package/dist/navigation-instruments/watch/watch.js +52 -38
  41. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  42. package/dist/svghelpers/radial-frame.d.ts +122 -0
  43. package/dist/svghelpers/radial-frame.d.ts.map +1 -0
  44. package/dist/svghelpers/radial-frame.js +259 -0
  45. package/dist/svghelpers/radial-frame.js.map +1 -0
  46. package/package.json +1 -1
@@ -1,5 +1,7 @@
1
1
  import { LitElement, nothing, html, svg, css } from "lit";
2
2
  import { property } from "lit/decorators.js";
3
+ import { ResizeController } from "@lit-labs/observers/resize-controller.js";
4
+ import { observeInnerBox, applyPinnedHostSize, computeRadialFrame, measureContainerPx, estimateLabelWidthPx } from "../../svghelpers/radial-frame.js";
3
5
  import { TickmarkStyle, TickmarkType } from "../watch/tickmark.js";
4
6
  import { WatchCircleType } from "../watch/watch.js";
5
7
  import { AdviceState } from "../watch/advice.js";
@@ -40,8 +42,22 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
40
42
  this.label = "STW";
41
43
  this.unit = "KN";
42
44
  this.fractionDigits = 1;
45
+ this._hostSizePinned = false;
46
+ this._resizeController = new ResizeController(this, {});
43
47
  this.maxAngle = 180 - 45;
44
48
  }
49
+ firstUpdated(changed) {
50
+ super.firstUpdated(changed);
51
+ observeInnerBox(this._resizeController, this.renderRoot);
52
+ }
53
+ updated(changed) {
54
+ super.updated(changed);
55
+ this._hostSizePinned = applyPinnedHostSize(
56
+ this,
57
+ this._frame,
58
+ this._hostSizePinned
59
+ );
60
+ }
45
61
  getAngle(v) {
46
62
  return v / this.maxSpeed * (180 + 45) - 90;
47
63
  }
@@ -52,6 +68,15 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
52
68
  const barColor = this.priority === Priority.enhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)";
53
69
  const setpointAngle = this.setpoint !== void 0 ? this.getAngle(this.setpoint) : void 0;
54
70
  const maxDigits = 1;
71
+ const tickmarks = this.tickmarks;
72
+ const frame = computeRadialFrame({
73
+ basePadding: 48,
74
+ labelWidthPx: this.tickmarksInside ? 0 : estimateLabelWidthPx(tickmarks.map((t) => t.text)),
75
+ containerPx: measureContainerPx(this),
76
+ faceDiameter: this.faceDiameter
77
+ });
78
+ this._frame = frame;
79
+ const shownTickmarks = frame.labelsHidden ? tickmarks.map((t) => ({ ...t, text: void 0 })) : tickmarks;
55
80
  return html`
56
81
  <div class="container">
57
82
  <obc-watch
@@ -62,8 +87,8 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
62
87
  .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}
63
88
  .setpointOverride=${this.setpointOverride}
64
89
  .animateSetpoint=${this.animateSetpoint}
65
- .padding=${48}
66
- .tickmarks=${this.tickmarks}
90
+ .arcFrame=${frame}
91
+ .tickmarks=${shownTickmarks}
67
92
  .tickmarksInside=${this.tickmarksInside}
68
93
  .tickmarkStyle=${this.tickmarkStyle}
69
94
  .advices=${this._advices}
@@ -84,7 +109,7 @@ let ObcSpeedGauge = class extends SetpointMixin(LitElement) {
84
109
  }
85
110
  ]}
86
111
  ></obc-watch>
87
- <svg class="rudder" viewBox="-224 -224 448 448">${this.needle}</svg>
112
+ <svg class="rudder" viewBox=${frame.viewBox}>${this.needle}</svg>
88
113
  ${this.hasReadout ? html`
89
114
  ${renderInstrumentReadout({
90
115
  className: "speed-gauge-value",
@@ -253,6 +278,9 @@ __decorateClass([
253
278
  __decorateClass([
254
279
  property({ type: Number })
255
280
  ], ObcSpeedGauge.prototype, "fractionDigits", 2);
281
+ __decorateClass([
282
+ property({ type: Number, attribute: "face-diameter" })
283
+ ], ObcSpeedGauge.prototype, "faceDiameter", 2);
256
284
  ObcSpeedGauge = __decorateClass([
257
285
  customElement("obc-speed-gauge")
258
286
  ], ObcSpeedGauge);
@@ -1 +1 @@
1
- {"version":3,"file":"speed-gauge.js","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"sourcesContent":["import {LitElement, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {WatchCircleType} from '../watch/watch.js';\nimport {AdviceType, AngleAdviceRaw, AdviceState} from '../watch/advice.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {Priority} from '../types.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {ReadoutDirection} from '../readout/readout.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcSpeedGaugeNeedleType {\n full = 'full',\n bar = 'bar',\n}\n\nexport interface SpeedAdvice {\n minSpeed: number;\n maxSpeed: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-speed-gauge>` — Radial speed gauge with needle and optional readout.\n *\n * `ObcSpeedGauge` renders a 225° arc gauge (−90° to +135°) that displays\n * the current speed with a configurable full-length or bar needle. It layers\n * an `<obc-watch>` base with a needle SVG overlay and an optional numeric\n * readout field. It inherits a full setpoint property bundle from\n * {@link SetpointMixin}, including auto at-setpoint detection, dual-marker\n * adjustment preview, and deadband tuning.\n *\n * ## Features\n *\n * - **Two needle types**: `full` (pointer with center dot) and `bar`\n * (short indicator bar) via `needleType`.\n * - **Bipolar range support**: When `minSpeed < 0`, negative tickmarks are\n * rendered with `main` tick style.\n * - **Optional readout**: Enable `hasReadout` to display an\n * `<obc-readout>` with the current speed, unit (KN), and label (STW).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin`; the setpoint angle and\n * at-setpoint state are computed and forwarded to `<obc-watch>`.\n * - **Speed advice zones**: Pass an array of {@link SpeedAdvice} objects to\n * render caution/alert arcs; triggered state is derived from whether the\n * current speed falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxSpeed` (and optionally `minSpeed`) to define the gauge range.\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Provide `tickmarkInterval` to control tickmark spacing.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Enable `hasReadout` to display the numeric value below the gauge.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The needle overlay SVG uses viewBox `−224 −224 448 448` to align with\n * the `<obc-watch>` layer.\n *\n * ## Example\n *\n * ```html\n * <obc-speed-gauge\n * speed=\"12.5\"\n * maxSpeed=\"25\"\n * needleType=\"full\"\n * enhanced\n * showLabels\n * hasReadout\n * tickmarkInterval=\"5\"\n * setpoint=\"15\"\n * ></obc-speed-gauge>\n * ```\n *\n * @element obc-speed-gauge\n * @typedef {import('./speed-gauge.js').SpeedAdvice} SpeedAdvice\n * @stable\n */\n@customElement('obc-speed-gauge')\nexport class ObcSpeedGauge extends SetpointMixin(LitElement) {\n @property({type: Number}) speed = 0;\n @property({type: Number}) maxSpeed = 100;\n @property({type: Number}) minSpeed = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n /**\n * Interval for tickmarks in speed units.\n * When undefined or <= 0, no tickmarks are shown (only the zero mark).\n */\n @property({type: Number}) tickmarkInterval: number | undefined = 20;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) needleType: ObcSpeedGaugeNeedleType =\n ObcSpeedGaugeNeedleType.full;\n @property({type: Array, attribute: false}) speedAdvices: SpeedAdvice[] = [];\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /**\n * When `true`, shows a centered `<obc-readout>` (label `STW`, unit `KN`)\n * below the gauge with the current speed. Default `false`.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /** Readout label. Default `STW`. */\n @property({type: String}) label = 'STW';\n /** Readout unit. Default `KN`. */\n @property({type: String}) unit = 'KN';\n /** Number of fraction digits shown in the readout. Default `1`. */\n @property({type: Number}) fractionDigits = 1;\n\n getAngle(v: number): number {\n return (v / this.maxSpeed) * (180 + 45) - 90;\n }\n\n get minAngle(): number {\n return this.getAngle(this.minSpeed) - 360;\n }\n\n maxAngle = 180 - 45;\n\n override render() {\n const barColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n const setpointAngle =\n this.setpoint !== undefined ? this.getAngle(this.setpoint) : undefined;\n\n const maxDigits = 1;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? this.getAngle(this.newSetpoint)\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.speed)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .padding=${48}\n .tickmarks=${this.tickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this._advices}\n .areas=${[\n {\n startAngle: this.minAngle,\n endAngle: this.maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ]}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${[\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.speed),\n fillColor: barColor,\n },\n ]}\n ></obc-watch>\n <svg class=\"rudder\" viewBox=\"-224 -224 448 448\">${this.needle}</svg>\n ${this.hasReadout\n ? html`\n ${renderInstrumentReadout({\n className: 'speed-gauge-value',\n direction: ReadoutDirection.horizontal,\n value: this.speed,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n maxDigits,\n priority: this.priority,\n })}\n `\n : nothing}\n </div>\n `;\n }\n\n get needle() {\n const needleColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n if (this.needleType === ObcSpeedGaugeNeedleType.full) {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n <circle cx=\"256\" cy=\"256\" r=\"14\" fill=${needleColor}/>\n <rect x=\"250\" y=\"96\" width=\"12\" height=\"192\" rx=\"6\" fill=${needleColor}/>\n <rect x=\"252\" y=\"98\" width=\"8\" height=\"188\" rx=\"4\" stroke=${needleColor} fill=${needleColor} stroke-width=\"4\"/>\n </svg> \n`;\n } else {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n<rect x=\"252\" y=\"96\" width=\"8\" height=\"48\" rx=\"4\" fill=${needleColor} stroke=\"var(--border-silhouette-color)\"/>\n</svg>\n `;\n }\n }\n\n get tickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n\n // Tickmarks — skip when undefined or <= 0 to prevent infinite loops\n const interval = this.tickmarkInterval;\n if (interval !== undefined && interval > 0 && Number.isFinite(interval)) {\n for (let i = interval; i < this.maxSpeed; i += interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.primary,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.maxSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.maxSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.maxSpeed.toString() : undefined,\n });\n }\n\n for (let i = -interval; i > this.minSpeed; i -= interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.main,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.minSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.minSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.minSpeed.toString() : undefined,\n });\n }\n }\n\n // Zero tickmark\n tickmarks.push({\n angle: this.getAngle(0),\n type: this.minSpeed < 0 ? TickmarkType.main : TickmarkType.textOnly,\n text: this.showLabels ? '0' : undefined,\n });\n\n return tickmarks;\n }\n\n get _advices(): AngleAdviceRaw[] {\n return this.speedAdvices.map((speedAdvice) => {\n const minAngle = this.getAngle(speedAdvice.minSpeed);\n const maxAngle = this.getAngle(speedAdvice.maxSpeed);\n let state = speedAdvice.hinted ? AdviceState.hinted : AdviceState.regular;\n if (\n this.speed >= speedAdvice.minSpeed &&\n this.speed <= speedAdvice.maxSpeed\n ) {\n state = AdviceState.triggered;\n }\n\n return {\n minAngle,\n maxAngle,\n type: speedAdvice.type,\n state,\n hideMinTickmark: speedAdvice.minSpeed === this.minSpeed,\n hideMaxTickmark: speedAdvice.maxSpeed === this.maxSpeed,\n };\n });\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n obc-watch {\n anchor-name: --watch;\n }\n\n .speed-gauge-value {\n position: absolute;\n top: clamp(\n 70%,\n calc(80% - (anchor-size(--watch height) - 200px) * 0.2),\n 80%\n );\n left: 50%;\n transform: translateX(-50%);\n width: fit-content;\n height: fit-content;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-speed-gauge': ObcSpeedGauge;\n }\n}\n"],"names":["ObcSpeedGaugeNeedleType"],"mappings":"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"}
1
+ {"version":3,"file":"speed-gauge.js","sources":["../../../src/navigation-instruments/speed-gauge/speed-gauge.ts"],"sourcesContent":["import {LitElement, PropertyValues, css, html, nothing, svg} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {ResizeController} from '@lit-labs/observers/resize-controller.js';\nimport {\n applyPinnedHostSize,\n computeRadialFrame,\n estimateLabelWidthPx,\n measureContainerPx,\n observeInnerBox,\n type RadialFrame,\n} from '../../svghelpers/radial-frame.js';\nimport {Tickmark, TickmarkStyle, TickmarkType} from '../watch/tickmark.js';\nimport {WatchCircleType} from '../watch/watch.js';\nimport {AdviceType, AngleAdviceRaw, AdviceState} from '../watch/advice.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport {Priority} from '../types.js';\nimport {renderInstrumentReadout} from '../readout/instrument-readout.js';\nimport {ReadoutDirection} from '../readout/readout.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcSpeedGaugeNeedleType {\n full = 'full',\n bar = 'bar',\n}\n\nexport interface SpeedAdvice {\n minSpeed: number;\n maxSpeed: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-speed-gauge>` — Radial speed gauge with needle and optional readout.\n *\n * `ObcSpeedGauge` renders a 225° arc gauge (−90° to +135°) that displays\n * the current speed with a configurable full-length or bar needle. It layers\n * an `<obc-watch>` base with a needle SVG overlay and an optional numeric\n * readout field. It inherits a full setpoint property bundle from\n * {@link SetpointMixin}, including auto at-setpoint detection, dual-marker\n * adjustment preview, and deadband tuning.\n *\n * ## Features\n *\n * - **Two needle types**: `full` (pointer with center dot) and `bar`\n * (short indicator bar) via `needleType`.\n * - **Bipolar range support**: When `minSpeed < 0`, negative tickmarks are\n * rendered with `main` tick style.\n * - **Optional readout**: Enable `hasReadout` to display an\n * `<obc-readout>` with the current speed, unit (KN), and label (STW).\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin`; the setpoint angle and\n * at-setpoint state are computed and forwarded to `<obc-watch>`.\n * - **Speed advice zones**: Pass an array of {@link SpeedAdvice} objects to\n * render caution/alert arcs; triggered state is derived from whether the\n * current speed falls inside the advice range.\n *\n * ## Usage Guidelines\n *\n * - Set `maxSpeed` (and optionally `minSpeed`) to define the gauge range.\n * - Use `priority` to switch between regular and enhanced color palettes\n * (default: `Priority.regular`).\n * - Provide `tickmarkInterval` to control tickmark spacing.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\n * - Enable `tickmarksInside` to render tickmarks inside the ring.\n * - Enable `hasReadout` to display the numeric value below the gauge.\n *\n * ## Best Practices\n *\n * - Prefer `SetpointMixin` properties (`setpoint`, `touching`, etc.) over\n * any legacy aliases — the mixin is the single source of truth.\n * - The needle overlay SVG uses viewBox `−224 −224 448 448` to align with\n * the `<obc-watch>` layer.\n *\n * ## Example\n *\n * ```html\n * <obc-speed-gauge\n * speed=\"12.5\"\n * maxSpeed=\"25\"\n * needleType=\"full\"\n * enhanced\n * showLabels\n * hasReadout\n * tickmarkInterval=\"5\"\n * setpoint=\"15\"\n * ></obc-speed-gauge>\n * ```\n *\n * @element obc-speed-gauge\n * @typedef {import('./speed-gauge.js').SpeedAdvice} SpeedAdvice\n * @stable\n */\n@customElement('obc-speed-gauge')\nexport class ObcSpeedGauge extends SetpointMixin(LitElement) {\n @property({type: Number}) speed = 0;\n @property({type: Number}) maxSpeed = 100;\n @property({type: Number}) minSpeed = 0;\n @property({type: Boolean}) showLabels: boolean = false;\n /** Whether to render tickmarks inside the ring. */\n @property({type: Boolean}) tickmarksInside: boolean = false;\n /**\n * Interval for tickmarks in speed units.\n * When undefined or <= 0, no tickmarks are shown (only the zero mark).\n */\n @property({type: Number}) tickmarkInterval: number | undefined = 20;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: String}) needleType: ObcSpeedGaugeNeedleType =\n ObcSpeedGaugeNeedleType.full;\n @property({type: Array, attribute: false}) speedAdvices: SpeedAdvice[] = [];\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n /**\n * When `true`, shows a centered `<obc-readout>` (label `STW`, unit `KN`)\n * below the gauge with the current speed. Default `false`.\n */\n @property({type: Boolean}) hasReadout: boolean = false;\n /** Readout label. Default `STW`. */\n @property({type: String}) label = 'STW';\n /** Readout unit. Default `KN`. */\n @property({type: String}) unit = 'KN';\n /** Number of fraction digits shown in the readout. Default `1`. */\n @property({type: Number}) fractionDigits = 1;\n /**\n * Outer-ring diameter in CSS pixels. When set, the instrument renders at a\n * fixed intrinsic size derived from the ring, arc shape and label reserve —\n * so instruments sharing the same value have identical ring circumference\n * regardless of label width or arc extent (like obc-donut-chart's\n * fixedHeight). When unset (default), the instrument fills its container.\n */\n @property({type: Number, attribute: 'face-diameter'})\n faceDiameter: number | undefined;\n\n private _frame: RadialFrame | undefined;\n\n /** Whether the host size styles were set by applyPinnedHostSize. */\n private _hostSizePinned = false;\n\n private _resizeController = new ResizeController(this, {});\n\n override firstUpdated(changed: PropertyValues): void {\n super.firstUpdated(changed);\n observeInnerBox(this._resizeController, this.renderRoot);\n }\n\n override updated(changed: PropertyValues): void {\n super.updated(changed);\n this._hostSizePinned = applyPinnedHostSize(\n this,\n this._frame,\n this._hostSizePinned\n );\n }\n\n getAngle(v: number): number {\n return (v / this.maxSpeed) * (180 + 45) - 90;\n }\n\n get minAngle(): number {\n return this.getAngle(this.minSpeed) - 360;\n }\n\n maxAngle = 180 - 45;\n\n override render() {\n const barColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-tertiary-color)'\n : 'var(--instrument-regular-tertiary-color)';\n const setpointAngle =\n this.setpoint !== undefined ? this.getAngle(this.setpoint) : undefined;\n\n const maxDigits = 1;\n\n const tickmarks = this.tickmarks;\n const frame = computeRadialFrame({\n basePadding: 48,\n labelWidthPx: this.tickmarksInside\n ? 0\n : estimateLabelWidthPx(tickmarks.map((t) => t.text)),\n containerPx: measureContainerPx(this),\n faceDiameter: this.faceDiameter,\n });\n this._frame = frame;\n const shownTickmarks = frame.labelsHidden\n ? tickmarks.map((t) => ({...t, text: undefined}))\n : tickmarks;\n\n return html`\n <div class=\"container\">\n <obc-watch\n .touching=${this.touching}\n .angleSetpoint=${setpointAngle}\n .newAngleSetpoint=${this.newSetpoint !== undefined\n ? this.getAngle(this.newSetpoint)\n : undefined}\n .atAngleSetpoint=${this.computeAtSetpoint(this.speed)}\n .angleSetpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .animateSetpoint=${this.animateSetpoint}\n .arcFrame=${frame}\n .tickmarks=${shownTickmarks}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .advices=${this._advices}\n .areas=${[\n {\n startAngle: this.minAngle,\n endAngle: this.maxAngle,\n roundInsideCut: true,\n roundOutsideCut: true,\n },\n ]}\n .watchCircleType=${WatchCircleType.double}\n .barAreas=${[\n {\n startAngle: this.getAngle(0),\n endAngle: this.getAngle(this.speed),\n fillColor: barColor,\n },\n ]}\n ></obc-watch>\n <svg class=\"rudder\" viewBox=${frame.viewBox}>${this.needle}</svg>\n ${this.hasReadout\n ? html`\n ${renderInstrumentReadout({\n className: 'speed-gauge-value',\n direction: ReadoutDirection.horizontal,\n value: this.speed,\n label: this.label,\n unit: this.unit,\n fractionDigits: this.fractionDigits,\n maxDigits,\n priority: this.priority,\n })}\n `\n : nothing}\n </div>\n `;\n }\n\n get needle() {\n const needleColor =\n this.priority === Priority.enhanced\n ? 'var(--instrument-enhanced-secondary-color)'\n : 'var(--instrument-regular-secondary-color)';\n if (this.needleType === ObcSpeedGaugeNeedleType.full) {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n <circle cx=\"256\" cy=\"256\" r=\"14\" fill=${needleColor}/>\n <rect x=\"250\" y=\"96\" width=\"12\" height=\"192\" rx=\"6\" fill=${needleColor}/>\n <rect x=\"252\" y=\"98\" width=\"8\" height=\"188\" rx=\"4\" stroke=${needleColor} fill=${needleColor} stroke-width=\"4\"/>\n </svg> \n`;\n } else {\n return svg`<g transform=\"rotate(${this.getAngle(this.speed)}) translate(-256, -256)\">\n<rect x=\"252\" y=\"96\" width=\"8\" height=\"48\" rx=\"4\" fill=${needleColor} stroke=\"var(--border-silhouette-color)\"/>\n</svg>\n `;\n }\n }\n\n get tickmarks(): Tickmark[] {\n const tickmarks: Tickmark[] = [];\n\n // Tickmarks — skip when undefined or <= 0 to prevent infinite loops\n const interval = this.tickmarkInterval;\n if (interval !== undefined && interval > 0 && Number.isFinite(interval)) {\n for (let i = interval; i < this.maxSpeed; i += interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.primary,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.maxSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.maxSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.maxSpeed.toString() : undefined,\n });\n }\n\n for (let i = -interval; i > this.minSpeed; i -= interval) {\n tickmarks.push({\n angle: this.getAngle(i),\n type: TickmarkType.main,\n text: this.showLabels ? i.toString() : undefined,\n });\n }\n\n if (this.showLabels && this.minSpeed % interval === 0) {\n tickmarks.push({\n angle: this.getAngle(this.minSpeed),\n type: TickmarkType.textOnly,\n text: this.showLabels ? this.minSpeed.toString() : undefined,\n });\n }\n }\n\n // Zero tickmark\n tickmarks.push({\n angle: this.getAngle(0),\n type: this.minSpeed < 0 ? TickmarkType.main : TickmarkType.textOnly,\n text: this.showLabels ? '0' : undefined,\n });\n\n return tickmarks;\n }\n\n get _advices(): AngleAdviceRaw[] {\n return this.speedAdvices.map((speedAdvice) => {\n const minAngle = this.getAngle(speedAdvice.minSpeed);\n const maxAngle = this.getAngle(speedAdvice.maxSpeed);\n let state = speedAdvice.hinted ? AdviceState.hinted : AdviceState.regular;\n if (\n this.speed >= speedAdvice.minSpeed &&\n this.speed <= speedAdvice.maxSpeed\n ) {\n state = AdviceState.triggered;\n }\n\n return {\n minAngle,\n maxAngle,\n type: speedAdvice.type,\n state,\n hideMinTickmark: speedAdvice.minSpeed === this.minSpeed,\n hideMaxTickmark: speedAdvice.maxSpeed === this.maxSpeed,\n };\n });\n }\n\n static override styles = css`\n * {\n box-sizing: border-box;\n }\n\n .container {\n position: relative;\n width: 100%;\n height: 100%;\n }\n\n .container > * {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n\n obc-watch {\n anchor-name: --watch;\n }\n\n .speed-gauge-value {\n position: absolute;\n top: clamp(\n 70%,\n calc(80% - (anchor-size(--watch height) - 200px) * 0.2),\n 80%\n );\n left: 50%;\n transform: translateX(-50%);\n width: fit-content;\n height: fit-content;\n }\n `;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-speed-gauge': ObcSpeedGauge;\n }\n}\n"],"names":["ObcSpeedGaugeNeedleType"],"mappings":"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"}
@@ -119,7 +119,20 @@ export declare class ObcWatch extends LitElement {
119
119
  private _setpointCssAngle;
120
120
  /** Whether the setpoint CSS angle has been initialised (to skip transition on first render). */
121
121
  private _setpointCssAngleInit;
122
+ /**
123
+ * Explicit padding override in SVG units: the un-zoomed viewBox becomes
124
+ * exactly `(176 + padding) * 2`. Setting it disables the automatic
125
+ * width-aware label reserve (issue #1021) — the caller owns label room.
126
+ */
122
127
  padding: number | undefined;
128
+ /**
129
+ * Outer-ring diameter in CSS pixels. When set, the instrument renders at a
130
+ * fixed intrinsic size derived from the ring, arc shape and label reserve —
131
+ * so instruments sharing the same value have identical ring circumference
132
+ * regardless of label width or arc extent (like obc-donut-chart's
133
+ * fixedHeight). When unset (default), the instrument fills its container.
134
+ */
135
+ faceDiameter: number | undefined;
123
136
  areas: WatchArea[];
124
137
  barAreas: WatchBarArea[];
125
138
  needles: WatchNeedle[];
@@ -195,11 +208,21 @@ export declare class ObcWatch extends LitElement {
195
208
  */
196
209
  private get _effectiveRpm();
197
210
  private _resizeController;
211
+ firstUpdated(changed: PropertyValues): void;
198
212
  willUpdate(changed: PropertyValues): void;
199
213
  disconnectedCallback(): void;
200
214
  updated(changed: PropertyValues): void;
201
215
  private get innerRingRadius();
202
216
  private _rOff;
217
+ /**
218
+ * Set by the frame when the label reserve exceeded its cap: tick label
219
+ * texts are dropped instead of clipped (see radial-frame.ts).
220
+ */
221
+ private _labelsHidden;
222
+ /** The frame of the last render, when computed internally (no arcFrame). */
223
+ private _ownFrame;
224
+ /** Whether the host size styles were set by applyPinnedHostSize. */
225
+ private _hostSizePinned;
203
226
  /**
204
227
  * Radius for a dial-band edge under zoom: additive (`base + _rOff`), keeping
205
228
  * band thickness constant in SVG units. INVARIANT: every band-edge radius
@@ -215,7 +238,12 @@ export declare class ObcWatch extends LitElement {
215
238
  private renderBars;
216
239
  private renderNeedles;
217
240
  private getScale;
218
- private getPadding;
241
+ /**
242
+ * Pixel width of the widest outside label, feeding the frame's label
243
+ * reserve (issue #1021). Explicit `padding` is a hard geometry override
244
+ * and disables the reserve, preserving legacy consumer output.
245
+ */
246
+ private getLabelWidthPx;
219
247
  render(): import('lit-html').TemplateResult<1>;
220
248
  private getRotColors;
221
249
  private renderRot;
@@ -1 +1 @@
1
- {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/watch/watch.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/watch/watch.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@ import { VesselImageSize, vesselImages } from "./vessel.js";
15
15
  import { VesselImage } from "./vessel.js";
16
16
  import { renderWind, renderCurrent } from "./environment.js";
17
17
  import { customElement } from "../../decorator.js";
18
- import { computeZoomToFitArcFrame } from "../../svghelpers/arc-frame.js";
18
+ import { observeInnerBox, applyPinnedHostSize, measureContainerPx, NSWE_LABEL_WIDTH_PX, estimateLabelWidthPx, computeRadialFrame } from "../../svghelpers/radial-frame.js";
19
19
  var __defProp = Object.defineProperty;
20
20
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
21
21
  var __decorateClass = (decorators, target, key, kind) => {
@@ -103,6 +103,8 @@ let ObcWatch = class extends LitElement {
103
103
  this._legacyRotationsPerMinute = 0;
104
104
  this._resizeController = new ResizeController(this, {});
105
105
  this._rOff = 0;
106
+ this._labelsHidden = false;
107
+ this._hostSizePinned = false;
106
108
  }
107
109
  set rotationsPerMinute(value) {
108
110
  this._legacyRotationsPerMinute = value;
@@ -124,6 +126,10 @@ let ObcWatch = class extends LitElement {
124
126
  }
125
127
  return this._legacyRotationsPerMinute;
126
128
  }
129
+ firstUpdated(changed) {
130
+ super.firstUpdated(changed);
131
+ observeInnerBox(this._resizeController, this.renderRoot);
132
+ }
127
133
  willUpdate(changed) {
128
134
  super.willUpdate(changed);
129
135
  if (this._rotController && (changed.has("rateOfTurnDegreesPerMinute") || changed.has("rotDotAnimationFactor") || changed.has("rotationsPerMinute"))) {
@@ -148,6 +154,11 @@ let ObcWatch = class extends LitElement {
148
154
  }
149
155
  updated(changed) {
150
156
  super.updated(changed);
157
+ this._hostSizePinned = applyPinnedHostSize(
158
+ this,
159
+ this.arcFrame ? void 0 : this._ownFrame,
160
+ this._hostSizePinned
161
+ );
151
162
  const el = this.rotType ? this.renderRoot.querySelector("#rot-spinner") : null;
152
163
  if (!el) {
153
164
  this._rotController = disposeRotController(this, this._rotController);
@@ -445,30 +456,26 @@ let ObcWatch = class extends LitElement {
445
456
  });
446
457
  }
447
458
  getScale({ width, height }) {
448
- let clientWidth = this.clientWidth;
449
- let clientHeight = this.clientHeight;
450
- if (clientWidth === 0 || clientHeight === 0) {
451
- const box = this.parentElement?.getBoundingClientRect();
452
- if (box) {
453
- clientWidth = box.width;
454
- clientHeight = box.height;
455
- }
456
- }
457
- const scale = Math.min(clientWidth / width, clientHeight / height);
459
+ const container = measureContainerPx(this);
460
+ const scale = Math.min(container.width / width, container.height / height);
458
461
  if (!Number.isFinite(scale) || scale <= 0) {
459
462
  return 1;
460
463
  }
461
464
  return scale;
462
465
  }
463
- getPadding() {
464
- if (this.padding !== void 0) {
465
- return this.padding;
466
+ /**
467
+ * Pixel width of the widest outside label, feeding the frame's label
468
+ * reserve (issue #1021). Explicit `padding` is a hard geometry override
469
+ * and disables the reserve, preserving legacy consumer output.
470
+ */
471
+ getLabelWidthPx() {
472
+ if (this.padding !== void 0 || this.tickmarksInside) {
473
+ return 0;
466
474
  }
467
- const hasTickmarksWithText = this.tickmarks.length > 0 && this.tickmarks.some((t) => t.text !== void 0);
468
- if (hasTickmarksWithText && !this.tickmarksInside) {
469
- return 24 * 2.5;
475
+ if (this.showLabels) {
476
+ return NSWE_LABEL_WIDTH_PX;
470
477
  }
471
- return 24;
478
+ return estimateLabelWidthPx(this.tickmarks.map((t) => t.text));
472
479
  }
473
480
  render() {
474
481
  let width;
@@ -476,31 +483,33 @@ let ObcWatch = class extends LitElement {
476
483
  let viewBox;
477
484
  if (this.arcFrame) {
478
485
  this._rOff = this.arcFrame.radiusOffset;
486
+ this._labelsHidden = false;
487
+ this._ownFrame = void 0;
479
488
  width = this.arcFrame.width;
480
489
  height = this.arcFrame.height;
481
490
  viewBox = this.arcFrame.viewBox;
482
- } else if (this.zoomToFitArc && this.areas.length > 0) {
483
- const ext = this.getPadding();
484
- const targetSize = (176 + ext) * 2;
485
- const frame = computeZoomToFitArcFrame({
491
+ } else {
492
+ const frame = computeRadialFrame({
493
+ basePadding: this.padding ?? 24,
494
+ labelWidthPx: this.getLabelWidthPx(),
495
+ clips: {
496
+ top: this.clipTop,
497
+ bottom: this.clipBottom,
498
+ left: this.clipLeft,
499
+ right: this.clipRight
500
+ },
501
+ containerPx: measureContainerPx(this),
502
+ faceDiameter: this.faceDiameter,
503
+ zoomToFitArc: this.zoomToFitArc,
486
504
  areas: this.areas,
487
- outerRadius: OUTER_RING_RADIUS,
488
- innerRadius: this.innerRingRadius,
489
- extension: ext,
490
- targetSize
505
+ innerRadius: this.innerRingRadius
491
506
  });
492
507
  this._rOff = frame.radiusOffset;
508
+ this._labelsHidden = frame.labelsHidden;
509
+ this._ownFrame = frame;
493
510
  width = frame.width;
494
511
  height = frame.height;
495
512
  viewBox = frame.viewBox;
496
- } else {
497
- this._rOff = 0;
498
- const full = (176 + this.getPadding()) * 2;
499
- width = full * (1 - this.clipLeft / 100 - this.clipRight / 100);
500
- height = full * (1 - this.clipTop / 100 - this.clipBottom / 100);
501
- const left = -full / 2 + full * this.clipLeft / 100;
502
- const top = -full / 2 + full * this.clipTop / 100;
503
- viewBox = `${left} ${top} ${width} ${height}`;
504
513
  }
505
514
  const rOff = this._rOff;
506
515
  const scale = this.getScale({ width, height });
@@ -514,7 +523,7 @@ let ObcWatch = class extends LitElement {
514
523
  size: t.type,
515
524
  style: this.tickmarkStyle,
516
525
  scale,
517
- text: this.showLabels ? void 0 : t.text,
526
+ text: this.showLabels || this._labelsHidden ? void 0 : t.text,
518
527
  inside: this.tickmarksInside,
519
528
  textRadius,
520
529
  rotation: this.rotation,
@@ -525,9 +534,11 @@ let ObcWatch = class extends LitElement {
525
534
  })
526
535
  );
527
536
  const advices = this.advices ? this.advices.map((a) => renderAdvice(a, rOff)) : nothing;
528
- const insideLabels = this.tickmarksInside && this.showLabels;
537
+ const showNsweLabels = this.showLabels && !this._labelsHidden;
538
+ const showNorthArrow = this.northArrow && !this._labelsHidden;
539
+ const insideLabels = this.tickmarksInside && showNsweLabels;
529
540
  const includeNorth = !this.northArrow;
530
- const labelPositions = this.showLabels ? getLabelPositions({
541
+ const labelPositions = showNsweLabels ? getLabelPositions({
531
542
  scale,
532
543
  inside: this.tickmarksInside,
533
544
  innerRadius: this.innerRingRadius + rOff,
@@ -540,7 +551,7 @@ let ObcWatch = class extends LitElement {
540
551
  innerRadius: this.innerRingRadius + rOff,
541
552
  includeNorth
542
553
  }) : nothing;
543
- const northArrowEl = this.northArrow ? renderNorthArrow({
554
+ const northArrowEl = showNorthArrow ? renderNorthArrow({
544
555
  scale,
545
556
  rotation: this.rotation,
546
557
  inside: this.northArrowInside ?? this.tickmarksInside
@@ -823,6 +834,9 @@ __decorateClass([
823
834
  __decorateClass([
824
835
  property({ type: Number })
825
836
  ], ObcWatch.prototype, "padding", 2);
837
+ __decorateClass([
838
+ property({ type: Number, attribute: "face-diameter" })
839
+ ], ObcWatch.prototype, "faceDiameter", 2);
826
840
  __decorateClass([
827
841
  property({ type: Array, attribute: false })
828
842
  ], ObcWatch.prototype, "areas", 2);