@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.
- package/dist/navigation-instruments/compass/compass.d.ts +1 -0
- package/dist/navigation-instruments/compass/compass.d.ts.map +1 -1
- package/dist/navigation-instruments/compass/compass.js +5 -0
- package/dist/navigation-instruments/compass/compass.js.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts +1 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-flat/compass-flat.js +5 -0
- package/dist/navigation-instruments/compass-flat/compass-flat.js.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts +1 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/compass-sector/compass-sector.js +5 -0
- package/dist/navigation-instruments/compass-sector/compass-sector.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts +1 -0
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.d.ts.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js +5 -0
- package/dist/navigation-instruments/rate-of-turn/rate-of-turn.js.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts +9 -10
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.d.ts.map +1 -1
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.js +50 -32
- package/dist/navigation-instruments/rate-of-turn/rot-renderer.js.map +1 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.d.ts.map +1 -1
- package/dist/navigation-instruments/rot-sector/rot-sector.js +9 -7
- package/dist/navigation-instruments/rot-sector/rot-sector.js.map +1 -1
- package/dist/navigation-instruments/watch/watch.d.ts +1 -0
- package/dist/navigation-instruments/watch/watch.d.ts.map +1 -1
- package/dist/navigation-instruments/watch/watch.js +58 -24
- package/dist/navigation-instruments/watch/watch.js.map +1 -1
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts +1 -0
- package/dist/navigation-instruments/watch-flat/watch-flat.d.ts.map +1 -1
- package/dist/navigation-instruments/watch-flat/watch-flat.js +40 -11
- package/dist/navigation-instruments/watch-flat/watch-flat.js.map +1 -1
- 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
|
|
22
|
-
const
|
|
23
|
-
const
|
|
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
|
-
`
|
|
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) <
|
|
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="${
|
|
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) <
|
|
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,
|
|
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
|
-
|
|
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":";;;;;;;;;;;;;;;;;AASO,IAAK,uCAAAA,wBAAL;AACLA,sBAAA,QAAA,IAAS;AACTA,sBAAA,KAAA,IAAM;AACNA,sBAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,sBAAA,CAAA,CAAA;AA6EL,IAAM,eAAN,cAA2B,cAAc,UAAU,EAAE;AAAA,EAArD,cAAA;AAAA,UAAA,GAAA,SAAA;AACqB,SAAA,QAAQ;AACR,SAAA,WAAW;AACV,SAAA,aAAsB;AAEtB,SAAA,kBAA2B;AAK5B,SAAA,0BAA8C;AAK9C,SAAA,4BAAgD;AAKhD,SAAA,2BACxB;AACwB,SAAA,WAAqB,SAAS;AAC7B,SAAA,gBAAyB;AAC1B,SAAA,gBACxB,cAAc;AAC2B,SAAA,UAA+B,CAAA;AAC/C,SAAA,eAAwB;AACzB,SAAA,eAAuB;AAEjD,SAAA,WAAW,CAAC,MAAsB;AAChC,UAAI,CAAC,KAAK,SAAU,QAAO;AAC3B,aAAQ,IAAI,KAAK,WAAY,KAAK;AAAA,IACpC;AAAA,EAAA;AAAA,EAEA,IAAI,QAA4B;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,IAAY,YAAoB;AAC9B,QAAI,KAAK,eAAe;AACtB,UAAI,KAAK,QAAQ,GAAG;AAClB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,QAAQ,GAAG;AAClB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,QAAI,KAAK,aAAa,SAAS,UAAU;AACvC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAES,SAAS;AAChB,UAAM,WAAW,KAAK;AAEtB,WAAO;AAAA;AAAA,iBAEM,KAAK,KAAK;AAAA,oBACP,KAAK,QAAQ;AAAA,uBACV,KAAK,WAAW;AAAA,kCACL,KAAK,sBAAsB;AAAA,4BACjC,KAAK,gBAAgB;AAAA,oBAC7B,KAAK,QAAQ;AAAA,0BACP,KAAK,cAAc;AAAA,kCACX,KAAK,sBAAsB;AAAA,oBACzC,KAAK,QAAQ;AAAA,oBACb,CAAC,KAAK,QAAQ;AAAA,oBACd,KAAK,QAAQ;AAAA,uBACV,KAAK,YAAY;AAAA,oBACpB,QAAQ;AAAA,sBACN,KAAK,UAAU;AAAA,2BACV,KAAK,eAAe;AAAA,yBACtB,KAAK,aAAa;AAAA,mCACR,KAAK,uBAAuB;AAAA,qCAC1B,KAAK,yBAAyB;AAAA,oCAC/B,KAAK,wBAAwB;AAAA,gBACjD,KAAK,KAAK;AAAA,sBACJ,KAAK,KAAK;AAAA,mBACb,KAAK,OAAO;AAAA,sBACT,EAAE;AAAA,wBACA,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA,EAIvC;AAAA,EAEA,IAAY,eAAuB;AACjC,QAAI,KAAK,eAAe;AACtB,UAAI,KAAK,QAAQ,GAAG;AAClB,eAAO;AAAA,MACT;AACA,UAAI,KAAK,QAAQ,GAAG;AAClB,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,aAAa,SAAS,UAAU;AACvC,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AACF;AA1G4B,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GADb,aACe,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAFb,aAEe,WAAA,YAAA,CAAA;AACC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAHd,aAGgB,WAAA,cAAA,CAAA;AAEA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GALd,aAKgB,WAAA,mBAAA,CAAA;AAKD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAVb,aAUe,WAAA,2BAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAfb,aAee,WAAA,6BAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GApBb,aAoBe,WAAA,4BAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtBb,aAsBe,WAAA,YAAA,CAAA;AACC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAvBd,aAuBgB,WAAA,iBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAxBb,aAwBe,WAAA,iBAAA,CAAA;AAEiB,gBAAA;AAAA,EAA1C,SAAS,EAAC,MAAM,OAAO,WAAW,OAAM;AAAA,GA1B9B,aA0BgC,WAAA,WAAA,CAAA;AAChB,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA3Bd,aA2BgB,WAAA,gBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Bb,aA4Be,WAAA,gBAAA,CAAA;AA5Bf,eAAN,gBAAA;AAAA,EADN,cAAc,gBAAgB;AAAA,GAClB,YAAA;"}
|
|
@@ -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":"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,
|
|
1
|
+
{"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/navigation-instruments/watch/watch.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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-
|
|
566
|
-
barBgColor: isEnhanced ? "var(--instrument-enhanced-
|
|
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
|
|
584
|
+
const { dotColor, barBgColor } = this.getRotColors();
|
|
574
585
|
const rOff = this._rOff;
|
|
575
586
|
if (this.rotType === RotType.bar) {
|
|
576
|
-
const
|
|
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
|
-
${
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
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
|
|
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);
|