@oicl/openbridge-webcomponents 0.0.20260409063909 → 0.0.20260409094807

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 (32) hide show
  1. package/dist/navigation-instruments/compass/compass.d.ts +1 -0
  2. package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
  3. package/dist/navigation-instruments/compass/compass.js +5 -0
  4. package/dist/navigation-instruments/compass/compass.js.map +1 -1
  5. package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +1 -0
  6. package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -1
  7. package/dist/navigation-instruments/compass-flat/compass-flat.js +5 -0
  8. package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
  9. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts +1 -0
  10. package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
  11. package/dist/navigation-instruments/compass-sector/compass-sector.js +5 -0
  12. package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
  13. package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts +1 -0
  14. package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts.map +1 -1
  15. package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js +5 -0
  16. package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js.map +1 -1
  17. package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts +9 -10
  18. package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts.map +1 -1
  19. package/dist/navigation-instruments/rate-of-turn/rot-renderer.js +50 -32
  20. package/dist/navigation-instruments/rate-of-turn/rot-renderer.js.map +1 -1
  21. package/dist/navigation-instruments/rot-sector/rot-sector.d.ts.map +1 -1
  22. package/dist/navigation-instruments/rot-sector/rot-sector.js +9 -7
  23. package/dist/navigation-instruments/rot-sector/rot-sector.js.map +1 -1
  24. package/dist/navigation-instruments/watch/watch.d.ts +1 -0
  25. package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
  26. package/dist/navigation-instruments/watch/watch.js +58 -24
  27. package/dist/navigation-instruments/watch/watch.js.map +1 -1
  28. package/dist/navigation-instruments/watch-flat/watch-flat.d.ts +1 -0
  29. package/dist/navigation-instruments/watch-flat/watch-flat.d.ts.map +1 -1
  30. package/dist/navigation-instruments/watch-flat/watch-flat.js +40 -11
  31. package/dist/navigation-instruments/watch-flat/watch-flat.js.map +1 -1
  32. package/package.json +1 -1
@@ -18,9 +18,9 @@ const SCALE_RADIUS = 172;
18
18
  const INNER_CIRCLE_RADIUS = 100;
19
19
  const BAR_HALF_THICKNESS = 8;
20
20
  const DOT_RADIUS = BAR_HALF_THICKNESS;
21
- const BAR_DOT_RADIUS = BAR_HALF_THICKNESS * 0.75;
22
- const BAR_DOT_STROKE = BAR_HALF_THICKNESS * 0.5;
23
- const BAR_DOT_INNER_RADIUS = BAR_DOT_RADIUS - BAR_DOT_STROKE / 2;
21
+ const BAR_DOT_INNER_RADIUS = BAR_HALF_THICKNESS * 0.75 - BAR_HALF_THICKNESS * 0.25;
22
+ const ROT_ZERO_DEADBAND_DEG = 0.05;
23
+ const ROT_ZERO_DEADBAND_PX = 0.5;
24
24
  function getTrackRadius(position, radiusOffset = 0) {
25
25
  const base = position === "scale" ? SCALE_RADIUS : INNER_CIRCLE_RADIUS;
26
26
  return base + radiusOffset;
@@ -65,7 +65,7 @@ function rotBarPath(startAngle, endAngle, trackRadius) {
65
65
  return [
66
66
  `M ${outerStartX} ${outerStartY}`,
67
67
  `A ${R} ${R} 0 0 ${outerSweep} ${outerEndX} ${outerEndY}`,
68
- `L ${innerEndX} ${innerEndY}`,
68
+ `A ${BAR_HALF_THICKNESS} ${BAR_HALF_THICKNESS} 0 0 ${outerSweep} ${innerEndX} ${innerEndY}`,
69
69
  `A ${r} ${r} 0 0 ${innerSweep} ${innerStartX} ${innerStartY}`,
70
70
  `Z`
71
71
  ].join(" ");
@@ -74,45 +74,64 @@ function shortestAngularDeltaDeg(startAngle, endAngle) {
74
74
  const cw = ((endAngle - startAngle) % 360 + 360) % 360;
75
75
  return cw <= 180 ? cw : 360 - cw;
76
76
  }
77
+ function rotBarThresholdAngle(position, radiusOffset = 0) {
78
+ const trackRadius = getTrackRadius(position, radiusOffset);
79
+ return BAR_HALF_THICKNESS / trackRadius * (180 / Math.PI);
80
+ }
81
+ function renderRotZeroPill(color, angle, position, radiusOffset = 0) {
82
+ const trackRadius = getTrackRadius(position, radiusOffset);
83
+ const w = BAR_HALF_THICKNESS;
84
+ const h = BAR_HALF_THICKNESS * 2;
85
+ const rx = BAR_HALF_THICKNESS / 2;
86
+ return svg`
87
+ <g transform="rotate(${angle})">
88
+ <rect
89
+ x="${-w / 2}"
90
+ y="${-trackRadius - h / 2}"
91
+ width="${w}"
92
+ height="${h}"
93
+ rx="${rx}"
94
+ fill="${color}"
95
+ />
96
+ </g>
97
+ `;
98
+ }
99
+ function renderLinearRotZeroPill(color, x, trackY) {
100
+ const w = BAR_HALF_THICKNESS;
101
+ const h = BAR_HALF_THICKNESS * 2;
102
+ const rx = BAR_HALF_THICKNESS / 2;
103
+ return svg`
104
+ <rect
105
+ x="${x - w / 2}"
106
+ y="${trackY - h / 2}"
107
+ width="${w}"
108
+ height="${h}"
109
+ rx="${rx}"
110
+ fill="${color}"
111
+ />
112
+ `;
113
+ }
77
114
  function renderRotBarStatic(config) {
78
115
  const {
79
116
  startAngle,
80
117
  endAngle,
81
- color,
82
118
  barColor,
83
119
  position,
84
- endDotFill = "var(--instrument-frame-primary-color)",
85
- endDotStroke = color,
86
120
  maskId = "rot-bar-mask",
87
121
  radiusOffset = 0
88
122
  } = config;
89
- if (shortestAngularDeltaDeg(startAngle, endAngle) < 0.1) {
123
+ if (shortestAngularDeltaDeg(startAngle, endAngle) < rotBarThresholdAngle(position, radiusOffset)) {
90
124
  return svg``;
91
125
  }
92
126
  const trackRadius = getTrackRadius(position, radiusOffset);
93
127
  const arcPath = rotBarPath(startAngle, endAngle, trackRadius);
94
- const { cx: endCx, cy: endCy } = dotOnTrack(endAngle, trackRadius);
95
- const dotAngularPad = Math.asin(BAR_DOT_INNER_RADIUS / trackRadius) * 180 / Math.PI;
96
- const cwSpan = ((endAngle - startAngle) % 360 + 360) % 360;
97
- const isCW = cwSpan <= 180;
98
- const clipPath = rotBarPath(
99
- startAngle,
100
- endAngle + (isCW ? dotAngularPad : -dotAngularPad),
101
- trackRadius
102
- );
103
128
  return svg`
104
129
  <defs>
105
130
  <clipPath id="${maskId}">
106
- <path d="${clipPath}" />
131
+ <path d="${arcPath}" />
107
132
  </clipPath>
108
133
  </defs>
109
134
  <path d="${arcPath}" fill="${barColor}" />
110
- <circle
111
- cx="${endCx}" cy="${endCy}" r="${BAR_DOT_RADIUS}"
112
- fill="${endDotFill}"
113
- stroke="${endDotStroke}"
114
- stroke-width="${BAR_DOT_STROKE}"
115
- />
116
135
  `;
117
136
  }
118
137
  function renderRotBarDots(color, position, radiusOffset = 0) {
@@ -158,14 +177,11 @@ function renderLinearRotBarStatic(config) {
158
177
  const {
159
178
  startX,
160
179
  endX,
161
- color,
162
180
  barColor,
163
181
  trackY,
164
- endDotFill = "var(--instrument-frame-primary-color)",
165
- endDotStroke = color,
166
182
  maskId = "rot-bar-mask-linear"
167
183
  } = config;
168
- if (Math.abs(endX - startX) < 1) return svg``;
184
+ if (Math.abs(endX - startX) < BAR_HALF_THICKNESS) return svg``;
169
185
  const h = BAR_HALF_THICKNESS;
170
186
  const top = trackY - h;
171
187
  const bot = trackY + h;
@@ -180,10 +196,6 @@ function renderLinearRotBarStatic(config) {
180
196
  </clipPath>
181
197
  </defs>
182
198
  <path d="${barPath}" fill="${barColor}" />
183
- <circle
184
- cx="${endX}" cy="${trackY}" r="${BAR_DOT_RADIUS}"
185
- fill="${endDotFill}" stroke="${endDotStroke}"
186
- stroke-width="${BAR_DOT_STROKE}" />
187
199
  `;
188
200
  }
189
201
  function renderLinearRotBarDots(color, trackY, dotSpacing, visibleWidth) {
@@ -196,16 +208,22 @@ function renderLinearRotBarDots(color, trackY, dotSpacing, visibleWidth) {
196
208
  );
197
209
  }
198
210
  export {
211
+ BAR_HALF_THICKNESS,
199
212
  LINEAR_DOT_ANGLE_SPACING,
200
213
  LinearRotPosition,
214
+ ROT_ZERO_DEADBAND_DEG,
215
+ ROT_ZERO_DEADBAND_PX,
201
216
  RotPosition,
202
217
  RotType,
203
218
  renderLinearRotBarDots,
204
219
  renderLinearRotBarStatic,
205
220
  renderLinearRotDots,
221
+ renderLinearRotZeroPill,
206
222
  renderRotBarDots,
207
223
  renderRotBarStatic,
208
224
  renderRotDots,
225
+ renderRotZeroPill,
226
+ rotBarThresholdAngle,
209
227
  shortestAngularDeltaDeg
210
228
  };
211
229
  //# sourceMappingURL=rot-renderer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rot-renderer.js","sources":["../../../src/navigation-instruments/rate-of-turn/rot-renderer.ts"],"sourcesContent":["/**\n * Rate-of-turn SVG renderer — pure functions for ROT dot and bar overlays.\n *\n * This module provides side-effect-free rendering functions that return\n * `SVGTemplateResult` fragments for compositing into radial instrument SVGs.\n * All geometry is derived from a small set of constants (`BAR_HALF_THICKNESS`,\n * `DOT_COUNT`, and per-position track radii) so dimensions can be tuned from\n * a single place.\n *\n * ## Exported Functions\n *\n * - `renderRotDots(color, position)` — Five evenly-spaced filled dots on the\n * track circle. Intended to be wrapped in a spinning `<g>` by the caller.\n * - `renderRotBarStatic(config)` — The static \"banana\" arc bar, end-dot, and\n * `<clipPath>` definition. The clip region is angularly padded at the end\n * side so spinning dots snap cleanly in/out.\n * - `renderRotBarDots(color, position)` — Smaller dots sized to fit inside\n * the bar, rendered inside the caller's clip-path group.\n * - `shortestAngularDeltaDeg(startAngle, endAngle)` — Wraparound-safe\n * minimal angular distance (0–180°) used for zero-span thresholds.\n *\n * ## Coordinate System\n *\n * All functions assume a centered SVG coordinate system (0, 0 at center)\n * with 0° at 12 o'clock and angles increasing clockwise. The caller\n * (typically `<obc-watch>`) is responsible for viewBox, rotation, and\n * animation via `RateOfTurnController`.\n *\n * ## Future Extensions\n *\n * The internal path builder (`rotBarPath`) accepts an arbitrary track radius,\n * enabling future use on compass sectors with different radii and on flat\n * (linear) compass layouts where the arc would be \"straightened\" into a\n * horizontal bar.\n */\nimport {svg, SVGTemplateResult} from 'lit';\n\nexport enum RotType {\n dots = 'dots',\n bar = 'bar',\n}\n\nexport enum RotPosition {\n scale = 'scale',\n innerCircle = 'innerCircle',\n}\n\n// TODO: RotStyle.port / RotStyle.starboard for port/starboard coloring\n\nconst DOT_COUNT = 5;\nconst DOT_ANGLES = Array.from(\n {length: DOT_COUNT},\n (_, i) => (360 / DOT_COUNT) * i\n);\n\n// Midpoints of watch ring pairs — cannot import from watch.ts (circular dep)\n// SCALE_RADIUS = (OUTER_RING_RADIUS + RING2_RADIUS) / 2 = (184 + 160) / 2\n// INNER_CIRCLE_RADIUS = (RING3_RADIUS + RING4_RADIUS) / 2 = (112 + 88) / 2\nconst SCALE_RADIUS = 172;\nconst INNER_CIRCLE_RADIUS = 100;\n\nconst BAR_HALF_THICKNESS = 8;\nconst DOT_RADIUS = BAR_HALF_THICKNESS;\nconst BAR_DOT_RADIUS = BAR_HALF_THICKNESS * 0.75;\nconst BAR_DOT_STROKE = BAR_HALF_THICKNESS * 0.5;\nconst BAR_DOT_INNER_RADIUS = BAR_DOT_RADIUS - BAR_DOT_STROKE / 2;\n\nfunction getTrackRadius(position: RotPosition, radiusOffset = 0): number {\n const base =\n position === RotPosition.scale ? SCALE_RADIUS : INNER_CIRCLE_RADIUS;\n return base + radiusOffset;\n}\n\nfunction dotOnTrack(angle: number, radius: number): {cx: number; cy: number} {\n const rad = (angle * Math.PI) / 180;\n return {\n cx: Math.sin(rad) * radius,\n cy: -Math.cos(rad) * radius,\n };\n}\n\nexport function renderRotDots(\n color: string,\n position: RotPosition,\n radiusOffset = 0\n): SVGTemplateResult {\n const radius = getTrackRadius(position, radiusOffset);\n return svg`${DOT_ANGLES.map((angle) => {\n const {cx, cy} = dotOnTrack(angle, radius);\n return svg`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${DOT_RADIUS}\" fill=\"${color}\" />`;\n })}`;\n}\n\nfunction rotBarPath(\n startAngle: number,\n endAngle: number,\n trackRadius: number\n): string {\n const R = trackRadius + BAR_HALF_THICKNESS;\n const r = trackRadius - BAR_HALF_THICKNESS;\n\n const a1 = (startAngle * Math.PI) / 180;\n const a2 = (endAngle * Math.PI) / 180;\n\n const outerStartX = Math.sin(a1) * R;\n const outerStartY = -Math.cos(a1) * R;\n const innerStartX = Math.sin(a1) * r;\n const innerStartY = -Math.cos(a1) * r;\n\n const outerEndX = Math.sin(a2) * R;\n const outerEndY = -Math.cos(a2) * R;\n const innerEndX = Math.sin(a2) * r;\n const innerEndY = -Math.cos(a2) * r;\n\n // Clockwise angular distance from start to end (0..2π)\n const cwSpan = (((a2 - a1) % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);\n\n // Always draw the shortest arc (< 180°)\n let outerSweep: number;\n let innerSweep: number;\n if (cwSpan <= Math.PI) {\n outerSweep = 1;\n innerSweep = 0;\n } else {\n outerSweep = 0;\n innerSweep = 1;\n }\n\n return [\n `M ${outerStartX} ${outerStartY}`,\n `A ${R} ${R} 0 0 ${outerSweep} ${outerEndX} ${outerEndY}`,\n `L ${innerEndX} ${innerEndY}`,\n `A ${r} ${r} 0 0 ${innerSweep} ${innerStartX} ${innerStartY}`,\n `Z`,\n ].join(' ');\n}\n\nexport function shortestAngularDeltaDeg(\n startAngle: number,\n endAngle: number\n): number {\n const cw = (((endAngle - startAngle) % 360) + 360) % 360;\n return cw <= 180 ? cw : 360 - cw;\n}\n\nexport interface RotBarConfig {\n startAngle: number;\n endAngle: number;\n color: string;\n barColor: string;\n position: RotPosition;\n endDotFill?: string;\n endDotStroke?: string;\n maskId?: string;\n radiusOffset?: number;\n}\n\nexport function renderRotBarStatic(config: RotBarConfig): SVGTemplateResult {\n const {\n startAngle,\n endAngle,\n color,\n barColor,\n position,\n endDotFill = 'var(--instrument-frame-primary-color)',\n endDotStroke = color,\n maskId = 'rot-bar-mask',\n radiusOffset = 0,\n } = config;\n\n if (shortestAngularDeltaDeg(startAngle, endAngle) < 0.1) {\n return svg``;\n }\n\n const trackRadius = getTrackRadius(position, radiusOffset);\n const arcPath = rotBarPath(startAngle, endAngle, trackRadius);\n const {cx: endCx, cy: endCy} = dotOnTrack(endAngle, trackRadius);\n\n // Expand the clip region angularly at the COG (end) side only so dots\n // snap fully in/out near the end dot. The HDG (start) side is flat —\n // dots should clip exactly at the bar edge with no extra padding.\n const dotAngularPad =\n (Math.asin(BAR_DOT_INNER_RADIUS / trackRadius) * 180) / Math.PI;\n const cwSpan = (((endAngle - startAngle) % 360) + 360) % 360;\n const isCW = cwSpan <= 180;\n const clipPath = rotBarPath(\n startAngle,\n endAngle + (isCW ? dotAngularPad : -dotAngularPad),\n trackRadius\n );\n\n return svg`\n <defs>\n <clipPath id=\"${maskId}\">\n <path d=\"${clipPath}\" />\n </clipPath>\n </defs>\n <path d=\"${arcPath}\" fill=\"${barColor}\" />\n <circle\n cx=\"${endCx}\" cy=\"${endCy}\" r=\"${BAR_DOT_RADIUS}\"\n fill=\"${endDotFill}\"\n stroke=\"${endDotStroke}\"\n stroke-width=\"${BAR_DOT_STROKE}\"\n />\n `;\n}\n\nexport function renderRotBarDots(\n color: string,\n position: RotPosition,\n radiusOffset = 0\n): SVGTemplateResult {\n const radius = getTrackRadius(position, radiusOffset);\n\n return svg`\n ${DOT_ANGLES.map((angle) => {\n const {cx, cy} = dotOnTrack(angle, radius);\n return svg`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${BAR_DOT_INNER_RADIUS}\" fill=\"${color}\" />`;\n })}\n `;\n}\n\n// ============================================================================\n// Linear (flat compass) ROT rendering\n// ============================================================================\n\n/**\n * Angular spacing between dots in degrees — same as radial (360 / 5 = 72).\n * In linear mode this is converted to pixels via `dotSpacing = 72 * translationScale`.\n */\nexport const LINEAR_DOT_ANGLE_SPACING = 360 / DOT_COUNT;\n\nconst LINEAR_DOT_RADIUS = BAR_HALF_THICKNESS / 2;\n\nexport enum LinearRotPosition {\n track = 'track',\n scale = 'scale',\n}\n\n/**\n * Render evenly-spaced filled dots along a horizontal track.\n *\n * Dots are placed at multiples of `dotSpacing` centered on x = 0.\n * The caller wraps the result in a translating `<g id=\"rot-spinner\">`\n * animated by `RateOfTurnController` in translate mode.\n *\n * Enough dots are generated to cover `visibleWidth` plus one full\n * animation cycle (`5 * dotSpacing`) on each side for seamless looping.\n */\nfunction linearDotStrip(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number,\n r: number\n): SVGTemplateResult {\n if (dotSpacing <= 0) return svg``;\n const cyclePx = DOT_COUNT * dotSpacing;\n const halfRange = visibleWidth / 2 + cyclePx;\n const firstIdx = Math.floor(-halfRange / dotSpacing);\n const lastIdx = Math.ceil(halfRange / dotSpacing);\n\n const dots: SVGTemplateResult[] = [];\n for (let i = firstIdx; i <= lastIdx; i++) {\n dots.push(\n svg`<circle cx=\"${i * dotSpacing}\" cy=\"${trackY}\" r=\"${r}\" fill=\"${color}\" />`\n );\n }\n return svg`${dots}`;\n}\n\nexport function renderLinearRotDots(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number\n): SVGTemplateResult {\n return linearDotStrip(\n color,\n trackY,\n dotSpacing,\n visibleWidth,\n LINEAR_DOT_RADIUS\n );\n}\n\nexport interface LinearRotBarConfig {\n startX: number;\n endX: number;\n color: string;\n barColor: string;\n trackY: number;\n endDotFill?: string;\n endDotStroke?: string;\n maskId?: string;\n}\n\n/**\n * Render the static horizontal bar, end-dot, and `<clipPath>` for a linear\n * ROT indicator. Analogous to `renderRotBarStatic` for radial instruments.\n *\n * The bar is a rounded capsule from `startX` to `endX` at vertical\n * position `trackY`. A ring-shaped end-dot sits at `endX`. The clip\n * region is padded at the end side so spinning bar-dots snap in/out\n * cleanly (same rationale as the angular padding in the radial version).\n *\n * Returns empty SVG when the bar span is less than 1 px.\n */\nexport function renderLinearRotBarStatic(\n config: LinearRotBarConfig\n): SVGTemplateResult {\n const {\n startX,\n endX,\n color,\n barColor,\n trackY,\n endDotFill = 'var(--instrument-frame-primary-color)',\n endDotStroke = color,\n maskId = 'rot-bar-mask-linear',\n } = config;\n\n if (Math.abs(endX - startX) < 1) return svg``;\n\n const h = BAR_HALF_THICKNESS;\n const top = trackY - h;\n const bot = trackY + h;\n const isEndRight = endX >= startX;\n\n // Bar path: flat on HDG/start side, semicircle capsule on COG/end side\n const flatX = startX;\n const roundX = endX;\n const barPath = isEndRight\n ? `M ${flatX} ${top} L ${roundX} ${top} A ${h} ${h} 0 0 1 ${roundX} ${bot} L ${flatX} ${bot} Z`\n : `M ${flatX} ${top} L ${roundX} ${top} A ${h} ${h} 0 0 0 ${roundX} ${bot} L ${flatX} ${bot} Z`;\n\n // Clip path: exact same shape as the bar\n return svg`\n <defs>\n <clipPath id=\"${maskId}\">\n <path d=\"${barPath}\" />\n </clipPath>\n </defs>\n <path d=\"${barPath}\" fill=\"${barColor}\" />\n <circle\n cx=\"${endX}\" cy=\"${trackY}\" r=\"${BAR_DOT_RADIUS}\"\n fill=\"${endDotFill}\" stroke=\"${endDotStroke}\"\n stroke-width=\"${BAR_DOT_STROKE}\" />\n `;\n}\n\n/**\n * Render filled dots along a horizontal track, intended to be placed\n * inside a `<g clip-path=\"…\">` that clips to the bar shape.\n * Analogous to `renderRotBarDots` for radial instruments.\n */\nexport function renderLinearRotBarDots(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number\n): SVGTemplateResult {\n return linearDotStrip(\n color,\n trackY,\n dotSpacing,\n visibleWidth,\n LINEAR_DOT_RADIUS\n );\n}\n"],"names":["RotType","RotPosition","LinearRotPosition"],"mappings":"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"}
1
+ {"version":3,"file":"rot-renderer.js","sources":["../../../src/navigation-instruments/rate-of-turn/rot-renderer.ts"],"sourcesContent":["/**\n * Rate-of-turn SVG renderer — pure functions for ROT dot and bar overlays.\n *\n * This module provides side-effect-free rendering functions that return\n * `SVGTemplateResult` fragments for compositing into radial instrument SVGs.\n * All geometry is derived from a small set of constants (`BAR_HALF_THICKNESS`,\n * `DOT_COUNT`, and per-position track radii) so dimensions can be tuned from\n * a single place.\n *\n * ## Exported Functions\n *\n * - `renderRotDots(color, position)` — Five evenly-spaced filled dots on the\n * track circle. Intended to be wrapped in a spinning `<g>` by the caller.\n * - `renderRotBarStatic(config)` — The static \"banana\" arc bar and\n * `<clipPath>` definition.\n * - `renderRotBarDots(color, position)` — Smaller dots sized to fit inside\n * the bar, rendered inside the caller's clip-path group.\n * - `shortestAngularDeltaDeg(startAngle, endAngle)` — Wraparound-safe\n * minimal angular distance (0–180°) used for zero-span thresholds.\n *\n * ## Coordinate System\n *\n * All functions assume a centered SVG coordinate system (0, 0 at center)\n * with 0° at 12 o'clock and angles increasing clockwise. The caller\n * (typically `<obc-watch>`) is responsible for viewBox, rotation, and\n * animation via `RateOfTurnController`.\n *\n * ## Future Extensions\n *\n * The internal path builder (`rotBarPath`) accepts an arbitrary track radius,\n * enabling future use on compass sectors with different radii and on flat\n * (linear) compass layouts where the arc would be \"straightened\" into a\n * horizontal bar.\n */\nimport {svg, SVGTemplateResult} from 'lit';\n\nexport enum RotType {\n dots = 'dots',\n bar = 'bar',\n}\n\nexport enum RotPosition {\n scale = 'scale',\n innerCircle = 'innerCircle',\n}\n\n// TODO: RotStyle.port / RotStyle.starboard for port/starboard coloring\n\nconst DOT_COUNT = 5;\nconst DOT_ANGLES = Array.from(\n {length: DOT_COUNT},\n (_, i) => (360 / DOT_COUNT) * i\n);\n\n// Midpoints of watch ring pairs — cannot import from watch.ts (circular dep)\n// SCALE_RADIUS = (OUTER_RING_RADIUS + RING2_RADIUS) / 2 = (184 + 160) / 2\n// INNER_CIRCLE_RADIUS = (RING3_RADIUS + RING4_RADIUS) / 2 = (112 + 88) / 2\nconst SCALE_RADIUS = 172;\nconst INNER_CIRCLE_RADIUS = 100;\n\nexport const BAR_HALF_THICKNESS = 8;\nconst DOT_RADIUS = BAR_HALF_THICKNESS;\nconst BAR_DOT_INNER_RADIUS =\n BAR_HALF_THICKNESS * 0.75 - BAR_HALF_THICKNESS * 0.25;\n\nexport const ROT_ZERO_DEADBAND_DEG = 0.05;\nexport const ROT_ZERO_DEADBAND_PX = 0.5;\n\nfunction getTrackRadius(position: RotPosition, radiusOffset = 0): number {\n const base =\n position === RotPosition.scale ? SCALE_RADIUS : INNER_CIRCLE_RADIUS;\n return base + radiusOffset;\n}\n\nfunction dotOnTrack(angle: number, radius: number): {cx: number; cy: number} {\n const rad = (angle * Math.PI) / 180;\n return {\n cx: Math.sin(rad) * radius,\n cy: -Math.cos(rad) * radius,\n };\n}\n\nexport function renderRotDots(\n color: string,\n position: RotPosition,\n radiusOffset = 0\n): SVGTemplateResult {\n const radius = getTrackRadius(position, radiusOffset);\n return svg`${DOT_ANGLES.map((angle) => {\n const {cx, cy} = dotOnTrack(angle, radius);\n return svg`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${DOT_RADIUS}\" fill=\"${color}\" />`;\n })}`;\n}\n\nfunction rotBarPath(\n startAngle: number,\n endAngle: number,\n trackRadius: number\n): string {\n const R = trackRadius + BAR_HALF_THICKNESS;\n const r = trackRadius - BAR_HALF_THICKNESS;\n\n const a1 = (startAngle * Math.PI) / 180;\n const a2 = (endAngle * Math.PI) / 180;\n\n const outerStartX = Math.sin(a1) * R;\n const outerStartY = -Math.cos(a1) * R;\n const innerStartX = Math.sin(a1) * r;\n const innerStartY = -Math.cos(a1) * r;\n\n const outerEndX = Math.sin(a2) * R;\n const outerEndY = -Math.cos(a2) * R;\n const innerEndX = Math.sin(a2) * r;\n const innerEndY = -Math.cos(a2) * r;\n\n // Clockwise angular distance from start to end (0..2π)\n const cwSpan = (((a2 - a1) % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI);\n\n // Always draw the shortest arc (< 180°)\n let outerSweep: number;\n let innerSweep: number;\n if (cwSpan <= Math.PI) {\n outerSweep = 1;\n innerSweep = 0;\n } else {\n outerSweep = 0;\n innerSweep = 1;\n }\n\n return [\n `M ${outerStartX} ${outerStartY}`,\n `A ${R} ${R} 0 0 ${outerSweep} ${outerEndX} ${outerEndY}`,\n `A ${BAR_HALF_THICKNESS} ${BAR_HALF_THICKNESS} 0 0 ${outerSweep} ${innerEndX} ${innerEndY}`,\n `A ${r} ${r} 0 0 ${innerSweep} ${innerStartX} ${innerStartY}`,\n `Z`,\n ].join(' ');\n}\n\nexport function shortestAngularDeltaDeg(\n startAngle: number,\n endAngle: number\n): number {\n const cw = (((endAngle - startAngle) % 360) + 360) % 360;\n return cw <= 180 ? cw : 360 - cw;\n}\n\nexport function rotBarThresholdAngle(\n position: RotPosition,\n radiusOffset = 0\n): number {\n const trackRadius = getTrackRadius(position, radiusOffset);\n return (BAR_HALF_THICKNESS / trackRadius) * (180 / Math.PI);\n}\n\nexport function renderRotZeroPill(\n color: string,\n angle: number,\n position: RotPosition,\n radiusOffset = 0\n): SVGTemplateResult {\n const trackRadius = getTrackRadius(position, radiusOffset);\n const w = BAR_HALF_THICKNESS;\n const h = BAR_HALF_THICKNESS * 2;\n const rx = BAR_HALF_THICKNESS / 2;\n return svg`\n <g transform=\"rotate(${angle})\">\n <rect\n x=\"${-w / 2}\"\n y=\"${-trackRadius - h / 2}\"\n width=\"${w}\"\n height=\"${h}\"\n rx=\"${rx}\"\n fill=\"${color}\"\n />\n </g>\n `;\n}\n\nexport function renderLinearRotZeroPill(\n color: string,\n x: number,\n trackY: number\n): SVGTemplateResult {\n const w = BAR_HALF_THICKNESS;\n const h = BAR_HALF_THICKNESS * 2;\n const rx = BAR_HALF_THICKNESS / 2;\n return svg`\n <rect\n x=\"${x - w / 2}\"\n y=\"${trackY - h / 2}\"\n width=\"${w}\"\n height=\"${h}\"\n rx=\"${rx}\"\n fill=\"${color}\"\n />\n `;\n}\n\nexport interface RotBarConfig {\n startAngle: number;\n endAngle: number;\n barColor: string;\n position: RotPosition;\n maskId?: string;\n radiusOffset?: number;\n}\n\nexport function renderRotBarStatic(config: RotBarConfig): SVGTemplateResult {\n const {\n startAngle,\n endAngle,\n barColor,\n position,\n maskId = 'rot-bar-mask',\n radiusOffset = 0,\n } = config;\n\n if (\n shortestAngularDeltaDeg(startAngle, endAngle) <\n rotBarThresholdAngle(position, radiusOffset)\n ) {\n return svg``;\n }\n\n const trackRadius = getTrackRadius(position, radiusOffset);\n const arcPath = rotBarPath(startAngle, endAngle, trackRadius);\n\n return svg`\n <defs>\n <clipPath id=\"${maskId}\">\n <path d=\"${arcPath}\" />\n </clipPath>\n </defs>\n <path d=\"${arcPath}\" fill=\"${barColor}\" />\n `;\n}\n\nexport function renderRotBarDots(\n color: string,\n position: RotPosition,\n radiusOffset = 0\n): SVGTemplateResult {\n const radius = getTrackRadius(position, radiusOffset);\n\n return svg`\n ${DOT_ANGLES.map((angle) => {\n const {cx, cy} = dotOnTrack(angle, radius);\n return svg`<circle cx=\"${cx}\" cy=\"${cy}\" r=\"${BAR_DOT_INNER_RADIUS}\" fill=\"${color}\" />`;\n })}\n `;\n}\n\n// ============================================================================\n// Linear (flat compass) ROT rendering\n// ============================================================================\n\n/**\n * Angular spacing between dots in degrees — same as radial (360 / 5 = 72).\n * In linear mode this is converted to pixels via `dotSpacing = 72 * translationScale`.\n */\nexport const LINEAR_DOT_ANGLE_SPACING = 360 / DOT_COUNT;\n\nconst LINEAR_DOT_RADIUS = BAR_HALF_THICKNESS / 2;\n\nexport enum LinearRotPosition {\n track = 'track',\n scale = 'scale',\n}\n\n/**\n * Render evenly-spaced filled dots along a horizontal track.\n *\n * Dots are placed at multiples of `dotSpacing` centered on x = 0.\n * The caller wraps the result in a translating `<g id=\"rot-spinner\">`\n * animated by `RateOfTurnController` in translate mode.\n *\n * Enough dots are generated to cover `visibleWidth` plus one full\n * animation cycle (`5 * dotSpacing`) on each side for seamless looping.\n */\nfunction linearDotStrip(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number,\n r: number\n): SVGTemplateResult {\n if (dotSpacing <= 0) return svg``;\n const cyclePx = DOT_COUNT * dotSpacing;\n const halfRange = visibleWidth / 2 + cyclePx;\n const firstIdx = Math.floor(-halfRange / dotSpacing);\n const lastIdx = Math.ceil(halfRange / dotSpacing);\n\n const dots: SVGTemplateResult[] = [];\n for (let i = firstIdx; i <= lastIdx; i++) {\n dots.push(\n svg`<circle cx=\"${i * dotSpacing}\" cy=\"${trackY}\" r=\"${r}\" fill=\"${color}\" />`\n );\n }\n return svg`${dots}`;\n}\n\nexport function renderLinearRotDots(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number\n): SVGTemplateResult {\n return linearDotStrip(\n color,\n trackY,\n dotSpacing,\n visibleWidth,\n LINEAR_DOT_RADIUS\n );\n}\n\nexport interface LinearRotBarConfig {\n startX: number;\n endX: number;\n barColor: string;\n trackY: number;\n maskId?: string;\n}\n\n/**\n * Render the static horizontal bar and `<clipPath>` for a linear\n * ROT indicator. Analogous to `renderRotBarStatic` for radial instruments.\n *\n * The bar is a rounded capsule from `startX` to `endX` at vertical\n * position `trackY`. The clip region matches the bar shape so spinning\n * bar-dots clip cleanly at the edges.\n *\n * Returns empty SVG when the bar span is less than 1 px.\n */\nexport function renderLinearRotBarStatic(\n config: LinearRotBarConfig\n): SVGTemplateResult {\n const {\n startX,\n endX,\n barColor,\n trackY,\n maskId = 'rot-bar-mask-linear',\n } = config;\n\n if (Math.abs(endX - startX) < BAR_HALF_THICKNESS) return svg``;\n\n const h = BAR_HALF_THICKNESS;\n const top = trackY - h;\n const bot = trackY + h;\n const isEndRight = endX >= startX;\n\n // Bar path: flat on HDG/start side, semicircle capsule on COG/end side\n const flatX = startX;\n const roundX = endX;\n const barPath = isEndRight\n ? `M ${flatX} ${top} L ${roundX} ${top} A ${h} ${h} 0 0 1 ${roundX} ${bot} L ${flatX} ${bot} Z`\n : `M ${flatX} ${top} L ${roundX} ${top} A ${h} ${h} 0 0 0 ${roundX} ${bot} L ${flatX} ${bot} Z`;\n\n // Clip path: exact same shape as the bar\n return svg`\n <defs>\n <clipPath id=\"${maskId}\">\n <path d=\"${barPath}\" />\n </clipPath>\n </defs>\n <path d=\"${barPath}\" fill=\"${barColor}\" />\n `;\n}\n\n/**\n * Render filled dots along a horizontal track, intended to be placed\n * inside a `<g clip-path=\"…\">` that clips to the bar shape.\n * Analogous to `renderRotBarDots` for radial instruments.\n */\nexport function renderLinearRotBarDots(\n color: string,\n trackY: number,\n dotSpacing: number,\n visibleWidth: number\n): SVGTemplateResult {\n return linearDotStrip(\n color,\n trackY,\n dotSpacing,\n visibleWidth,\n LINEAR_DOT_RADIUS\n );\n}\n"],"names":["RotType","RotPosition","LinearRotPosition"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"rot-sector.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rot-sector/rot-sector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAO,MAAM,KAAK,CAAC;AAGrC,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAErC,OAAO,8DAA8D,CAAC;AACtE,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAEnD,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,qBACa,YAAa,SAAQ,iBAAyB;IAC/B,KAAK,SAAK;IACV,QAAQ,SAAO;IACd,UAAU,EAAE,OAAO,CAAS;IACvD,mDAAmD;IACxB,eAAe,EAAE,OAAO,CAAS;IAC5D;;;OAGG;IACuB,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAM;IAC3E;;;OAGG;IACuB,yBAAyB,EAAE,MAAM,GAAG,SAAS,CAAM;IAC7E;;;OAGG;IACuB,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAC1D;IACc,QAAQ,EAAE,QAAQ,CAAoB;IACrC,aAAa,EAAE,OAAO,CAAS;IAChC,aAAa,EAAE,aAAa,CAC9B;IACmB,OAAO,EAAE,iBAAiB,EAAE,CAAM;IAClD,YAAY,EAAE,OAAO,CAAS;IAC/B,YAAY,EAAE,MAAM,CAAM;IAEpD,QAAQ,GAAI,GAAG,MAAM,KAAG,MAAM,CAG5B;IAEF,IAAI,KAAK,IAAI,kBAAkB,CAE9B;IAED,OAAO,KAAK,SAAS,GAapB;IAEQ,MAAM;IAkCf,OAAO,KAAK,YAAY,GAgBvB;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,YAAY,CAAC;KAChC;CACF"}
1
+ {"version":3,"file":"rot-sector.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/rot-sector/rot-sector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAO,MAAM,KAAK,CAAC;AAGrC,OAAO,EAAC,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAC,QAAQ,EAAC,MAAM,aAAa,CAAC;AAErC,OAAO,8DAA8D,CAAC;AACtE,OAAO,EAAC,aAAa,EAAC,MAAM,sBAAsB,CAAC;AAEnD,oBAAY,kBAAkB;IAC5B,MAAM,WAAW;IACjB,GAAG,QAAQ;IACX,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;CACjB;;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,qBACa,YAAa,SAAQ,iBAAyB;IAC/B,KAAK,SAAK;IACV,QAAQ,SAAO;IACd,UAAU,EAAE,OAAO,CAAS;IACvD,mDAAmD;IACxB,eAAe,EAAE,OAAO,CAAS;IAC5D;;;OAGG;IACuB,uBAAuB,EAAE,MAAM,GAAG,SAAS,CAAM;IAC3E;;;OAGG;IACuB,yBAAyB,EAAE,MAAM,GAAG,SAAS,CAAM;IAC7E;;;OAGG;IACuB,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAC1D;IACc,QAAQ,EAAE,QAAQ,CAAoB;IACrC,aAAa,EAAE,OAAO,CAAS;IAChC,aAAa,EAAE,aAAa,CAC9B;IACmB,OAAO,EAAE,iBAAiB,EAAE,CAAM;IAClD,YAAY,EAAE,OAAO,CAAS;IAC/B,YAAY,EAAE,MAAM,CAAM;IAEpD,QAAQ,GAAI,GAAG,MAAM,KAAG,MAAM,CAG5B;IAEF,IAAI,KAAK,IAAI,kBAAkB,CAE9B;IAED,OAAO,KAAK,SAAS,GAepB;IAEQ,MAAM;IAkCf,OAAO,KAAK,YAAY,GAgBvB;CACF;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,gBAAgB,EAAE,YAAY,CAAC;KAChC;CACF"}
@@ -46,14 +46,16 @@ let ObcRotSector = class extends SetpointMixin(LitElement) {
46
46
  return "bar";
47
47
  }
48
48
  get _barColor() {
49
- if (this.priority !== Priority.enhanced) {
50
- return "var(--instrument-regular-tertiary-color)";
51
- }
52
49
  if (this.portStarboard) {
53
50
  if (this.value > 0) {
54
51
  return "var(--instrument-starboard-secondary-color)";
55
52
  }
56
- return "var(--instrument-port-secondary-color)";
53
+ if (this.value < 0) {
54
+ return "var(--instrument-port-secondary-color)";
55
+ }
56
+ }
57
+ if (this.priority !== Priority.enhanced) {
58
+ return "var(--instrument-regular-tertiary-color)";
57
59
  }
58
60
  return "var(--instrument-enhanced-tertiary-color)";
59
61
  }
@@ -90,9 +92,6 @@ let ObcRotSector = class extends SetpointMixin(LitElement) {
90
92
  `;
91
93
  }
92
94
  get _needleColor() {
93
- if (this.priority !== Priority.enhanced) {
94
- return "var(--instrument-regular-secondary-color)";
95
- }
96
95
  if (this.portStarboard) {
97
96
  if (this.value > 0) {
98
97
  return "var(--instrument-starboard-primary-color)";
@@ -102,6 +101,9 @@ let ObcRotSector = class extends SetpointMixin(LitElement) {
102
101
  }
103
102
  return "var(--instrument-regular-secondary-color)";
104
103
  }
104
+ if (this.priority !== Priority.enhanced) {
105
+ return "var(--instrument-regular-secondary-color)";
106
+ }
105
107
  return "var(--instrument-enhanced-secondary-color)";
106
108
  }
107
109
  };
@@ -1 +1 @@
1
- {"version":3,"file":"rot-sector.js","sources":["../../../src/navigation-instruments/rot-sector/rot-sector.ts"],"sourcesContent":["import {LitElement, html} from 'lit';\nimport {customElement} from '../../decorator.js';\nimport {property} from 'lit/decorators.js';\nimport {AdviceType} from '../watch/advice.js';\nimport {Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport '../../building-blocks/instrument-radial/instrument-radial.js';\nimport {TickmarkStyle} from '../watch/tickmark.js';\n\nexport enum ObcGaugeRadialType {\n filled = 'filled',\n bar = 'bar',\n needle = 'needle',\n}\n\nexport interface GaugeRadialAdvice {\n minValue: number;\n maxValue: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-rot-sector>` — Rate-of-turn sector gauge for rotational velocity.\n *\n * `ObcRotSector` is a thin wrapper around `<obc-instrument-radial>` that\n * displays a bipolar sector gauge showing rate of turn. The arc extent is\n * configurable via `rotArcExtent` (default 60°), mapping the value range\n * (−maxValue to +maxValue) to ±rotArcExtent degrees. The bottom 50% of the\n * circle is clipped, producing a compact sector arc. When `zoomToFitArc`\n * is enabled, clipping is bypassed and the arc is enlarged to fill the\n * available space. It inherits\n * a full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning.\n *\n * ## Features\n *\n * - **Bipolar sector**: Value range is symmetric around zero (−maxValue to\n * +maxValue), mapped to a ±`rotArcExtent`° arc (default 60°).\n * - **Port/starboard coloring**: When `portStarboard` is true, positive\n * values render in starboard (green) and negative in port (red).\n * - **Bar display**: Always renders as a `bar` type — no needle or filled\n * variants.\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to the inner\n * `<obc-instrument-radial>`.\n * - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to\n * render caution/alert arcs on the gauge.\n *\n * ## Usage Guidelines\n *\n * - Set `maxValue` to define the symmetric ± range.\n * - Use `priority` to switch between regular and enhanced color palettes.\n * - Enable `portStarboard` to show directional coloring.\n * - Provide `primaryTickmarkInterval` and `secondaryTickmarkInterval` to\n * control tickmark density.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\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 sector is always bottom-clipped at 50%; do not change `clipBottom`\n * externally.\n *\n * ## Example\n *\n * ```html\n * <obc-rot-sector\n * value=\"15\"\n * maxValue=\"60\"\n * enhanced\n * portStarboard\n * showLabels\n * primaryTickmarkInterval=\"20\"\n * secondaryTickmarkInterval=\"10\"\n * setpoint=\"30\"\n * ></obc-rot-sector>\n * ```\n *\n * @element obc-rot-sector\n * @typedef {import('./rot-sector.js').GaugeRadialAdvice} GaugeRadialAdvice\n */\n@customElement('obc-rot-sector')\nexport class ObcRotSector extends SetpointMixin(LitElement) {\n @property({type: Number}) value = 0;\n @property({type: Number}) maxValue = 100;\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 primary tickmarks in value units.\n * When undefined or <= 0, no primary tickmarks are shown.\n */\n @property({type: Number}) primaryTickmarkInterval: number | undefined = 50;\n /**\n * Interval for secondary tickmarks in value units.\n * When undefined or <= 0, no secondary tickmarks are shown.\n */\n @property({type: Number}) secondaryTickmarkInterval: number | undefined = 10;\n /**\n * Interval for tertiary tickmarks in value units.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Boolean}) portStarboard: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: GaugeRadialAdvice[] = [];\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n @property({type: Number}) rotArcExtent: number = 60;\n\n getAngle = (v: number): number => {\n if (!this.maxValue) return 0;\n return (v / this.maxValue) * this.rotArcExtent;\n };\n\n get _type(): ObcGaugeRadialType {\n return ObcGaugeRadialType.bar;\n }\n\n private get _barColor(): string {\n if (this.priority !== Priority.enhanced) {\n return 'var(--instrument-regular-tertiary-color)';\n }\n\n if (this.portStarboard) {\n if (this.value > 0) {\n return 'var(--instrument-starboard-secondary-color)';\n }\n return 'var(--instrument-port-secondary-color)';\n }\n\n return 'var(--instrument-enhanced-tertiary-color)';\n }\n\n override render() {\n const barColor = this._barColor;\n\n return html`\n <obc-instrument-radial\n .value=${this.value}\n .setpoint=${this.setpoint}\n .newSetpoint=${this.newSetpoint}\n .setpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .touching=${this.touching}\n .autoAtSetpoint=${this.autoAtSetpoint}\n .autoAtSetpointDeadband=${this.autoAtSetpointDeadband}\n .maxValue=${this.maxValue}\n .minValue=${-this.maxValue}\n .getAngle=${this.getAngle}\n .needleColor=${this._needleColor}\n .barColor=${barColor}\n .showLabels=${this.showLabels}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .primaryTickmarkInterval=${this.primaryTickmarkInterval}\n .secondaryTickmarkInterval=${this.secondaryTickmarkInterval}\n .tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}\n .type=${this._type}\n .needleType=${this._type}\n .advices=${this.advices}\n .clipBottom=${50}\n .zoomToFitArc=${this.zoomToFitArc}\n >\n </obc-instrument-radial>\n `;\n }\n\n private get _needleColor(): string {\n if (this.priority !== Priority.enhanced) {\n return 'var(--instrument-regular-secondary-color)';\n }\n\n if (this.portStarboard) {\n if (this.value > 0) {\n return 'var(--instrument-starboard-primary-color)';\n }\n if (this.value < 0) {\n return 'var(--instrument-port-primary-color)';\n }\n return 'var(--instrument-regular-secondary-color)';\n }\n\n return 'var(--instrument-enhanced-secondary-color)';\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rot-sector': ObcRotSector;\n }\n}\n"],"names":["ObcGaugeRadialType"],"mappings":"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"}
1
+ {"version":3,"file":"rot-sector.js","sources":["../../../src/navigation-instruments/rot-sector/rot-sector.ts"],"sourcesContent":["import {LitElement, html} from 'lit';\nimport {customElement} from '../../decorator.js';\nimport {property} from 'lit/decorators.js';\nimport {AdviceType} from '../watch/advice.js';\nimport {Priority} from '../types.js';\nimport {SetpointMixin} from '../../svghelpers/setpoint-mixin.js';\nimport '../../building-blocks/instrument-radial/instrument-radial.js';\nimport {TickmarkStyle} from '../watch/tickmark.js';\n\nexport enum ObcGaugeRadialType {\n filled = 'filled',\n bar = 'bar',\n needle = 'needle',\n}\n\nexport interface GaugeRadialAdvice {\n minValue: number;\n maxValue: number;\n type: AdviceType;\n hinted: boolean;\n}\n\n/**\n * `<obc-rot-sector>` — Rate-of-turn sector gauge for rotational velocity.\n *\n * `ObcRotSector` is a thin wrapper around `<obc-instrument-radial>` that\n * displays a bipolar sector gauge showing rate of turn. The arc extent is\n * configurable via `rotArcExtent` (default 60°), mapping the value range\n * (−maxValue to +maxValue) to ±rotArcExtent degrees. The bottom 50% of the\n * circle is clipped, producing a compact sector arc. When `zoomToFitArc`\n * is enabled, clipping is bypassed and the arc is enlarged to fill the\n * available space. It inherits\n * a full setpoint property bundle from {@link SetpointMixin}, including\n * auto at-setpoint detection, dual-marker adjustment preview, and deadband\n * tuning.\n *\n * ## Features\n *\n * - **Bipolar sector**: Value range is symmetric around zero (−maxValue to\n * +maxValue), mapped to a ±`rotArcExtent`° arc (default 60°).\n * - **Port/starboard coloring**: When `portStarboard` is true, positive\n * values render in starboard (green) and negative in port (red).\n * - **Bar display**: Always renders as a `bar` type — no needle or filled\n * variants.\n * - **Setpoint via mixin**: `setpoint`, `newSetpoint`, `touching`,\n * `autoAtSetpointDeadband`, `setpointOverride`, and all other setpoint\n * properties are provided by `SetpointMixin` and forwarded to the inner\n * `<obc-instrument-radial>`.\n * - **Advice zones**: Pass an array of {@link GaugeRadialAdvice} objects to\n * render caution/alert arcs on the gauge.\n *\n * ## Usage Guidelines\n *\n * - Set `maxValue` to define the symmetric ± range.\n * - Use `priority` to switch between regular and enhanced color palettes.\n * - Enable `portStarboard` to show directional coloring.\n * - Provide `primaryTickmarkInterval` and `secondaryTickmarkInterval` to\n * control tickmark density.\n * - Enable `showLabels` to show numeric labels at primary tickmarks.\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 sector is always bottom-clipped at 50%; do not change `clipBottom`\n * externally.\n *\n * ## Example\n *\n * ```html\n * <obc-rot-sector\n * value=\"15\"\n * maxValue=\"60\"\n * enhanced\n * portStarboard\n * showLabels\n * primaryTickmarkInterval=\"20\"\n * secondaryTickmarkInterval=\"10\"\n * setpoint=\"30\"\n * ></obc-rot-sector>\n * ```\n *\n * @element obc-rot-sector\n * @typedef {import('./rot-sector.js').GaugeRadialAdvice} GaugeRadialAdvice\n */\n@customElement('obc-rot-sector')\nexport class ObcRotSector extends SetpointMixin(LitElement) {\n @property({type: Number}) value = 0;\n @property({type: Number}) maxValue = 100;\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 primary tickmarks in value units.\n * When undefined or <= 0, no primary tickmarks are shown.\n */\n @property({type: Number}) primaryTickmarkInterval: number | undefined = 50;\n /**\n * Interval for secondary tickmarks in value units.\n * When undefined or <= 0, no secondary tickmarks are shown.\n */\n @property({type: Number}) secondaryTickmarkInterval: number | undefined = 10;\n /**\n * Interval for tertiary tickmarks in value units.\n * When undefined or <= 0, no tertiary tickmarks are shown.\n */\n @property({type: Number}) tertiaryTickmarkInterval: number | undefined =\n undefined;\n @property({type: String}) priority: Priority = Priority.regular;\n @property({type: Boolean}) portStarboard: boolean = false;\n @property({type: String}) tickmarkStyle: TickmarkStyle =\n TickmarkStyle.regular;\n @property({type: Array, attribute: false}) advices: GaugeRadialAdvice[] = [];\n @property({type: Boolean}) zoomToFitArc: boolean = false;\n @property({type: Number}) rotArcExtent: number = 60;\n\n getAngle = (v: number): number => {\n if (!this.maxValue) return 0;\n return (v / this.maxValue) * this.rotArcExtent;\n };\n\n get _type(): ObcGaugeRadialType {\n return ObcGaugeRadialType.bar;\n }\n\n private get _barColor(): string {\n if (this.portStarboard) {\n if (this.value > 0) {\n return 'var(--instrument-starboard-secondary-color)';\n }\n if (this.value < 0) {\n return 'var(--instrument-port-secondary-color)';\n }\n }\n\n if (this.priority !== Priority.enhanced) {\n return 'var(--instrument-regular-tertiary-color)';\n }\n\n return 'var(--instrument-enhanced-tertiary-color)';\n }\n\n override render() {\n const barColor = this._barColor;\n\n return html`\n <obc-instrument-radial\n .value=${this.value}\n .setpoint=${this.setpoint}\n .newSetpoint=${this.newSetpoint}\n .setpointAtZeroDeadband=${this.setpointAtZeroDeadband}\n .setpointOverride=${this.setpointOverride}\n .touching=${this.touching}\n .autoAtSetpoint=${this.autoAtSetpoint}\n .autoAtSetpointDeadband=${this.autoAtSetpointDeadband}\n .maxValue=${this.maxValue}\n .minValue=${-this.maxValue}\n .getAngle=${this.getAngle}\n .needleColor=${this._needleColor}\n .barColor=${barColor}\n .showLabels=${this.showLabels}\n .tickmarksInside=${this.tickmarksInside}\n .tickmarkStyle=${this.tickmarkStyle}\n .primaryTickmarkInterval=${this.primaryTickmarkInterval}\n .secondaryTickmarkInterval=${this.secondaryTickmarkInterval}\n .tertiaryTickmarkInterval=${this.tertiaryTickmarkInterval}\n .type=${this._type}\n .needleType=${this._type}\n .advices=${this.advices}\n .clipBottom=${50}\n .zoomToFitArc=${this.zoomToFitArc}\n >\n </obc-instrument-radial>\n `;\n }\n\n private get _needleColor(): string {\n if (this.portStarboard) {\n if (this.value > 0) {\n return 'var(--instrument-starboard-primary-color)';\n }\n if (this.value < 0) {\n return 'var(--instrument-port-primary-color)';\n }\n return 'var(--instrument-regular-secondary-color)';\n }\n\n if (this.priority !== Priority.enhanced) {\n return 'var(--instrument-regular-secondary-color)';\n }\n\n return 'var(--instrument-enhanced-secondary-color)';\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-rot-sector': ObcRotSector;\n }\n}\n"],"names":["ObcGaugeRadialType"],"mappings":"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"}
@@ -157,6 +157,7 @@ export declare class ObcWatch extends LitElement {
157
157
  rotStartAngle: number;
158
158
  rotEndAngle: number;
159
159
  rotPriority: Priority | undefined;
160
+ rotPortStarboard: boolean;
160
161
  set rotationsPerMinute(value: number);
161
162
  get rotationsPerMinute(): number;
162
163
  private _rotationsPerMinute;
@@ -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":"AAAA,OAAO,EACL,UAAU,EACV,cAAc,EAMf,MAAM,KAAK,CAAC;AAeb,OAAO,EAAC,eAAe,EAAE,QAAQ,EAAC,MAAM,aAAa,CAAC;AAGtD,OAAO,EAAa,cAAc,EAAe,MAAM,aAAa,CAAC;AACrE,OAAO,EAAC,QAAQ,EAAE,aAAa,EAAW,MAAM,eAAe,CAAC;AAChE,OAAO,EAAC,aAAa,EAAC,CAAC;AACvB,OAAO,EACL,OAAO,EACP,WAAW,EAQZ,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAC,OAAO,EAAE,WAAW,EAAC,CAAC;AAW9B,OAAO,EAAC,WAAW,EAAE,eAAe,EAAe,MAAM,aAAa,CAAC;AAGvE,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAC,WAAW,EAAE,eAAe,EAAC,CAAC;AAEtC,oBAAY,eAAe;IACzB,MAAM,WAAW;IACjB,MAAM,WAAW;IACjB,UAAU,eAAe;IACzB,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,eAAO,MAAM,iBAAiB,QAAU,CAAC;AAMzC,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAahE;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8DG;AACH,qBACa,QAAS,SAAQ,UAAU;IACtC,OAAO,CAAC,WAAW,CAA8D;IACjF,OAAO,CAAC,cAAc,CAAkE;IAE9D,KAAK,EAAE,eAAe,CAA0B;IAChD,QAAQ,EAAE,QAAQ,CAAoB;IACtC,eAAe,EAAE,eAAe,CACjC;IACE,UAAU,EAAE,OAAO,CAAS;IAC5B,gBAAgB,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,eAAe,EAAE,OAAO,CAAS;IAClC,2BAA2B,EAAE,MAAM,CAAO;IACzC,gBAAgB,EAAE,OAAO,CAAS;IAClC,QAAQ,EAAE,OAAO,CAAS;IAE1B,eAAe,EAAE,OAAO,CAAS;IAEnD,OAAO,CAAC,0BAA0B,CAAqB;IAChE,OAAO,CAAC,eAAe,CAAC,CAAgC;IAExD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB,CAAa;IAEtC,gGAAgG;IAChG,OAAO,CAAC,qBAAqB,CAAS;IACZ,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACX,KAAK,EAAE,SAAS,EAAE,CAAM;IACxB,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,OAAO,EAAE,WAAW,EAAE,CAAM;IAC5B,SAAS,EAAE,QAAQ,EAAE,CAAM;IAC3C,eAAe,EAAE,OAAO,CAAS;IAClC,aAAa,EAAE,aAAa,CAC9B;IACmB,OAAO,EAAE,cAAc,EAAE,CAAM;IAC/C,gBAAgB,EAAE,OAAO,CAAS;IAClC,UAAU,EAAE,OAAO,CAAS;IACZ,OAAO,EAAE,WAAW,EAAE,CAAM;IAC7C,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3C,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IACvC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC9B,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC9C,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC1C,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,sBAAsB,EAAE,OAAO,CAAS;IACzC,OAAO,EAAE,MAAM,CAAK;IACpB,UAAU,EAAE,MAAM,CAAK;IACvB,aAAa,EAAE,MAAM,CAAK;IAC1B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAS;IAC3B,QAAQ,EAAE,iBAAiB,GAAG,SAAS,CAAC;IAC5C,aAAa,EAAE,MAAM,CAAK;IAE1B,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,WAAW,EAAE,WAAW,CAA2B;IACnD,aAAa,EAAE,MAAM,CAAK;IAC1B,WAAW,EAAE,MAAM,CAAK;IACxB,WAAW,EAAE,QAAQ,GAAG,SAAS,CAAC;IACjC,gBAAgB,EAAE,OAAO,CAAS;IAC7D,IACI,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAKnC;IACD,IAAI,kBAAkB,IANQ,MAAM,CAQnC;IACD,OAAO,CAAC,mBAAmB,CAAK;IAChC,OAAO,CAAC,cAAc,CAAC,CAAuB;IAI9C,OAAO,CAAC,iBAAiB,CAAkC;IAElD,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAiBzC,oBAAoB,IAAI,IAAI;IAM5B,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IAmB/C,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,CAAC,KAAK,CAAK;IAElB,OAAO,CAAC,WAAW;IAgHnB,OAAO,CAAC,mBAAmB;IAkD3B,OAAO,CAAC,eAAe;IAkFvB,OAAO,CAAC,UAAU;IA4ClB,OAAO,CAAC,aAAa;IAmBrB,OAAO,CAAC,QAAQ;IAiBhB,OAAO,CAAC,UAAU;IAaT,MAAM;IA+If,OAAO,CAAC,YAAY;IA2CpB,OAAO,CAAC,SAAS;IA8DjB,OAAO,CAAC,cAAc;IA0GtB,OAAO,CAAC,iBAAiB;IAuBzB,OAAO,CAAC,4BAA4B;IAoBpC,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,WAAW,EAAE,QAAQ,CAAC;KACvB;CACF"}
@@ -8,7 +8,7 @@ import compentStyle from "./watch.css.js";
8
8
  import { ResizeController } from "@lit-labs/observers/resize-controller.js";
9
9
  import { renderAdvice, adviceMask } from "./advice.js";
10
10
  import { TickmarkStyle, tickmark } from "./tickmark.js";
11
- import { RotPosition, RotType, shortestAngularDeltaDeg, renderRotBarStatic, renderRotBarDots, renderRotDots } from "../rate-of-turn/rot-renderer.js";
11
+ import { RotPosition, RotType, shortestAngularDeltaDeg, rotBarThresholdAngle, ROT_ZERO_DEADBAND_DEG, renderRotZeroPill, renderRotBarStatic, renderRotBarDots, renderRotDots } from "../rate-of-turn/rot-renderer.js";
12
12
  import { disposeRotController, RateOfTurnController } from "../rate-of-turn/rate-of-turn.controller.js";
13
13
  import { getLabelPositions, renderLabels, renderNorthArrow } from "./label.js";
14
14
  import { VesselImageSize, vesselImages } from "./vessel.js";
@@ -94,6 +94,7 @@ let ObcWatch = class extends LitElement {
94
94
  this.rotPosition = RotPosition.innerCircle;
95
95
  this.rotStartAngle = 0;
96
96
  this.rotEndAngle = 0;
97
+ this.rotPortStarboard = false;
97
98
  this._rotationsPerMinute = 0;
98
99
  this._resizeController = new ResizeController(this, {});
99
100
  this._rOff = 0;
@@ -552,49 +553,79 @@ let ObcWatch = class extends LitElement {
552
553
  getRotColors() {
553
554
  const p = this.rotPriority ?? this.priority;
554
555
  const isEnhanced = p === Priority.enhanced;
555
- const isInner = this.rotPosition === RotPosition.innerCircle;
556
- if (isInner) {
557
- return {
558
- dotColor: isEnhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)",
559
- barBgColor: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)",
560
- endDotFill: "var(--border-silhouette-color)",
561
- endDotStroke: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)"
562
- };
556
+ if (this.rotPortStarboard) {
557
+ let direction;
558
+ if (this.rotType === RotType.bar) {
559
+ const cwSpan = ((this.rotEndAngle - this.rotStartAngle) % 360 + 360) % 360;
560
+ direction = cwSpan <= 180 ? cwSpan : cwSpan - 360;
561
+ } else {
562
+ direction = this._rotationsPerMinute;
563
+ }
564
+ if (direction > 0) {
565
+ return {
566
+ dotColor: "var(--instrument-starboard-secondary-color)",
567
+ barBgColor: "var(--instrument-starboard-primary-color)"
568
+ };
569
+ }
570
+ if (direction < 0) {
571
+ return {
572
+ dotColor: "var(--instrument-port-secondary-color)",
573
+ barBgColor: "var(--instrument-port-primary-color)"
574
+ };
575
+ }
563
576
  }
564
577
  return {
565
- dotColor: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)",
566
- barBgColor: isEnhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)",
567
- endDotFill: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--border-silhouette-color)",
568
- endDotStroke: isEnhanced ? "var(--instrument-frame-primary-color)" : "var(--instrument-regular-secondary-color)"
578
+ dotColor: isEnhanced ? "var(--instrument-enhanced-tertiary-color)" : "var(--instrument-regular-tertiary-color)",
579
+ barBgColor: isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)"
569
580
  };
570
581
  }
571
582
  renderRot() {
572
583
  if (!this.rotType) return nothing;
573
- const { dotColor, barBgColor, endDotFill, endDotStroke } = this.getRotColors();
584
+ const { dotColor, barBgColor } = this.getRotColors();
574
585
  const rOff = this._rOff;
575
586
  if (this.rotType === RotType.bar) {
576
- const hasBar = shortestAngularDeltaDeg(this.rotStartAngle, this.rotEndAngle) >= 0.1;
587
+ const angularDelta = shortestAngularDeltaDeg(
588
+ this.rotStartAngle,
589
+ this.rotEndAngle
590
+ );
591
+ const threshold = rotBarThresholdAngle(this.rotPosition, rOff);
592
+ if (angularDelta < ROT_ZERO_DEADBAND_DEG) {
593
+ return renderRotZeroPill(
594
+ barBgColor,
595
+ this.rotStartAngle,
596
+ this.rotPosition,
597
+ rOff
598
+ );
599
+ }
600
+ if (angularDelta < threshold) {
601
+ return nothing;
602
+ }
577
603
  return svg`
578
604
  ${renderRotBarStatic({
579
605
  startAngle: this.rotStartAngle,
580
606
  endAngle: this.rotEndAngle,
581
- color: dotColor,
582
607
  barColor: barBgColor,
583
608
  position: this.rotPosition,
584
- endDotFill,
585
- endDotStroke,
586
609
  maskId: "rot-bar-mask",
587
610
  radiusOffset: rOff
588
611
  })}
589
- ${hasBar ? svg`<g clip-path="url(#rot-bar-mask)">
590
- <g id="rot-spinner">
591
- ${renderRotBarDots(dotColor, this.rotPosition, rOff)}
592
- </g>
593
- </g>` : nothing}
612
+ ${svg`<g clip-path="url(#rot-bar-mask)">
613
+ <g id="rot-spinner">
614
+ ${renderRotBarDots(dotColor, this.rotPosition, rOff)}
615
+ </g>
616
+ </g>`}
594
617
  `;
595
618
  }
596
619
  const p = this.rotPriority ?? this.priority;
597
- const dotsColor = p === Priority.enhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)";
620
+ const isEnhanced = p === Priority.enhanced;
621
+ let dotsColor = isEnhanced ? "var(--instrument-enhanced-secondary-color)" : "var(--instrument-regular-secondary-color)";
622
+ if (this.rotPortStarboard) {
623
+ if (this._rotationsPerMinute > 0) {
624
+ dotsColor = "var(--instrument-starboard-secondary-color)";
625
+ } else if (this._rotationsPerMinute < 0) {
626
+ dotsColor = "var(--instrument-port-secondary-color)";
627
+ }
628
+ }
598
629
  return svg`
599
630
  <g id="rot-spinner">
600
631
  ${renderRotDots(dotsColor, this.rotPosition, rOff)}
@@ -852,6 +883,9 @@ __decorateClass([
852
883
  __decorateClass([
853
884
  property({ type: String })
854
885
  ], ObcWatch.prototype, "rotPriority", 2);
886
+ __decorateClass([
887
+ property({ type: Boolean })
888
+ ], ObcWatch.prototype, "rotPortStarboard", 2);
855
889
  __decorateClass([
856
890
  property({ type: Number })
857
891
  ], ObcWatch.prototype, "rotationsPerMinute", 1);